diff --git a/.travis.yml b/.travis.yml index ad4e5b73..55f7c097 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,8 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libmpc; fi install: + - export CWD=`pwd` + - echo $CWD - export CC=$CC$VERSION - export CXX=$CXX$VERSION - echo $PATH @@ -36,11 +38,22 @@ script: - ./bootstrap.sh - mkdir build - cd build - - ../configure --enable-precision=single --enable-simd=SSE4 --enable-comms=none + - mkdir lime + - cd lime + - mkdir build + - cd build + - wget http://usqcd-software.github.io/downloads/c-lime/lime-1.3.2.tar.gz + - tar xf lime-1.3.2.tar.gz + - cd lime-1.3.2 + - ./configure --prefix=$CWD/build/lime/install + - make -j4 + - make install + - cd $CWD/build + - ../configure --enable-precision=single --enable-simd=SSE4 --enable-comms=none --with-lime=$CWD/build/lime/install - make -j4 - ./benchmarks/Benchmark_dwf --threads 1 --debug-signals - echo make clean - - ../configure --enable-precision=double --enable-simd=SSE4 --enable-comms=none + - ../configure --enable-precision=double --enable-simd=SSE4 --enable-comms=none --with-lime=$CWD/build/lime/install - make -j4 - ./benchmarks/Benchmark_dwf --threads 1 --debug-signals - make check diff --git a/VERSION b/VERSION index bfad377d..a0211af1 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ -Version : 0.7.0 +Version : 0.8.0 - Clang 3.5 and above, ICPC v16 and above, GCC 6.3 and above recommended - MPI and MPI3 comms optimisations for KNL and OPA finished diff --git a/benchmarks/Benchmark_IO.cc b/benchmarks/Benchmark_IO.cc new file mode 100644 index 00000000..479ae037 --- /dev/null +++ b/benchmarks/Benchmark_IO.cc @@ -0,0 +1,108 @@ +#include +#ifdef HAVE_LIME + +using namespace std; +using namespace Grid; +using namespace Grid::QCD; + +#define MSG cout << GridLogMessage +#define SEP \ +"=============================================================================" +#ifndef BENCH_IO_LMAX +#define BENCH_IO_LMAX 40 +#endif + +typedef function WriterFn; +typedef function ReaderFn; + +string filestem(const int l) +{ + return "iobench_l" + to_string(l); +} + +void limeWrite(const string filestem, LatticeFermion &vec) +{ + emptyUserRecord record; + ScidacWriter binWriter(vec._grid->IsBoss()); + + binWriter.open(filestem + ".bin"); + binWriter.writeScidacFieldRecord(vec, record); + binWriter.close(); +} + +void limeRead(LatticeFermion &vec, const string filestem) +{ + emptyUserRecord record; + ScidacReader binReader; + + binReader.open(filestem + ".bin"); + binReader.readScidacFieldRecord(vec, record); + binReader.close(); +} + +void writeBenchmark(const int l, const WriterFn &write) +{ + auto mpi = GridDefaultMpi(); + auto simd = GridDefaultSimd(Nd, vComplex::Nsimd()); + vector latt = {l*mpi[0], l*mpi[1], l*mpi[2], l*mpi[3]}; + unique_ptr gPt(SpaceTimeGrid::makeFourDimGrid(latt, simd, mpi)); + GridCartesian *g = gPt.get(); + GridParallelRNG rng(g); + LatticeFermion vec(g); + emptyUserRecord record; + ScidacWriter binWriter(g->IsBoss()); + + cout << "-- Local volume " << l << "^4" << endl; + random(rng, vec); + write(filestem(l), vec); +} + +void readBenchmark(const int l, const ReaderFn &read) +{ + auto mpi = GridDefaultMpi(); + auto simd = GridDefaultSimd(Nd, vComplex::Nsimd()); + vector latt = {l*mpi[0], l*mpi[1], l*mpi[2], l*mpi[3]}; + unique_ptr gPt(SpaceTimeGrid::makeFourDimGrid(latt, simd, mpi)); + GridCartesian *g = gPt.get(); + LatticeFermion vec(g); + emptyUserRecord record; + ScidacReader binReader; + + cout << "-- Local volume " << l << "^4" << endl; + read(vec, filestem(l)); +} + +int main (int argc, char ** argv) +{ + Grid_init(&argc,&argv); + + auto simd = GridDefaultSimd(Nd,vComplex::Nsimd()); + auto mpi = GridDefaultMpi(); + + int64_t threads = GridThread::GetThreads(); + MSG << "Grid is setup to use " << threads << " threads" << endl; + MSG << SEP << endl; + MSG << "Benchmark Lime write" << endl; + MSG << SEP << endl; + for (int l = 4; l <= BENCH_IO_LMAX; l += 2) + { + writeBenchmark(l, limeWrite); + } + + MSG << "Benchmark Lime read" << endl; + MSG << SEP << endl; + for (int l = 4; l <= BENCH_IO_LMAX; l += 2) + { + readBenchmark(l, limeRead); + } + + Grid_finalize(); + + return EXIT_SUCCESS; +} +#else +int main (int argc, char ** argv) +{ + return EXIT_SUCCESS; +} +#endif diff --git a/benchmarks/Benchmark_ITT.cc b/benchmarks/Benchmark_ITT.cc index 666e4830..f811ac32 100644 --- a/benchmarks/Benchmark_ITT.cc +++ b/benchmarks/Benchmark_ITT.cc @@ -158,8 +158,10 @@ public: dbytes=0; ncomm=0; - - parallel_for(int dir=0;dir<8;dir++){ +#ifdef GRID_OMP +#pragma omp parallel for num_threads(Grid::CartesianCommunicator::nCommThreads) +#endif + for(int dir=0;dir<8;dir++){ double tbytes; int mu =dir % 4; @@ -175,9 +177,14 @@ public: int comm_proc = mpi_layout[mu]-1; Grid.ShiftedRanks(mu,comm_proc,xmit_to_rank,recv_from_rank); } +#ifdef GRID_OMP + int tid = omp_get_thread_num(); +#else + int tid = dir; +#endif tbytes= Grid.StencilSendToRecvFrom((void *)&xbuf[dir][0], xmit_to_rank, (void *)&rbuf[dir][0], recv_from_rank, - bytes,dir); + bytes,tid); #ifdef GRID_OMP #pragma omp atomic diff --git a/benchmarks/Benchmark_comms.cc b/benchmarks/Benchmark_comms.cc index 29ccf96c..6d95bbe2 100644 --- a/benchmarks/Benchmark_comms.cc +++ b/benchmarks/Benchmark_comms.cc @@ -169,7 +169,11 @@ int main (int argc, char ** argv) for(int lat=4;lat<=maxlat;lat+=4){ for(int Ls=8;Ls<=8;Ls*=2){ - std::vector latt_size ({lat,lat,lat,lat}); + std::vector latt_size ({lat*mpi_layout[0], + lat*mpi_layout[1], + lat*mpi_layout[2], + lat*mpi_layout[3]}); + GridCartesian Grid(latt_size,simd_layout,mpi_layout); RealD Nrank = Grid._Nprocessors; @@ -446,7 +450,7 @@ int main (int argc, char ** argv) } - +#ifdef GRID_OMP std::cout< simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); std::vector mpi_layout = GridDefaultMpi(); @@ -51,7 +53,7 @@ int main (int argc, char ** argv) std::cout< latt_size ({lat*mpi_layout[0],lat*mpi_layout[1],lat*mpi_layout[2],lat*mpi_layout[3]}); int64_t vol = latt_size[0]*latt_size[1]*latt_size[2]*latt_size[3]; @@ -83,7 +85,7 @@ int main (int argc, char ** argv) std::cout< latt_size ({lat*mpi_layout[0],lat*mpi_layout[1],lat*mpi_layout[2],lat*mpi_layout[3]}); int64_t vol = latt_size[0]*latt_size[1]*latt_size[2]*latt_size[3]; @@ -114,7 +116,7 @@ int main (int argc, char ** argv) std::cout< latt_size ({lat*mpi_layout[0],lat*mpi_layout[1],lat*mpi_layout[2],lat*mpi_layout[3]}); int64_t vol = latt_size[0]*latt_size[1]*latt_size[2]*latt_size[3]; @@ -145,7 +147,38 @@ int main (int argc, char ** argv) std::cout< latt_size ({lat*mpi_layout[0],lat*mpi_layout[1],lat*mpi_layout[2],lat*mpi_layout[3]}); + int64_t vol = latt_size[0]*latt_size[1]*latt_size[2]*latt_size[3]; + + GridCartesian Grid(latt_size,simd_layout,mpi_layout); + GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(std::vector({45,12,81,9})); + + LatticeColourMatrix z(&Grid); random(pRNG,z); + LatticeColourMatrix x(&Grid); random(pRNG,x); + LatticeColourMatrix y(&Grid); random(pRNG,y); + + double start=usecond(); + for(int64_t i=0;i latt_size ({lat*mpi_layout[0],lat*mpi_layout[1],lat*mpi_layout[2],lat*mpi_layout[3]}); int64_t vol = latt_size[0]*latt_size[1]*latt_size[2]*latt_size[3]; @@ -157,18 +190,64 @@ int main (int argc, char ** argv) LatticeColourMatrix x(&Grid); random(pRNG,x); LatticeColourMatrix y(&Grid); random(pRNG,y); - double start=usecond(); - for(int64_t i=0;i latt_size ({lat*mpi_layout[0],lat*mpi_layout[1],lat*mpi_layout[2],lat*mpi_layout[3]}); + int64_t vol = latt_size[0]*latt_size[1]*latt_size[2]*latt_size[3]; + + GridCartesian Grid(latt_size,simd_layout,mpi_layout); + GridParallelRNG pRNG(&Grid); pRNG.SeedFixedIntegers(std::vector({45,12,81,9})); + + LatticeColourMatrix z(&Grid); random(pRNG,z); + LatticeColourMatrix x(&Grid); random(pRNG,x); + LatticeColourMatrix y(&Grid); random(pRNG,y); + LatticeColourMatrix tmp(&Grid); + + for(int mu=0;mu<4;mu++){ + double tshift=0; + double tmult =0; + + double start=usecond(); + for(int64_t i=0;i #include +#include using namespace Grid; using namespace QCD; @@ -113,12 +114,12 @@ void Application::parseParameterFile(const std::string parameterFileName) setPar(par); if (!push(reader, "modules")) { - HADRON_ERROR(Parsing, "Cannot open node 'modules' in parameter file '" + HADRONS_ERROR(Parsing, "Cannot open node 'modules' in parameter file '" + parameterFileName + "'"); } if (!push(reader, "module")) { - HADRON_ERROR(Parsing, "Cannot open node 'modules/module' in parameter file '" + HADRONS_ERROR(Parsing, "Cannot open node 'modules/module' in parameter file '" + parameterFileName + "'"); } do @@ -176,7 +177,7 @@ void Application::saveSchedule(const std::string filename) if (!scheduled_) { - HADRON_ERROR(Definition, "Computation not scheduled"); + HADRONS_ERROR(Definition, "Computation not scheduled"); } for (auto address: program_) @@ -207,7 +208,7 @@ void Application::printSchedule(void) { if (!scheduled_) { - HADRON_ERROR(Definition, "Computation not scheduled"); + HADRONS_ERROR(Definition, "Computation not scheduled"); } auto peak = vm().memoryNeeded(program_); LOG(Message) << "Schedule (memory needed: " << sizeString(peak) << "):" diff --git a/extras/Hadrons/Application.hpp b/extras/Hadrons/Application.hpp index 8cd15433..0254f2fc 100644 --- a/extras/Hadrons/Application.hpp +++ b/extras/Hadrons/Application.hpp @@ -31,7 +31,7 @@ See the full license in the file "LICENSE" in the top level distribution directo #include #include -#include +#include BEGIN_HADRONS_NAMESPACE diff --git a/extras/Hadrons/EigenPack.hpp b/extras/Hadrons/EigenPack.hpp index d27e35b9..4169cba1 100644 --- a/extras/Hadrons/EigenPack.hpp +++ b/extras/Hadrons/EigenPack.hpp @@ -44,9 +44,21 @@ class EigenPack { public: typedef F Field; + struct PackRecord + { + std::string operatorXml, solverXml; + }; + struct VecRecord: Serializable + { + GRID_SERIALIZABLE_CLASS_MEMBERS(VecRecord, + unsigned int, index, + double, eval); + VecRecord(void): index(0), eval(0.) {} + }; public: std::vector eval; std::vector evec; + PackRecord record; public: EigenPack(void) = default; virtual ~EigenPack(void) = default; @@ -62,68 +74,139 @@ public: evec.resize(size, grid); } - virtual void read(const std::string fileStem, const int traj = -1) + virtual void read(const std::string fileStem, const bool multiFile, const int traj = -1) { - std::string evecFilename, evalFilename; - - makeFilenames(evecFilename, evalFilename, fileStem, traj); - XmlReader xmlReader(evalFilename); - basicRead(evec, evecFilename, evec.size()); - LOG(Message) << "Reading " << eval.size() << " eigenvalues from '" - << evalFilename << "'" << std::endl; - Grid::read(xmlReader, "evals", eval); + if (multiFile) + { + for(int k = 0; k < evec.size(); ++k) + { + basicReadSingle(evec[k], eval[k], evecFilename(fileStem, k, traj), k); + } + } + else + { + basicRead(evec, eval, evecFilename(fileStem, -1, traj), evec.size()); + } } - virtual void write(const std::string fileStem, const int traj = -1) + virtual void write(const std::string fileStem, const bool multiFile, const int traj = -1) { - std::string evecFilename, evalFilename; - - makeFilenames(evecFilename, evalFilename, fileStem, traj); - XmlWriter xmlWriter(evalFilename); - basicWrite(evecFilename, evec, evec.size()); - LOG(Message) << "Writing " << eval.size() << " eigenvalues to '" - << evalFilename << "'" << std::endl; - Grid::write(xmlWriter, "evals", eval); + if (multiFile) + { + for(int k = 0; k < evec.size(); ++k) + { + basicWriteSingle(evecFilename(fileStem, k, traj), evec[k], eval[k], k); + } + } + else + { + basicWrite(evecFilename(fileStem, -1, traj), evec, eval, evec.size()); + } } protected: - void makeFilenames(std::string &evecFilename, std::string &evalFilename, - const std::string stem, const int traj = -1) + std::string evecFilename(const std::string stem, const int vec, const int traj) { std::string t = (traj < 0) ? "" : ("." + std::to_string(traj)); - evecFilename = stem + "_evec" + t + ".bin"; - evalFilename = stem + "_eval" + t + ".xml"; + if (vec == -1) + { + return stem + t + ".bin"; + } + else + { + return stem + t + "/v" + std::to_string(vec) + ".bin"; + } } template - static void basicRead(std::vector &evec, const std::string filename, - const unsigned int size) + void basicRead(std::vector &evec, std::vector &eval, + const std::string filename, const unsigned int size) { - emptyUserRecord record; ScidacReader binReader; binReader.open(filename); + binReader.skipPastObjectRecord(SCIDAC_FILE_XML); for(int k = 0; k < size; ++k) { - binReader.readScidacFieldRecord(evec[k], record); + VecRecord vecRecord; + + LOG(Message) << "Reading eigenvector " << k << std::endl; + binReader.readScidacFieldRecord(evec[k], vecRecord); + if (vecRecord.index != k) + { + HADRONS_ERROR(Io, "Eigenvector " + std::to_string(k) + " has a" + + " wrong index (expected " + std::to_string(vecRecord.index) + + ") in file '" + filename + "'"); + } + eval[k] = vecRecord.eval; } binReader.close(); } template - static void basicWrite(const std::string filename, std::vector &evec, - const unsigned int size) + void basicReadSingle(T &evec, double &eval, const std::string filename, + const unsigned int index) { - emptyUserRecord record; - ScidacWriter binWriter; + ScidacReader binReader; + VecRecord vecRecord; + binReader.open(filename); + binReader.skipPastObjectRecord(SCIDAC_FILE_XML); + LOG(Message) << "Reading eigenvector " << index << std::endl; + binReader.readScidacFieldRecord(evec, vecRecord); + if (vecRecord.index != index) + { + HADRONS_ERROR(Io, "Eigenvector " + std::to_string(index) + " has a" + + " wrong index (expected " + std::to_string(vecRecord.index) + + ") in file '" + filename + "'"); + } + eval = vecRecord.eval; + binReader.close(); + } + + template + void basicWrite(const std::string filename, std::vector &evec, + const std::vector &eval, const unsigned int size) + { + ScidacWriter binWriter(evec[0]._grid->IsBoss()); + XmlWriter xmlWriter("", "eigenPackPar"); + + makeFileDir(filename, evec[0]._grid); + xmlWriter.pushXmlString(record.operatorXml); + xmlWriter.pushXmlString(record.solverXml); binWriter.open(filename); + binWriter.writeLimeObject(1, 1, xmlWriter, "parameters", SCIDAC_FILE_XML); for(int k = 0; k < size; ++k) { - binWriter.writeScidacFieldRecord(evec[k], record); + VecRecord vecRecord; + + vecRecord.index = k; + vecRecord.eval = eval[k]; + LOG(Message) << "Writing eigenvector " << k << std::endl; + binWriter.writeScidacFieldRecord(evec[k], vecRecord, DEFAULT_ASCII_PREC); } binWriter.close(); } + + template + void basicWriteSingle(const std::string filename, T &evec, + const double eval, const unsigned int index) + { + ScidacWriter binWriter(evec._grid->IsBoss()); + XmlWriter xmlWriter("", "eigenPackPar"); + VecRecord vecRecord; + + makeFileDir(filename, evec._grid); + xmlWriter.pushXmlString(record.operatorXml); + xmlWriter.pushXmlString(record.solverXml); + binWriter.open(filename); + binWriter.writeLimeObject(1, 1, xmlWriter, "parameters", SCIDAC_FILE_XML); + vecRecord.index = index; + vecRecord.eval = eval; + LOG(Message) << "Writing eigenvector " << index << std::endl; + binWriter.writeScidacFieldRecord(evec, vecRecord, DEFAULT_ASCII_PREC); + binWriter.close(); + } }; template @@ -152,54 +235,76 @@ public: evecCoarse.resize(sizeCoarse, gridCoarse); } - virtual void read(const std::string fileStem, const int traj = -1) + void readFine(const std::string fileStem, const bool multiFile, const int traj = -1) { - std::string evecFineFilename, evalFineFilename; - std::string evecCoarseFilename, evalCoarseFilename; - - this->makeFilenames(evecFineFilename, evalFineFilename, - fileStem + "_fine", traj); - this->makeFilenames(evecCoarseFilename, evalCoarseFilename, - fileStem + "_coarse", traj); - XmlReader xmlFineReader(evalFineFilename); - XmlReader xmlCoarseReader(evalCoarseFilename); - LOG(Message) << "Reading " << this->evec.size() << " fine eigenvectors from '" - << evecFineFilename << "'" << std::endl; - this->basicRead(this->evec, evecFineFilename, this->evec.size()); - LOG(Message) << "Reading " << evecCoarse.size() << " coarse eigenvectors from '" - << evecCoarseFilename << "'" << std::endl; - this->basicRead(evecCoarse, evecCoarseFilename, evecCoarse.size()); - LOG(Message) << "Reading " << this->eval.size() << " fine eigenvalues from '" - << evalFineFilename << "'" << std::endl; - Grid::read(xmlFineReader, "evals", this->eval); - LOG(Message) << "Reading " << evalCoarse.size() << " coarse eigenvalues from '" - << evalCoarseFilename << "'" << std::endl; - Grid::read(xmlCoarseReader, "evals", evalCoarse); + if (multiFile) + { + for(int k = 0; k < this->evec.size(); ++k) + { + this->basicReadSingle(this->evec[k], this->eval[k], this->evecFilename(fileStem + "_fine", k, traj), k); + } + } + else + { + this->basicRead(this->evec, this->eval, this->evecFilename(fileStem + "_fine", -1, traj), this->evec.size()); + } } - virtual void write(const std::string fileStem, const int traj = -1) + void readCoarse(const std::string fileStem, const bool multiFile, const int traj = -1) { - std::string evecFineFilename, evalFineFilename; - std::string evecCoarseFilename, evalCoarseFilename; + if (multiFile) + { + for(int k = 0; k < evecCoarse.size(); ++k) + { + this->basicReadSingle(evecCoarse[k], evalCoarse[k], this->evecFilename(fileStem + "_coarse", k, traj), k); + } + } + else + { + this->basicRead(evecCoarse, evalCoarse, this->evecFilename(fileStem + "_coarse", -1, traj), evecCoarse.size()); + } + } - this->makeFilenames(evecFineFilename, evalFineFilename, - fileStem + "_fine", traj); - this->makeFilenames(evecCoarseFilename, evalCoarseFilename, - fileStem + "_coarse", traj); - XmlWriter xmlFineWriter(evalFineFilename); - XmlWriter xmlCoarseWriter(evalCoarseFilename); - LOG(Message) << "Writing " << this->evec.size() << " fine eigenvectors to '" - << evecFineFilename << "'" << std::endl; - this->basicWrite(evecFineFilename, this->evec, this->evec.size()); - LOG(Message) << "Writing " << evecCoarse.size() << " coarse eigenvectors to '" - << evecCoarseFilename << "'" << std::endl; - this->basicWrite(evecCoarseFilename, evecCoarse, evecCoarse.size()); - LOG(Message) << "Writing " << this->eval.size() << " fine eigenvalues to '" - << evalFineFilename << "'" << std::endl; - Grid::write(xmlFineWriter, "evals", this->eval); - LOG(Message) << "Writing " << evalCoarse.size() << " coarse eigenvalues to '" - << evalCoarseFilename << "'" << std::endl; - Grid::write(xmlCoarseWriter, "evals", evalCoarse); + virtual void read(const std::string fileStem, const bool multiFile, const int traj = -1) + { + readFine(fileStem, multiFile, traj); + readCoarse(fileStem, multiFile, traj); + } + + void writeFine(const std::string fileStem, const bool multiFile, const int traj = -1) + { + if (multiFile) + { + for(int k = 0; k < this->evec.size(); ++k) + { + this->basicWriteSingle(this->evecFilename(fileStem + "_fine", k, traj), this->evec[k], this->eval[k], k); + } + } + else + { + this->basicWrite(this->evecFilename(fileStem + "_fine", -1, traj), this->evec, this->eval, this->evec.size()); + } + } + + void writeCoarse(const std::string fileStem, const bool multiFile, const int traj = -1) + { + if (multiFile) + { + for(int k = 0; k < evecCoarse.size(); ++k) + { + this->basicWriteSingle(this->evecFilename(fileStem + "_coarse", k, traj), evecCoarse[k], evalCoarse[k], k); + } + } + else + { + this->basicWrite(this->evecFilename(fileStem + "_coarse", -1, traj), evecCoarse, evalCoarse, evecCoarse.size()); + } + } + + virtual void write(const std::string fileStem, const bool multiFile, const int traj = -1) + { + writeFine(fileStem, multiFile, traj); + writeCoarse(fileStem, multiFile, traj); } }; diff --git a/extras/Hadrons/Environment.cc b/extras/Hadrons/Environment.cc index 9c9618f7..990a717e 100644 --- a/extras/Hadrons/Environment.cc +++ b/extras/Hadrons/Environment.cc @@ -35,7 +35,7 @@ using namespace QCD; using namespace Hadrons; #define ERROR_NO_ADDRESS(address)\ -HADRON_ERROR(Definition, "no object with address " + std::to_string(address)); +HADRONS_ERROR(Definition, "no object with address " + std::to_string(address)); /****************************************************************************** * Environment implementation * @@ -85,7 +85,7 @@ void Environment::createCoarseGrid(const std::vector &blockSize, coarseDim[d] = fineDim[d]/blockSize[d]; if (coarseDim[d]*blockSize[d] != fineDim[d]) { - HADRON_ERROR(Size, "Fine dimension " + std::to_string(d) + HADRONS_ERROR(Size, "Fine dimension " + std::to_string(d) + " (" + std::to_string(fineDim[d]) + ") not divisible by coarse dimension (" + std::to_string(coarseDim[d]) + ")"); @@ -96,7 +96,7 @@ void Environment::createCoarseGrid(const std::vector &blockSize, cLs = Ls/blockSize[nd]; if (cLs*blockSize[nd] != Ls) { - HADRON_ERROR(Size, "Fine Ls (" + std::to_string(Ls) + HADRONS_ERROR(Size, "Fine Ls (" + std::to_string(Ls) + ") not divisible by coarse Ls (" + std::to_string(cLs) + ")"); } @@ -106,14 +106,10 @@ void Environment::createCoarseGrid(const std::vector &blockSize, gridCoarse4d_[key4d].reset( SpaceTimeGrid::makeFourDimGrid(coarseDim, GridDefaultSimd(nd, vComplex::Nsimd()), GridDefaultMpi())); - gridCoarseRb4d_[key4d].reset( - SpaceTimeGrid::makeFourDimRedBlackGrid(gridCoarse4d_[key4d].get())); if (Ls > 1) { gridCoarse5d_[key5d].reset( SpaceTimeGrid::makeFiveDimGrid(cLs, gridCoarse4d_[key4d].get())); - gridCoarseRb5d_[key5d].reset( - SpaceTimeGrid::makeFiveDimRedBlackGrid(cLs, gridCoarse4d_[key4d].get())); } } @@ -132,7 +128,7 @@ GridCartesian * Environment::getGrid(const unsigned int Ls) const } catch(std::out_of_range &) { - HADRON_ERROR(Definition, "no grid with Ls= " + std::to_string(Ls)); + HADRONS_ERROR(Definition, "no grid with Ls= " + std::to_string(Ls)); } } @@ -151,7 +147,7 @@ GridRedBlackCartesian * Environment::getRbGrid(const unsigned int Ls) const } catch(std::out_of_range &) { - HADRON_ERROR(Definition, "no red-black grid with Ls= " + std::to_string(Ls)); + HADRONS_ERROR(Definition, "no red-black grid with Ls= " + std::to_string(Ls)); } } @@ -175,31 +171,7 @@ GridCartesian * Environment::getCoarseGrid( } catch(std::out_of_range &) { - HADRON_ERROR(Definition, "no coarse grid with Ls= " + std::to_string(Ls)); - } -} - -GridRedBlackCartesian * Environment::getRbCoarseGrid( - const std::vector &blockSize, const unsigned int Ls) const -{ - auto key = blockSize; - - try - { - if (Ls == 1) - { - key.resize(getNd()); - return gridCoarseRb4d_.at(key).get(); - } - else - { - key.push_back(Ls); - return gridCoarseRb5d_.at(key).get(); - } - } - catch(std::out_of_range &) - { - HADRON_ERROR(Definition, "no coarse red-black grid with Ls= " + std::to_string(Ls)); + HADRONS_ERROR(Definition, "no coarse grid with Ls= " + std::to_string(Ls)); } } @@ -249,7 +221,7 @@ void Environment::addObject(const std::string name, const int moduleAddress) } else { - HADRON_ERROR(Definition, "object '" + name + "' already exists"); + HADRONS_ERROR(Definition, "object '" + name + "' already exists"); } } @@ -272,7 +244,7 @@ unsigned int Environment::getObjectAddress(const std::string name) const } else { - HADRON_ERROR(Definition, "no object with name '" + name + "'"); + HADRONS_ERROR(Definition, "no object with name '" + name + "'"); } } diff --git a/extras/Hadrons/Environment.hpp b/extras/Hadrons/Environment.hpp index 0fb81250..a9c3c724 100644 --- a/extras/Hadrons/Environment.hpp +++ b/extras/Hadrons/Environment.hpp @@ -92,8 +92,6 @@ public: GridRedBlackCartesian * getRbGrid(const unsigned int Ls = 1) const; GridCartesian * getCoarseGrid(const std::vector &blockSize, const unsigned int Ls = 1) const; - GridRedBlackCartesian * getRbCoarseGrid(const std::vector &blockSize, - const unsigned int Ls = 1) const; std::vector getDim(void) const; int getDim(const unsigned int mu) const; unsigned long int getLocalVolume(void) const; @@ -166,9 +164,7 @@ private: GridRbPt gridRb4d_; std::map gridRb5d_; std::map, GridPt> gridCoarse4d_; - std::map, GridRbPt> gridCoarseRb4d_; std::map, GridPt> gridCoarse5d_; - std::map, GridRbPt> gridCoarseRb5d_; unsigned int nd_; // random number generator RngPt rng4d_; @@ -249,7 +245,7 @@ void Environment::createDerivedObject(const std::string name, (object_[address].type != &typeid(B)) or (object_[address].derivedType != &typeid(T))) { - HADRON_ERROR(Definition, "object '" + name + "' already allocated"); + HADRONS_ERROR(Definition, "object '" + name + "' already allocated"); } } @@ -283,7 +279,7 @@ T * Environment::getDerivedObject(const unsigned int address) const } else { - HADRON_ERROR(Definition, "object with address " + std::to_string(address) + + HADRONS_ERROR(Definition, "object with address " + std::to_string(address) + " cannot be casted to '" + typeName(&typeid(T)) + "' (has type '" + typeName(&typeid(h->get())) + "')"); } @@ -291,20 +287,20 @@ T * Environment::getDerivedObject(const unsigned int address) const } else { - HADRON_ERROR(Definition, "object with address " + std::to_string(address) + + HADRONS_ERROR(Definition, "object with address " + std::to_string(address) + " does not have type '" + typeName(&typeid(B)) + "' (has type '" + getObjectType(address) + "')"); } } else { - HADRON_ERROR(Definition, "object with address " + std::to_string(address) + + HADRONS_ERROR(Definition, "object with address " + std::to_string(address) + " is empty"); } } else { - HADRON_ERROR(Definition, "no object with address " + std::to_string(address)); + HADRONS_ERROR(Definition, "no object with address " + std::to_string(address)); } } @@ -342,7 +338,7 @@ bool Environment::isObjectOfType(const unsigned int address) const } else { - HADRON_ERROR(Definition, "no object with address " + std::to_string(address)); + HADRONS_ERROR(Definition, "no object with address " + std::to_string(address)); } } diff --git a/extras/Hadrons/Exceptions.cc b/extras/Hadrons/Exceptions.cc index eedc03b1..e87181b2 100644 --- a/extras/Hadrons/Exceptions.cc +++ b/extras/Hadrons/Exceptions.cc @@ -27,6 +27,8 @@ See the full license in the file "LICENSE" in the top level distribution directo /* END LEGAL */ #include +#include +#include #ifndef ERR_SUFF #define ERR_SUFF " (" + loc + ")" @@ -47,6 +49,7 @@ CONST_EXC(Definition, Logic("definition error: " + msg, loc)) CONST_EXC(Implementation, Logic("implementation error: " + msg, loc)) CONST_EXC(Range, Logic("range error: " + msg, loc)) CONST_EXC(Size, Logic("size error: " + msg, loc)) + // runtime errors CONST_EXC(Runtime, runtime_error(msg + ERR_SUFF)) CONST_EXC(Argument, Runtime("argument error: " + msg, loc)) @@ -55,3 +58,24 @@ CONST_EXC(Memory, Runtime("memory error: " + msg, loc)) CONST_EXC(Parsing, Runtime("parsing error: " + msg, loc)) CONST_EXC(Program, Runtime("program error: " + msg, loc)) CONST_EXC(System, Runtime("system error: " + msg, loc)) + +// abort functions +void Grid::Hadrons::Exceptions::abort(const std::exception& e) +{ + auto &vm = VirtualMachine::getInstance(); + int mod = vm.getCurrentModule(); + + LOG(Error) << "FATAL ERROR -- Exception " << typeName(&typeid(e)) + << std::endl; + if (mod >= 0) + { + LOG(Error) << "During execution of module '" + << vm.getModuleName(mod) << "' (address " << mod << ")" + << std::endl; + } + LOG(Error) << e.what() << std::endl; + LOG(Error) << "Aborting program" << std::endl; + Grid_finalize(); + + exit(EXIT_FAILURE); +} diff --git a/extras/Hadrons/Exceptions.hpp b/extras/Hadrons/Exceptions.hpp index ce11618a..3eb1c25f 100644 --- a/extras/Hadrons/Exceptions.hpp +++ b/extras/Hadrons/Exceptions.hpp @@ -34,10 +34,10 @@ See the full license in the file "LICENSE" in the top level distribution directo #include #endif -#define SRC_LOC std::string(__FUNCTION__) + " at " + std::string(__FILE__) + ":"\ - + std::to_string(__LINE__) -#define HADRON_ERROR(exc, msg)\ -throw(Exceptions::exc(msg, SRC_LOC)); +#define HADRONS_SRC_LOC std::string(__FUNCTION__) + " at " \ + + std::string(__FILE__) + ":" + std::to_string(__LINE__) +#define HADRONS_ERROR(exc, msg)\ +throw(Exceptions::exc(msg, HADRONS_SRC_LOC)); #define DECL_EXC(name, base) \ class name: public base\ @@ -56,6 +56,7 @@ namespace Exceptions DECL_EXC(Implementation, Logic); DECL_EXC(Range, Logic); DECL_EXC(Size, Logic); + // runtime errors DECL_EXC(Runtime, std::runtime_error); DECL_EXC(Argument, Runtime); @@ -64,6 +65,9 @@ namespace Exceptions DECL_EXC(Parsing, Runtime); DECL_EXC(Program, Runtime); DECL_EXC(System, Runtime); + + // abort functions + void abort(const std::exception& e); } END_HADRONS_NAMESPACE diff --git a/extras/Hadrons/Factory.hpp b/extras/Hadrons/Factory.hpp index 705a639e..07516640 100644 --- a/extras/Hadrons/Factory.hpp +++ b/extras/Hadrons/Factory.hpp @@ -94,7 +94,7 @@ std::unique_ptr Factory::create(const std::string type, } catch (std::out_of_range &) { - HADRON_ERROR(Argument, "object of type '" + type + "' unknown"); + HADRONS_ERROR(Argument, "object of type '" + type + "' unknown"); } return func(name); diff --git a/extras/Hadrons/GeneticScheduler.hpp b/extras/Hadrons/GeneticScheduler.hpp index d6f9bdee..83666402 100644 --- a/extras/Hadrons/GeneticScheduler.hpp +++ b/extras/Hadrons/GeneticScheduler.hpp @@ -57,7 +57,9 @@ public: virtual ~GeneticScheduler(void) = default; // access const Gene & getMinSchedule(void); - int getMinValue(void); + V getMinValue(void); + // reset population + void initPopulation(void); // breed a new generation void nextGeneration(void); // heuristic benchmarks @@ -76,8 +78,6 @@ public: return out; } private: - // evolution steps - void initPopulation(void); void doCrossover(void); void doMutation(void); // genetic operators @@ -116,7 +116,7 @@ GeneticScheduler::getMinSchedule(void) } template -int GeneticScheduler::getMinValue(void) +V GeneticScheduler::getMinValue(void) { return population_.begin()->first; } diff --git a/extras/Hadrons/Global.cc b/extras/Hadrons/Global.cc index 0164a1ab..26b74a6f 100644 --- a/extras/Hadrons/Global.cc +++ b/extras/Hadrons/Global.cc @@ -57,8 +57,8 @@ void Hadrons::initLogger(void) GridLogIterative.setChanWidth(cw); GridLogDebug.setChanWidth(cw); GridLogIRL.setChanWidth(cw); - HadronsLogError.Active(GridLogError.isActive()); - HadronsLogWarning.Active(GridLogWarning.isActive()); + HadronsLogError.Active(true); + HadronsLogWarning.Active(true); HadronsLogMessage.Active(GridLogMessage.isActive()); HadronsLogIterative.Active(GridLogIterative.isActive()); HadronsLogDebug.Active(GridLogDebug.isActive()); @@ -92,3 +92,84 @@ const std::string Hadrons::resultFileExt = "h5"; #else const std::string Hadrons::resultFileExt = "xml"; #endif + +// recursive mkdir ///////////////////////////////////////////////////////////// +int Hadrons::mkdir(const std::string dirName) +{ + if (!dirName.empty() and access(dirName.c_str(), R_OK|W_OK|X_OK)) + { + mode_t mode755; + char tmp[MAX_PATH_LENGTH]; + char *p = NULL; + size_t len; + + mode755 = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; + + snprintf(tmp, sizeof(tmp), "%s", dirName.c_str()); + len = strlen(tmp); + if(tmp[len - 1] == '/') + { + tmp[len - 1] = 0; + } + for(p = tmp + 1; *p; p++) + { + if(*p == '/') + { + *p = 0; + ::mkdir(tmp, mode755); + *p = '/'; + } + } + + return ::mkdir(tmp, mode755); + } + else + { + return 0; + } +} + +std::string Hadrons::basename(const std::string &s) +{ + constexpr char sep = '/'; + size_t i = s.rfind(sep, s.length()); + + if (i != std::string::npos) + { + return s.substr(i+1, s.length() - i); + } + else + { + return s; + } +} + +std::string Hadrons::dirname(const std::string &s) +{ + constexpr char sep = '/'; + size_t i = s.rfind(sep, s.length()); + + if (i != std::string::npos) + { + return s.substr(0, i); + } + else + { + return ""; + } +} + +void Hadrons::makeFileDir(const std::string filename, GridBase *g) +{ + if (g->IsBoss()) + { + std::string dir = dirname(filename); + int status = mkdir(dir); + + if (status) + { + HADRONS_ERROR(Io, "cannot create directory '" + dir + + "' ( " + std::strerror(errno) + ")"); + } + } +} diff --git a/extras/Hadrons/Global.hpp b/extras/Hadrons/Global.hpp index 12b9a029..72fbdf80 100644 --- a/extras/Hadrons/Global.hpp +++ b/extras/Hadrons/Global.hpp @@ -39,6 +39,10 @@ See the full license in the file "LICENSE" in the top level distribution directo #define SITE_SIZE_TYPE size_t #endif +#ifndef DEFAULT_ASCII_PREC +#define DEFAULT_ASCII_PREC 16 +#endif + #define BEGIN_HADRONS_NAMESPACE \ namespace Grid {\ using namespace QCD;\ @@ -110,7 +114,7 @@ public: }; #define LOG(channel) std::cout << HadronsLog##channel -#define DEBUG_VAR(var) LOG(Debug) << #var << "= " << (var) << std::endl; +#define HADRONS_DEBUG_VAR(var) LOG(Debug) << #var << "= " << (var) << std::endl; extern HadronsLogger HadronsLogError; extern HadronsLogger HadronsLogWarning; @@ -187,8 +191,14 @@ typedef XmlWriter ResultWriter; #define RESULT_FILE_NAME(name) \ name + "." + std::to_string(vm().getTrajectory()) + "." + resultFileExt -// default Schur convention +// recursive mkdir +#define MAX_PATH_LENGTH 512u +int mkdir(const std::string dirName); +std::string basename(const std::string &s); +std::string dirname(const std::string &s); +void makeFileDir(const std::string filename, GridBase *g); +// default Schur convention #ifndef HADRONS_DEFAULT_SCHUR #define HADRONS_DEFAULT_SCHUR DiagTwo #endif diff --git a/extras/Hadrons/Graph.hpp b/extras/Hadrons/Graph.hpp index 67694aa8..ad84e7e0 100644 --- a/extras/Hadrons/Graph.hpp +++ b/extras/Hadrons/Graph.hpp @@ -184,7 +184,7 @@ void Graph::removeVertex(const T &value) } else { - HADRON_ERROR(Range, "vertex does not exists"); + HADRONS_ERROR(Range, "vertex does not exists"); } // remove all edges containing the vertex @@ -213,7 +213,7 @@ void Graph::removeEdge(const Edge &e) } else { - HADRON_ERROR(Range, "edge does not exists"); + HADRONS_ERROR(Range, "edge does not exists"); } } @@ -259,7 +259,7 @@ void Graph::mark(const T &value, const bool doMark) } else { - HADRON_ERROR(Range, "vertex does not exists"); + HADRONS_ERROR(Range, "vertex does not exists"); } } @@ -297,7 +297,7 @@ bool Graph::isMarked(const T &value) const } else { - HADRON_ERROR(Range, "vertex does not exists"); + HADRONS_ERROR(Range, "vertex does not exists"); return false; } @@ -543,7 +543,7 @@ std::vector Graph::topoSort(void) { if (tmpMarked.at(v)) { - HADRON_ERROR(Range, "cannot topologically sort a cyclic graph"); + HADRONS_ERROR(Range, "cannot topologically sort a cyclic graph"); } if (!isMarked(v)) { @@ -602,7 +602,7 @@ std::vector Graph::topoSort(Gen &gen) { if (tmpMarked.at(v)) { - HADRON_ERROR(Range, "cannot topologically sort a cyclic graph"); + HADRONS_ERROR(Range, "cannot topologically sort a cyclic graph"); } if (!isMarked(v)) { diff --git a/extras/Hadrons/HadronsXmlRun.cc b/extras/Hadrons/HadronsXmlRun.cc index 4fcfabf2..6b613bb4 100644 --- a/extras/Hadrons/HadronsXmlRun.cc +++ b/extras/Hadrons/HadronsXmlRun.cc @@ -69,12 +69,7 @@ int main(int argc, char *argv[]) } catch (const std::exception& e) { - LOG(Error) << "FATAL ERROR -- Exception " << typeName(&typeid(e)) << std::endl; - LOG(Error) << e.what() << std::endl; - LOG(Error) << "Aborting program" << std::endl; - Grid_finalize(); - - return EXIT_FAILURE; + Exceptions::abort(e); } // epilogue diff --git a/extras/Hadrons/Module.cc b/extras/Hadrons/Module.cc index 54978f93..faf01d5a 100644 --- a/extras/Hadrons/Module.cc +++ b/extras/Hadrons/Module.cc @@ -49,7 +49,7 @@ std::string ModuleBase::getName(void) const // get factory registration name if available std::string ModuleBase::getRegisteredName(void) { - HADRON_ERROR(Definition, "module '" + getName() + "' has no registered type" + HADRONS_ERROR(Definition, "module '" + getName() + "' has no registered type" + " in the factory"); } diff --git a/extras/Hadrons/Module.hpp b/extras/Hadrons/Module.hpp index 85c27472..2726da96 100644 --- a/extras/Hadrons/Module.hpp +++ b/extras/Hadrons/Module.hpp @@ -35,32 +35,7 @@ See the full license in the file "LICENSE" in the top level distribution directo BEGIN_HADRONS_NAMESPACE // module registration macros -#define MODULE_REGISTER(mod, base)\ -class mod: public base\ -{\ -public:\ - typedef base Base;\ - using Base::Base;\ - virtual std::string getRegisteredName(void)\ - {\ - return std::string(#mod);\ - }\ -};\ -class mod##ModuleRegistrar\ -{\ -public:\ - mod##ModuleRegistrar(void)\ - {\ - ModuleFactory &modFac = ModuleFactory::getInstance();\ - modFac.registerBuilder(#mod, [&](const std::string name)\ - {\ - return std::unique_ptr(new mod(name));\ - });\ - }\ -};\ -static mod##ModuleRegistrar mod##ModuleRegistrarInstance; - -#define MODULE_REGISTER_NS(mod, base, ns)\ +#define MODULE_REGISTER(mod, base, ns)\ class mod: public base\ {\ public:\ @@ -85,6 +60,10 @@ public:\ };\ static ns##mod##ModuleRegistrar ns##mod##ModuleRegistrarInstance; +#define MODULE_REGISTER_TMP(mod, base, ns)\ +extern template class base;\ +MODULE_REGISTER(mod, ARG(base), ns); + #define ARG(...) __VA_ARGS__ #define MACRO_REDIRECT(arg1, arg2, arg3, macro, ...) macro @@ -141,10 +120,13 @@ envTmp(type, name, Ls, env().getGrid(Ls)) MACRO_REDIRECT(__VA_ARGS__, envTmpLat5, envTmpLat4)(__VA_ARGS__) #define saveResult(ioStem, name, result)\ -if (env().getGrid()->IsBoss())\ +if (env().getGrid()->IsBoss() and !ioStem.empty())\ {\ - ResultWriter _writer(RESULT_FILE_NAME(ioStem));\ - write(_writer, name, result);\ + makeFileDir(ioStem, env().getGrid());\ + {\ + ResultWriter _writer(RESULT_FILE_NAME(ioStem));\ + write(_writer, name, result);\ + }\ } /****************************************************************************** @@ -172,6 +154,8 @@ public: // parse parameters virtual void parseParameters(XmlReader &reader, const std::string name) = 0; virtual void saveParameters(XmlWriter &writer, const std::string name) = 0; + // parameter string + virtual std::string parString(void) const = 0; // setup virtual void setup(void) {}; virtual void execute(void) = 0; @@ -200,9 +184,11 @@ public: // parse parameters virtual void parseParameters(XmlReader &reader, const std::string name); virtual void saveParameters(XmlWriter &writer, const std::string name); + // parameter string + virtual std::string parString(void) const; // parameter access - const P & par(void) const; - void setPar(const P &par); + const P & par(void) const; + void setPar(const P &par); private: P par_; }; @@ -225,6 +211,8 @@ public: push(writer, "options"); pop(writer); }; + // parameter string (empty) + virtual std::string parString(void) const {return "";}; }; /****************************************************************************** @@ -247,6 +235,16 @@ void Module

::saveParameters(XmlWriter &writer, const std::string name) write(writer, name, par_); } +template +std::string Module

::parString(void) const +{ + XmlWriter writer("", ""); + + write(writer, par_.SerialisableClassName(), par_); + + return writer.string(); +} + template const P & Module

::par(void) const { diff --git a/extras/Hadrons/Modules.hpp b/extras/Hadrons/Modules.hpp index 400c4c8c..d333455c 100644 --- a/extras/Hadrons/Modules.hpp +++ b/extras/Hadrons/Modules.hpp @@ -1,33 +1,3 @@ -/************************************************************************************* - -Grid physics library, www.github.com/paboyle/Grid - -Source file: extras/Hadrons/Modules.hpp - -Copyright (C) 2015-2018 - -Author: Antonin Portelli -Author: Guido Cossu -Author: Lanny91 -Author: pretidav - -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 #include #include @@ -64,14 +34,18 @@ See the full license in the file "LICENSE" in the top level distribution directo #include #include #include +#include +#include #include #include +#include #include #include #include #include #include #include +#include #include #include #include diff --git a/extras/Hadrons/Modules/MAction/DWF.cc b/extras/Hadrons/Modules/MAction/DWF.cc new file mode 100644 index 00000000..ae518018 --- /dev/null +++ b/extras/Hadrons/Modules/MAction/DWF.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MAction/DWF.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MAction; + +template class Grid::Hadrons::MAction::TDWF; + diff --git a/extras/Hadrons/Modules/MAction/DWF.hpp b/extras/Hadrons/Modules/MAction/DWF.hpp index 4dfd06cf..f0dda4b0 100644 --- a/extras/Hadrons/Modules/MAction/DWF.hpp +++ b/extras/Hadrons/Modules/MAction/DWF.hpp @@ -61,7 +61,7 @@ public: // constructor TDWF(const std::string name); // destructor - virtual ~TDWF(void) = default; + virtual ~TDWF(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -72,7 +72,8 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(DWF, TDWF, MAction); +extern template class TDWF; +MODULE_REGISTER_TMP(DWF, TDWF, MAction); /****************************************************************************** * DWF template implementation * diff --git a/extras/Hadrons/Modules/MAction/Wilson.cc b/extras/Hadrons/Modules/MAction/Wilson.cc new file mode 100644 index 00000000..11924d5a --- /dev/null +++ b/extras/Hadrons/Modules/MAction/Wilson.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MAction/Wilson.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MAction; + +template class Grid::Hadrons::MAction::TWilson; + diff --git a/extras/Hadrons/Modules/MAction/Wilson.hpp b/extras/Hadrons/Modules/MAction/Wilson.hpp index 6467b3ee..1a119571 100644 --- a/extras/Hadrons/Modules/MAction/Wilson.hpp +++ b/extras/Hadrons/Modules/MAction/Wilson.hpp @@ -59,7 +59,7 @@ public: // constructor TWilson(const std::string name); // destructor - virtual ~TWilson(void) = default; + virtual ~TWilson(void) {}; // dependencies/products virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -70,7 +70,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Wilson, TWilson, MAction); +MODULE_REGISTER_TMP(Wilson, TWilson, MAction); /****************************************************************************** * TWilson template implementation * diff --git a/extras/Hadrons/Modules/MAction/WilsonClover.cc b/extras/Hadrons/Modules/MAction/WilsonClover.cc new file mode 100644 index 00000000..77099044 --- /dev/null +++ b/extras/Hadrons/Modules/MAction/WilsonClover.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MAction/WilsonClover.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MAction; + +template class Grid::Hadrons::MAction::TWilsonClover; + diff --git a/extras/Hadrons/Modules/MAction/WilsonClover.hpp b/extras/Hadrons/Modules/MAction/WilsonClover.hpp index 2967931c..ead3accc 100644 --- a/extras/Hadrons/Modules/MAction/WilsonClover.hpp +++ b/extras/Hadrons/Modules/MAction/WilsonClover.hpp @@ -64,7 +64,7 @@ public: // constructor TWilsonClover(const std::string name); // destructor - virtual ~TWilsonClover(void) = default; + virtual ~TWilsonClover(void) {}; // dependencies/products virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -74,7 +74,7 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(WilsonClover, TWilsonClover, MAction); +MODULE_REGISTER_TMP(WilsonClover, TWilsonClover, MAction); /****************************************************************************** * TWilsonClover template implementation * diff --git a/extras/Hadrons/Modules/MAction/ZMobiusDWF.cc b/extras/Hadrons/Modules/MAction/ZMobiusDWF.cc new file mode 100644 index 00000000..7a49c120 --- /dev/null +++ b/extras/Hadrons/Modules/MAction/ZMobiusDWF.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MAction/ZMobiusDWF.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MAction; + +template class Grid::Hadrons::MAction::TZMobiusDWF; + diff --git a/extras/Hadrons/Modules/MAction/ZMobiusDWF.hpp b/extras/Hadrons/Modules/MAction/ZMobiusDWF.hpp index 518b88f2..52e65322 100644 --- a/extras/Hadrons/Modules/MAction/ZMobiusDWF.hpp +++ b/extras/Hadrons/Modules/MAction/ZMobiusDWF.hpp @@ -62,7 +62,7 @@ public: // constructor TZMobiusDWF(const std::string name); // destructor - virtual ~TZMobiusDWF(void) = default; + virtual ~TZMobiusDWF(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -72,7 +72,7 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(ZMobiusDWF, TZMobiusDWF, MAction); +MODULE_REGISTER_TMP(ZMobiusDWF, TZMobiusDWF, MAction); /****************************************************************************** * TZMobiusDWF implementation * diff --git a/extras/Hadrons/Modules/MContraction/Baryon.cc b/extras/Hadrons/Modules/MContraction/Baryon.cc new file mode 100644 index 00000000..7daf5008 --- /dev/null +++ b/extras/Hadrons/Modules/MContraction/Baryon.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MContraction/Baryon.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MContraction; + +template class Grid::Hadrons::MContraction::TBaryon; + diff --git a/extras/Hadrons/Modules/MContraction/Baryon.hpp b/extras/Hadrons/Modules/MContraction/Baryon.hpp index f3bf360d..654706c6 100644 --- a/extras/Hadrons/Modules/MContraction/Baryon.hpp +++ b/extras/Hadrons/Modules/MContraction/Baryon.hpp @@ -68,7 +68,7 @@ public: // constructor TBaryon(const std::string name); // destructor - virtual ~TBaryon(void) = default; + virtual ~TBaryon(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -79,7 +79,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Baryon, ARG(TBaryon), MContraction); +MODULE_REGISTER_TMP(Baryon, ARG(TBaryon), MContraction); /****************************************************************************** * TBaryon implementation * diff --git a/extras/Hadrons/Modules/MContraction/DiscLoop.cc b/extras/Hadrons/Modules/MContraction/DiscLoop.cc new file mode 100644 index 00000000..8c7a72ee --- /dev/null +++ b/extras/Hadrons/Modules/MContraction/DiscLoop.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MContraction/DiscLoop.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MContraction; + +template class Grid::Hadrons::MContraction::TDiscLoop; + diff --git a/extras/Hadrons/Modules/MContraction/DiscLoop.hpp b/extras/Hadrons/Modules/MContraction/DiscLoop.hpp index 4a30963f..ea3d3d2f 100644 --- a/extras/Hadrons/Modules/MContraction/DiscLoop.hpp +++ b/extras/Hadrons/Modules/MContraction/DiscLoop.hpp @@ -65,7 +65,7 @@ public: // constructor TDiscLoop(const std::string name); // destructor - virtual ~TDiscLoop(void) = default; + virtual ~TDiscLoop(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -76,7 +76,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(DiscLoop, TDiscLoop, MContraction); +MODULE_REGISTER_TMP(DiscLoop, TDiscLoop, MContraction); /****************************************************************************** * TDiscLoop implementation * diff --git a/extras/Hadrons/Modules/MContraction/Gamma3pt.cc b/extras/Hadrons/Modules/MContraction/Gamma3pt.cc new file mode 100644 index 00000000..13e911bb --- /dev/null +++ b/extras/Hadrons/Modules/MContraction/Gamma3pt.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MContraction/Gamma3pt.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MContraction; + +template class Grid::Hadrons::MContraction::TGamma3pt; + diff --git a/extras/Hadrons/Modules/MContraction/Gamma3pt.hpp b/extras/Hadrons/Modules/MContraction/Gamma3pt.hpp index b615cd7b..e30845bc 100644 --- a/extras/Hadrons/Modules/MContraction/Gamma3pt.hpp +++ b/extras/Hadrons/Modules/MContraction/Gamma3pt.hpp @@ -96,7 +96,7 @@ public: // constructor TGamma3pt(const std::string name); // destructor - virtual ~TGamma3pt(void) = default; + virtual ~TGamma3pt(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -107,7 +107,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Gamma3pt, ARG(TGamma3pt), MContraction); +MODULE_REGISTER_TMP(Gamma3pt, ARG(TGamma3pt), MContraction); /****************************************************************************** * TGamma3pt implementation * diff --git a/extras/Hadrons/Modules/MContraction/Meson.cc b/extras/Hadrons/Modules/MContraction/Meson.cc new file mode 100644 index 00000000..3b880705 --- /dev/null +++ b/extras/Hadrons/Modules/MContraction/Meson.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MContraction/Meson.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MContraction; + +template class Grid::Hadrons::MContraction::TMeson; + diff --git a/extras/Hadrons/Modules/MContraction/Meson.hpp b/extras/Hadrons/Modules/MContraction/Meson.hpp index 5d27c526..036247e2 100644 --- a/extras/Hadrons/Modules/MContraction/Meson.hpp +++ b/extras/Hadrons/Modules/MContraction/Meson.hpp @@ -90,7 +90,7 @@ public: // constructor TMeson(const std::string name); // destructor - virtual ~TMeson(void) = default; + virtual ~TMeson(void) {}; // dependencies/products virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -102,7 +102,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Meson, ARG(TMeson), MContraction); +MODULE_REGISTER_TMP(Meson, ARG(TMeson), MContraction); /****************************************************************************** * TMeson implementation * diff --git a/extras/Hadrons/Modules/MContraction/WardIdentity.cc b/extras/Hadrons/Modules/MContraction/WardIdentity.cc new file mode 100644 index 00000000..8b5cc2e3 --- /dev/null +++ b/extras/Hadrons/Modules/MContraction/WardIdentity.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MContraction/WardIdentity.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MContraction; + +template class Grid::Hadrons::MContraction::TWardIdentity; + diff --git a/extras/Hadrons/Modules/MContraction/WardIdentity.hpp b/extras/Hadrons/Modules/MContraction/WardIdentity.hpp index 2801d88c..e529d7a2 100644 --- a/extras/Hadrons/Modules/MContraction/WardIdentity.hpp +++ b/extras/Hadrons/Modules/MContraction/WardIdentity.hpp @@ -71,7 +71,7 @@ public: // constructor TWardIdentity(const std::string name); // destructor - virtual ~TWardIdentity(void) = default; + virtual ~TWardIdentity(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -84,7 +84,7 @@ private: unsigned int Ls_; }; -MODULE_REGISTER_NS(WardIdentity, TWardIdentity, MContraction); +MODULE_REGISTER_TMP(WardIdentity, TWardIdentity, MContraction); /****************************************************************************** * TWardIdentity implementation * @@ -119,7 +119,7 @@ void TWardIdentity::setup(void) Ls_ = env().getObjectLs(par().q); if (Ls_ != env().getObjectLs(par().action)) { - HADRON_ERROR(Size, "Ls mismatch between quark action and propagator"); + HADRONS_ERROR(Size, "Ls mismatch between quark action and propagator"); } envTmpLat(PropagatorField, "tmp"); envTmpLat(PropagatorField, "vector_WI"); diff --git a/extras/Hadrons/Modules/MContraction/WeakHamiltonian.hpp b/extras/Hadrons/Modules/MContraction/WeakHamiltonian.hpp index 9d8ada98..507e8cdb 100644 --- a/extras/Hadrons/Modules/MContraction/WeakHamiltonian.hpp +++ b/extras/Hadrons/Modules/MContraction/WeakHamiltonian.hpp @@ -97,7 +97,7 @@ public:\ /* constructor */ \ T##modname(const std::string name);\ /* destructor */ \ - virtual ~T##modname(void) = default;\ + virtual ~T##modname(void) {};\ /* dependency relation */ \ virtual std::vector getInput(void);\ virtual std::vector getOutput(void);\ @@ -109,7 +109,7 @@ protected:\ /* execution */ \ virtual void execute(void);\ };\ -MODULE_REGISTER_NS(modname, T##modname, MContraction); +MODULE_REGISTER(modname, T##modname, MContraction); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MFermion/GaugeProp.cc b/extras/Hadrons/Modules/MFermion/GaugeProp.cc new file mode 100644 index 00000000..8db69495 --- /dev/null +++ b/extras/Hadrons/Modules/MFermion/GaugeProp.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MFermion/GaugeProp.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MFermion; + +template class Grid::Hadrons::MFermion::TGaugeProp; + diff --git a/extras/Hadrons/Modules/MFermion/GaugeProp.hpp b/extras/Hadrons/Modules/MFermion/GaugeProp.hpp index 45b9de6c..ee21cba9 100644 --- a/extras/Hadrons/Modules/MFermion/GaugeProp.hpp +++ b/extras/Hadrons/Modules/MFermion/GaugeProp.hpp @@ -81,7 +81,7 @@ public: // constructor TGaugeProp(const std::string name); // destructor - virtual ~TGaugeProp(void) = default; + virtual ~TGaugeProp(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -95,7 +95,7 @@ private: SolverFn *solver_{nullptr}; }; -MODULE_REGISTER_NS(GaugeProp, TGaugeProp, MFermion); +MODULE_REGISTER_TMP(GaugeProp, TGaugeProp, MFermion); /****************************************************************************** * TGaugeProp implementation * ******************************************************************************/ @@ -177,7 +177,7 @@ void TGaugeProp::execute(void) { if (Ls_ != env().getObjectLs(par().source)) { - HADRON_ERROR(Size, "Ls mismatch between quark action and source"); + HADRONS_ERROR(Size, "Ls mismatch between quark action and source"); } else { diff --git a/extras/Hadrons/Modules/MGauge/FundtoHirep.cc b/extras/Hadrons/Modules/MGauge/FundtoHirep.cc index ba8e9330..824ee8c8 100644 --- a/extras/Hadrons/Modules/MGauge/FundtoHirep.cc +++ b/extras/Hadrons/Modules/MGauge/FundtoHirep.cc @@ -4,9 +4,11 @@ Grid physics library, www.github.com/paboyle/Grid Source file: extras/Hadrons/Modules/MGauge/FundtoHirep.cc -Copyright (C) 2015 -Copyright (C) 2016 +Copyright (C) 2015-2018 +Author: Antonin Portelli +Author: Guido Cossu +Author: pretidav 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 diff --git a/extras/Hadrons/Modules/MGauge/FundtoHirep.hpp b/extras/Hadrons/Modules/MGauge/FundtoHirep.hpp index 508145bc..3a3a83e5 100644 --- a/extras/Hadrons/Modules/MGauge/FundtoHirep.hpp +++ b/extras/Hadrons/Modules/MGauge/FundtoHirep.hpp @@ -55,7 +55,7 @@ public: // constructor TFundtoHirep(const std::string name); // destructor - virtual ~TFundtoHirep(void) = default; + virtual ~TFundtoHirep(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -65,9 +65,9 @@ public: void execute(void); }; -//MODULE_REGISTER_NS(FundtoAdjoint, TFundtoHirep, MGauge); -//MODULE_REGISTER_NS(FundtoTwoIndexSym, TFundtoHirep, MGauge); -//MODULE_REGISTER_NS(FundtoTwoIndexAsym, TFundtoHirep, MGauge); +//MODULE_REGISTER_TMP(FundtoAdjoint, TFundtoHirep, MGauge); +//MODULE_REGISTER_TMP(FundtoTwoIndexSym, TFundtoHirep, MGauge); +//MODULE_REGISTER_TMP(FundtoTwoIndexAsym, TFundtoHirep, MGauge); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MGauge/Random.hpp b/extras/Hadrons/Modules/MGauge/Random.hpp index 51a08dbb..13d0e478 100644 --- a/extras/Hadrons/Modules/MGauge/Random.hpp +++ b/extras/Hadrons/Modules/MGauge/Random.hpp @@ -46,7 +46,7 @@ public: // constructor TRandom(const std::string name); // destructor - virtual ~TRandom(void) = default; + virtual ~TRandom(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -57,7 +57,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Random, TRandom, MGauge); +MODULE_REGISTER(Random, TRandom, MGauge); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MGauge/StochEm.cc b/extras/Hadrons/Modules/MGauge/StochEm.cc index fec64699..1727706c 100644 --- a/extras/Hadrons/Modules/MGauge/StochEm.cc +++ b/extras/Hadrons/Modules/MGauge/StochEm.cc @@ -7,6 +7,8 @@ Source file: extras/Hadrons/Modules/MGauge/StochEm.cc Copyright (C) 2015-2018 Author: Antonin Portelli +Author: James Harrison +Author: Vera Guelpers 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 diff --git a/extras/Hadrons/Modules/MGauge/StochEm.hpp b/extras/Hadrons/Modules/MGauge/StochEm.hpp index fc09a0ee..5eb9f1e9 100644 --- a/extras/Hadrons/Modules/MGauge/StochEm.hpp +++ b/extras/Hadrons/Modules/MGauge/StochEm.hpp @@ -7,6 +7,7 @@ Source file: extras/Hadrons/Modules/MGauge/StochEm.hpp Copyright (C) 2015-2018 Author: Antonin Portelli +Author: James Harrison Author: Vera Guelpers This program is free software; you can redistribute it and/or modify @@ -59,7 +60,7 @@ public: // constructor TStochEm(const std::string name); // destructor - virtual ~TStochEm(void) = default; + virtual ~TStochEm(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -72,7 +73,7 @@ private: bool weightDone_; }; -MODULE_REGISTER_NS(StochEm, TStochEm, MGauge); +MODULE_REGISTER(StochEm, TStochEm, MGauge); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MGauge/Unit.hpp b/extras/Hadrons/Modules/MGauge/Unit.hpp index d6ce5a6b..8bdb7ef3 100644 --- a/extras/Hadrons/Modules/MGauge/Unit.hpp +++ b/extras/Hadrons/Modules/MGauge/Unit.hpp @@ -46,7 +46,7 @@ public: // constructor TUnit(const std::string name); // destructor - virtual ~TUnit(void) = default; + virtual ~TUnit(void) {}; // dependencies/products virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -57,7 +57,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Unit, TUnit, MGauge); +MODULE_REGISTER(Unit, TUnit, MGauge); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MGauge/UnitEm.cc b/extras/Hadrons/Modules/MGauge/UnitEm.cc index e5536d7a..6260f10a 100644 --- a/extras/Hadrons/Modules/MGauge/UnitEm.cc +++ b/extras/Hadrons/Modules/MGauge/UnitEm.cc @@ -7,6 +7,7 @@ Source file: extras/Hadrons/Modules/MGauge/StochEm.cc Copyright (C) 2015 Copyright (C) 2016 +Author: James Harrison 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 diff --git a/extras/Hadrons/Modules/MGauge/UnitEm.hpp b/extras/Hadrons/Modules/MGauge/UnitEm.hpp index 1df45d4a..94214274 100644 --- a/extras/Hadrons/Modules/MGauge/UnitEm.hpp +++ b/extras/Hadrons/Modules/MGauge/UnitEm.hpp @@ -7,6 +7,7 @@ Source file: extras/Hadrons/Modules/MGauge/StochEm.hpp Copyright (C) 2015 Copyright (C) 2016 +Author: James Harrison 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 diff --git a/extras/Hadrons/Modules/MIO/LoadBinary.cc b/extras/Hadrons/Modules/MIO/LoadBinary.cc new file mode 100644 index 00000000..f04df9df --- /dev/null +++ b/extras/Hadrons/Modules/MIO/LoadBinary.cc @@ -0,0 +1,40 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MIO/LoadBinary.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MIO; + +template class Grid::Hadrons::MIO::TLoadBinary; +template class Grid::Hadrons::MIO::TLoadBinary>; +template class Grid::Hadrons::MIO::TLoadBinary>; +template class Grid::Hadrons::MIO::TLoadBinary>; +template class Grid::Hadrons::MIO::TLoadBinary>; +template class Grid::Hadrons::MIO::TLoadBinary>; + diff --git a/extras/Hadrons/Modules/MIO/LoadBinary.hpp b/extras/Hadrons/Modules/MIO/LoadBinary.hpp index d9a8b5f8..b2070bef 100644 --- a/extras/Hadrons/Modules/MIO/LoadBinary.hpp +++ b/extras/Hadrons/Modules/MIO/LoadBinary.hpp @@ -61,7 +61,7 @@ public: // constructor TLoadBinary(const std::string name); // destructor - virtual ~TLoadBinary(void) = default; + virtual ~TLoadBinary(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -71,12 +71,12 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(LoadBinary, TLoadBinary, MIO); -MODULE_REGISTER_NS(LoadBinaryScalarSU2, TLoadBinary>, MIO); -MODULE_REGISTER_NS(LoadBinaryScalarSU3, TLoadBinary>, MIO); -MODULE_REGISTER_NS(LoadBinaryScalarSU4, TLoadBinary>, MIO); -MODULE_REGISTER_NS(LoadBinaryScalarSU5, TLoadBinary>, MIO); -MODULE_REGISTER_NS(LoadBinaryScalarSU6, TLoadBinary>, MIO); +MODULE_REGISTER_TMP(LoadBinary, TLoadBinary, MIO); +MODULE_REGISTER_TMP(LoadBinaryScalarSU2, TLoadBinary>, MIO); +MODULE_REGISTER_TMP(LoadBinaryScalarSU3, TLoadBinary>, MIO); +MODULE_REGISTER_TMP(LoadBinaryScalarSU4, TLoadBinary>, MIO); +MODULE_REGISTER_TMP(LoadBinaryScalarSU5, TLoadBinary>, MIO); +MODULE_REGISTER_TMP(LoadBinaryScalarSU6, TLoadBinary>, MIO); /****************************************************************************** * TLoadBinary implementation * diff --git a/extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.cc b/extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.cc new file mode 100644 index 00000000..0ed7643c --- /dev/null +++ b/extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MIO; + +template class Grid::Hadrons::MIO::TLoadCoarseEigenPack>; + diff --git a/extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.hpp b/extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.hpp index 77c3a7ee..945b6751 100644 --- a/extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.hpp +++ b/extras/Hadrons/Modules/MIO/LoadCoarseEigenPack.hpp @@ -45,6 +45,7 @@ class LoadCoarseEigenPackPar: Serializable public: GRID_SERIALIZABLE_CLASS_MEMBERS(LoadCoarseEigenPackPar, std::string, filestem, + bool, multiFile, unsigned int, sizeFine, unsigned int, sizeCoarse, unsigned int, Ls, @@ -56,11 +57,14 @@ class TLoadCoarseEigenPack: public Module { public: typedef CoarseEigenPack BasePack; + template + using iImplScalar = iScalar>>; + typedef iImplScalar SiteComplex; public: // constructor TLoadCoarseEigenPack(const std::string name); // destructor - virtual ~TLoadCoarseEigenPack(void) = default; + virtual ~TLoadCoarseEigenPack(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -70,8 +74,7 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(LoadCoarseFermionEigenPack, - ARG(TLoadCoarseEigenPack>), MIO); +MODULE_REGISTER_TMP(LoadCoarseFermionEigenPack, ARG(TLoadCoarseEigenPack>), MIO); /****************************************************************************** * TLoadCoarseEigenPack implementation * @@ -114,9 +117,15 @@ void TLoadCoarseEigenPack::setup(void) template void TLoadCoarseEigenPack::execute(void) { - auto &epack = envGetDerived(BasePack, Pack, getName()); + auto cg = env().getCoarseGrid(par().blockSize, par().Ls); + auto &epack = envGetDerived(BasePack, Pack, getName()); + Lattice dummy(cg); - epack.read(par().filestem, vm().getTrajectory()); + epack.read(par().filestem, par().multiFile, vm().getTrajectory()); + LOG(Message) << "Block Gramm-Schmidt pass 1"<< std::endl; + blockOrthogonalise(dummy, epack.evec); + LOG(Message) << "Block Gramm-Schmidt pass 2"<< std::endl; + blockOrthogonalise(dummy, epack.evec); } END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MIO/LoadEigenPack.cc b/extras/Hadrons/Modules/MIO/LoadEigenPack.cc new file mode 100644 index 00000000..5b7aebc3 --- /dev/null +++ b/extras/Hadrons/Modules/MIO/LoadEigenPack.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MIO/LoadEigenPack.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MIO; + +template class Grid::Hadrons::MIO::TLoadEigenPack>; + diff --git a/extras/Hadrons/Modules/MIO/LoadEigenPack.hpp b/extras/Hadrons/Modules/MIO/LoadEigenPack.hpp index bcc3f22b..fcad4107 100644 --- a/extras/Hadrons/Modules/MIO/LoadEigenPack.hpp +++ b/extras/Hadrons/Modules/MIO/LoadEigenPack.hpp @@ -45,6 +45,7 @@ class LoadEigenPackPar: Serializable public: GRID_SERIALIZABLE_CLASS_MEMBERS(LoadEigenPackPar, std::string, filestem, + bool, multiFile, unsigned int, size, unsigned int, Ls); }; @@ -58,7 +59,7 @@ public: // constructor TLoadEigenPack(const std::string name); // destructor - virtual ~TLoadEigenPack(void) = default; + virtual ~TLoadEigenPack(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -68,7 +69,7 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(LoadFermionEigenPack, TLoadEigenPack>, MIO); +MODULE_REGISTER_TMP(LoadFermionEigenPack, TLoadEigenPack>, MIO); /****************************************************************************** * TLoadEigenPack implementation * @@ -111,7 +112,8 @@ void TLoadEigenPack::execute(void) { auto &epack = envGetDerived(BasePack, Pack, getName()); - epack.read(par().filestem, vm().getTrajectory()); + epack.read(par().filestem, par().multiFile, vm().getTrajectory()); + epack.eval.resize(par().size); } END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MIO/LoadNersc.hpp b/extras/Hadrons/Modules/MIO/LoadNersc.hpp index d6742e1e..11b86eec 100644 --- a/extras/Hadrons/Modules/MIO/LoadNersc.hpp +++ b/extras/Hadrons/Modules/MIO/LoadNersc.hpp @@ -52,7 +52,7 @@ public: // constructor TLoadNersc(const std::string name); // destructor - virtual ~TLoadNersc(void) = default; + virtual ~TLoadNersc(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -62,7 +62,7 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(LoadNersc, TLoadNersc, MIO); +MODULE_REGISTER(LoadNersc, TLoadNersc, MIO); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MLoop/NoiseLoop.cc b/extras/Hadrons/Modules/MLoop/NoiseLoop.cc new file mode 100644 index 00000000..5c510afd --- /dev/null +++ b/extras/Hadrons/Modules/MLoop/NoiseLoop.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MLoop/NoiseLoop.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MLoop; + +template class Grid::Hadrons::MLoop::TNoiseLoop; + diff --git a/extras/Hadrons/Modules/MLoop/NoiseLoop.hpp b/extras/Hadrons/Modules/MLoop/NoiseLoop.hpp index e61bf163..3ce9353d 100644 --- a/extras/Hadrons/Modules/MLoop/NoiseLoop.hpp +++ b/extras/Hadrons/Modules/MLoop/NoiseLoop.hpp @@ -71,7 +71,7 @@ public: // constructor TNoiseLoop(const std::string name); // destructor - virtual ~TNoiseLoop(void) = default; + virtual ~TNoiseLoop(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -82,7 +82,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(NoiseLoop, TNoiseLoop, MLoop); +MODULE_REGISTER_TMP(NoiseLoop, TNoiseLoop, MLoop); /****************************************************************************** * TNoiseLoop implementation * diff --git a/extras/Hadrons/Modules/MScalar/ChargedProp.hpp b/extras/Hadrons/Modules/MScalar/ChargedProp.hpp index baa8c20f..3ca7940f 100644 --- a/extras/Hadrons/Modules/MScalar/ChargedProp.hpp +++ b/extras/Hadrons/Modules/MScalar/ChargedProp.hpp @@ -7,6 +7,7 @@ Source file: extras/Hadrons/Modules/MScalar/ChargedProp.hpp Copyright (C) 2015-2018 Author: Antonin Portelli +Author: James Harrison 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 @@ -81,7 +82,7 @@ public: // constructor TChargedProp(const std::string name); // destructor - virtual ~TChargedProp(void) = default; + virtual ~TChargedProp(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -103,7 +104,7 @@ private: std::vector phase_; }; -MODULE_REGISTER_NS(ChargedProp, TChargedProp, MScalar); +MODULE_REGISTER(ChargedProp, TChargedProp, MScalar); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MScalar/FreeProp.hpp b/extras/Hadrons/Modules/MScalar/FreeProp.hpp index df17f44e..50f4ba52 100644 --- a/extras/Hadrons/Modules/MScalar/FreeProp.hpp +++ b/extras/Hadrons/Modules/MScalar/FreeProp.hpp @@ -56,7 +56,7 @@ public: // constructor TFreeProp(const std::string name); // destructor - virtual ~TFreeProp(void) = default; + virtual ~TFreeProp(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -70,7 +70,7 @@ private: bool freePropDone_; }; -MODULE_REGISTER_NS(FreeProp, TFreeProp, MScalar); +MODULE_REGISTER(FreeProp, TFreeProp, MScalar); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MScalarSUN/Div.cc b/extras/Hadrons/Modules/MScalarSUN/Div.cc new file mode 100644 index 00000000..6a2e366d --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/Div.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/Div.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TDiv>; +template class Grid::Hadrons::MScalarSUN::TDiv>; +template class Grid::Hadrons::MScalarSUN::TDiv>; +template class Grid::Hadrons::MScalarSUN::TDiv>; +template class Grid::Hadrons::MScalarSUN::TDiv>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/Div.hpp b/extras/Hadrons/Modules/MScalarSUN/Div.hpp index 0ecb1dbe..ff26c60b 100644 --- a/extras/Hadrons/Modules/MScalarSUN/Div.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/Div.hpp @@ -49,24 +49,25 @@ public: std::string, output); }; +class DivResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(DivResult, + DiffType, type, + Complex, value); +}; + template class TDiv: public Module { public: typedef typename SImpl::Field Field; typedef typename SImpl::ComplexField ComplexField; - class Result: Serializable - { - public: - GRID_SERIALIZABLE_CLASS_MEMBERS(Result, - DiffType, type, - Complex, value); - }; public: // constructor TDiv(const std::string name); // destructor - virtual ~TDiv(void) = default; + virtual ~TDiv(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -76,11 +77,11 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(DivSU2, TDiv>, MScalarSUN); -MODULE_REGISTER_NS(DivSU3, TDiv>, MScalarSUN); -MODULE_REGISTER_NS(DivSU4, TDiv>, MScalarSUN); -MODULE_REGISTER_NS(DivSU5, TDiv>, MScalarSUN); -MODULE_REGISTER_NS(DivSU6, TDiv>, MScalarSUN); +MODULE_REGISTER_TMP(DivSU2, TDiv>, MScalarSUN); +MODULE_REGISTER_TMP(DivSU3, TDiv>, MScalarSUN); +MODULE_REGISTER_TMP(DivSU4, TDiv>, MScalarSUN); +MODULE_REGISTER_TMP(DivSU5, TDiv>, MScalarSUN); +MODULE_REGISTER_TMP(DivSU6, TDiv>, MScalarSUN); /****************************************************************************** * TDiv implementation * @@ -112,7 +113,7 @@ void TDiv::setup(void) { if (par().op.size() != env().getNd()) { - HADRON_ERROR(Size, "the number of components differs from number of dimensions"); + HADRONS_ERROR(Size, "the number of components differs from number of dimensions"); } envCreateLat(ComplexField, getName()); } @@ -126,7 +127,7 @@ void TDiv::execute(void) LOG(Message) << "Computing the " << par().type << " divergence of ["; for (unsigned int mu = 0; mu < nd; ++mu) { - std::cout << par().op[mu] << ((mu == nd - 1) ? "]" : ", "); + std::cout << "'" << par().op[mu] << ((mu == nd - 1) ? "']" : "', "); } std::cout << std::endl; @@ -139,7 +140,7 @@ void TDiv::execute(void) } if (!par().output.empty()) { - Result r; + DivResult r; r.type = par().type; r.value = TensorRemove(sum(div)); diff --git a/extras/Hadrons/Modules/MScalarSUN/EMT.cc b/extras/Hadrons/Modules/MScalarSUN/EMT.cc new file mode 100644 index 00000000..7f8ca16d --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/EMT.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/EMT.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TEMT>; +template class Grid::Hadrons::MScalarSUN::TEMT>; +template class Grid::Hadrons::MScalarSUN::TEMT>; +template class Grid::Hadrons::MScalarSUN::TEMT>; +template class Grid::Hadrons::MScalarSUN::TEMT>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/EMT.hpp b/extras/Hadrons/Modules/MScalarSUN/EMT.hpp index 8c1239df..dbbfb6b3 100644 --- a/extras/Hadrons/Modules/MScalarSUN/EMT.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/EMT.hpp @@ -54,6 +54,17 @@ public: std::string, output); }; +class EMTResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(EMTResult, + std::vector>, value, + double, m2, + double, lambda, + double, g, + double, xi); +}; + template class TEMT: public Module { @@ -64,7 +75,7 @@ public: // constructor TEMT(const std::string name); // destructor - virtual ~TEMT(void) = default; + virtual ~TEMT(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -74,11 +85,11 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(EMTSU2, TEMT>, MScalarSUN); -MODULE_REGISTER_NS(EMTSU3, TEMT>, MScalarSUN); -MODULE_REGISTER_NS(EMTSU4, TEMT>, MScalarSUN); -MODULE_REGISTER_NS(EMTSU5, TEMT>, MScalarSUN); -MODULE_REGISTER_NS(EMTSU6, TEMT>, MScalarSUN); +MODULE_REGISTER_TMP(EMTSU2, TEMT>, MScalarSUN); +MODULE_REGISTER_TMP(EMTSU3, TEMT>, MScalarSUN); +MODULE_REGISTER_TMP(EMTSU4, TEMT>, MScalarSUN); +MODULE_REGISTER_TMP(EMTSU5, TEMT>, MScalarSUN); +MODULE_REGISTER_TMP(EMTSU6, TEMT>, MScalarSUN); /****************************************************************************** * TEMT implementation * @@ -99,8 +110,12 @@ std::vector TEMT::getInput(void) for (unsigned int nu = mu; nu < env().getNd(); ++nu) { in.push_back(varName(par().kinetic, mu, nu)); - in.push_back(varName(par().improvement, mu, nu)); + if (!par().improvement.empty()) + { + in.push_back(varName(par().improvement, mu, nu)); + } } + in.push_back(varName(par().kinetic, "sum")); in.push_back(varName(par().phiPow, 2)); in.push_back(varName(par().phiPow, 4)); @@ -130,7 +145,6 @@ void TEMT::setup(void) { envCreateLat(ComplexField, varName(getName(), mu, nu)); } - envTmpLat(ComplexField, "sumkin"); } // execution /////////////////////////////////////////////////////////////////// @@ -140,37 +154,59 @@ void TEMT::execute(void) LOG(Message) << "Computing energy-momentum tensor" << std::endl; LOG(Message) << " kinetic terms: '" << par().kinetic << "'" << std::endl; LOG(Message) << " tr(phi^n): '" << par().phiPow << "'" << std::endl; - LOG(Message) << " improvement: '" << par().improvement << "'" << std::endl; + if (!par().improvement.empty()) + { + LOG(Message) << " improvement: '" << par().improvement << "'" << std::endl; + } LOG(Message) << " m^2= " << par().m2 << std::endl; LOG(Message) << " lambda= " << par().lambda << std::endl; LOG(Message) << " g= " << par().g << std::endl; - LOG(Message) << " xi= " << par().xi << std::endl; + if (!par().improvement.empty()) + { + LOG(Message) << " xi= " << par().xi << std::endl; + } - const unsigned int N = SImpl::Group::Dimension; + const unsigned int N = SImpl::Group::Dimension, nd = env().getNd(); auto &trphi2 = envGet(ComplexField, varName(par().phiPow, 2)); auto &trphi4 = envGet(ComplexField, varName(par().phiPow, 4)); + auto &sumkin = envGet(ComplexField, varName(par().kinetic, "sum")); + EMTResult result; - envGetTmp(ComplexField, sumkin); - sumkin = zero; - for (unsigned int mu = 0; mu < env().getNd(); ++mu) + if (!par().output.empty()) { - auto &trkin = envGet(ComplexField, varName(par().kinetic, mu, mu)); - - sumkin += trkin; + result.m2 = par().m2; + result.g = par().g; + result.lambda = par().lambda; + result.xi = par().xi; + result.value.resize(nd, std::vector(nd)); } - for (unsigned int mu = 0; mu < env().getNd(); ++mu) - for (unsigned int nu = mu; nu < env().getNd(); ++nu) + for (unsigned int mu = 0; mu < nd; ++mu) + for (unsigned int nu = mu; nu < nd; ++nu) { auto &out = envGet(ComplexField, varName(getName(), mu, nu)); auto &trkin = envGet(ComplexField, varName(par().kinetic, mu, nu)); - auto &imp = envGet(ComplexField, varName(par().improvement, mu, nu)); + + out = 2.*trkin; + if (!par().improvement.empty()) + { + auto &imp = envGet(ComplexField, varName(par().improvement, mu, nu)); - out = 2.*trkin + par().xi*imp; + out += par().xi*imp; + } if (mu == nu) { out -= sumkin + par().m2*trphi2 + par().lambda*trphi4; } out *= N/par().g; + if (!par().output.empty()) + { + result.value[mu][nu] = TensorRemove(sum(out)); + result.value[mu][nu] = result.value[nu][mu]; + } + } + if (!par().output.empty()) + { + saveResult(par().output, "emt", result); } } diff --git a/extras/Hadrons/Modules/MScalarSUN/Grad.cc b/extras/Hadrons/Modules/MScalarSUN/Grad.cc new file mode 100644 index 00000000..be03b4a7 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/Grad.cc @@ -0,0 +1,38 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/Grad.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TGrad>; +template class Grid::Hadrons::MScalarSUN::TGrad>; +template class Grid::Hadrons::MScalarSUN::TGrad>; +template class Grid::Hadrons::MScalarSUN::TGrad>; +template class Grid::Hadrons::MScalarSUN::TGrad>; diff --git a/extras/Hadrons/Modules/MScalarSUN/Grad.hpp b/extras/Hadrons/Modules/MScalarSUN/Grad.hpp new file mode 100644 index 00000000..ecf65e90 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/Grad.hpp @@ -0,0 +1,166 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/Grad.hpp + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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_MScalarSUN_Grad_hpp_ +#define Hadrons_MScalarSUN_Grad_hpp_ + +#include +#include +#include +#include + +BEGIN_HADRONS_NAMESPACE + +/****************************************************************************** + * Gradient of a complex field * + ******************************************************************************/ +BEGIN_MODULE_NAMESPACE(MScalarSUN) + +class GradPar: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(GradPar, + std::string, op, + DiffType, type, + std::string, output); +}; + +class GradResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(GradResult, + DiffType, type, + std::vector, value); +}; + +template +class TGrad: public Module +{ +public: + typedef typename SImpl::Field Field; + typedef typename SImpl::ComplexField ComplexField; +public: + // constructor + TGrad(const std::string name); + // destructor + virtual ~TGrad(void) {}; + // dependency relation + virtual std::vector getInput(void); + virtual std::vector getOutput(void); + // setup + virtual void setup(void); + // execution + virtual void execute(void); +}; + +MODULE_REGISTER_TMP(GradSU2, TGrad>, MScalarSUN); +MODULE_REGISTER_TMP(GradSU3, TGrad>, MScalarSUN); +MODULE_REGISTER_TMP(GradSU4, TGrad>, MScalarSUN); +MODULE_REGISTER_TMP(GradSU5, TGrad>, MScalarSUN); +MODULE_REGISTER_TMP(GradSU6, TGrad>, MScalarSUN); + +/****************************************************************************** + * TGrad implementation * + ******************************************************************************/ +// constructor ///////////////////////////////////////////////////////////////// +template +TGrad::TGrad(const std::string name) +: Module(name) +{} + +// dependencies/products /////////////////////////////////////////////////////// +template +std::vector TGrad::getInput(void) +{ + std::vector in = {par().op}; + + return in; +} + +template +std::vector TGrad::getOutput(void) +{ + std::vector out; + const auto nd = env().getNd(); + + for (unsigned int mu = 0; mu < nd; ++mu) + { + out.push_back(varName(getName(), mu)); + } + + return out; +} + +// setup /////////////////////////////////////////////////////////////////////// +template +void TGrad::setup(void) +{ + const auto nd = env().getNd(); + + for (unsigned int mu = 0; mu < nd; ++mu) + { + envCreateLat(ComplexField, varName(getName(), mu)); + } +} + +// execution /////////////////////////////////////////////////////////////////// +template +void TGrad::execute(void) +{ + LOG(Message) << "Computing the " << par().type << " gradient of '" + << par().op << "'" << std::endl; + + const unsigned int nd = env().getNd(); + GradResult result; + auto &op = envGet(ComplexField, par().op); + + if (!par().output.empty()) + { + result.type = par().type; + result.value.resize(nd); + } + for (unsigned int mu = 0; mu < nd; ++mu) + { + auto &der = envGet(ComplexField, varName(getName(), mu)); + + dmu(der, op, mu, par().type); + if (!par().output.empty()) + { + result.value[mu] = TensorRemove(sum(der)); + } + } + if (!par().output.empty()) + { + saveResult(par().output, "grad", result); + } +} + +END_MODULE_NAMESPACE + +END_HADRONS_NAMESPACE + +#endif // Hadrons_MScalarSUN_Grad_hpp_ diff --git a/extras/Hadrons/Modules/MScalarSUN/ShiftProbe.cc b/extras/Hadrons/Modules/MScalarSUN/ShiftProbe.cc new file mode 100644 index 00000000..30320667 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/ShiftProbe.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/ShiftProbe.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TShiftProbe>; +template class Grid::Hadrons::MScalarSUN::TShiftProbe>; +template class Grid::Hadrons::MScalarSUN::TShiftProbe>; +template class Grid::Hadrons::MScalarSUN::TShiftProbe>; +template class Grid::Hadrons::MScalarSUN::TShiftProbe>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/ShiftProbe.hpp b/extras/Hadrons/Modules/MScalarSUN/ShiftProbe.hpp index 8d52327e..edd38e42 100644 --- a/extras/Hadrons/Modules/MScalarSUN/ShiftProbe.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/ShiftProbe.hpp @@ -40,7 +40,7 @@ BEGIN_HADRONS_NAMESPACE ******************************************************************************/ BEGIN_MODULE_NAMESPACE(MScalarSUN) -typedef std::pair ShiftPair; +typedef std::pair ShiftPair; class ShiftProbePar: Serializable { @@ -51,25 +51,25 @@ public: std::string, output); }; +class ShiftProbeResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(ShiftProbeResult, + std::string, shifts, + Complex, value); +}; + template class TShiftProbe: public Module { public: - typedef typename SImpl::Field Field; typedef typename SImpl::ComplexField ComplexField; - class Result: Serializable - { - public: - GRID_SERIALIZABLE_CLASS_MEMBERS(Result, - std::string, op, - Complex , value); - }; public: // constructor TShiftProbe(const std::string name); // destructor - virtual ~TShiftProbe(void) = default; + virtual ~TShiftProbe(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -79,11 +79,11 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(ShiftProbeSU2, TShiftProbe>, MScalarSUN); -MODULE_REGISTER_NS(ShiftProbeSU3, TShiftProbe>, MScalarSUN); -MODULE_REGISTER_NS(ShiftProbeSU4, TShiftProbe>, MScalarSUN); -MODULE_REGISTER_NS(ShiftProbeSU5, TShiftProbe>, MScalarSUN); -MODULE_REGISTER_NS(ShiftProbeSU6, TShiftProbe>, MScalarSUN); +MODULE_REGISTER_TMP(ShiftProbeSU2, TShiftProbe>, MScalarSUN); +MODULE_REGISTER_TMP(ShiftProbeSU3, TShiftProbe>, MScalarSUN); +MODULE_REGISTER_TMP(ShiftProbeSU4, TShiftProbe>, MScalarSUN); +MODULE_REGISTER_TMP(ShiftProbeSU5, TShiftProbe>, MScalarSUN); +MODULE_REGISTER_TMP(ShiftProbeSU6, TShiftProbe>, MScalarSUN); /****************************************************************************** * TShiftProbe implementation * @@ -127,27 +127,27 @@ void TShiftProbe::execute(void) << std::endl; std::vector shift; - unsigned int sign; + double sign; auto &phi = envGet(Field, par().field); auto &probe = envGet(ComplexField, getName()); shift = strToVec(par().shifts); if (shift.size() % 2 != 0) { - HADRON_ERROR(Size, "the number of shifts is odd"); + HADRONS_ERROR(Size, "the number of shifts is odd"); } - sign = (shift.size() % 4 == 0) ? 1 : -1; + sign = (shift.size() % 4 == 0) ? 1. : -1.; for (auto &s: shift) { if (s.first >= env().getNd()) { - HADRON_ERROR(Size, "dimension to large for shift <" + HADRONS_ERROR(Size, "dimension to large for shift <" + std::to_string(s.first) + " " + std::to_string(s.second) + ">" ); } } envGetTmp(Field, acc); - acc = 1.; + acc = 1.; for (unsigned int i = 0; i < shift.size(); ++i) { if (shift[i].second == 0) @@ -160,6 +160,14 @@ void TShiftProbe::execute(void) } } probe = sign*trace(acc); + if (!par().output.empty()) + { + ShiftProbeResult r; + + r.shifts = par().shifts; + r.value = TensorRemove(sum(probe)); + saveResult(par().output, "probe", r); + } } END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MScalarSUN/StochFreeField.cc b/extras/Hadrons/Modules/MScalarSUN/StochFreeField.cc new file mode 100644 index 00000000..0be90022 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/StochFreeField.cc @@ -0,0 +1,11 @@ +#include + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TStochFreeField>; +template class Grid::Hadrons::MScalarSUN::TStochFreeField>; +template class Grid::Hadrons::MScalarSUN::TStochFreeField>; +template class Grid::Hadrons::MScalarSUN::TStochFreeField>; +template class Grid::Hadrons::MScalarSUN::TStochFreeField>; diff --git a/extras/Hadrons/Modules/MScalarSUN/StochFreeField.hpp b/extras/Hadrons/Modules/MScalarSUN/StochFreeField.hpp new file mode 100644 index 00000000..75ef3fde --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/StochFreeField.hpp @@ -0,0 +1,151 @@ +#ifndef Hadrons_MScalarSUN_StochFreeField_hpp_ +#define Hadrons_MScalarSUN_StochFreeField_hpp_ + +#include +#include +#include + +BEGIN_HADRONS_NAMESPACE + +/****************************************************************************** + * stochastic free SU(N) scalar field * + ******************************************************************************/ +BEGIN_MODULE_NAMESPACE(MScalarSUN) + +class StochFreeFieldPar: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(StochFreeFieldPar, + double, m2, + double, g); +}; + +template +class TStochFreeField: public Module +{ +public: + typedef typename SImpl::Field Field; + typedef typename SImpl::ComplexField ComplexField; + typedef typename SImpl::Group Group; + typedef typename SImpl::SiteField::scalar_object Site; +public: + // constructor + TStochFreeField(const std::string name); + // destructor + virtual ~TStochFreeField(void) {}; + // dependency relation + virtual std::vector getInput(void); + virtual std::vector getOutput(void); + // setup + virtual void setup(void); + // execution + virtual void execute(void); +private: + bool create_weight; +}; + +MODULE_REGISTER_TMP(StochFreeFieldSU2, TStochFreeField>, MScalarSUN); +MODULE_REGISTER_TMP(StochFreeFieldSU3, TStochFreeField>, MScalarSUN); +MODULE_REGISTER_TMP(StochFreeFieldSU4, TStochFreeField>, MScalarSUN); +MODULE_REGISTER_TMP(StochFreeFieldSU5, TStochFreeField>, MScalarSUN); +MODULE_REGISTER_TMP(StochFreeFieldSU6, TStochFreeField>, MScalarSUN); + +/****************************************************************************** + * TStochFreeField implementation * + ******************************************************************************/ +// constructor ///////////////////////////////////////////////////////////////// +template +TStochFreeField::TStochFreeField(const std::string name) +: Module(name) +{} + +// dependencies/products /////////////////////////////////////////////////////// +template +std::vector TStochFreeField::getInput(void) +{ + std::vector in; + + return in; +} + +template +std::vector TStochFreeField::getOutput(void) +{ + std::vector out = {getName()}; + + return out; +} + +// setup /////////////////////////////////////////////////////////////////////// +template +void TStochFreeField::setup(void) +{ + create_weight = false; + if (!env().hasCreatedObject("_" + getName() + "_weight")) + { + envCacheLat(ComplexField, "_" + getName() + "_weight"); + create_weight = true; + } + envTmpLat(Field, "phift"); + envTmpLat(ComplexField, "ca"); + envCreateLat(Field, getName()); +} + +// execution /////////////////////////////////////////////////////////////////// +template +void TStochFreeField::execute(void) +{ + LOG(Message) << "Generating stochastic scalar field" << std::endl; + + const unsigned int N = Group::Dimension; + const unsigned int Nadj = Group::AdjointDimension; + auto &phi = envGet(Field, getName()); + auto &w = envGet(ComplexField, "_" + getName() + "_weight"); + auto &rng = *env().get4dRng(); + double trphi2; + FFT fft(env().getGrid()); + Integer vol; + + vol = 1; + for(int d = 0; d < env().getNd(); d++) + { + vol = vol*env().getDim(d); + } + if (create_weight) + { + LOG(Message) << "Caching momentum-space scalar action" << std::endl; + + SImpl::MomentumSpacePropagator(w, sqrt(par().m2)); + w *= par().g/N; + w = sqrt(vol)*sqrt(w); + } + LOG(Message) << "Generating random momentum-space field" << std::endl; + envGetTmp(Field, phift); + envGetTmp(ComplexField, ca); + phift = zero; + for (int a = 0; a < Nadj; ++a) + { + Site ta; + + gaussian(rng, ca); + Group::generator(a, ta); + phift += ca*ta; + } + phift *= w; + LOG(Message) << "Field Fourier transform" << std::endl; + fft.FFT_all_dim(phi, phift, FFT::backward); + phi = 0.5*(phi - adj(phi)); + trphi2 = -TensorRemove(sum(trace(phi*phi))).real()/vol; + LOG(Message) << "tr(phi^2)= " << trphi2 << std::endl; + + // ComplexField phi2(env().getGrid()); + + // phi2=trace(phi*phi); + // std::cout << phi2 << std::endl; +} + +END_MODULE_NAMESPACE + +END_HADRONS_NAMESPACE + +#endif // Hadrons_MScalarSUN_StochFreeField_hpp_ diff --git a/extras/Hadrons/Modules/MScalarSUN/TimeMomProbe.cc b/extras/Hadrons/Modules/MScalarSUN/TimeMomProbe.cc new file mode 100644 index 00000000..f22d08af --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TimeMomProbe.cc @@ -0,0 +1,11 @@ +#include + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TTimeMomProbe>; +template class Grid::Hadrons::MScalarSUN::TTimeMomProbe>; +template class Grid::Hadrons::MScalarSUN::TTimeMomProbe>; +template class Grid::Hadrons::MScalarSUN::TTimeMomProbe>; +template class Grid::Hadrons::MScalarSUN::TTimeMomProbe>; diff --git a/extras/Hadrons/Modules/MScalarSUN/TimeMomProbe.hpp b/extras/Hadrons/Modules/MScalarSUN/TimeMomProbe.hpp new file mode 100644 index 00000000..4807e865 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TimeMomProbe.hpp @@ -0,0 +1,241 @@ +#ifndef Hadrons_MScalarSUN_TimeMomProbe_hpp_ +#define Hadrons_MScalarSUN_TimeMomProbe_hpp_ + +#include +#include +#include +#include + +BEGIN_HADRONS_NAMESPACE + +/****************************************************************************** + * n-point functions O(t,p)*tr(phi(t_1,p_1)*...*phi(t_n,p_n)) * + ******************************************************************************/ +BEGIN_MODULE_NAMESPACE(MScalarSUN) + +class TimeMomProbePar: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TimeMomProbePar, + std::string, field, + std::vector, op, + std::vector>, timeMom, + std::string, output); +}; + +class TimeMomProbeResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TimeMomProbeResult, + std::string, op, + std::vector>, timeMom, + std::vector, data); +}; + +template +class TTimeMomProbe: public Module +{ +public: + typedef typename SImpl::Field Field; + typedef typename SImpl::SiteField::scalar_object Site; + typedef typename SImpl::ComplexField ComplexField; + typedef std::vector SlicedOp; +public: + // constructor + TTimeMomProbe(const std::string name); + // destructor + virtual ~TTimeMomProbe(void) {}; + // dependency relation + virtual std::vector getInput(void); + virtual std::vector getOutput(void); + // setup + virtual void setup(void); + // execution + virtual void execute(void); +private: + void vectorModulo(std::vector &v); +}; + +MODULE_REGISTER_TMP(TimeMomProbeSU2, TTimeMomProbe>, MScalarSUN); +MODULE_REGISTER_TMP(TimeMomProbeSU3, TTimeMomProbe>, MScalarSUN); +MODULE_REGISTER_TMP(TimeMomProbeSU4, TTimeMomProbe>, MScalarSUN); +MODULE_REGISTER_TMP(TimeMomProbeSU5, TTimeMomProbe>, MScalarSUN); +MODULE_REGISTER_TMP(TimeMomProbeSU6, TTimeMomProbe>, MScalarSUN); + +/****************************************************************************** + * TTimeMomProbe implementation * + ******************************************************************************/ +// constructor ///////////////////////////////////////////////////////////////// +template +TTimeMomProbe::TTimeMomProbe(const std::string name) +: Module(name) +{} + +// dependencies/products /////////////////////////////////////////////////////// +template +std::vector TTimeMomProbe::getInput(void) +{ + std::vector in = par().op; + + in.push_back(par().field); + + return in; +} + +template +std::vector TTimeMomProbe::getOutput(void) +{ + std::vector out; + + return out; +} + +// setup /////////////////////////////////////////////////////////////////////// +template +void TTimeMomProbe::setup(void) +{ + envTmpLat(ComplexField, "ftBuf"); + envTmpLat(Field, "ftMatBuf"); +} + +// execution /////////////////////////////////////////////////////////////////// +// NB: time is direction 0 +template +void TTimeMomProbe::vectorModulo(std::vector &v) +{ + for (unsigned int mu = 0; mu < env().getNd(); ++mu) + { + auto d = env().getDim(mu); + v[mu] = ((v[mu] % d) + d) % d; + } +} + +template +void TTimeMomProbe::execute(void) +{ + const unsigned int nd = env().getNd(); + const unsigned int nt = env().getDim(0); + double partVol = 1.; + std::set> timeMomSet; + std::vector>> timeMom; + std::vector> transferMom; + FFT fft(env().getGrid()); + std::vector dMask(nd, 1); + std::vector result; + std::map> slicedOp; + std::vector slicedProbe; + auto &phi = envGet(Field, par().field); + + envGetTmp(ComplexField, ftBuf); + envGetTmp(Field, ftMatBuf); + dMask[0] = 0; + for (unsigned int mu = 1; mu < nd; ++mu) + { + partVol *= env().getDim(mu); + } + timeMom.resize(par().timeMom.size()); + for (unsigned int p = 0; p < timeMom.size(); ++p) + { + for (auto &tms: par().timeMom[p]) + { + std::vector tm = strToVec(tms); + + timeMom[p].push_back(tm); + timeMomSet.insert(tm); + } + transferMom.push_back(std::vector(nd - 1, 0)); + for (auto &tm: timeMom[p]) + { + for (unsigned int j = 1; j < nd; ++j) + { + transferMom[p][j - 1] -= tm[j]; + } + } + LOG(Message) << "Probe " << p << " (" << timeMom[p].size() << " points) : " << std::endl; + LOG(Message) << " phi(t_i, p_i) for (t_i, p_i) in " << timeMom[p] << std::endl; + LOG(Message) << " operator with momentum " << transferMom[p] << std::endl; + } + LOG(Message) << "FFT: field '" << par().field << "'" << std::endl; + fft.FFT_dim_mask(ftMatBuf, phi, dMask, FFT::forward); + slicedProbe.resize(timeMom.size()); + for (unsigned int p = 0; p < timeMom.size(); ++p) + { + std::vector qt; + + LOG(Message) << "Making probe " << p << std::endl; + slicedProbe[p].resize(nt); + for (unsigned int t = 0; t < nt; ++t) + { + Site acc; + + for (unsigned int i = 0; i < timeMom[p].size(); ++i) + { + Site buf; + + qt = timeMom[p][i]; + qt[0] += t; + vectorModulo(qt); + peekSite(buf, ftMatBuf, qt); + if (i == 0) + { + acc = buf; + } + else + { + acc *= buf; + } + } + slicedProbe[p][t] = TensorRemove(trace(acc)); + } + //std::cout << slicedProbe[p]<< std::endl; + } + for (auto &o: par().op) + { + auto &op = envGet(ComplexField, o); + + slicedOp[o].resize(transferMom.size()); + LOG(Message) << "FFT: operator '" << o << "'" << std::endl; + fft.FFT_dim_mask(ftBuf, op, dMask, FFT::forward); + //std::cout << ftBuf << std::endl; + for (unsigned int p = 0; p < transferMom.size(); ++p) + { + std::vector qt(nd, 0); + + for (unsigned int j = 1; j < nd; ++j) + { + qt[j] = transferMom[p][j - 1]; + } + slicedOp[o][p].resize(nt); + for (unsigned int t = 0; t < nt; ++t) + { + TComplex buf; + + qt[0] = t; + vectorModulo(qt); + peekSite(buf, ftBuf, qt); + slicedOp[o][p][t] = TensorRemove(buf); + } + //std::cout << ftBuf << std::endl; + //std::cout << slicedOp[o][p] << std::endl; + } + } + LOG(Message) << "Making correlators" << std::endl; + for (auto &o: par().op) + for (unsigned int p = 0; p < timeMom.size(); ++p) + { + TimeMomProbeResult r; + + LOG(Message) << " <" << o << " probe_" << p << ">" << std::endl; + r.op = o; + r.timeMom = timeMom[p]; + r.data = makeTwoPoint(slicedOp[o][p], slicedProbe[p], 1./partVol); + result.push_back(r); + } + saveResult(par().output, "timemomprobe", result); +} + +END_MODULE_NAMESPACE + +END_HADRONS_NAMESPACE + +#endif // Hadrons_MScalarSUN_TimeMomProbe_hpp_ diff --git a/extras/Hadrons/Modules/MScalarSUN/TrKinetic.cc b/extras/Hadrons/Modules/MScalarSUN/TrKinetic.cc new file mode 100644 index 00000000..8d377f21 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TrKinetic.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/TrKinetic.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TTrKinetic>; +template class Grid::Hadrons::MScalarSUN::TTrKinetic>; +template class Grid::Hadrons::MScalarSUN::TTrKinetic>; +template class Grid::Hadrons::MScalarSUN::TTrKinetic>; +template class Grid::Hadrons::MScalarSUN::TTrKinetic>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/TrKinetic.hpp b/extras/Hadrons/Modules/MScalarSUN/TrKinetic.hpp index f1b520de..a714daaa 100644 --- a/extras/Hadrons/Modules/MScalarSUN/TrKinetic.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/TrKinetic.hpp @@ -49,24 +49,25 @@ public: std::string, output); }; +class TrKineticResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TrKineticResult, + std::vector>, value, + DiffType, type); +}; + template class TTrKinetic: public Module { public: typedef typename SImpl::Field Field; typedef typename SImpl::ComplexField ComplexField; - class Result: Serializable - { - public: - GRID_SERIALIZABLE_CLASS_MEMBERS(Result, - std::string, op, - Complex , value); - }; public: // constructor TTrKinetic(const std::string name); // destructor - virtual ~TTrKinetic(void) = default; + virtual ~TTrKinetic(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -76,11 +77,11 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(TrKineticSU2, TTrKinetic>, MScalarSUN); -MODULE_REGISTER_NS(TrKineticSU3, TTrKinetic>, MScalarSUN); -MODULE_REGISTER_NS(TrKineticSU4, TTrKinetic>, MScalarSUN); -MODULE_REGISTER_NS(TrKineticSU5, TTrKinetic>, MScalarSUN); -MODULE_REGISTER_NS(TrKineticSU6, TTrKinetic>, MScalarSUN); +MODULE_REGISTER_TMP(TrKineticSU2, TTrKinetic>, MScalarSUN); +MODULE_REGISTER_TMP(TrKineticSU3, TTrKinetic>, MScalarSUN); +MODULE_REGISTER_TMP(TrKineticSU4, TTrKinetic>, MScalarSUN); +MODULE_REGISTER_TMP(TrKineticSU5, TTrKinetic>, MScalarSUN); +MODULE_REGISTER_TMP(TrKineticSU6, TTrKinetic>, MScalarSUN); /****************************************************************************** * TTrKinetic implementation * @@ -110,6 +111,7 @@ std::vector TTrKinetic::getOutput(void) { out.push_back(varName(getName(), mu, nu)); } + out.push_back(varName(getName(), "sum")); return out; } @@ -123,6 +125,7 @@ void TTrKinetic::setup(void) { envCreateLat(ComplexField, varName(getName(), mu, nu)); } + envCreateLat(ComplexField, varName(getName(), "sum")); envTmp(std::vector, "der", 1, env().getNd(), env().getGrid()); } @@ -133,34 +136,39 @@ void TTrKinetic::execute(void) LOG(Message) << "Computing tr(d_mu phi*d_nu phi) using " << par().type << " derivative" << std::endl; - std::vector result; - auto &phi = envGet(Field, par().field); + const unsigned int nd = env().getNd(); + TrKineticResult result; + auto &phi = envGet(Field, par().field); + auto &sumkin = envGet(ComplexField, varName(getName(), "sum")); envGetTmp(std::vector, der); - for (unsigned int mu = 0; mu < env().getNd(); ++mu) + sumkin = zero; + if (!par().output.empty()) + { + result.type = par().type; + result.value.resize(nd, std::vector(nd)); + } + for (unsigned int mu = 0; mu < nd; ++mu) { dmu(der[mu], phi, mu, par().type); } - for (unsigned int mu = 0; mu < env().getNd(); ++mu) - for (unsigned int nu = mu; nu < env().getNd(); ++nu) + for (unsigned int mu = 0; mu < nd; ++mu) + for (unsigned int nu = mu; nu < nd; ++nu) { auto &out = envGet(ComplexField, varName(getName(), mu, nu)); out = -trace(der[mu]*der[nu]); + if (mu == nu) + { + sumkin += out; + } if (!par().output.empty()) { - Result r; - - r.op = "tr(d_" + std::to_string(mu) + "phi*d_" - + std::to_string(nu) + "phi)"; - r.value = TensorRemove(sum(out)); - result.push_back(r); + result.value[mu][nu] = TensorRemove(sum(out)); + result.value[mu][nu] = result.value[nu][mu]; } } - if (result.size() > 0) - { - saveResult(par().output, "trkinetic", result); - } + saveResult(par().output, "trkinetic", result); } END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MScalarSUN/TrMag.cc b/extras/Hadrons/Modules/MScalarSUN/TrMag.cc new file mode 100644 index 00000000..29897abc --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TrMag.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/TrMag.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TTrMag>; +template class Grid::Hadrons::MScalarSUN::TTrMag>; +template class Grid::Hadrons::MScalarSUN::TTrMag>; +template class Grid::Hadrons::MScalarSUN::TTrMag>; +template class Grid::Hadrons::MScalarSUN::TTrMag>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/TrMag.hpp b/extras/Hadrons/Modules/MScalarSUN/TrMag.hpp index 879951d5..cdbf7e30 100644 --- a/extras/Hadrons/Modules/MScalarSUN/TrMag.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/TrMag.hpp @@ -49,24 +49,25 @@ public: std::string, output); }; +class TrMagResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TrMagResult, + std::string, op, + Real, value); +}; + template class TTrMag: public Module { public: typedef typename SImpl::Field Field; typedef typename SImpl::ComplexField ComplexField; - class Result: Serializable - { - public: - GRID_SERIALIZABLE_CLASS_MEMBERS(Result, - std::string, op, - Real, value); - }; public: // constructor TTrMag(const std::string name); // destructor - virtual ~TTrMag(void) = default; + virtual ~TTrMag(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -76,11 +77,11 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(TrMagSU2, TTrMag>, MScalarSUN); -MODULE_REGISTER_NS(TrMagSU3, TTrMag>, MScalarSUN); -MODULE_REGISTER_NS(TrMagSU4, TTrMag>, MScalarSUN); -MODULE_REGISTER_NS(TrMagSU5, TTrMag>, MScalarSUN); -MODULE_REGISTER_NS(TrMagSU6, TTrMag>, MScalarSUN); +MODULE_REGISTER_TMP(TrMagSU2, TTrMag>, MScalarSUN); +MODULE_REGISTER_TMP(TrMagSU3, TTrMag>, MScalarSUN); +MODULE_REGISTER_TMP(TrMagSU4, TTrMag>, MScalarSUN); +MODULE_REGISTER_TMP(TrMagSU5, TTrMag>, MScalarSUN); +MODULE_REGISTER_TMP(TrMagSU6, TTrMag>, MScalarSUN); /****************************************************************************** * TTrMag implementation * @@ -120,8 +121,8 @@ void TTrMag::execute(void) LOG(Message) << "Computing tr(mag^n) for n even up to " << par().maxPow << std::endl; - std::vector result; - auto &phi = envGet(Field, par().field); + std::vector result; + auto &phi = envGet(Field, par().field); auto m2 = sum(phi), mn = m2; @@ -129,7 +130,7 @@ void TTrMag::execute(void) mn = 1.; for (unsigned int n = 2; n <= par().maxPow; n += 2) { - Result r; + TrMagResult r; mn = mn*m2; r.op = "tr(mag^" + std::to_string(n) + ")"; diff --git a/extras/Hadrons/Modules/MScalarSUN/TrPhi.cc b/extras/Hadrons/Modules/MScalarSUN/TrPhi.cc new file mode 100644 index 00000000..e1fcb8e5 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TrPhi.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/TrPhi.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TTrPhi>; +template class Grid::Hadrons::MScalarSUN::TTrPhi>; +template class Grid::Hadrons::MScalarSUN::TTrPhi>; +template class Grid::Hadrons::MScalarSUN::TTrPhi>; +template class Grid::Hadrons::MScalarSUN::TTrPhi>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/TrPhi.hpp b/extras/Hadrons/Modules/MScalarSUN/TrPhi.hpp index aa98bfb3..9be0a5d6 100644 --- a/extras/Hadrons/Modules/MScalarSUN/TrPhi.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/TrPhi.hpp @@ -49,24 +49,26 @@ public: std::string, output); }; +class TrPhiResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TrPhiResult, + std::string, op, + Real, value); +}; + template class TTrPhi: public Module { public: typedef typename SImpl::Field Field; typedef typename SImpl::ComplexField ComplexField; - class Result: Serializable - { - public: - GRID_SERIALIZABLE_CLASS_MEMBERS(Result, - std::string, op, - Real, value); - }; + public: // constructor TTrPhi(const std::string name); // destructor - virtual ~TTrPhi(void) = default; + virtual ~TTrPhi(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -76,11 +78,11 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(TrPhiSU2, TTrPhi>, MScalarSUN); -MODULE_REGISTER_NS(TrPhiSU3, TTrPhi>, MScalarSUN); -MODULE_REGISTER_NS(TrPhiSU4, TTrPhi>, MScalarSUN); -MODULE_REGISTER_NS(TrPhiSU5, TTrPhi>, MScalarSUN); -MODULE_REGISTER_NS(TrPhiSU6, TTrPhi>, MScalarSUN); +MODULE_REGISTER_TMP(TrPhiSU2, TTrPhi>, MScalarSUN); +MODULE_REGISTER_TMP(TrPhiSU3, TTrPhi>, MScalarSUN); +MODULE_REGISTER_TMP(TrPhiSU4, TTrPhi>, MScalarSUN); +MODULE_REGISTER_TMP(TrPhiSU5, TTrPhi>, MScalarSUN); +MODULE_REGISTER_TMP(TrPhiSU6, TTrPhi>, MScalarSUN); /****************************************************************************** * TTrPhi implementation * @@ -119,7 +121,7 @@ void TTrPhi::setup(void) { if (par().maxPow < 2) { - HADRON_ERROR(Size, "'maxPow' should be at least equal to 2"); + HADRONS_ERROR(Size, "'maxPow' should be at least equal to 2"); } envTmpLat(Field, "phi2"); envTmpLat(Field, "buf"); @@ -136,8 +138,8 @@ void TTrPhi::execute(void) LOG(Message) << "Computing tr(phi^n) for n even up to " << par().maxPow << std::endl; - std::vector result; - auto &phi = envGet(Field, par().field); + std::vector result; + auto &phi = envGet(Field, par().field); envGetTmp(Field, phi2); envGetTmp(Field, buf); @@ -151,7 +153,7 @@ void TTrPhi::execute(void) phin = trace(buf); if (!par().output.empty()) { - Result r; + TrPhiResult r; r.op = "tr(phi^" + std::to_string(n) + ")"; r.value = TensorRemove(sum(phin)).real(); diff --git a/extras/Hadrons/Modules/MScalarSUN/TransProj.cc b/extras/Hadrons/Modules/MScalarSUN/TransProj.cc new file mode 100644 index 00000000..0fb230bb --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TransProj.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/TransProj.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TTransProj>; +template class Grid::Hadrons::MScalarSUN::TTransProj>; +template class Grid::Hadrons::MScalarSUN::TTransProj>; +template class Grid::Hadrons::MScalarSUN::TTransProj>; +template class Grid::Hadrons::MScalarSUN::TTransProj>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/TransProj.hpp b/extras/Hadrons/Modules/MScalarSUN/TransProj.hpp index 4532b4ab..c9b42bf0 100644 --- a/extras/Hadrons/Modules/MScalarSUN/TransProj.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/TransProj.hpp @@ -49,24 +49,25 @@ public: std::string, output); }; +class TransProjResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TransProjResult, + std::vector>, value, + DiffType, type); +}; + template class TTransProj: public Module { public: typedef typename SImpl::Field Field; typedef typename SImpl::ComplexField ComplexField; - class Result: Serializable - { - public: - GRID_SERIALIZABLE_CLASS_MEMBERS(Result, - std::string, op, - Complex , value); - }; public: // constructor TTransProj(const std::string name); // destructor - virtual ~TTransProj(void) = default; + virtual ~TTransProj(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -77,11 +78,11 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(TransProjSU2, TTransProj>, MScalarSUN); -MODULE_REGISTER_NS(TransProjSU3, TTransProj>, MScalarSUN); -MODULE_REGISTER_NS(TransProjSU4, TTransProj>, MScalarSUN); -MODULE_REGISTER_NS(TransProjSU5, TTransProj>, MScalarSUN); -MODULE_REGISTER_NS(TransProjSU6, TTransProj>, MScalarSUN); +MODULE_REGISTER_TMP(TransProjSU2, TTransProj>, MScalarSUN); +MODULE_REGISTER_TMP(TransProjSU3, TTransProj>, MScalarSUN); +MODULE_REGISTER_TMP(TransProjSU4, TTransProj>, MScalarSUN); +MODULE_REGISTER_TMP(TransProjSU5, TTransProj>, MScalarSUN); +MODULE_REGISTER_TMP(TransProjSU6, TTransProj>, MScalarSUN); /****************************************************************************** * TTransProj implementation * @@ -137,21 +138,27 @@ void TTransProj::execute(void) << par().type << " derivatives and op= '" << par().op << "'" << std::endl; - std::vector result; - auto &op = envGet(ComplexField, par().op); + const unsigned int nd = env().getNd(); + TransProjResult result; + auto &op = envGet(ComplexField, par().op); envGetTmp(ComplexField, buf1); envGetTmp(ComplexField, buf2); envGetTmp(ComplexField, lap); lap = zero; - for (unsigned int mu = 0; mu < env().getNd(); ++mu) + if (!par().output.empty()) + { + result.type = par().type; + result.value.resize(nd, std::vector(nd)); + } + for (unsigned int mu = 0; mu < nd; ++mu) { dmu(buf1, op, mu, par().type); dmu(buf2, buf1, mu, par().type); lap += buf2; } - for (unsigned int mu = 0; mu < env().getNd(); ++mu) - for (unsigned int nu = mu; nu < env().getNd(); ++nu) + for (unsigned int mu = 0; mu < nd; ++mu) + for (unsigned int nu = mu; nu < nd; ++nu) { auto &out = envGet(ComplexField, varName(getName(), mu, nu)); dmu(buf1, op, mu, par().type); @@ -163,16 +170,11 @@ void TTransProj::execute(void) } if (!par().output.empty()) { - Result r; - - r.op = "(delta_" + std::to_string(mu) + "," + std::to_string(nu) - + " d^2 - d_" + std::to_string(mu) + "*d_" - + std::to_string(nu) + ")*op"; - r.value = TensorRemove(sum(out)); - result.push_back(r); + result.value[mu][nu] = TensorRemove(sum(out)); + result.value[mu][nu] = result.value[nu][mu]; } } - if (result.size() > 0) + if (!par().output.empty()) { saveResult(par().output, "transproj", result); } diff --git a/extras/Hadrons/Modules/MScalarSUN/TwoPoint.cc b/extras/Hadrons/Modules/MScalarSUN/TwoPoint.cc new file mode 100644 index 00000000..840cc02a --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TwoPoint.cc @@ -0,0 +1,39 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MScalarSUN/TwoPoint.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TTwoPoint>; +template class Grid::Hadrons::MScalarSUN::TTwoPoint>; +template class Grid::Hadrons::MScalarSUN::TTwoPoint>; +template class Grid::Hadrons::MScalarSUN::TTwoPoint>; +template class Grid::Hadrons::MScalarSUN::TTwoPoint>; + diff --git a/extras/Hadrons/Modules/MScalarSUN/TwoPoint.hpp b/extras/Hadrons/Modules/MScalarSUN/TwoPoint.hpp index 5227e95a..2407f26f 100644 --- a/extras/Hadrons/Modules/MScalarSUN/TwoPoint.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/TwoPoint.hpp @@ -43,30 +43,35 @@ BEGIN_MODULE_NAMESPACE(MScalarSUN) class TwoPointPar: Serializable { public: + typedef std::pair OpPair; GRID_SERIALIZABLE_CLASS_MEMBERS(TwoPointPar, - std::vector, op, + std::vector, op, + std::vector, mom, std::string, output); }; +class TwoPointResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TwoPointResult, + std::string, sink, + std::string, source, + std::vector, mom, + std::vector, data); +}; + template class TTwoPoint: public Module { public: - typedef typename SImpl::Field Field; - typedef typename SImpl::ComplexField ComplexField; - class Result: Serializable - { - public: - GRID_SERIALIZABLE_CLASS_MEMBERS(Result, - std::string, sink, - std::string, source, - std::vector, data); - }; + typedef typename SImpl::Field Field; + typedef typename SImpl::ComplexField ComplexField; + typedef std::vector SlicedOp; public: // constructor TTwoPoint(const std::string name); // destructor - virtual ~TTwoPoint(void) = default; + virtual ~TTwoPoint(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -75,17 +80,14 @@ public: // execution virtual void execute(void); private: - // make 2-pt function - template - std::vector makeTwoPoint(const std::vector &sink, - const std::vector &source); + std::vector> mom_; }; -MODULE_REGISTER_NS(TwoPointSU2, TTwoPoint>, MScalarSUN); -MODULE_REGISTER_NS(TwoPointSU3, TTwoPoint>, MScalarSUN); -MODULE_REGISTER_NS(TwoPointSU4, TTwoPoint>, MScalarSUN); -MODULE_REGISTER_NS(TwoPointSU5, TTwoPoint>, MScalarSUN); -MODULE_REGISTER_NS(TwoPointSU6, TTwoPoint>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointSU2, TTwoPoint>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointSU3, TTwoPoint>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointSU4, TTwoPoint>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointSU5, TTwoPoint>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointSU6, TTwoPoint>, MScalarSUN); /****************************************************************************** * TTwoPoint implementation * @@ -100,7 +102,20 @@ TTwoPoint::TTwoPoint(const std::string name) template std::vector TTwoPoint::getInput(void) { - return par().op; + std::vector in; + std::set ops; + + for (auto &p: par().op) + { + ops.insert(p.first); + ops.insert(p.second); + } + for (auto &o: ops) + { + in.push_back(o); + } + + return in; } template @@ -115,68 +130,91 @@ std::vector TTwoPoint::getOutput(void) template void TTwoPoint::setup(void) { - const unsigned int nt = env().getDim().back(); - envTmp(std::vector>, "slicedOp", 1, par().op.size(), - std::vector(nt)); + const unsigned int nd = env().getDim().size(); + + mom_.resize(par().mom.size()); + for (unsigned int i = 0; i < mom_.size(); ++i) + { + mom_[i] = strToVec(par().mom[i]); + if (mom_[i].size() != nd - 1) + { + HADRONS_ERROR(Size, "momentum number of components different from " + + std::to_string(nd-1)); + } + } + envTmpLat(ComplexField, "ftBuf"); } // execution /////////////////////////////////////////////////////////////////// template void TTwoPoint::execute(void) { - LOG(Message) << "Computing 2-point functions for operators:" << std::endl; - for (auto &o: par().op) + LOG(Message) << "Computing 2-point functions" << std::endl; + for (auto &p: par().op) { - LOG(Message) << " '" << o << "'" << std::endl; + LOG(Message) << " <" << p.first << " " << p.second << ">" << std::endl; } - const unsigned int nd = env().getDim().size(); - std::vector result; - - envGetTmp(std::vector>, slicedOp); - for (unsigned int i = 0; i < par().op.size(); ++i) - { - auto &op = envGet(ComplexField, par().op[i]); + const unsigned int nd = env().getNd(); + const unsigned int nt = env().getDim().back(); + const unsigned int nop = par().op.size(); + const unsigned int nmom = mom_.size(); + double partVol = 1.; + std::vector dMask(nd, 1); + std::set ops; + std::vector result; + std::map> slicedOp; + FFT fft(env().getGrid()); + TComplex buf; - sliceSum(op, slicedOp[i], nd - 1); + envGetTmp(ComplexField, ftBuf); + dMask[nd - 1] = 0; + for (unsigned int mu = 0; mu < nd - 1; ++mu) + { + partVol *= env().getDim()[mu]; } - for (unsigned int i = 0; i < par().op.size(); ++i) - for (unsigned int j = 0; j < par().op.size(); ++j) + for (auto &p: par().op) { - Result r; + ops.insert(p.first); + ops.insert(p.second); + } + for (auto &o: ops) + { + auto &op = envGet(ComplexField, o); - r.sink = par().op[i]; - r.source = par().op[j]; - r.data = makeTwoPoint(slicedOp[i], slicedOp[j]); + slicedOp[o].resize(nmom); + LOG(Message) << "Operator '" << o << "' FFT" << std::endl; + fft.FFT_dim_mask(ftBuf, op, dMask, FFT::forward); + for (unsigned int m = 0; m < nmom; ++m) + { + auto qt = mom_[m]; + + qt.resize(nd); + slicedOp[o][m].resize(nt); + for (unsigned int t = 0; t < nt; ++t) + { + qt[nd - 1] = t; + peekSite(buf, ftBuf, qt); + slicedOp[o][m][t] = TensorRemove(buf); + } + } + } + LOG(Message) << "Making contractions" << std::endl; + for (unsigned int m = 0; m < nmom; ++m) + for (auto &p: par().op) + { + TwoPointResult r; + + r.sink = p.first; + r.source = p.second; + r.mom = mom_[m]; + r.data = makeTwoPoint(slicedOp[p.first][m], slicedOp[p.second][m], + 1./partVol); result.push_back(r); } saveResult(par().output, "twopt", result); } -// make 2-pt function ////////////////////////////////////////////////////////// -template -template -std::vector TTwoPoint::makeTwoPoint( - const std::vector &sink, - const std::vector &source) -{ - assert(sink.size() == source.size()); - - unsigned int nt = sink.size(); - std::vector res(nt, 0.); - - for (unsigned int dt = 0; dt < nt; ++dt) - { - for (unsigned int t = 0; t < nt; ++t) - { - res[dt] += TensorRemove(trace(sink[(t+dt)%nt]*source[t])); - } - res[dt] *= 1./static_cast(nt); - } - - return res; -} - END_MODULE_NAMESPACE END_HADRONS_NAMESPACE diff --git a/extras/Hadrons/Modules/MScalarSUN/TwoPointNPR.cc b/extras/Hadrons/Modules/MScalarSUN/TwoPointNPR.cc new file mode 100644 index 00000000..70fb2445 --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TwoPointNPR.cc @@ -0,0 +1,11 @@ +#include + +using namespace Grid; +using namespace Hadrons; +using namespace MScalarSUN; + +template class Grid::Hadrons::MScalarSUN::TTwoPointNPR>; +template class Grid::Hadrons::MScalarSUN::TTwoPointNPR>; +template class Grid::Hadrons::MScalarSUN::TTwoPointNPR>; +template class Grid::Hadrons::MScalarSUN::TTwoPointNPR>; +template class Grid::Hadrons::MScalarSUN::TTwoPointNPR>; diff --git a/extras/Hadrons/Modules/MScalarSUN/TwoPointNPR.hpp b/extras/Hadrons/Modules/MScalarSUN/TwoPointNPR.hpp new file mode 100644 index 00000000..4c2cdb0d --- /dev/null +++ b/extras/Hadrons/Modules/MScalarSUN/TwoPointNPR.hpp @@ -0,0 +1,182 @@ +#ifndef Hadrons_MScalarSUN_TwoPointNPR_hpp_ +#define Hadrons_MScalarSUN_TwoPointNPR_hpp_ + +#include +#include +#include +#include + +BEGIN_HADRONS_NAMESPACE + +/****************************************************************************** + * TwoPointNPR * + ******************************************************************************/ +BEGIN_MODULE_NAMESPACE(MScalarSUN) + +class TwoPointNPRPar: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TwoPointNPRPar, + std::vector, op, + std::string, field, + std::string, output); +}; + +class TwoPointNPRResult: Serializable +{ +public: + GRID_SERIALIZABLE_CLASS_MEMBERS(TwoPointNPRResult, + std::string, op, + std::vector, data); +}; + +template +class TTwoPointNPR: public Module +{ +public: + typedef typename SImpl::Field Field; + typedef typename SImpl::SiteField::scalar_object Site; + typedef typename SImpl::ComplexField ComplexField; +public: + // constructor + TTwoPointNPR(const std::string name); + // destructor + virtual ~TTwoPointNPR(void) {}; + // dependency relation + virtual std::vector getInput(void); + virtual std::vector getOutput(void); + // setup + virtual void setup(void); + // execution + virtual void execute(void); +}; + +MODULE_REGISTER_TMP(TwoPointNPRSU2, TTwoPointNPR>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointNPRSU3, TTwoPointNPR>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointNPRSU4, TTwoPointNPR>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointNPRSU5, TTwoPointNPR>, MScalarSUN); +MODULE_REGISTER_TMP(TwoPointNPRSU6, TTwoPointNPR>, MScalarSUN); + +/****************************************************************************** + * TTwoPointNPR implementation * + ******************************************************************************/ +// constructor ///////////////////////////////////////////////////////////////// +template +TTwoPointNPR::TTwoPointNPR(const std::string name) +: Module(name) +{} + +// dependencies/products /////////////////////////////////////////////////////// +template +std::vector TTwoPointNPR::getInput(void) +{ + std::vector in = par().op; + + in.push_back(par().field); + + return in; +} + +template +std::vector TTwoPointNPR::getOutput(void) +{ + std::vector out; + + return out; +} + +// setup /////////////////////////////////////////////////////////////////////// +template +void TTwoPointNPR::setup(void) +{ + const unsigned int nl = env().getDim(0); + + for (unsigned int mu = 1; mu < env().getNd(); ++mu) + { + if (nl != env().getDim(mu)) + { + HADRONS_ERROR(Size, "non-cubic grid"); + } + } + envTmpLat(ComplexField, "ftBuf"); + envTmpLat(Field, "ftMatBuf"); +} + +// execution /////////////////////////////////////////////////////////////////// +template +void TTwoPointNPR::execute(void) +{ + const unsigned int nd = env().getNd(); + const unsigned int nl = env().getDim(0); + FFT fft(env().getGrid()); + std::vector result; + TwoPointNPRResult twoPtp1, twoPtp2; + auto &phi = envGet(Field, par().field); + bool doTwoPt = true; + + envGetTmp(ComplexField, ftBuf); + envGetTmp(Field, ftMatBuf); + LOG(Message) << "FFT: field '" << par().field << "'" << std::endl; + fft.FFT_all_dim(ftMatBuf, phi, FFT::forward); + for (auto &opName: par().op) + { + auto &op = envGet(ComplexField, opName); + std::vector p1, p2, p; + Site phip1, phip2; + TComplex opp; + TwoPointNPRResult r; + + LOG(Message) << "FFT: operator '" << opName << "'" << std::endl; + fft.FFT_all_dim(ftBuf, op, FFT::forward); + LOG(Message) << "Generating vertex function" << std::endl; + r.op = opName; + r.data.resize(nl); + if (doTwoPt) + { + twoPtp1.op = "phi_prop_p1"; + twoPtp1.data.resize(nl); + twoPtp2.op = "phi_prop_p2"; + twoPtp2.data.resize(nl); + } + for (unsigned int n = 0; n < nl; ++n) + { + p1.assign(nd, 0); + p2.assign(nd, 0); + p.assign(nd, 0); + // non-exceptional RI/SMOM kinematic + // p1 = mu*(1,1,0): in mom + // p2 = mu*(0,1,1): out mom + // p = p1 - p2 = mu*(1,0,-1) + // mu = 2*n*pi/L + p1[0] = n; + p1[1] = n; + p2[1] = n; + p2[2] = n; + p[0] = n; + p[2] = (nl - n) % nl; + peekSite(phip1, ftMatBuf, p1); + peekSite(phip2, ftMatBuf, p2); + peekSite(opp, ftBuf, p); + if (doTwoPt) + { + twoPtp1.data[n] = TensorRemove(trace(phip1*adj(phip1))); + twoPtp2.data[n] = TensorRemove(trace(phip2*adj(phip2))); + } + r.data[n] = TensorRemove(trace(phip2*adj(phip1))*opp); + } + if (doTwoPt) + { + result.push_back(twoPtp1); + result.push_back(twoPtp2); + } + result.push_back(r); + doTwoPt = false; + } + saveResult(par().output, "twoptnpr", result); +} + +END_MODULE_NAMESPACE + +END_HADRONS_NAMESPACE + +#endif // Hadrons_MScalarSUN_TwoPointNPR_hpp_ diff --git a/extras/Hadrons/Modules/MScalarSUN/Utils.hpp b/extras/Hadrons/Modules/MScalarSUN/Utils.hpp index 1a17282a..68009f5e 100644 --- a/extras/Hadrons/Modules/MScalarSUN/Utils.hpp +++ b/extras/Hadrons/Modules/MScalarSUN/Utils.hpp @@ -44,7 +44,7 @@ inline void dmu(Field &out, const Field &in, const unsigned int mu, const DiffTy if (mu >= env.getNd()) { - HADRON_ERROR(Range, "Derivative direction out of range"); + HADRONS_ERROR(Range, "Derivative direction out of range"); } switch(type) { @@ -58,7 +58,7 @@ inline void dmu(Field &out, const Field &in, const unsigned int mu, const DiffTy out = 0.5*(Cshift(in, mu, 1) - Cshift(in, mu, -1)); break; default: - HADRON_ERROR(Argument, "Derivative type invalid"); + HADRONS_ERROR(Argument, "Derivative type invalid"); break; } } @@ -70,7 +70,7 @@ inline void dmuAcc(Field &out, const Field &in, const unsigned int mu, const Dif if (mu >= env.getNd()) { - HADRON_ERROR(Range, "Derivative direction out of range"); + HADRONS_ERROR(Range, "Derivative direction out of range"); } switch(type) { @@ -84,20 +84,47 @@ inline void dmuAcc(Field &out, const Field &in, const unsigned int mu, const Dif out += 0.5*(Cshift(in, mu, 1) - Cshift(in, mu, -1)); break; default: - HADRON_ERROR(Argument, "Derivative type invalid"); + HADRONS_ERROR(Argument, "Derivative type invalid"); break; } } +template +std::vector makeTwoPoint(const std::vector &sink, + const std::vector &source, + const double factor = 1.) +{ + assert(sink.size() == source.size()); + + unsigned int nt = sink.size(); + std::vector res(nt, 0.); + + for (unsigned int dt = 0; dt < nt; ++dt) + { + for (unsigned int t = 0; t < nt; ++t) + { + res[dt] += trace(sink[(t+dt)%nt]*source[t]); + } + res[dt] *= factor/static_cast(nt); + } + + return res; +} + +inline std::string varName(const std::string name, const std::string suf) +{ + return name + "_" + suf; +} + inline std::string varName(const std::string name, const unsigned int mu) { - return name + "_" + std::to_string(mu); + return varName(name, std::to_string(mu)); } inline std::string varName(const std::string name, const unsigned int mu, const unsigned int nu) { - return name + "_" + std::to_string(mu) + "_" + std::to_string(nu); + return varName(name, std::to_string(mu) + "_" + std::to_string(nu)); } END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/MSink/Point.cc b/extras/Hadrons/Modules/MSink/Point.cc new file mode 100644 index 00000000..127c4c74 --- /dev/null +++ b/extras/Hadrons/Modules/MSink/Point.cc @@ -0,0 +1,36 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSink/Point.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSink; + +template class Grid::Hadrons::MSink::TPoint; +template class Grid::Hadrons::MSink::TPoint; + diff --git a/extras/Hadrons/Modules/MSink/Point.hpp b/extras/Hadrons/Modules/MSink/Point.hpp index ee824c03..7617ee78 100644 --- a/extras/Hadrons/Modules/MSink/Point.hpp +++ b/extras/Hadrons/Modules/MSink/Point.hpp @@ -7,6 +7,7 @@ Source file: extras/Hadrons/Modules/MSink/Point.hpp Copyright (C) 2015-2018 Author: Antonin Portelli +Author: Guido Cossu Author: Lanny91 This program is free software; you can redistribute it and/or modify @@ -58,7 +59,7 @@ public: // constructor TPoint(const std::string name); // destructor - virtual ~TPoint(void) = default; + virtual ~TPoint(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -72,8 +73,8 @@ private: std::string momphName_; }; -MODULE_REGISTER_NS(Point, TPoint, MSink); -MODULE_REGISTER_NS(ScalarPoint, TPoint, MSink); +MODULE_REGISTER_TMP(Point, TPoint, MSink); +MODULE_REGISTER_TMP(ScalarPoint, TPoint, MSink); /****************************************************************************** * TPoint implementation * diff --git a/extras/Hadrons/Modules/MSink/Smear.cc b/extras/Hadrons/Modules/MSink/Smear.cc new file mode 100644 index 00000000..ff250140 --- /dev/null +++ b/extras/Hadrons/Modules/MSink/Smear.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSink/Smear.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSink; + +template class Grid::Hadrons::MSink::TSmear; + diff --git a/extras/Hadrons/Modules/MSink/Smear.hpp b/extras/Hadrons/Modules/MSink/Smear.hpp index e72dece0..1a46c693 100644 --- a/extras/Hadrons/Modules/MSink/Smear.hpp +++ b/extras/Hadrons/Modules/MSink/Smear.hpp @@ -59,7 +59,7 @@ public: // constructor TSmear(const std::string name); // destructor - virtual ~TSmear(void) = default; + virtual ~TSmear(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -70,7 +70,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Smear, TSmear, MSink); +MODULE_REGISTER_TMP(Smear, TSmear, MSink); /****************************************************************************** * TSmear implementation * diff --git a/extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.cc b/extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.cc new file mode 100644 index 00000000..5bddce95 --- /dev/null +++ b/extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.cc @@ -0,0 +1,36 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSolver; + +template class Grid::Hadrons::MSolver::TLocalCoherenceLanczos; +template class Grid::Hadrons::MSolver::TLocalCoherenceLanczos; + diff --git a/extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.hpp b/extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.hpp index 80717f32..c9088cf4 100644 --- a/extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.hpp +++ b/extras/Hadrons/Modules/MSolver/LocalCoherenceLanczos.hpp @@ -51,7 +51,8 @@ public: ChebyParams, smoother, RealD, coarseRelaxTol, std::string, blockSize, - std::string, output); + std::string, output, + bool, multiFile); }; template @@ -69,7 +70,7 @@ public: // constructor TLocalCoherenceLanczos(const std::string name); // destructor - virtual ~TLocalCoherenceLanczos(void) = default; + virtual ~TLocalCoherenceLanczos(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -79,12 +80,8 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(LocalCoherenceLanczos, - ARG(TLocalCoherenceLanczos), - MSolver); -MODULE_REGISTER_NS(ZLocalCoherenceLanczos, - ARG(TLocalCoherenceLanczos), - MSolver); +MODULE_REGISTER_TMP(LocalCoherenceLanczos, ARG(TLocalCoherenceLanczos), MSolver); +MODULE_REGISTER_TMP(ZLocalCoherenceLanczos, ARG(TLocalCoherenceLanczos), MSolver); /****************************************************************************** * TLocalCoherenceLanczos implementation * @@ -125,19 +122,18 @@ void TLocalCoherenceLanczos::setup(void) env().createCoarseGrid(blockSize, Ls); - auto cg = env().getCoarseGrid(blockSize, Ls); - auto cgrb = env().getRbCoarseGrid(blockSize, Ls); - int cNm = (par().doCoarse) ? par().coarseParams.Nm : 0; + auto cg = env().getCoarseGrid(blockSize, Ls); + int cNm = (par().doCoarse) ? par().coarseParams.Nm : 0; LOG(Message) << "Coarse grid: " << cg->GlobalDimensions() << std::endl; envCreateDerived(BasePack, CoarsePack, getName(), Ls, - par().fineParams.Nm, cNm, env().getRbGrid(Ls), cgrb); + par().fineParams.Nm, cNm, env().getRbGrid(Ls), cg); auto &epack = envGetDerived(BasePack, CoarsePack, getName()); envTmp(SchurFMat, "mat", Ls, envGet(FMat, par().action)); envGetTmp(SchurFMat, mat); - envTmp(LCL, "solver", Ls, env().getRbGrid(Ls), cgrb, mat, + envTmp(LCL, "solver", Ls, env().getRbGrid(Ls), cg, mat, Odd, epack.evec, epack.evecCoarse, epack.eval, epack.evalCoarse); } @@ -149,6 +145,8 @@ void TLocalCoherenceLanczos::execute(void) auto &coarsePar = par().coarseParams; auto &epack = envGetDerived(BasePack, CoarsePack, getName()); + epack.record.operatorXml = vm().getModule(par().action)->parString(); + epack.record.solverXml = parString(); envGetTmp(LCL, solver); LOG(Message) << "Performing fine grid IRL -- Nstop= " << finePar.Nstop << ", Nk= " << finePar.Nk << ", Nm= " @@ -157,6 +155,10 @@ void TLocalCoherenceLanczos::execute(void) finePar.resid,finePar.MaxIt, finePar.betastp, finePar.MinRes); solver.testFine(finePar.resid*100.0); + if (!par().output.empty()) + { + epack.writeFine(par().output, par().multiFile, vm().getTrajectory()); + } if (par().doCoarse) { LOG(Message) << "Orthogonalising" << std::endl; @@ -170,10 +172,10 @@ void TLocalCoherenceLanczos::execute(void) coarsePar.MinRes); solver.testCoarse(coarsePar.resid*100.0, par().smoother, par().coarseRelaxTol); - } - if (!par().output.empty()) - { - epack.write(par().output, vm().getTrajectory()); + if (!par().output.empty()) + { + epack.writeCoarse(par().output, par().multiFile, vm().getTrajectory()); + } } } diff --git a/extras/Hadrons/Modules/MSolver/RBPrecCG.cc b/extras/Hadrons/Modules/MSolver/RBPrecCG.cc new file mode 100644 index 00000000..867c6c5d --- /dev/null +++ b/extras/Hadrons/Modules/MSolver/RBPrecCG.cc @@ -0,0 +1,36 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSolver/RBPrecCG.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSolver; + +template class Grid::Hadrons::MSolver::TRBPrecCG; +template class Grid::Hadrons::MSolver::TRBPrecCG; + diff --git a/extras/Hadrons/Modules/MSolver/RBPrecCG.hpp b/extras/Hadrons/Modules/MSolver/RBPrecCG.hpp index 8d1b0fc6..206d44d1 100644 --- a/extras/Hadrons/Modules/MSolver/RBPrecCG.hpp +++ b/extras/Hadrons/Modules/MSolver/RBPrecCG.hpp @@ -67,7 +67,7 @@ public: // constructor TRBPrecCG(const std::string name); // destructor - virtual ~TRBPrecCG(void) = default; + virtual ~TRBPrecCG(void) {}; // dependencies/products virtual std::vector getInput(void); virtual std::vector getReference(void); @@ -79,10 +79,8 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(RBPrecCG, - ARG(TRBPrecCG), MSolver); -MODULE_REGISTER_NS(ZRBPrecCG, - ARG(TRBPrecCG), MSolver); +MODULE_REGISTER_TMP(RBPrecCG, ARG(TRBPrecCG), MSolver); +MODULE_REGISTER_TMP(ZRBPrecCG, ARG(TRBPrecCG), MSolver); /****************************************************************************** * TRBPrecCG template implementation * @@ -107,6 +105,11 @@ std::vector TRBPrecCG::getReference(void) { std::vector ref = {par().action}; + if (!par().eigenPack.empty()) + { + ref.push_back(par().eigenPack); + } + return ref; } @@ -124,7 +127,7 @@ void TRBPrecCG::setup(void) { if (par().maxIteration == 0) { - HADRON_ERROR(Argument, "zero maximum iteration"); + HADRONS_ERROR(Argument, "zero maximum iteration"); } LOG(Message) << "setting up Schur red-black preconditioned CG for" @@ -147,6 +150,9 @@ void TRBPrecCG::setup(void) { auto &epack = envGetDerived(EPack, CoarseEPack, par().eigenPack); + LOG(Message) << "using low-mode deflation with coarse eigenpack '" + << par().eigenPack << "' (" + << epack.evecCoarse.size() << " modes)" << std::endl; guesser.reset(new CoarseGuesser(epack.evec, epack.evecCoarse, epack.evalCoarse)); } @@ -154,6 +160,9 @@ void TRBPrecCG::setup(void) { auto &epack = envGet(EPack, par().eigenPack); + LOG(Message) << "using low-mode deflation with eigenpack '" + << par().eigenPack << "' (" + << epack.evec.size() << " modes)" << std::endl; guesser.reset(new FineGuesser(epack.evec, epack.eval)); } } diff --git a/extras/Hadrons/Modules/MSource/Point.cc b/extras/Hadrons/Modules/MSource/Point.cc new file mode 100644 index 00000000..5e49af2a --- /dev/null +++ b/extras/Hadrons/Modules/MSource/Point.cc @@ -0,0 +1,36 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSource/Point.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSource; + +template class Grid::Hadrons::MSource::TPoint; +template class Grid::Hadrons::MSource::TPoint; + diff --git a/extras/Hadrons/Modules/MSource/Point.hpp b/extras/Hadrons/Modules/MSource/Point.hpp index ac6df252..0898a1a8 100644 --- a/extras/Hadrons/Modules/MSource/Point.hpp +++ b/extras/Hadrons/Modules/MSource/Point.hpp @@ -68,7 +68,7 @@ public: // constructor TPoint(const std::string name); // destructor - virtual ~TPoint(void) = default; + virtual ~TPoint(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -79,8 +79,8 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(Point, TPoint, MSource); -MODULE_REGISTER_NS(ScalarPoint, TPoint, MSource); +MODULE_REGISTER_TMP(Point, TPoint, MSource); +MODULE_REGISTER_TMP(ScalarPoint, TPoint, MSource); /****************************************************************************** * TPoint template implementation * diff --git a/extras/Hadrons/Modules/MSource/SeqConserved.cc b/extras/Hadrons/Modules/MSource/SeqConserved.cc new file mode 100644 index 00000000..35b6ef37 --- /dev/null +++ b/extras/Hadrons/Modules/MSource/SeqConserved.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSource/SeqConserved.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSource; + +template class Grid::Hadrons::MSource::TSeqConserved; + diff --git a/extras/Hadrons/Modules/MSource/SeqConserved.hpp b/extras/Hadrons/Modules/MSource/SeqConserved.hpp index d7780528..ce9cd4e6 100644 --- a/extras/Hadrons/Modules/MSource/SeqConserved.hpp +++ b/extras/Hadrons/Modules/MSource/SeqConserved.hpp @@ -89,7 +89,7 @@ public: // constructor TSeqConserved(const std::string name); // destructor - virtual ~TSeqConserved(void) = default; + virtual ~TSeqConserved(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -103,7 +103,7 @@ private: std::string SeqmomphName_; }; -MODULE_REGISTER_NS(SeqConserved, TSeqConserved, MSource); +MODULE_REGISTER_TMP(SeqConserved, TSeqConserved, MSource); /****************************************************************************** diff --git a/extras/Hadrons/Modules/MSource/SeqGamma.cc b/extras/Hadrons/Modules/MSource/SeqGamma.cc new file mode 100644 index 00000000..ce4f3dd0 --- /dev/null +++ b/extras/Hadrons/Modules/MSource/SeqGamma.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSource/SeqGamma.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSource; + +template class Grid::Hadrons::MSource::TSeqGamma; + diff --git a/extras/Hadrons/Modules/MSource/SeqGamma.hpp b/extras/Hadrons/Modules/MSource/SeqGamma.hpp index 40eda29f..4fe4dd76 100644 --- a/extras/Hadrons/Modules/MSource/SeqGamma.hpp +++ b/extras/Hadrons/Modules/MSource/SeqGamma.hpp @@ -76,7 +76,7 @@ public: // constructor TSeqGamma(const std::string name); // destructor - virtual ~TSeqGamma(void) = default; + virtual ~TSeqGamma(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -90,7 +90,7 @@ private: std::string momphName_, tName_; }; -MODULE_REGISTER_NS(SeqGamma, TSeqGamma, MSource); +MODULE_REGISTER_TMP(SeqGamma, TSeqGamma, MSource); /****************************************************************************** * TSeqGamma implementation * diff --git a/extras/Hadrons/Modules/MSource/Wall.cc b/extras/Hadrons/Modules/MSource/Wall.cc new file mode 100644 index 00000000..9b293232 --- /dev/null +++ b/extras/Hadrons/Modules/MSource/Wall.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSource/Wall.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSource; + +template class Grid::Hadrons::MSource::TWall; + diff --git a/extras/Hadrons/Modules/MSource/Wall.hpp b/extras/Hadrons/Modules/MSource/Wall.hpp index 5853b11a..f8bec19e 100644 --- a/extras/Hadrons/Modules/MSource/Wall.hpp +++ b/extras/Hadrons/Modules/MSource/Wall.hpp @@ -70,7 +70,7 @@ public: // constructor TWall(const std::string name); // destructor - virtual ~TWall(void) = default; + virtual ~TWall(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -84,7 +84,7 @@ private: std::string momphName_, tName_; }; -MODULE_REGISTER_NS(Wall, TWall, MSource); +MODULE_REGISTER_TMP(Wall, TWall, MSource); /****************************************************************************** * TWall implementation * diff --git a/extras/Hadrons/Modules/MSource/Z2.cc b/extras/Hadrons/Modules/MSource/Z2.cc new file mode 100644 index 00000000..9644c6fd --- /dev/null +++ b/extras/Hadrons/Modules/MSource/Z2.cc @@ -0,0 +1,36 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MSource/Z2.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MSource; + +template class Grid::Hadrons::MSource::TZ2; +template class Grid::Hadrons::MSource::TZ2; + diff --git a/extras/Hadrons/Modules/MSource/Z2.hpp b/extras/Hadrons/Modules/MSource/Z2.hpp index 4414e37f..cecff8b0 100644 --- a/extras/Hadrons/Modules/MSource/Z2.hpp +++ b/extras/Hadrons/Modules/MSource/Z2.hpp @@ -71,7 +71,7 @@ public: // constructor TZ2(const std::string name); // destructor - virtual ~TZ2(void) = default; + virtual ~TZ2(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -85,8 +85,8 @@ private: std::string tName_; }; -MODULE_REGISTER_NS(Z2, TZ2, MSource); -MODULE_REGISTER_NS(ScalarZ2, TZ2, MSource); +MODULE_REGISTER_TMP(Z2, TZ2, MSource); +MODULE_REGISTER_TMP(ScalarZ2, TZ2, MSource); /****************************************************************************** * TZ2 template implementation * diff --git a/extras/Hadrons/Modules/MUtilities/TestSeqConserved.cc b/extras/Hadrons/Modules/MUtilities/TestSeqConserved.cc new file mode 100644 index 00000000..99beac71 --- /dev/null +++ b/extras/Hadrons/Modules/MUtilities/TestSeqConserved.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MUtilities/TestSeqConserved.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MUtilities; + +template class Grid::Hadrons::MUtilities::TTestSeqConserved; + diff --git a/extras/Hadrons/Modules/MUtilities/TestSeqConserved.hpp b/extras/Hadrons/Modules/MUtilities/TestSeqConserved.hpp index 6ee1e3c2..7b1bc1db 100644 --- a/extras/Hadrons/Modules/MUtilities/TestSeqConserved.hpp +++ b/extras/Hadrons/Modules/MUtilities/TestSeqConserved.hpp @@ -77,7 +77,7 @@ public: // constructor TTestSeqConserved(const std::string name); // destructor - virtual ~TTestSeqConserved(void) = default; + virtual ~TTestSeqConserved(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -88,7 +88,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(TestSeqConserved, TTestSeqConserved, MUtilities); +MODULE_REGISTER_TMP(TestSeqConserved, TTestSeqConserved, MUtilities); /****************************************************************************** * TTestSeqConserved implementation * @@ -123,7 +123,7 @@ void TTestSeqConserved::setup(void) auto Ls = env().getObjectLs(par().q); if (Ls != env().getObjectLs(par().action)) { - HADRON_ERROR(Size, "Ls mismatch between quark action and propagator"); + HADRONS_ERROR(Size, "Ls mismatch between quark action and propagator"); } envTmpLat(PropagatorField, "tmp"); envTmpLat(LatticeComplex, "c"); diff --git a/extras/Hadrons/Modules/MUtilities/TestSeqGamma.cc b/extras/Hadrons/Modules/MUtilities/TestSeqGamma.cc new file mode 100644 index 00000000..f53d9f85 --- /dev/null +++ b/extras/Hadrons/Modules/MUtilities/TestSeqGamma.cc @@ -0,0 +1,35 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: extras/Hadrons/Modules/MUtilities/TestSeqGamma.cc + +Copyright (C) 2015-2018 + +Author: Antonin Portelli + +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 + +using namespace Grid; +using namespace Hadrons; +using namespace MUtilities; + +template class Grid::Hadrons::MUtilities::TTestSeqGamma; + diff --git a/extras/Hadrons/Modules/MUtilities/TestSeqGamma.hpp b/extras/Hadrons/Modules/MUtilities/TestSeqGamma.hpp index df35d887..6f2665e4 100644 --- a/extras/Hadrons/Modules/MUtilities/TestSeqGamma.hpp +++ b/extras/Hadrons/Modules/MUtilities/TestSeqGamma.hpp @@ -61,7 +61,7 @@ public: // constructor TTestSeqGamma(const std::string name); // destructor - virtual ~TTestSeqGamma(void) = default; + virtual ~TTestSeqGamma(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -72,7 +72,7 @@ protected: virtual void execute(void); }; -MODULE_REGISTER_NS(TestSeqGamma, TTestSeqGamma, MUtilities); +MODULE_REGISTER_TMP(TestSeqGamma, TTestSeqGamma, MUtilities); /****************************************************************************** * TTestSeqGamma implementation * diff --git a/extras/Hadrons/Modules/templates/Module.cc.template b/extras/Hadrons/Modules/templates/Module.cc.template deleted file mode 100644 index 0c509d6d..00000000 --- a/extras/Hadrons/Modules/templates/Module.cc.template +++ /dev/null @@ -1,39 +0,0 @@ -#include - -using namespace Grid; -using namespace Hadrons; - -/****************************************************************************** -* T___FILEBASENAME___ implementation * -******************************************************************************/ -// constructor ///////////////////////////////////////////////////////////////// -T___FILEBASENAME___::T___FILEBASENAME___(const std::string name) -: Module<___FILEBASENAME___Par>(name) -{} - -// dependencies/products /////////////////////////////////////////////////////// -std::vector T___FILEBASENAME___::getInput(void) -{ - std::vector in; - - return in; -} - -std::vector T___FILEBASENAME___::getOutput(void) -{ - std::vector out = {getName()}; - - return out; -} - -// setup /////////////////////////////////////////////////////////////////////// -void T___FILEBASENAME___::setup(void) -{ - -} - -// execution /////////////////////////////////////////////////////////////////// -void T___FILEBASENAME___::execute(void) -{ - -} diff --git a/extras/Hadrons/Modules/templates/Module.hpp.template b/extras/Hadrons/Modules/templates/Module.hpp.template deleted file mode 100644 index fb43260f..00000000 --- a/extras/Hadrons/Modules/templates/Module.hpp.template +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef Hadrons____FILEBASENAME____hpp_ -#define Hadrons____FILEBASENAME____hpp_ - -#include -#include -#include - -BEGIN_HADRONS_NAMESPACE - -/****************************************************************************** - * ___FILEBASENAME___ * - ******************************************************************************/ -class ___FILEBASENAME___Par: Serializable -{ -public: - GRID_SERIALIZABLE_CLASS_MEMBERS(___FILEBASENAME___Par, - unsigned int, i); -}; - -class T___FILEBASENAME___: public Module<___FILEBASENAME___Par> -{ -public: - // constructor - T___FILEBASENAME___(const std::string name); - // destructor - virtual ~T___FILEBASENAME___(void) = default; - // dependency relation - virtual std::vector getInput(void); - virtual std::vector getOutput(void); - // setup - virtual void setup(void); - // execution - virtual void execute(void); -}; - -MODULE_REGISTER(___FILEBASENAME___, T___FILEBASENAME___); - -END_HADRONS_NAMESPACE - -#endif // Hadrons____FILEBASENAME____hpp_ diff --git a/extras/Hadrons/Modules/templates/Module_in_NS.hpp.template b/extras/Hadrons/Modules/templates/Module_in_NS.hpp.template index ea77b12a..b34568c2 100644 --- a/extras/Hadrons/Modules/templates/Module_in_NS.hpp.template +++ b/extras/Hadrons/Modules/templates/Module_in_NS.hpp.template @@ -25,7 +25,7 @@ public: // constructor T___FILEBASENAME___(const std::string name); // destructor - virtual ~T___FILEBASENAME___(void) = default; + virtual ~T___FILEBASENAME___(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -35,7 +35,7 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(___FILEBASENAME___, T___FILEBASENAME___, ___NAMESPACE___); +MODULE_REGISTER(___FILEBASENAME___, T___FILEBASENAME___, ___NAMESPACE___); END_MODULE_NAMESPACE diff --git a/extras/Hadrons/Modules/templates/Module_tmp.hpp.template b/extras/Hadrons/Modules/templates/Module_tmp.hpp.template deleted file mode 100644 index 2ee053a9..00000000 --- a/extras/Hadrons/Modules/templates/Module_tmp.hpp.template +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef Hadrons____FILEBASENAME____hpp_ -#define Hadrons____FILEBASENAME____hpp_ - -#include -#include -#include - -BEGIN_HADRONS_NAMESPACE - -/****************************************************************************** - * ___FILEBASENAME___ * - ******************************************************************************/ -class ___FILEBASENAME___Par: Serializable -{ -public: - GRID_SERIALIZABLE_CLASS_MEMBERS(___FILEBASENAME___Par, - unsigned int, i); -}; - -template -class T___FILEBASENAME___: public Module<___FILEBASENAME___Par> -{ -public: - // constructor - T___FILEBASENAME___(const std::string name); - // destructor - virtual ~T___FILEBASENAME___(void) = default; - // dependency relation - virtual std::vector getInput(void); - virtual std::vector getOutput(void); - // setup - virtual void setup(void); - // execution - virtual void execute(void); -}; - -MODULE_REGISTER(___FILEBASENAME___, T___FILEBASENAME___); - -/****************************************************************************** - * T___FILEBASENAME___ implementation * - ******************************************************************************/ -// constructor ///////////////////////////////////////////////////////////////// -template -T___FILEBASENAME___::T___FILEBASENAME___(const std::string name) -: Module<___FILEBASENAME___Par>(name) -{} - -// dependencies/products /////////////////////////////////////////////////////// -template -std::vector T___FILEBASENAME___::getInput(void) -{ - std::vector in; - - return in; -} - -template -std::vector T___FILEBASENAME___::getOutput(void) -{ - std::vector out = {getName()}; - - return out; -} - -// setup /////////////////////////////////////////////////////////////////////// -template -void T___FILEBASENAME___::setup(void) -{ - -} - -// execution /////////////////////////////////////////////////////////////////// -template -void T___FILEBASENAME___::execute(void) -{ - -} - -END_HADRONS_NAMESPACE - -#endif // Hadrons____FILEBASENAME____hpp_ diff --git a/extras/Hadrons/Modules/templates/Module_tmp_in_NS.cc.template b/extras/Hadrons/Modules/templates/Module_tmp_in_NS.cc.template new file mode 100644 index 00000000..8dfafcf8 --- /dev/null +++ b/extras/Hadrons/Modules/templates/Module_tmp_in_NS.cc.template @@ -0,0 +1,7 @@ +#include + +using namespace Grid; +using namespace Hadrons; +using namespace ___NAMESPACE___; + +template class Grid::Hadrons::___NAMESPACE___::T___FILEBASENAME___; diff --git a/extras/Hadrons/Modules/templates/Module_tmp_in_NS.hpp.template b/extras/Hadrons/Modules/templates/Module_tmp_in_NS.hpp.template index b79c0ad3..5a05a498 100644 --- a/extras/Hadrons/Modules/templates/Module_tmp_in_NS.hpp.template +++ b/extras/Hadrons/Modules/templates/Module_tmp_in_NS.hpp.template @@ -26,7 +26,7 @@ public: // constructor T___FILEBASENAME___(const std::string name); // destructor - virtual ~T___FILEBASENAME___(void) = default; + virtual ~T___FILEBASENAME___(void) {}; // dependency relation virtual std::vector getInput(void); virtual std::vector getOutput(void); @@ -36,7 +36,7 @@ public: virtual void execute(void); }; -MODULE_REGISTER_NS(___FILEBASENAME___, T___FILEBASENAME___, ___NAMESPACE___); +MODULE_REGISTER_TMP(___FILEBASENAME___, T___FILEBASENAME___, ___NAMESPACE___); /****************************************************************************** * T___FILEBASENAME___ implementation * diff --git a/extras/Hadrons/VirtualMachine.cc b/extras/Hadrons/VirtualMachine.cc index 2b7f9620..cc197ef8 100644 --- a/extras/Hadrons/VirtualMachine.cc +++ b/extras/Hadrons/VirtualMachine.cc @@ -123,7 +123,7 @@ void VirtualMachine::pushModule(VirtualMachine::ModPt &pt) else { // output already fully registered, error - HADRON_ERROR(Definition, "object '" + out + HADRONS_ERROR(Definition, "object '" + out + "' is already produced by module '" + module_[env().getObjectModule(out)].name + "' (while pushing module '" + name + "')"); @@ -158,7 +158,7 @@ void VirtualMachine::pushModule(VirtualMachine::ModPt &pt) } else { - HADRON_ERROR(Definition, "module '" + name + "' already exists"); + HADRONS_ERROR(Definition, "module '" + name + "' already exists"); } } @@ -185,7 +185,7 @@ ModuleBase * VirtualMachine::getModule(const unsigned int address) const } else { - HADRON_ERROR(Definition, "no module with address " + std::to_string(address)); + HADRONS_ERROR(Definition, "no module with address " + std::to_string(address)); } } @@ -202,7 +202,7 @@ unsigned int VirtualMachine::getModuleAddress(const std::string name) const } else { - HADRON_ERROR(Definition, "no module with name '" + name + "'"); + HADRONS_ERROR(Definition, "no module with name '" + name + "'"); } } @@ -214,7 +214,7 @@ std::string VirtualMachine::getModuleName(const unsigned int address) const } else { - HADRON_ERROR(Definition, "no module with address " + std::to_string(address)); + HADRONS_ERROR(Definition, "no module with address " + std::to_string(address)); } } @@ -226,7 +226,7 @@ std::string VirtualMachine::getModuleType(const unsigned int address) const } else { - HADRON_ERROR(Definition, "no module with address " + std::to_string(address)); + HADRONS_ERROR(Definition, "no module with address " + std::to_string(address)); } } @@ -250,6 +250,11 @@ std::string VirtualMachine::getModuleNamespace(const std::string name) const return getModuleNamespace(getModuleAddress(name)); } +int VirtualMachine::getCurrentModule(void) const +{ + return currentModule_; +} + bool VirtualMachine::hasModule(const unsigned int address) const { return (address < module_.size()); @@ -301,9 +306,10 @@ void VirtualMachine::makeModuleGraph(void) if (min < 0) { - HADRON_ERROR(Definition, "object with address " - + std::to_string(in) - + " is not produced by any module"); + HADRONS_ERROR(Definition, "dependency '" + + env().getObjectName(in) + "' (address " + + std::to_string(in) + + ") is not produced by any module"); } else { @@ -468,7 +474,9 @@ void VirtualMachine::memoryProfile(const unsigned int address) << "' (" << address << ")..." << std::endl; try { + currentModule_ = address; m->setup(); + currentModule_ = -1; updateProfile(address); } catch (Exceptions::Definition &) @@ -588,6 +596,9 @@ VirtualMachine::Program VirtualMachine::schedule(const GeneticPar &par) }; Scheduler scheduler(graph, memPeak, gpar); gen = 0; + scheduler.initPopulation(); + LOG(Iterative) << "Start: " << sizeString(scheduler.getMinValue()) + << std::endl; do { //LOG(Debug) << "Generation " << gen << ":" << std::endl; @@ -622,7 +633,7 @@ VirtualMachine::Program VirtualMachine::schedule(const GeneticPar &par) #define SEP "---------------" #define MEM_MSG(size) sizeString(size) -void VirtualMachine::executeProgram(const Program &p) const +void VirtualMachine::executeProgram(const Program &p) { Size memPeak = 0, sizeBefore, sizeAfter; GarbageSchedule freeProg; @@ -650,7 +661,9 @@ void VirtualMachine::executeProgram(const Program &p) const LOG(Message) << SEP << " Measurement step " << i + 1 << "/" << p.size() << " (module '" << module_[p[i]].name << "') " << SEP << std::endl; + currentModule_ = p[i]; (*module_[p[i]].data)(); + currentModule_ = -1; sizeBefore = env().getTotalSize(); // print used memory after execution LOG(Message) << "Allocated objects: " << MEM_MSG(sizeBefore) @@ -679,7 +692,7 @@ void VirtualMachine::executeProgram(const Program &p) const } } -void VirtualMachine::executeProgram(const std::vector &p) const +void VirtualMachine::executeProgram(const std::vector &p) { Program pAddress; diff --git a/extras/Hadrons/VirtualMachine.hpp b/extras/Hadrons/VirtualMachine.hpp index 68eeb0c0..ccc06d63 100644 --- a/extras/Hadrons/VirtualMachine.hpp +++ b/extras/Hadrons/VirtualMachine.hpp @@ -114,6 +114,7 @@ public: std::string getModuleType(const std::string name) const; std::string getModuleNamespace(const unsigned int address) const; std::string getModuleNamespace(const std::string name) const; + int getCurrentModule(void) const; bool hasModule(const unsigned int address) const; bool hasModule(const std::string name) const; // print VM content @@ -133,8 +134,8 @@ public: // genetic scheduler Program schedule(const GeneticPar &par); // general execution - void executeProgram(const Program &p) const; - void executeProgram(const std::vector &p) const; + void executeProgram(const Program &p); + void executeProgram(const std::vector &p); private: // environment shortcut DEFINE_ENV_ALIAS; @@ -154,13 +155,13 @@ private: // module and related maps std::vector module_; std::map moduleAddress_; - std::string currentModule_{""}; + int currentModule_{-1}; // module graph bool graphOutdated_{true}; Graph graph_; // memory profile bool memoryProfileOutdated_{true}; - MemoryProfile profile_; + MemoryProfile profile_; }; /****************************************************************************** @@ -194,7 +195,7 @@ M * VirtualMachine::getModule(const unsigned int address) const } else { - HADRON_ERROR(Definition, "module '" + module_[address].name + HADRONS_ERROR(Definition, "module '" + module_[address].name + "' does not have type " + typeid(M).name() + "(has type: " + getModuleType(address) + ")"); } diff --git a/extras/Hadrons/add_module.sh b/extras/Hadrons/add_module.sh index d5d23ea4..e37d19b1 100755 --- a/extras/Hadrons/add_module.sh +++ b/extras/Hadrons/add_module.sh @@ -1,31 +1,22 @@ #!/usr/bin/env bash -if (( $# != 1 && $# != 2)); then - echo "usage: `basename $0` []" 1>&2 +if (( $# != 2 )); then + echo "usage: `basename $0` " 1>&2 exit 1 fi NAME=$1 NS=$2 -if (( $# == 1 )); then - if [ -e "Modules/${NAME}.cc" ] || [ -e "Modules/${NAME}.hpp" ]; then - echo "error: files Modules/${NAME}.* already exists" 1>&2 - exit 1 - fi - sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module.cc.template > Modules/${NAME}.cc - sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module.hpp.template > Modules/${NAME}.hpp -elif (( $# == 2 )); then - mkdir -p Modules/${NS} - if [ -e "Modules/${NS}/${NAME}.cc" ] || [ -e "Modules/${NS}/${NAME}.hpp" ]; then - echo "error: files Modules/${NS}/${NAME}.* already exists" 1>&2 - exit 1 - fi - TMPCC=".${NS}.${NAME}.tmp.cc" - TMPHPP=".${NS}.${NAME}.tmp.hpp" - sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_in_NS.cc.template > ${TMPCC} - sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_in_NS.hpp.template > ${TMPHPP} - sed "s/___NAMESPACE___/${NS}/g" ${TMPCC} > Modules/${NS}/${NAME}.cc - sed "s/___NAMESPACE___/${NS}/g" ${TMPHPP} > Modules/${NS}/${NAME}.hpp - rm -f ${TMPCC} ${TMPHPP} +mkdir -p Modules/${NS} +if [ -e "Modules/${NS}/${NAME}.cc" ] || [ -e "Modules/${NS}/${NAME}.hpp" ]; then + echo "error: files Modules/${NS}/${NAME}.* already exists" 1>&2 + exit 1 fi +TMPCC=".${NS}.${NAME}.tmp.cc" +TMPHPP=".${NS}.${NAME}.tmp.hpp" +sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_in_NS.cc.template > ${TMPCC} +sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_in_NS.hpp.template > ${TMPHPP} +sed "s/___NAMESPACE___/${NS}/g" ${TMPCC} > Modules/${NS}/${NAME}.cc +sed "s/___NAMESPACE___/${NS}/g" ${TMPHPP} > Modules/${NS}/${NAME}.hpp +rm -f ${TMPCC} ${TMPHPP} ./make_module_list.sh diff --git a/extras/Hadrons/add_module_template.sh b/extras/Hadrons/add_module_template.sh index 0069fcea..8ba112dd 100755 --- a/extras/Hadrons/add_module_template.sh +++ b/extras/Hadrons/add_module_template.sh @@ -1,28 +1,22 @@ #!/usr/bin/env bash -if (( $# != 1 && $# != 2)); then - echo "usage: `basename $0` []" 1>&2 +if (( $# != 2)); then + echo "usage: `basename $0` " 1>&2 exit 1 fi NAME=$1 NS=$2 -if (( $# == 1 )); then - if [ -e "Modules/${NAME}.cc" ] || [ -e "Modules/${NAME}.hpp" ]; then - echo "error: files Modules/${NAME}.* already exists" 1>&2 - exit 1 - fi - sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_tmp.hpp.template > Modules/${NAME}.hpp -elif (( $# == 2 )); then - mkdir -p Modules/${NS} - if [ -e "Modules/${NS}/${NAME}.cc" ] || [ -e "Modules/${NS}/${NAME}.hpp" ]; then - echo "error: files Modules/${NS}/${NAME}.* already exists" 1>&2 - exit 1 - fi - TMPCC=".${NS}.${NAME}.tmp.cc" - TMPHPP=".${NS}.${NAME}.tmp.hpp" - sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_tmp_in_NS.hpp.template > ${TMPHPP} - sed "s/___NAMESPACE___/${NS}/g" ${TMPHPP} > Modules/${NS}/${NAME}.hpp - rm -f ${TMPCC} ${TMPHPP} +mkdir -p Modules/${NS} +if [ -e "Modules/${NS}/${NAME}.cc" ] || [ -e "Modules/${NS}/${NAME}.hpp" ]; then + echo "error: files Modules/${NS}/${NAME}.* already exists" 1>&2 + exit 1 fi +TMPCC=".${NS}.${NAME}.tmp.cc" +TMPHPP=".${NS}.${NAME}.tmp.hpp" +sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_tmp_in_NS.cc.template > ${TMPCC} +sed "s/___FILEBASENAME___/${NAME}/g" Modules/templates/Module_tmp_in_NS.hpp.template > ${TMPHPP} +sed "s/___NAMESPACE___/${NS}/g" ${TMPCC} > Modules/${NS}/${NAME}.cc +sed "s/___NAMESPACE___/${NS}/g" ${TMPHPP} > Modules/${NS}/${NAME}.hpp +rm -f ${TMPCC} ${TMPHPP} ./make_module_list.sh diff --git a/extras/Hadrons/make_module_inst.sh b/extras/Hadrons/make_module_inst.sh new file mode 100755 index 00000000..32ead3f0 --- /dev/null +++ b/extras/Hadrons/make_module_inst.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +for m in `find Modules -name '*.hpp' -type f -print`; do + echo "====== ${m}" + CCFILE=`echo $m | sed -E s/\.hpp/.cc/g` + NS=`echo $m | awk -F '/' '{print $2}'` + NMOD=`grep -E 'MODULE_REGISTER_TMP.+<.+>.?' $m | wc -l` + if [ ! -e ${CCFILE} ] && (( NMOD != 0 )); then + echo "#include " >> ${CCFILE} + echo "" >> ${CCFILE} + echo "using namespace Grid;" >> ${CCFILE} + echo "using namespace Hadrons;" >> ${CCFILE} + echo "using namespace ${NS};" >> ${CCFILE} + echo "" >> ${CCFILE} + for i in `grep -E 'MODULE_REGISTER_TMP.+<.+>.?' $m | sed -E 's/ +//g'` + do + TMPARG=`echo ${i} | grep -oE 'ARG\(.+>\)' | sed -E 's/^ARG\(//g' | sed -E 's/\)$//g'` + SUB=`echo ${i} | sed -E 's/ARG\(.+>\)/@arg@/g' | sed -E 's/,/|/g'` + SUB=`echo ${SUB} | sed -E 's/.+\(//g' | sed -E 's/\);//g'` + SUB=`echo ${SUB} | sed -E "s/@arg@/${TMPARG}/g"` + NAME=`echo ${SUB} | awk -F '|' '{print $1}'` + TYPE=`echo ${SUB} | awk -F '|' '{print $2}'` + echo "template class Grid::Hadrons::${NS}::${TYPE};" >> ${CCFILE} + done + echo "" >> ${CCFILE} + fi +done \ No newline at end of file diff --git a/extras/Hadrons/modules.inc b/extras/Hadrons/modules.inc index 55f99f66..1d1b945e 100644 --- a/extras/Hadrons/modules.inc +++ b/extras/Hadrons/modules.inc @@ -1,17 +1,54 @@ modules_cc =\ Modules/MContraction/WeakHamiltonianEye.cc \ + Modules/MContraction/Baryon.cc \ + Modules/MContraction/Meson.cc \ Modules/MContraction/WeakNeutral4ptDisc.cc \ Modules/MContraction/WeakHamiltonianNonEye.cc \ - Modules/MGauge/Random.cc \ - Modules/MGauge/StochEm.cc \ + Modules/MContraction/WardIdentity.cc \ + Modules/MContraction/DiscLoop.cc \ + Modules/MContraction/Gamma3pt.cc \ + Modules/MFermion/GaugeProp.cc \ + Modules/MSource/Point.cc \ + Modules/MSource/Wall.cc \ + Modules/MSource/SeqConserved.cc \ + Modules/MSource/SeqGamma.cc \ + Modules/MSource/Z2.cc \ + Modules/MSink/Point.cc \ + Modules/MSink/Smear.cc \ + Modules/MSolver/RBPrecCG.cc \ + Modules/MSolver/LocalCoherenceLanczos.cc \ Modules/MGauge/Unit.cc \ Modules/MGauge/UnitEm.cc \ + Modules/MGauge/StochEm.cc \ + Modules/MGauge/Random.cc \ Modules/MGauge/FundtoHirep.cc \ - Modules/MScalar/ChargedProp.cc \ + Modules/MUtilities/TestSeqGamma.cc \ + Modules/MUtilities/TestSeqConserved.cc \ + Modules/MLoop/NoiseLoop.cc \ Modules/MScalar/FreeProp.cc \ + Modules/MScalar/ChargedProp.cc \ Modules/MScalar/ScalarVP.cc \ Modules/MScalar/VPCounterTerms.cc \ - Modules/MIO/LoadNersc.cc + Modules/MAction/Wilson.cc \ + Modules/MAction/ZMobiusDWF.cc \ + Modules/MAction/WilsonClover.cc \ + Modules/MAction/DWF.cc \ + Modules/MScalarSUN/TrPhi.cc \ + Modules/MScalarSUN/Grad.cc \ + Modules/MScalarSUN/TimeMomProbe.cc \ + Modules/MScalarSUN/TrMag.cc \ + Modules/MScalarSUN/TrKinetic.cc \ + Modules/MScalarSUN/EMT.cc \ + Modules/MScalarSUN/ShiftProbe.cc \ + Modules/MScalarSUN/TransProj.cc \ + Modules/MScalarSUN/StochFreeField.cc \ + Modules/MScalarSUN/TwoPoint.cc \ + Modules/MScalarSUN/TwoPointNPR.cc \ + Modules/MScalarSUN/Div.cc \ + Modules/MIO/LoadEigenPack.cc \ + Modules/MIO/LoadBinary.cc \ + Modules/MIO/LoadNersc.cc \ + Modules/MIO/LoadCoarseEigenPack.cc modules_hpp =\ Modules/MContraction/Baryon.hpp \ @@ -50,14 +87,18 @@ modules_hpp =\ Modules/MAction/Wilson.hpp \ Modules/MAction/WilsonClover.hpp \ Modules/MAction/ZMobiusDWF.hpp \ + Modules/MScalarSUN/StochFreeField.hpp \ + Modules/MScalarSUN/TwoPointNPR.hpp \ Modules/MScalarSUN/ShiftProbe.hpp \ Modules/MScalarSUN/Div.hpp \ + Modules/MScalarSUN/TimeMomProbe.hpp \ Modules/MScalarSUN/TrMag.hpp \ Modules/MScalarSUN/EMT.hpp \ Modules/MScalarSUN/TwoPoint.hpp \ Modules/MScalarSUN/TrPhi.hpp \ Modules/MScalarSUN/Utils.hpp \ Modules/MScalarSUN/TransProj.hpp \ + Modules/MScalarSUN/Grad.hpp \ Modules/MScalarSUN/TrKinetic.hpp \ Modules/MIO/LoadEigenPack.hpp \ Modules/MIO/LoadNersc.hpp \ diff --git a/lib/algorithms/iterative/ImplicitlyRestartedLanczos.h b/lib/algorithms/iterative/ImplicitlyRestartedLanczos.h index 787cf15a..8011e796 100644 --- a/lib/algorithms/iterative/ImplicitlyRestartedLanczos.h +++ b/lib/algorithms/iterative/ImplicitlyRestartedLanczos.h @@ -479,15 +479,13 @@ until convergence Field B(grid); B.checkerboard = evec[0].checkerboard; // power of two search pattern; not every evalue in eval2 is assessed. + int allconv =1; for(int jj = 1; jj<=Nstop; jj*=2){ int j = Nstop-jj; RealD e = eval2_copy[j]; // Discard the evalue basisRotateJ(B,evec,Qt,j,0,Nk,Nm); - if( _Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) { - if ( j > Nconv ) { - Nconv=j+1; - jj=Nstop; // Terminate the scan - } + if( !_Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) { + allconv=0; } } // Do evec[0] for good measure @@ -495,8 +493,10 @@ until convergence int j=0; RealD e = eval2_copy[0]; basisRotateJ(B,evec,Qt,j,0,Nk,Nm); - _Tester.TestConvergence(j,eresid,B,e,evalMaxApprox); + if( !_Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) allconv=0; } + if ( allconv ) Nconv = Nstop; + // test if we converged, if so, terminate std::cout<= "<=Nstop || beta_k < betastp){ diff --git a/lib/algorithms/iterative/LocalCoherenceLanczos.h b/lib/algorithms/iterative/LocalCoherenceLanczos.h index 0c7f4f65..c771d1cb 100644 --- a/lib/algorithms/iterative/LocalCoherenceLanczos.h +++ b/lib/algorithms/iterative/LocalCoherenceLanczos.h @@ -48,6 +48,7 @@ struct LanczosParams : Serializable { struct LocalCoherenceLanczosParams : Serializable { public: GRID_SERIALIZABLE_CLASS_MEMBERS(LocalCoherenceLanczosParams, + bool, saveEvecs, bool, doFine, bool, doFineRead, bool, doCoarse, @@ -284,9 +285,11 @@ public: }; void Orthogonalise(void ) { - CoarseScalar InnerProd(_CoarseGrid); - blockOrthogonalise(InnerProd,subspace);std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"< static RealD normalise(T& v) diff --git a/lib/allocator/AlignedAllocator.h b/lib/allocator/AlignedAllocator.h index 3b27aec9..b0f7e206 100644 --- a/lib/allocator/AlignedAllocator.h +++ b/lib/allocator/AlignedAllocator.h @@ -277,7 +277,9 @@ public: uint8_t *cp = (uint8_t *)ptr; if ( ptr ) { // One touch per 4k page, static OMP loop to catch same loop order +#ifdef GRID_OMP #pragma omp parallel for schedule(static) +#endif for(size_type n=0;n /* END LEGAL */ #include +#include namespace Grid { @@ -113,19 +114,151 @@ void GlobalSharedMemory::Init(Grid_MPI_Comm comm) assert(WorldNode!=-1); _ShmSetup=1; } - -void GlobalSharedMemory::OptimalCommunicator(const std::vector &processors,Grid_MPI_Comm & optimal_comm) +// Gray encode support +int BinaryToGray (int binary) { + int gray = (binary>>1)^binary; + return gray; +} +int Log2Size(int TwoToPower,int MAXLOG2) { - //////////////////////////////////////////////////////////////// - // Assert power of two shm_size. - //////////////////////////////////////////////////////////////// int log2size = -1; - for(int i=0;i<=MAXLOG2RANKSPERNODE;i++){ - if ( (0x1< &processors,Grid_MPI_Comm & optimal_comm) +{ +#undef HYPERCUBE +#ifdef HYPERCUBE + //////////////////////////////////////////////////////////////// + // Assert power of two shm_size. + //////////////////////////////////////////////////////////////// + int log2size = Log2Size(WorldShmSize,MAXLOG2RANKSPERNODE); + assert(log2size != -1); + + //////////////////////////////////////////////////////////////// + // Identify the hypercube coordinate of this node using hostname + //////////////////////////////////////////////////////////////// + // n runs 0...7 9...16 18...25 27...34 (8*4) 5 bits + // i runs 0..7 3 bits + // r runs 0..3 2 bits + // 2^10 = 1024 nodes + const int maxhdim = 10; + std::vector HyperCubeCoords(maxhdim,0); + std::vector RootHyperCubeCoords(maxhdim,0); + int R; + int I; + int N; + const int namelen = _POSIX_HOST_NAME_MAX; + char name[namelen]; + + // Parse ICE-XA hostname to get hypercube location + gethostname(name,namelen); + int nscan = sscanf(name,"r%di%dn%d",&R,&I,&N) ; + assert(nscan==3); + + int nlo = N%9; + int nhi = N/9; + uint32_t hypercoor = (R<<8)|(I<<5)|(nhi<<3)|nlo ; + uint32_t rootcoor = hypercoor; + + ////////////////////////////////////////////////////////////////// + // Print debug info + ////////////////////////////////////////////////////////////////// + for(int d=0;d>d)&0x1; + } + + std::string hname(name); + std::cout << "hostname "<=0); + + ////////////////////////////////////// + // Printing + ////////////////////////////////////// + for(int d=0;d>d)&0x1; + } + + //////////////////////////////////////////////////////////////// + // Identify subblock of ranks on node spreading across dims + // in a maximally symmetrical way + //////////////////////////////////////////////////////////////// + int ndimension = processors.size(); + std::vector processor_coor(ndimension); + std::vector WorldDims = processors; std::vector ShmDims (ndimension,1); std::vector NodeDims (ndimension); + std::vector ShmCoor (ndimension); std::vector NodeCoor (ndimension); std::vector WorldCoor(ndimension); + std::vector HyperCoor(ndimension); + int dim = 0; + for(int l2=0;l2> bits; + } + //////////////////////////////////////////////////////////////// + // Check processor counts match + //////////////////////////////////////////////////////////////// + int Nprocessors=1; + for(int i=0;i &processors, ///////////////////////////////////////////////////////////////// int ierr= MPI_Comm_split(WorldComm,0,rank,&optimal_comm); assert(ierr==0); +#endif } +//////////////////////////////////////////////////////////////////////////////////////////// +// SHMGET +//////////////////////////////////////////////////////////////////////////////////////////// +#ifdef GRID_MPI3_SHMGET +void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) +{ + std::cout << "SharedMemoryAllocate "<< bytes<< " shmget implementation "< shmids(WorldShmSize); + + if ( WorldShmRank == 0 ) { + for(int r=0;rpw_name,WorldNode,r); shm_unlink(shm_name); int fd=shm_open(shm_name,O_RDWR|O_CREAT,0666); @@ -323,7 +519,8 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) size_t size = bytes ; - sprintf(shm_name,"/Grid_mpi3_shm_%d_%d",WorldNode,r); + struct passwd *pw = getpwuid (getuid()); + sprintf(shm_name,"/Grid_%s_mpi3_shm_%d_%d",pw->pw_name,WorldNode,r); int fd=shm_open(shm_name,O_RDWR,0666); if ( fd<0 ) { perror("failed shm_open"); assert(0); } @@ -341,6 +538,9 @@ void GlobalSharedMemory::SharedMemoryAllocate(uint64_t bytes, int flags) } #endif + + + //////////////////////////////////////////////////////// // Global shared functionality finished // Now move to per communicator functionality diff --git a/lib/cshift/Cshift_common.h b/lib/cshift/Cshift_common.h index 1be672e8..24e0d2ab 100644 --- a/lib/cshift/Cshift_common.h +++ b/lib/cshift/Cshift_common.h @@ -45,31 +45,33 @@ Gather_plane_simple (const Lattice &rhs,commVector &buffer,int dimen int so=plane*rhs._grid->_ostride[dimension]; // base offset for start of plane int e1=rhs._grid->_slice_nblock[dimension]; int e2=rhs._grid->_slice_block[dimension]; + int ent = 0; + + static std::vector > table; table.resize(e1*e2); int stride=rhs._grid->_slice_stride[dimension]; if ( cbmask == 0x3 ) { - parallel_for_nest2(int n=0;n(off+bo+b,so+o+b); } } } else { int bo=0; - std::vector > table; for(int n=0;nCheckerBoardFromOindex(o+b); if ( ocb &cbmask ) { - table.push_back(std::pair (bo++,o+b)); + table[ent++]=std::pair (off+bo++,so+o+b); } } } - parallel_for(int i=0;i void Scatter_plane_simple (Lattice &rhs,commVector_slice_nblock[dimension]; int e2=rhs._grid->_slice_block[dimension]; int stride=rhs._grid->_slice_stride[dimension]; - + + static std::vector > table; table.resize(e1*e2); + int ent =0; + if ( cbmask ==0x3 ) { - parallel_for_nest2(int n=0;n_slice_stride[dimension]; int bo =n*rhs._grid->_slice_block[dimension]; - rhs._odata[so+o+b]=buffer[bo+b]; + table[ent++] = std::pair(so+o+b,bo+b); } } + } else { - std::vector > table; int bo=0; for(int n=0;n_slice_stride[dimension]; int ocb=1<CheckerBoardFromOindex(o+b);// Could easily be a table lookup if ( ocb & cbmask ) { - table.push_back(std::pair (so+o+b,bo++)); + table[ent++]=std::pair (so+o+b,bo++); } } } - parallel_for(int i=0;i void Copy_plane(Lattice& lhs,const Lattice &rhs int e1=rhs._grid->_slice_nblock[dimension]; // clearly loop invariant for icpc int e2=rhs._grid->_slice_block[dimension]; int stride = rhs._grid->_slice_stride[dimension]; + static std::vector > table; table.resize(e1*e2); + int ent=0; + if(cbmask == 0x3 ){ - parallel_for_nest2(int n=0;n(lo+o,ro+o); } } } else { - parallel_for_nest2(int n=0;nCheckerBoardFromOindex(o); if ( ocb&cbmask ) { - //lhs._odata[lo+o]=rhs._odata[ro+o]; - vstream(lhs._odata[lo+o],rhs._odata[ro+o]); + table[ent++] = std::pair(lo+o,ro+o); } } } } - + + parallel_for(int i=0;i void Copy_plane_permute(Lattice& lhs,const Lattice &rhs, int dimension,int lplane,int rplane,int cbmask,int permute_type) @@ -269,16 +278,28 @@ template void Copy_plane_permute(Lattice& lhs,const Lattice_slice_block [dimension]; int stride = rhs._grid->_slice_stride[dimension]; - parallel_for_nest2(int n=0;n > table; table.resize(e1*e2); + int ent=0; + double t_tab,t_perm; + if ( cbmask == 0x3 ) { + for(int n=0;n(lo+o+b,ro+o+b); + }} + } else { + for(int n=0;nCheckerBoardFromOindex(o+b); - if ( ocb&cbmask ) { - permute(lhs._odata[lo+o+b],rhs._odata[ro+o+b],permute_type); - } + if ( ocb&cbmask ) table[ent++] = std::pair(lo+o+b,ro+o+b); + }} + } - }} + parallel_for(int i=0;i void Cshift_local(Lattice& ret,const Lattice &r sshift[0] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Even); sshift[1] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Odd); + double t_local; + if ( sshift[0] == sshift[1] ) { Cshift_local(ret,rhs,dimension,shift,0x3); } else { @@ -299,7 +322,7 @@ template void Cshift_local(Lattice& ret,const Lattice &r } } -template Lattice Cshift_local(Lattice &ret,const Lattice &rhs,int dimension,int shift,int cbmask) +template void Cshift_local(Lattice &ret,const Lattice &rhs,int dimension,int shift,int cbmask) { GridBase *grid = rhs._grid; int fd = grid->_fdimensions[dimension]; @@ -325,11 +348,7 @@ template Lattice Cshift_local(Lattice &ret,const Lattice int sshift = grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,cb); int sx = (x+sshift)%rd; - - // FIXME : This must change where we have a - // Rotate slice. - // Document how this works ; why didn't I do this when I first wrote it... // wrap is whether sshift > rd. // num is sshift mod rd. // @@ -365,10 +384,8 @@ template Lattice Cshift_local(Lattice &ret,const Lattice if ( permute_slice ) Copy_plane_permute(ret,rhs,dimension,x,sx,cbmask,permute_type_dist); else Copy_plane(ret,rhs,dimension,x,sx,cbmask); - } - return ret; } } #endif diff --git a/lib/cshift/Cshift_mpi.h b/lib/cshift/Cshift_mpi.h index a66b49bf..98972135 100644 --- a/lib/cshift/Cshift_mpi.h +++ b/lib/cshift/Cshift_mpi.h @@ -54,13 +54,13 @@ template Lattice Cshift(const Lattice &rhs,int dimension if ( !comm_dim ) { - // std::cout << "Cshift_local" < void Cshift_comms_simd(Lattice& ret,const LatticeCheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Even); sshift[1] = rhs._grid->CheckerBoardShiftForCB(rhs.checkerboard,dimension,shift,Odd); + //std::cout << "Cshift_comms_simd dim "< void Cshift_comms_simd(Lattice &ret,const Lattice_simd_layout[dimension]; int comm_dim = grid->_processors[dimension] >1 ; + //std::cout << "Cshift_comms_simd dim "<< dimension << " fd "<=0); diff --git a/lib/lattice/Lattice_base.h b/lib/lattice/Lattice_base.h index 014e443d..1169d18f 100644 --- a/lib/lattice/Lattice_base.h +++ b/lib/lattice/Lattice_base.h @@ -256,9 +256,42 @@ public: _odata[ss]=r._odata[ss]; } } + + Lattice(Lattice&& r){ // move constructor + _grid = r._grid; + checkerboard = r.checkerboard; + _odata=std::move(r._odata); + } - - + inline Lattice & operator = (Lattice && r) + { + _grid = r._grid; + checkerboard = r.checkerboard; + _odata =std::move(r._odata); + return *this; + } + + inline Lattice & operator = (const Lattice & r){ + _grid = r._grid; + checkerboard = r.checkerboard; + _odata.resize(_grid->oSites());// essential + + parallel_for(int ss=0;ss<_grid->oSites();ss++){ + _odata[ss]=r._odata[ss]; + } + return *this; + } + + template strong_inline Lattice & operator = (const Lattice & r){ + this->checkerboard = r.checkerboard; + conformable(*this,r); + + parallel_for(int ss=0;ss<_grid->oSites();ss++){ + this->_odata[ss]=r._odata[ss]; + } + return *this; + } + virtual ~Lattice(void) = default; void reset(GridBase* grid) { @@ -277,15 +310,6 @@ public: return *this; } - template strong_inline Lattice & operator = (const Lattice & r){ - this->checkerboard = r.checkerboard; - conformable(*this,r); - - parallel_for(int ss=0;ss<_grid->oSites();ss++){ - this->_odata[ss]=r._odata[ss]; - } - return *this; - } // *=,+=,-= operators inherit behvour from correspond */+/- operation template strong_inline Lattice &operator *=(const T &r) { diff --git a/lib/lattice/Lattice_comparison_utils.h b/lib/lattice/Lattice_comparison_utils.h index 9580d4d2..cbac20ec 100644 --- a/lib/lattice/Lattice_comparison_utils.h +++ b/lib/lattice/Lattice_comparison_utils.h @@ -179,7 +179,7 @@ namespace Grid { return ret; } -#define DECLARE_RELATIONAL(op,functor) \ +#define DECLARE_RELATIONAL_EQ(op,functor) \ template = 0>\ inline vInteger operator op (const vsimd & lhs, const vsimd & rhs)\ {\ @@ -198,11 +198,6 @@ namespace Grid { typedef typename vsimd::scalar_type scalar;\ return Comparison(functor(),lhs,rhs);\ }\ - template = 0>\ - inline vInteger operator op(const iScalar &lhs,const iScalar &rhs)\ - { \ - return lhs._internal op rhs._internal; \ - } \ template\ inline vInteger operator op(const iScalar &lhs,const typename vsimd::scalar_type &rhs) \ { \ @@ -212,14 +207,21 @@ namespace Grid { inline vInteger operator op(const typename vsimd::scalar_type &lhs,const iScalar &rhs) \ { \ return lhs op rhs._internal; \ - } + } \ +#define DECLARE_RELATIONAL(op,functor) \ + DECLARE_RELATIONAL_EQ(op,functor) \ + template\ + inline vInteger operator op(const iScalar &lhs,const iScalar &rhs)\ + { \ + return lhs._internal op rhs._internal; \ + } DECLARE_RELATIONAL(<,slt); DECLARE_RELATIONAL(<=,sle); DECLARE_RELATIONAL(>,sgt); DECLARE_RELATIONAL(>=,sge); -DECLARE_RELATIONAL(==,seq); +DECLARE_RELATIONAL_EQ(==,seq); DECLARE_RELATIONAL(!=,sne); #undef DECLARE_RELATIONAL diff --git a/lib/lattice/Lattice_coordinate.h b/lib/lattice/Lattice_coordinate.h index 2e20ba17..19eceba8 100644 --- a/lib/lattice/Lattice_coordinate.h +++ b/lib/lattice/Lattice_coordinate.h @@ -52,23 +52,5 @@ namespace Grid { } }; - // LatticeCoordinate(); - // FIXME for debug; deprecate this; made obscelete by - template void lex_sites(Lattice &l){ - Real *v_ptr = (Real *)&l._odata[0]; - size_t o_len = l._grid->oSites(); - size_t v_len = sizeof(vobj)/sizeof(vRealF); - size_t vec_len = vRealF::Nsimd(); - - for(int i=0;i &out, const Lattice &in) extract1(in_vobj, out_ptrs, 0); } } + +template +typename std::enable_if::value && !isSIMDvectorized::value, void>::type +unvectorizeToRevLexOrdArray(std::vector &out, const Lattice &in) +{ + + typedef typename vobj::vector_type vtype; + + GridBase* in_grid = in._grid; + out.resize(in_grid->lSites()); + + int ndim = in_grid->Nd(); + int in_nsimd = vtype::Nsimd(); + + std::vector > in_icoor(in_nsimd); + + for(int lane=0; lane < in_nsimd; lane++){ + in_icoor[lane].resize(ndim); + in_grid->iCoorFromIindex(in_icoor[lane], lane); + } + + parallel_for(int in_oidx = 0; in_oidx < in_grid->oSites(); in_oidx++){ //loop over outer index + //Assemble vector of pointers to output elements + std::vector out_ptrs(in_nsimd); + + std::vector in_ocoor(ndim); + in_grid->oCoorFromOindex(in_ocoor, in_oidx); + + std::vector lcoor(in_grid->Nd()); + + for(int lane=0; lane < in_nsimd; lane++){ + for(int mu=0;mu_rdimensions[mu]*in_icoor[lane][mu]; + + int lex; + Lexicographic::IndexFromCoorReversed(lcoor, lex, in_grid->_ldimensions); + out_ptrs[lane] = &out[lex]; + } + + //Unpack into those ptrs + const vobj & in_vobj = in._odata[in_oidx]; + extract1(in_vobj, out_ptrs, 0); + } +} + //Copy SIMD-vectorized lattice to array of scalar objects in lexicographic order template typename std::enable_if::value @@ -648,10 +693,59 @@ vectorizeFromLexOrdArray( std::vector &in, Lattice &out) } } +template +typename std::enable_if::value + && !isSIMDvectorized::value, void>::type +vectorizeFromRevLexOrdArray( std::vector &in, Lattice &out) +{ + + typedef typename vobj::vector_type vtype; + + GridBase* grid = out._grid; + assert(in.size()==grid->lSites()); + + int ndim = grid->Nd(); + int nsimd = vtype::Nsimd(); + + std::vector > icoor(nsimd); + + for(int lane=0; lane < nsimd; lane++){ + icoor[lane].resize(ndim); + grid->iCoorFromIindex(icoor[lane],lane); + } + + parallel_for(uint64_t oidx = 0; oidx < grid->oSites(); oidx++){ //loop over outer index + //Assemble vector of pointers to output elements + std::vector ptrs(nsimd); + + std::vector ocoor(ndim); + grid->oCoorFromOindex(ocoor, oidx); + + std::vector lcoor(grid->Nd()); + + for(int lane=0; lane < nsimd; lane++){ + + for(int mu=0;mu_rdimensions[mu]*icoor[lane][mu]; + } + + int lex; + Lexicographic::IndexFromCoorReversed(lcoor, lex, grid->_ldimensions); + ptrs[lane] = &in[lex]; + } + + //pack from those ptrs + vobj vecobj; + merge1(vecobj, ptrs, 0); + out._odata[oidx] = vecobj; + } +} + //Convert a Lattice from one precision to another template void precisionChange(Lattice &out, const Lattice &in){ assert(out._grid->Nd() == in._grid->Nd()); + assert(out._grid->FullDimensions() == in._grid->FullDimensions()); out.checkerboard = in.checkerboard; GridBase *in_grid=in._grid; GridBase *out_grid = out._grid; diff --git a/lib/parallelIO/BinaryIO.h b/lib/parallelIO/BinaryIO.h index 39acf0e0..a60fe962 100644 --- a/lib/parallelIO/BinaryIO.h +++ b/lib/parallelIO/BinaryIO.h @@ -110,11 +110,11 @@ class BinaryIO { lsites = 1; } - #pragma omp parallel +PARALLEL_REGION { uint32_t nersc_csum_thr = 0; - #pragma omp for +PARALLEL_FOR_LOOP_INTERN for (uint64_t local_site = 0; local_site < lsites; local_site++) { uint32_t *site_buf = (uint32_t *)&fbuf[local_site]; @@ -124,7 +124,7 @@ class BinaryIO { } } - #pragma omp critical +PARALLEL_CRITICAL { nersc_csum += nersc_csum_thr; } @@ -146,14 +146,14 @@ class BinaryIO { std::vector local_start =grid->LocalStarts(); std::vector global_vol =grid->FullDimensions(); -#pragma omp parallel +PARALLEL_REGION { std::vector coor(nd); uint32_t scidac_csuma_thr=0; uint32_t scidac_csumb_thr=0; uint32_t site_crc=0; -#pragma omp for +PARALLEL_FOR_LOOP_INTERN for(uint64_t local_site=0;local_site>(32-gsite31); } -#pragma omp critical +PARALLEL_CRITICAL { scidac_csuma^= scidac_csuma_thr; scidac_csumb^= scidac_csumb_thr; @@ -263,7 +263,7 @@ class BinaryIO { GridBase *grid, std::vector &iodata, std::string file, - uint64_t offset, + uint64_t& offset, const std::string &format, int control, uint32_t &nersc_csum, uint32_t &scidac_csuma, @@ -372,7 +372,7 @@ class BinaryIO { std::cout << GridLogMessage <<"IOobject: C++ read I/O " << file << " : " << iodata.size() * sizeof(fobj) << " bytes" << std::endl; 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) { fin.seekg(-sizeof(fobj), fin.end); @@ -431,14 +431,20 @@ class BinaryIO { MPI_Abort(MPI_COMM_WORLD, 1); //assert(ierr == 0); } - std::cout << GridLogDebug << "MPI read I/O set view " << file << std::endl; + std::cout << GridLogDebug << "MPI write I/O set view " << file << std::endl; ierr = MPI_File_set_view(fh, disp, mpiObject, fileArray, "native", MPI_INFO_NULL); assert(ierr == 0); - std::cout << GridLogDebug << "MPI read I/O write all " << file << std::endl; + std::cout << GridLogDebug << "MPI write I/O write all " << file << std::endl; ierr = MPI_File_write_all(fh, &iodata[0], 1, localArray, &status); assert(ierr == 0); + MPI_Offset os; + MPI_File_get_position(fh, &os); + MPI_File_get_byte_offset(fh, os, &disp); + offset = disp; + + MPI_File_close(&fh); MPI_Type_free(&fileArray); MPI_Type_free(&localArray); @@ -448,16 +454,20 @@ class BinaryIO { } else { std::cout << GridLogMessage << "IOobject: C++ write I/O " << file << " : " - << iodata.size() * sizeof(fobj) << " bytes" << std::endl; + << iodata.size() * sizeof(fobj) << " bytes and offset " << offset << std::endl; std::ofstream fout; fout.exceptions ( std::fstream::failbit | std::fstream::badbit ); try { - fout.open(file,std::ios::binary|std::ios::out|std::ios::in); + if (offset) { // Must already exist and contain data + fout.open(file,std::ios::binary|std::ios::out|std::ios::in); + } else { // Allow create + fout.open(file,std::ios::binary|std::ios::out); + } } catch (const std::fstream::failure& exc) { std::cout << GridLogError << "Error in opening the file " << file << " for output" < tmp(RngStateCount); diff --git a/lib/parallelIO/IldgIO.h b/lib/parallelIO/IldgIO.h index b81d1e43..3cfc1349 100644 --- a/lib/parallelIO/IldgIO.h +++ b/lib/parallelIO/IldgIO.h @@ -182,6 +182,11 @@ class GridLimeReader : public BinaryIO { { filename= _filename; File = fopen(filename.c_str(), "r"); + if (File == nullptr) + { + std::cerr << "cannot open file '" << filename << "'" << std::endl; + abort(); + } LimeR = limeCreateReader(File); } ///////////////////////////////////////////// @@ -248,7 +253,6 @@ class GridLimeReader : public BinaryIO { template void readLimeObject(serialisable_object &object,std::string object_name,std::string record_name) { - std::string xmlstring; // should this be a do while; can we miss a first record?? while ( limeReaderNextRecord(LimeR) == LIME_SUCCESS ) { @@ -262,7 +266,8 @@ class GridLimeReader : public BinaryIO { limeReaderReadData((void *)&xmlc[0], &nbytes, LimeR); // std::cout << GridLogMessage<< " readLimeObject matches XML " << &xmlc[0] <(message.c_str()), PayloadSize); - assert(limeWriteRecordHeader(h, LimeW) >= 0); - limeDestroyHeader(h); + if ( boss_node ) { + LimeRecordHeader *h; + h = limeCreateHeader(MB, ME, const_cast(message.c_str()), PayloadSize); + assert(limeWriteRecordHeader(h, LimeW) >= 0); + limeDestroyHeader(h); + } return LIME_SUCCESS; } //////////////////////////////////////////// // Write a generic serialisable object //////////////////////////////////////////// - template - void writeLimeObject(int MB,int ME,serialisable_object &object,std::string object_name,std::string record_name) + void writeLimeObject(int MB,int ME,XmlWriter &writer,std::string object_name,std::string record_name) { - std::string xmlstring; - { - XmlWriter WR("",""); - write(WR,object_name,object); - xmlstring = WR.XmlString(); - } - // std::cout << "WriteLimeObject" << record_name <(record_name.c_str()), nbytes); - assert(h!= NULL); + if ( boss_node ) { + std::string xmlstring = writer.docString(); - err=limeWriteRecordHeader(h, LimeW); assert(err>=0); - err=limeWriteRecordData(&xmlstring[0], &nbytes, LimeW); assert(err>=0); - err=limeWriterCloseRecord(LimeW); assert(err>=0); - limeDestroyHeader(h); - // std::cout << " File offset is now"<(record_name.c_str()), nbytes); + assert(h!= NULL); + + err=limeWriteRecordHeader(h, LimeW); assert(err>=0); + err=limeWriteRecordData(&xmlstring[0], &nbytes, LimeW); assert(err>=0); + err=limeWriterCloseRecord(LimeW); assert(err>=0); + limeDestroyHeader(h); + } } - //////////////////////////////////////////// + + template + void writeLimeObject(int MB,int ME,serialisable_object &object,std::string object_name,std::string record_name, const unsigned int scientificPrec = 0) + { + XmlWriter WR("",""); + + if (scientificPrec) + { + WR.scientificFormat(true); + WR.setPrecision(scientificPrec); + } + write(WR,object_name,object); + writeLimeObject(MB, ME, WR, object_name, record_name); + } + //////////////////////////////////////////////////// // Write a generic lattice field and csum - //////////////////////////////////////////// + // This routine is Collectively called by all nodes + // in communicator used by the field._grid + //////////////////////////////////////////////////// template void writeLimeLatticeBinaryObject(Lattice &field,std::string record_name) { @@ -350,6 +378,9 @@ class GridLimeWriter : public BinaryIO { // iv) fseek on FILE * to end of this disjoint section. // v) Continue writing scidac record. //////////////////////////////////////////////////////////////////// + + GridBase *grid = field._grid; + assert(boss_node == field._grid->IsBoss() ); //////////////////////////////////////////// // Create record header @@ -357,19 +388,28 @@ class GridLimeWriter : public BinaryIO { typedef typename vobj::scalar_object sobj; int err; uint32_t nersc_csum,scidac_csuma,scidac_csumb; - uint64_t PayloadSize = sizeof(sobj) * field._grid->_gsites; - createLimeRecordHeader(record_name, 0, 0, PayloadSize); - + uint64_t PayloadSize = sizeof(sobj) * grid->_gsites; + if ( boss_node ) { + createLimeRecordHeader(record_name, 0, 0, PayloadSize); + fflush(File); + } + // std::cout << "W sizeof(sobj)" <_gsites<Broadcast(0,(void *)&offset1,sizeof(offset1)); /////////////////////////////////////////// - // Write by other means into the binary record + // The above is collective. Write by other means into the binary record /////////////////////////////////////////// - uint64_t offset1 = ftello(File); // std::cout << " Writing to offset "<(); BinarySimpleMunger munge; BinaryIO::writeLatticeObject(field, filename, munge, offset1, format,nersc_csum,scidac_csuma,scidac_csumb); @@ -377,13 +417,19 @@ class GridLimeWriter : public BinaryIO { /////////////////////////////////////////// // Wind forward and close the record /////////////////////////////////////////// - fseek(File,0,SEEK_END); - uint64_t offset2 = ftello(File); // std::cout << " now at offset "<=0); + ///////////////////////////////////////////////////////////// + // Check MPI-2 I/O did what we expect to file + ///////////////////////////////////////////////////////////// + if ( boss_node ) { + err=limeWriterCloseRecord(LimeW); assert(err>=0); + } //////////////////////////////////////// // Write checksum element, propagaing forward from the BinaryIO // Always pair a checksum with a binary object, and close message @@ -393,26 +439,32 @@ class GridLimeWriter : public BinaryIO { std::stringstream streamb; streamb << std::hex << scidac_csumb; checksum.suma= streama.str(); checksum.sumb= streamb.str(); - // std::cout << GridLogMessage<<" writing scidac checksums "< - void writeScidacFileRecord(GridBase *grid,SerialisableUserFile &_userFile) - { - scidacFile _scidacFile(grid); - writeLimeObject(1,0,_scidacFile,_scidacFile.SerialisableClassName(),std::string(SCIDAC_PRIVATE_FILE_XML)); - writeLimeObject(0,1,_userFile,_userFile.SerialisableClassName(),std::string(SCIDAC_FILE_XML)); - } + ScidacWriter(bool isboss =true ) : GridLimeWriter(isboss) { }; + + template + void writeScidacFileRecord(GridBase *grid,SerialisableUserFile &_userFile) + { + scidacFile _scidacFile(grid); + if ( this->boss_node ) { + writeLimeObject(1,0,_scidacFile,_scidacFile.SerialisableClassName(),std::string(SCIDAC_PRIVATE_FILE_XML)); + writeLimeObject(0,1,_userFile,_userFile.SerialisableClassName(),std::string(SCIDAC_FILE_XML)); + } + } //////////////////////////////////////////////// // Write generic lattice field in scidac format //////////////////////////////////////////////// template - void writeScidacFieldRecord(Lattice &field,userRecord _userRecord) + void writeScidacFieldRecord(Lattice &field,userRecord _userRecord, + const unsigned int recordScientificPrec = 0) { GridBase * grid = field._grid; @@ -428,9 +480,12 @@ class ScidacWriter : public GridLimeWriter { ////////////////////////////////////////////// // Fill the Lime file record by record ////////////////////////////////////////////// - writeLimeObject(1,0,header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message - writeLimeObject(0,0,_userRecord,_userRecord.SerialisableClassName(),std::string(SCIDAC_RECORD_XML)); - writeLimeObject(0,0,_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML)); + if ( this->boss_node ) { + writeLimeObject(1,0,header ,std::string("FieldMetaData"),std::string(GRID_FORMAT)); // Open message + writeLimeObject(0,0,_userRecord,_userRecord.SerialisableClassName(),std::string(SCIDAC_RECORD_XML), recordScientificPrec); + writeLimeObject(0,0,_scidacRecord,_scidacRecord.SerialisableClassName(),std::string(SCIDAC_PRIVATE_RECORD_XML)); + } + // Collective call writeLimeLatticeBinaryObject(field,std::string(ILDG_BINARY_DATA)); // Closes message with checksum } }; @@ -497,6 +552,8 @@ class ScidacReader : public GridLimeReader { class IldgWriter : public ScidacWriter { public: + + IldgWriter(bool isboss) : ScidacWriter(isboss) {}; /////////////////////////////////// // A little helper @@ -656,9 +713,11 @@ class IldgReader : public GridLimeReader { ////////////////////////////////// // ILDG format record + + std::string xmlstring(&xmlc[0]); if ( !strncmp(limeReaderType(LimeR), ILDG_FORMAT,strlen(ILDG_FORMAT)) ) { - XmlReader RD(&xmlc[0],""); + XmlReader RD(xmlstring, true, ""); read(RD,"ildgFormat",ildgFormat_); if ( ildgFormat_.precision == 64 ) format = std::string("IEEE64BIG"); @@ -673,13 +732,13 @@ class IldgReader : public GridLimeReader { } if ( !strncmp(limeReaderType(LimeR), ILDG_DATA_LFN,strlen(ILDG_DATA_LFN)) ) { - FieldMetaData_.ildg_lfn = std::string(&xmlc[0]); + FieldMetaData_.ildg_lfn = xmlstring; found_ildgLFN = 1; } if ( !strncmp(limeReaderType(LimeR), GRID_FORMAT,strlen(ILDG_FORMAT)) ) { - XmlReader RD(&xmlc[0],""); + XmlReader RD(xmlstring, true, ""); read(RD,"FieldMetaData",FieldMetaData_); format = FieldMetaData_.floating_point; @@ -693,18 +752,17 @@ class IldgReader : public GridLimeReader { } if ( !strncmp(limeReaderType(LimeR), SCIDAC_RECORD_XML,strlen(SCIDAC_RECORD_XML)) ) { - std::string xmls(&xmlc[0]); // is it a USQCD info field - if ( xmls.find(std::string("usqcdInfo")) != std::string::npos ) { + if ( xmlstring.find(std::string("usqcdInfo")) != std::string::npos ) { // std::cout << GridLogMessage<<"...found a usqcdInfo field"< munge; - offset = writeHeader(header,file); + if ( grid->IsBoss() ) { + truncate(file); + offset = writeHeader(header,file); + } + grid->Broadcast(0,(void *)&offset,sizeof(offset)); uint32_t nersc_csum,scidac_csuma,scidac_csumb; BinaryIO::writeLatticeObject(Umu,file,munge,offset,header.floating_point, nersc_csum,scidac_csuma,scidac_csumb); header.checksum = nersc_csum; - writeHeader(header,file); + if ( grid->IsBoss() ) { + writeHeader(header,file); + } std::cout<IsBoss() ) { + truncate(file); + offset = writeHeader(header,file); + } + grid->Broadcast(0,(void *)&offset,sizeof(offset)); + uint32_t nersc_csum,scidac_csuma,scidac_csumb; BinaryIO::writeRNG(serial,parallel,file,offset,nersc_csum,scidac_csuma,scidac_csumb); header.checksum = nersc_csum; - offset = writeHeader(header,file); + if ( grid->IsBoss() ) { + offset = writeHeader(header,file); + } std::cout< #include #include +#include #ifdef PUGIXML_WCHAR_MODE # include @@ -28,9 +29,6 @@ #ifndef PUGIXML_NO_XPATH # include # include -# ifdef PUGIXML_NO_EXCEPTIONS -# include -# endif #endif #ifndef PUGIXML_NO_STL @@ -46,14 +44,17 @@ # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4324) // structure was padded due to __declspec(align()) -# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable # pragma warning(disable: 4702) // unreachable code # pragma warning(disable: 4996) // this function or variable may be unsafe -# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged +#endif + +#if defined(_MSC_VER) && defined(__c2__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" // this function or variable may be unsafe #endif #ifdef __INTEL_COMPILER -# pragma warning(disable: 177) // function was declared but never referenced +# pragma warning(disable: 177) // function was declared but never referenced # pragma warning(disable: 279) // controlling expression is constant # pragma warning(disable: 1478 1786) // function was declared "deprecated" # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type @@ -75,17 +76,21 @@ # pragma diag_suppress=237 // controlling expression is constant #endif +#ifdef __TI_COMPILER_VERSION__ +# pragma diag_suppress 179 // function was declared but never referenced +#endif + // Inlining controls #if defined(_MSC_VER) && _MSC_VER >= 1300 # define PUGI__NO_INLINE __declspec(noinline) #elif defined(__GNUC__) # define PUGI__NO_INLINE __attribute__((noinline)) #else -# define PUGI__NO_INLINE +# define PUGI__NO_INLINE #endif // Branch weight controls -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__c2__) # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) #else # define PUGI__UNLIKELY(cond) (cond) @@ -101,10 +106,29 @@ # define PUGI__DMC_VOLATILE #endif +// Integer sanitizer workaround; we only apply this for clang since gcc8 has no_sanitize but not unsigned-integer-overflow and produces "attribute directive ignored" warnings +#if defined(__clang__) && defined(__has_attribute) +# if __has_attribute(no_sanitize) +# define PUGI__UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow"))) +# else +# define PUGI__UNSIGNED_OVERFLOW +# endif +#else +# define PUGI__UNSIGNED_OVERFLOW +#endif + // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) using std::memcpy; using std::memmove; +using std::memset; +#endif + +// Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations +#if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX) +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define LLONG_MAX __LONG_LONG_MAX__ +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) #endif // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features @@ -112,6 +136,16 @@ using std::memmove; # define PUGI__MSVC_CRT_VERSION _MSC_VER #endif +// Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size. +#if __cplusplus >= 201103 +# define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) +#elif defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 +# define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__) +#else +# define PUGI__SNPRINTF sprintf +#endif + +// We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat. #ifdef PUGIXML_HEADER_ONLY # define PUGI__NS_BEGIN namespace pugi { namespace impl { # define PUGI__NS_END } } @@ -130,9 +164,7 @@ using std::memmove; #endif // uintptr_t -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -# include -#else +#if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561) namespace pugi { # ifndef _UINTPTR_T_DEFINED @@ -143,6 +175,8 @@ namespace pugi typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; } +#else +# include #endif // Memory allocation @@ -204,7 +238,7 @@ PUGI__NS_BEGIN for (size_t i = 0; i < count; ++i) if (lhs[i] != rhs[i]) return false; - + return lhs[count] == 0; } @@ -221,21 +255,14 @@ PUGI__NS_BEGIN return static_cast(end - s); #endif } - -#ifdef PUGIXML_WCHAR_MODE - // Convert string to wide string, assuming all symbols are ASCII - PUGI__FN void widen_ascii(wchar_t* dest, const char* source) - { - for (const char* i = source; *i; ++i) *dest++ = *i; - *dest = 0; - } -#endif PUGI__NS_END // auto_ptr-like object for exception recovery PUGI__NS_BEGIN - template struct auto_deleter + template struct auto_deleter { + typedef void (*D)(T*); + T* data; D deleter; @@ -277,67 +304,37 @@ PUGI__NS_BEGIN } } - void** find(const void* key) + void* find(const void* key) { - assert(key); - if (_capacity == 0) return 0; - size_t hashmod = _capacity - 1; - size_t bucket = hash(key) & hashmod; + item_t* item = get_item(key); + assert(item); + assert(item->key == key || (item->key == 0 && item->value == 0)); - for (size_t probe = 0; probe <= hashmod; ++probe) - { - item_t& probe_item = _items[bucket]; - - if (probe_item.key == key) - return &probe_item.value; - - if (probe_item.key == 0) - return 0; - - // hash collision, quadratic probing - bucket = (bucket + probe + 1) & hashmod; - } - - assert(!"Hash table is full"); - return 0; + return item->value; } - void** insert(const void* key) + void insert(const void* key, void* value) { - assert(key); - assert(_count < _capacity * 3 / 4); + assert(_capacity != 0 && _count < _capacity - _capacity / 4); - size_t hashmod = _capacity - 1; - size_t bucket = hash(key) & hashmod; + item_t* item = get_item(key); + assert(item); - for (size_t probe = 0; probe <= hashmod; ++probe) + if (item->key == 0) { - item_t& probe_item = _items[bucket]; - - if (probe_item.key == 0) - { - probe_item.key = key; - _count++; - return &probe_item.value; - } - - if (probe_item.key == key) - return &probe_item.value; - - // hash collision, quadratic probing - bucket = (bucket + probe + 1) & hashmod; + _count++; + item->key = key; } - assert(!"Hash table is full"); - return 0; + item->value = value; } - bool reserve() + bool reserve(size_t extra = 16) { - if (_count + 16 >= _capacity - _capacity / 4) - return rehash(); + if (_count + extra >= _capacity - _capacity / 4) + return rehash(_count + extra); return true; } @@ -354,9 +351,32 @@ PUGI__NS_BEGIN size_t _count; - bool rehash(); + bool rehash(size_t count); - static unsigned int hash(const void* key) + item_t* get_item(const void* key) + { + assert(key); + assert(_capacity > 0); + + size_t hashmod = _capacity - 1; + size_t bucket = hash(key) & hashmod; + + for (size_t probe = 0; probe <= hashmod; ++probe) + { + item_t& probe_item = _items[bucket]; + + if (probe_item.key == key || probe_item.key == 0) + return &probe_item; + + // hash collision, quadratic probing + bucket = (bucket + probe + 1) & hashmod; + } + + assert(false && "Hash table is full"); // unreachable + return 0; + } + + static PUGI__UNSIGNED_OVERFLOW unsigned int hash(const void* key) { unsigned int h = static_cast(reinterpret_cast(key)); @@ -371,27 +391,33 @@ PUGI__NS_BEGIN } }; - PUGI__FN_NO_INLINE bool compact_hash_table::rehash() + PUGI__FN_NO_INLINE bool compact_hash_table::rehash(size_t count) { + size_t capacity = 32; + while (count >= capacity - capacity / 4) + capacity *= 2; + compact_hash_table rt; - rt._capacity = (_capacity == 0) ? 32 : _capacity * 2; - rt._items = static_cast(xml_memory::allocate(sizeof(item_t) * rt._capacity)); + rt._capacity = capacity; + rt._items = static_cast(xml_memory::allocate(sizeof(item_t) * capacity)); if (!rt._items) return false; - memset(rt._items, 0, sizeof(item_t) * rt._capacity); + memset(rt._items, 0, sizeof(item_t) * capacity); for (size_t i = 0; i < _capacity; ++i) if (_items[i].key) - *rt.insert(_items[i].key) = _items[i].value; + rt.insert(_items[i].key, _items[i].value); if (_items) xml_memory::deallocate(_items); - _capacity = rt._capacity; + _capacity = capacity; _items = rt._items; + assert(_count == rt._count); + return true; } @@ -399,43 +425,33 @@ PUGI__NS_END #endif PUGI__NS_BEGIN - static const size_t xml_memory_page_size = - #ifdef PUGIXML_MEMORY_PAGE_SIZE - PUGIXML_MEMORY_PAGE_SIZE - #else - 32768 - #endif - ; - #ifdef PUGIXML_COMPACT static const uintptr_t xml_memory_block_alignment = 4; - - static const uintptr_t xml_memory_page_alignment = sizeof(void*); #else static const uintptr_t xml_memory_block_alignment = sizeof(void*); - - static const uintptr_t xml_memory_page_alignment = 64; - static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); #endif // extra metadata bits - static const uintptr_t xml_memory_page_contents_shared_mask = 32; - static const uintptr_t xml_memory_page_name_allocated_mask = 16; - static const uintptr_t xml_memory_page_value_allocated_mask = 8; - static const uintptr_t xml_memory_page_type_mask = 7; + static const uintptr_t xml_memory_page_contents_shared_mask = 64; + static const uintptr_t xml_memory_page_name_allocated_mask = 32; + static const uintptr_t xml_memory_page_value_allocated_mask = 16; + static const uintptr_t xml_memory_page_type_mask = 15; // combined masks for string uniqueness static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; #ifdef PUGIXML_COMPACT + #define PUGI__GETHEADER_IMPL(object, page, flags) // unused #define PUGI__GETPAGE_IMPL(header) (header).get_page() #else - #define PUGI__GETPAGE_IMPL(header) reinterpret_cast((header) & impl::xml_memory_page_pointer_mask) + #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast(object) - reinterpret_cast(page)) << 8) | (flags)) + // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings + #define PUGI__GETPAGE_IMPL(header) static_cast(const_cast(static_cast(reinterpret_cast(&header) - (header >> 8)))) #endif #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header) - #define PUGI__NODETYPE(n) static_cast(((n)->header & impl::xml_memory_page_type_mask) + 1) + #define PUGI__NODETYPE(n) static_cast((n)->header & impl::xml_memory_page_type_mask) struct xml_allocator; @@ -475,6 +491,14 @@ PUGI__NS_BEGIN #endif }; + static const size_t xml_memory_page_size = + #ifdef PUGIXML_MEMORY_PAGE_SIZE + (PUGIXML_MEMORY_PAGE_SIZE) + #else + 32768 + #endif + - sizeof(xml_memory_page); + struct xml_memory_string_header { uint16_t page_offset; // offset from page->data @@ -495,30 +519,21 @@ PUGI__NS_BEGIN size_t size = sizeof(xml_memory_page) + data_size; // allocate block with some alignment, leaving memory for worst-case padding - void* memory = xml_memory::allocate(size + xml_memory_page_alignment); + void* memory = xml_memory::allocate(size); if (!memory) return 0; - // align to next page boundary (note: this guarantees at least 1 usable byte before the page) - char* page_memory = reinterpret_cast((reinterpret_cast(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1)); - // prepare page structure - xml_memory_page* page = xml_memory_page::construct(page_memory); + xml_memory_page* page = xml_memory_page::construct(memory); assert(page); page->allocator = _root->allocator; - // record the offset for freeing the memory block - assert(page_memory > memory && page_memory - static_cast(memory) <= 127); - page_memory[-1] = static_cast(page_memory - static_cast(memory)); - return page; } static void deallocate_page(xml_memory_page* page) { - char* page_memory = reinterpret_cast(page); - - xml_memory::deallocate(page_memory - page_memory[-1]); + xml_memory::deallocate(page); } void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); @@ -627,7 +642,7 @@ PUGI__NS_BEGIN // allocate memory for string and header block size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); - + // round size up to block alignment boundary size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1); @@ -749,12 +764,12 @@ PUGI__NS_BEGIN void operator&=(uintptr_t mod) { - _flags &= mod; + _flags &= static_cast(mod); } void operator|=(uintptr_t mod) { - _flags |= mod; + _flags |= static_cast(mod); } uintptr_t operator&(uintptr_t mod) const @@ -764,10 +779,11 @@ PUGI__NS_BEGIN xml_memory_page* get_page() const { + // round-trip through void* to silence 'cast increases required alignment of target type' warnings const char* page_marker = reinterpret_cast(this) - (_page << compact_alignment_log2); - const char* page = page_marker - *reinterpret_cast(page_marker); + const char* page = page_marker - *reinterpret_cast(static_cast(page_marker)); - return const_cast(reinterpret_cast(page)); + return const_cast(reinterpret_cast(static_cast(page))); } private: @@ -784,12 +800,12 @@ PUGI__NS_BEGIN template PUGI__FN_NO_INLINE T* compact_get_value(const void* object) { - return static_cast(*compact_get_page(object, header_offset)->allocator->_hash->find(object)); + return static_cast(compact_get_page(object, header_offset)->allocator->_hash->find(object)); } template PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value) { - *compact_get_page(object, header_offset)->allocator->_hash->insert(object) = value; + compact_get_page(object, header_offset)->allocator->_hash->insert(object, value); } template class compact_pointer @@ -836,7 +852,7 @@ PUGI__NS_BEGIN { uintptr_t base = reinterpret_cast(this) & ~(compact_alignment - 1); - return reinterpret_cast(base + ((_data - 1 + start) << compact_alignment_log2)); + return reinterpret_cast(base + (_data - 1 + start) * compact_alignment); } else return compact_get_value(this); @@ -847,7 +863,7 @@ PUGI__NS_BEGIN T* operator->() const { - return operator T*(); + return *this; } private: @@ -914,7 +930,7 @@ PUGI__NS_BEGIN { uintptr_t base = reinterpret_cast(this) & ~(compact_alignment - 1); - return reinterpret_cast(base + ((_data - 1 - 65533) << compact_alignment_log2)); + return reinterpret_cast(base + (_data - 1 - 65533) * compact_alignment); } else if (_data == 65534) return static_cast(compact_get_page(this, header_offset)->compact_shared_parent); @@ -927,7 +943,7 @@ PUGI__NS_BEGIN T* operator->() const { - return operator T*(); + return *this; } private: @@ -959,7 +975,8 @@ PUGI__NS_BEGIN if (static_cast(offset) < (65535 << 7)) { - uint16_t* base = reinterpret_cast(reinterpret_cast(this) - base_offset); + // round-trip through void* to silence 'cast increases required alignment of target type' warnings + uint16_t* base = reinterpret_cast(static_cast(reinterpret_cast(this) - base_offset)); if (*base == 0) { @@ -1003,7 +1020,8 @@ PUGI__NS_BEGIN { xml_memory_page* page = compact_get_page(this, header_offset); - const uint16_t* base = reinterpret_cast(reinterpret_cast(this) - base_offset); + // round-trip through void* to silence 'cast increases required alignment of target type' warnings + const uint16_t* base = reinterpret_cast(static_cast(reinterpret_cast(this) - base_offset)); assert(*base); ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1); @@ -1048,7 +1066,7 @@ namespace pugi struct xml_node_struct { - xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type - 1), namevalue_base(0) + xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) { PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); } @@ -1075,8 +1093,9 @@ namespace pugi { struct xml_attribute_struct { - xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) + xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0) { + header = PUGI__GETHEADER_IMPL(this, page, 0); } uintptr_t header; @@ -1090,8 +1109,9 @@ namespace pugi struct xml_node_struct { - xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) + xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) { + header = PUGI__GETHEADER_IMPL(this, page, type); } uintptr_t header; @@ -1122,9 +1142,6 @@ PUGI__NS_BEGIN { xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) { - #ifdef PUGIXML_COMPACT - _hash = &hash; - #endif } const char_t* buffer; @@ -1599,28 +1616,11 @@ PUGI__NS_BEGIN } }; - template struct wchar_selector; - - template <> struct wchar_selector<2> + struct utf8_decoder { - typedef uint16_t type; - typedef utf16_counter counter; - typedef utf16_writer writer; - }; + typedef uint8_t type; - template <> struct wchar_selector<4> - { - typedef uint32_t type; - typedef utf32_counter counter; - typedef utf32_writer writer; - }; - - typedef wchar_selector::counter wchar_counter; - typedef wchar_selector::writer wchar_writer; - - template struct utf_decoder - { - static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) + template static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) { const uint8_t utf8_byte_mask = 0x3f; @@ -1681,29 +1681,34 @@ PUGI__NS_BEGIN return result; } + }; - static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) + template struct utf16_decoder + { + typedef uint16_t type; + + template static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits) { - const uint16_t* end = data + size; - - while (data < end) + while (size) { - unsigned int lead = opt_swap::value ? endian_swap(*data) : *data; + uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; // U+0000..U+D7FF if (lead < 0xD800) { result = Traits::low(result, lead); data += 1; + size -= 1; } // U+E000..U+FFFF else if (static_cast(lead - 0xE000) < 0x2000) { result = Traits::low(result, lead); data += 1; + size -= 1; } // surrogate pair lead - else if (static_cast(lead - 0xD800) < 0x400 && data + 1 < end) + else if (static_cast(lead - 0xD800) < 0x400 && size >= 2) { uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; @@ -1711,26 +1716,32 @@ PUGI__NS_BEGIN { result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); data += 2; + size -= 2; } else { data += 1; + size -= 1; } } else { data += 1; + size -= 1; } } return result; } + }; - static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) + template struct utf32_decoder + { + typedef uint32_t type; + + template static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits) { - const uint32_t* end = data + size; - - while (data < end) + while (size) { uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; @@ -1739,53 +1750,76 @@ PUGI__NS_BEGIN { result = Traits::low(result, lead); data += 1; + size -= 1; } // U+10000..U+10FFFF else { result = Traits::high(result, lead); data += 1; + size -= 1; } } return result; } + }; - static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result) + struct latin1_decoder + { + typedef uint8_t type; + + template static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) { - for (size_t i = 0; i < size; ++i) + while (size) { - result = Traits::low(result, data[i]); + result = Traits::low(result, *data); + data += 1; + size -= 1; } return result; } - - static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result) - { - return decode_utf16_block(data, size, result); - } - - static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result) - { - return decode_utf32_block(data, size, result); - } - - static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result) - { - return decode_wchar_block_impl(reinterpret_cast::type*>(data), size, result); - } }; - template PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length) + template struct wchar_selector; + + template <> struct wchar_selector<2> { - for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); - } + typedef uint16_t type; + typedef utf16_counter counter; + typedef utf16_writer writer; + typedef utf16_decoder decoder; + }; + + template <> struct wchar_selector<4> + { + typedef uint32_t type; + typedef utf32_counter counter; + typedef utf32_writer writer; + typedef utf32_decoder decoder; + }; + + typedef wchar_selector::counter wchar_counter; + typedef wchar_selector::writer wchar_writer; + + struct wchar_decoder + { + typedef wchar_t type; + + template static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits) + { + typedef wchar_selector::decoder decoder; + + return decoder::process(reinterpret_cast(data), size, result, traits); + } + }; #ifdef PUGIXML_WCHAR_MODE PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) { - for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); + for (size_t i = 0; i < length; ++i) + result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); } #endif PUGI__NS_END @@ -1832,7 +1866,7 @@ PUGI__NS_BEGIN ctx_digit = 8, // 0-9 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . }; - + static const unsigned char chartypex_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 @@ -1854,7 +1888,7 @@ PUGI__NS_BEGIN 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; - + #ifdef PUGIXML_WCHAR_MODE #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) #else @@ -1877,12 +1911,71 @@ PUGI__NS_BEGIN if (sizeof(wchar_t) == 2) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - else + else return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; } - PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) + PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) { + #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } + #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; } + + // check if we have a non-empty XML declaration + if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space))) + return false; + + // scan XML declaration until the encoding field + for (size_t i = 6; i + 1 < size; ++i) + { + // declaration can not contain ? in quoted values + if (data[i] == '?') + return false; + + if (data[i] == 'e' && data[i + 1] == 'n') + { + size_t offset = i; + + // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed + PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o'); + PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g'); + + // S? = S? + PUGI__SCANCHARTYPE(ct_space); + PUGI__SCANCHAR('='); + PUGI__SCANCHARTYPE(ct_space); + + // the only two valid delimiters are ' and " + uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\''; + + PUGI__SCANCHAR(delimiter); + + size_t start = offset; + + out_encoding = data + offset; + + PUGI__SCANCHARTYPE(ct_symbol); + + out_length = offset - start; + + PUGI__SCANCHAR(delimiter); + + return true; + } + } + + return false; + + #undef PUGI__SCANCHAR + #undef PUGI__SCANCHARTYPE + } + + PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) + { + // skip encoding autodetection if input buffer is too small + if (size < 4) return encoding_utf8; + + uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; + // look for BOM in first few bytes if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; @@ -1895,13 +1988,32 @@ PUGI__NS_BEGIN if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le; if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be; if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le; - if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8; // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be; if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; - // no known BOM detected, assume utf8 + // no known BOM detected; parse declaration + const uint8_t* enc = 0; + size_t enc_length = 0; + + if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length)) + { + // iso-8859-1 (case-insensitive) + if (enc_length == 10 + && (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o' + && enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9' + && enc[8] == '-' && enc[9] == '1') + return encoding_latin1; + + // latin1 (case-insensitive) + if (enc_length == 6 + && (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't' + && (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n' + && enc[5] == '1') + return encoding_latin1; + } + return encoding_utf8; } @@ -1919,15 +2031,10 @@ PUGI__NS_BEGIN // only do autodetection if no explicit encoding is requested if (encoding != encoding_auto) return encoding; - // skip encoding autodetection if input buffer is too small - if (size < 4) return encoding_utf8; - // try to guess encoding (based on XML specification, Appendix F.1) const uint8_t* data = static_cast(contents); - PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; - - return guess_buffer_encoding(d0, d1, d2, d3); + return guess_buffer_encoding(data, size); } PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) @@ -1994,38 +2101,13 @@ PUGI__NS_BEGIN return true; } - PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) + template PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { - const uint8_t* data = static_cast(contents); - size_t data_length = size; + const typename D::type* data = static_cast(contents); + size_t data_length = size / sizeof(typename D::type); // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf8_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf8 input to wchar_t - wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_utf8_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint16_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint16_t); - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf16_block(data, data_length, 0); + size_t length = D::process(data, data_length, 0, wchar_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); @@ -2033,57 +2115,7 @@ PUGI__NS_BEGIN // second pass: convert utf16 input to wchar_t wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_utf16_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint32_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint32_t); - - // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf32_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf32 input to wchar_t - wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_utf32_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) - { - const uint8_t* data = static_cast(contents); - size_t data_length = size; - - // get length in wchar_t units - size_t length = data_length; - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // convert latin1 input to wchar_t - wchar_writer::value_type obegin = reinterpret_cast(buffer); - wchar_writer::value_type oend = utf_decoder::decode_latin1_block(data, data_length, obegin); + wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer()); assert(oend == obegin + length); *oend = 0; @@ -2100,13 +2132,16 @@ PUGI__NS_BEGIN xml_encoding wchar_encoding = get_wchar_encoding(); // fast path: no conversion required - if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + if (encoding == wchar_encoding) + return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // only endian-swapping is required - if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); + if (need_endian_swap_utf(encoding, wchar_encoding)) + return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf8 - if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); + if (encoding == encoding_utf8) + return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder()); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) @@ -2114,8 +2149,8 @@ PUGI__NS_BEGIN xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()) : + convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()); } // source encoding is utf32 @@ -2124,24 +2159,25 @@ PUGI__NS_BEGIN xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()) : + convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()); } // source encoding is latin1 - if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size); + if (encoding == encoding_latin1) + return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); // unreachable return false; } #else - template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + template PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { - const uint16_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint16_t); + const typename D::type* data = static_cast(contents); + size_t data_length = size / sizeof(typename D::type); // first pass: get length in utf8 units - size_t length = utf_decoder::decode_utf16_block(data, data_length, 0); + size_t length = D::process(data, data_length, 0, utf8_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); @@ -2149,32 +2185,7 @@ PUGI__NS_BEGIN // second pass: convert utf16 input to utf8 uint8_t* obegin = reinterpret_cast(buffer); - uint8_t* oend = utf_decoder::decode_utf16_block(data, data_length, obegin); - - assert(oend == obegin + length); - *oend = 0; - - out_buffer = buffer; - out_length = length + 1; - - return true; - } - - template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) - { - const uint32_t* data = static_cast(contents); - size_t data_length = size / sizeof(uint32_t); - - // first pass: get length in utf8 units - size_t length = utf_decoder::decode_utf32_block(data, data_length, 0); - - // allocate buffer of suitable length - char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); - if (!buffer) return false; - - // second pass: convert utf32 input to utf8 - uint8_t* obegin = reinterpret_cast(buffer); - uint8_t* oend = utf_decoder::decode_utf32_block(data, data_length, obegin); + uint8_t* oend = D::process(data, data_length, obegin, utf8_writer()); assert(oend == obegin + length); *oend = 0; @@ -2210,7 +2221,7 @@ PUGI__NS_BEGIN if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // first pass: get length in utf8 units - size_t length = prefix_length + utf_decoder::decode_latin1_block(postfix, postfix_length, 0); + size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); @@ -2220,7 +2231,7 @@ PUGI__NS_BEGIN memcpy(buffer, data, prefix_length); uint8_t* obegin = reinterpret_cast(buffer); - uint8_t* oend = utf_decoder::decode_latin1_block(postfix, postfix_length, obegin + prefix_length); + uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer()); assert(oend == obegin + length); *oend = 0; @@ -2234,7 +2245,8 @@ PUGI__NS_BEGIN PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // fast path: no conversion required - if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + if (encoding == encoding_utf8) + return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) @@ -2242,8 +2254,8 @@ PUGI__NS_BEGIN xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()) : + convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()); } // source encoding is utf32 @@ -2252,14 +2264,15 @@ PUGI__NS_BEGIN xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : - convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()) : + convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()); } // source encoding is latin1 - if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); + if (encoding == encoding_latin1) + return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); // unreachable return false; } #endif @@ -2267,20 +2280,20 @@ PUGI__NS_BEGIN PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) { // get length in utf8 characters - return utf_decoder::decode_wchar_block(str, length, 0); + return wchar_decoder::process(str, length, 0, utf8_counter()); } PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) { // convert to utf8 uint8_t* begin = reinterpret_cast(buffer); - uint8_t* end = utf_decoder::decode_wchar_block(str, length, begin); - + uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer()); + assert(begin + size == end); (void)!end; (void)!size; } - + #ifndef PUGIXML_NO_STL PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) { @@ -2302,7 +2315,7 @@ PUGI__NS_BEGIN const uint8_t* data = reinterpret_cast(str); // first pass: get length in wchar_t units - size_t length = utf_decoder::decode_utf8_block(data, size, 0); + size_t length = utf8_decoder::process(data, size, 0, wchar_counter()); // allocate resulting string std::basic_string result; @@ -2312,7 +2325,7 @@ PUGI__NS_BEGIN if (length > 0) { wchar_writer::value_type begin = reinterpret_cast(&result[0]); - wchar_writer::value_type end = utf_decoder::decode_utf8_block(data, size, begin); + wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer()); assert(begin + length == end); (void)!end; @@ -2340,17 +2353,15 @@ PUGI__NS_BEGIN } template - PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source) + PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) { - size_t source_length = strlength(source); - if (source_length == 0) { // empty string and null pointer are equivalent, so just deallocate old memory xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; if (header & header_mask) alloc->deallocate_string(dest); - + // mark the string as not allocated dest = 0; header &= ~header_mask; @@ -2360,8 +2371,9 @@ PUGI__NS_BEGIN else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) { // we can reuse old buffer, so just copy the new data (including zero terminator) - memcpy(dest, source, (source_length + 1) * sizeof(char_t)); - + memcpy(dest, source, source_length * sizeof(char_t)); + dest[source_length] = 0; + return true; } else @@ -2375,11 +2387,12 @@ PUGI__NS_BEGIN if (!buf) return false; // copy the string (including zero terminator) - memcpy(buf, source, (source_length + 1) * sizeof(char_t)); + memcpy(buf, source, source_length * sizeof(char_t)); + buf[source_length] = 0; // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); - + // the string is now allocated, so set the flag dest = buf; header |= header_mask; @@ -2392,11 +2405,11 @@ PUGI__NS_BEGIN { char_t* end; size_t size; - + gap(): end(0), size(0) { } - + // Push new gap, move s count bytes further (skipping the gap). // Collapse previous gap. void push(char_t*& s, size_t count) @@ -2407,14 +2420,14 @@ PUGI__NS_BEGIN assert(s >= end); memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); } - + s += count; // end of current gap - + // "merge" two gaps end = s; size += count; } - + // Collapse all gaps, return past-the-end pointer char_t* flush(char_t* s) { @@ -2429,7 +2442,7 @@ PUGI__NS_BEGIN else return s; } }; - + PUGI__FN char_t* strconv_escape(char_t* s, gap& g) { char_t* stre = s + 1; @@ -2461,7 +2474,7 @@ PUGI__NS_BEGIN ch = *++stre; } - + ++stre; } else // &#... (dec code) @@ -2472,7 +2485,7 @@ PUGI__NS_BEGIN for (;;) { - if (static_cast(static_cast(ch) - '0') <= 9) + if (static_cast(ch - '0') <= 9) ucsc = 10 * ucsc + (ch - '0'); else if (ch == ';') break; @@ -2481,7 +2494,7 @@ PUGI__NS_BEGIN ch = *++stre; } - + ++stre; } @@ -2490,7 +2503,7 @@ PUGI__NS_BEGIN #else s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); #endif - + g.push(s, stre - s); return stre; } @@ -2505,7 +2518,7 @@ PUGI__NS_BEGIN { *s++ = '&'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2530,7 +2543,7 @@ PUGI__NS_BEGIN { *s++ = '>'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2543,7 +2556,7 @@ PUGI__NS_BEGIN { *s++ = '<'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2556,7 +2569,7 @@ PUGI__NS_BEGIN { *s++ = '"'; ++stre; - + g.push(s, stre - s); return stre; } @@ -2566,7 +2579,7 @@ PUGI__NS_BEGIN default: break; } - + return stre; } @@ -2574,7 +2587,7 @@ PUGI__NS_BEGIN #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) - #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } + #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } #define PUGI__POPNODE() { cursor = cursor->parent; } #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } #define PUGI__SCANWHILE(X) { while (X) ++s; } @@ -2586,21 +2599,21 @@ PUGI__NS_BEGIN PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) { gap g; - + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); - + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a - + if (*s == '\n') g.push(s, 1); } else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here { *g.flush(s) = 0; - + return s + (s[2] == '>' ? 3 : 2); } else if (*s == 0) @@ -2614,21 +2627,21 @@ PUGI__NS_BEGIN PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) { gap g; - + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); - + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a - + if (*s == '\n') g.push(s, 1); } else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here { *g.flush(s) = 0; - + return s + 1; } else if (*s == 0) @@ -2638,9 +2651,9 @@ PUGI__NS_BEGIN else ++s; } } - + typedef char_t* (*strconv_pcdata_t)(char_t*); - + template struct strconv_pcdata_impl { static char_t* parse(char_t* s) @@ -2662,13 +2675,13 @@ PUGI__NS_BEGIN --end; *end = 0; - + return s + 1; } else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a - + if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') @@ -2691,7 +2704,7 @@ PUGI__NS_BEGIN } } }; - + PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); @@ -2706,12 +2719,12 @@ PUGI__NS_BEGIN case 5: return strconv_pcdata_impl::parse; case 6: return strconv_pcdata_impl::parse; case 7: return strconv_pcdata_impl::parse; - default: assert(false); return 0; // should not get here + default: assert(false); return 0; // unreachable } } typedef char_t* (*strconv_attribute_t)(char_t*, char_t); - + template struct strconv_attribute_impl { static char_t* parse_wnorm(char_t* s, char_t end_quote) @@ -2722,35 +2735,35 @@ PUGI__NS_BEGIN if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s; - + do ++str; while (PUGI__IS_CHARTYPE(*str, ct_space)); - + g.push(s, str - s); } while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); - + if (*s == end_quote) { char_t* str = g.flush(s); - + do *str-- = 0; while (PUGI__IS_CHARTYPE(*str, ct_space)); - + return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) { *s++ = ' '; - + if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s + 1; while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; - + g.push(s, str - s); } } @@ -2773,11 +2786,11 @@ PUGI__NS_BEGIN while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); - + if (*s == end_quote) { *g.flush(s) = 0; - + return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) @@ -2785,7 +2798,7 @@ PUGI__NS_BEGIN if (*s == '\r') { *s++ = ' '; - + if (*s == '\n') g.push(s, 1); } else *s++ = ' '; @@ -2809,17 +2822,17 @@ PUGI__NS_BEGIN while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); - + if (*s == end_quote) { *g.flush(s) = 0; - + return s + 1; } else if (*s == '\r') { *s++ = '\n'; - + if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') @@ -2841,11 +2854,11 @@ PUGI__NS_BEGIN while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); - + if (*s == end_quote) { *g.flush(s) = 0; - + return s + 1; } else if (opt_escape::value && *s == '&') @@ -2864,7 +2877,7 @@ PUGI__NS_BEGIN PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); - + switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) { case 0: return strconv_attribute_impl::parse_simple; @@ -2883,7 +2896,7 @@ PUGI__NS_BEGIN case 13: return strconv_attribute_impl::parse_wnorm; case 14: return strconv_attribute_impl::parse_wnorm; case 15: return strconv_attribute_impl::parse_wnorm; - default: assert(false); return 0; // should not get here + default: assert(false); return 0; // unreachable } } @@ -2898,18 +2911,12 @@ PUGI__NS_BEGIN struct xml_parser { - xml_allocator alloc; - xml_allocator* alloc_state; + xml_allocator* alloc; char_t* error_offset; xml_parse_status error_status; - - xml_parser(xml_allocator* alloc_): alloc(*alloc_), alloc_state(alloc_), error_offset(0), error_status(status_ok) - { - } - ~xml_parser() + xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) { - *alloc_state = alloc; } // DOCTYPE consists of nested sections of the following possible types: @@ -3236,7 +3243,7 @@ PUGI__NS_BEGIN { strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); - + char_t ch = 0; xml_node_struct* cursor = root; char_t* mark = s; @@ -3267,10 +3274,10 @@ PUGI__NS_BEGIN while (true) { PUGI__SKIPWS(); // Eat any whitespace. - + if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... { - xml_attribute_struct* a = append_new_attribute(cursor, alloc); // Make space for this attribute. + xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute. if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); a->name = s; // Save the offset. @@ -3285,7 +3292,7 @@ PUGI__NS_BEGIN ch = *s; ++s; } - + if (ch == '=') // '<... #=...' { PUGI__SKIPWS(); // Eat any whitespace. @@ -3297,7 +3304,7 @@ PUGI__NS_BEGIN a->value = s; // Save the offset. s = strconv_attribute(s, ch); - + if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); // After this line the loop continues from the start; @@ -3312,7 +3319,7 @@ PUGI__NS_BEGIN else if (*s == '/') { ++s; - + if (*s == '>') { PUGI__POPNODE(); @@ -3353,7 +3360,7 @@ PUGI__NS_BEGIN { // we stepped over null terminator, backtrack & handle closing tag --s; - + if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); } else PUGI__THROW_ERROR(status_bad_start_element, s); @@ -3362,20 +3369,22 @@ PUGI__NS_BEGIN { ++s; + mark = s; + char_t* name = cursor->name; - if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s); - + if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark); + while (PUGI__IS_CHARTYPE(*s, ct_symbol)) { - if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s); + if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark); } if (*name) { if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); - else PUGI__THROW_ERROR(status_end_element_mismatch, s); + else PUGI__THROW_ERROR(status_end_element_mismatch, mark); } - + PUGI__POPNODE(); // Pop. PUGI__SKIPWS(); @@ -3429,23 +3438,31 @@ PUGI__NS_BEGIN if (!PUGI__OPTSET(parse_trim_pcdata)) s = mark; - + if (cursor->parent || PUGI__OPTSET(parse_fragment)) { - PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. - cursor->value = s; // Save the offset. + if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) + { + cursor->value = s; // Save the offset. + } + else + { + PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. + + cursor->value = s; // Save the offset. + + PUGI__POPNODE(); // Pop since this is a standalone. + } s = strconv_pcdata(s); - - PUGI__POPNODE(); // Pop since this is a standalone. - + if (!*s) break; } else { PUGI__SCANFOR(*s == '<'); // '...<' if (!*s) break; - + ++s; } @@ -3493,14 +3510,14 @@ PUGI__NS_BEGIN // get last child of the root before parsing xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0; - + // create parser on stack xml_parser parser(static_cast(xmldoc)); // save last character and make buffer zero-terminated (speeds up parsing) char_t endch = buffer[length - 1]; buffer[length - 1] = 0; - + // skip BOM to make sure it does not end up as part of parse output char_t* buffer_data = parse_skip_bom(buffer); @@ -3517,7 +3534,7 @@ PUGI__NS_BEGIN return make_parse_result(status_unrecognized_tag, length - 1); // check if there are any element nodes parsed - xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child; + xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0; if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) return make_parse_result(status_no_document_element, length - 1); @@ -3561,12 +3578,36 @@ PUGI__NS_BEGIN return encoding_utf8; } + template PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T) + { + PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); + + typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); + + return static_cast(end - dest) * sizeof(*dest); + } + + template PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap) + { + PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); + + typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); + + if (opt_swap) + { + for (typename T::value_type i = dest; i != end; ++i) + *i = endian_swap(*i); + } + + return static_cast(end - dest) * sizeof(*dest); + } + #ifdef PUGIXML_WCHAR_MODE PUGI__FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 1) return 0; - // discard last character if it's the lead of a surrogate pair + // discard last character if it's the lead of a surrogate pair return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; } @@ -3579,58 +3620,32 @@ PUGI__NS_BEGIN return length * sizeof(char_t); } - + // convert to utf8 if (encoding == encoding_utf8) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - return static_cast(end - dest); - } + return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer()); // convert to utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { - uint16_t* dest = r_u16; - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); + return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding); } // convert to utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { - uint32_t* dest = r_u32; - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_wchar_block(data, length, dest); - - // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); + return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding); } // convert to latin1 if (encoding == encoding_latin1) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); + return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); - return static_cast(end - dest); - } - - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); // unreachable return 0; } #else @@ -3654,43 +3669,22 @@ PUGI__NS_BEGIN { if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { - uint16_t* dest = r_u16; - - // convert to native utf16 - uint16_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint16_t); + return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding); } if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { - uint32_t* dest = r_u32; - - // convert to native utf32 - uint32_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); - - // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; - if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); - - return static_cast(end - dest) * sizeof(uint32_t); + return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding); } if (encoding == encoding_latin1) - { - uint8_t* dest = r_u8; - uint8_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); - return static_cast(end - dest); - } - - assert(!"Invalid encoding"); + assert(false && "Invalid encoding"); // unreachable return 0; } #endif @@ -3914,10 +3908,10 @@ PUGI__NS_BEGIN while (*s) { const char_t* prev = s; - + // While *s is a usual symbol PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); - + writer.write_buffer(prev, static_cast(s - prev)); switch (*s) @@ -4083,7 +4077,7 @@ PUGI__NS_BEGIN writer.write(' '); } - writer.write_string(a->name ? a->name : default_name); + writer.write_string(a->name ? a->name + 0 : default_name); writer.write('=', '"'); if (a->value) @@ -4096,7 +4090,7 @@ PUGI__NS_BEGIN PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); - const char_t* name = node->name ? node->name : default_name; + const char_t* name = node->name ? node->name + 0 : default_name; writer.write('<'); writer.write_string(name); @@ -4104,24 +4098,61 @@ PUGI__NS_BEGIN if (node->first_attribute) node_output_attributes(writer, node, indent, indent_length, flags, depth); - if (!node->first_child) + // element nodes can have value if parse_embed_pcdata was used + if (!node->value) { - writer.write(' ', '/', '>'); + if (!node->first_child) + { + if (flags & format_no_empty_element_tags) + { + writer.write('>', '<', '/'); + writer.write_string(name); + writer.write('>'); - return false; + return false; + } + else + { + if ((flags & format_raw) == 0) + writer.write(' '); + + writer.write('/', '>'); + + return false; + } + } + else + { + writer.write('>'); + + return true; + } } else { writer.write('>'); - return true; + text_output(writer, node->value, ctx_special_pcdata, flags); + + if (!node->first_child) + { + writer.write('<', '/'); + writer.write_string(name); + writer.write('>'); + + return false; + } + else + { + return true; + } } } PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); - const char_t* name = node->name ? node->name : default_name; + const char_t* name = node->name ? node->name + 0 : default_name; writer.write('<', '/'); writer.write_string(name); @@ -4148,7 +4179,7 @@ PUGI__NS_BEGIN case node_pi: writer.write('<', '?'); - writer.write_string(node->name ? node->name : default_name); + writer.write_string(node->name ? node->name + 0 : default_name); if (node->value) { @@ -4161,7 +4192,7 @@ PUGI__NS_BEGIN case node_declaration: writer.write('<', '?'); - writer.write_string(node->name ? node->name : default_name); + writer.write_string(node->name ? node->name + 0 : default_name); node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0); writer.write('?', '>'); break; @@ -4180,7 +4211,7 @@ PUGI__NS_BEGIN break; default: - assert(!"Invalid node type"); + assert(false && "Invalid node type"); // unreachable } } @@ -4222,6 +4253,10 @@ PUGI__NS_BEGIN if (node_output_start(writer, node, indent, indent_length, flags, depth)) { + // element nodes can have value if parse_embed_pcdata was used + if (node->value) + indent_flags = 0; + node = node->first_child; depth++; continue; @@ -4355,7 +4390,7 @@ PUGI__NS_BEGIN source_header |= xml_memory_page_contents_shared_mask; } else - strcpy_insitu(dest, header, header_mask, source); + strcpy_insitu(dest, header, header_mask, source, strlength(source)); } } @@ -4388,6 +4423,7 @@ PUGI__NS_BEGIN while (sit && sit != sn) { + // when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop if (sit != dn) { xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit)); @@ -4438,39 +4474,96 @@ PUGI__NS_BEGIN } // get value with conversion functions - PUGI__FN int get_integer_base(const char_t* value) + template PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv) { + U result = 0; const char_t* s = value; while (PUGI__IS_CHARTYPE(*s, ct_space)) s++; - if (*s == '-') - s++; + bool negative = (*s == '-'); - return (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; + s += (*s == '+' || *s == '-'); + + bool overflow = false; + + if (s[0] == '0' && (s[1] | ' ') == 'x') + { + s += 2; + + // since overflow detection relies on length of the sequence skip leading zeros + while (*s == '0') + s++; + + const char_t* start = s; + + for (;;) + { + if (static_cast(*s - '0') < 10) + result = result * 16 + (*s - '0'); + else if (static_cast((*s | ' ') - 'a') < 6) + result = result * 16 + ((*s | ' ') - 'a' + 10); + else + break; + + s++; + } + + size_t digits = static_cast(s - start); + + overflow = digits > sizeof(U) * 2; + } + else + { + // since overflow detection relies on length of the sequence skip leading zeros + while (*s == '0') + s++; + + const char_t* start = s; + + for (;;) + { + if (static_cast(*s - '0') < 10) + result = result * 10 + (*s - '0'); + else + break; + + s++; + } + + size_t digits = static_cast(s - start); + + PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2); + + const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5; + const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6'; + const size_t high_bit = sizeof(U) * 8 - 1; + + overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit))); + } + + if (negative) + { + // Workaround for crayc++ CC-3059: Expected no overflow in routine. + #ifdef _CRAYC + return (overflow || result > ~minv + 1) ? minv : ~result + 1; + #else + return (overflow || result > 0 - minv) ? minv : 0 - result; + #endif + } + else + return (overflow || result > maxv) ? maxv : result; } PUGI__FN int get_value_int(const char_t* value) { - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstol(value, 0, base)); - #else - return static_cast(strtol(value, 0, base)); - #endif + return string_to_integer(value, static_cast(INT_MIN), INT_MAX); } PUGI__FN unsigned int get_value_uint(const char_t* value) { - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstoul(value, 0, base)); - #else - return static_cast(strtoul(value, 0, base)); - #endif + return string_to_integer(value, 0, UINT_MAX); } PUGI__FN double get_value_double(const char_t* value) @@ -4503,118 +4596,117 @@ PUGI__NS_BEGIN #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long get_value_llong(const char_t* value) { - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - #ifdef PUGI__MSVC_CRT_VERSION - return _wcstoi64(value, 0, base); - #else - return wcstoll(value, 0, base); - #endif - #else - #ifdef PUGI__MSVC_CRT_VERSION - return _strtoi64(value, 0, base); - #else - return strtoll(value, 0, base); - #endif - #endif + return string_to_integer(value, static_cast(LLONG_MIN), LLONG_MAX); } PUGI__FN unsigned long long get_value_ullong(const char_t* value) { - int base = get_integer_base(value); - - #ifdef PUGIXML_WCHAR_MODE - #ifdef PUGI__MSVC_CRT_VERSION - return _wcstoui64(value, 0, base); - #else - return wcstoull(value, 0, base); - #endif - #else - #ifdef PUGI__MSVC_CRT_VERSION - return _strtoui64(value, 0, base); - #else - return strtoull(value, 0, base); - #endif - #endif + return string_to_integer(value, 0, ULLONG_MAX); } #endif + template PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) + { + char_t* result = end - 1; + U rest = negative ? 0 - value : value; + + do + { + *result-- = static_cast('0' + (rest % 10)); + rest /= 10; + } + while (rest); + + assert(result >= begin); + (void)begin; + + *result = '-'; + + return result + !negative; + } + // set value with conversion functions template - PUGI__FN bool set_value_buffer(String& dest, Header& header, uintptr_t header_mask, char (&buf)[128]) + PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) { #ifdef PUGIXML_WCHAR_MODE char_t wbuf[128]; - impl::widen_ascii(wbuf, buf); + assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0])); - return strcpy_insitu(dest, header, header_mask, wbuf); + size_t offset = 0; + for (; buf[offset]; ++offset) wbuf[offset] = buf[offset]; + + return strcpy_insitu(dest, header, header_mask, wbuf, offset); #else - return strcpy_insitu(dest, header, header_mask, buf); + return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); #endif } - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, int value) + template + PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) { - char buf[128]; - sprintf(buf, "%d", value); - - return set_value_buffer(dest, header, header_mask, buf); - } + char_t buf[64]; + char_t* end = buf + sizeof(buf) / sizeof(buf[0]); + char_t* begin = integer_to_string(buf, end, value, negative); - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned int value) - { - char buf[128]; - sprintf(buf, "%u", value); - - return set_value_buffer(dest, header, header_mask, buf); + return strcpy_insitu(dest, header, header_mask, begin, end - begin); } template PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value) { char buf[128]; - sprintf(buf, "%.9g", value); + PUGI__SNPRINTF(buf, "%.9g", value); - return set_value_buffer(dest, header, header_mask, buf); + return set_value_ascii(dest, header, header_mask, buf); } template PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value) { char buf[128]; - sprintf(buf, "%.17g", value); + PUGI__SNPRINTF(buf, "%.17g", value); - return set_value_buffer(dest, header, header_mask, buf); - } - - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, bool value) - { - return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - } - -#ifdef PUGIXML_HAS_LONG_LONG - template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, long long value) - { - char buf[128]; - sprintf(buf, "%lld", value); - - return set_value_buffer(dest, header, header_mask, buf); + return set_value_ascii(dest, header, header_mask, buf); } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned long long value) + PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) { - char buf[128]; - sprintf(buf, "%llu", value); - - return set_value_buffer(dest, header, header_mask, buf); + return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); + } + + PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) + { + // check input buffer + if (!contents && size) return make_parse_result(status_io_error); + + // get actual encoding + xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); + + // get private buffer + char_t* buffer = 0; + size_t length = 0; + + if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); + + // delete original buffer if we performed a conversion + if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); + + // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself + if (own || buffer != contents) *out_buffer = buffer; + + // store buffer for offset_debug + doc->buffer = buffer; + + // parse + xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options); + + // remember encoding + res.encoding = buffer_encoding; + + return res; } -#endif // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) @@ -4644,7 +4736,7 @@ PUGI__NS_BEGIN // check for I/O errors if (length < 0) return status_io_error; - + // check for overflow size_t result = static_cast(length); @@ -4657,7 +4749,7 @@ PUGI__NS_BEGIN } // This function assumes that buffer has extra sizeof(char_t) writable bytes after size - PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) + PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) { // We only need to zero-terminate if encoding conversion does not do it for us #ifdef PUGIXML_WCHAR_MODE @@ -4681,7 +4773,7 @@ PUGI__NS_BEGIN return size; } - PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) + PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer) { if (!file) return make_parse_result(status_file_not_found); @@ -4689,7 +4781,7 @@ PUGI__NS_BEGIN size_t size = 0; xml_parse_status size_status = get_file_size(file, size); if (size_status != status_ok) return make_parse_result(size_status); - + size_t max_suffix_size = sizeof(char_t); // allocate buffer for the whole file @@ -4706,8 +4798,13 @@ PUGI__NS_BEGIN } xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); - - return doc.load_buffer_inplace_own(contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding); + + return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); + } + + PUGI__FN void close_file(FILE* file) + { + fclose(file); } #ifndef PUGIXML_NO_STL @@ -4717,7 +4814,7 @@ PUGI__NS_BEGIN { void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); if (!memory) return 0; - + return new (memory) xml_stream_chunk(); } @@ -4827,14 +4924,14 @@ PUGI__NS_BEGIN // return buffer size_t actual_length = static_cast(stream.gcount()); assert(actual_length <= read_length); - + *out_buffer = buffer.release(); *out_size = actual_length * sizeof(T); return status_ok; } - template PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding) + template PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer) { void* buffer = 0; size_t size = 0; @@ -4855,8 +4952,8 @@ PUGI__NS_BEGIN if (status != status_ok) return make_parse_result(status); xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); - - return doc.load_buffer_inplace_own(buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding); + + return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer); } #endif @@ -4917,37 +5014,21 @@ PUGI__NS_BEGIN return ferror(file) == 0; } - PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) + struct name_null_sentry { - // check input buffer - if (!contents && size) return make_parse_result(status_io_error); + xml_node_struct* node; + char_t* name; - // get actual encoding - xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); + name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name) + { + node->name = 0; + } - // get private buffer - char_t* buffer = 0; - size_t length = 0; - - if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); - - // delete original buffer if we performed a conversion - if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); - - // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself - if (own || buffer != contents) *out_buffer = buffer; - - // store buffer for offset_debug - doc->buffer = buffer; - - // parse - xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options); - - // remember encoding - res.encoding = buffer_encoding; - - return res; - } + ~name_null_sentry() + { + node->name = name; + } + }; PUGI__NS_END namespace pugi @@ -4991,7 +5072,7 @@ namespace pugi PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) { } - + PUGI__FN xml_tree_walker::~xml_tree_walker() { } @@ -5037,7 +5118,7 @@ namespace pugi { return (_attr == r._attr); } - + PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const { return (_attr != r._attr); @@ -5047,17 +5128,17 @@ namespace pugi { return (_attr < r._attr); } - + PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const { return (_attr > r._attr); } - + PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const { return (_attr <= r._attr); } - + PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const { return (_attr >= r._attr); @@ -5075,7 +5156,7 @@ namespace pugi PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const { - return (_attr && _attr->value) ? _attr->value : def; + return (_attr && _attr->value) ? _attr->value + 0 : def; } PUGI__FN int xml_attribute::as_int(int def) const @@ -5145,7 +5226,7 @@ namespace pugi set_value(rhs); return *this; } - + PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) { set_value(rhs); @@ -5158,12 +5239,24 @@ namespace pugi return *this; } + PUGI__FN xml_attribute& xml_attribute::operator=(long rhs) + { + set_value(rhs); + return *this; + } + + PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs) + { + set_value(rhs); + return *this; + } + PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) { set_value(rhs); return *this; } - + PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) { set_value(rhs); @@ -5193,29 +5286,43 @@ namespace pugi PUGI__FN bool xml_attribute::set_name(const char_t* rhs) { if (!_attr) return false; - - return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs); + + return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } - + PUGI__FN bool xml_attribute::set_value(const char_t* rhs) { if (!_attr) return false; - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } PUGI__FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + } + + PUGI__FN bool xml_attribute::set_value(long rhs) + { + if (!_attr) return false; + + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + } + + PUGI__FN bool xml_attribute::set_value(unsigned long rhs) + { + if (!_attr) return false; + + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(double rhs) @@ -5224,7 +5331,7 @@ namespace pugi return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } - + PUGI__FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; @@ -5236,7 +5343,7 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #ifdef PUGIXML_HAS_LONG_LONG @@ -5244,14 +5351,14 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } #endif @@ -5274,7 +5381,7 @@ namespace pugi PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) { } - + PUGI__FN static void unspecified_bool_xml_node(xml_node***) { } @@ -5298,7 +5405,7 @@ namespace pugi { return iterator(0, _root); } - + PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const { return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root); @@ -5308,7 +5415,7 @@ namespace pugi { return attribute_iterator(0, _root); } - + PUGI__FN xml_object_range xml_node::children() const { return xml_object_range(begin(), end()); @@ -5338,17 +5445,17 @@ namespace pugi { return (_root < r._root); } - + PUGI__FN bool xml_node::operator>(const xml_node& r) const { return (_root > r._root); } - + PUGI__FN bool xml_node::operator<=(const xml_node& r) const { return (_root <= r._root); } - + PUGI__FN bool xml_node::operator>=(const xml_node& r) const { return (_root >= r._root); @@ -5358,7 +5465,7 @@ namespace pugi { return !_root; } - + PUGI__FN const char_t* xml_node::name() const { return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); @@ -5368,12 +5475,12 @@ namespace pugi { return _root ? PUGI__NODETYPE(_root) : node_null; } - + PUGI__FN const char_t* xml_node::value() const { return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); } - + PUGI__FN xml_node xml_node::child(const char_t* name_) const { if (!_root) return xml_node(); @@ -5391,14 +5498,14 @@ namespace pugi for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) if (i->name && impl::strequal(name_, i->name)) return xml_attribute(i); - + return xml_attribute(); } - + PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); @@ -5413,7 +5520,7 @@ namespace pugi PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); @@ -5456,7 +5563,7 @@ namespace pugi PUGI__FN xml_node xml_node::previous_sibling() const { if (!_root) return xml_node(); - + if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); else return xml_node(); } @@ -5479,7 +5586,11 @@ namespace pugi PUGI__FN const char_t* xml_node::child_value() const { if (!_root) return PUGIXML_TEXT(""); - + + // element nodes can have value if parse_embed_pcdata was used + if (PUGI__NODETYPE(_root) == node_element && _root->value) + return _root->value; + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (impl::is_text_node(i) && i->value) return i->value; @@ -5514,28 +5625,28 @@ namespace pugi PUGI__FN bool xml_node::set_name(const char_t* rhs) { - static const bool has_name[] = { false, false, true, false, false, false, true, true, false }; + xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; - if (!_root || !has_name[PUGI__NODETYPE(_root)]) + if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; - return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs); + return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } - + PUGI__FN bool xml_node::set_value(const char_t* rhs) { - static const bool has_value[] = { false, false, false, true, true, true, true, false, true }; + xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; - if (!_root || !has_value[PUGI__NODETYPE(_root)]) + if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) return false; - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5545,14 +5656,14 @@ namespace pugi impl::append_attribute(a._attr, _root); a.set_name(name_); - + return a; } PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5570,7 +5681,7 @@ namespace pugi { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5588,7 +5699,7 @@ namespace pugi { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); @@ -5675,7 +5786,7 @@ namespace pugi PUGI__FN xml_node xml_node::append_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); @@ -5695,12 +5806,12 @@ namespace pugi impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); - + xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); - + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; @@ -5713,7 +5824,7 @@ namespace pugi impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); - + xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); @@ -5731,7 +5842,7 @@ namespace pugi impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); - + xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); @@ -5963,31 +6074,27 @@ namespace pugi // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense doc->header |= impl::xml_memory_page_contents_shared_mask; - + // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) impl::xml_memory_page* page = 0; - impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page)); + impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer) + sizeof(void*), page)); (void)page; if (!extra) return impl::make_parse_result(status_out_of_memory); + #ifdef PUGIXML_COMPACT + // align the memory block to a pointer boundary; this is required for compact mode where memory allocations are only 4b aligned + // note that this requires up to sizeof(void*)-1 additional memory, which the allocation above takes into account + extra = reinterpret_cast((reinterpret_cast(extra) + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1)); + #endif + // add extra buffer to the list extra->buffer = 0; extra->next = doc->extra_buffers; doc->extra_buffers = extra; // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level - struct name_sentry - { - xml_node_struct* node; - char_t* name; - - ~name_sentry() { node->name = name; } - }; - - name_sentry sentry = { _root, _root->name }; - - sentry.node->name = 0; + impl::name_null_sentry sentry(_root); return impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &extra->buffer); } @@ -5995,7 +6102,7 @@ namespace pugi PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) { @@ -6010,7 +6117,7 @@ namespace pugi PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); - + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) @@ -6040,7 +6147,7 @@ namespace pugi if (j != _root) result[--offset] = delimiter; - if (j->name && *j->name) + if (j->name) { size_t length = impl::strlength(j->name); @@ -6059,7 +6166,7 @@ namespace pugi { xml_node found = *this; // Current search context. - if (!_root || !path_ || !path_[0]) return found; + if (!_root || !path_[0]) return found; if (path_[0] == delimiter) { @@ -6105,48 +6212,47 @@ namespace pugi PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) { walker._depth = -1; - - xml_node arg_begin = *this; + + xml_node arg_begin(_root); if (!walker.begin(arg_begin)) return false; - xml_node cur = first_child(); - + xml_node_struct* cur = _root ? _root->first_child + 0 : 0; + if (cur) { ++walker._depth; - do + do { - xml_node arg_for_each = cur; + xml_node arg_for_each(cur); if (!walker.for_each(arg_for_each)) return false; - - if (cur.first_child()) + + if (cur->first_child) { ++walker._depth; - cur = cur.first_child(); + cur = cur->first_child; } - else if (cur.next_sibling()) - cur = cur.next_sibling(); + else if (cur->next_sibling) + cur = cur->next_sibling; else { - // Borland C++ workaround - while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) + while (!cur->next_sibling && cur != _root && cur->parent) { --walker._depth; - cur = cur.parent(); + cur = cur->parent; } - - if (cur != *this) - cur = cur.next_sibling(); + + if (cur != _root) + cur = cur->next_sibling; } } - while (cur && cur != *this); + while (cur && cur != _root); } assert(walker._depth == -1); - xml_node arg_end = *this; + xml_node arg_end(_root); return walker.end(arg_end); } @@ -6213,6 +6319,7 @@ namespace pugi return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1; default: + assert(false && "Invalid node type"); // unreachable return -1; } } @@ -6237,6 +6344,10 @@ namespace pugi { if (!_root || impl::is_text_node(_root)) return _root; + // element nodes can have value if parse_embed_pcdata was used + if (PUGI__NODETYPE(_root) == node_element && _root->value) + return _root; + for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) if (impl::is_text_node(node)) return node; @@ -6286,7 +6397,7 @@ namespace pugi { xml_node_struct* d = _data(); - return (d && d->value) ? d->value : def; + return (d && d->value) ? d->value + 0 : def; } PUGI__FN int xml_text::as_int(int def) const @@ -6344,21 +6455,35 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; } PUGI__FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + } + + PUGI__FN bool xml_text::set(long rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + } + + PUGI__FN bool xml_text::set(unsigned long rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(float rhs) @@ -6379,7 +6504,7 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #ifdef PUGIXML_HAS_LONG_LONG @@ -6387,14 +6512,14 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } #endif @@ -6416,6 +6541,18 @@ namespace pugi return *this; } + PUGI__FN xml_text& xml_text::operator=(long rhs) + { + set(rhs); + return *this; + } + + PUGI__FN xml_text& xml_text::operator=(unsigned long rhs) + { + set(rhs); + return *this; + } + PUGI__FN xml_text& xml_text::operator=(double rhs) { set(rhs); @@ -6481,7 +6618,7 @@ namespace pugi { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } - + PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; @@ -6496,7 +6633,7 @@ namespace pugi PUGI__FN xml_node* xml_node_iterator::operator->() const { assert(_wrap._root); - return const_cast(&_wrap); // BCC32 workaround + return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() @@ -6542,7 +6679,7 @@ namespace pugi { return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; } - + PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const { return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; @@ -6557,7 +6694,7 @@ namespace pugi PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const { assert(_wrap._attr); - return const_cast(&_wrap); // BCC32 workaround + return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() @@ -6618,7 +6755,7 @@ namespace pugi PUGI__FN xml_node* xml_named_node_iterator::operator->() const { assert(_wrap._root); - return const_cast(&_wrap); // BCC32 workaround + return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() @@ -6699,18 +6836,37 @@ namespace pugi PUGI__FN xml_document::xml_document(): _buffer(0) { - create(); + _create(); } PUGI__FN xml_document::~xml_document() { - destroy(); + _destroy(); } +#ifdef PUGIXML_HAS_MOVE + PUGI__FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(0) + { + _create(); + _move(rhs); + } + + PUGI__FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT + { + if (this == &rhs) return *this; + + _destroy(); + _create(); + _move(rhs); + + return *this; + } +#endif + PUGI__FN void xml_document::reset() { - destroy(); - create(); + _destroy(); + _create(); } PUGI__FN void xml_document::reset(const xml_document& proto) @@ -6721,31 +6877,30 @@ namespace pugi append_copy(cur); } - PUGI__FN void xml_document::create() + PUGI__FN void xml_document::_create() { assert(!_root); #ifdef PUGIXML_COMPACT - const size_t page_offset = sizeof(uint32_t); + // space for page marker for the first page (uint32_t), rounded up to pointer size; assumes pointers are at least 32-bit + const size_t page_offset = sizeof(void*); #else const size_t page_offset = 0; #endif // initialize sentinel page - PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) + page_offset <= sizeof(_memory)); - - // align upwards to page boundary - void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1)); + PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); // prepare page structure - impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory); + impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory); assert(page); page->busy_size = impl::xml_memory_page_size; // setup first page marker #ifdef PUGIXML_COMPACT - page->compact_page_marker = reinterpret_cast(reinterpret_cast(page) + sizeof(impl::xml_memory_page)); + // round-trip through void* to avoid 'cast increases required alignment of target type' warning + page->compact_page_marker = reinterpret_cast(static_cast(reinterpret_cast(page) + sizeof(impl::xml_memory_page))); *page->compact_page_marker = sizeof(impl::xml_memory_page); #endif @@ -6756,11 +6911,16 @@ namespace pugi // setup sentinel page page->allocator = static_cast(_root); + // setup hash table pointer in allocator + #ifdef PUGIXML_COMPACT + page->allocator->_hash = &static_cast(_root)->hash; + #endif + // verify the document allocation assert(reinterpret_cast(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); } - PUGI__FN void xml_document::destroy() + PUGI__FN void xml_document::_destroy() { assert(_root); @@ -6799,19 +6959,126 @@ namespace pugi _root = 0; } +#ifdef PUGIXML_HAS_MOVE + PUGI__FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT + { + impl::xml_document_struct* doc = static_cast(_root); + impl::xml_document_struct* other = static_cast(rhs._root); + + // save first child pointer for later; this needs hash access + xml_node_struct* other_first_child = other->first_child; + + #ifdef PUGIXML_COMPACT + // reserve space for the hash table up front; this is the only operation that can fail + // if it does, we have no choice but to throw (if we have exceptions) + if (other_first_child) + { + size_t other_children = 0; + for (xml_node_struct* node = other_first_child; node; node = node->next_sibling) + other_children++; + + // in compact mode, each pointer assignment could result in a hash table request + // during move, we have to relocate document first_child and parents of all children + // normally there's just one child and its parent has a pointerless encoding but + // we assume the worst here + if (!other->_hash->reserve(other_children + 1)) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return; + #else + throw std::bad_alloc(); + #endif + } + } + #endif + + // move allocation state + doc->_root = other->_root; + doc->_busy_size = other->_busy_size; + + // move buffer state + doc->buffer = other->buffer; + doc->extra_buffers = other->extra_buffers; + _buffer = rhs._buffer; + + #ifdef PUGIXML_COMPACT + // move compact hash; note that the hash table can have pointers to other but they will be "inactive", similarly to nodes removed with remove_child + doc->hash = other->hash; + doc->_hash = &doc->hash; + + // make sure we don't access other hash up until the end when we reinitialize other document + other->_hash = 0; + #endif + + // move page structure + impl::xml_memory_page* doc_page = PUGI__GETPAGE(doc); + assert(doc_page && !doc_page->prev && !doc_page->next); + + impl::xml_memory_page* other_page = PUGI__GETPAGE(other); + assert(other_page && !other_page->prev); + + // relink pages since root page is embedded into xml_document + if (impl::xml_memory_page* page = other_page->next) + { + assert(page->prev == other_page); + + page->prev = doc_page; + + doc_page->next = page; + other_page->next = 0; + } + + // make sure pages point to the correct document state + for (impl::xml_memory_page* page = doc_page->next; page; page = page->next) + { + assert(page->allocator == other); + + page->allocator = doc; + + #ifdef PUGIXML_COMPACT + // this automatically migrates most children between documents and prevents ->parent assignment from allocating + if (page->compact_shared_parent == other) + page->compact_shared_parent = doc; + #endif + } + + // move tree structure + assert(!doc->first_child); + + doc->first_child = other_first_child; + + for (xml_node_struct* node = other_first_child; node; node = node->next_sibling) + { + #ifdef PUGIXML_COMPACT + // most children will have migrated when we reassigned compact_shared_parent + assert(node->parent == other || node->parent == doc); + + node->parent = doc; + #else + assert(node->parent == other); + node->parent = doc; + #endif + } + + // reset other document + new (other) impl::xml_document_struct(PUGI__GETPAGE(other)); + rhs._buffer = 0; + } +#endif + #ifndef PUGIXML_NO_STL PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) { reset(); - return impl::load_stream_impl(*this, stream, options, encoding); + return impl::load_stream_impl(static_cast(_root), stream, options, encoding, &_buffer); } PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) { reset(); - return impl::load_stream_impl(*this, stream, options, encoding_wchar); + return impl::load_stream_impl(static_cast(_root), stream, options, encoding_wchar, &_buffer); } #endif @@ -6837,9 +7104,9 @@ namespace pugi reset(); using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(fopen(path_, "rb"), fclose); + auto_deleter file(fopen(path_, "rb"), impl::close_file); - return impl::load_file_impl(*this, file.data, options, encoding); + return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) @@ -6847,9 +7114,9 @@ namespace pugi reset(); using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(impl::open_file_wide(path_, L"rb"), fclose); + auto_deleter file(impl::open_file_wide(path_, L"rb"), impl::close_file); - return impl::load_file_impl(*this, file.data, options, encoding); + return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) @@ -6920,7 +7187,7 @@ namespace pugi PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), fclose); + auto_deleter file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding); } @@ -6928,7 +7195,7 @@ namespace pugi PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround - auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), fclose); + auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding); } @@ -6956,14 +7223,14 @@ namespace pugi { return impl::as_utf8_impl(str.c_str(), str.size()); } - + PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) { assert(str); return impl::as_wide_impl(str, strlen(str)); } - + PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) { return impl::as_wide_impl(str.c_str(), str.size()); @@ -7095,7 +7362,7 @@ PUGI__NS_BEGIN if (begin == end) return begin; // last written element - I write = begin++; + I write = begin++; // merge unique elements while (begin != end) @@ -7110,134 +7377,76 @@ PUGI__NS_BEGIN return write + 1; } - template void copy_backwards(I begin, I end, I target) + template void insertion_sort(T* begin, T* end, const Pred& pred) { - while (begin != end) *--target = *--end; - } + if (begin == end) + return; - template void insertion_sort(I begin, I end, const Pred& pred, T*) - { - assert(begin != end); - - for (I it = begin + 1; it != end; ++it) + for (T* it = begin + 1; it != end; ++it) { T val = *it; + T* hole = it; - if (pred(val, *begin)) + // move hole backwards + while (hole > begin && pred(val, *(hole - 1))) { - // move to front - copy_backwards(begin, it, it + 1); - *begin = val; + *hole = *(hole - 1); + hole--; } + + // fill hole with element + *hole = val; + } + } + + template I median3(I first, I middle, I last, const Pred& pred) + { + if (pred(*middle, *first)) swap(middle, first); + if (pred(*last, *middle)) swap(last, middle); + if (pred(*middle, *first)) swap(middle, first); + + return middle; + } + + template void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend) + { + // invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups) + T* eq = begin; + T* lt = begin; + T* gt = end; + + while (lt < gt) + { + if (pred(*lt, pivot)) + lt++; + else if (*lt == pivot) + swap(*eq++, *lt++); else - { - I hole = it; - - // move hole backwards - while (pred(val, *(hole - 1))) - { - *hole = *(hole - 1); - hole--; - } - - // fill hole with element - *hole = val; - } + swap(*lt, *--gt); } - } - // std variant for elements with == - template void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) - { - I eqbeg = middle, eqend = middle + 1; + // we now have just 4 groups: = < >; move equal elements to the middle + T* eqbeg = gt; - // expand equal range - while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; - while (eqend != end && *eqend == *eqbeg) ++eqend; + for (T* it = begin; it != eq; ++it) + swap(*it, *--eqbeg); - // process outer elements - I ltend = eqbeg, gtbeg = eqend; - - for (;;) - { - // find the element from the right side that belongs to the left one - for (; gtbeg != end; ++gtbeg) - if (!pred(*eqbeg, *gtbeg)) - { - if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); - else break; - } - - // find the element from the left side that belongs to the right one - for (; ltend != begin; --ltend) - if (!pred(*(ltend - 1), *eqbeg)) - { - if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); - else break; - } - - // scanned all elements - if (gtbeg == end && ltend == begin) - { - *out_eqbeg = eqbeg; - *out_eqend = eqend; - return; - } - - // make room for elements by moving equal area - if (gtbeg == end) - { - if (--ltend != --eqbeg) swap(*ltend, *eqbeg); - swap(*eqbeg, *--eqend); - } - else if (ltend == begin) - { - if (eqend != gtbeg) swap(*eqbeg, *eqend); - ++eqend; - swap(*gtbeg++, *eqbeg++); - } - else swap(*gtbeg++, *--ltend); - } - } - - template void median3(I first, I middle, I last, const Pred& pred) - { - if (pred(*middle, *first)) swap(*middle, *first); - if (pred(*last, *middle)) swap(*last, *middle); - if (pred(*middle, *first)) swap(*middle, *first); - } - - template void median(I first, I middle, I last, const Pred& pred) - { - if (last - first <= 40) - { - // median of three for small chunks - median3(first, middle, last, pred); - } - else - { - // median of nine - size_t step = (last - first + 1) / 8; - - median3(first, first + step, first + 2 * step, pred); - median3(middle - step, middle, middle + step, pred); - median3(last - 2 * step, last - step, last, pred); - median3(first + step, middle, last - step, pred); - } + *out_eqbeg = eqbeg; + *out_eqend = gt; } template void sort(I begin, I end, const Pred& pred) { // sort large chunks - while (end - begin > 32) + while (end - begin > 16) { // find median element I middle = begin + (end - begin) / 2; - median(begin, middle, end - 1, pred); + I median = median3(begin, middle, end - 1, pred); // partition in three chunks (< = >) I eqbeg, eqend; - partition(begin, middle, end, pred, &eqbeg, &eqend); + partition3(begin, end, *median, pred, &eqbeg, &eqend); // loop on larger half if (eqbeg - begin > end - eqend) @@ -7253,7 +7462,7 @@ PUGI__NS_BEGIN } // insertion sort small chunk - if (begin != end) insertion_sort(begin, end, pred, &*begin); + insertion_sort(begin, end, pred); } PUGI__NS_END @@ -7270,7 +7479,7 @@ PUGI__NS_BEGIN static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); struct xpath_memory_block - { + { xpath_memory_block* next; size_t capacity; @@ -7280,25 +7489,18 @@ PUGI__NS_BEGIN double alignment; }; }; - - class xpath_allocator + + struct xpath_allocator { xpath_memory_block* _root; size_t _root_size; + bool* _error; - public: - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf* error_handler; - #endif - - xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) + xpath_allocator(xpath_memory_block* root, bool* error = 0): _root(root), _root_size(0), _error(error) { - #ifdef PUGIXML_NO_EXCEPTIONS - error_handler = 0; - #endif } - - void* allocate_nothrow(size_t size) + + void* allocate(size_t size) { // round size up to block alignment boundary size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); @@ -7319,35 +7521,22 @@ PUGI__NS_BEGIN size_t block_size = block_capacity + offsetof(xpath_memory_block, data); xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); - if (!block) return 0; - + if (!block) + { + if (_error) *_error = true; + return 0; + } + block->next = _root; block->capacity = block_capacity; - + _root = block; _root_size = size; - + return block->data; } } - void* allocate(size_t size) - { - void* result = allocate_nothrow(size); - - if (!result) - { - #ifdef PUGIXML_NO_EXCEPTIONS - assert(error_handler); - longjmp(*error_handler, 1); - #else - throw std::bad_alloc(); - #endif - } - - return result; - } - void* reallocate(void* ptr, size_t old_size, size_t new_size) { // round size up to block alignment boundary @@ -7357,33 +7546,35 @@ PUGI__NS_BEGIN // we can only reallocate the last object assert(ptr == 0 || static_cast(ptr) + old_size == &_root->data[0] + _root_size); - // adjust root size so that we have not allocated the object at all - bool only_object = (_root_size == old_size); + // try to reallocate the object inplace + if (ptr && _root_size - old_size + new_size <= _root->capacity) + { + _root_size = _root_size - old_size + new_size; + return ptr; + } - if (ptr) _root_size -= old_size; - - // allocate a new version (this will obviously reuse the memory if possible) + // allocate a new block void* result = allocate(new_size); - assert(result); + if (!result) return 0; // we have a new block - if (result != ptr && ptr) + if (ptr) { - // copy old data + // copy old data (we only support growing) assert(new_size >= old_size); memcpy(result, ptr, old_size); // free the previous page if it had no other objects - if (only_object) - { - assert(_root->data == result); - assert(_root->next); + assert(_root->data == result); + assert(_root->next); + if (_root->next->data == ptr) + { + // deallocate the whole page, unless it was the first one xpath_memory_block* next = _root->next->next; if (next) { - // deallocate the whole page, unless it was the first one xml_memory::deallocate(_root->next); _root->next = next; } @@ -7455,22 +7646,15 @@ PUGI__NS_BEGIN xpath_allocator result; xpath_allocator temp; xpath_stack stack; + bool oom; - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf error_handler; - #endif - - xpath_stack_data(): result(blocks + 0), temp(blocks + 1) + xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false) { blocks[0].next = blocks[1].next = 0; blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data); stack.result = &result; stack.temp = &temp; - - #ifdef PUGIXML_NO_EXCEPTIONS - result.error_handler = temp.error_handler = &error_handler; - #endif } ~xpath_stack_data() @@ -7492,7 +7676,7 @@ PUGI__NS_BEGIN static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) { char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); - assert(result); + if (!result) return 0; memcpy(result, string, length * sizeof(char_t)); result[length] = 0; @@ -7521,9 +7705,13 @@ PUGI__NS_BEGIN { assert(begin <= end); - size_t length = static_cast(end - begin); + if (begin == end) + return xpath_string(); - return length == 0 ? xpath_string() : xpath_string(duplicate_string(begin, length, alloc), true, length); + size_t length = static_cast(end - begin); + const char_t* data = duplicate_string(begin, length, alloc); + + return data ? xpath_string(data, true, length) : xpath_string(); } xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0) @@ -7549,7 +7737,7 @@ PUGI__NS_BEGIN // allocate new buffer char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); - assert(result); + if (!result) return; // append first string to the new buffer in case there was no reallocation if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); @@ -7574,15 +7762,18 @@ PUGI__NS_BEGIN { return _uses_heap ? _length_heap : strlength(_buffer); } - + char_t* data(xpath_allocator* alloc) { // make private heap copy if (!_uses_heap) { size_t length_ = strlength(_buffer); + const char_t* data_ = duplicate_string(_buffer, length_, alloc); - _buffer = duplicate_string(_buffer, length_, alloc); + if (!data_) return 0; + + _buffer = data_; _uses_heap = true; _length_heap = length_; } @@ -7664,14 +7855,18 @@ PUGI__NS_BEGIN case node_comment: case node_pi: return xpath_string::from_const(n.value()); - + case node_document: case node_element: { xpath_string result; + // element nodes can have value if parse_embed_pcdata was used + if (n.value()[0]) + result.append(xpath_string::from_const(n.value()), alloc); + xml_node cur = n.first_child(); - + while (cur && cur != n) { if (cur.type() == node_pcdata || cur.type() == node_cdata) @@ -7689,16 +7884,16 @@ PUGI__NS_BEGIN if (cur != n) cur = cur.next_sibling(); } } - + return result; } - + default: return xpath_string(); } } } - + PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) { assert(ln->parent == rn->parent); @@ -7722,7 +7917,7 @@ PUGI__NS_BEGIN // if rn sibling chain ended ln must be before rn return !rs; } - + PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) { // find common ancestor at the same depth, if any @@ -7803,7 +7998,7 @@ PUGI__NS_BEGIN return 0; } - + struct document_order_comparator { bool operator()(const xpath_node& lhs, const xpath_node& rhs) const @@ -7827,10 +8022,10 @@ PUGI__NS_BEGIN for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) if (a == rhs.attribute()) return true; - + return false; } - + // compare attribute parents ln = lhs.parent(); rn = rhs.parent(); @@ -7839,21 +8034,21 @@ PUGI__NS_BEGIN { // attributes go after the parent element if (lhs.parent() == rhs.node()) return false; - + ln = lhs.parent(); } else if (rhs.attribute()) { // attributes go after the parent element if (rhs.parent() == lhs.node()) return true; - + rn = rhs.parent(); } if (ln == rn) return false; if (!ln || !rn) return ln < rn; - + return node_is_before(ln.internal_object(), rn.internal_object()); } }; @@ -7866,20 +8061,22 @@ PUGI__NS_BEGIN else return rhs.attribute() ? false : lhs.node() < rhs.node(); } }; - + PUGI__FN double gen_nan() { #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) - union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1]; - u[0].i = 0x7fc00000; - return u[0].f; + PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); + typedef uint32_t UI; // BCC5 workaround + union { float f; UI i; } u; + u.i = 0x7fc00000; + return u.f; #else // fallback const volatile double zero = 0.0; return zero / zero; #endif } - + PUGI__FN bool is_nan(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) @@ -7892,7 +8089,7 @@ PUGI__NS_BEGIN return v != v; #endif } - + PUGI__FN const char_t* convert_number_to_string_special(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) @@ -7924,12 +8121,12 @@ PUGI__NS_BEGIN return 0; #endif } - + PUGI__FN bool convert_number_to_boolean(double value) { return (value != 0 && !is_nan(value)); } - + PUGI__FN void truncate_zeros(char* begin, char* end) { while (begin != end && end[-1] == '0') end--; @@ -7939,11 +8136,11 @@ PUGI__NS_BEGIN // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) - PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get base values int sign, exponent; - _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); + _ecvt_s(buffer, sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign); // truncate redundant zeros truncate_zeros(buffer, buffer + strlen(buffer)); @@ -7953,12 +8150,10 @@ PUGI__NS_BEGIN *out_exponent = exponent; } #else - PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get a scientific notation value with IEEE DBL_DIG decimals - sprintf(buffer, "%.*e", DBL_DIG, value); - assert(strlen(buffer) < buffer_size); - (void)!buffer_size; + PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value); // get the exponent (possibly negative) char* exponent_string = strchr(buffer, 'e'); @@ -7995,12 +8190,12 @@ PUGI__NS_BEGIN char* mantissa; int exponent; - convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); + convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent); // allocate a buffer of suitable length for the number size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4; char_t* result = static_cast(alloc->allocate(sizeof(char_t) * result_size)); - assert(result); + if (!result) return xpath_string(); // make the number! char_t* s = result; @@ -8017,7 +8212,7 @@ PUGI__NS_BEGIN { while (exponent > 0) { - assert(*mantissa == 0 || static_cast(static_cast(*mantissa) - '0') <= 9); + assert(*mantissa == 0 || static_cast(*mantissa - '0') <= 9); *s++ = *mantissa ? *mantissa++ : '0'; exponent--; } @@ -8050,7 +8245,7 @@ PUGI__NS_BEGIN return xpath_string::from_heap_preallocated(result, s); } - + PUGI__FN bool check_string_to_number_format(const char_t* string) { // parse leading whitespace @@ -8117,7 +8312,7 @@ PUGI__NS_BEGIN return true; } - + PUGI__FN double round_nearest(double value) { return floor(value + 0.5); @@ -8129,17 +8324,17 @@ PUGI__NS_BEGIN // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); } - + PUGI__FN const char_t* qualified_name(const xpath_node& node) { return node.attribute() ? node.attribute().name() : node.node().name(); } - + PUGI__FN const char_t* local_name(const xpath_node& node) { const char_t* name = qualified_name(node); const char_t* p = find_char(name, ':'); - + return p ? p + 1 : name; } @@ -8169,39 +8364,39 @@ PUGI__NS_BEGIN PUGI__FN const char_t* namespace_uri(xml_node node) { namespace_uri_predicate pred = node.name(); - + xml_node p = node; - + while (p) { xml_attribute a = p.find_attribute(pred); - + if (a) return a.value(); - + p = p.parent(); } - + return PUGIXML_TEXT(""); } PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { namespace_uri_predicate pred = attr.name(); - + // Default namespace does not apply to attributes if (!pred.prefix) return PUGIXML_TEXT(""); - + xml_node p = parent; - + while (p) { xml_attribute a = p.find_attribute(pred); - + if (a) return a.value(); - + p = p.parent(); } - + return PUGIXML_TEXT(""); } @@ -8284,12 +8479,10 @@ PUGI__NS_BEGIN if (!table[i]) table[i] = static_cast(i); - void* result = alloc->allocate_nothrow(sizeof(table)); + void* result = alloc->allocate(sizeof(table)); + if (!result) return 0; - if (result) - { - memcpy(result, table, sizeof(table)); - } + memcpy(result, table, sizeof(table)); return static_cast(result); } @@ -8376,7 +8569,7 @@ PUGI__NS_BEGIN static const xpath_node_set dummy_node_set; - PUGI__FN unsigned int hash_string(const char_t* str) + PUGI__FN PUGI__UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str) { // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) unsigned int result = 0; @@ -8387,11 +8580,11 @@ PUGI__NS_BEGIN result += result << 10; result ^= result >> 6; } - + result += result << 3; result ^= result >> 11; result += result << 15; - + return result; } @@ -8459,7 +8652,7 @@ PUGI__NS_BEGIN break; default: - assert(!"Invalid variable type"); + assert(false && "Invalid variable type"); // unreachable } } @@ -8480,7 +8673,7 @@ PUGI__NS_BEGIN return lhs->set(static_cast(rhs)->value); default: - assert(!"Invalid variable type"); + assert(false && "Invalid variable type"); // unreachable return false; } } @@ -8545,9 +8738,9 @@ PUGI__NS_BEGIN else type = sorted; } - + if (type != order) reverse(begin, end); - + return order; } @@ -8567,7 +8760,7 @@ PUGI__NS_BEGIN return *min_element(begin, end, document_order_comparator()); default: - assert(!"Invalid node set type"); + assert(false && "Invalid node set type"); // unreachable return xpath_node(); } } @@ -8632,7 +8825,7 @@ PUGI__NS_BEGIN { // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); - assert(data); + if (!data) return; // finalize _begin = data; @@ -8660,7 +8853,7 @@ PUGI__NS_BEGIN { if (_type == xpath_node_set::type_unsorted) sort(_begin, _end, duplicate_comparator()); - + _end = unique(_begin, _end); } @@ -8684,7 +8877,7 @@ PUGI__NS_BEGIN // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); - assert(data); + if (!data) return; // finalize _begin = data; @@ -8768,12 +8961,12 @@ PUGI__NS_BEGIN { next(); } - + const char_t* state() const { return _cur; } - + void next() { const char_t* cur = _cur; @@ -8788,7 +8981,7 @@ PUGI__NS_BEGIN case 0: _cur_lexeme = lex_eof; break; - + case '>': if (*(cur+1) == '=') { @@ -8832,7 +9025,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_equal; break; - + case '+': cur += 1; _cur_lexeme = lex_plus; @@ -8856,7 +9049,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_union; break; - + case '$': cur += 1; @@ -8874,7 +9067,7 @@ PUGI__NS_BEGIN } _cur_lexeme_contents.end = cur; - + _cur_lexeme = lex_var_ref; } else @@ -8895,7 +9088,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_close_brace; break; - + case '[': cur += 1; _cur_lexeme = lex_open_square_brace; @@ -8926,7 +9119,7 @@ PUGI__NS_BEGIN _cur_lexeme = lex_slash; } break; - + case '.': if (*(cur+1) == '.') { @@ -8942,7 +9135,7 @@ PUGI__NS_BEGIN while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; _cur_lexeme_contents.end = cur; - + _cur_lexeme = lex_number; } else @@ -8968,7 +9161,7 @@ PUGI__NS_BEGIN _cur_lexeme_contents.begin = cur; while (*cur && *cur != terminator) cur++; _cur_lexeme_contents.end = cur; - + if (!*cur) _cur_lexeme = lex_none; else @@ -8998,7 +9191,7 @@ PUGI__NS_BEGIN _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; - + if (*cur == '.') { cur++; @@ -9031,7 +9224,7 @@ PUGI__NS_BEGIN } _cur_lexeme_contents.end = cur; - + _cur_lexeme = lex_string; } else @@ -9142,7 +9335,7 @@ PUGI__NS_BEGIN axis_preceding_sibling, axis_self }; - + enum nodetest_t { nodetest_none, @@ -9177,7 +9370,7 @@ PUGI__NS_BEGIN }; template const axis_t axis_to_type::axis = N; - + class xpath_ast_node { private: @@ -9297,7 +9490,7 @@ PUGI__NS_BEGIN } } - assert(!"Wrong types"); + assert(false && "Wrong types"); // unreachable return false; } @@ -9372,7 +9565,7 @@ PUGI__NS_BEGIN } else { - assert(!"Wrong types"); + assert(false && "Wrong types"); // unreachable return false; } } @@ -9496,7 +9689,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_node: case nodetest_all: if (is_xpath_attribute(name)) @@ -9505,7 +9698,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_all_in_namespace: if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) { @@ -9513,14 +9706,14 @@ PUGI__NS_BEGIN return true; } break; - + default: ; } return false; } - + bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) { assert(n); @@ -9536,11 +9729,11 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_node: ns.push_back(xml_node(n), alloc); return true; - + case nodetest_type_comment: if (type == node_comment) { @@ -9548,7 +9741,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_text: if (type == node_pcdata || type == node_cdata) { @@ -9556,7 +9749,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_type_pi: if (type == node_pi) { @@ -9564,7 +9757,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_pi: if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) { @@ -9572,7 +9765,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_all: if (type == node_element) { @@ -9580,7 +9773,7 @@ PUGI__NS_BEGIN return true; } break; - + case nodetest_all_in_namespace: if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) { @@ -9590,7 +9783,7 @@ PUGI__NS_BEGIN break; default: - assert(!"Unknown axis"); + assert(false && "Unknown axis"); // unreachable } return false; @@ -9607,33 +9800,33 @@ PUGI__NS_BEGIN for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) if (step_push(ns, a, n, alloc) & once) return; - + break; } - + case axis_child: { for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; - + break; } - + case axis_descendant: case axis_descendant_or_self: { if (axis == axis_descendant_or_self) if (step_push(ns, n, alloc) & once) return; - + xml_node_struct* cur = n->first_child; - + while (cur) { if (step_push(ns, cur, alloc) & once) return; - + if (cur->first_child) cur = cur->first_child; else @@ -9644,32 +9837,32 @@ PUGI__NS_BEGIN if (cur == n) return; } - + cur = cur->next_sibling; } } - + break; } - + case axis_following_sibling: { for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; - + break; } - + case axis_preceding_sibling: { for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) if (step_push(ns, c, alloc) & once) return; - + break; } - + case axis_following: { xml_node_struct* cur = n; @@ -9748,7 +9941,7 @@ PUGI__NS_BEGIN break; } - + case axis_ancestor: case axis_ancestor_or_self: { @@ -9757,15 +9950,15 @@ PUGI__NS_BEGIN return; xml_node_struct* cur = n->parent; - + while (cur) { if (step_push(ns, cur, alloc) & once) return; - + cur = cur->parent; } - + break; } @@ -9783,12 +9976,12 @@ PUGI__NS_BEGIN break; } - + default: - assert(!"Unimplemented axis"); + assert(false && "Unimplemented axis"); // unreachable } } - + template void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; @@ -9803,15 +9996,15 @@ PUGI__NS_BEGIN return; xml_node_struct* cur = p; - + while (cur) { if (step_push(ns, cur, alloc) & once) return; - + cur = cur->parent; } - + break; } @@ -9827,7 +10020,7 @@ PUGI__NS_BEGIN case axis_following: { xml_node_struct* cur = p; - + while (cur) { if (cur->first_child) @@ -9864,9 +10057,9 @@ PUGI__NS_BEGIN step_fill(ns, p, alloc, once, v); break; } - + default: - assert(!"Unimplemented axis"); + assert(false && "Unimplemented axis"); // unreachable } } @@ -9908,7 +10101,7 @@ PUGI__NS_BEGIN // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); - + step_fill(ns, *it, stack.result, once, v); if (_right) apply_predicates(ns, size, stack, eval); } @@ -9926,7 +10119,7 @@ PUGI__NS_BEGIN return ns; } - + public: xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) @@ -9941,14 +10134,14 @@ PUGI__NS_BEGIN assert(type == ast_number_constant); _data.number = value; } - + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_variable); _data.variable = value; } - + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) { @@ -9983,25 +10176,25 @@ PUGI__NS_BEGIN { case ast_op_or: return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); - + case ast_op_and: return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); - + case ast_op_equal: return compare_eq(_left, _right, c, stack, equal_to()); case ast_op_not_equal: return compare_eq(_left, _right, c, stack, not_equal_to()); - + case ast_op_less: return compare_rel(_left, _right, c, stack, less()); - + case ast_op_greater: return compare_rel(_right, _left, c, stack, less()); case ast_op_less_or_equal: return compare_rel(_left, _right, c, stack, less_equal()); - + case ast_op_greater_or_equal: return compare_rel(_right, _left, c, stack, less_equal()); @@ -10027,43 +10220,43 @@ PUGI__NS_BEGIN case ast_func_boolean: return _left->eval_boolean(c, stack); - + case ast_func_not: return !_left->eval_boolean(c, stack); - + case ast_func_true: return true; - + case ast_func_false: return false; case ast_func_lang: { if (c.n.attribute()) return false; - + xpath_allocator_capture cr(stack.result); xpath_string lang = _left->eval_string(c, stack); - + for (xml_node n = c.n.node(); n; n = n.parent()) { xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); - + if (a) { const char_t* value = a.value(); - + // strnicmp / strncasecmp is not portable for (const char_t* lit = lang.c_str(); *lit; ++lit) { if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; ++value; } - + return *value == 0 || *value == '-'; } } - + return false; } @@ -10082,25 +10275,24 @@ PUGI__NS_BEGIN if (_rettype == xpath_type_boolean) return _data.variable->get_boolean(); - - // fallthrough to type conversion } + // fallthrough default: { switch (_rettype) { case xpath_type_number: return convert_number_to_boolean(eval_number(c, stack)); - + case xpath_type_string: { xpath_allocator_capture cr(stack.result); return !eval_string(c, stack).empty(); } - - case xpath_type_node_set: + + case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); @@ -10108,7 +10300,7 @@ PUGI__NS_BEGIN } default: - assert(!"Wrong expression for return type boolean"); + assert(false && "Wrong expression for return type boolean"); // unreachable return false; } } @@ -10121,7 +10313,7 @@ PUGI__NS_BEGIN { case ast_op_add: return _left->eval_number(c, stack) + _right->eval_number(c, stack); - + case ast_op_subtract: return _left->eval_number(c, stack) - _right->eval_number(c, stack); @@ -10142,7 +10334,7 @@ PUGI__NS_BEGIN case ast_func_last: return static_cast(c.size); - + case ast_func_position: return static_cast(c.position); @@ -10152,28 +10344,28 @@ PUGI__NS_BEGIN return static_cast(_left->eval_node_set(c, stack, nodeset_eval_all).size()); } - + case ast_func_string_length_0: { xpath_allocator_capture cr(stack.result); return static_cast(string_value(c.n, stack.result).length()); } - + case ast_func_string_length_1: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_string(c, stack).length()); } - + case ast_func_number_0: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(string_value(c.n, stack.result).c_str()); } - + case ast_func_number_1: return _left->eval_number(c, stack); @@ -10182,76 +10374,75 @@ PUGI__NS_BEGIN xpath_allocator_capture cr(stack.result); double r = 0; - + xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); - + for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) { xpath_allocator_capture cri(stack.result); r += convert_string_to_number(string_value(*it, stack.result).c_str()); } - + return r; } case ast_func_floor: { double r = _left->eval_number(c, stack); - + return r == r ? floor(r) : r; } case ast_func_ceiling: { double r = _left->eval_number(c, stack); - + return r == r ? ceil(r) : r; } case ast_func_round: return round_nearest_nzero(_left->eval_number(c, stack)); - + case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_number) return _data.variable->get_number(); - - // fallthrough to type conversion } + // fallthrough default: { switch (_rettype) { case xpath_type_boolean: return eval_boolean(c, stack) ? 1 : 0; - + case xpath_type_string: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } - + case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } - + default: - assert(!"Wrong expression for return type number"); + assert(false && "Wrong expression for return type number"); // unreachable return 0; } - + } } } - + xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) { assert(_type == ast_func_concat); @@ -10262,16 +10453,9 @@ PUGI__NS_BEGIN size_t count = 1; for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; - // gather all strings - xpath_string static_buffer[4]; - xpath_string* buffer = static_buffer; - - // allocate on-heap for large concats - if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) - { - buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); - assert(buffer); - } + // allocate a buffer for temporary string objects + xpath_string* buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); + if (!buffer) return xpath_string(); // evaluate all strings to temporary stack xpath_stack swapped_stack = {stack.temp, stack.result}; @@ -10288,7 +10472,7 @@ PUGI__NS_BEGIN // create final string char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); - assert(result); + if (!result) return xpath_string(); char_t* ri = result; @@ -10307,11 +10491,11 @@ PUGI__NS_BEGIN { case ast_string_constant: return xpath_string::from_const(_data.string); - + case ast_func_local_name_0: { xpath_node na = c.n; - + return xpath_string::from_const(local_name(na)); } @@ -10321,14 +10505,14 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); - + return xpath_string::from_const(local_name(na)); } case ast_func_name_0: { xpath_node na = c.n; - + return xpath_string::from_const(qualified_name(na)); } @@ -10338,14 +10522,14 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); - + return xpath_string::from_const(qualified_name(na)); } case ast_func_namespace_uri_0: { xpath_node na = c.n; - + return xpath_string::from_const(namespace_uri(na)); } @@ -10355,7 +10539,7 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); - + return xpath_string::from_const(namespace_uri(na)); } @@ -10378,10 +10562,10 @@ PUGI__NS_BEGIN xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); - + return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); } - + case ast_func_substring_after: { xpath_allocator_capture cr(stack.temp); @@ -10390,7 +10574,7 @@ PUGI__NS_BEGIN xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); - + const char_t* pos = find_substring(s.c_str(), p.c_str()); if (!pos) return xpath_string(); @@ -10410,19 +10594,19 @@ PUGI__NS_BEGIN size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); - + if (is_nan(first)) return xpath_string(); // NaN else if (first >= s_length + 1) return xpath_string(); - + size_t pos = first < 1 ? 1 : static_cast(first); assert(1 <= pos && pos <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + s.length(); - + return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } - + case ast_func_substring_3: { xpath_allocator_capture cr(stack.temp); @@ -10434,12 +10618,12 @@ PUGI__NS_BEGIN double first = round_nearest(_right->eval_number(c, stack)); double last = first + round_nearest(_right->_next->eval_number(c, stack)); - + if (is_nan(first) || is_nan(last)) return xpath_string(); else if (first >= s_length + 1) return xpath_string(); else if (first >= last) return xpath_string(); else if (last < 1) return xpath_string(); - + size_t pos = first < 1 ? 1 : static_cast(first); size_t end = last >= s_length + 1 ? s_length + 1 : static_cast(last); @@ -10455,6 +10639,8 @@ PUGI__NS_BEGIN xpath_string s = string_value(c.n, stack.result); char_t* begin = s.data(stack.result); + if (!begin) return xpath_string(); + char_t* end = normalize_space(begin); return xpath_string::from_heap_preallocated(begin, end); @@ -10465,8 +10651,10 @@ PUGI__NS_BEGIN xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); + if (!begin) return xpath_string(); + char_t* end = normalize_space(begin); - + return xpath_string::from_heap_preallocated(begin, end); } @@ -10481,6 +10669,8 @@ PUGI__NS_BEGIN xpath_string to = _right->_next->eval_string(c, swapped_stack); char_t* begin = s.data(stack.result); + if (!begin) return xpath_string(); + char_t* end = translate(begin, from.c_str(), to.c_str(), to.length()); return xpath_string::from_heap_preallocated(begin, end); @@ -10491,6 +10681,8 @@ PUGI__NS_BEGIN xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); + if (!begin) return xpath_string(); + char_t* end = translate_table(begin, _data.table); return xpath_string::from_heap_preallocated(begin, end); @@ -10502,20 +10694,19 @@ PUGI__NS_BEGIN if (_rettype == xpath_type_string) return xpath_string::from_const(_data.variable->get_string()); - - // fallthrough to type conversion } + // fallthrough default: { switch (_rettype) { case xpath_type_boolean: return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); - + case xpath_type_number: return convert_number_to_string(eval_number(c, stack), stack.result); - + case xpath_type_node_set: { xpath_allocator_capture cr(stack.temp); @@ -10525,9 +10716,9 @@ PUGI__NS_BEGIN xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); } - + default: - assert(!"Wrong expression for return type string"); + assert(false && "Wrong expression for return type string"); // unreachable return xpath_string(); } } @@ -10566,20 +10757,20 @@ PUGI__NS_BEGIN bool once = eval_once(set.type(), eval); apply_predicate(set, 0, stack, once); - + return set; } - + case ast_func_id: return xpath_node_set_raw(); - + case ast_step: { switch (_axis) { case axis_ancestor: return step_do(c, stack, eval, axis_to_type()); - + case axis_ancestor_or_self: return step_do(c, stack, eval, axis_to_type()); @@ -10588,7 +10779,7 @@ PUGI__NS_BEGIN case axis_child: return step_do(c, stack, eval, axis_to_type()); - + case axis_descendant: return step_do(c, stack, eval, axis_to_type()); @@ -10597,28 +10788,28 @@ PUGI__NS_BEGIN case axis_following: return step_do(c, stack, eval, axis_to_type()); - + case axis_following_sibling: return step_do(c, stack, eval, axis_to_type()); - + case axis_namespace: // namespaced axis is not supported return xpath_node_set_raw(); - + case axis_parent: return step_do(c, stack, eval, axis_to_type()); - + case axis_preceding: return step_do(c, stack, eval, axis_to_type()); case axis_preceding_sibling: return step_do(c, stack, eval, axis_to_type()); - + case axis_self: return step_do(c, stack, eval, axis_to_type()); default: - assert(!"Unknown axis"); + assert(false && "Unknown axis"); // unreachable return xpath_node_set_raw(); } } @@ -10652,21 +10843,25 @@ PUGI__NS_BEGIN return ns; } - - // fallthrough to type conversion } + // fallthrough default: - assert(!"Wrong expression for return type node set"); + assert(false && "Wrong expression for return type node set"); // unreachable return xpath_node_set_raw(); } } void optimize(xpath_allocator* alloc) { - if (_left) _left->optimize(alloc); - if (_right) _right->optimize(alloc); - if (_next) _next->optimize(alloc); + if (_left) + _left->optimize(alloc); + + if (_right) + _right->optimize(alloc); + + if (_next) + _next->optimize(alloc); optimize_self(alloc); } @@ -10730,7 +10925,7 @@ PUGI__NS_BEGIN _type = ast_opt_compare_attribute; } } - + bool is_posinv_expr() const { switch (_type) @@ -10754,10 +10949,10 @@ PUGI__NS_BEGIN default: if (_left && !_left->is_posinv_expr()) return false; - + for (xpath_ast_node* n = _right; n; n = n->_next) if (!n->is_posinv_expr()) return false; - + return true; } } @@ -10795,65 +10990,77 @@ PUGI__NS_BEGIN char_t _scratch[32]; - #ifdef PUGIXML_NO_EXCEPTIONS - jmp_buf _error_handler; - #endif - - void throw_error(const char* message) + xpath_ast_node* error(const char* message) { _result->error = message; _result->offset = _lexer.current_pos() - _query; - #ifdef PUGIXML_NO_EXCEPTIONS - longjmp(_error_handler, 1); - #else - throw xpath_exception(*_result); - #endif + return 0; } - void throw_error_oom() + xpath_ast_node* error_oom() { - #ifdef PUGIXML_NO_EXCEPTIONS - throw_error("Out of memory"); - #else - throw std::bad_alloc(); - #endif + assert(_alloc->_error); + *_alloc->_error = true; + + return 0; } void* alloc_node() { - void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); + return _alloc->allocate(sizeof(xpath_ast_node)); + } - if (!result) throw_error_oom(); + xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, const char_t* value) + { + void* memory = alloc_node(); + return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; + } - return result; + xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, double value) + { + void* memory = alloc_node(); + return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; + } + + xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value) + { + void* memory = alloc_node(); + return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; + } + + xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0) + { + void* memory = alloc_node(); + return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : 0; + } + + xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents) + { + void* memory = alloc_node(); + return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : 0; + } + + xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test) + { + void* memory = alloc_node(); + return memory ? new (memory) xpath_ast_node(type, left, right, test) : 0; } const char_t* alloc_string(const xpath_lexer_string& value) { - if (value.begin) - { - size_t length = static_cast(value.end - value.begin); + if (!value.begin) + return PUGIXML_TEXT(""); - char_t* c = static_cast(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); - if (!c) throw_error_oom(); - assert(c); // workaround for clang static analysis + size_t length = static_cast(value.end - value.begin); - memcpy(c, value.begin, length * sizeof(char_t)); - c[length] = 0; + char_t* c = static_cast(_alloc->allocate((length + 1) * sizeof(char_t))); + if (!c) return 0; - return c; - } - else return 0; - } + memcpy(c, value.begin, length * sizeof(char_t)); + c[length] = 0; - xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) - { - assert(argc <= 1); - - if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - - return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); + return c; } xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) @@ -10862,111 +11069,118 @@ PUGI__NS_BEGIN { case 'b': if (name == PUGIXML_TEXT("boolean") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); - + return alloc_node(ast_func_boolean, xpath_type_boolean, args[0]); + break; - + case 'c': if (name == PUGIXML_TEXT("count") && argc == 1) { - if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); + if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); + return alloc_node(ast_func_count, xpath_type_number, args[0]); } else if (name == PUGIXML_TEXT("contains") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); + return alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); else if (name == PUGIXML_TEXT("concat") && argc >= 2) - return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); + return alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("ceiling") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); - - break; - - case 'f': - if (name == PUGIXML_TEXT("false") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); - else if (name == PUGIXML_TEXT("floor") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); - - break; - - case 'i': - if (name == PUGIXML_TEXT("id") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); - - break; - - case 'l': - if (name == PUGIXML_TEXT("last") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); - else if (name == PUGIXML_TEXT("lang") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("local-name") && argc <= 1) - return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); - - break; - - case 'n': - if (name == PUGIXML_TEXT("name") && argc <= 1) - return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); - else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) - return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); - else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("not") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); - else if (name == PUGIXML_TEXT("number") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); - - break; - - case 'p': - if (name == PUGIXML_TEXT("position") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); - - break; - - case 'r': - if (name == PUGIXML_TEXT("round") && argc == 1) - return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); + return alloc_node(ast_func_ceiling, xpath_type_number, args[0]); break; - - case 's': - if (name == PUGIXML_TEXT("string") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); - else if (name == PUGIXML_TEXT("string-length") && argc <= 1) - return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); - else if (name == PUGIXML_TEXT("starts-with") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring-before") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring-after") && argc == 2) - return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) - return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); - else if (name == PUGIXML_TEXT("sum") && argc == 1) + + case 'f': + if (name == PUGIXML_TEXT("false") && argc == 0) + return alloc_node(ast_func_false, xpath_type_boolean); + else if (name == PUGIXML_TEXT("floor") && argc == 1) + return alloc_node(ast_func_floor, xpath_type_number, args[0]); + + break; + + case 'i': + if (name == PUGIXML_TEXT("id") && argc == 1) + return alloc_node(ast_func_id, xpath_type_node_set, args[0]); + + break; + + case 'l': + if (name == PUGIXML_TEXT("last") && argc == 0) + return alloc_node(ast_func_last, xpath_type_number); + else if (name == PUGIXML_TEXT("lang") && argc == 1) + return alloc_node(ast_func_lang, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("local-name") && argc <= 1) { - if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); - return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); + return alloc_node(argc == 0 ? ast_func_local_name_0 : ast_func_local_name_1, xpath_type_string, args[0]); } break; - + + case 'n': + if (name == PUGIXML_TEXT("name") && argc <= 1) + { + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); + return alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]); + } + else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) + { + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); + return alloc_node(argc == 0 ? ast_func_namespace_uri_0 : ast_func_namespace_uri_1, xpath_type_string, args[0]); + } + else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) + return alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("not") && argc == 1) + return alloc_node(ast_func_not, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("number") && argc <= 1) + return alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); + + break; + + case 'p': + if (name == PUGIXML_TEXT("position") && argc == 0) + return alloc_node(ast_func_position, xpath_type_number); + + break; + + case 'r': + if (name == PUGIXML_TEXT("round") && argc == 1) + return alloc_node(ast_func_round, xpath_type_number, args[0]); + + break; + + case 's': + if (name == PUGIXML_TEXT("string") && argc <= 1) + return alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("string-length") && argc <= 1) + return alloc_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); + else if (name == PUGIXML_TEXT("starts-with") && argc == 2) + return alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-before") && argc == 2) + return alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-after") && argc == 2) + return alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) + return alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("sum") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); + return alloc_node(ast_func_sum, xpath_type_number, args[0]); + } + + break; + case 't': if (name == PUGIXML_TEXT("translate") && argc == 3) - return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); + return alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("true") && argc == 0) - return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); - + return alloc_node(ast_func_true, xpath_type_boolean); + break; default: break; } - throw_error("Unrecognized function or wrong parameter count"); - - return 0; + return error("Unrecognized function or wrong parameter count"); } axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) @@ -10982,37 +11196,37 @@ PUGI__NS_BEGIN return axis_ancestor_or_self; else if (name == PUGIXML_TEXT("attribute")) return axis_attribute; - + break; - + case 'c': if (name == PUGIXML_TEXT("child")) return axis_child; - + break; - + case 'd': if (name == PUGIXML_TEXT("descendant")) return axis_descendant; else if (name == PUGIXML_TEXT("descendant-or-self")) return axis_descendant_or_self; - + break; - + case 'f': if (name == PUGIXML_TEXT("following")) return axis_following; else if (name == PUGIXML_TEXT("following-sibling")) return axis_following_sibling; - + break; - + case 'n': if (name == PUGIXML_TEXT("namespace")) return axis_namespace; - + break; - + case 'p': if (name == PUGIXML_TEXT("parent")) return axis_parent; @@ -11020,13 +11234,13 @@ PUGI__NS_BEGIN return axis_preceding; else if (name == PUGIXML_TEXT("preceding-sibling")) return axis_preceding_sibling; - + break; - + case 's': if (name == PUGIXML_TEXT("self")) return axis_self; - + break; default: @@ -11064,7 +11278,7 @@ PUGI__NS_BEGIN return nodetest_type_text; break; - + default: break; } @@ -11082,18 +11296,18 @@ PUGI__NS_BEGIN xpath_lexer_string name = _lexer.contents(); if (!_variables) - throw_error("Unknown variable: variable set is not provided"); + return error("Unknown variable: variable set is not provided"); xpath_variable* var = 0; if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var)) - throw_error_oom(); + return error_oom(); if (!var) - throw_error("Unknown variable: variable set does not contain the given name"); + return error("Unknown variable: variable set does not contain the given name"); _lexer.next(); - return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); + return alloc_node(ast_variable, var->type(), var); } case lex_open_brace: @@ -11101,9 +11315,10 @@ PUGI__NS_BEGIN _lexer.next(); xpath_ast_node* n = parse_expression(); + if (!n) return 0; if (_lexer.current() != lex_close_brace) - throw_error("Unmatched braces"); + return error("Expected ')' to match an opening '('"); _lexer.next(); @@ -11113,11 +11328,11 @@ PUGI__NS_BEGIN case lex_quoted_string: { const char_t* value = alloc_string(_lexer.contents()); + if (!value) return 0; - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); _lexer.next(); - return n; + return alloc_node(ast_string_constant, xpath_type_string, value); } case lex_number: @@ -11125,84 +11340,86 @@ PUGI__NS_BEGIN double value = 0; if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value)) - throw_error_oom(); + return error_oom(); - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); _lexer.next(); - return n; + return alloc_node(ast_number_constant, xpath_type_number, value); } case lex_string: { xpath_ast_node* args[2] = {0}; size_t argc = 0; - + xpath_lexer_string function = _lexer.contents(); _lexer.next(); - - xpath_ast_node* last_arg = 0; - - if (_lexer.current() != lex_open_brace) - throw_error("Unrecognized function call"); - _lexer.next(); - if (_lexer.current() != lex_close_brace) - args[argc++] = parse_expression(); + xpath_ast_node* last_arg = 0; + + if (_lexer.current() != lex_open_brace) + return error("Unrecognized function call"); + _lexer.next(); while (_lexer.current() != lex_close_brace) { - if (_lexer.current() != lex_comma) - throw_error("No comma between function arguments"); - _lexer.next(); - + if (argc > 0) + { + if (_lexer.current() != lex_comma) + return error("No comma between function arguments"); + _lexer.next(); + } + xpath_ast_node* n = parse_expression(); - + if (!n) return 0; + if (argc < 2) args[argc] = n; else last_arg->set_next(n); argc++; last_arg = n; } - + _lexer.next(); return parse_function(function, argc, args); } default: - throw_error("Unrecognizable primary expression"); - - return 0; + return error("Unrecognizable primary expression"); } } - + // FilterExpr ::= PrimaryExpr | FilterExpr Predicate // Predicate ::= '[' PredicateExpr ']' // PredicateExpr ::= Expr xpath_ast_node* parse_filter_expression() { xpath_ast_node* n = parse_primary_expression(); + if (!n) return 0; while (_lexer.current() == lex_open_square_brace) { _lexer.next(); + if (n->rettype() != xpath_type_node_set) + return error("Predicate has to be applied to node set"); + xpath_ast_node* expr = parse_expression(); + if (!expr) return 0; - if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); - - n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default); + n = alloc_node(ast_filter, n, expr, predicate_default); + if (!n) return 0; if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); - + return error("Expected ']' to match an opening '['"); + _lexer.next(); } - + return n; } - + // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep // AxisSpecifier ::= AxisName '::' | '@'? // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' @@ -11211,7 +11428,7 @@ PUGI__NS_BEGIN xpath_ast_node* parse_step(xpath_ast_node* set) { if (set && set->rettype() != xpath_type_node_set) - throw_error("Step has to be applied to node set"); + return error("Step has to be applied to node set"); bool axis_specified = false; axis_t axis = axis_child; // implied child axis @@ -11220,25 +11437,31 @@ PUGI__NS_BEGIN { axis = axis_attribute; axis_specified = true; - + _lexer.next(); } else if (_lexer.current() == lex_dot) { _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); + + if (_lexer.current() == lex_open_square_brace) + return error("Predicates are not allowed after an abbreviated step"); + + return alloc_node(ast_step, set, axis_self, nodetest_type_node, 0); } else if (_lexer.current() == lex_double_dot) { _lexer.next(); - - return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); + + if (_lexer.current() == lex_open_square_brace) + return error("Predicates are not allowed after an abbreviated step"); + + return alloc_node(ast_step, set, axis_parent, nodetest_type_node, 0); } - + nodetest_t nt_type = nodetest_none; xpath_lexer_string nt_name; - + if (_lexer.current() == lex_string) { // node name test @@ -11249,11 +11472,13 @@ PUGI__NS_BEGIN if (_lexer.current() == lex_double_colon) { // parse axis name - if (axis_specified) throw_error("Two axis specifiers in one step"); + if (axis_specified) + return error("Two axis specifiers in one step"); axis = parse_axis_name(nt_name, axis_specified); - if (!axis_specified) throw_error("Unknown axis"); + if (!axis_specified) + return error("Unknown axis"); // read actual node test _lexer.next(); @@ -11269,42 +11494,47 @@ PUGI__NS_BEGIN nt_name = _lexer.contents(); _lexer.next(); } - else throw_error("Unrecognized node test"); + else + { + return error("Unrecognized node test"); + } } - + if (nt_type == nodetest_none) { // node type test or processing-instruction if (_lexer.current() == lex_open_brace) { _lexer.next(); - + if (_lexer.current() == lex_close_brace) { _lexer.next(); nt_type = parse_node_test_type(nt_name); - if (nt_type == nodetest_none) throw_error("Unrecognized node type"); - + if (nt_type == nodetest_none) + return error("Unrecognized node type"); + nt_name = xpath_lexer_string(); } else if (nt_name == PUGIXML_TEXT("processing-instruction")) { if (_lexer.current() != lex_quoted_string) - throw_error("Only literals are allowed as arguments to processing-instruction()"); - + return error("Only literals are allowed as arguments to processing-instruction()"); + nt_type = nodetest_pi; nt_name = _lexer.contents(); _lexer.next(); - + if (_lexer.current() != lex_close_brace) - throw_error("Unmatched brace near processing-instruction()"); + return error("Unmatched brace near processing-instruction()"); _lexer.next(); } else - throw_error("Unmatched brace near node type test"); - + { + return error("Unmatched brace near node type test"); + } } // QName or NCName:* else @@ -11312,10 +11542,13 @@ PUGI__NS_BEGIN if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* { nt_name.end--; // erase * - + nt_type = nodetest_all_in_namespace; } - else nt_type = nodetest_name; + else + { + nt_type = nodetest_name; + } } } } @@ -11324,52 +11557,66 @@ PUGI__NS_BEGIN nt_type = nodetest_all; _lexer.next(); } - else throw_error("Unrecognized node test"); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); - + else + { + return error("Unrecognized node test"); + } + + const char_t* nt_name_copy = alloc_string(nt_name); + if (!nt_name_copy) return 0; + + xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy); + if (!n) return 0; + xpath_ast_node* last = 0; - + while (_lexer.current() == lex_open_square_brace) { _lexer.next(); - - xpath_ast_node* expr = parse_expression(); - xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default); - + xpath_ast_node* expr = parse_expression(); + if (!expr) return 0; + + xpath_ast_node* pred = alloc_node(ast_predicate, 0, expr, predicate_default); + if (!pred) return 0; + if (_lexer.current() != lex_close_square_brace) - throw_error("Unmatched square brace"); + return error("Expected ']' to match an opening '['"); _lexer.next(); - + if (last) last->set_next(pred); else n->set_right(pred); - + last = pred; } return n; } - + // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) { xpath_ast_node* n = parse_step(set); - + if (!n) return 0; + while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); if (l == lex_double_slash) - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - + { + n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + if (!n) return 0; + } + n = parse_step(n); + if (!n) return 0; } - + return n; } - + // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath xpath_ast_node* parse_location_path() @@ -11377,8 +11624,9 @@ PUGI__NS_BEGIN if (_lexer.current() == lex_slash) { _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + + xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); + if (!n) return 0; // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path lexeme_t l = _lexer.current(); @@ -11391,17 +11639,20 @@ PUGI__NS_BEGIN else if (_lexer.current() == lex_double_slash) { _lexer.next(); - - xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - + + xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); + if (!n) return 0; + + n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + if (!n) return 0; + return parse_relative_location_path(n); } // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 return parse_relative_location_path(0); } - + // PathExpr ::= LocationPath // | FilterExpr // | FilterExpr '/' RelativeLocationPath @@ -11416,8 +11667,7 @@ PUGI__NS_BEGIN // PrimaryExpr begins with '$' in case of it being a variable reference, // '(' in case of it being an expression, string literal, number constant or // function call. - - if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || + if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || _lexer.current() == lex_string) { @@ -11425,29 +11675,34 @@ PUGI__NS_BEGIN { // This is either a function call, or not - if not, we shall proceed with location path const char_t* state = _lexer.state(); - + while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; - - if (*state != '(') return parse_location_path(); + + if (*state != '(') + return parse_location_path(); // This looks like a function call; however this still can be a node-test. Check it. - if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); + if (parse_node_test_type(_lexer.contents()) != nodetest_none) + return parse_location_path(); } - + xpath_ast_node* n = parse_filter_expression(); + if (!n) return 0; if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); - + if (l == lex_double_slash) { - if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); + if (n->rettype() != xpath_type_node_set) + return error("Step has to be applied to node set"); - n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + if (!n) return 0; } - + // select from location path return parse_relative_location_path(n); } @@ -11459,12 +11714,15 @@ PUGI__NS_BEGIN _lexer.next(); // precedence 7+ - only parses union expressions - xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7); + xpath_ast_node* n = parse_expression(7); + if (!n) return 0; - return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); + return alloc_node(ast_op_negate, xpath_type_number, n); } else + { return parse_location_path(); + } } struct binary_op_t @@ -11542,20 +11800,23 @@ PUGI__NS_BEGIN _lexer.next(); xpath_ast_node* rhs = parse_path_or_unary_expression(); + if (!rhs) return 0; binary_op_t nextop = binary_op_t::parse(_lexer); while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence) { rhs = parse_expression_rec(rhs, nextop.precedence); + if (!rhs) return 0; nextop = binary_op_t::parse(_lexer); } if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set)) - throw_error("Union operator has to be applied to node sets"); + return error("Union operator has to be applied to node sets"); - lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs); + lhs = alloc_node(op.asttype, op.rettype, lhs, rhs); + if (!lhs) return 0; op = binary_op_t::parse(_lexer); } @@ -11581,9 +11842,12 @@ PUGI__NS_BEGIN // | MultiplicativeExpr '*' UnaryExpr // | MultiplicativeExpr 'div' UnaryExpr // | MultiplicativeExpr 'mod' UnaryExpr - xpath_ast_node* parse_expression() + xpath_ast_node* parse_expression(int limit = 0) { - return parse_expression_rec(parse_path_or_unary_expression(), 0); + xpath_ast_node* n = parse_path_or_unary_expression(); + if (!n) return 0; + + return parse_expression_rec(n, limit); } xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) @@ -11592,28 +11856,21 @@ PUGI__NS_BEGIN xpath_ast_node* parse() { - xpath_ast_node* result = parse_expression(); - + xpath_ast_node* n = parse_expression(); + if (!n) return 0; + + // check if there are unparsed tokens left if (_lexer.current() != lex_eof) - { - // there are still unparsed tokens left, error - throw_error("Incorrect query"); - } - - return result; + return error("Incorrect query"); + + return n; } static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) { xpath_parser parser(query, variables, alloc, result); - #ifdef PUGIXML_NO_EXCEPTIONS - int error = setjmp(parser._error_handler); - - return (error == 0) ? parser.parse() : 0; - #else return parser.parse(); - #endif } }; @@ -11636,7 +11893,7 @@ PUGI__NS_BEGIN xml_memory::deallocate(impl); } - xpath_query_impl(): root(0), alloc(&block) + xpath_query_impl(): root(0), alloc(&block, &oom), oom(false) { block.next = 0; block.capacity = sizeof(block.data); @@ -11645,21 +11902,9 @@ PUGI__NS_BEGIN xpath_ast_node* root; xpath_allocator alloc; xpath_memory_block block; + bool oom; }; - PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) - { - if (!impl) return xpath_string(); - - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_string(); - #endif - - xpath_context c(n, 1, 1); - - return impl->root->eval_string(c, sd.stack); - } - PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) { if (!impl) return 0; @@ -11687,7 +11932,7 @@ namespace pugi { assert(_result.error); } - + PUGI__FN const char* xpath_exception::what() const throw() { return _result.error; @@ -11698,15 +11943,15 @@ namespace pugi return _result; } #endif - + PUGI__FN xpath_node::xpath_node() { } - + PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) { } - + PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) { } @@ -11715,12 +11960,12 @@ namespace pugi { return _attribute ? xml_node() : _node; } - + PUGI__FN xml_attribute xpath_node::attribute() const { return _attribute; } - + PUGI__FN xml_node xpath_node::parent() const { return _attribute ? _node : _node.parent(); @@ -11734,7 +11979,7 @@ namespace pugi { return (_node || _attribute) ? unspecified_bool_xpath_node : 0; } - + PUGI__FN bool xpath_node::operator!() const { return !(_node || _attribute); @@ -11744,7 +11989,7 @@ namespace pugi { return _node == n._node && _attribute == n._attribute; } - + PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const { return _node != n._node || _attribute != n._attribute; @@ -11795,7 +12040,7 @@ namespace pugi } memcpy(storage, begin_, size_ * sizeof(xpath_node)); - + // deallocate old buffer if (_begin != &_storage) impl::xml_memory::deallocate(_begin); @@ -11806,8 +12051,8 @@ namespace pugi } } -#if __cplusplus >= 201103 - PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) +#ifdef PUGIXML_HAS_MOVE + PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT { _type = rhs._type; _storage = rhs._storage; @@ -11834,12 +12079,12 @@ namespace pugi if (_begin != &_storage) impl::xml_memory::deallocate(_begin); } - + PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage) { _assign(ns._begin, ns._end, ns._type); } - + PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) { if (this == &ns) return *this; @@ -11849,13 +12094,13 @@ namespace pugi return *this; } -#if __cplusplus >= 201103 - PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage) +#ifdef PUGIXML_HAS_MOVE + PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(&_storage), _end(&_storage) { _move(rhs); } - PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) + PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; @@ -11872,17 +12117,17 @@ namespace pugi { return _type; } - + PUGI__FN size_t xpath_node_set::size() const { return _end - _begin; } - + PUGI__FN bool xpath_node_set::empty() const { return _begin == _end; } - + PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const { assert(index < size()); @@ -11893,12 +12138,12 @@ namespace pugi { return _begin; } - + PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const { return _end; } - + PUGI__FN void xpath_node_set::sort(bool reverse) { _type = impl::xpath_sort(_begin, _end, _type, reverse); @@ -11944,7 +12189,7 @@ namespace pugi return static_cast(this)->name; default: - assert(!"Invalid variable type"); + assert(false && "Invalid variable type"); // unreachable return 0; } } @@ -12049,8 +12294,8 @@ namespace pugi return *this; } -#if __cplusplus >= 201103 - PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) +#ifdef PUGIXML_HAS_MOVE + PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { @@ -12059,7 +12304,7 @@ namespace pugi } } - PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) + PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { @@ -12230,6 +12475,15 @@ namespace pugi _impl = impl.release(); _result.error = 0; } + else + { + #ifdef PUGIXML_NO_EXCEPTIONS + if (qimpl->oom) _result.error = "Out of memory"; + #else + if (qimpl->oom) throw std::bad_alloc(); + throw xpath_exception(_result); + #endif + } } } @@ -12243,14 +12497,16 @@ namespace pugi impl::xpath_query_impl::destroy(static_cast(_impl)); } -#if __cplusplus >= 201103 - PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) +#ifdef PUGIXML_HAS_MOVE + PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT { _impl = rhs._impl; + _result = rhs._result; rhs._impl = 0; + rhs._result = xpath_parse_result(); } - xpath_query& xpath_query::operator=(xpath_query&& rhs) + PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; @@ -12258,7 +12514,9 @@ namespace pugi impl::xpath_query_impl::destroy(static_cast(_impl)); _impl = rhs._impl; + _result = rhs._result; rhs._impl = 0; + rhs._result = xpath_parse_result(); return *this; } @@ -12274,37 +12532,63 @@ namespace pugi PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const { if (!_impl) return false; - + impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return false; - #endif - - return static_cast(_impl)->root->eval_boolean(c, sd.stack); + bool r = static_cast(_impl)->root->eval_boolean(c, sd.stack); + + if (sd.oom) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return false; + #else + throw std::bad_alloc(); + #endif + } + + return r; } - + PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const { if (!_impl) return impl::gen_nan(); - + impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return impl::gen_nan(); - #endif + double r = static_cast(_impl)->root->eval_number(c, sd.stack); - return static_cast(_impl)->root->eval_number(c, sd.stack); + if (sd.oom) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return impl::gen_nan(); + #else + throw std::bad_alloc(); + #endif + } + + return r; } #ifndef PUGIXML_NO_STL PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const { + if (!_impl) return string_t(); + + impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; - impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); + impl::xpath_string r = static_cast(_impl)->root->eval_string(c, sd.stack); + + if (sd.oom) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return string_t(); + #else + throw std::bad_alloc(); + #endif + } return string_t(r.c_str(), r.length()); } @@ -12312,12 +12596,22 @@ namespace pugi PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const { + impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; - impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); + impl::xpath_string r = _impl ? static_cast(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string(); + + if (sd.oom) + { + #ifdef PUGIXML_NO_EXCEPTIONS + r = impl::xpath_string(); + #else + throw std::bad_alloc(); + #endif + } size_t full_size = r.length() + 1; - + if (capacity > 0) { size_t size = (full_size < capacity) ? full_size : capacity; @@ -12326,7 +12620,7 @@ namespace pugi memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); buffer[size - 1] = 0; } - + return full_size; } @@ -12338,12 +12632,17 @@ namespace pugi impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_node_set(); - #endif - impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all); + if (sd.oom) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return xpath_node_set(); + #else + throw std::bad_alloc(); + #endif + } + return xpath_node_set(r.begin(), r.end(), r.type()); } @@ -12355,12 +12654,17 @@ namespace pugi impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; - #ifdef PUGIXML_NO_EXCEPTIONS - if (setjmp(sd.error_handler)) return xpath_node(); - #endif - impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first); + if (sd.oom) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return xpath_node(); + #else + throw std::bad_alloc(); + #endif + } + return r.first(); } @@ -12386,7 +12690,7 @@ namespace pugi PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); - return select_node(q); + return q.evaluate_node(*this); } PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const @@ -12397,7 +12701,7 @@ namespace pugi PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); - return select_nodes(q); + return q.evaluate_node_set(*this); } PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const @@ -12408,7 +12712,7 @@ namespace pugi PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); - return select_single_node(q); + return q.evaluate_node(*this); } PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const @@ -12429,16 +12733,23 @@ namespace pugi # pragma warning(pop) #endif +#if defined(_MSC_VER) && defined(__c2__) +# pragma clang diagnostic pop +#endif + // Undefine all local macros (makes sure we're not leaking macros in header-only mode) #undef PUGI__NO_INLINE #undef PUGI__UNLIKELY #undef PUGI__STATIC_ASSERT #undef PUGI__DMC_VOLATILE +#undef PUGI__UNSIGNED_OVERFLOW #undef PUGI__MSVC_CRT_VERSION +#undef PUGI__SNPRINTF #undef PUGI__NS_BEGIN #undef PUGI__NS_END #undef PUGI__FN #undef PUGI__FN_NO_INLINE +#undef PUGI__GETHEADER_IMPL #undef PUGI__GETPAGE_IMPL #undef PUGI__GETPAGE #undef PUGI__NODETYPE @@ -12460,7 +12771,7 @@ namespace pugi #endif /** - * Copyright (c) 2006-2015 Arseny Kapoulkine + * Copyright (c) 2006-2018 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -12473,7 +12784,7 @@ namespace pugi * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/lib/pugixml/pugixml.h b/lib/pugixml/pugixml.h index cdd24b6d..86403be3 100644 --- a/lib/pugixml/pugixml.h +++ b/lib/pugixml/pugixml.h @@ -1,7 +1,7 @@ /** - * pugixml parser - version 1.6 + * pugixml parser - version 1.9 * -------------------------------------------------------- - * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2006-2018, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -13,7 +13,7 @@ #ifndef PUGIXML_VERSION // Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons -# define PUGIXML_VERSION 160 +# define PUGIXML_VERSION 190 #endif // Include user configuration file (this can define various configuration macros) @@ -72,6 +72,44 @@ # endif #endif +// If the platform is known to have move semantics support, compile move ctor/operator implementation +#ifndef PUGIXML_HAS_MOVE +# if __cplusplus >= 201103 +# define PUGIXML_HAS_MOVE +# elif defined(_MSC_VER) && _MSC_VER >= 1600 +# define PUGIXML_HAS_MOVE +# endif +#endif + +// If C++ is 2011 or higher, add 'noexcept' specifiers +#ifndef PUGIXML_NOEXCEPT +# if __cplusplus >= 201103 +# define PUGIXML_NOEXCEPT noexcept +# elif defined(_MSC_VER) && _MSC_VER >= 1900 +# define PUGIXML_NOEXCEPT noexcept +# else +# define PUGIXML_NOEXCEPT +# endif +#endif + +// Some functions can not be noexcept in compact mode +#ifdef PUGIXML_COMPACT +# define PUGIXML_NOEXCEPT_IF_NOT_COMPACT +#else +# define PUGIXML_NOEXCEPT_IF_NOT_COMPACT PUGIXML_NOEXCEPT +#endif + +// If C++ is 2011 or higher, add 'override' qualifiers +#ifndef PUGIXML_OVERRIDE +# if __cplusplus >= 201103 +# define PUGIXML_OVERRIDE override +# elif defined(_MSC_VER) && _MSC_VER >= 1700 +# define PUGIXML_OVERRIDE override +# else +# define PUGIXML_OVERRIDE +# endif +#endif + // Character interface macros #ifdef PUGIXML_WCHAR_MODE # define PUGIXML_TEXT(t) L ## t @@ -133,13 +171,13 @@ namespace pugi // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. const unsigned int parse_eol = 0x0020; - + // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. const unsigned int parse_wconv_attribute = 0x0040; // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. const unsigned int parse_wnorm_attribute = 0x0080; - + // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. const unsigned int parse_declaration = 0x0100; @@ -158,6 +196,11 @@ namespace pugi // is a valid document. This flag is off by default. const unsigned int parse_fragment = 0x1000; + // This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of + // the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments. + // This flag is off by default. + const unsigned int parse_embed_pcdata = 0x2000; + // The default parsing mode. // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. @@ -184,16 +227,16 @@ namespace pugi }; // Formatting flags - + // Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default. const unsigned int format_indent = 0x01; - + // Write encoding-specific BOM to the output stream. This flag is off by default. const unsigned int format_write_bom = 0x02; // Use raw output mode (no indentation and no line breaks are written). This flag is off by default. const unsigned int format_raw = 0x04; - + // Omit default XML declaration even if there is no declaration in the document. This flag is off by default. const unsigned int format_no_declaration = 0x08; @@ -206,6 +249,9 @@ namespace pugi // Write every attribute on a new line with appropriate indentation. This flag is off by default. const unsigned int format_indent_attributes = 0x40; + // Don't output empty element tags, instead writing an explicit start and end tag even if there are no children. This flag is off by default. + const unsigned int format_no_empty_element_tags = 0x80; + // The default set of formatting flags. // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none. const unsigned int format_default = format_indent; @@ -225,7 +271,7 @@ namespace pugi class xml_node; class xml_text; - + #ifndef PUGIXML_NO_XPATH class xpath_node; class xpath_node_set; @@ -268,7 +314,7 @@ namespace pugi // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio xml_writer_file(void* file); - virtual void write(const void* data, size_t size); + virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: void* file; @@ -283,7 +329,7 @@ namespace pugi xml_writer_stream(std::basic_ostream >& stream); xml_writer_stream(std::basic_ostream >& stream); - virtual void write(const void* data, size_t size); + virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: std::basic_ostream >* narrow_stream; @@ -299,13 +345,13 @@ namespace pugi private: xml_attribute_struct* _attr; - + typedef void (*unspecified_bool_type)(xml_attribute***); public: // Default constructor. Constructs an empty attribute. xml_attribute(); - + // Constructs attribute from internal pointer explicit xml_attribute(xml_attribute_struct* attr); @@ -354,6 +400,8 @@ namespace pugi // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); bool set_value(unsigned int rhs); + bool set_value(long rhs); + bool set_value(unsigned long rhs); bool set_value(double rhs); bool set_value(float rhs); bool set_value(bool rhs); @@ -367,6 +415,8 @@ namespace pugi xml_attribute& operator=(const char_t* rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); + xml_attribute& operator=(long rhs); + xml_attribute& operator=(unsigned long rhs); xml_attribute& operator=(double rhs); xml_attribute& operator=(float rhs); xml_attribute& operator=(bool rhs); @@ -417,7 +467,7 @@ namespace pugi // Borland C++ workaround bool operator!() const; - + // Comparison operators (compares wrapped node pointers) bool operator==(const xml_node& r) const; bool operator!=(const xml_node& r) const; @@ -438,7 +488,7 @@ namespace pugi // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. const char_t* value() const; - + // Get attribute list xml_attribute first_attribute() const; xml_attribute last_attribute() const; @@ -450,7 +500,7 @@ namespace pugi // Get next/previous sibling in the children list of the parent node xml_node next_sibling() const; xml_node previous_sibling() const; - + // Get parent node xml_node parent() const; @@ -478,7 +528,7 @@ namespace pugi // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) bool set_name(const char_t* rhs); bool set_value(const char_t* rhs); - + // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(const char_t* name); xml_attribute prepend_attribute(const char_t* name); @@ -532,11 +582,11 @@ namespace pugi template xml_attribute find_attribute(Predicate pred) const { if (!_root) return xml_attribute(); - + for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) if (pred(attrib)) return attrib; - + return xml_attribute(); } @@ -544,11 +594,11 @@ namespace pugi template xml_node find_child(Predicate pred) const { if (!_root) return xml_node(); - + for (xml_node node = first_child(); node; node = node.next_sibling()) if (pred(node)) return node; - + return xml_node(); } @@ -558,7 +608,7 @@ namespace pugi if (!_root) return xml_node(); xml_node cur = first_child(); - + while (cur._root && cur._root != _root) { if (pred(cur)) return cur; @@ -590,7 +640,7 @@ namespace pugi // Recursively traverse subtree with xml_tree_walker bool traverse(xml_tree_walker& walker); - + #ifndef PUGIXML_NO_XPATH // Select single node by evaluating XPath query. Returns first node from the resulting node set. xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const; @@ -601,11 +651,11 @@ namespace pugi xpath_node_set select_nodes(const xpath_query& query) const; // (deprecated: use select_node instead) Select single node by evaluating XPath query. - xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; - xpath_node select_single_node(const xpath_query& query) const; + PUGIXML_DEPRECATED xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; + PUGIXML_DEPRECATED xpath_node select_single_node(const xpath_query& query) const; #endif - + // Print subtree using a writer object void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; @@ -701,6 +751,8 @@ namespace pugi // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); bool set(unsigned int rhs); + bool set(long rhs); + bool set(unsigned long rhs); bool set(double rhs); bool set(float rhs); bool set(bool rhs); @@ -714,6 +766,8 @@ namespace pugi xml_text& operator=(const char_t* rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); + xml_text& operator=(long rhs); + xml_text& operator=(unsigned long rhs); xml_text& operator=(double rhs); xml_text& operator=(float rhs); xml_text& operator=(bool rhs); @@ -867,11 +921,11 @@ namespace pugi private: int _depth; - + protected: // Get current traversal depth int depth() const; - + public: xml_tree_walker(); virtual ~xml_tree_walker(); @@ -942,13 +996,14 @@ namespace pugi char_t* _buffer; char _memory[192]; - + // Non-copyable semantics xml_document(const xml_document&); - const xml_document& operator=(const xml_document&); + xml_document& operator=(const xml_document&); - void create(); - void destroy(); + void _create(); + void _destroy(); + void _move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; public: // Default constructor, makes empty document @@ -957,6 +1012,12 @@ namespace pugi // Destructor, invalidates all node/attribute handles to this document ~xml_document(); + #ifdef PUGIXML_HAS_MOVE + // Move semantics support + xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; + xml_document& operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; + #endif + // Removes all nodes, leaving the empty document void reset(); @@ -970,7 +1031,7 @@ namespace pugi #endif // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. - xml_parse_result load(const char_t* contents, unsigned int options = parse_default); + PUGIXML_DEPRECATED xml_parse_result load(const char_t* contents, unsigned int options = parse_default); // Load document from zero-terminated string. No encoding conversions are applied. xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); @@ -1051,7 +1112,7 @@ namespace pugi // Non-copyable semantics xpath_variable(const xpath_variable&); xpath_variable& operator=(const xpath_variable&); - + public: // Get variable name const char_t* name() const; @@ -1095,10 +1156,10 @@ namespace pugi xpath_variable_set(const xpath_variable_set& rhs); xpath_variable_set& operator=(const xpath_variable_set& rhs); - #if __cplusplus >= 201103 + #ifdef PUGIXML_HAS_MOVE // Move semantics support - xpath_variable_set(xpath_variable_set&& rhs); - xpath_variable_set& operator=(xpath_variable_set&& rhs); + xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; + xpath_variable_set& operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; #endif // Add a new variable or get the existing one, if the types match @@ -1139,29 +1200,29 @@ namespace pugi // Destructor ~xpath_query(); - #if __cplusplus >= 201103 + #ifdef PUGIXML_HAS_MOVE // Move semantics support - xpath_query(xpath_query&& rhs); - xpath_query& operator=(xpath_query&& rhs); + xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT; + xpath_query& operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT; #endif // Get query expression return type xpath_value_type return_type() const; - + // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. bool evaluate_boolean(const xpath_node& n) const; - + // Evaluate expression as double value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. double evaluate_number(const xpath_node& n) const; - + #ifndef PUGIXML_NO_STL // Evaluate expression as string value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. string_t evaluate_string(const xpath_node& n) const; #endif - + // Evaluate expression as string value in the specified context; performs type conversion if necessary. // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. @@ -1188,7 +1249,7 @@ namespace pugi // Borland C++ workaround bool operator!() const; }; - + #ifndef PUGIXML_NO_EXCEPTIONS // XPath exception class class PUGIXML_CLASS xpath_exception: public std::exception @@ -1201,26 +1262,26 @@ namespace pugi explicit xpath_exception(const xpath_parse_result& result); // Get error message - virtual const char* what() const throw(); + virtual const char* what() const throw() PUGIXML_OVERRIDE; // Get parse result const xpath_parse_result& result() const; }; #endif - + // XPath node class (either xml_node or xml_attribute) class PUGIXML_CLASS xpath_node { private: xml_node _node; xml_attribute _attribute; - + typedef void (*unspecified_bool_type)(xpath_node***); public: // Default constructor; constructs empty XPath node xpath_node(); - + // Construct XPath node from XML node/attribute xpath_node(const xml_node& node); xpath_node(const xml_attribute& attribute, const xml_node& parent); @@ -1228,13 +1289,13 @@ namespace pugi // Get node/attribute, if any xml_node node() const; xml_attribute attribute() const; - + // Get parent of contained node/attribute xml_node parent() const; // Safe bool conversion operator operator unspecified_bool_type() const; - + // Borland C++ workaround bool operator!() const; @@ -1260,13 +1321,13 @@ namespace pugi type_sorted, // Sorted by document order (ascending) type_sorted_reverse // Sorted by document order (descending) }; - + // Constant iterator type typedef const xpath_node* const_iterator; // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work typedef const xpath_node* iterator; - + // Default constructor. Constructs empty set. xpath_node_set(); @@ -1275,49 +1336,49 @@ namespace pugi // Destructor ~xpath_node_set(); - + // Copy constructor/assignment operator xpath_node_set(const xpath_node_set& ns); xpath_node_set& operator=(const xpath_node_set& ns); - #if __cplusplus >= 201103 + #ifdef PUGIXML_HAS_MOVE // Move semantics support - xpath_node_set(xpath_node_set&& rhs); - xpath_node_set& operator=(xpath_node_set&& rhs); + xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; + xpath_node_set& operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; #endif // Get collection type type_t type() const; - + // Get collection size size_t size() const; // Indexing operator const xpath_node& operator[](size_t index) const; - + // Collection iterators const_iterator begin() const; const_iterator end() const; // Sort the collection in ascending/descending order by document order void sort(bool reverse = false); - + // Get first node in the collection by document order xpath_node first() const; - + // Check if collection is empty bool empty() const; - + private: type_t _type; - + xpath_node _storage; - + xpath_node* _begin; xpath_node* _end; void _assign(const_iterator begin, const_iterator end, type_t type); - void _move(xpath_node_set& rhs); + void _move(xpath_node_set& rhs) PUGIXML_NOEXCEPT; }; #endif @@ -1325,7 +1386,7 @@ namespace pugi // Convert wide string to UTF8 std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); - + // Convert UTF8 to wide string std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); @@ -1333,13 +1394,13 @@ namespace pugi // Memory allocation function interface; returns pointer to allocated memory or NULL on failure typedef void* (*allocation_function)(size_t size); - + // Memory deallocation function interface typedef void (*deallocation_function)(void* ptr); // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); - + // Get current memory management functions allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); @@ -1375,7 +1436,7 @@ namespace std #endif /** - * Copyright (c) 2006-2015 Arseny Kapoulkine + * Copyright (c) 2006-2018 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -1388,7 +1449,7 @@ namespace std * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/lib/pugixml/readme.txt b/lib/pugixml/readme.txt index faa41d37..5beb08a9 100644 --- a/lib/pugixml/readme.txt +++ b/lib/pugixml/readme.txt @@ -1,6 +1,6 @@ -pugixml 1.6 - an XML processing library +pugixml 1.9 - an XML processing library -Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +Copyright (C) 2006-2018, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) Report bugs and download new versions at http://pugixml.org/ This is the distribution of pugixml, which is a C++ XML processing library, @@ -28,7 +28,7 @@ The distribution contains the following folders: This library is distributed under the MIT License: -Copyright (c) 2006-2015 Arseny Kapoulkine +Copyright (c) 2006-2018 Arseny Kapoulkine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/lib/qcd/action/fermion/CayleyFermion5D.cc b/lib/qcd/action/fermion/CayleyFermion5D.cc index e053b98c..e3b77390 100644 --- a/lib/qcd/action/fermion/CayleyFermion5D.cc +++ b/lib/qcd/action/fermion/CayleyFermion5D.cc @@ -52,6 +52,35 @@ namespace QCD { { } +/////////////////////////////////////////////////////////////// +// Physical surface field utilities +/////////////////////////////////////////////////////////////// +template +void CayleyFermion5D::ExportPhysicalFermionSolution(const FermionField &solution5d,FermionField &exported4d) +{ + int Ls = this->Ls; + FermionField tmp(this->FermionGrid()); + tmp = solution5d; + conformable(solution5d._grid,this->FermionGrid()); + conformable(exported4d._grid,this->GaugeGrid()); + axpby_ssp_pminus(tmp, 0., solution5d, 1., solution5d, 0, 0); + axpby_ssp_pplus (tmp, 1., tmp , 1., solution5d, 0, Ls-1); + ExtractSlice(exported4d, tmp, 0, 0); +} +template +void CayleyFermion5D::ImportPhysicalFermionSource(const FermionField &input4d,FermionField &imported5d) +{ + int Ls = this->Ls; + FermionField tmp(this->FermionGrid()); + conformable(imported5d._grid,this->FermionGrid()); + conformable(input4d._grid ,this->GaugeGrid()); + tmp = zero; + InsertSlice(input4d, tmp, 0 , 0); + InsertSlice(input4d, tmp, Ls-1, 0); + axpby_ssp_pplus (tmp, 0., tmp, 1., tmp, 0, 0); + axpby_ssp_pminus(tmp, 0., tmp, 1., tmp, Ls-1, Ls-1); + Dminus(tmp,imported5d); +} template void CayleyFermion5D::Dminus(const FermionField &psi, FermionField &chi) { diff --git a/lib/qcd/action/fermion/CayleyFermion5D.h b/lib/qcd/action/fermion/CayleyFermion5D.h index ef75235a..b370b09d 100644 --- a/lib/qcd/action/fermion/CayleyFermion5D.h +++ b/lib/qcd/action/fermion/CayleyFermion5D.h @@ -83,8 +83,13 @@ namespace Grid { virtual void M5D (const FermionField &psi, FermionField &chi); virtual void M5Ddag(const FermionField &psi, FermionField &chi); + /////////////////////////////////////////////////////////////// + // Physical surface field utilities + /////////////////////////////////////////////////////////////// virtual void Dminus(const FermionField &psi, FermionField &chi); virtual void DminusDag(const FermionField &psi, FermionField &chi); + virtual void ExportPhysicalFermionSolution(const FermionField &solution5d,FermionField &exported4d); + virtual void ImportPhysicalFermionSource(const FermionField &input4d,FermionField &imported5d); ///////////////////////////////////////////////////// // Instantiate different versions depending on Impl diff --git a/lib/qcd/action/fermion/ContinuedFractionFermion5D.cc b/lib/qcd/action/fermion/ContinuedFractionFermion5D.cc index 5d39ef9b..f6857115 100644 --- a/lib/qcd/action/fermion/ContinuedFractionFermion5D.cc +++ b/lib/qcd/action/fermion/ContinuedFractionFermion5D.cc @@ -295,6 +295,27 @@ namespace Grid { assert((Ls&0x1)==1); // Odd Ls required } + template + void ContinuedFractionFermion5D::ExportPhysicalFermionSolution(const FermionField &solution5d,FermionField &exported4d) + { + int Ls = this->Ls; + conformable(solution5d._grid,this->FermionGrid()); + conformable(exported4d._grid,this->GaugeGrid()); + ExtractSlice(exported4d, solution5d, Ls-1, Ls-1); + } + template + void ContinuedFractionFermion5D::ImportPhysicalFermionSource(const FermionField &input4d,FermionField &imported5d) + { + int Ls = this->Ls; + conformable(imported5d._grid,this->FermionGrid()); + conformable(input4d._grid ,this->GaugeGrid()); + FermionField tmp(this->FermionGrid()); + tmp=zero; + InsertSlice(input4d, tmp, Ls-1, Ls-1); + tmp=Gamma(Gamma::Algebra::Gamma5)*tmp; + this->Dminus(tmp,imported5d); + } + FermOpTemplateInstantiate(ContinuedFractionFermion5D); } diff --git a/lib/qcd/action/fermion/ContinuedFractionFermion5D.h b/lib/qcd/action/fermion/ContinuedFractionFermion5D.h index e1e50aa5..b551fc28 100644 --- a/lib/qcd/action/fermion/ContinuedFractionFermion5D.h +++ b/lib/qcd/action/fermion/ContinuedFractionFermion5D.h @@ -65,6 +65,14 @@ namespace Grid { // Efficient support for multigrid coarsening virtual void Mdir (const FermionField &in, FermionField &out,int dir,int disp); + /////////////////////////////////////////////////////////////// + // Physical surface field utilities + /////////////////////////////////////////////////////////////// + // virtual void Dminus(const FermionField &psi, FermionField &chi); // Inherit trivial case + // virtual void DminusDag(const FermionField &psi, FermionField &chi); // Inherit trivial case + virtual void ExportPhysicalFermionSolution(const FermionField &solution5d,FermionField &exported4d); + virtual void ImportPhysicalFermionSource (const FermionField &input4d,FermionField &imported5d); + // Constructors ContinuedFractionFermion5D(GaugeField &_Umu, GridCartesian &FiveDimGrid, diff --git a/lib/qcd/action/fermion/FermionOperator.h b/lib/qcd/action/fermion/FermionOperator.h index 9eb74baa..f81c9e2c 100644 --- a/lib/qcd/action/fermion/FermionOperator.h +++ b/lib/qcd/action/fermion/FermionOperator.h @@ -127,7 +127,20 @@ namespace Grid { unsigned int mu, unsigned int tmin, unsigned int tmax, - ComplexField &lattice_cmplx)=0; + ComplexField &lattice_cmplx)=0; + /////////////////////////////////////////////// + // Physical field import/export + /////////////////////////////////////////////// + virtual void Dminus(const FermionField &psi, FermionField &chi) { chi=psi; } + virtual void DminusDag(const FermionField &psi, FermionField &chi) { chi=psi; } + virtual void ImportPhysicalFermionSource(const FermionField &input,FermionField &imported) + { + imported = input; + }; + virtual void ExportPhysicalFermionSolution(const FermionField &solution,FermionField &exported) + { + exported=solution; + }; }; } diff --git a/lib/qcd/action/fermion/PartialFractionFermion5D.cc b/lib/qcd/action/fermion/PartialFractionFermion5D.cc index 3a78e043..11840027 100644 --- a/lib/qcd/action/fermion/PartialFractionFermion5D.cc +++ b/lib/qcd/action/fermion/PartialFractionFermion5D.cc @@ -396,6 +396,27 @@ namespace Grid { amax=zolo_hi; } + template + void PartialFractionFermion5D::ExportPhysicalFermionSolution(const FermionField &solution5d,FermionField &exported4d) + { + int Ls = this->Ls; + conformable(solution5d._grid,this->FermionGrid()); + conformable(exported4d._grid,this->GaugeGrid()); + ExtractSlice(exported4d, solution5d, Ls-1, Ls-1); + } + template + void PartialFractionFermion5D::ImportPhysicalFermionSource(const FermionField &input4d,FermionField &imported5d) + { + int Ls = this->Ls; + conformable(imported5d._grid,this->FermionGrid()); + conformable(input4d._grid ,this->GaugeGrid()); + FermionField tmp(this->FermionGrid()); + tmp=zero; + InsertSlice(input4d, tmp, Ls-1, Ls-1); + tmp=Gamma(Gamma::Algebra::Gamma5)*tmp; + this->Dminus(tmp,imported5d); + } + // Constructors template PartialFractionFermion5D::PartialFractionFermion5D(GaugeField &_Umu, diff --git a/lib/qcd/action/fermion/PartialFractionFermion5D.h b/lib/qcd/action/fermion/PartialFractionFermion5D.h index 0ec72de4..91f1bd3c 100644 --- a/lib/qcd/action/fermion/PartialFractionFermion5D.h +++ b/lib/qcd/action/fermion/PartialFractionFermion5D.h @@ -70,6 +70,12 @@ namespace Grid { // Efficient support for multigrid coarsening virtual void Mdir (const FermionField &in, FermionField &out,int dir,int disp); + /////////////////////////////////////////////////////////////// + // Physical surface field utilities + /////////////////////////////////////////////////////////////// + virtual void ExportPhysicalFermionSolution(const FermionField &solution5d,FermionField &exported4d); + virtual void ImportPhysicalFermionSource (const FermionField &input4d,FermionField &imported5d); + // Constructors PartialFractionFermion5D(GaugeField &_Umu, GridCartesian &FiveDimGrid, diff --git a/lib/qcd/action/fermion/WilsonCompressor.h b/lib/qcd/action/fermion/WilsonCompressor.h index b47700ac..6ec2ede9 100644 --- a/lib/qcd/action/fermion/WilsonCompressor.h +++ b/lib/qcd/action/fermion/WilsonCompressor.h @@ -69,39 +69,47 @@ class WilsonCompressorTemplate< _HCspinor, _Hspinor, _Spinor, projector, /*****************************************************/ /* Compress includes precision change if mpi data is not same */ /*****************************************************/ - inline void Compress(SiteHalfSpinor *buf,Integer o,const SiteSpinor &in) { - projector::Proj(buf[o],in,mu,dag); + inline void Compress(SiteHalfSpinor * __restrict__ buf,Integer o,const SiteSpinor &in) { + SiteHalfSpinor tmp; + projector::Proj(tmp,in,mu,dag); + vstream(buf[o],tmp); } /*****************************************************/ /* Exchange includes precision change if mpi data is not same */ /*****************************************************/ - inline void Exchange(SiteHalfSpinor *mp, - SiteHalfSpinor *vp0, - SiteHalfSpinor *vp1, + inline void Exchange(SiteHalfSpinor * __restrict__ mp, + const SiteHalfSpinor * __restrict__ vp0, + const SiteHalfSpinor * __restrict__ vp1, Integer type,Integer o){ - exchange(mp[2*o],mp[2*o+1],vp0[o],vp1[o],type); + SiteHalfSpinor tmp1; + SiteHalfSpinor tmp2; + exchange(tmp1,tmp2,vp0[o],vp1[o],type); + vstream(mp[2*o ],tmp1); + vstream(mp[2*o+1],tmp2); } /*****************************************************/ /* Have a decompression step if mpi data is not same */ /*****************************************************/ - inline void Decompress(SiteHalfSpinor *out, - SiteHalfSpinor *in, Integer o) { + inline void Decompress(SiteHalfSpinor * __restrict__ out, + SiteHalfSpinor * __restrict__ in, Integer o) { assert(0); } /*****************************************************/ /* Compress Exchange */ /*****************************************************/ - inline void CompressExchange(SiteHalfSpinor *out0, - SiteHalfSpinor *out1, - const SiteSpinor *in, + inline void CompressExchange(SiteHalfSpinor * __restrict__ out0, + SiteHalfSpinor * __restrict__ out1, + const SiteSpinor * __restrict__ in, Integer j,Integer k, Integer m,Integer type){ SiteHalfSpinor temp1, temp2,temp3,temp4; projector::Proj(temp1,in[k],mu,dag); projector::Proj(temp2,in[m],mu,dag); - exchange(out0[j],out1[j],temp1,temp2,type); + exchange(temp3,temp4,temp1,temp2,type); + vstream(out0[j],temp3); + vstream(out1[j],temp4); } /*****************************************************/ diff --git a/lib/qcd/action/fermion/WilsonKernelsHand.cc b/lib/qcd/action/fermion/WilsonKernelsHand.cc index aa6b5f6b..50816495 100644 --- a/lib/qcd/action/fermion/WilsonKernelsHand.cc +++ b/lib/qcd/action/fermion/WilsonKernelsHand.cc @@ -30,181 +30,60 @@ Author: paboyle #define REGISTER -#define LOAD_CHIMU_BODY(F) \ - Chimu_00=ref(F)(0)(0); \ - Chimu_01=ref(F)(0)(1); \ - Chimu_02=ref(F)(0)(2); \ - Chimu_10=ref(F)(1)(0); \ - Chimu_11=ref(F)(1)(1); \ - Chimu_12=ref(F)(1)(2); \ - Chimu_20=ref(F)(2)(0); \ - Chimu_21=ref(F)(2)(1); \ - Chimu_22=ref(F)(2)(2); \ - Chimu_30=ref(F)(3)(0); \ - Chimu_31=ref(F)(3)(1); \ - Chimu_32=ref(F)(3)(2) +#define LOAD_CHIMU \ + {const SiteSpinor & ref (in._odata[offset]); \ + Chimu_00=ref()(0)(0);\ + Chimu_01=ref()(0)(1);\ + Chimu_02=ref()(0)(2);\ + Chimu_10=ref()(1)(0);\ + Chimu_11=ref()(1)(1);\ + Chimu_12=ref()(1)(2);\ + Chimu_20=ref()(2)(0);\ + Chimu_21=ref()(2)(1);\ + Chimu_22=ref()(2)(2);\ + Chimu_30=ref()(3)(0);\ + Chimu_31=ref()(3)(1);\ + Chimu_32=ref()(3)(2);} -#define LOAD_CHIMU(DIR,F,PERM) \ - { const SiteSpinor & ref (in._odata[offset]); LOAD_CHIMU_BODY(F); } - -#define LOAD_CHI_BODY(F) \ - Chi_00 = ref(F)(0)(0);\ - Chi_01 = ref(F)(0)(1);\ - Chi_02 = ref(F)(0)(2);\ - Chi_10 = ref(F)(1)(0);\ - Chi_11 = ref(F)(1)(1);\ - Chi_12 = ref(F)(1)(2) - -#define LOAD_CHI(DIR,F,PERM) \ - {const SiteHalfSpinor &ref(buf[offset]); LOAD_CHI_BODY(F); } - - -//G-parity implementations using in-place intrinsic ops - -//1l 1h -> 1h 1l -//0l 0h , 1h 1l -> 0l 1h 0h,1l -//0h,1l -> 1l,0h -//if( (distance == 1 && !perm_will_occur) || (distance == -1 && perm_will_occur) ) -//Pulled fermion through forwards face, GPBC on upper component -//Need 0= 0l 1h 1= 1l 0h -//else if( (distance == -1 && !perm) || (distance == 1 && perm) ) -//Pulled fermion through backwards face, GPBC on lower component -//Need 0= 1l 0h 1= 0l 1h - -//1l 1h -> 1h 1l -//0l 0h , 1h 1l -> 0l 1h 0h,1l -#define DO_TWIST_0L_1H(INTO,S,C,F, PERM, tmp1, tmp2, tmp3) \ - permute##PERM(tmp1, ref(1)(S)(C)); \ - exchange##PERM(tmp2,tmp3, ref(0)(S)(C), tmp1); \ - INTO = tmp2; - -//0l 0h -> 0h 0l -//1l 1h, 0h 0l -> 1l 0h, 1h 0l -#define DO_TWIST_1L_0H(INTO,S,C,F, PERM, tmp1, tmp2, tmp3) \ - permute##PERM(tmp1, ref(0)(S)(C)); \ - exchange##PERM(tmp2,tmp3, ref(1)(S)(C), tmp1); \ - INTO = tmp2; - - - - -#define LOAD_CHI_SETUP(DIR,F) \ - g = F; \ - direction = st._directions[DIR]; \ - distance = st._distances[DIR]; \ - sl = st._grid->_simd_layout[direction]; \ - inplace_twist = 0; \ - if(SE->_around_the_world && this->Params.twists[DIR % 4]){ \ - if(sl == 1){ \ - g = (F+1) % 2; \ - }else{ \ - inplace_twist = 1; \ - } \ - } - -#define LOAD_CHIMU_GPARITY_INPLACE_TWIST(DIR,F,PERM) \ - { const SiteSpinor &ref(in._odata[offset]); \ - LOAD_CHI_SETUP(DIR,F); \ - if(!inplace_twist){ \ - LOAD_CHIMU_BODY(g); \ - }else{ \ - if( ( F==0 && ((distance == 1 && !perm) || (distance == -1 && perm)) ) || \ - ( F==1 && ((distance == -1 && !perm) || (distance == 1 && perm)) ) ){ \ - DO_TWIST_0L_1H(Chimu_00,0,0,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chimu_01,0,1,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_0L_1H(Chimu_02,0,2,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chimu_10,1,0,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_0L_1H(Chimu_11,1,1,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chimu_12,1,2,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_0L_1H(Chimu_20,2,0,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chimu_21,2,1,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_0L_1H(Chimu_22,2,2,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chimu_30,3,0,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_0L_1H(Chimu_31,3,1,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chimu_32,3,2,F,PERM, U_11,U_20,U_21); \ - }else{ \ - DO_TWIST_1L_0H(Chimu_00,0,0,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chimu_01,0,1,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_1L_0H(Chimu_02,0,2,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chimu_10,1,0,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_1L_0H(Chimu_11,1,1,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chimu_12,1,2,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_1L_0H(Chimu_20,2,0,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chimu_21,2,1,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_1L_0H(Chimu_22,2,2,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chimu_30,3,0,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_1L_0H(Chimu_31,3,1,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chimu_32,3,2,F,PERM, U_11,U_20,U_21); \ - } \ - } \ - } - - -#define LOAD_CHI_GPARITY_INPLACE_TWIST(DIR,F,PERM) \ - { const SiteHalfSpinor &ref(buf[offset]); \ - LOAD_CHI_SETUP(DIR,F); \ - if(!inplace_twist){ \ - LOAD_CHI_BODY(g); \ - }else{ \ - if( ( F==0 && ((distance == 1 && !perm) || (distance == -1 && perm)) ) || \ - ( F==1 && ((distance == -1 && !perm) || (distance == 1 && perm)) ) ){ \ - DO_TWIST_0L_1H(Chi_00,0,0,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chi_01,0,1,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_0L_1H(Chi_02,0,2,F,PERM, UChi_00,UChi_01,UChi_02); \ - DO_TWIST_0L_1H(Chi_10,1,0,F,PERM, UChi_10,UChi_11,UChi_12); \ - DO_TWIST_0L_1H(Chi_11,1,1,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_0L_1H(Chi_12,1,2,F,PERM, U_11,U_20,U_21); \ - }else{ \ - DO_TWIST_1L_0H(Chi_00,0,0,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chi_01,0,1,F,PERM, U_11,U_20,U_21); \ - DO_TWIST_1L_0H(Chi_02,0,2,F,PERM, UChi_00,UChi_01,UChi_02); \ - DO_TWIST_1L_0H(Chi_10,1,0,F,PERM, UChi_10,UChi_11,UChi_12); \ - DO_TWIST_1L_0H(Chi_11,1,1,F,PERM, U_00,U_01,U_10); \ - DO_TWIST_1L_0H(Chi_12,1,2,F,PERM, U_11,U_20,U_21); \ - } \ - } \ - } - - -#define LOAD_CHI_GPARITY(DIR,F,PERM) LOAD_CHI_GPARITY_INPLACE_TWIST(DIR,F,PERM) -#define LOAD_CHIMU_GPARITY(DIR,F,PERM) LOAD_CHIMU_GPARITY_INPLACE_TWIST(DIR,F,PERM) +#define LOAD_CHI\ + {const SiteHalfSpinor &ref(buf[offset]); \ + Chi_00 = ref()(0)(0);\ + Chi_01 = ref()(0)(1);\ + Chi_02 = ref()(0)(2);\ + Chi_10 = ref()(1)(0);\ + Chi_11 = ref()(1)(1);\ + Chi_12 = ref()(1)(2);} // To splat or not to splat depends on the implementation -#define MULT_2SPIN_BODY \ - Impl::loadLinkElement(U_00,ref()(0,0)); \ - Impl::loadLinkElement(U_10,ref()(1,0)); \ - Impl::loadLinkElement(U_20,ref()(2,0)); \ - Impl::loadLinkElement(U_01,ref()(0,1)); \ - Impl::loadLinkElement(U_11,ref()(1,1)); \ - Impl::loadLinkElement(U_21,ref()(2,1)); \ - UChi_00 = U_00*Chi_00; \ - UChi_10 = U_00*Chi_10; \ - UChi_01 = U_10*Chi_00; \ - UChi_11 = U_10*Chi_10; \ - UChi_02 = U_20*Chi_00; \ - UChi_12 = U_20*Chi_10; \ - UChi_00+= U_01*Chi_01; \ - UChi_10+= U_01*Chi_11; \ - UChi_01+= U_11*Chi_01; \ - UChi_11+= U_11*Chi_11; \ - UChi_02+= U_21*Chi_01; \ - UChi_12+= U_21*Chi_11; \ - Impl::loadLinkElement(U_00,ref()(0,2)); \ - Impl::loadLinkElement(U_10,ref()(1,2)); \ - Impl::loadLinkElement(U_20,ref()(2,2)); \ - UChi_00+= U_00*Chi_02; \ - UChi_10+= U_00*Chi_12; \ - UChi_01+= U_10*Chi_02; \ - UChi_11+= U_10*Chi_12; \ - UChi_02+= U_20*Chi_02; \ - UChi_12+= U_20*Chi_12 - - -#define MULT_2SPIN(A,F) \ - {auto & ref(U._odata[sU](A)); MULT_2SPIN_BODY; } - -#define MULT_2SPIN_GPARITY(A,F) \ - {auto & ref(U._odata[sU](F)(A)); MULT_2SPIN_BODY; } +#define MULT_2SPIN(A)\ + {auto & ref(U._odata[sU](A)); \ + Impl::loadLinkElement(U_00,ref()(0,0)); \ + Impl::loadLinkElement(U_10,ref()(1,0)); \ + Impl::loadLinkElement(U_20,ref()(2,0)); \ + Impl::loadLinkElement(U_01,ref()(0,1)); \ + Impl::loadLinkElement(U_11,ref()(1,1)); \ + Impl::loadLinkElement(U_21,ref()(2,1)); \ + UChi_00 = U_00*Chi_00;\ + UChi_10 = U_00*Chi_10;\ + UChi_01 = U_10*Chi_00;\ + UChi_11 = U_10*Chi_10;\ + UChi_02 = U_20*Chi_00;\ + UChi_12 = U_20*Chi_10;\ + UChi_00+= U_01*Chi_01;\ + UChi_10+= U_01*Chi_11;\ + UChi_01+= U_11*Chi_01;\ + UChi_11+= U_11*Chi_11;\ + UChi_02+= U_21*Chi_01;\ + UChi_12+= U_21*Chi_11;\ + Impl::loadLinkElement(U_00,ref()(0,2)); \ + Impl::loadLinkElement(U_10,ref()(1,2)); \ + Impl::loadLinkElement(U_20,ref()(2,2)); \ + UChi_00+= U_00*Chi_02;\ + UChi_10+= U_00*Chi_12;\ + UChi_01+= U_10*Chi_02;\ + UChi_11+= U_10*Chi_12;\ + UChi_02+= U_20*Chi_02;\ + UChi_12+= U_20*Chi_12;} #define PERMUTE_DIR(dir) \ @@ -428,87 +307,84 @@ Author: paboyle result_31-= UChi_11; \ result_32-= UChi_12; -#define HAND_STENCIL_LEG(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ +#define HAND_STENCIL_LEG(PROJ,PERM,DIR,RECON) \ SE=st.GetEntry(ptype,DIR,ss); \ offset = SE->_offset; \ local = SE->_is_local; \ perm = SE->_permute; \ if ( local ) { \ - LOAD_CHIMU_IMPL(DIR,F,PERM); \ + LOAD_CHIMU; \ PROJ; \ if ( perm) { \ PERMUTE_DIR(PERM); \ } \ } else { \ - LOAD_CHI_IMPL(DIR,F,PERM); \ + LOAD_CHI; \ } \ - MULT_2SPIN_IMPL(DIR,F); \ + MULT_2SPIN(DIR); \ RECON; - -#define HAND_STENCIL_LEG_INT(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ +#define HAND_STENCIL_LEG_INT(PROJ,PERM,DIR,RECON) \ SE=st.GetEntry(ptype,DIR,ss); \ offset = SE->_offset; \ local = SE->_is_local; \ perm = SE->_permute; \ if ( local ) { \ - LOAD_CHIMU_IMPL(DIR,F,PERM); \ + LOAD_CHIMU; \ PROJ; \ if ( perm) { \ PERMUTE_DIR(PERM); \ } \ } else if ( st.same_node[DIR] ) { \ - LOAD_CHI_IMPL(DIR,F,PERM); \ + LOAD_CHI; \ } \ if (local || st.same_node[DIR] ) { \ - MULT_2SPIN_IMPL(DIR,F); \ + MULT_2SPIN(DIR); \ RECON; \ } -#define HAND_STENCIL_LEG_EXT(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ +#define HAND_STENCIL_LEG_EXT(PROJ,PERM,DIR,RECON) \ SE=st.GetEntry(ptype,DIR,ss); \ offset = SE->_offset; \ - local = SE->_is_local; \ - perm = SE->_permute; \ if((!SE->_is_local)&&(!st.same_node[DIR]) ) { \ - LOAD_CHI_IMPL(DIR,F,PERM); \ - MULT_2SPIN_IMPL(DIR,F); \ + LOAD_CHI; \ + MULT_2SPIN(DIR); \ RECON; \ nmu++; \ } -#define HAND_RESULT(ss,F) \ +#define HAND_RESULT(ss) \ { \ SiteSpinor & ref (out._odata[ss]); \ - vstream(ref(F)(0)(0),result_00); \ - vstream(ref(F)(0)(1),result_01); \ - vstream(ref(F)(0)(2),result_02); \ - vstream(ref(F)(1)(0),result_10); \ - vstream(ref(F)(1)(1),result_11); \ - vstream(ref(F)(1)(2),result_12); \ - vstream(ref(F)(2)(0),result_20); \ - vstream(ref(F)(2)(1),result_21); \ - vstream(ref(F)(2)(2),result_22); \ - vstream(ref(F)(3)(0),result_30); \ - vstream(ref(F)(3)(1),result_31); \ - vstream(ref(F)(3)(2),result_32); \ + vstream(ref()(0)(0),result_00); \ + vstream(ref()(0)(1),result_01); \ + vstream(ref()(0)(2),result_02); \ + vstream(ref()(1)(0),result_10); \ + vstream(ref()(1)(1),result_11); \ + vstream(ref()(1)(2),result_12); \ + vstream(ref()(2)(0),result_20); \ + vstream(ref()(2)(1),result_21); \ + vstream(ref()(2)(2),result_22); \ + vstream(ref()(3)(0),result_30); \ + vstream(ref()(3)(1),result_31); \ + vstream(ref()(3)(2),result_32); \ } -#define HAND_RESULT_EXT(ss,F) \ +#define HAND_RESULT_EXT(ss) \ if (nmu){ \ SiteSpinor & ref (out._odata[ss]); \ - ref(F)(0)(0)+=result_00; \ - ref(F)(0)(1)+=result_01; \ - ref(F)(0)(2)+=result_02; \ - ref(F)(1)(0)+=result_10; \ - ref(F)(1)(1)+=result_11; \ - ref(F)(1)(2)+=result_12; \ - ref(F)(2)(0)+=result_20; \ - ref(F)(2)(1)+=result_21; \ - ref(F)(2)(2)+=result_22; \ - ref(F)(3)(0)+=result_30; \ - ref(F)(3)(1)+=result_31; \ - ref(F)(3)(2)+=result_32; \ + ref()(0)(0)+=result_00; \ + ref()(0)(1)+=result_01; \ + ref()(0)(2)+=result_02; \ + ref()(1)(0)+=result_10; \ + ref()(1)(1)+=result_11; \ + ref()(1)(2)+=result_12; \ + ref()(2)(0)+=result_20; \ + ref()(2)(1)+=result_21; \ + ref()(2)(2)+=result_22; \ + ref()(3)(0)+=result_30; \ + ref()(3)(1)+=result_31; \ + ref()(3)(2)+=result_32; \ } @@ -587,18 +463,15 @@ WilsonKernels::HandDhopSite(StencilImpl &st,LebesgueOrder &lo,DoubledGauge int offset,local,perm, ptype; StencilEntry *SE; -#define HAND_DOP_SITE(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ - HAND_STENCIL_LEG(XM_PROJ,3,Xp,XM_RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_RESULT(ss,F) - - HAND_DOP_SITE(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); + HAND_STENCIL_LEG(XM_PROJ,3,Xp,XM_RECON); + HAND_STENCIL_LEG(YM_PROJ,2,Yp,YM_RECON_ACCUM); + HAND_STENCIL_LEG(ZM_PROJ,1,Zp,ZM_RECON_ACCUM); + HAND_STENCIL_LEG(TM_PROJ,0,Tp,TM_RECON_ACCUM); + HAND_STENCIL_LEG(XP_PROJ,3,Xm,XP_RECON_ACCUM); + HAND_STENCIL_LEG(YP_PROJ,2,Ym,YP_RECON_ACCUM); + HAND_STENCIL_LEG(ZP_PROJ,1,Zm,ZP_RECON_ACCUM); + HAND_STENCIL_LEG(TP_PROJ,0,Tm,TP_RECON_ACCUM); + HAND_RESULT(ss); } template @@ -612,19 +485,16 @@ void WilsonKernels::HandDhopSiteDag(StencilImpl &st,LebesgueOrder &lo,Doub StencilEntry *SE; int offset,local,perm, ptype; - -#define HAND_DOP_SITE_DAG(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ - HAND_STENCIL_LEG(XP_PROJ,3,Xp,XP_RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_RESULT(ss,F) - - HAND_DOP_SITE_DAG(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); + + HAND_STENCIL_LEG(XP_PROJ,3,Xp,XP_RECON); + HAND_STENCIL_LEG(YP_PROJ,2,Yp,YP_RECON_ACCUM); + HAND_STENCIL_LEG(ZP_PROJ,1,Zp,ZP_RECON_ACCUM); + HAND_STENCIL_LEG(TP_PROJ,0,Tp,TP_RECON_ACCUM); + HAND_STENCIL_LEG(XM_PROJ,3,Xm,XM_RECON_ACCUM); + HAND_STENCIL_LEG(YM_PROJ,2,Ym,YM_RECON_ACCUM); + HAND_STENCIL_LEG(ZM_PROJ,1,Zm,ZM_RECON_ACCUM); + HAND_STENCIL_LEG(TM_PROJ,0,Tm,TM_RECON_ACCUM); + HAND_RESULT(ss); } template void @@ -639,20 +509,16 @@ WilsonKernels::HandDhopSiteInt(StencilImpl &st,LebesgueOrder &lo,DoubledGa int offset,local,perm, ptype; StencilEntry *SE; - -#define HAND_DOP_SITE_INT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ - ZERO_RESULT; \ - HAND_STENCIL_LEG_INT(XM_PROJ,3,Xp,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_RESULT(ss,F) - - HAND_DOP_SITE_INT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); + ZERO_RESULT; + HAND_STENCIL_LEG_INT(XM_PROJ,3,Xp,XM_RECON_ACCUM); + HAND_STENCIL_LEG_INT(YM_PROJ,2,Yp,YM_RECON_ACCUM); + HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM); + HAND_STENCIL_LEG_INT(TM_PROJ,0,Tp,TM_RECON_ACCUM); + HAND_STENCIL_LEG_INT(XP_PROJ,3,Xm,XP_RECON_ACCUM); + HAND_STENCIL_LEG_INT(YP_PROJ,2,Ym,YP_RECON_ACCUM); + HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM); + HAND_STENCIL_LEG_INT(TP_PROJ,0,Tm,TP_RECON_ACCUM); + HAND_RESULT(ss); } template @@ -666,20 +532,16 @@ void WilsonKernels::HandDhopSiteDagInt(StencilImpl &st,LebesgueOrder &lo,D StencilEntry *SE; int offset,local,perm, ptype; - -#define HAND_DOP_SITE_DAG_INT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ - ZERO_RESULT; \ - HAND_STENCIL_LEG_INT(XP_PROJ,3,Xp,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_INT(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_RESULT(ss,F) - - HAND_DOP_SITE_DAG_INT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); + ZERO_RESULT; + HAND_STENCIL_LEG_INT(XP_PROJ,3,Xp,XP_RECON_ACCUM); + HAND_STENCIL_LEG_INT(YP_PROJ,2,Yp,YP_RECON_ACCUM); + HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM); + HAND_STENCIL_LEG_INT(TP_PROJ,0,Tp,TP_RECON_ACCUM); + HAND_STENCIL_LEG_INT(XM_PROJ,3,Xm,XM_RECON_ACCUM); + HAND_STENCIL_LEG_INT(YM_PROJ,2,Ym,YM_RECON_ACCUM); + HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM); + HAND_STENCIL_LEG_INT(TM_PROJ,0,Tm,TM_RECON_ACCUM); + HAND_RESULT(ss); } template void @@ -695,20 +557,16 @@ WilsonKernels::HandDhopSiteExt(StencilImpl &st,LebesgueOrder &lo,DoubledGa int offset,local,perm, ptype; StencilEntry *SE; int nmu=0; - -#define HAND_DOP_SITE_EXT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ - ZERO_RESULT; \ - HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xp,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_RESULT_EXT(ss,F) - - HAND_DOP_SITE_EXT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); + ZERO_RESULT; + HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xp,XM_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(YM_PROJ,2,Yp,YM_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tp,TM_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xm,XP_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(YP_PROJ,2,Ym,YP_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tm,TP_RECON_ACCUM); + HAND_RESULT_EXT(ss); } template @@ -723,193 +581,18 @@ void WilsonKernels::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,D StencilEntry *SE; int offset,local,perm, ptype; int nmu=0; - -#define HAND_DOP_SITE_DAG_EXT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ - ZERO_RESULT; \ - HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xp,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ - HAND_RESULT_EXT(ss,F) - - HAND_DOP_SITE_DAG_EXT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); + ZERO_RESULT; + HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xp,XP_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(YP_PROJ,2,Yp,YP_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tp,TP_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xm,XM_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(YM_PROJ,2,Ym,YM_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM); + HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tm,TM_RECON_ACCUM); + HAND_RESULT_EXT(ss); } - //////////////////////////////////////////////// - // Specialise Gparity to simple implementation - //////////////////////////////////////////////// -#define HAND_SPECIALISE_EMPTY(IMPL) \ - template<> void \ - WilsonKernels::HandDhopSite(StencilImpl &st, \ - LebesgueOrder &lo, \ - DoubledGaugeField &U, \ - SiteHalfSpinor *buf, \ - int sF,int sU, \ - const FermionField &in, \ - FermionField &out){ assert(0); } \ - template<> void \ - WilsonKernels::HandDhopSiteDag(StencilImpl &st, \ - LebesgueOrder &lo, \ - DoubledGaugeField &U, \ - SiteHalfSpinor *buf, \ - int sF,int sU, \ - const FermionField &in, \ - FermionField &out){ assert(0); } \ - template<> void \ - WilsonKernels::HandDhopSiteInt(StencilImpl &st, \ - LebesgueOrder &lo, \ - DoubledGaugeField &U, \ - SiteHalfSpinor *buf, \ - int sF,int sU, \ - const FermionField &in, \ - FermionField &out){ assert(0); } \ - template<> void \ - WilsonKernels::HandDhopSiteExt(StencilImpl &st, \ - LebesgueOrder &lo, \ - DoubledGaugeField &U, \ - SiteHalfSpinor *buf, \ - int sF,int sU, \ - const FermionField &in, \ - FermionField &out){ assert(0); } \ - template<> void \ - WilsonKernels::HandDhopSiteDagInt(StencilImpl &st, \ - LebesgueOrder &lo, \ - DoubledGaugeField &U, \ - SiteHalfSpinor *buf, \ - int sF,int sU, \ - const FermionField &in, \ - FermionField &out){ assert(0); } \ - template<> void \ - WilsonKernels::HandDhopSiteDagExt(StencilImpl &st, \ - LebesgueOrder &lo, \ - DoubledGaugeField &U, \ - SiteHalfSpinor *buf, \ - int sF,int sU, \ - const FermionField &in, \ - FermionField &out){ assert(0); } \ - - - -#define HAND_SPECIALISE_GPARITY(IMPL) \ - template<> void \ - WilsonKernels::HandDhopSite(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ - int ss,int sU,const FermionField &in, FermionField &out) \ - { \ - typedef IMPL Impl; \ - typedef typename Simd::scalar_type S; \ - typedef typename Simd::vector_type V; \ - \ - HAND_DECLARATIONS(ignore); \ - \ - int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ - StencilEntry *SE; \ - HAND_DOP_SITE(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - HAND_DOP_SITE(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - } \ - \ - template<> \ - void WilsonKernels::HandDhopSiteDag(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ - int ss,int sU,const FermionField &in, FermionField &out) \ - { \ - typedef IMPL Impl; \ - typedef typename Simd::scalar_type S; \ - typedef typename Simd::vector_type V; \ - \ - HAND_DECLARATIONS(ignore); \ - \ - StencilEntry *SE; \ - int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ - HAND_DOP_SITE_DAG(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - HAND_DOP_SITE_DAG(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - } \ - \ - template<> void \ - WilsonKernels::HandDhopSiteInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ - int ss,int sU,const FermionField &in, FermionField &out) \ - { \ - typedef IMPL Impl; \ - typedef typename Simd::scalar_type S; \ - typedef typename Simd::vector_type V; \ - \ - HAND_DECLARATIONS(ignore); \ - \ - int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ - StencilEntry *SE; \ - HAND_DOP_SITE_INT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - HAND_DOP_SITE_INT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - } \ - \ - template<> \ - void WilsonKernels::HandDhopSiteDagInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ - int ss,int sU,const FermionField &in, FermionField &out) \ - { \ - typedef IMPL Impl; \ - typedef typename Simd::scalar_type S; \ - typedef typename Simd::vector_type V; \ - \ - HAND_DECLARATIONS(ignore); \ - \ - StencilEntry *SE; \ - int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ - HAND_DOP_SITE_DAG_INT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - HAND_DOP_SITE_DAG_INT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - } \ - \ - template<> void \ - WilsonKernels::HandDhopSiteExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ - int ss,int sU,const FermionField &in, FermionField &out) \ - { \ - typedef IMPL Impl; \ - typedef typename Simd::scalar_type S; \ - typedef typename Simd::vector_type V; \ - \ - HAND_DECLARATIONS(ignore); \ - \ - int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ - StencilEntry *SE; \ - int nmu=0; \ - HAND_DOP_SITE_EXT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - nmu = 0; \ - HAND_DOP_SITE_EXT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - } \ - template<> \ - void WilsonKernels::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ - int ss,int sU,const FermionField &in, FermionField &out) \ - { \ - typedef IMPL Impl; \ - typedef typename Simd::scalar_type S; \ - typedef typename Simd::vector_type V; \ - \ - HAND_DECLARATIONS(ignore); \ - \ - StencilEntry *SE; \ - int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ - int nmu=0; \ - HAND_DOP_SITE_DAG_EXT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - nmu = 0; \ - HAND_DOP_SITE_DAG_EXT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ - } - - -HAND_SPECIALISE_GPARITY(GparityWilsonImplF); -HAND_SPECIALISE_GPARITY(GparityWilsonImplD); -HAND_SPECIALISE_GPARITY(GparityWilsonImplFH); -HAND_SPECIALISE_GPARITY(GparityWilsonImplDF); - - - - - - - - - - - ////////////// Wilson ; uses this implementation ///////////////////// #define INSTANTIATE_THEM(A) \ @@ -930,8 +613,6 @@ INSTANTIATE_THEM(WilsonImplF); INSTANTIATE_THEM(WilsonImplD); INSTANTIATE_THEM(ZWilsonImplF); INSTANTIATE_THEM(ZWilsonImplD); -INSTANTIATE_THEM(GparityWilsonImplF); -INSTANTIATE_THEM(GparityWilsonImplD); INSTANTIATE_THEM(DomainWallVec5dImplF); INSTANTIATE_THEM(DomainWallVec5dImplD); INSTANTIATE_THEM(ZDomainWallVec5dImplF); @@ -940,12 +621,11 @@ INSTANTIATE_THEM(WilsonImplFH); INSTANTIATE_THEM(WilsonImplDF); INSTANTIATE_THEM(ZWilsonImplFH); INSTANTIATE_THEM(ZWilsonImplDF); -INSTANTIATE_THEM(GparityWilsonImplFH); -INSTANTIATE_THEM(GparityWilsonImplDF); INSTANTIATE_THEM(DomainWallVec5dImplFH); INSTANTIATE_THEM(DomainWallVec5dImplDF); INSTANTIATE_THEM(ZDomainWallVec5dImplFH); INSTANTIATE_THEM(ZDomainWallVec5dImplDF); INSTANTIATE_THEM(WilsonTwoIndexAntiSymmetricImplF); INSTANTIATE_THEM(WilsonTwoIndexAntiSymmetricImplD); + }} diff --git a/lib/qcd/action/fermion/WilsonKernelsHandGparity.cc b/lib/qcd/action/fermion/WilsonKernelsHandGparity.cc new file mode 100644 index 00000000..3bf2f10a --- /dev/null +++ b/lib/qcd/action/fermion/WilsonKernelsHandGparity.cc @@ -0,0 +1,878 @@ + /************************************************************************************* + + Grid physics library, www.github.com/paboyle/Grid + + Source file: ./lib/qcd/action/fermion/WilsonKernelsHand.cc + + Copyright (C) 2015 + +Author: Peter Boyle +Author: paboyle + + 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 + +#define REGISTER + +#define LOAD_CHIMU_BODY(F) \ + Chimu_00=ref(F)(0)(0); \ + Chimu_01=ref(F)(0)(1); \ + Chimu_02=ref(F)(0)(2); \ + Chimu_10=ref(F)(1)(0); \ + Chimu_11=ref(F)(1)(1); \ + Chimu_12=ref(F)(1)(2); \ + Chimu_20=ref(F)(2)(0); \ + Chimu_21=ref(F)(2)(1); \ + Chimu_22=ref(F)(2)(2); \ + Chimu_30=ref(F)(3)(0); \ + Chimu_31=ref(F)(3)(1); \ + Chimu_32=ref(F)(3)(2) + +#define LOAD_CHIMU(DIR,F,PERM) \ + { const SiteSpinor & ref (in._odata[offset]); LOAD_CHIMU_BODY(F); } + +#define LOAD_CHI_BODY(F) \ + Chi_00 = ref(F)(0)(0);\ + Chi_01 = ref(F)(0)(1);\ + Chi_02 = ref(F)(0)(2);\ + Chi_10 = ref(F)(1)(0);\ + Chi_11 = ref(F)(1)(1);\ + Chi_12 = ref(F)(1)(2) + +#define LOAD_CHI(DIR,F,PERM) \ + {const SiteHalfSpinor &ref(buf[offset]); LOAD_CHI_BODY(F); } + + +//G-parity implementations using in-place intrinsic ops + +//1l 1h -> 1h 1l +//0l 0h , 1h 1l -> 0l 1h 0h,1l +//0h,1l -> 1l,0h +//if( (distance == 1 && !perm_will_occur) || (distance == -1 && perm_will_occur) ) +//Pulled fermion through forwards face, GPBC on upper component +//Need 0= 0l 1h 1= 1l 0h +//else if( (distance == -1 && !perm) || (distance == 1 && perm) ) +//Pulled fermion through backwards face, GPBC on lower component +//Need 0= 1l 0h 1= 0l 1h + +//1l 1h -> 1h 1l +//0l 0h , 1h 1l -> 0l 1h 0h,1l +#define DO_TWIST_0L_1H(INTO,S,C,F, PERM, tmp1, tmp2, tmp3) \ + permute##PERM(tmp1, ref(1)(S)(C)); \ + exchange##PERM(tmp2,tmp3, ref(0)(S)(C), tmp1); \ + INTO = tmp2; + +//0l 0h -> 0h 0l +//1l 1h, 0h 0l -> 1l 0h, 1h 0l +#define DO_TWIST_1L_0H(INTO,S,C,F, PERM, tmp1, tmp2, tmp3) \ + permute##PERM(tmp1, ref(0)(S)(C)); \ + exchange##PERM(tmp2,tmp3, ref(1)(S)(C), tmp1); \ + INTO = tmp2; + + + + +#define LOAD_CHI_SETUP(DIR,F) \ + g = F; \ + direction = st._directions[DIR]; \ + distance = st._distances[DIR]; \ + sl = st._grid->_simd_layout[direction]; \ + inplace_twist = 0; \ + if(SE->_around_the_world && this->Params.twists[DIR % 4]){ \ + if(sl == 1){ \ + g = (F+1) % 2; \ + }else{ \ + inplace_twist = 1; \ + } \ + } + +#define LOAD_CHIMU_GPARITY_INPLACE_TWIST(DIR,F,PERM) \ + { const SiteSpinor &ref(in._odata[offset]); \ + LOAD_CHI_SETUP(DIR,F); \ + if(!inplace_twist){ \ + LOAD_CHIMU_BODY(g); \ + }else{ \ + if( ( F==0 && ((distance == 1 && !perm) || (distance == -1 && perm)) ) || \ + ( F==1 && ((distance == -1 && !perm) || (distance == 1 && perm)) ) ){ \ + DO_TWIST_0L_1H(Chimu_00,0,0,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chimu_01,0,1,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_0L_1H(Chimu_02,0,2,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chimu_10,1,0,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_0L_1H(Chimu_11,1,1,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chimu_12,1,2,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_0L_1H(Chimu_20,2,0,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chimu_21,2,1,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_0L_1H(Chimu_22,2,2,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chimu_30,3,0,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_0L_1H(Chimu_31,3,1,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chimu_32,3,2,F,PERM, U_11,U_20,U_21); \ + }else{ \ + DO_TWIST_1L_0H(Chimu_00,0,0,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chimu_01,0,1,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_1L_0H(Chimu_02,0,2,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chimu_10,1,0,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_1L_0H(Chimu_11,1,1,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chimu_12,1,2,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_1L_0H(Chimu_20,2,0,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chimu_21,2,1,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_1L_0H(Chimu_22,2,2,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chimu_30,3,0,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_1L_0H(Chimu_31,3,1,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chimu_32,3,2,F,PERM, U_11,U_20,U_21); \ + } \ + } \ + } + + +#define LOAD_CHI_GPARITY_INPLACE_TWIST(DIR,F,PERM) \ + { const SiteHalfSpinor &ref(buf[offset]); \ + LOAD_CHI_SETUP(DIR,F); \ + if(!inplace_twist){ \ + LOAD_CHI_BODY(g); \ + }else{ \ + if( ( F==0 && ((distance == 1 && !perm) || (distance == -1 && perm)) ) || \ + ( F==1 && ((distance == -1 && !perm) || (distance == 1 && perm)) ) ){ \ + DO_TWIST_0L_1H(Chi_00,0,0,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chi_01,0,1,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_0L_1H(Chi_02,0,2,F,PERM, UChi_00,UChi_01,UChi_02); \ + DO_TWIST_0L_1H(Chi_10,1,0,F,PERM, UChi_10,UChi_11,UChi_12); \ + DO_TWIST_0L_1H(Chi_11,1,1,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_0L_1H(Chi_12,1,2,F,PERM, U_11,U_20,U_21); \ + }else{ \ + DO_TWIST_1L_0H(Chi_00,0,0,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chi_01,0,1,F,PERM, U_11,U_20,U_21); \ + DO_TWIST_1L_0H(Chi_02,0,2,F,PERM, UChi_00,UChi_01,UChi_02); \ + DO_TWIST_1L_0H(Chi_10,1,0,F,PERM, UChi_10,UChi_11,UChi_12); \ + DO_TWIST_1L_0H(Chi_11,1,1,F,PERM, U_00,U_01,U_10); \ + DO_TWIST_1L_0H(Chi_12,1,2,F,PERM, U_11,U_20,U_21); \ + } \ + } \ + } + + +#define LOAD_CHI_GPARITY(DIR,F,PERM) LOAD_CHI_GPARITY_INPLACE_TWIST(DIR,F,PERM) +#define LOAD_CHIMU_GPARITY(DIR,F,PERM) LOAD_CHIMU_GPARITY_INPLACE_TWIST(DIR,F,PERM) + +// To splat or not to splat depends on the implementation +#define MULT_2SPIN_BODY \ + Impl::loadLinkElement(U_00,ref()(0,0)); \ + Impl::loadLinkElement(U_10,ref()(1,0)); \ + Impl::loadLinkElement(U_20,ref()(2,0)); \ + Impl::loadLinkElement(U_01,ref()(0,1)); \ + Impl::loadLinkElement(U_11,ref()(1,1)); \ + Impl::loadLinkElement(U_21,ref()(2,1)); \ + UChi_00 = U_00*Chi_00; \ + UChi_10 = U_00*Chi_10; \ + UChi_01 = U_10*Chi_00; \ + UChi_11 = U_10*Chi_10; \ + UChi_02 = U_20*Chi_00; \ + UChi_12 = U_20*Chi_10; \ + UChi_00+= U_01*Chi_01; \ + UChi_10+= U_01*Chi_11; \ + UChi_01+= U_11*Chi_01; \ + UChi_11+= U_11*Chi_11; \ + UChi_02+= U_21*Chi_01; \ + UChi_12+= U_21*Chi_11; \ + Impl::loadLinkElement(U_00,ref()(0,2)); \ + Impl::loadLinkElement(U_10,ref()(1,2)); \ + Impl::loadLinkElement(U_20,ref()(2,2)); \ + UChi_00+= U_00*Chi_02; \ + UChi_10+= U_00*Chi_12; \ + UChi_01+= U_10*Chi_02; \ + UChi_11+= U_10*Chi_12; \ + UChi_02+= U_20*Chi_02; \ + UChi_12+= U_20*Chi_12 + + +#define MULT_2SPIN(A,F) \ + {auto & ref(U._odata[sU](A)); MULT_2SPIN_BODY; } + +#define MULT_2SPIN_GPARITY(A,F) \ + {auto & ref(U._odata[sU](F)(A)); MULT_2SPIN_BODY; } + + +#define PERMUTE_DIR(dir) \ + permute##dir(Chi_00,Chi_00);\ + permute##dir(Chi_01,Chi_01);\ + permute##dir(Chi_02,Chi_02);\ + permute##dir(Chi_10,Chi_10);\ + permute##dir(Chi_11,Chi_11);\ + permute##dir(Chi_12,Chi_12); + +// hspin(0)=fspin(0)+timesI(fspin(3)); +// hspin(1)=fspin(1)+timesI(fspin(2)); +#define XP_PROJ \ + Chi_00 = Chimu_00+timesI(Chimu_30);\ + Chi_01 = Chimu_01+timesI(Chimu_31);\ + Chi_02 = Chimu_02+timesI(Chimu_32);\ + Chi_10 = Chimu_10+timesI(Chimu_20);\ + Chi_11 = Chimu_11+timesI(Chimu_21);\ + Chi_12 = Chimu_12+timesI(Chimu_22); + +#define YP_PROJ \ + Chi_00 = Chimu_00-Chimu_30;\ + Chi_01 = Chimu_01-Chimu_31;\ + Chi_02 = Chimu_02-Chimu_32;\ + Chi_10 = Chimu_10+Chimu_20;\ + Chi_11 = Chimu_11+Chimu_21;\ + Chi_12 = Chimu_12+Chimu_22; + +#define ZP_PROJ \ + Chi_00 = Chimu_00+timesI(Chimu_20); \ + Chi_01 = Chimu_01+timesI(Chimu_21); \ + Chi_02 = Chimu_02+timesI(Chimu_22); \ + Chi_10 = Chimu_10-timesI(Chimu_30); \ + Chi_11 = Chimu_11-timesI(Chimu_31); \ + Chi_12 = Chimu_12-timesI(Chimu_32); + +#define TP_PROJ \ + Chi_00 = Chimu_00+Chimu_20; \ + Chi_01 = Chimu_01+Chimu_21; \ + Chi_02 = Chimu_02+Chimu_22; \ + Chi_10 = Chimu_10+Chimu_30; \ + Chi_11 = Chimu_11+Chimu_31; \ + Chi_12 = Chimu_12+Chimu_32; + + +// hspin(0)=fspin(0)-timesI(fspin(3)); +// hspin(1)=fspin(1)-timesI(fspin(2)); +#define XM_PROJ \ + Chi_00 = Chimu_00-timesI(Chimu_30);\ + Chi_01 = Chimu_01-timesI(Chimu_31);\ + Chi_02 = Chimu_02-timesI(Chimu_32);\ + Chi_10 = Chimu_10-timesI(Chimu_20);\ + Chi_11 = Chimu_11-timesI(Chimu_21);\ + Chi_12 = Chimu_12-timesI(Chimu_22); + +#define YM_PROJ \ + Chi_00 = Chimu_00+Chimu_30;\ + Chi_01 = Chimu_01+Chimu_31;\ + Chi_02 = Chimu_02+Chimu_32;\ + Chi_10 = Chimu_10-Chimu_20;\ + Chi_11 = Chimu_11-Chimu_21;\ + Chi_12 = Chimu_12-Chimu_22; + +#define ZM_PROJ \ + Chi_00 = Chimu_00-timesI(Chimu_20); \ + Chi_01 = Chimu_01-timesI(Chimu_21); \ + Chi_02 = Chimu_02-timesI(Chimu_22); \ + Chi_10 = Chimu_10+timesI(Chimu_30); \ + Chi_11 = Chimu_11+timesI(Chimu_31); \ + Chi_12 = Chimu_12+timesI(Chimu_32); + +#define TM_PROJ \ + Chi_00 = Chimu_00-Chimu_20; \ + Chi_01 = Chimu_01-Chimu_21; \ + Chi_02 = Chimu_02-Chimu_22; \ + Chi_10 = Chimu_10-Chimu_30; \ + Chi_11 = Chimu_11-Chimu_31; \ + Chi_12 = Chimu_12-Chimu_32; + +// fspin(0)=hspin(0); +// fspin(1)=hspin(1); +// fspin(2)=timesMinusI(hspin(1)); +// fspin(3)=timesMinusI(hspin(0)); +#define XP_RECON\ + result_00 = UChi_00;\ + result_01 = UChi_01;\ + result_02 = UChi_02;\ + result_10 = UChi_10;\ + result_11 = UChi_11;\ + result_12 = UChi_12;\ + result_20 = timesMinusI(UChi_10);\ + result_21 = timesMinusI(UChi_11);\ + result_22 = timesMinusI(UChi_12);\ + result_30 = timesMinusI(UChi_00);\ + result_31 = timesMinusI(UChi_01);\ + result_32 = timesMinusI(UChi_02); + +#define XP_RECON_ACCUM\ + result_00+=UChi_00;\ + result_01+=UChi_01;\ + result_02+=UChi_02;\ + result_10+=UChi_10;\ + result_11+=UChi_11;\ + result_12+=UChi_12;\ + result_20-=timesI(UChi_10);\ + result_21-=timesI(UChi_11);\ + result_22-=timesI(UChi_12);\ + result_30-=timesI(UChi_00);\ + result_31-=timesI(UChi_01);\ + result_32-=timesI(UChi_02); + +#define XM_RECON\ + result_00 = UChi_00;\ + result_01 = UChi_01;\ + result_02 = UChi_02;\ + result_10 = UChi_10;\ + result_11 = UChi_11;\ + result_12 = UChi_12;\ + result_20 = timesI(UChi_10);\ + result_21 = timesI(UChi_11);\ + result_22 = timesI(UChi_12);\ + result_30 = timesI(UChi_00);\ + result_31 = timesI(UChi_01);\ + result_32 = timesI(UChi_02); + +#define XM_RECON_ACCUM\ + result_00+= UChi_00;\ + result_01+= UChi_01;\ + result_02+= UChi_02;\ + result_10+= UChi_10;\ + result_11+= UChi_11;\ + result_12+= UChi_12;\ + result_20+= timesI(UChi_10);\ + result_21+= timesI(UChi_11);\ + result_22+= timesI(UChi_12);\ + result_30+= timesI(UChi_00);\ + result_31+= timesI(UChi_01);\ + result_32+= timesI(UChi_02); + +#define YP_RECON_ACCUM\ + result_00+= UChi_00;\ + result_01+= UChi_01;\ + result_02+= UChi_02;\ + result_10+= UChi_10;\ + result_11+= UChi_11;\ + result_12+= UChi_12;\ + result_20+= UChi_10;\ + result_21+= UChi_11;\ + result_22+= UChi_12;\ + result_30-= UChi_00;\ + result_31-= UChi_01;\ + result_32-= UChi_02; + +#define YM_RECON_ACCUM\ + result_00+= UChi_00;\ + result_01+= UChi_01;\ + result_02+= UChi_02;\ + result_10+= UChi_10;\ + result_11+= UChi_11;\ + result_12+= UChi_12;\ + result_20-= UChi_10;\ + result_21-= UChi_11;\ + result_22-= UChi_12;\ + result_30+= UChi_00;\ + result_31+= UChi_01;\ + result_32+= UChi_02; + +#define ZP_RECON_ACCUM\ + result_00+= UChi_00;\ + result_01+= UChi_01;\ + result_02+= UChi_02;\ + result_10+= UChi_10;\ + result_11+= UChi_11;\ + result_12+= UChi_12;\ + result_20-= timesI(UChi_00); \ + result_21-= timesI(UChi_01); \ + result_22-= timesI(UChi_02); \ + result_30+= timesI(UChi_10); \ + result_31+= timesI(UChi_11); \ + result_32+= timesI(UChi_12); + +#define ZM_RECON_ACCUM\ + result_00+= UChi_00;\ + result_01+= UChi_01;\ + result_02+= UChi_02;\ + result_10+= UChi_10;\ + result_11+= UChi_11;\ + result_12+= UChi_12;\ + result_20+= timesI(UChi_00); \ + result_21+= timesI(UChi_01); \ + result_22+= timesI(UChi_02); \ + result_30-= timesI(UChi_10); \ + result_31-= timesI(UChi_11); \ + result_32-= timesI(UChi_12); + +#define TP_RECON_ACCUM\ + result_00+= UChi_00;\ + result_01+= UChi_01;\ + result_02+= UChi_02;\ + result_10+= UChi_10;\ + result_11+= UChi_11;\ + result_12+= UChi_12;\ + result_20+= UChi_00; \ + result_21+= UChi_01; \ + result_22+= UChi_02; \ + result_30+= UChi_10; \ + result_31+= UChi_11; \ + result_32+= UChi_12; + +#define TM_RECON_ACCUM\ + result_00+= UChi_00;\ + result_01+= UChi_01;\ + result_02+= UChi_02;\ + result_10+= UChi_10;\ + result_11+= UChi_11;\ + result_12+= UChi_12;\ + result_20-= UChi_00; \ + result_21-= UChi_01; \ + result_22-= UChi_02; \ + result_30-= UChi_10; \ + result_31-= UChi_11; \ + result_32-= UChi_12; + +#define HAND_STENCIL_LEG(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + SE=st.GetEntry(ptype,DIR,ss); \ + offset = SE->_offset; \ + local = SE->_is_local; \ + perm = SE->_permute; \ + if ( local ) { \ + LOAD_CHIMU_IMPL(DIR,F,PERM); \ + PROJ; \ + if ( perm) { \ + PERMUTE_DIR(PERM); \ + } \ + } else { \ + LOAD_CHI_IMPL(DIR,F,PERM); \ + } \ + MULT_2SPIN_IMPL(DIR,F); \ + RECON; + + +#define HAND_STENCIL_LEG_INT(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + SE=st.GetEntry(ptype,DIR,ss); \ + offset = SE->_offset; \ + local = SE->_is_local; \ + perm = SE->_permute; \ + if ( local ) { \ + LOAD_CHIMU_IMPL(DIR,F,PERM); \ + PROJ; \ + if ( perm) { \ + PERMUTE_DIR(PERM); \ + } \ + } else if ( st.same_node[DIR] ) { \ + LOAD_CHI_IMPL(DIR,F,PERM); \ + } \ + if (local || st.same_node[DIR] ) { \ + MULT_2SPIN_IMPL(DIR,F); \ + RECON; \ + } + +#define HAND_STENCIL_LEG_EXT(PROJ,PERM,DIR,RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + SE=st.GetEntry(ptype,DIR,ss); \ + offset = SE->_offset; \ + local = SE->_is_local; \ + perm = SE->_permute; \ + if((!SE->_is_local)&&(!st.same_node[DIR]) ) { \ + LOAD_CHI_IMPL(DIR,F,PERM); \ + MULT_2SPIN_IMPL(DIR,F); \ + RECON; \ + nmu++; \ + } + +#define HAND_RESULT(ss,F) \ + { \ + SiteSpinor & ref (out._odata[ss]); \ + vstream(ref(F)(0)(0),result_00); \ + vstream(ref(F)(0)(1),result_01); \ + vstream(ref(F)(0)(2),result_02); \ + vstream(ref(F)(1)(0),result_10); \ + vstream(ref(F)(1)(1),result_11); \ + vstream(ref(F)(1)(2),result_12); \ + vstream(ref(F)(2)(0),result_20); \ + vstream(ref(F)(2)(1),result_21); \ + vstream(ref(F)(2)(2),result_22); \ + vstream(ref(F)(3)(0),result_30); \ + vstream(ref(F)(3)(1),result_31); \ + vstream(ref(F)(3)(2),result_32); \ + } + +#define HAND_RESULT_EXT(ss,F) \ + if (nmu){ \ + SiteSpinor & ref (out._odata[ss]); \ + ref(F)(0)(0)+=result_00; \ + ref(F)(0)(1)+=result_01; \ + ref(F)(0)(2)+=result_02; \ + ref(F)(1)(0)+=result_10; \ + ref(F)(1)(1)+=result_11; \ + ref(F)(1)(2)+=result_12; \ + ref(F)(2)(0)+=result_20; \ + ref(F)(2)(1)+=result_21; \ + ref(F)(2)(2)+=result_22; \ + ref(F)(3)(0)+=result_30; \ + ref(F)(3)(1)+=result_31; \ + ref(F)(3)(2)+=result_32; \ + } + + +#define HAND_DECLARATIONS(a) \ + Simd result_00; \ + Simd result_01; \ + Simd result_02; \ + Simd result_10; \ + Simd result_11; \ + Simd result_12; \ + Simd result_20; \ + Simd result_21; \ + Simd result_22; \ + Simd result_30; \ + Simd result_31; \ + Simd result_32; \ + Simd Chi_00; \ + Simd Chi_01; \ + Simd Chi_02; \ + Simd Chi_10; \ + Simd Chi_11; \ + Simd Chi_12; \ + Simd UChi_00; \ + Simd UChi_01; \ + Simd UChi_02; \ + Simd UChi_10; \ + Simd UChi_11; \ + Simd UChi_12; \ + Simd U_00; \ + Simd U_10; \ + Simd U_20; \ + Simd U_01; \ + Simd U_11; \ + Simd U_21; + +#define ZERO_RESULT \ + result_00=zero; \ + result_01=zero; \ + result_02=zero; \ + result_10=zero; \ + result_11=zero; \ + result_12=zero; \ + result_20=zero; \ + result_21=zero; \ + result_22=zero; \ + result_30=zero; \ + result_31=zero; \ + result_32=zero; + +#define Chimu_00 Chi_00 +#define Chimu_01 Chi_01 +#define Chimu_02 Chi_02 +#define Chimu_10 Chi_10 +#define Chimu_11 Chi_11 +#define Chimu_12 Chi_12 +#define Chimu_20 UChi_00 +#define Chimu_21 UChi_01 +#define Chimu_22 UChi_02 +#define Chimu_30 UChi_10 +#define Chimu_31 UChi_11 +#define Chimu_32 UChi_12 + +namespace Grid { +namespace QCD { + +template void +WilsonKernels::HandDhopSite(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, + int ss,int sU,const FermionField &in, FermionField &out) +{ +// T==0, Z==1, Y==2, Z==3 expect 1,2,2,2 simd layout etc... + typedef typename Simd::scalar_type S; + typedef typename Simd::vector_type V; + + HAND_DECLARATIONS(ignore); + + int offset,local,perm, ptype; + StencilEntry *SE; + +#define HAND_DOP_SITE(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + HAND_STENCIL_LEG(XM_PROJ,3,Xp,XM_RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_RESULT(ss,F) + + HAND_DOP_SITE(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); +} + +template +void WilsonKernels::HandDhopSiteDag(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, + int ss,int sU,const FermionField &in, FermionField &out) +{ + typedef typename Simd::scalar_type S; + typedef typename Simd::vector_type V; + + HAND_DECLARATIONS(ignore); + + StencilEntry *SE; + int offset,local,perm, ptype; + +#define HAND_DOP_SITE_DAG(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + HAND_STENCIL_LEG(XP_PROJ,3,Xp,XP_RECON,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_RESULT(ss,F) + + HAND_DOP_SITE_DAG(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); +} + +template void +WilsonKernels::HandDhopSiteInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, + int ss,int sU,const FermionField &in, FermionField &out) +{ +// T==0, Z==1, Y==2, Z==3 expect 1,2,2,2 simd layout etc... + typedef typename Simd::scalar_type S; + typedef typename Simd::vector_type V; + + HAND_DECLARATIONS(ignore); + + int offset,local,perm, ptype; + StencilEntry *SE; + +#define HAND_DOP_SITE_INT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + ZERO_RESULT; \ + HAND_STENCIL_LEG_INT(XM_PROJ,3,Xp,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_RESULT(ss,F) + + HAND_DOP_SITE_INT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); +} + +template +void WilsonKernels::HandDhopSiteDagInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, + int ss,int sU,const FermionField &in, FermionField &out) +{ + typedef typename Simd::scalar_type S; + typedef typename Simd::vector_type V; + + HAND_DECLARATIONS(ignore); + + StencilEntry *SE; + int offset,local,perm, ptype; + +#define HAND_DOP_SITE_DAG_INT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + ZERO_RESULT; \ + HAND_STENCIL_LEG_INT(XP_PROJ,3,Xp,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_INT(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_RESULT(ss,F) + + HAND_DOP_SITE_DAG_INT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); +} + +template void +WilsonKernels::HandDhopSiteExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, + int ss,int sU,const FermionField &in, FermionField &out) +{ +// T==0, Z==1, Y==2, Z==3 expect 1,2,2,2 simd layout etc... + typedef typename Simd::scalar_type S; + typedef typename Simd::vector_type V; + + HAND_DECLARATIONS(ignore); + + int offset,local,perm, ptype; + StencilEntry *SE; + int nmu=0; + +#define HAND_DOP_SITE_EXT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + ZERO_RESULT; \ + HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xp,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(YM_PROJ,2,Yp,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zp,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tp,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xm,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(YP_PROJ,2,Ym,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zm,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tm,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_RESULT_EXT(ss,F) + + HAND_DOP_SITE_EXT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); +} + +template +void WilsonKernels::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, + int ss,int sU,const FermionField &in, FermionField &out) +{ + typedef typename Simd::scalar_type S; + typedef typename Simd::vector_type V; + + HAND_DECLARATIONS(ignore); + + StencilEntry *SE; + int offset,local,perm, ptype; + int nmu=0; + +#define HAND_DOP_SITE_DAG_EXT(F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL) \ + ZERO_RESULT; \ + HAND_STENCIL_LEG_EXT(XP_PROJ,3,Xp,XP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(YP_PROJ,2,Yp,YP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(ZP_PROJ,1,Zp,ZP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(TP_PROJ,0,Tp,TP_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(XM_PROJ,3,Xm,XM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(YM_PROJ,2,Ym,YM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(ZM_PROJ,1,Zm,ZM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_STENCIL_LEG_EXT(TM_PROJ,0,Tm,TM_RECON_ACCUM,F,LOAD_CHI_IMPL,LOAD_CHIMU_IMPL,MULT_2SPIN_IMPL); \ + HAND_RESULT_EXT(ss,F) + + HAND_DOP_SITE_DAG_EXT(, LOAD_CHI,LOAD_CHIMU,MULT_2SPIN); +} + +#define HAND_SPECIALISE_GPARITY(IMPL) \ + template<> void \ + WilsonKernels::HandDhopSite(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out) \ + { \ + typedef IMPL Impl; \ + typedef typename Simd::scalar_type S; \ + typedef typename Simd::vector_type V; \ + \ + HAND_DECLARATIONS(ignore); \ + \ + int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ + StencilEntry *SE; \ + HAND_DOP_SITE(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + HAND_DOP_SITE(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + } \ + \ + template<> \ + void WilsonKernels::HandDhopSiteDag(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out) \ + { \ + typedef IMPL Impl; \ + typedef typename Simd::scalar_type S; \ + typedef typename Simd::vector_type V; \ + \ + HAND_DECLARATIONS(ignore); \ + \ + StencilEntry *SE; \ + int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ + HAND_DOP_SITE_DAG(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + HAND_DOP_SITE_DAG(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + } \ + \ + template<> void \ + WilsonKernels::HandDhopSiteInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out) \ + { \ + typedef IMPL Impl; \ + typedef typename Simd::scalar_type S; \ + typedef typename Simd::vector_type V; \ + \ + HAND_DECLARATIONS(ignore); \ + \ + int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ + StencilEntry *SE; \ + HAND_DOP_SITE_INT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + HAND_DOP_SITE_INT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + } \ + \ + template<> \ + void WilsonKernels::HandDhopSiteDagInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out) \ + { \ + typedef IMPL Impl; \ + typedef typename Simd::scalar_type S; \ + typedef typename Simd::vector_type V; \ + \ + HAND_DECLARATIONS(ignore); \ + \ + StencilEntry *SE; \ + int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ + HAND_DOP_SITE_DAG_INT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + HAND_DOP_SITE_DAG_INT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + } \ + \ + template<> void \ + WilsonKernels::HandDhopSiteExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out) \ + { \ + typedef IMPL Impl; \ + typedef typename Simd::scalar_type S; \ + typedef typename Simd::vector_type V; \ + \ + HAND_DECLARATIONS(ignore); \ + \ + int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ + StencilEntry *SE; \ + int nmu=0; \ + HAND_DOP_SITE_EXT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + nmu = 0; \ + HAND_DOP_SITE_EXT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + } \ + template<> \ + void WilsonKernels::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out) \ + { \ + typedef IMPL Impl; \ + typedef typename Simd::scalar_type S; \ + typedef typename Simd::vector_type V; \ + \ + HAND_DECLARATIONS(ignore); \ + \ + StencilEntry *SE; \ + int offset,local,perm, ptype, g, direction, distance, sl, inplace_twist; \ + int nmu=0; \ + HAND_DOP_SITE_DAG_EXT(0, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + nmu = 0; \ + HAND_DOP_SITE_DAG_EXT(1, LOAD_CHI_GPARITY,LOAD_CHIMU_GPARITY,MULT_2SPIN_GPARITY); \ + } + + +HAND_SPECIALISE_GPARITY(GparityWilsonImplF); +HAND_SPECIALISE_GPARITY(GparityWilsonImplD); +HAND_SPECIALISE_GPARITY(GparityWilsonImplFH); +HAND_SPECIALISE_GPARITY(GparityWilsonImplDF); + + + + + + + + + + + +////////////// Wilson ; uses this implementation ///////////////////// + +#define INSTANTIATE_THEM(A) \ +template void WilsonKernels::HandDhopSite(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf,\ + int ss,int sU,const FermionField &in, FermionField &out); \ +template void WilsonKernels::HandDhopSiteDag(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out);\ +template void WilsonKernels::HandDhopSiteInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf,\ + int ss,int sU,const FermionField &in, FermionField &out); \ +template void WilsonKernels::HandDhopSiteDagInt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out); \ +template void WilsonKernels::HandDhopSiteExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf,\ + int ss,int sU,const FermionField &in, FermionField &out); \ +template void WilsonKernels::HandDhopSiteDagExt(StencilImpl &st,LebesgueOrder &lo,DoubledGaugeField &U,SiteHalfSpinor *buf, \ + int ss,int sU,const FermionField &in, FermionField &out); + +INSTANTIATE_THEM(GparityWilsonImplF); +INSTANTIATE_THEM(GparityWilsonImplD); +INSTANTIATE_THEM(GparityWilsonImplFH); +INSTANTIATE_THEM(GparityWilsonImplDF); +}} diff --git a/lib/qcd/action/gauge/Photon.h b/lib/qcd/action/gauge/Photon.h index f36df5ea..6ff697c5 100644 --- a/lib/qcd/action/gauge/Photon.h +++ b/lib/qcd/action/gauge/Photon.h @@ -266,7 +266,7 @@ namespace QCD{ vol = vol * latt_size[d]; } invKHatSquared(weight); - weight = sqrt(vol*real(weight)); + weight = sqrt(vol)*sqrt(weight); zmSub(weight); break; } diff --git a/lib/qcd/hmc/HMCResourceManager.h b/lib/qcd/hmc/HMCResourceManager.h index 3e20a8c1..fcfaeaed 100644 --- a/lib/qcd/hmc/HMCResourceManager.h +++ b/lib/qcd/hmc/HMCResourceManager.h @@ -48,6 +48,22 @@ with this program; if not, write to the Free Software Foundation, Inc., } \ } +#define RegisterLoadCheckPointerMetadataFunction(NAME) \ + template < class Metadata > \ + void Load##NAME##Checkpointer(const CheckpointerParameters& Params_, const Metadata& M_) { \ + if (!have_CheckPointer) { \ + std::cout << GridLogDebug << "Loading Metadata Checkpointer " << #NAME \ + << std::endl; \ + CP = std::unique_ptr( \ + new NAME##CPModule(Params_, M_)); \ + have_CheckPointer = true; \ + } else { \ + std::cout << GridLogError << "Checkpointer already loaded " \ + << std::endl; \ + exit(1); \ + } \ + } + namespace Grid { namespace QCD { @@ -77,7 +93,7 @@ class HMCResourceManager { bool have_CheckPointer; // NOTE: operator << is not overloaded for std::vector - // so thsi function is necessary + // so this function is necessary void output_vector_string(const std::vector &vs){ for (auto &i: vs) std::cout << i << " "; @@ -254,6 +270,7 @@ class HMCResourceManager { RegisterLoadCheckPointerFunction(Nersc); #ifdef HAVE_LIME RegisterLoadCheckPointerFunction(ILDG); + RegisterLoadCheckPointerMetadataFunction(Scidac); #endif //////////////////////////////////////////////////////// diff --git a/lib/qcd/hmc/checkpointers/BaseCheckpointer.h b/lib/qcd/hmc/checkpointers/BaseCheckpointer.h index 9be9efca..f4ef252b 100644 --- a/lib/qcd/hmc/checkpointers/BaseCheckpointer.h +++ b/lib/qcd/hmc/checkpointers/BaseCheckpointer.h @@ -76,6 +76,14 @@ class BaseHmcCheckpointer : public HmcObservable { } } + void check_filename(const std::string &filename){ + std::ifstream f(filename.c_str()); + if(!f.good()){ + std::cout << GridLogError << "Filename " << filename << " not found. Aborting. " << std::endl; + abort(); + }; + } + virtual void initialize(const CheckpointerParameters &Params) = 0; virtual void CheckpointRestore(int traj, typename Impl::Field &U, diff --git a/lib/qcd/hmc/checkpointers/BinaryCheckpointer.h b/lib/qcd/hmc/checkpointers/BinaryCheckpointer.h index 59d655ad..025398eb 100644 --- a/lib/qcd/hmc/checkpointers/BinaryCheckpointer.h +++ b/lib/qcd/hmc/checkpointers/BinaryCheckpointer.h @@ -93,6 +93,9 @@ class BinaryHmcCheckpointer : public BaseHmcCheckpointer { void CheckpointRestore(int traj, Field &U, GridSerialRNG &sRNG, GridParallelRNG &pRNG) { std::string config, rng; this->build_filenames(traj, Params, config, rng); + this->check_filename(rng); + this->check_filename(config); + BinarySimpleMunger munge; diff --git a/lib/qcd/hmc/checkpointers/CheckPointerModules.h b/lib/qcd/hmc/checkpointers/CheckPointerModules.h index 5debedef..f17cd2c8 100644 --- a/lib/qcd/hmc/checkpointers/CheckPointerModules.h +++ b/lib/qcd/hmc/checkpointers/CheckPointerModules.h @@ -136,6 +136,20 @@ class ILDGCPModule: public CheckPointerModule< ImplementationPolicy> { }; +template +class ScidacCPModule: public CheckPointerModule< ImplementationPolicy> { + typedef CheckPointerModule< ImplementationPolicy> CPBase; + Metadata M; + + // acquire resource + virtual void initialize(){ + this->CheckPointPtr.reset(new ScidacHmcCheckpointer(this->Par_, M)); + } +public: + ScidacCPModule(typename CPBase::APar Par, Metadata M_):M(M_), CPBase(Par) {} + template + ScidacCPModule(Reader& Reader) : Parametrized(Reader), M(Reader){}; +}; #endif diff --git a/lib/qcd/hmc/checkpointers/CheckPointers.h b/lib/qcd/hmc/checkpointers/CheckPointers.h index 423ce45c..e7a5fa82 100644 --- a/lib/qcd/hmc/checkpointers/CheckPointers.h +++ b/lib/qcd/hmc/checkpointers/CheckPointers.h @@ -34,6 +34,7 @@ directory #include #include #include +#include //#include diff --git a/lib/qcd/hmc/checkpointers/ILDGCheckpointer.h b/lib/qcd/hmc/checkpointers/ILDGCheckpointer.h index 3bcdc77a..f7e6b17e 100644 --- a/lib/qcd/hmc/checkpointers/ILDGCheckpointer.h +++ b/lib/qcd/hmc/checkpointers/ILDGCheckpointer.h @@ -74,10 +74,10 @@ class ILDGHmcCheckpointer : public BaseHmcCheckpointer { if ((traj % Params.saveInterval) == 0) { std::string config, rng; this->build_filenames(traj, Params, config, rng); - + GridBase *grid = U._grid; uint32_t nersc_csum,scidac_csuma,scidac_csumb; BinaryIO::writeRNG(sRNG, pRNG, rng, 0,nersc_csum,scidac_csuma,scidac_csumb); - IldgWriter _IldgWriter; + IldgWriter _IldgWriter(grid->IsBoss()); _IldgWriter.open(config); _IldgWriter.writeConfiguration(U, traj, config, config); _IldgWriter.close(); @@ -95,6 +95,10 @@ class ILDGHmcCheckpointer : public BaseHmcCheckpointer { GridParallelRNG &pRNG) { std::string config, rng; this->build_filenames(traj, Params, config, rng); + this->check_filename(rng); + this->check_filename(config); + + uint32_t nersc_csum,scidac_csuma,scidac_csumb; BinaryIO::readRNG(sRNG, pRNG, rng, 0,nersc_csum,scidac_csuma,scidac_csumb); diff --git a/lib/qcd/hmc/checkpointers/NerscCheckpointer.h b/lib/qcd/hmc/checkpointers/NerscCheckpointer.h index a4b1b480..d452b994 100644 --- a/lib/qcd/hmc/checkpointers/NerscCheckpointer.h +++ b/lib/qcd/hmc/checkpointers/NerscCheckpointer.h @@ -69,6 +69,9 @@ class NerscHmcCheckpointer : public BaseHmcCheckpointer { GridParallelRNG &pRNG) { std::string config, rng; this->build_filenames(traj, Params, config, rng); + this->check_filename(rng); + this->check_filename(config); + FieldMetaData header; NerscIO::readRNGState(sRNG, pRNG, header, rng); diff --git a/lib/qcd/hmc/checkpointers/ScidacCheckpointer.h b/lib/qcd/hmc/checkpointers/ScidacCheckpointer.h new file mode 100644 index 00000000..0867b882 --- /dev/null +++ b/lib/qcd/hmc/checkpointers/ScidacCheckpointer.h @@ -0,0 +1,125 @@ +/************************************************************************************* + +Grid physics library, www.github.com/paboyle/Grid + +Source file: ./lib/qcd/hmc/ScidacCheckpointer.h + +Copyright (C) 2018 + +Author: Guido Cossu + +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 SCIDAC_CHECKPOINTER +#define SCIDAC_CHECKPOINTER + +#ifdef HAVE_LIME + +#include +#include +#include + +namespace Grid { +namespace QCD { + +// For generic fields +template +class ScidacHmcCheckpointer : public BaseHmcCheckpointer { + private: + CheckpointerParameters Params; + Metadata MData; + + typedef typename Implementation::Field Field; + + public: + //INHERIT_GIMPL_TYPES(Implementation); + + ScidacHmcCheckpointer(const CheckpointerParameters &Params_) { initialize(Params_); } + ScidacHmcCheckpointer(const CheckpointerParameters &Params_, const Metadata& M_):MData(M_) { initialize(Params_); } + + void initialize(const CheckpointerParameters &Params_) { + Params = Params_; + + // check here that the format is valid + int ieee32big = (Params.format == std::string("IEEE32BIG")); + int ieee32 = (Params.format == std::string("IEEE32")); + int ieee64big = (Params.format == std::string("IEEE64BIG")); + int ieee64 = (Params.format == std::string("IEEE64")); + + if (!(ieee64big || ieee32 || ieee32big || ieee64)) { + std::cout << GridLogError << "Unrecognized file format " << Params.format + << std::endl; + std::cout << GridLogError + << "Allowed: IEEE32BIG | IEEE32 | IEEE64BIG | IEEE64" + << std::endl; + + exit(1); + } + } + + void TrajectoryComplete(int traj, Field &U, GridSerialRNG &sRNG, + GridParallelRNG &pRNG) { + if ((traj % Params.saveInterval) == 0) { + std::string config, rng; + this->build_filenames(traj, Params, config, rng); + GridBase *grid = U._grid; + uint32_t nersc_csum,scidac_csuma,scidac_csumb; + BinaryIO::writeRNG(sRNG, pRNG, rng, 0,nersc_csum,scidac_csuma,scidac_csumb); + ScidacWriter _ScidacWriter(grid->IsBoss()); + _ScidacWriter.open(config); + _ScidacWriter.writeScidacFieldRecord(U, MData); + _ScidacWriter.close(); + + std::cout << GridLogMessage << "Written Scidac Configuration on " << config + << " checksum " << std::hex << nersc_csum<<"/" + << scidac_csuma<<"/" << scidac_csumb + << std::dec << std::endl; + } + }; + + void CheckpointRestore(int traj, Field &U, GridSerialRNG &sRNG, + GridParallelRNG &pRNG) { + std::string config, rng; + this->build_filenames(traj, Params, config, rng); + this->check_filename(rng); + this->check_filename(config); + + + uint32_t nersc_csum,scidac_csuma,scidac_csumb; + BinaryIO::readRNG(sRNG, pRNG, rng, 0,nersc_csum,scidac_csuma,scidac_csumb); + + Metadata md_content; + ScidacReader _ScidacReader; + _ScidacReader.open(config); + _ScidacReader.readScidacFieldRecord(U,md_content); // format from the header + _ScidacReader.close(); + + std::cout << GridLogMessage << "Read Scidac Configuration from " << config + << " checksum " << std::hex + << nersc_csum<<"/" + << scidac_csuma<<"/" + << scidac_csumb + << std::dec << std::endl; + }; +}; +} +} + +#endif // HAVE_LIME +#endif // ILDG_CHECKPOINTER diff --git a/lib/qcd/hmc/integrators/Integrator.h b/lib/qcd/hmc/integrators/Integrator.h index 95b19904..232eba42 100644 --- a/lib/qcd/hmc/integrators/Integrator.h +++ b/lib/qcd/hmc/integrators/Integrator.h @@ -114,18 +114,26 @@ class Integrator { // input U actually not used in the fundamental case // Fundamental updates, include smearing - for (int a = 0; a < as[level].actions.size(); ++a) { + for (int a = 0; a < as[level].actions.size(); ++a) { + double start_full = usecond(); Field force(U._grid); conformable(U._grid, Mom._grid); + Field& Us = Smearer.get_U(as[level].actions.at(a)->is_smeared); + double start_force = usecond(); as[level].actions.at(a)->deriv(Us, force); // deriv should NOT include Ta std::cout << GridLogIntegrator << "Smearing (on/off): " << as[level].actions.at(a)->is_smeared << std::endl; if (as[level].actions.at(a)->is_smeared) Smearer.smeared_force(force); force = FieldImplementation::projectForce(force); // Ta for gauge fields + double end_force = usecond(); Real force_abs = std::sqrt(norm2(force)/U._grid->gSites()); - std::cout << GridLogIntegrator << "Force average: " << force_abs << std::endl; + std::cout << GridLogIntegrator << "["< Factory::create(const std::string type, } catch (std::out_of_range &) { - //HADRON_ERROR("object of type '" + type + "' unknown"); + //HADRONS_ERROR("object of type '" + type + "' unknown"); std::cout << GridLogError << "Error" << std::endl; std::cout << GridLogError << obj_type() << " object of name [" << type << "] unknown" << std::endl; exit(1); diff --git a/lib/qcd/smearing/GaugeConfiguration.h b/lib/qcd/smearing/GaugeConfiguration.h index fc045ba2..6fea875b 100644 --- a/lib/qcd/smearing/GaugeConfiguration.h +++ b/lib/qcd/smearing/GaugeConfiguration.h @@ -6,30 +6,33 @@ #ifndef GAUGE_CONFIG_ #define GAUGE_CONFIG_ -namespace Grid { +namespace Grid +{ -namespace QCD { +namespace QCD +{ - //trivial class for no smearing - template< class Impl > -class NoSmearing { +//trivial class for no smearing +template +class NoSmearing +{ public: INHERIT_FIELD_TYPES(Impl); - Field* ThinField; + Field *ThinField; - NoSmearing(): ThinField(NULL) {} + NoSmearing() : ThinField(NULL) {} - void set_Field(Field& U) { ThinField = &U; } + void set_Field(Field &U) { ThinField = &U; } - void smeared_force(Field&) const {} + void smeared_force(Field &) const {} - Field& get_SmearedU() { return *ThinField; } + Field &get_SmearedU() { return *ThinField; } - Field& get_U(bool smeared = false) { + Field &get_U(bool smeared = false) + { return *ThinField; } - }; /*! @@ -44,32 +47,36 @@ public: It stores a list of smeared configurations. */ template -class SmearedConfiguration { - public: +class SmearedConfiguration +{ +public: INHERIT_GIMPL_TYPES(Gimpl); - private: +private: const unsigned int smearingLevels; Smear_Stout StoutSmearing; std::vector SmearedSet; // Member functions //==================================================================== - void fill_smearedSet(GaugeField& U) { - ThinLinks = &U; // attach the smearing routine to the field U + void fill_smearedSet(GaugeField &U) + { + ThinLinks = &U; // attach the smearing routine to the field U // check the pointer is not null if (ThinLinks == NULL) std::cout << GridLogError << "[SmearedConfiguration] Error in ThinLinks pointer\n"; - if (smearingLevels > 0) { + if (smearingLevels > 0) + { std::cout << GridLogDebug << "[SmearedConfiguration] Filling SmearedSet\n"; GaugeField previous_u(ThinLinks->_grid); previous_u = *ThinLinks; - for (int smearLvl = 0; smearLvl < smearingLevels; ++smearLvl) { + for (int smearLvl = 0; smearLvl < smearingLevels; ++smearLvl) + { StoutSmearing.smear(SmearedSet[smearLvl], previous_u); previous_u = SmearedSet[smearLvl]; @@ -81,9 +88,10 @@ class SmearedConfiguration { } } //==================================================================== - GaugeField AnalyticSmearedForce(const GaugeField& SigmaKPrime, - const GaugeField& GaugeK) const { - GridBase* grid = GaugeK._grid; + GaugeField AnalyticSmearedForce(const GaugeField &SigmaKPrime, + const GaugeField &GaugeK) const + { + GridBase *grid = GaugeK._grid; GaugeField C(grid), SigmaK(grid), iLambda(grid); GaugeLinkField iLambda_mu(grid); GaugeLinkField iQ(grid), e_iQ(grid); @@ -94,7 +102,8 @@ class SmearedConfiguration { SigmaK = zero; iLambda = zero; - for (int mu = 0; mu < Nd; mu++) { + for (int mu = 0; mu < Nd; mu++) + { Cmu = peekLorentz(C, mu); GaugeKmu = peekLorentz(GaugeK, mu); SigmaKPrime_mu = peekLorentz(SigmaKPrime, mu); @@ -104,20 +113,22 @@ class SmearedConfiguration { pokeLorentz(iLambda, iLambda_mu, mu); } StoutSmearing.derivative(SigmaK, iLambda, - GaugeK); // derivative of SmearBase + GaugeK); // derivative of SmearBase return SigmaK; } /*! @brief Returns smeared configuration at level 'Level' */ - const GaugeField& get_smeared_conf(int Level) const { + const GaugeField &get_smeared_conf(int Level) const + { return SmearedSet[Level]; } //==================================================================== - void set_iLambda(GaugeLinkField& iLambda, GaugeLinkField& e_iQ, - const GaugeLinkField& iQ, const GaugeLinkField& Sigmap, - const GaugeLinkField& GaugeK) const { - GridBase* grid = iQ._grid; + void set_iLambda(GaugeLinkField &iLambda, GaugeLinkField &e_iQ, + const GaugeLinkField &iQ, const GaugeLinkField &Sigmap, + const GaugeLinkField &GaugeK) const + { + GridBase *grid = iQ._grid; GaugeLinkField iQ2(grid), iQ3(grid), B1(grid), B2(grid), USigmap(grid); GaugeLinkField unity(grid); unity = 1.0; @@ -206,15 +217,15 @@ class SmearedConfiguration { } //==================================================================== - public: - GaugeField* - ThinLinks; /*!< @brief Pointer to the thin - links configuration */ +public: + GaugeField * + ThinLinks; /* Pointer to the thin links configuration */ - /*! @brief Standard constructor */ - SmearedConfiguration(GridCartesian* UGrid, unsigned int Nsmear, - Smear_Stout& Stout) - : smearingLevels(Nsmear), StoutSmearing(Stout), ThinLinks(NULL) { + /* Standard constructor */ + SmearedConfiguration(GridCartesian *UGrid, unsigned int Nsmear, + Smear_Stout &Stout) + : smearingLevels(Nsmear), StoutSmearing(Stout), ThinLinks(NULL) + { for (unsigned int i = 0; i < smearingLevels; ++i) SmearedSet.push_back(*(new GaugeField(UGrid))); } @@ -223,21 +234,29 @@ class SmearedConfiguration { SmearedConfiguration() : smearingLevels(0), StoutSmearing(), SmearedSet(), ThinLinks(NULL) {} - - // attach the smeared routines to the thin links U and fill the smeared set - void set_Field(GaugeField& U) { fill_smearedSet(U); } + void set_Field(GaugeField &U) + { + double start = usecond(); + fill_smearedSet(U); + double end = usecond(); + double time = (end - start)/ 1e3; + std::cout << GridLogMessage << "Smearing in " << time << " ms" << std::endl; + } //==================================================================== - void smeared_force(GaugeField& SigmaTilde) const { - if (smearingLevels > 0) { + void smeared_force(GaugeField &SigmaTilde) const + { + if (smearingLevels > 0) + { + double start = usecond(); GaugeField force = SigmaTilde; // actually = U*SigmaTilde GaugeLinkField tmp_mu(SigmaTilde._grid); - for (int mu = 0; mu < Nd; mu++) { + for (int mu = 0; mu < Nd; mu++) + { // to get just SigmaTilde - tmp_mu = adj(peekLorentz(SmearedSet[smearingLevels - 1], mu)) * - peekLorentz(force, mu); + tmp_mu = adj(peekLorentz(SmearedSet[smearingLevels - 1], mu)) * peekLorentz(force, mu); pokeLorentz(force, tmp_mu, mu); } @@ -246,33 +265,43 @@ class SmearedConfiguration { force = AnalyticSmearedForce(force, *ThinLinks); - for (int mu = 0; mu < Nd; mu++) { + for (int mu = 0; mu < Nd; mu++) + { tmp_mu = peekLorentz(*ThinLinks, mu) * peekLorentz(force, mu); pokeLorentz(SigmaTilde, tmp_mu, mu); } - } // if smearingLevels = 0 do nothing + double end = usecond(); + double time = (end - start)/ 1e3; + std::cout << GridLogMessage << "Smearing force in " << time << " ms" << std::endl; + } // if smearingLevels = 0 do nothing } //==================================================================== - GaugeField& get_SmearedU() { return SmearedSet[smearingLevels - 1]; } + GaugeField &get_SmearedU() { return SmearedSet[smearingLevels - 1]; } - GaugeField& get_U(bool smeared = false) { + GaugeField &get_U(bool smeared = false) + { // get the config, thin links by default - if (smeared) { - if (smearingLevels) { + if (smeared) + { + if (smearingLevels) + { RealD impl_plaq = WilsonLoops::avgPlaquette(SmearedSet[smearingLevels - 1]); std::cout << GridLogDebug << "getting Usmr Plaq: " << impl_plaq << std::endl; return get_SmearedU(); - - } else { + } + else + { RealD impl_plaq = WilsonLoops::avgPlaquette(*ThinLinks); std::cout << GridLogDebug << "getting Thin Plaq: " << impl_plaq << std::endl; return *ThinLinks; } - } else { + } + else + { RealD impl_plaq = WilsonLoops::avgPlaquette(*ThinLinks); std::cout << GridLogDebug << "getting Thin Plaq: " << impl_plaq << std::endl; diff --git a/lib/qcd/smearing/WilsonFlow.h b/lib/qcd/smearing/WilsonFlow.h index 4f5c0d43..1c0855ab 100644 --- a/lib/qcd/smearing/WilsonFlow.h +++ b/lib/qcd/smearing/WilsonFlow.h @@ -173,8 +173,8 @@ void WilsonFlow::smear(GaugeField& out, const GaugeField& in) const { std::cout << "Time to evolve " << diff.count() << " s\n"; #endif std::cout << GridLogMessage << "[WilsonFlow] Energy density (plaq) : " - << step << " " - << energyDensityPlaquette(step,out) << std::endl; + << step << " " << tau(step) << " " + << energyDensityPlaquette(step,out) << std::endl; if( step % measure_interval == 0){ std::cout << GridLogMessage << "[WilsonFlow] Top. charge : " << step << " " @@ -193,8 +193,8 @@ void WilsonFlow::smear_adaptive(GaugeField& out, const GaugeField& in, Re //std::cout << GridLogMessage << "Evolution time :"<< taus << std::endl; evolve_step_adaptive(out, maxTau); std::cout << GridLogMessage << "[WilsonFlow] Energy density (plaq) : " - << step << " " - << energyDensityPlaquette(out) << std::endl; + << step << " " << taus << " " + << energyDensityPlaquette(out) << std::endl; if( step % measure_interval == 0){ std::cout << GridLogMessage << "[WilsonFlow] Top. charge : " << step << " " diff --git a/lib/serialisation/BaseIO.h b/lib/serialisation/BaseIO.h index bc178e0d..dd15e7da 100644 --- a/lib/serialisation/BaseIO.h +++ b/lib/serialisation/BaseIO.h @@ -60,8 +60,14 @@ namespace Grid { void write(const std::string &s, const iVector &output); template void write(const std::string &s, const iMatrix &output); + void scientificFormat(const bool set); + bool isScientific(void); + void setPrecision(const unsigned int prec); + unsigned int getPrecision(void); private: - T *upcast; + T *upcast; + bool scientific_{false}; + unsigned int prec_{0}; }; // Static abstract reader @@ -155,6 +161,30 @@ namespace Grid { { upcast->writeDefault(s, tensorToVec(output)); } + + template + void Writer::scientificFormat(const bool set) + { + scientific_ = set; + } + + template + bool Writer::isScientific(void) + { + return scientific_; + } + + template + void Writer::setPrecision(const unsigned int prec) + { + prec_ = prec; + } + + template + unsigned int Writer::getPrecision(void) + { + return prec_; + } // Reader template implementation template diff --git a/lib/serialisation/BinaryIO.cc b/lib/serialisation/BinaryIO.cc index 7133adc0..a4d26b69 100644 --- a/lib/serialisation/BinaryIO.cc +++ b/lib/serialisation/BinaryIO.cc @@ -29,15 +29,14 @@ Author: paboyle #include using namespace Grid; -using namespace std; // Writer implementation /////////////////////////////////////////////////////// -BinaryWriter::BinaryWriter(const string &fileName) -: file_(fileName, ios::binary|ios::out) +BinaryWriter::BinaryWriter(const std::string &fileName) +: file_(fileName, std::ios::binary|std::ios::out) {} template <> -void BinaryWriter::writeDefault(const string &s, const string &x) +void BinaryWriter::writeDefault(const std::string &s, const std::string &x) { uint64_t sz = x.size(); @@ -48,20 +47,20 @@ void BinaryWriter::writeDefault(const string &s, const string &x) } } -void BinaryWriter::writeDefault(const string &s, const char *x) +void BinaryWriter::writeDefault(const std::string &s, const char *x) { - string sx(x); + std::string sx(x); writeDefault(s, sx); } // Reader implementation /////////////////////////////////////////////////////// -BinaryReader::BinaryReader(const string &fileName) -: file_(fileName, ios::binary|ios::in) +BinaryReader::BinaryReader(const std::string &fileName) +: file_(fileName, std::ios::binary|std::ios::in) {} template <> -void BinaryReader::readDefault(const string &s, string &output) +void BinaryReader::readDefault(const std::string &s, std::string &output) { uint64_t sz; diff --git a/lib/serialisation/Hdf5IO.cc b/lib/serialisation/Hdf5IO.cc index 1fb7be0c..b915a988 100644 --- a/lib/serialisation/Hdf5IO.cc +++ b/lib/serialisation/Hdf5IO.cc @@ -55,6 +55,11 @@ void Hdf5Writer::writeDefault(const std::string &s, const char *x) writeDefault(s, sx); } +Group & Hdf5Writer::getGroup(void) +{ + return group_; +} + // Reader implementation /////////////////////////////////////////////////////// Hdf5Reader::Hdf5Reader(const std::string &fileName) : fileName_(fileName) @@ -103,3 +108,8 @@ void Hdf5Reader::readDefault(const std::string &s, std::string &x) x.resize(strType.getSize()); attribute.read(strType, &(x[0])); } + +Group & Hdf5Reader::getGroup(void) +{ + return group_; +} diff --git a/lib/serialisation/Hdf5IO.h b/lib/serialisation/Hdf5IO.h index 12625ab8..1ae2791e 100644 --- a/lib/serialisation/Hdf5IO.h +++ b/lib/serialisation/Hdf5IO.h @@ -38,6 +38,7 @@ namespace Grid template typename std::enable_if>::is_number, void>::type writeDefault(const std::string &s, const std::vector &x); + H5NS::Group & getGroup(void); private: template void writeSingleAttribute(const U &x, const std::string &name, @@ -65,6 +66,7 @@ namespace Grid template typename std::enable_if>::is_number, void>::type readDefault(const std::string &s, std::vector &x); + H5NS::Group & getGroup(void); private: template void readSingleAttribute(U &x, const std::string &name, diff --git a/lib/serialisation/JSON_IO.cc b/lib/serialisation/JSON_IO.cc index 6a01aa84..98edc375 100644 --- a/lib/serialisation/JSON_IO.cc +++ b/lib/serialisation/JSON_IO.cc @@ -28,11 +28,10 @@ #include using namespace Grid; -using namespace std; // Writer implementation /////////////////////////////////////////////////////// -JSONWriter::JSONWriter(const string &fileName) -: fileName_(fileName), ss_("{ ", ostringstream::ate){} +JSONWriter::JSONWriter(const std::string &fileName) +: fileName_(fileName), ss_("{ ", std::ostringstream::ate){} JSONWriter::~JSONWriter(void) { @@ -46,7 +45,7 @@ JSONWriter::~JSONWriter(void) os << std::setw(2) << json::parse(ss_.str()) << std::endl; } -void JSONWriter::push(const string &s) +void JSONWriter::push(const std::string &s) { // adding a nested object if (s.size()) @@ -90,7 +89,7 @@ namespace Grid // Reader implementation /////////////////////////////////////////////////////// -JSONReader::JSONReader(const string &fileName) +JSONReader::JSONReader(const std::string &fileName) : fileName_(fileName) { std::ifstream file(fileName_); @@ -102,7 +101,7 @@ JSONReader::JSONReader(const string &fileName) jcur_ = jobject_; } -bool JSONReader::push(const string &s) +bool JSONReader::push(const std::string &s) { if (s.size()){ jold_.push_back(jcur_); @@ -159,7 +158,7 @@ bool JSONReader::nextElement(const std::string &s) } template <> -void JSONReader::readDefault(const string &s, string &output) +void JSONReader::readDefault(const std::string &s, std::string &output) { //cout << "JSONReader::readDefault(string) : " << s<< " " << jcur_ << endl; if (s.size()){ diff --git a/lib/serialisation/MacroMagic.h b/lib/serialisation/MacroMagic.h index 5df2c780..95cd1c3c 100644 --- a/lib/serialisation/MacroMagic.h +++ b/lib/serialisation/MacroMagic.h @@ -115,7 +115,7 @@ THE SOFTWARE. #define GRID_MACRO_WRITE_MEMBER(A,B) Grid::write(WR,#B,obj. B); #define GRID_SERIALIZABLE_CLASS_MEMBERS(cname,...)\ - std::string SerialisableClassName(void) {return std::string(#cname);} \ + std::string SerialisableClassName(void) const {return std::string(#cname);} \ GRID_MACRO_EVAL(GRID_MACRO_MAP(GRID_MACRO_MEMBER,__VA_ARGS__))\ template \ static inline void write(Writer &WR,const std::string &s, const cname &obj){ \ diff --git a/lib/serialisation/TextIO.cc b/lib/serialisation/TextIO.cc index 5e27dfbc..77c45fd9 100644 --- a/lib/serialisation/TextIO.cc +++ b/lib/serialisation/TextIO.cc @@ -30,17 +30,16 @@ #include using namespace Grid; -using namespace std; #define GRID_TEXT_INDENT 2 //number of spaces for indentation of levels // Writer implementation /////////////////////////////////////////////////////// -TextWriter::TextWriter(const string &fileName) -: file_(fileName, ios::out) +TextWriter::TextWriter(const std::string &fileName) +: file_(fileName, std::ios::out) {} -void TextWriter::push(const string &s) +void TextWriter::push(const std::string &s) { level_++; }; @@ -58,16 +57,16 @@ void TextWriter::indent(void) }; // Reader implementation /////////////////////////////////////////////////////// -TextReader::TextReader(const string &fileName) +TextReader::TextReader(const std::string &fileName) { - file_.open(fileName, ios::in); + file_.open(fileName, std::ios::in); if (!file_.is_open()) { std::cout << GridLogMessage << "TextReader: Error opening file " << fileName << std::endl; exit(1);// write better error handling } } -bool TextReader::push(const string &s) +bool TextReader::push(const std::string &s) { level_++; return true; @@ -91,7 +90,7 @@ void TextReader::checkIndent(void) } if (!check) { - cerr << "TextReader: mismatch on level " << level_ << std::endl; + std::cerr << "TextReader: mismatch on level " << level_ << std::endl; exit(1); } } diff --git a/lib/serialisation/VectorUtils.h b/lib/serialisation/VectorUtils.h index 6df9416d..880744ec 100644 --- a/lib/serialisation/VectorUtils.h +++ b/lib/serialisation/VectorUtils.h @@ -78,6 +78,48 @@ namespace Grid { typedef typename std::vector::type>> type; }; + template + void tensorDim(std::vector &dim, const T &t, const bool wipe = true) + { + if (wipe) + { + dim.clear(); + } + } + + template + void tensorDim(std::vector &dim, const iScalar &t, const bool wipe = true) + { + if (wipe) + { + dim.clear(); + } + tensorDim(dim, t._internal, false); + } + + template + void tensorDim(std::vector &dim, const iVector &t, const bool wipe = true) + { + if (wipe) + { + dim.clear(); + } + dim.push_back(N); + tensorDim(dim, t._internal[0], false); + } + + template + void tensorDim(std::vector &dim, const iMatrix &t, const bool wipe = true) + { + if (wipe) + { + dim.clear(); + } + dim.push_back(N); + dim.push_back(N); + tensorDim(dim, t._internal[0][0], false); + } + template typename TensorToVec::type tensorToVec(const T &t) { @@ -367,13 +409,13 @@ namespace Grid { inline std::ostream & operator<<(std::ostream &os, const std::vector &v) { os << "["; - for (auto &x: v) + for (unsigned int i = 0; i < v.size(); ++i) { - os << x << " "; - } - if (v.size() > 0) - { - os << "\b"; + os << v[i]; + if (i < v.size() - 1) + { + os << " "; + } } os << "]"; diff --git a/lib/serialisation/XmlIO.cc b/lib/serialisation/XmlIO.cc index 8ac7422c..e793c2f9 100644 --- a/lib/serialisation/XmlIO.cc +++ b/lib/serialisation/XmlIO.cc @@ -29,10 +29,20 @@ Author: paboyle #include using namespace Grid; -using namespace std; + +void Grid::xmlCheckParse(const pugi::xml_parse_result &result, const std::string name) +{ + if (!result) + { + std::cerr << "XML parsing error for " << name << std::endl; + std::cerr << "XML error description: " << result.description() << std::endl; + std::cerr << "XML error offset : " << result.offset << std::endl; + abort(); + } +} // Writer implementation /////////////////////////////////////////////////////// -XmlWriter::XmlWriter(const string &fileName, string toplev) : fileName_(fileName) +XmlWriter::XmlWriter(const std::string &fileName, std::string toplev) : fileName_(fileName) { if ( toplev == std::string("") ) { node_=doc_; @@ -45,60 +55,73 @@ XmlWriter::XmlWriter(const string &fileName, string toplev) : fileName_(fileName XmlWriter::~XmlWriter(void) { if ( fileName_ != std::string("") ) { - doc_.save_file(fileName_.c_str(), " "); + doc_.save_file(fileName_.c_str(), indent_.c_str()); } } -void XmlWriter::push(const string &s) +void XmlWriter::push(const std::string &s) { node_ = node_.append_child(s.c_str()); } +void XmlWriter::pushXmlString(const std::string &s) +{ + pugi::xml_document doc; + auto result = doc.load_buffer(s.c_str(), s.size()); + + xmlCheckParse(result, "fragment\n'" + s +"'"); + for (pugi::xml_node child = doc.first_child(); child; child = child.next_sibling()) + { + node_ = node_.append_copy(child); + } + pop(); +} + void XmlWriter::pop(void) { node_ = node_.parent(); } -std::string XmlWriter::XmlString(void) + +std::string XmlWriter::docString(void) { std::ostringstream oss; - doc_.save(oss); + doc_.save(oss, indent_.c_str()); return oss.str(); } -XmlReader::XmlReader(const char *xmlstring,string toplev) : fileName_("") +std::string XmlWriter::string(void) { - pugi::xml_parse_result result; - result = doc_.load_string(xmlstring); - if ( !result ) { - cerr << "XML error description (from char *): " << result.description() << "\nXML\n"<< xmlstring << "\n"; - cerr << "XML error offset (from char *) " << result.offset << "\nXML\n"<< xmlstring <<"\n"; - abort(); - } - if ( toplev == std::string("") ) { - node_ = doc_; - } else { - node_ = doc_.child(toplev.c_str()); - } + std::ostringstream oss; + doc_.save(oss, indent_.c_str(), pugi::format_default | pugi::format_no_declaration); + return oss.str(); } // Reader implementation /////////////////////////////////////////////////////// -XmlReader::XmlReader(const string &fileName,string toplev) : fileName_(fileName) +XmlReader::XmlReader(const std::string &s, const bool isBuffer, + std::string toplev) { pugi::xml_parse_result result; - result = doc_.load_file(fileName_.c_str()); - if ( !result ) { - cerr << "XML error description: " << result.description() <<" "<< fileName_ <<"\n"; - cerr << "XML error offset : " << result.offset <<" "<< fileName_ <<"\n"; - abort(); + + if (isBuffer) + { + fileName_ = ""; + result = doc_.load_string(s.c_str()); + xmlCheckParse(result, "string\n'" + s + "'"); + } + else + { + fileName_ = s; + result = doc_.load_file(s.c_str()); + xmlCheckParse(result, "file '" + fileName_ + "'"); } if ( toplev == std::string("") ) { - node_ = doc_; + node_ = doc_; } else { node_ = doc_.child(toplev.c_str()); } } -bool XmlReader::push(const string &s) +bool XmlReader::push(const std::string &s) { if (node_.child(s.c_str())) { @@ -129,11 +152,10 @@ bool XmlReader::nextElement(const std::string &s) { return false; } - } template <> -void XmlReader::readDefault(const string &s, string &output) +void XmlReader::readDefault(const std::string &s, std::string &output) { if (node_.child(s.c_str())) { diff --git a/lib/serialisation/XmlIO.h b/lib/serialisation/XmlIO.h index e37eb8d9..17ccb32e 100644 --- a/lib/serialisation/XmlIO.h +++ b/lib/serialisation/XmlIO.h @@ -43,20 +43,24 @@ Author: paboyle namespace Grid { + void xmlCheckParse(const pugi::xml_parse_result &result, const std::string name); class XmlWriter: public Writer { public: - XmlWriter(const std::string &fileName,std::string toplev = std::string("grid") ); + XmlWriter(const std::string &fileName, std::string toplev = std::string("grid") ); virtual ~XmlWriter(void); void push(const std::string &s); + void pushXmlString(const std::string &s); void pop(void); template void writeDefault(const std::string &s, const U &x); template void writeDefault(const std::string &s, const std::vector &x); - std::string XmlString(void); + std::string docString(void); + std::string string(void); private: + const std::string indent_{" "}; pugi::xml_document doc_; pugi::xml_node node_; std::string fileName_; @@ -65,8 +69,8 @@ namespace Grid class XmlReader: public Reader { public: - XmlReader(const char *xmlstring,std::string toplev = std::string("grid") ); - XmlReader(const std::string &fileName,std::string toplev = std::string("grid") ); + XmlReader(const std::string &fileName, const bool isBuffer = false, + std::string toplev = std::string("grid") ); virtual ~XmlReader(void) = default; bool push(const std::string &s); void pop(void); @@ -75,6 +79,8 @@ namespace Grid void readDefault(const std::string &s, U &output); template void readDefault(const std::string &s, std::vector &output); + private: + void checkParse(const pugi::xml_parse_result &result, const std::string name); private: pugi::xml_document doc_; pugi::xml_node node_; @@ -97,6 +103,14 @@ namespace Grid { std::ostringstream os; + if (getPrecision()) + { + os.precision(getPrecision()); + } + if (isScientific()) + { + os << std::scientific; + } os << std::boolalpha << x; pugi::xml_node leaf = node_.append_child(s.c_str()); leaf.append_child(pugi::node_pcdata).set_value(os.str().c_str()); diff --git a/lib/stencil/Stencil.h b/lib/stencil/Stencil.h index 69c010f4..a79064eb 100644 --- a/lib/stencil/Stencil.h +++ b/lib/stencil/Stencil.h @@ -66,6 +66,8 @@ void Gather_plane_simple_table (std::vector >& table,const La parallel_for(int i=0;i void CommsMerge(decompressor decompress,std::vector &mm,std::vector &dd) { + mergetime-=usecond(); for(int i=0;i 0); } if( GridCmdOptionExists(*argv,*argv+*argc,"--cacheblocking") ){ arg= GridCmdOptionPayload(*argv,*argv+*argc,"--cacheblocking"); diff --git a/lib/util/Init.h b/lib/util/Init.h index 3da00742..c8236dc6 100644 --- a/lib/util/Init.h +++ b/lib/util/Init.h @@ -61,6 +61,7 @@ namespace Grid { std::vector &simd, std::vector &mpi); + void printHash(void); }; #endif diff --git a/lib/util/version.cc b/lib/util/version.cc new file mode 100644 index 00000000..19759274 --- /dev/null +++ b/lib/util/version.cc @@ -0,0 +1,12 @@ +#include +#include +namespace Grid { + void printHash(){ +#ifdef GITHASH + std::cout << "Current Grid git commit hash=" << GITHASH << std::endl; +#else + std::cout << "Current Grid git commit hash is undefined. Check makefile." << std::endl; +#endif +#undef GITHASH +} +} diff --git a/tests/IO/Test_ildg_io.cc b/tests/IO/Test_ildg_io.cc index 6aac2e38..55dd93b8 100644 --- a/tests/IO/Test_ildg_io.cc +++ b/tests/IO/Test_ildg_io.cc @@ -79,7 +79,7 @@ int main (int argc, char ** argv) std::cout <({42,10,81,9})); diff --git a/tests/Test_compressed_lanczos_hot_start.cc b/tests/Test_compressed_lanczos_hot_start.cc new file mode 100644 index 00000000..65f69c54 --- /dev/null +++ b/tests/Test_compressed_lanczos_hot_start.cc @@ -0,0 +1,259 @@ + /************************************************************************************* + + Grid physics library, www.github.com/paboyle/Grid + + Source file: ./tests/Test_dwf_compressed_lanczos_reorg.cc + + Copyright (C) 2017 + +Author: Leans heavily on Christoph Lehner's code +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 */ +/* + * Reimplement the badly named "multigrid" lanczos as compressed Lanczos using the features + * in Grid that were intended to be used to support blocked Aggregates, from + */ +#include +#include +#include + +using namespace std; +using namespace Grid; +using namespace Grid::QCD; + +template +class LocalCoherenceLanczosScidac : public LocalCoherenceLanczos +{ +public: + typedef iVector CoarseSiteVector; + typedef Lattice CoarseField; + typedef Lattice CoarseScalar; // used for inner products on fine field + typedef Lattice FineField; + + LocalCoherenceLanczosScidac(GridBase *FineGrid,GridBase *CoarseGrid, + LinearOperatorBase &FineOp, + int checkerboard) + // Base constructor + : LocalCoherenceLanczos(FineGrid,CoarseGrid,FineOp,checkerboard) + {}; + + void checkpointFine(std::string evecs_file,std::string evals_file) + { +#ifdef HAVE_LIME + assert(this->subspace.size()==nbasis); + emptyUserRecord record; + Grid::QCD::ScidacWriter WR(this->_FineGrid->IsBoss()); + WR.open(evecs_file); + for(int k=0;ksubspace[k],record); + } + WR.close(); + + XmlWriter WRx(evals_file); + write(WRx,"evals",this->evals_fine); +#else + assert(0); +#endif + } + + void checkpointFineRestore(std::string evecs_file,std::string evals_file) + { +#ifdef HAVE_LIME + this->evals_fine.resize(nbasis); + this->subspace.resize(nbasis,this->_FineGrid); + + std::cout << GridLogIRL<< "checkpointFineRestore: Reading evals from "<evals_fine); + + assert(this->evals_fine.size()==nbasis); + + std::cout << GridLogIRL<< "checkpointFineRestore: Reading evecs from "<subspace[k].checkerboard=this->_checkerboard; + RD.readScidacFieldRecord(this->subspace[k],record); + + } + RD.close(); +#else + assert(0); +#endif + } + + void checkpointCoarse(std::string evecs_file,std::string evals_file) + { +#ifdef HAVE_LIME + int n = this->evec_coarse.size(); + emptyUserRecord record; + Grid::QCD::ScidacWriter WR(this->_CoarseGrid->IsBoss()); + WR.open(evecs_file); + for(int k=0;kevec_coarse[k],record); + } + WR.close(); + + XmlWriter WRx(evals_file); + write(WRx,"evals",this->evals_coarse); +#else + assert(0); +#endif + } + + void checkpointCoarseRestore(std::string evecs_file,std::string evals_file,int nvec) + { +#ifdef HAVE_LIME + std::cout << "resizing coarse vecs to " << nvec<< std::endl; + this->evals_coarse.resize(nvec); + this->evec_coarse.resize(nvec,this->_CoarseGrid); + std::cout << GridLogIRL<< "checkpointCoarseRestore: Reading evals from "<evals_coarse); + + assert(this->evals_coarse.size()==nvec); + emptyUserRecord record; + std::cout << GridLogIRL<< "checkpointCoarseRestore: Reading evecs from "<evec_coarse[k],record); + } + RD.close(); +#else + assert(0); +#endif + } +}; + +int main (int argc, char ** argv) { + + Grid_init(&argc,&argv); + GridLogIRL.TimingMode(1); + + LocalCoherenceLanczosParams Params; + { + Params.omega.resize(10); + Params.blockSize.resize(5); + XmlWriter writer("Params_template.xml"); + write(writer,"Params",Params); + std::cout << GridLogMessage << " Written Params_template.xml" < blockSize = Params.blockSize; + std::vector latt({32,32,32,32}); + uint64_t vol = Ls*latt[0]*latt[1]*latt[2]*latt[3]; + double mat_flop= 2.0*1320.0*vol; + // Grids + GridCartesian * UGrid = SpaceTimeGrid::makeFourDimGrid(latt, + GridDefaultSimd(Nd,vComplex::Nsimd()), + GridDefaultMpi()); + GridRedBlackCartesian * UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); + GridCartesian * FGrid = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid); + GridRedBlackCartesian * FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGrid); + + std::vector fineLatt = latt; + int dims=fineLatt.size(); + assert(blockSize.size()==dims+1); + std::vector coarseLatt(dims); + std::vector coarseLatt5d ; + + for (int d=0;d seeds4({1,2,3,4}); + GridParallelRNG RNG4(UGrid); RNG4.SeedFixedIntegers(seeds4); + LatticeGaugeField Umu(UGrid); + SU3::HotConfiguration(RNG4,Umu); + // FieldMetaData header; + // NerscIO::readConfiguration(Umu,header,Params.config); + + std::cout << GridLogMessage << "Lattice dimensions: " << latt << " Ls: " << Ls << std::endl; + + // ZMobius EO Operator + ZMobiusFermionR Ddwf(Umu, *FGrid, *FrbGrid, *UGrid, *UrbGrid, mass, M5, Params.omega,1.,0.); + SchurDiagTwoOperator HermOp(Ddwf); + + // Eigenvector storage + LanczosParams fine =Params.FineParams; + LanczosParams coarse=Params.CoarseParams; + + const int Ns1 = fine.Nstop; const int Ns2 = coarse.Nstop; + const int Nk1 = fine.Nk; const int Nk2 = coarse.Nk; + const int Nm1 = fine.Nm; const int Nm2 = coarse.Nm; + + std::cout << GridLogMessage << "Keep " << fine.Nstop << " fine vectors" << std::endl; + std::cout << GridLogMessage << "Keep " << coarse.Nstop << " coarse vectors" << std::endl; + assert(Nm2 >= Nm1); + + const int nbasis= 60; + assert(nbasis==Ns1); + LocalCoherenceLanczosScidac _LocalCoherenceLanczos(FrbGrid,CoarseGrid5,HermOp,Odd); + std::cout << GridLogMessage << "Constructed LocalCoherenceLanczos" << std::endl; + + assert( (Params.doFine)||(Params.doFineRead)); + + if ( Params.doFine ) { + std::cout << GridLogMessage << "Performing fine grid IRL Nstop "<< Ns1 << " Nk "< HermOpEO(Ddwf); SchurDiagMooeeOperator HermOpEO_f(Ddwf_f); - std::cout << "Starting mixed CG" << std::endl; + std::cout << GridLogMessage << "::::::::::::: Starting mixed CG" << std::endl; MixedPrecisionConjugateGradient mCG(1.0e-8, 10000, 50, FrbGrid_f, HermOpEO_f, HermOpEO); mCG(src_o,result_o); - std::cout << "Starting regular CG" << std::endl; + std::cout << GridLogMessage << "::::::::::::: Starting regular CG" << std::endl; ConjugateGradient CG(1.0e-8,10000); CG(HermOpEO,src_o,result_o_2); LatticeFermionD diff_o(FrbGrid); RealD diff = axpy_norm(diff_o, -1.0, result_o, result_o_2); - std::cout << "Diff between mixed and regular CG: " << diff << std::endl; + std::cout << GridLogMessage << "::::::::::::: Diff between mixed and regular CG: " << diff << std::endl; + #ifdef HAVE_LIME + if( GridCmdOptionExists(argv,argv+argc,"--checksums") ){ + std::string file1("./Propagator1"); + emptyUserRecord record; + uint32_t nersc_csum; + uint32_t scidac_csuma; + uint32_t scidac_csumb; + typedef SpinColourVectorD FermionD; + typedef vSpinColourVectorD vFermionD; + + BinarySimpleMunger munge; + std::string format = getFormatString(); + + BinaryIO::writeLatticeObject(result_o,file1,munge, 0, format, + nersc_csum,scidac_csuma,scidac_csumb); + + std::cout << GridLogMessage << " Mixed checksums "<(result_o_2,file1,munge, 0, format, + nersc_csum,scidac_csuma,scidac_csumb); + + std::cout << GridLogMessage << " CG checksums "< + + 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 + +using namespace std; +using namespace Grid; +using namespace Grid::QCD; + +int main (int argc, char ** argv) +{ + Grid_init(&argc,&argv); + + std::vector latt_size = GridDefaultLatt(); + std::vector simd_layout = GridDefaultSimd(Nd,vComplex::Nsimd()); + std::vector mpi_layout = GridDefaultMpi(); + + GridCartesian Grid(latt_size,simd_layout,mpi_layout); + GridRedBlackCartesian RBGrid(&Grid); + + int threads = GridThread::GetThreads(); + std::cout< seeds({1,2,3,4}); + + GridParallelRNG pRNG(&Grid); + pRNG.SeedFixedIntegers(std::vector({45,12,81,9})); + + LatticeGaugeField U(&Grid); + + SU3::HotConfiguration(pRNG,U); + + double beta = 1.0; + double c1 = 0.331; + + //ConjugatePlaqPlusRectangleActionR Action(beta,c1); + ConjugateWilsonGaugeActionR Action(beta); + //WilsonGaugeActionR Action(beta); + + ComplexD S = Action.S(U); + + // get the deriv of phidag MdagM phi with respect to "U" + LatticeGaugeField UdSdU(&Grid); + + Action.deriv(U,UdSdU); + + //////////////////////////////////// + // Modify the gauge field a little + //////////////////////////////////// + RealD dt = 0.0001; + + LatticeColourMatrix mommu(&Grid); + LatticeColourMatrix forcemu(&Grid); + LatticeGaugeField mom(&Grid); + LatticeGaugeField Uprime(&Grid); + + for(int mu=0;mu(mom,mommu,mu); + + // fourth order exponential approx + parallel_for(auto i=mom.begin();i(UdSdU,mu); + mommu = PeekIndex(mom,mu); + + // Update gauge action density + // U = exp(p dt) U + // dU/dt = p U + // so dSdt = trace( dUdt dSdU) = trace( p UdSdUmu ) + + dS = dS - trace(mommu*UdSdUmu)*dt*2.0; + + } + ComplexD dSpred = sum(dS); + + std::cout << GridLogMessage << " S "< +#include using namespace Grid; using namespace Hadrons; diff --git a/tests/hadrons/Test_hadrons.hpp b/tests/hadrons/Test_hadrons.hpp index 67124d6c..fc061459 100644 --- a/tests/hadrons/Test_hadrons.hpp +++ b/tests/hadrons/Test_hadrons.hpp @@ -26,6 +26,7 @@ *******************************************************************************/ #include +#include using namespace Grid; using namespace Hadrons; diff --git a/tests/hadrons/Test_hadrons_2AS_spectrum.cc b/tests/hadrons/Test_hadrons_2AS_spectrum.cc deleted file mode 100644 index b3906730..00000000 --- a/tests/hadrons/Test_hadrons_2AS_spectrum.cc +++ /dev/null @@ -1,169 +0,0 @@ -/******************************************************************************* - Grid physics library, www.github.com/paboyle/Grid - - Source file: tests/hadrons/Test_hadrons_spectrum.cc - - Copyright (C) 2015 - - Author: Antonin Portelli - - 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 - -using namespace Grid; -using namespace Hadrons; - - - BEGIN_HADRONS_NAMESPACE - BEGIN_MODULE_NAMESPACE(MFermion) - MODULE_REGISTER_NS(GaugeProp2AS, TGaugeProp, MFermion); - END_MODULE_NAMESPACE - BEGIN_MODULE_NAMESPACE(MSource) - MODULE_REGISTER_NS(Point2AS, TPoint, MSource); - END_MODULE_NAMESPACE - BEGIN_MODULE_NAMESPACE(MContraction) - MODULE_REGISTER_NS(Meson2AS, ARG(TMeson), MContraction); -// MODULE_REGISTER_NS(BaryonMultirep, ARG(TBaryon), MContraction); - END_MODULE_NAMESPACE - BEGIN_MODULE_NAMESPACE(MSink) - MODULE_REGISTER_NS(ScalarPoint2AS, TPoint, MSink); - END_MODULE_NAMESPACE - BEGIN_MODULE_NAMESPACE(MSolver) - MODULE_REGISTER_NS(RBPrecCG2AS, TRBPrecCG, MSolver); - END_MODULE_NAMESPACE - BEGIN_MODULE_NAMESPACE(MAction) - MODULE_REGISTER_NS(WilsonClover2AS, TWilsonClover, MAction); - END_MODULE_NAMESPACE - END_HADRONS_NAMESPACE - - -int main(int argc, char *argv[]) -{ - // initialization ////////////////////////////////////////////////////////// - Grid_init(&argc, &argv); - HadronsLogError.Active(GridLogError.isActive()); - HadronsLogWarning.Active(GridLogWarning.isActive()); - HadronsLogMessage.Active(GridLogMessage.isActive()); - HadronsLogIterative.Active(GridLogIterative.isActive()); - HadronsLogDebug.Active(GridLogDebug.isActive()); - LOG(Message) << "Grid initialized" << std::endl; - // run setup /////////////////////////////////////////////////////////////// - Application application; - std::vector flavour = {"l", "s"}; - std::vector mass = {-0.01, -0.04}; - double csw = 1.0; - // global parameters - Application::GlobalPar globalPar; - globalPar.trajCounter.start = 1500; - globalPar.trajCounter.end = 1520; - globalPar.trajCounter.step = 20; - globalPar.seed = "1 2 3 4"; - application.setPar(globalPar); - // gauge field - application.createModule("gauge"); - MSource::Point2AS::Par ptPar; - ptPar.position = "0 0 0 0"; - application.createModule("pt", ptPar); - // sink - MSink::ScalarPoint2AS::Par sinkPar; - sinkPar.mom = "0 0 0"; - application.createModule("sink", sinkPar); - - // set fermion boundary conditions to be periodic space, antiperiodic time. - std::string boundary = "1 1 1 -1"; - - for (unsigned int i = 0; i < flavour.size(); ++i) - { - // actions - MAction::WilsonClover2AS::Par actionPar; - actionPar.gauge = "gauge"; - actionPar.mass = mass[i]; - actionPar.csw_r = csw; - actionPar.csw_t = csw; - actionPar.clover_anisotropy.isAnisotropic= false; - actionPar.clover_anisotropy.t_direction = Nd-1 ; - actionPar.clover_anisotropy.xi_0 = 1.0 ; - actionPar.clover_anisotropy.nu = 1.0 ; - actionPar.boundary = boundary; - application.createModule("WilsonClover2AS_" + flavour[i], actionPar); - - // solvers - MSolver::RBPrecCG2AS::Par solverPar; - solverPar.action = "WilsonClover2AS_" + flavour[i]; - solverPar.residual = 1.0e-8; - solverPar.maxIteration = 10000; - application.createModule("CG_" + flavour[i], - solverPar); - - // propagators - MFermion::GaugeProp2AS::Par quarkPar; - quarkPar.solver = "CG_" + flavour[i]; - quarkPar.source = "pt"; - application.createModule("Qpt_" + flavour[i], quarkPar); - quarkPar.source = "z2"; - application.createModule("QZ2_" + flavour[i], quarkPar); - } - for (unsigned int i = 0; i < flavour.size(); ++i) - for (unsigned int j = i; j < flavour.size(); ++j) - { - MContraction::Meson2AS::Par mesPar; - - mesPar.output = "mesons2AS/pt_" + flavour[i] + flavour[j]; - mesPar.q1 = "Qpt_" + flavour[i]; - mesPar.q2 = "Qpt_" + flavour[j]; - mesPar.gammas = "all"; - mesPar.sink = "sink"; - application.createModule("meson_pt_" - + flavour[i] + flavour[j], - mesPar); - - // mesPar.output = "mesons2AS/Z2_" + flavour[i] + flavour[j]; - // mesPar.q1 = "QZ2_" + flavour[i]; - // mesPar.q2 = "QZ2_" + flavour[j]; - // mesPar.gammas = "all"; - // mesPar.sink = "sink"; - // application.createModule("meson_Z2_" - // + flavour[i] + flavour[j], - // mesPar); - } - for (unsigned int i = 0; i < flavour.size(); ++i) - for (unsigned int j = i; j < flavour.size(); ++j) - for (unsigned int k = j; k < flavour.size(); ++k) - { - MContraction::Baryon::Par barPar; - - barPar.output = "baryons/pt_" + flavour[i] + flavour[j] + flavour[k]; - barPar.q1 = "Qpt_" + flavour[i]; - barPar.q2 = "Qpt_" + flavour[j]; - barPar.q3 = "Qpt_" + flavour[k]; - application.createModule( - "baryon_pt_" + flavour[i] + flavour[j] + flavour[k], barPar); - } - - // execution - application.saveParameterFile("spectrum.xml"); - application.run(); - - // epilogue - LOG(Message) << "Grid is finalizing now" << std::endl; - Grid_finalize(); - - return EXIT_SUCCESS; -} diff --git a/tests/hadrons/Test_hadrons_meson_3pt.cc b/tests/hadrons/Test_hadrons_meson_3pt.cc index b12ef472..243ffebb 100644 --- a/tests/hadrons/Test_hadrons_meson_3pt.cc +++ b/tests/hadrons/Test_hadrons_meson_3pt.cc @@ -26,6 +26,7 @@ *******************************************************************************/ #include +#include using namespace Grid; using namespace Hadrons; diff --git a/tests/hadrons/Test_hadrons_quark.cc b/tests/hadrons/Test_hadrons_quark.cc index cf3d2590..64cbfd30 100644 --- a/tests/hadrons/Test_hadrons_quark.cc +++ b/tests/hadrons/Test_hadrons_quark.cc @@ -26,7 +26,6 @@ *******************************************************************************/ #include "Test_hadrons.hpp" -#include using namespace Grid; using namespace QCD; diff --git a/tests/hadrons/Test_hadrons_spectrum.cc b/tests/hadrons/Test_hadrons_spectrum.cc index 682dcc9b..f41bd5b4 100644 --- a/tests/hadrons/Test_hadrons_spectrum.cc +++ b/tests/hadrons/Test_hadrons_spectrum.cc @@ -26,6 +26,7 @@ *******************************************************************************/ #include +#include using namespace Grid; using namespace Hadrons; diff --git a/tests/hadrons/Test_hadrons_wilsonFund.cc b/tests/hadrons/Test_hadrons_wilsonFund.cc index 36e751b6..bad0f2d3 100644 --- a/tests/hadrons/Test_hadrons_wilsonFund.cc +++ b/tests/hadrons/Test_hadrons_wilsonFund.cc @@ -26,6 +26,7 @@ *******************************************************************************/ #include +#include using namespace Grid; using namespace Hadrons; diff --git a/tests/hmc/Test_hmc_ScalarActionNxN.cc b/tests/hmc/Test_hmc_ScalarActionNxN.cc index 9e40beac..33e52d82 100644 --- a/tests/hmc/Test_hmc_ScalarActionNxN.cc +++ b/tests/hmc/Test_hmc_ScalarActionNxN.cc @@ -34,6 +34,8 @@ class ScalarActionParameters : Serializable { double, lambda, double, g); + ScalarActionParameters() = default; + template ScalarActionParameters(Reader& Reader){ read(Reader, "ScalarAction", *this); @@ -124,10 +126,13 @@ int main(int argc, char **argv) { ScalarGrid.set_rb(new GridRedBlackCartesian(ScalarGrid.get_full())); TheHMC.Resources.AddGrid("scalar", ScalarGrid); std::cout << "Lattice size : " << GridDefaultLatt() << std::endl; + + ScalarActionParameters SPar(Reader); // Checkpointer definition CheckpointerParameters CPparams(Reader); - TheHMC.Resources.LoadBinaryCheckpointer(CPparams); + //TheHMC.Resources.LoadBinaryCheckpointer(CPparams); + TheHMC.Resources.LoadScidacCheckpointer(CPparams, SPar); RNGModuleParameters RNGpar(Reader); TheHMC.Resources.SetRNGSeeds(RNGpar); @@ -140,7 +145,6 @@ int main(int argc, char **argv) { // Collect actions, here use more encapsulation // Scalar action in adjoint representation - ScalarActionParameters SPar(Reader); ScalarAction Saction(SPar.mass_squared, SPar.lambda, SPar.g); // Collect actions diff --git a/tests/hmc/Test_hmc_WG_Production.cc b/tests/hmc/Test_hmc_WG_Production.cc index b99446d5..7f8d8124 100644 --- a/tests/hmc/Test_hmc_WG_Production.cc +++ b/tests/hmc/Test_hmc_WG_Production.cc @@ -33,6 +33,7 @@ namespace Grid{ GRID_SERIALIZABLE_CLASS_MEMBERS(ActionParameters, double, beta) + ActionParameters() = default; template ActionParameters(Reader& Reader){ @@ -68,11 +69,15 @@ int main(int argc, char **argv) { } Serialiser Reader(TheHMC.ParameterFile); - + // Read parameters from input file + ActionParameters WilsonPar(Reader); // Checkpointer definition CheckpointerParameters CPparams(Reader); - TheHMC.Resources.LoadNerscCheckpointer(CPparams); + //TheHMC.Resources.LoadNerscCheckpointer(CPparams); + + // Store metadata in the Scidac checkpointer + TheHMC.Resources.LoadScidacCheckpointer(CPparams, WilsonPar); RNGModuleParameters RNGpar(Reader); TheHMC.Resources.SetRNGSeeds(RNGpar); @@ -91,8 +96,6 @@ int main(int argc, char **argv) { // need wrappers of the fermionic classes // that have a complex construction // standard - ActionParameters WilsonPar(Reader); - //RealD beta = 6.4 ; WilsonGaugeActionR Waction(WilsonPar.beta); ActionLevel Level1(1); diff --git a/tests/lanczos/Test_compressed_lanczos.cc b/tests/lanczos/Test_compressed_lanczos.cc new file mode 100644 index 00000000..8bce82bb --- /dev/null +++ b/tests/lanczos/Test_compressed_lanczos.cc @@ -0,0 +1,253 @@ + /************************************************************************************* + + Grid physics library, www.github.com/paboyle/Grid + + Source file: ./tests/Test_dwf_compressed_lanczos_reorg.cc + + Copyright (C) 2017 + +Author: Leans heavily on Christoph Lehner's code +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 */ +/* + * Reimplement the badly named "multigrid" lanczos as compressed Lanczos using the features + * in Grid that were intended to be used to support blocked Aggregates, from + */ +#include +#include +#include + +using namespace std; +using namespace Grid; +using namespace Grid::QCD; + +template +class LocalCoherenceLanczosScidac : public LocalCoherenceLanczos +{ +public: + typedef iVector CoarseSiteVector; + typedef Lattice CoarseField; + typedef Lattice CoarseScalar; // used for inner products on fine field + typedef Lattice FineField; + + LocalCoherenceLanczosScidac(GridBase *FineGrid,GridBase *CoarseGrid, + LinearOperatorBase &FineOp, + int checkerboard) + // Base constructor + : LocalCoherenceLanczos(FineGrid,CoarseGrid,FineOp,checkerboard) + {}; + + void checkpointFine(std::string evecs_file,std::string evals_file) + { + assert(this->subspace.size()==nbasis); + emptyUserRecord record; + Grid::QCD::ScidacWriter WR(this->_FineGrid->IsBoss()); + WR.open(evecs_file); + for(int k=0;ksubspace[k],record); + } + WR.close(); + + XmlWriter WRx(evals_file); + write(WRx,"evals",this->evals_fine); + } + + void checkpointFineRestore(std::string evecs_file,std::string evals_file) + { + this->evals_fine.resize(nbasis); + this->subspace.resize(nbasis,this->_FineGrid); + + std::cout << GridLogIRL<< "checkpointFineRestore: Reading evals from "<evals_fine); + + assert(this->evals_fine.size()==nbasis); + + std::cout << GridLogIRL<< "checkpointFineRestore: Reading evecs from "<subspace[k].checkerboard=this->_checkerboard; + RD.readScidacFieldRecord(this->subspace[k],record); + + } + RD.close(); + } + + void checkpointCoarse(std::string evecs_file,std::string evals_file) + { + int n = this->evec_coarse.size(); + emptyUserRecord record; + Grid::QCD::ScidacWriter WR(this->_CoarseGrid->IsBoss()); + WR.open(evecs_file); + for(int k=0;kevec_coarse[k],record); + } + WR.close(); + + XmlWriter WRx(evals_file); + write(WRx,"evals",this->evals_coarse); + } + + void checkpointCoarseRestore(std::string evecs_file,std::string evals_file,int nvec) + { + std::cout << "resizing coarse vecs to " << nvec<< std::endl; + this->evals_coarse.resize(nvec); + this->evec_coarse.resize(nvec,this->_CoarseGrid); + std::cout << GridLogIRL<< "checkpointCoarseRestore: Reading evals from "<evals_coarse); + + assert(this->evals_coarse.size()==nvec); + emptyUserRecord record; + std::cout << GridLogIRL<< "checkpointCoarseRestore: Reading evecs from "<evec_coarse[k],record); + } + RD.close(); + } +}; + +int main (int argc, char ** argv) { + + Grid_init(&argc,&argv); + GridLogIRL.TimingMode(1); + + LocalCoherenceLanczosParams Params; + { + Params.omega.resize(10); + Params.blockSize.resize(5); + XmlWriter writer("Params_template.xml"); + write(writer,"Params",Params); + std::cout << GridLogMessage << " Written Params_template.xml" < blockSize = Params.blockSize; + + // Grids + GridCartesian * UGrid = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), + GridDefaultSimd(Nd,vComplex::Nsimd()), + GridDefaultMpi()); + GridRedBlackCartesian * UrbGrid = SpaceTimeGrid::makeFourDimRedBlackGrid(UGrid); + GridCartesian * FGrid = SpaceTimeGrid::makeFiveDimGrid(Ls,UGrid); + GridRedBlackCartesian * FrbGrid = SpaceTimeGrid::makeFiveDimRedBlackGrid(Ls,UGrid); + + std::vector fineLatt = GridDefaultLatt(); + int dims=fineLatt.size(); + assert(blockSize.size()==dims+1); + std::vector coarseLatt(dims); + std::vector coarseLatt5d ; + + for (int d=0;d HermOp(Ddwf); + + // Eigenvector storage + LanczosParams fine =Params.FineParams; + LanczosParams coarse=Params.CoarseParams; + + const int Ns1 = fine.Nstop; const int Ns2 = coarse.Nstop; + const int Nk1 = fine.Nk; const int Nk2 = coarse.Nk; + const int Nm1 = fine.Nm; const int Nm2 = coarse.Nm; + + std::cout << GridLogMessage << "Keep " << fine.Nstop << " fine vectors" << std::endl; + std::cout << GridLogMessage << "Keep " << coarse.Nstop << " coarse vectors" << std::endl; + assert(Nm2 >= Nm1); + + const int nbasis= 60; + assert(nbasis==Ns1); + LocalCoherenceLanczosScidac _LocalCoherenceLanczos(FrbGrid,CoarseGrid5,HermOp,Odd); + std::cout << GridLogMessage << "Constructed LocalCoherenceLanczos" << std::endl; + + assert( (Params.doFine)||(Params.doFineRead)); + + if ( Params.doFine ) { + std::cout << GridLogMessage << "Performing fine grid IRL Nstop "<< Ns1 << " Nk "<subspace.size()==nbasis); emptyUserRecord record; - Grid::QCD::ScidacWriter WR; + Grid::QCD::ScidacWriter WR(this->_FineGrid->IsBoss()); WR.open(evecs_file); for(int k=0;ksubspace[k],record); @@ -96,7 +96,7 @@ public: { int n = this->evec_coarse.size(); emptyUserRecord record; - Grid::QCD::ScidacWriter WR; + Grid::QCD::ScidacWriter WR(this->_CoarseGrid->IsBoss()); WR.open(evecs_file); for(int k=0;kevec_coarse[k],record); diff --git a/tests/solver/Test_dwf_mrhs_cg.cc b/tests/solver/Test_dwf_mrhs_cg.cc index 207e1331..72ba3d26 100644 --- a/tests/solver/Test_dwf_mrhs_cg.cc +++ b/tests/solver/Test_dwf_mrhs_cg.cc @@ -114,7 +114,7 @@ int main (int argc, char ** argv) { FGrid->Barrier(); - ScidacWriter _ScidacWriter; + ScidacWriter _ScidacWriter(FGrid->IsBoss()); _ScidacWriter.open(file); std::cout << GridLogMessage << "****************************************************************** "<IsBoss()); _ScidacWriter.open(filefn.str()); _ScidacWriter.writeScidacFieldRecord(src[n],record); _ScidacWriter.close();