├── LICENSE ├── include ├── estimator_gpu.cuh ├── dynamic_array_serialization.h ├── cmc.h ├── factory_potential.h ├── factory.h ├── communicator.h ├── common_gpu.h ├── wavefunction.h ├── worm.h ├── container.h ├── special_functions.cuh ├── special_functions.hip.h ├── pimc.h ├── lookuptable.h ├── action.h ├── path.h ├── constants.h ├── dynamic_array_math.h ├── common.h └── setup.h ├── tools └── conversion │ ├── CMakeLists.txt │ └── convert_serialized_graphene_data.cpp ├── features.md ├── src ├── worm.cpp ├── cmc.cpp ├── pdrive.cpp ├── constants.cpp └── communicator.cpp └── CMakeLists.txt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Adrian Del Maestro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /include/estimator_gpu.cuh: -------------------------------------------------------------------------------- 1 | #ifndef ESTIMATOR_GPU_CUH 2 | #define ESTIMATOR_GPU_CUH 3 | #include "common_gpu.h" 4 | #include "device_launch_parameters.h" 5 | 6 | void gpu_isf_launcher(double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, int M, int N, int N_extent); 7 | void gpu_isf_launcher(cudaStream_t s, double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, int M, int N, int N_extent); 8 | 9 | void gpu_ssf_launcher(double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, int M, int N, int N_extent, int n_qvecs); 10 | void gpu_ssf_launcher(cudaStream_t s, double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, int M, int N, int N_extent, int n_qvecs); 11 | 12 | void gpu_ssf_cyl_launcher(double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, double maxR, int M, int N, int N_extent, int n_qvecs); 13 | void gpu_ssf_cyl_launcher(cudaStream_t s, double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, double maxR, int M, int N, int N_extent, int n_qvecs); 14 | 15 | void gpu_es_launcher(double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, int M, int N, int N_extent); 16 | void gpu_es_launcher(cudaStream_t s, double* __restrict__ isf, double* __restrict__ qvecs, double* __restrict__ beads, double inorm, int M, int N, int N_extent); 17 | #endif 18 | -------------------------------------------------------------------------------- /tools/conversion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(ConversionTool) 3 | 4 | # Set the C++ standard 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Include directories 9 | include_directories(${PROJECT_SOURCE_DIR}/../../include) 10 | 11 | # Add the conversion tool executable. 12 | add_executable(convert_serialized_graphene_data convert_serialized_graphene_data.cpp) 13 | 14 | # Optionally, allow the user to set BLITZ_INCLUDE_DIR. 15 | if(NOT DEFINED BLITZ_INCLUDE_DIR) 16 | set(BLITZ_INCLUDE_DIR "/usr/include" CACHE PATH "Path to Blitz headers") 17 | endif() 18 | include_directories(${BLITZ_INCLUDE_DIR}) 19 | 20 | # Check if Blitz is available by compiling an inline source snippet. 21 | include(CheckCXXSourceCompiles) 22 | check_cxx_source_compiles( 23 | " 24 | #include 25 | int main() { 26 | blitz::Array arr(10); 27 | return 0; 28 | } 29 | " BLITZ_WORKS 30 | ) 31 | 32 | if(NOT BLITZ_WORKS) 33 | message(FATAL_ERROR "Could not compile test code including . " 34 | "Please check that Blitz is installed and BLITZ_INCLUDE_DIR is set correctly.") 35 | else() 36 | message(STATUS "Blitz headers found and working.") 37 | endif() 38 | 39 | # Find Boost 40 | find_package(Boost REQUIRED COMPONENTS serialization ) 41 | include_directories(${Boost_INCLUDE_DIRS}) 42 | target_link_libraries(convert_serialized_graphene_data ${Boost_LIBRARIES}) 43 | 44 | # Add the compiler definition for boost serialization. 45 | target_compile_definitions(convert_serialized_graphene_data PRIVATE BZ_HAVE_BOOST_SERIALIZATION) 46 | -------------------------------------------------------------------------------- /include/dynamic_array_serialization.h: -------------------------------------------------------------------------------- 1 | #ifndef DYNAMIC_ARRAY_SERIALIZATION_H 2 | #define DYNAMIC_ARRAY_SERIALIZATION_H 3 | 4 | #include "dynamic_array.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // Save the DynamicArray to a binary file. 12 | template 13 | void saveDynamicArray(const DynamicArray& arr, const std::string& filename) { 14 | std::ofstream ofs(filename, std::ios::binary); 15 | if (!ofs) 16 | throw std::runtime_error("Could not open file for writing: " + filename); 17 | 18 | // Write the extents (dimensions) 19 | auto extents = arr.extents(); 20 | ofs.write(reinterpret_cast(extents.data()), extents.size() * sizeof(std::size_t)); 21 | 22 | // Write the total number of elements. 23 | std::size_t total = arr.size(); 24 | ofs.write(reinterpret_cast(&total), sizeof(total)); 25 | 26 | // Write the raw data. 27 | ofs.write(reinterpret_cast(arr.data()), total * sizeof(T)); 28 | 29 | if (!ofs) 30 | throw std::runtime_error("Error occurred while writing data to " + filename); 31 | } 32 | 33 | // Load the DynamicArray from a binary file. 34 | template 35 | void loadDynamicArray(DynamicArray& arr, const std::string& filename) { 36 | std::ifstream ifs(filename, std::ios::binary); 37 | if (!ifs) 38 | throw std::runtime_error("Could not open file for reading: " + filename); 39 | 40 | // Read extents. 41 | std::array extents; 42 | ifs.read(reinterpret_cast(extents.data()), extents.size() * sizeof(std::size_t)); 43 | if (!ifs) 44 | throw std::runtime_error("Error reading extents from " + filename); 45 | 46 | // Resize the array to match the extents. 47 | std::apply([&](auto&&... args){ arr.resize(args...); }, extents); 48 | 49 | // Read total number of elements. 50 | std::size_t total; 51 | ifs.read(reinterpret_cast(&total), sizeof(total)); 52 | if (!ifs) 53 | throw std::runtime_error("Error reading total size from " + filename); 54 | 55 | if (total != arr.size()) 56 | throw std::runtime_error("Data size mismatch in file " + filename); 57 | 58 | // Read the raw data. 59 | ifs.read(reinterpret_cast(arr.data()), total * sizeof(T)); 60 | if (!ifs) 61 | throw std::runtime_error("Error reading data from " + filename); 62 | } 63 | 64 | #endif // DYNAMIC_ARRAY_SERIALIZATION_H 65 | 66 | -------------------------------------------------------------------------------- /include/cmc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmc.h 3 | * @author Adrian Del Maestro 4 | * @date 08.13.2012 5 | * 6 | * @brief ClassicalMonteCarlo class definition 7 | */ 8 | 9 | #ifndef CMC_H 10 | #define CMC_H 11 | 12 | #include "common.h" 13 | #include "communicator.h" 14 | #include "potential.h" 15 | 16 | // ======================================================================== 17 | // ClassicalMonteCarlo Class 18 | // ======================================================================== 19 | /** 20 | * Pre-equilibration via classical Monte Carlo. 21 | * 22 | * We perform a series of classical Monte Carlo updates with the hopes of 23 | * obtaining a good classical ground state from which to initiate our quantum 24 | * monte carlo from. 25 | */ 26 | class ClassicalMonteCarlo{ 27 | public: 28 | ClassicalMonteCarlo(PotentialBase *, PotentialBase *, MTRand &, const 29 | Container *, DynamicArray &); 30 | ~ClassicalMonteCarlo(); 31 | 32 | void run(uint32, bool); ///< Perform the Monte Carlo equilibration 33 | 34 | private: 35 | 36 | PotentialBase *externalPtr; // The external potential 37 | PotentialBase *interactionPtr; // The interaction potential 38 | MTRand &random; // A reference to the RNG 39 | const Container *boxPtr; // A constant reference to the container class 40 | DynamicArray &config; // The particle configurations 41 | 42 | double z; // The fugacity 43 | double energy; // The total potential energy 44 | double deltaV; // Change in potential energy 45 | dVec sep; // A particle separation 46 | 47 | 48 | int numParticles; // The current number of particles 49 | 50 | uint32 numMoveTotal; // Number of moves attempted 51 | uint32 numMoveAccept; // Number of moves accepted 52 | 53 | uint32 numInsertTotal; // Number of inserts attempted 54 | uint32 numInsertAccept; // Number of inserts accepted 55 | 56 | uint32 numDeleteTotal; // Number of deletes attempted 57 | uint32 numDeleteAccept; // Number of deletes accepted 58 | 59 | /* Measured quantities */ 60 | double aveEnergy; 61 | double aveNumParticles; 62 | double aveEoN; 63 | 64 | /* Move, create and destroy particles */ 65 | void moveParticle(); 66 | void insertParticle(); 67 | void deleteParticle(); 68 | 69 | /* Perform measurements */ 70 | void measure(int &); 71 | 72 | /* Compute the total potential energy */ 73 | double getTotalEnergy(); 74 | }; 75 | 76 | #endif 77 | 78 | -------------------------------------------------------------------------------- /include/factory_potential.h: -------------------------------------------------------------------------------- 1 | #ifndef FACTORY_POTENTIAL_H 2 | #define FACTORY_POTENTIAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "setup.h" 9 | 10 | class PotentialFactory { 11 | public: 12 | 13 | /* there are two types of potentials that we need to instantiate */ 14 | enum class Type { 15 | Interaction, 16 | External 17 | }; 18 | 19 | /* singleton access by value? */ 20 | static PotentialFactory& instance() { 21 | static PotentialFactory factory; 22 | return factory; 23 | } 24 | 25 | template 26 | void registerCreator(const std::string& name, std::function creator) { 27 | if constexpr (T == Type::Interaction) { 28 | creatorsInteraction[name] = creator; 29 | } else { 30 | creatorsExternal[name] = creator; 31 | } 32 | } 33 | 34 | template 35 | PotentialBase* create(const std::string& name) const { 36 | const auto& creators = (T == Type::Interaction) ? creatorsInteraction : creatorsExternal; 37 | auto it = creators.find(name); 38 | if (it != creators.end()) { 39 | return it->second(); 40 | } 41 | return nullptr; 42 | } 43 | 44 | template 45 | std::vector getNames() const { 46 | std::vector names; 47 | const auto& creators = (T == Type::Interaction) ? creatorsInteraction : creatorsExternal; 48 | for (const auto& pair : creators) { 49 | names.push_back(pair.first); 50 | } 51 | return names; 52 | } 53 | 54 | private: 55 | PotentialFactory() = default; 56 | std::map> creatorsInteraction; 57 | std::map> creatorsExternal; 58 | }; 59 | 60 | #define GET_SETUP() auto& setup = Setup::instance(); 61 | #define NO_SETUP() do {} while(0); 62 | 63 | #define REGISTER_POTENTIAL(NAME, TYPE, POTENTIAL_TYPE, WITH_PARAMS, ...) \ 64 | struct TYPE ## _ ## POTENTIAL_TYPE ## _Potential_Register { \ 65 | TYPE ## _ ## POTENTIAL_TYPE ## _Potential_Register() { \ 66 | PotentialFactory::instance().registerCreator(NAME, []() { \ 67 | WITH_PARAMS \ 68 | return new TYPE(__VA_ARGS__); \ 69 | }); \ 70 | } \ 71 | }; \ 72 | static TYPE ## _ ## POTENTIAL_TYPE ## _Potential_Register global_##TYPE##_##POTENTIAL_TYPE##_potential_register; 73 | 74 | #define REGISTER_INTERACTION_POTENTIAL(NAME, TYPE, WITH_PARAMS, ...) \ 75 | REGISTER_POTENTIAL(NAME, TYPE, Interaction, WITH_PARAMS, __VA_ARGS__) 76 | 77 | #define REGISTER_EXTERNAL_POTENTIAL(NAME, TYPE, WITH_PARAMS, ...) \ 78 | REGISTER_POTENTIAL(NAME, TYPE, External, WITH_PARAMS, __VA_ARGS__) 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /features.md: -------------------------------------------------------------------------------- 1 | PIMC Feature List 2 | ================= 3 | 4 | ### Local Permutation Cycle 5 | 6 | Update Constant Singleton to use Associative Containers 7 | ------------------------------------------------------- 8 | Goal: Clean up and re-factor the constants() singleton to use a map taking the 9 | parameter name. This is more consistent with the latest version of the code 10 | and should simplify extensions. 11 | 12 | ### Concerns 13 | * map lookups are O(log(n)) should we be concerned by this? 14 | * would extra freedom of insertion into map lead to bugs? 15 | 16 | DONE: Local Superfluid Density Estimators 17 | ----------------------------------------- 18 | 19 | ### Local Winding Number Estimator 20 | ### Local Area Estimator 21 | 22 | * Details provided in E. W. Draeger and D. M. Ceperley, Phys. Rev. Lett. 90, 065301 (2003). 23 | 24 | MOSTLY DONE: Re-Factoring of Communicator 25 | ----------------------------------------- 26 | 27 | Goal: Creation of a new class which contains all functionality needed for a 28 | input/ouptut file. Communicator could then just contain a map of filenames 29 | to file objects 30 | 31 | ### Requirements 32 | * Data 33 | * File pointer 34 | * File label (string) 35 | * State (open/close) 36 | * Methods 37 | * open/close 38 | * reset 39 | 40 | ### Reset 41 | 42 | Reset is used for those files that are not continually kept open but that we 43 | wish to write over. To be safe, we should write to a new temporary file, then 44 | rename after successful completion. 45 | 46 | ### Possible Issues 47 | * fixed file functionality has not been fully tested 48 | 49 | DONE: Generic Density Tensor Functionality 50 | ------------------------------------------ 51 | 52 | ### Outline 53 | 54 | We want a generic way to map a d-vec particle position to a bin in a 1d array that is independent of dimension or container type 55 | 56 | Define: 57 | * Discretization in each dimension: dx,dy,dz 58 | * Should we use a fixed number of bins? 59 | 60 | ### Prism 61 | * 1d: 62 | 63 | index = (r[0] + 0.5*side[0])/dr[0] 64 | size = L/dr 65 | 66 | * 2d: 67 | 68 | i[0] = (r[0] + 0.5*side[0])/dr[0] 69 | i[1] = (r[1] + 0.5*side[1])/dr[1] 70 | size = (Lx/dx)*(Ly/dy) 71 | index = i[0]*N[1] + i[1] 72 | 73 | * 3d: 74 | 75 | i[0] = (r[0] + 0.5*side[0])/dr[0] 76 | i[1] = (r[1] + 0.5*side[1])/dr[1] 77 | i[2] = (r[2] + 0.5*side[2])/dr[2] 78 | size = N[0]*N[1]*N[2] 79 | 80 | index = i[0]*N[1]*N[2] + i[1]*N[2] + i[2] 81 | 82 | dV = dx*dy*dz 83 | 84 | ### Cylinder: 85 | 86 | 3d: We will use cylindrical polar coordinates (r,theta,z) 87 | 88 | N[0] = R/dr 89 | N[1] = 2.0*pi/dtheta 90 | N[2] = side[2]/dz 91 | 92 | i[0] = (r[0]*r[0] + r[1]*r[1])/dr 93 | theta = atan2(r[1],r[0]) 94 | if theta < 0: theta += 2.0*pi 95 | i[1] = theta/dtheta 96 | i[2] = (r[2] + 0.5*side[2])/dr[2] 97 | 98 | index = i[0]*N[1]*N[2] + i[1]*N[2] + i[2] 99 | 100 | dV(r) = r*dr*dtheta*dz 101 | 102 | 103 | -------------------------------------------------------------------------------- /tools/conversion/convert_serialized_graphene_data.cpp: -------------------------------------------------------------------------------- 1 | // convert_blitz_to_dynamic.cpp 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "blitz/array.h" 11 | #include "dynamic_array.h" 12 | #include "dynamic_array_serialization.h" 13 | 14 | // Helper function to convert a blitz::Array to a DynamicArray. 15 | template 16 | DynamicArray convertBlitzToDynamic(const blitz::Array& blitzArray) { 17 | // Get the extents from blitz::Array. 18 | blitz::TinyVector shape = blitzArray.shape(); 19 | std::array extents; 20 | for (int i = 0; i < Rank; ++i) 21 | extents[i] = static_cast(shape(i)); 22 | 23 | // Create and resize the DynamicArray. 24 | DynamicArray dynArray; 25 | std::apply([&](auto&&... args){ dynArray.resize(args...); }, extents); 26 | 27 | // Copy the data (assuming blitz stores data contiguously). 28 | std::copy(blitzArray.data(), blitzArray.data() + dynArray.size(), dynArray.data()); 29 | return dynArray; 30 | } 31 | 32 | void printUsage(const std::string& progName) { 33 | std::cerr << "Usage: " << progName << " \n" 34 | << " Looks for a legacy archive file named _serialized.dat\n" 35 | << " and writes new DynamicArray archives as _serialized_V3d.dat, etc.\n"; 36 | } 37 | 38 | int main(int argc, char* argv[]) { 39 | if (argc < 2) { 40 | printUsage(argv[0]); 41 | return 1; 42 | } 43 | 44 | std::string filePrefix = argv[1]; 45 | std::string legacyFile = filePrefix + "_serialized.dat"; 46 | 47 | try { 48 | // Open the legacy archive file. 49 | std::ifstream ifs(legacyFile, std::ios::binary); 50 | if (!ifs) 51 | throw std::runtime_error("Failed to open legacy archive file: " + legacyFile); 52 | 53 | // Load legacy data using Boost.Archive. 54 | const auto aflags = boost::archive::no_header | boost::archive::no_tracking; 55 | boost::archive::binary_iarchive ia(ifs, aflags); 56 | 57 | blitz::Array V3d; 58 | blitz::Array gradV3d_x; 59 | blitz::Array gradV3d_y; 60 | blitz::Array gradV3d_z; 61 | blitz::Array grad2V3d; 62 | blitz::Array LUTinfo; 63 | ia >> V3d >> gradV3d_x >> gradV3d_y >> gradV3d_z >> grad2V3d >> LUTinfo; 64 | 65 | // Convert each blitz::Array to a DynamicArray. 66 | auto dynV3d = convertBlitzToDynamic(V3d); 67 | auto dynGradV3d_x = convertBlitzToDynamic(gradV3d_x); 68 | auto dynGradV3d_y = convertBlitzToDynamic(gradV3d_y); 69 | auto dynGradV3d_z = convertBlitzToDynamic(gradV3d_z); 70 | auto dynGrad2V3d = convertBlitzToDynamic(grad2V3d); 71 | auto dynLUTinfo = convertBlitzToDynamic(LUTinfo); 72 | 73 | // Save the new DynamicArrays using the new serialization functions. 74 | saveDynamicArray(dynV3d, filePrefix + "_serialized_V3d.dat"); 75 | saveDynamicArray(dynGradV3d_x, filePrefix + "_serialized_gradV3d_x.dat"); 76 | saveDynamicArray(dynGradV3d_y, filePrefix + "_serialized_gradV3d_y.dat"); 77 | saveDynamicArray(dynGradV3d_z, filePrefix + "_serialized_gradV3d_z.dat"); 78 | saveDynamicArray(dynGrad2V3d, filePrefix + "_serialized_grad2V3d.dat"); 79 | saveDynamicArray(dynLUTinfo, filePrefix + "_serialized_LUTinfo.dat"); 80 | 81 | std::cout << "Conversion completed successfully.\n"; 82 | } 83 | catch (const std::exception& ex) { 84 | std::cerr << "Conversion failed: " << ex.what() << "\n"; 85 | return 1; 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /include/factory.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file factory.h 3 | * @author Adrian Del Maestro 4 | * @date 06.13.2016 5 | * 6 | * @brief Factory class definitions. 7 | */ 8 | 9 | #ifndef FACTORY_H 10 | #define FACTORY_H 11 | 12 | /** 13 | * An abstract factory class which creates new object instances based on a std::string 14 | * descripter and constructor signature. 15 | * 16 | * We use the factory method design pattern 17 | * (http://en.wikipedia.org/wiki/Factory_(object-oriented_programming)) to 18 | * create a new instance of an estimator object. 19 | * 20 | * Design borrowed heavily from: 21 | * @see http://www.gamedev.net/page/resources/_/technical/general-programming/creating-a-generic-object-factory-r2097 22 | */ 23 | 24 | template class Factory; 25 | 26 | template 27 | class Factory 28 | { 29 | protected: 30 | /* The constructor signature (*) refers to a function pointer (the constructor) */ 31 | using CreateObjectFunc = BaseType (*)(ParamType...); 32 | 33 | public: 34 | 35 | /** The names of all objects instatiated by the factory */ 36 | std::vector getNames() const { 37 | std::vector names; 38 | for(auto const& createIter: _create) 39 | names.push_back(createIter.first); 40 | return names; 41 | } 42 | 43 | /** Singleton access */ 44 | Factory *getInstance() 45 | { 46 | static Factory fact; 47 | return &fact; 48 | 49 | } 50 | 51 | /** Overload () to return a singleton instance */ 52 | const Factory * operator() () const { return getInstance();} 53 | Factory * operator() () { return getInstance();} 54 | 55 | /** Return an instantiated object with a given name */ 56 | BaseType Create(std::string name, ParamType ...param) { 57 | typename std::map::const_iterator objItr = _create.find(name); 58 | if (objItr != _create.end()) { 59 | return (objItr->second)(param...); 60 | /* auto created = (objItr->second)(param...); */ 61 | /* created->name1 = name; */ 62 | /* return created; */ 63 | } 64 | return nullptr; 65 | } 66 | 67 | /** Register the derived type with a descriptive name in the std::map */ 68 | template 69 | bool Register(std::string name) 70 | { 71 | _create[name] = &createObj; 72 | return true; 73 | } 74 | 75 | protected: 76 | std::map _create; // The name->constructor std::map 77 | 78 | /* Create the new object */ 79 | template 80 | static BaseType createObj(ParamType ...param) 81 | { return new DerivedType(param...);} 82 | 83 | }; 84 | 85 | class EstimatorBase; 86 | class MoveBase; 87 | class ActionBase; 88 | class WaveFunctionBase; 89 | class Path; 90 | class MTRand; 91 | class LookupTable; 92 | 93 | /* Typedefs used for actually creating factories */ 94 | typedef Factory EstimatorFactory; 95 | typedef Factory MultiEstimatorFactory; 96 | typedef Factory MoveFactory; 97 | typedef Factory WaveFunctionFactory; 98 | 99 | /* template */ 100 | /* BaseType CreateObject(ParamType ...param) */ 101 | /* { */ 102 | /* return new DerivedType(param...); */ 103 | /* } */ 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /include/communicator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file communicator.h 3 | * @author Adrian Del Maestro 4 | * @date 03.25.2009 5 | * 6 | * @brief Class definitions for all file input/output 7 | */ 8 | 9 | #ifndef COMMUNICATOR_H 10 | #define COMMUNICATOR_H 11 | 12 | #include "common.h" 13 | #include "constants.h" 14 | #include 15 | #include 16 | 17 | 18 | // ======================================================================== 19 | // File Class 20 | // ======================================================================== 21 | /** 22 | * A basic input/output file class. 23 | * 24 | */ 25 | class File 26 | { 27 | public: 28 | 29 | File(std::string, std::string, std::string, std::string); 30 | File(std::string); 31 | ~File() {close();} 32 | 33 | /* Return the file stream */ 34 | std::fstream & stream() { 35 | return rwfile; 36 | } 37 | 38 | /* Open the primary file */ 39 | void open(std::ios_base::openmode); 40 | 41 | /* Reset and rename the primary file */ 42 | void reset(); 43 | void rename(); 44 | void prepare() {prepared_ = true;} 45 | bool prepared() {return prepared_;} 46 | 47 | /* Close the file if open */ 48 | void close(); 49 | 50 | bool exists() {return exists_;} ///< did the file exist before opening? 51 | 52 | protected: 53 | friend class Communicator; // Friends for I/O 54 | 55 | std::string name; // The File name 56 | std::string bakname; // The backup name 57 | 58 | bool exists_; // Does the file exist? Check on creation. 59 | bool prepared_; // Has the file already been prepared for writing? 60 | 61 | std::fstream rwfile; // The i/o file object 62 | 63 | /* An alternate open which takes a filename */ 64 | void open(std::ios_base::openmode, std::string); 65 | 66 | }; 67 | 68 | // ======================================================================== 69 | // Communicator Class 70 | // ======================================================================== 71 | /** 72 | * Performs input/output. 73 | * 74 | * Holds information on input and output files that will need to be accessed 75 | * throughout the simulation and allows their access via the singleton 76 | * design pattern. 77 | * @see http://en.wikipedia.org/wiki/Singleton_pattern 78 | */ 79 | class Communicator 80 | { 81 | public: 82 | static Communicator* getInstance(); 83 | 84 | /** Initialize the output files */ 85 | void init(double, bool, std::string, std::string); 86 | 87 | /** Get method returning file object */ 88 | File *file(std::string type) { 89 | if (!file_.count(type)) 90 | initFile(type); 91 | return &file_.at(type); 92 | } 93 | 94 | void updateNames(); 95 | 96 | protected: 97 | Communicator() {} 98 | Communicator(const Communicator&); ///< Copy constructor 99 | Communicator& operator= (const Communicator&); ///< Singleton equals 100 | 101 | private: 102 | std::ios_base::openmode mode; // The file i/o mode 103 | 104 | std::string ensemble; // The type of ensemble 105 | std::string dataName; // The labelling scheme of the output files 106 | std::string header; // A unique file header 107 | 108 | std::string initName; // A possible initial file name 109 | std::string fixedName; // A posible fixed file name 110 | std::string baseDir; // The output base directory 111 | 112 | double tau; // A local copy of the actual imaginary time step. 113 | 114 | boost::ptr_map file_; // The file map 115 | 116 | /* Initialize a input/output file */ 117 | void initFile(std::string); 118 | }; 119 | 120 | 121 | /**************************************************************************//** 122 | * Global public access to the communcator singleton. 123 | ******************************************************************************/ 124 | inline Communicator* communicate() { 125 | Communicator *temp = Communicator::getInstance(); 126 | return temp; 127 | } 128 | #endif 129 | 130 | -------------------------------------------------------------------------------- /include/common_gpu.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_GPU_H 2 | #define COMMON_GPU_H 3 | #include 4 | 5 | #define IS_POWER_OF_TWO(x) ((x != 0) && ((x & (x - 1)) == 0)) 6 | 7 | /* Determine if using GPU acceleration */ 8 | #ifdef USE_GPU 9 | #ifndef GPU_BLOCK_SIZE 10 | #define GPU_BLOCK_SIZE 256 ///< number of threads per block 11 | #endif 12 | 13 | #ifndef TILE_WIDTH 14 | #define TILE_WIDTH 32 ///< width of tiles for matmul 15 | #endif 16 | 17 | #if GPU_BLOCK_SIZE > 2048 18 | #error "GPU_BLOCK_SIZE > 2048 unsupported" 19 | #endif 20 | 21 | #if !IS_POWER_OF_TWO(GPU_BLOCK_SIZE) 22 | #error "GPU_BLOCK_SIZE must be a power of two" 23 | #endif 24 | 25 | #ifndef MAX_GPU_STREAMS 26 | #define MAX_GPU_STREAMS 1 ///< Max number of concurrent GPU streams 27 | #endif 28 | #ifdef USE_HIP 29 | #include "hip/hip_runtime.h" 30 | #define GPU_ASSERT(x) (assert((x)==hipSuccess)) 31 | typedef hipStream_t gpu_stream_t; 32 | #define gpu_stream_create(x) hipStreamCreate(&x) 33 | #define gpu_stream_destroy(x) hipStreamDestroy(x) 34 | #define gpu_malloc_device(T, x, y, z) hipMallocAsync(&x, sizeof(T)*y, z) 35 | #define gpu_memcpy_host_to_device(w, x, y, z) hipMemcpyAsync(w, x, y, hipMemcpyHostToDevice, z) 36 | #define gpu_memcpy_device_to_host(w, x, y, z) hipMemcpyAsync(w, x, y, hipMemcpyDeviceToHost, z) 37 | #define gpu_wait(x) hipStreamSynchronize(x) 38 | #define gpu_memset(w, x, y, z) hipMemsetAsync(w, x, y, z) 39 | #define gpu_free(x, y) hipFreeAsync(x, y) 40 | #ifdef USE_BLAS 41 | #include "hipblas.hpp" 42 | typedef hipHandle_t gpu_blas_handle_t; 43 | #define GPU_BLAS_ASSERT(x) (assert((x)==HIPBLAS_STATUS_SUCCESS)) 44 | #define gpu_create_blas_handle(x) hipblasCreate(&x) 45 | #define gpu_destroy_blas_handle(x) hipblasDestroy(x) 46 | #define gpu_set_stream(x, y) hipblasSetStream(x, y) 47 | #endif 48 | #endif 49 | #ifdef USE_CUDA 50 | #include 51 | #define GPU_ASSERT(x) (assert((x)==cudaSuccess)) 52 | typedef cudaStream_t gpu_stream_t; 53 | #define gpu_stream_create(x) cudaStreamCreate(&x) 54 | #define gpu_stream_destroy(x) cudaStreamDestroy(x) 55 | #define gpu_malloc_device(T, x, y, z) cudaMallocAsync(&x, sizeof(T)*y, z) 56 | #define gpu_memcpy_host_to_device(w, x, y, z) cudaMemcpyAsync(w, x, y, cudaMemcpyHostToDevice, z) 57 | #define gpu_memcpy_device_to_host(w, x, y, z) cudaMemcpyAsync(w, x, y, cudaMemcpyDeviceToHost, z) 58 | #define gpu_wait(x) cudaStreamSynchronize(x) 59 | #define gpu_memset(w, x, y, z) cudaMemsetAsync(w, x, y, z) 60 | #define gpu_free(x, y) cudaFreeAsync(x, y) 61 | #ifdef USE_BLAS 62 | #include "cublas_v2.h" 63 | typedef cublasHandle_t gpu_blas_handle_t; 64 | #define GPU_BLAS_ASSERT(x) (assert((x)==CUBLAS_STATUS_SUCCESS)) 65 | #define gpu_create_blas_handle(x) cublasCreate(&x) 66 | #define gpu_destroy_blas_handle(x) cublasDestroy(x) 67 | #define gpu_set_stream(x, y) cublasSetStream(x, y) 68 | #endif 69 | #endif 70 | #ifdef USE_SYCL 71 | #include 72 | #define GPU_ASSERT(x) x 73 | #ifndef SUB_GROUP_SIZE 74 | #define SUB_GROUP_SIZE 32 ///< number of threads per subgroup 75 | #endif 76 | #if !IS_POWER_OF_TWO(SUB_GROUP_SIZE) 77 | #error "SUB_GROUP_SIZE must be a power of two" 78 | #endif 79 | #if GPU_BLOCK_SIZE < 2*SUB_GROUP_SIZE 80 | #error "GPU_BLOCK_SIZE must be >= 2*SUB_GROUP_SIZE" 81 | #endif 82 | typedef sycl::queue gpu_stream_t; 83 | #define gpu_stream_create(x) x = sycl::queue() 84 | #define gpu_stream_destroy(x) do {} while(0) 85 | #define gpu_malloc_device(T, x, y, z) x = sycl::malloc_device< T >( y, z ) 86 | #define gpu_memcpy_host_to_device(w, x, y, z) z.memcpy(w, x, y) 87 | #define gpu_memcpy_device_to_host(w, x, y, z) z.memcpy(w, x, y) 88 | #define gpu_wait(x) x.wait() 89 | #define gpu_memset(w, x, y, z) z.memset(w, x, y) 90 | #define gpu_free(x, y) sycl::free(x, y) 91 | #ifdef USE_BLAS 92 | #include "onemath/mkl.hpp" 93 | typedef sycl::queue gpu_blas_handle_t; 94 | #define GPU_BLAS_ASSERT(x) x 95 | #define gpu_create_blas_handle(x) do {} while(0) 96 | #define gpu_destroy_blas_handle(x) do {} while(0) 97 | #define gpu_set_stream(x, y) x = y 98 | #endif 99 | #endif 100 | #endif 101 | #endif 102 | -------------------------------------------------------------------------------- /src/worm.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file worm.cpp 3 | * @author Adrian Del Maestro 4 | * @brief Worm class implementation. 5 | */ 6 | 7 | #include "worm.h" 8 | #include "path.h" 9 | 10 | // --------------------------------------------------------------------------- 11 | // --------------------------------------------------------------------------- 12 | // WORM CLASS ---------------------------------------------------------------- 13 | // --------------------------------------------------------------------------- 14 | // --------------------------------------------------------------------------- 15 | 16 | /**************************************************************************//** 17 | * Constructor. 18 | * 19 | * Initialize the worm object. 20 | * @param numParticles The number of particles 21 | ******************************************************************************/ 22 | Worm::Worm(int numParticles) { 23 | 24 | int numTimeSlices = constants()->numTimeSlices(); 25 | 26 | /* Setup the bead array */ 27 | beads.resize(numTimeSlices,numParticles); 28 | beads.fill(1u); 29 | 30 | /* Count the initial number of beads */ 31 | resetNumBeadsOn(); 32 | 33 | /* The initial configuration is always diagonal */ 34 | isConfigDiagonal = true; 35 | 36 | /* Max worm cost [PRE 74, 036701 (2006)] */ 37 | maxWormCost = 4.0; 38 | 39 | /* Initialize the properties of the worm */ 40 | reset(); 41 | } 42 | 43 | /**************************************************************************//** 44 | * Destructor. 45 | ******************************************************************************/ 46 | Worm::~Worm () { 47 | } 48 | 49 | /**************************************************************************//** 50 | * Reset the worm to a null state. 51 | ******************************************************************************/ 52 | void Worm::reset() { 53 | gap = XXX; 54 | length = 0; 55 | sep.fill(0.0); 56 | head.fill(XXX); 57 | tail.fill(XXX); 58 | special1.fill(XXX); 59 | special2.fill(XXX); 60 | } 61 | 62 | /**************************************************************************//** 63 | * We update all worm properties for a new head and tail. 64 | * 65 | * Given new head and tail positions, we assign them and compute the gap, 66 | * length and separation, while turning off all special flags. 67 | ******************************************************************************/ 68 | void Worm::update(Path &path, const beadLocator &newHead, 69 | const beadLocator &newTail) { 70 | 71 | /* Assign the new head and tail */ 72 | head = newHead; 73 | tail = newTail; 74 | 75 | /* Compute the new worm gap. This is defined to be the scalar separation 76 | * between the head and tail modulo the number of time slices*/ 77 | gap = tail[0] - head[0]; 78 | if (gap < 0) 79 | gap += path.numTimeSlices; 80 | PIMC_ASSERT(gap>=0); 81 | 82 | /* Get the new length */ 83 | beadLocator beadIndex; 84 | beadIndex = tail; 85 | length = 0; 86 | do { 87 | ++length; 88 | beadIndex = path.next(beadIndex); 89 | /* cout << head[0] << " " << head[1] << " " << tail[0] << " " << tail[1] << " " << beadIndex[0] << " " << beadIndex[1] << endl; */ 90 | } while (!all(beadIndex, head)); 91 | 92 | /* Now we update the head-tail separation */ 93 | sep = path.getSeparation(tail,head); 94 | 95 | /* Unlink the head and tail */ 96 | path.next(head).fill(XXX); 97 | path.prev(tail).fill(XXX); 98 | 99 | /* Turn off the special beads */ 100 | special1.fill(XXX); 101 | special2.fill(XXX); 102 | } 103 | 104 | /**************************************************************************//** 105 | * Compute the value of the potential action trajectory factor. 106 | * 107 | ******************************************************************************/ 108 | double Worm::factor(const beadState state1, const beadLocator &bead2) const { 109 | 110 | beadState state2 = getState(bead2); 111 | 112 | if ((state1 == NONE) && (state2 == NONE)) 113 | return 1.0; 114 | else if ((state1 == HEADTAIL) && (state2 == HEADTAIL)) 115 | return 0.0; 116 | else 117 | return 0.5; 118 | } 119 | 120 | /**************************************************************************//** 121 | * Test to see if a supplied bead is located on a worm. 122 | ******************************************************************************/ 123 | bool Worm::foundBead(const Path &path, const beadLocator &beadIndex) { 124 | if (isConfigDiagonal) 125 | return false; 126 | else { 127 | beadLocator beadID; 128 | beadID = tail; 129 | while ( (!all(beadID, beadIndex)) && (!all(beadID, path.next(head))) ) { 130 | beadID = path.next(beadID); 131 | } 132 | return all(beadID, beadIndex); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /include/wavefunction.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file wavefunction.h 3 | * @author Adrian Del Maestro 4 | * @date 04.09.2013 5 | * 6 | * @brief Action class definitions. 7 | */ 8 | 9 | /* #include "common.h" */ 10 | 11 | #include "constants.h" 12 | #include "lookuptable.h" 13 | 14 | #ifndef WAVEFUNCTION_H 15 | #define WAVEFUNCTION_H 16 | 17 | class Path; 18 | 19 | // ======================================================================== 20 | // WaveFunctionBase Class 21 | // ======================================================================== 22 | /** 23 | * Holds a base class that all trial wave function classes will be derived from. 24 | * 25 | * For a given set of worldlines, computes the real value of a trial 26 | * wavefunction. 27 | */ 28 | class WaveFunctionBase { 29 | 30 | public: 31 | WaveFunctionBase (const Path &,LookupTable &_lookup); 32 | virtual ~WaveFunctionBase(); 33 | 34 | /** The Constant Trial Wave Function*/ 35 | virtual double PsiTrial(const int) { return 1.0; }; 36 | virtual double PsiTrial(const double) { return 1.0; }; 37 | virtual double PsiTrial(const beadLocator &) { return 1.0; }; 38 | virtual double delPsiTrial(const double ) { return 0.0; }; 39 | virtual double delSqPsiTrial(const double ) { return 0.0; }; 40 | virtual double gradSqPsiTrial(const int) { return 0.0; }; 41 | 42 | protected: 43 | const Path &path; ///< A reference to the paths 44 | LookupTable &lookup; ///< We need a non-constant reference for updates 45 | 46 | }; 47 | 48 | // ======================================================================== 49 | // ConstantWaveFunction Class 50 | // ======================================================================== 51 | /** 52 | * Simple constant wavefunction (implements the base class). 53 | */ 54 | class ConstantWaveFunction: public WaveFunctionBase { 55 | public: 56 | ConstantWaveFunction(const Path &,LookupTable &_lookup); 57 | ~ConstantWaveFunction(); 58 | 59 | static const std::string name; 60 | std::string getName() const {return name;} 61 | }; 62 | 63 | 64 | // ======================================================================== 65 | // SechWaveFunction Class 66 | // ======================================================================== 67 | /** 68 | * Implementation of the Psi_T = sech(a*x) trial wave function suitable 69 | * for the simple harmonic osscilator. 70 | * @see A. Sarsa, K. E. Schmidt, and W. R. Magro, J. Chem. Phys. 113, 1366 (2000). 71 | */ 72 | class SechWaveFunction: public WaveFunctionBase { 73 | 74 | public: 75 | SechWaveFunction(const Path &,LookupTable &_lookup); 76 | ~SechWaveFunction(); 77 | 78 | static const std::string name; 79 | std::string getName() const {return name;} 80 | 81 | double PsiTrial (const int); 82 | 83 | private: 84 | double a; // The parameter of the wave function 85 | 86 | }; 87 | 88 | // ======================================================================== 89 | // JastrowWaveFunction Class 90 | // ======================================================================== 91 | /** 92 | * Implementation of a Jastrow trial wave function suitable for He 93 | * @see Cuervo, Roy, & Boninsegni,, J. Chem. Phys., 122(11), 114504 (2005). 94 | */ 95 | class JastrowWaveFunction: public WaveFunctionBase { 96 | 97 | public: 98 | JastrowWaveFunction(const Path &, LookupTable &_lookup); 99 | ~JastrowWaveFunction(); 100 | 101 | double PsiTrial (const double); 102 | double PsiTrial (const int); 103 | double delPsiTrial(const double r); 104 | double delSqPsiTrial(const double r); 105 | double gradSqPsiTrial(const int); 106 | 107 | double twoBodyPsiTrial (const double); 108 | 109 | static const std::string name; 110 | std::string getName() const {return name;} 111 | 112 | private: 113 | double alpha; // The parameter of the wave function 114 | double beta; // The parameter of the wave function 115 | 116 | }; 117 | 118 | // ======================================================================== 119 | // LiebLinigerWaveFunction Class 120 | // ======================================================================== 121 | /** 122 | * Implementation of a Jastrow trial wave function suitable for He 123 | * @see Cuervo, Roy, & Boninsegni,, J. Chem. Phys., 122(11), 114504 (2005). 124 | */ 125 | class LiebLinigerWaveFunction: public WaveFunctionBase { 126 | 127 | public: 128 | LiebLinigerWaveFunction(const Path &, LookupTable &_lookup); 129 | ~LiebLinigerWaveFunction(); 130 | 131 | double PsiTrial (const double); 132 | double PsiTrial (const beadLocator &bead1); 133 | double PsiTrial (const int); 134 | 135 | double delPsiTrial(const double r); 136 | double delSqPsiTrial(const double r); 137 | double gradSqPsiTrial(const int); 138 | 139 | static const std::string name; 140 | std::string getName() const {return name;} 141 | 142 | private: 143 | double R; // The parameter length scale of the wave function 144 | double k; // The wavevector of the wave function 145 | 146 | }; 147 | 148 | // ======================================================================== 149 | // SutherlandWaveFunction Class 150 | // ======================================================================== 151 | /** 152 | * Implementation of the Sutherland model exact wavefunction. 153 | * @see Eq. (4) in Astrakharchik, G., Gangardt, D., Lozovik, Y. and Sorokin, I. 154 | * Off-diagonal correlations of the Calogero-Sutherland model. Phys. Rev. E 74, 021105 (2006). 155 | */ 156 | class SutherlandWaveFunction: public WaveFunctionBase { 157 | 158 | public: 159 | SutherlandWaveFunction(const Path &, LookupTable &_lookup); 160 | ~SutherlandWaveFunction(); 161 | 162 | /** The 2-body trial wavefunction */ 163 | double PsiTrial(const double r) {return pow(2.0*sin(pioL*r),lambda);} 164 | double PsiTrial (const int); 165 | 166 | static const std::string name; 167 | std::string getName() const {return name;} 168 | 169 | private: 170 | double lambda; // Sutherland model \lambda 171 | double pioL; // pi / L 172 | }; 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /include/worm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file worm.h 3 | * @author Adrian Del Maestro 4 | * @date 12.08.2008 5 | * @brief Worm class definition. 6 | */ 7 | 8 | #ifndef WORM_H 9 | #define WORM_H 10 | 11 | #include "common.h" 12 | #include "constants.h" 13 | 14 | class Path; 15 | // ======================================================================== 16 | // Worm Class 17 | // ======================================================================== 18 | /** 19 | * Contains information on the worm. 20 | * In a grand-canonical or worm simulation, one world line may lose its 21 | * periodicity in imaginary time. This class holds all parameters and 22 | * methods used to describe worm configurations. 23 | */ 24 | 25 | class Worm { 26 | 27 | public: 28 | Worm(int); 29 | ~Worm(); 30 | 31 | beadLocator head; ///< The coordinates of the worm head 32 | beadLocator tail; ///< The coordinates of the worm tail 33 | beadLocator special1; ///< Special bead, used in move updates 34 | beadLocator special2; ///< Special bead, used in move updates 35 | double maxWormCost; ///< The maximum 'cost' of inserting a worm 36 | dVec sep; ///< The spatial separation between head and tail 37 | int length; ///< The length of the worm 38 | int gap; ///< numTimeSlices - length 39 | bool isConfigDiagonal; ///< Stores the diagonality of the configuration 40 | 41 | /* Safe get methods for beads */ 42 | inline int beadOn(int,int) const; 43 | inline int beadOn(const beadLocator&) const; 44 | 45 | /* Get the state of a bead */ 46 | beadState getState (const beadLocator &) const; 47 | 48 | /* The worm-trajectory factor for interactions and external potentials*/ 49 | double factor(const beadState, const beadLocator&) const; 50 | double factor(const beadState state1) const { return 1.0 - 0.5*(state1 != NONE);}; 51 | 52 | /* Safely add/delete beads */ 53 | inline void delBead(int,int); 54 | inline void addBead(int,int); 55 | inline void delBead(const beadLocator&); 56 | inline void addBead(const beadLocator&); 57 | 58 | /* Reset all worm parameters to null */ 59 | void reset(); 60 | 61 | /* Update all worm parameters */ 62 | void update(Path &, const beadLocator &, const beadLocator &); 63 | 64 | /* Determine if a given beadLocator is on a worm */ 65 | bool foundBead(const Path &, const beadLocator &); 66 | 67 | /** Return true if the worm is too costly */ 68 | inline bool tooCostly() { 69 | if (gap == 0) 70 | return true; 71 | else 72 | return ((dot(sep,sep) * constants()->fourLambdaTauInv() / (1.0*gap)) > maxWormCost); 73 | } 74 | /** Return true if the worm is too costly */ 75 | inline bool tooCostly(const dVec& _sep, int _gap) { 76 | if (_gap == 0) 77 | return true; 78 | else { 79 | return ((dot(_sep,_sep) * constants()->fourLambdaTauInv() / (1.0*_gap)) > maxWormCost); 80 | } 81 | } 82 | 83 | /** Return the bead list.*/ 84 | const DynamicArray & getBeads() const { return beads; } 85 | 86 | /* Test whether a given bead is on a worm */ 87 | /** Return the number of active beads. */ 88 | int getNumBeadsOn() const {return numBeadsOn;} 89 | /** Increment the number of active beads. */ 90 | void incNumBeadsOn() {++numBeadsOn;} 91 | /** Decrement the number of active beads. */ 92 | void decNumBeadsOn() {--numBeadsOn;} 93 | /** Reset the number of active beads. */ 94 | void resetNumBeadsOn() {numBeadsOn = std::accumulate(beads.begin(), beads.end(), 0.0);} 95 | 96 | friend class Path; // Path needs access to beads 97 | friend class PathIntegralMonteCarlo; // Friends for I/O 98 | 99 | private: 100 | DynamicArray beads; // Is a bead present? 101 | int numBeadsOn; // How many beads are present 102 | }; 103 | 104 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 105 | // INLINE FUNCTION DEFINITIONS 106 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 107 | 108 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 109 | /** Get the state of the supplied bead? */ 110 | inline beadState Worm::getState(const beadLocator &beadIndex) const { 111 | if (all(beadIndex, head) || all(beadIndex, tail)) 112 | return HEADTAIL; 113 | else if (all(beadIndex, special1) || all(beadIndex, special2)) 114 | return SPECIAL; 115 | else 116 | return NONE; 117 | } 118 | 119 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 120 | 121 | /** Safely delete a bead (int indexed) */ 122 | inline void Worm::delBead(int slice, int ptcl) { 123 | PIMC_ASSERT((slice >= 0) && (slice < constants()->numTimeSlices())); 124 | beads(slice,ptcl) = 0; 125 | } 126 | 127 | /** Safely delete a bead (beadLocator indexed) */ 128 | inline void Worm::delBead(const beadLocator &beadIndex) { 129 | PIMC_ASSERT((beadIndex[0] >= 0) && (beadIndex[0] < constants()->numTimeSlices())); 130 | beads(beadIndex) = 0; 131 | } 132 | 133 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 134 | /** Safely add a bead (int indexed) */ 135 | inline void Worm::addBead(int slice, int ptcl) { 136 | PIMC_ASSERT((slice >= 0) && (slice < constants()->numTimeSlices())); 137 | beads(slice,ptcl) = 1; 138 | } 139 | 140 | /** Safely add a bead (beadLocator indexed) */ 141 | inline void Worm::addBead(const beadLocator &beadIndex) { 142 | PIMC_ASSERT((beadIndex[0] >= 0) && (beadIndex[0] < constants()->numTimeSlices())); 143 | beads(beadIndex) = 1; 144 | } 145 | 146 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 147 | /** Safely get a bead (int indexed) */ 148 | inline int Worm::beadOn(int slice, int ptcl) const { 149 | PIMC_ASSERT((slice >=0) && (slice < constants()->numTimeSlices())); 150 | return beads(slice,ptcl); 151 | } 152 | 153 | /** Safely get a bead (beadLocator indexed) */ 154 | inline int Worm::beadOn(const beadLocator &beadIndex) const { 155 | return beads(beadIndex); 156 | } 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /include/container.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file container.h 3 | * @author Adrian Del Maestro 4 | * @date 11.24.2008 5 | * 6 | * @brief The simulation cell. 7 | */ 8 | 9 | #ifndef CONTAINER_H 10 | #define CONTAINER_H 11 | 12 | #include "common.h" 13 | 14 | // ======================================================================== 15 | // Container Class 16 | // ======================================================================== 17 | /** 18 | * The base class which holds details on the generalized box that our 19 | * system will be simulated inside of. 20 | * 21 | * This class implements boundary conditions, and holds details on the 22 | * physical dimensions of the simulation cell. 23 | */ 24 | class Container { 25 | public: 26 | Container(); 27 | virtual ~Container(); 28 | 29 | std::array periodic; ///< Determines which dimensions have periodic bc 30 | 31 | dVec side; ///< The linear dimensions of the box 32 | dVec sideInv; ///< The inverse box dimensions 33 | dVec sideInv2; ///< 2 times the inverse box dimensions 34 | 35 | double volume; ///< The volume of the container in A^3 36 | double rcut2; ///< The smallest separation squared 37 | double maxSep; ///< The maximum possible separation for 2 beads on the same timeslice 38 | 39 | std::string name; ///< The name of the container 40 | 41 | int numGrid; ///< The number of grid boxes for the position grid 42 | bool fullyPeriodic; ///< Is the prism fully periodic? 43 | 44 | dVec gridSize; ///< The grid size in each dimension 45 | 46 | /** Place a std::vector in boundary conditions. */ 47 | /** Algorithm C4 from 48 | * @see: Z. Phys. Chem. 227 (2013) 345–352 49 | */ 50 | void putInBC(dVec & r) const { 51 | for (std::size_t i = 0; i < NDIM; ++i) { 52 | r[i] -= pSide[i] * std::floor(r[i] * sideInv[i] + 0.5); 53 | } 54 | /* int k; */ 55 | /* for (int i = 0; i < NDIM; ++i) { */ 56 | /* k = int(r[i]*sideInv[i] + ((r[i]>=0.0)?0.5:-0.5)); */ 57 | /* r[i] -= k*pSide[i]; */ 58 | /* } */ 59 | } 60 | 61 | /* An old version */ 62 | /* void putInBC1(dVec & r) const { */ 63 | /* for (int i = 0; i < NDIM; ++i) { */ 64 | /* r[i] -= (r[i] >= 0.5*side[i])*pSide[i]; */ 65 | /* r[i] += (r[i] < -0.5*side[i])*pSide[i]; */ 66 | /* } */ 67 | /* } */ 68 | 69 | /* Place a std::vector in boundary conditions. */ 70 | void putInBC1(dVec & r) const { 71 | for (int i = 0; i < NDIM; ++i) { 72 | while (r[i] >= 0.5*side[i] && periodic[i]) 73 | r[i] -= pSide[i]; 74 | while (r[i] < -0.5*side[i] && periodic[i]) 75 | r[i] += pSide[i]; 76 | } 77 | } 78 | 79 | /** Place a std::vector inside the simulation cell */ 80 | virtual void putInside(dVec &) const = 0; 81 | 82 | /** Random position inside a box. */ 83 | virtual dVec randPosition(MTRand &) const = 0; 84 | 85 | /** Random updated position inside a box. */ 86 | virtual dVec randUpdate(MTRand &, const dVec &) const = 0; 87 | 88 | /** Map a position into a grid index */ 89 | virtual int gridIndex(const dVec &) const = 0; 90 | 91 | /** The physical size of a NDIM-dimensional grid box */ 92 | virtual double gridBoxVolume(const int) const = 0; 93 | 94 | #if NDIM > 1 95 | /** The radius of a grid box */ 96 | double gridRadius2(const int) const; 97 | #endif 98 | 99 | 100 | protected: 101 | dVec pSide; ///< Periodic * side 102 | }; 103 | 104 | // ======================================================================== 105 | // Prism Class 106 | // ======================================================================== 107 | /** 108 | * A NDIM-dimensional hyperprism with periodic boundary conditions. 109 | */ 110 | class Prism: public Container { 111 | public: 112 | inline static constexpr std::array defaultPeriodic = make_array(1u); 113 | Prism(const double, const int); 114 | Prism(const dVec &, const std::array &_periodic=defaultPeriodic); 115 | ~Prism(); 116 | 117 | /** For PBC, this is identical to putInBC */ 118 | void putInside(dVec &r) const { 119 | putInBC(r); 120 | 121 | /* This is slow! Try function pointers? Or create a separate hard 122 | * top box? */ 123 | if (!fullyPeriodic) { 124 | for (int i = 0; i < NDIM; i++) { 125 | if (!periodic[i]) { 126 | if (r[i] >= 0.5*side[i]) 127 | r[i] = 0.5*side[i] - 2*EPS; 128 | if (r[i] < -0.5*side[i]) 129 | r[i] = -0.5*side[i] + 2*EPS; 130 | } 131 | } 132 | } 133 | } 134 | 135 | dVec randPosition(MTRand &) const; 136 | dVec randUpdate(MTRand &, const dVec &) const; 137 | int gridIndex(const dVec &) const; 138 | double gridBoxVolume(const int) const; 139 | }; 140 | 141 | // ======================================================================== 142 | // Cylinder Class 143 | // ======================================================================== 144 | /** 145 | * A three dimensional cylinder with fixed boundary conditions in the 146 | * x and y directions and periodic boundary conditions in the z direction. 147 | */ 148 | class Cylinder: public Container { 149 | public: 150 | Cylinder(const double, const double, const int); 151 | Cylinder(const double, const double); 152 | ~Cylinder(); 153 | 154 | /* Place a std::vector inside the cylinder */ 155 | void putInside(dVec &r) const; 156 | 157 | /* The various types of random positions inside the cylinder */ 158 | dVec randPosition(MTRand &) const; 159 | dVec randUpdate(MTRand &, const dVec &) const; 160 | 161 | dVec randUpdateJumpShell(MTRand &, const dVec &) const; 162 | dVec randUpdateSmall(MTRand &, const dVec &) const; 163 | 164 | int gridIndex(const dVec &) const; 165 | double gridBoxVolume(const int) const; 166 | }; 167 | #endif 168 | -------------------------------------------------------------------------------- /include/special_functions.cuh: -------------------------------------------------------------------------------- 1 | // Some of these functions are adapted from the Cephes and specfun libraries: 2 | // http://www.netlib.org/cephes/ 3 | // http://www.netlib.org/specfun/ 4 | 5 | #include 6 | #include 7 | 8 | #if !defined(SPECIAL_FUNCTIONS_CUH) 9 | #define SPECIAL_FUNCTIONS_CUH 10 | 11 | #define PI 3.14159265358979323846 // pi 12 | #define PIO2 1.57079632679489661923 // pi/2 13 | #define EUL 0.577215664901532860606512090082402 // Euler's constant 14 | 15 | /* Polynomial evaluation. */ 16 | 17 | __device__ double polevl(double x, double *coef, int N) { 18 | double ans; 19 | double *p; 20 | int i; 21 | 22 | p = coef; 23 | ans = *p++; 24 | i = N; 25 | 26 | do 27 | ans = ans*x + *p++; 28 | while (--i); 29 | 30 | return (ans); 31 | } 32 | 33 | __device__ double p1evl(double x, double *coef, int N) { 34 | double ans; 35 | double *p; 36 | int i; 37 | 38 | p = coef; 39 | ans = x + *p++; 40 | i = N-1; 41 | 42 | do 43 | ans = ans*x + *p++; 44 | while (--i); 45 | 46 | return (ans); 47 | } 48 | 49 | /* Constants used to compute the sine/cosine integrals. */ 50 | 51 | __constant__ double SN[] = { 52 | -8.39167827910303881427E-11, 53 | 4.62591714427012837309E-8, 54 | -9.75759303843632795789E-6, 55 | 9.76945438170435310816E-4, 56 | -4.13470316229406538752E-2, 57 | 1.00000000000000000302E0, 58 | }; 59 | __constant__ double SD[] = { 60 | 2.03269266195951942049E-12, 61 | 1.27997891179943299903E-9, 62 | 4.41827842801218905784E-7, 63 | 9.96412122043875552487E-5, 64 | 1.42085239326149893930E-2, 65 | 9.99999999999999996984E-1, 66 | }; 67 | __constant__ double CN[] = { 68 | 2.02524002389102268789E-11, 69 | -1.35249504915790756375E-8, 70 | 3.59325051419993077021E-6, 71 | -4.74007206873407909465E-4, 72 | 2.89159652607555242092E-2, 73 | -1.00000000000000000080E0, 74 | }; 75 | __constant__ double CD[] = { 76 | 4.07746040061880559506E-12, 77 | 3.06780997581887812692E-9, 78 | 1.23210355685883423679E-6, 79 | 3.17442024775032769882E-4, 80 | 5.10028056236446052392E-2, 81 | 4.00000000000000000080E0, 82 | }; 83 | __constant__ double FN4[] = { 84 | 4.23612862892216586994E0, 85 | 5.45937717161812843388E0, 86 | 1.62083287701538329132E0, 87 | 1.67006611831323023771E-1, 88 | 6.81020132472518137426E-3, 89 | 1.08936580650328664411E-4, 90 | 5.48900223421373614008E-7, 91 | }; 92 | __constant__ double FD4[] = { 93 | /* 1.00000000000000000000E0,*/ 94 | 8.16496634205391016773E0, 95 | 7.30828822505564552187E0, 96 | 1.86792257950184183883E0, 97 | 1.78792052963149907262E-1, 98 | 7.01710668322789753610E-3, 99 | 1.10034357153915731354E-4, 100 | 5.48900252756255700982E-7, 101 | }; 102 | __constant__ double FN8[] = { 103 | 4.55880873470465315206E-1, 104 | 7.13715274100146711374E-1, 105 | 1.60300158222319456320E-1, 106 | 1.16064229408124407915E-2, 107 | 3.49556442447859055605E-4, 108 | 4.86215430826454749482E-6, 109 | 3.20092790091004902806E-8, 110 | 9.41779576128512936592E-11, 111 | 9.70507110881952024631E-14, 112 | }; 113 | __constant__ double FD8[] = { 114 | /* 1.00000000000000000000E0,*/ 115 | 9.17463611873684053703E-1, 116 | 1.78685545332074536321E-1, 117 | 1.22253594771971293032E-2, 118 | 3.58696481881851580297E-4, 119 | 4.92435064317881464393E-6, 120 | 3.21956939101046018377E-8, 121 | 9.43720590350276732376E-11, 122 | 9.70507110881952025725E-14, 123 | }; 124 | __constant__ double GN4[] = { 125 | 8.71001698973114191777E-2, 126 | 6.11379109952219284151E-1, 127 | 3.97180296392337498885E-1, 128 | 7.48527737628469092119E-2, 129 | 5.38868681462177273157E-3, 130 | 1.61999794598934024525E-4, 131 | 1.97963874140963632189E-6, 132 | 7.82579040744090311069E-9, 133 | }; 134 | __constant__ double GD4[] = { 135 | /* 1.00000000000000000000E0,*/ 136 | 1.64402202413355338886E0, 137 | 6.66296701268987968381E-1, 138 | 9.88771761277688796203E-2, 139 | 6.22396345441768420760E-3, 140 | 1.73221081474177119497E-4, 141 | 2.02659182086343991969E-6, 142 | 7.82579218933534490868E-9, 143 | }; 144 | __constant__ double GN8[] = { 145 | 6.97359953443276214934E-1, 146 | 3.30410979305632063225E-1, 147 | 3.84878767649974295920E-2, 148 | 1.71718239052347903558E-3, 149 | 3.48941165502279436777E-5, 150 | 3.47131167084116673800E-7, 151 | 1.70404452782044526189E-9, 152 | 3.85945925430276600453E-12, 153 | 3.14040098946363334640E-15, 154 | }; 155 | __constant__ double GD8[] = { 156 | /* 1.00000000000000000000E0,*/ 157 | 1.68548898811011640017E0, 158 | 4.87852258695304967486E-1, 159 | 4.67913194259625806320E-2, 160 | 1.90284426674399523638E-3, 161 | 3.68475504442561108162E-5, 162 | 3.57043223443740838771E-7, 163 | 1.72693748966316146736E-9, 164 | 3.87830166023954706752E-12, 165 | 3.14040098946363335242E-15, 166 | }; 167 | 168 | /* Sine/cosine integrals. */ 169 | 170 | __device__ void sici(double x, double *si, double *ci) { 171 | double z, c, s, f, g; 172 | short sign; 173 | 174 | if (x < 0.0) { 175 | sign = -1; 176 | x = -x; 177 | } else 178 | sign = 0; 179 | 180 | if (x == 0.0) { 181 | *si = 0; 182 | *ci = -DBL_MAX; 183 | return; 184 | } 185 | 186 | if (x > 1.0e9) { 187 | *si = PIO2 - cos(x)/x; 188 | *ci = sin(x)/x; 189 | } 190 | 191 | if (x > 4.0) 192 | goto asympt; 193 | 194 | z = x*x; 195 | s = x*polevl(z, SN, 5)/polevl(z, SD, 5); 196 | c = z*polevl(z, CN, 5)/polevl(z, CD, 5); 197 | 198 | if (sign) 199 | s = -s; 200 | 201 | *si = s; 202 | *ci = EUL + log(x) + c; 203 | return; 204 | 205 | asympt: 206 | s = sin(x); 207 | c = cos(x); 208 | z = 1.0/(x*x); 209 | 210 | if (x < 8.0) { 211 | f = polevl(z, FN4, 6)/(x*p1evl(z, FD4, 7)); 212 | g = z*polevl(z, GN4, 7)/p1evl(z, GD4, 7); 213 | } else { 214 | f = polevl(z, FN8, 8)/(x*p1evl(z, FD8, 8)); 215 | g = z*polevl(z, GN8, 8)/p1evl(z, GD8, 9); 216 | } 217 | *si = PIO2 - f*c - g*s; 218 | if (sign) 219 | *si = -(*si); 220 | *ci = f*s - g*c; 221 | return; 222 | } 223 | 224 | __device__ void si(double x, double *si) { 225 | double z, c, s, f, g; 226 | short sign; 227 | 228 | if (x < 0.0) { 229 | sign = -1; 230 | x = -x; 231 | } else 232 | sign = 0; 233 | 234 | if (x == 0.0) { 235 | *si = 0; 236 | return; 237 | } 238 | 239 | if (x > 1.0e9) { 240 | *si = PIO2 - cos(x)/x; 241 | } 242 | 243 | if (x > 4.0) 244 | goto asympt; 245 | 246 | z = x*x; 247 | s = x*polevl(z, SN, 5)/polevl(z, SD, 5); 248 | 249 | if (sign) 250 | s = -s; 251 | 252 | *si = s; 253 | return; 254 | 255 | asympt: 256 | s = sin(x); 257 | c = cos(x); 258 | z = 1.0/(x*x); 259 | 260 | if (x < 8.0) { 261 | f = polevl(z, FN4, 6)/(x*p1evl(z, FD4, 7)); 262 | g = z*polevl(z, GN4, 7)/p1evl(z, GD4, 7); 263 | } else { 264 | f = polevl(z, FN8, 8)/(x*p1evl(z, FD8, 8)); 265 | g = z*polevl(z, GN8, 8)/p1evl(z, GD8, 9); 266 | } 267 | *si = PIO2 - f*c - g*s; 268 | if (sign) 269 | *si = -(*si); 270 | return; 271 | } 272 | 273 | #endif /* !defined(SPECIAL_FUNCTIONS_CUH) */ 274 | -------------------------------------------------------------------------------- /include/special_functions.hip.h: -------------------------------------------------------------------------------- 1 | // Some of these functions are adapted from the Cephes and specfun libraries: 2 | // http://www.netlib.org/cephes/ 3 | // http://www.netlib.org/specfun/ 4 | 5 | #include 6 | #include 7 | 8 | #if !defined(SPECIAL_FUNCTIONS_HIP_H) 9 | #define SPECIAL_FUNCTIONS_HIP_H 10 | 11 | #define PI 3.14159265358979323846 // pi 12 | #define PIO2 1.57079632679489661923 // pi/2 13 | #define EUL 0.577215664901532860606512090082402 // Euler's constant 14 | 15 | /* Polynomial evaluation. */ 16 | 17 | __device__ double polevl(double x, double *coef, int N) { 18 | double ans; 19 | double *p; 20 | int i; 21 | 22 | p = coef; 23 | ans = *p++; 24 | i = N; 25 | 26 | do 27 | ans = ans*x + *p++; 28 | while (--i); 29 | 30 | return (ans); 31 | } 32 | 33 | __device__ double p1evl(double x, double *coef, int N) { 34 | double ans; 35 | double *p; 36 | int i; 37 | 38 | p = coef; 39 | ans = x + *p++; 40 | i = N-1; 41 | 42 | do 43 | ans = ans*x + *p++; 44 | while (--i); 45 | 46 | return (ans); 47 | } 48 | 49 | /* Constants used to compute the sine/cosine integrals. */ 50 | 51 | __constant__ double SN[] = { 52 | -8.39167827910303881427E-11, 53 | 4.62591714427012837309E-8, 54 | -9.75759303843632795789E-6, 55 | 9.76945438170435310816E-4, 56 | -4.13470316229406538752E-2, 57 | 1.00000000000000000302E0, 58 | }; 59 | __constant__ double SD[] = { 60 | 2.03269266195951942049E-12, 61 | 1.27997891179943299903E-9, 62 | 4.41827842801218905784E-7, 63 | 9.96412122043875552487E-5, 64 | 1.42085239326149893930E-2, 65 | 9.99999999999999996984E-1, 66 | }; 67 | __constant__ double CN[] = { 68 | 2.02524002389102268789E-11, 69 | -1.35249504915790756375E-8, 70 | 3.59325051419993077021E-6, 71 | -4.74007206873407909465E-4, 72 | 2.89159652607555242092E-2, 73 | -1.00000000000000000080E0, 74 | }; 75 | __constant__ double CD[] = { 76 | 4.07746040061880559506E-12, 77 | 3.06780997581887812692E-9, 78 | 1.23210355685883423679E-6, 79 | 3.17442024775032769882E-4, 80 | 5.10028056236446052392E-2, 81 | 4.00000000000000000080E0, 82 | }; 83 | __constant__ double FN4[] = { 84 | 4.23612862892216586994E0, 85 | 5.45937717161812843388E0, 86 | 1.62083287701538329132E0, 87 | 1.67006611831323023771E-1, 88 | 6.81020132472518137426E-3, 89 | 1.08936580650328664411E-4, 90 | 5.48900223421373614008E-7, 91 | }; 92 | __constant__ double FD4[] = { 93 | /* 1.00000000000000000000E0,*/ 94 | 8.16496634205391016773E0, 95 | 7.30828822505564552187E0, 96 | 1.86792257950184183883E0, 97 | 1.78792052963149907262E-1, 98 | 7.01710668322789753610E-3, 99 | 1.10034357153915731354E-4, 100 | 5.48900252756255700982E-7, 101 | }; 102 | __constant__ double FN8[] = { 103 | 4.55880873470465315206E-1, 104 | 7.13715274100146711374E-1, 105 | 1.60300158222319456320E-1, 106 | 1.16064229408124407915E-2, 107 | 3.49556442447859055605E-4, 108 | 4.86215430826454749482E-6, 109 | 3.20092790091004902806E-8, 110 | 9.41779576128512936592E-11, 111 | 9.70507110881952024631E-14, 112 | }; 113 | __constant__ double FD8[] = { 114 | /* 1.00000000000000000000E0,*/ 115 | 9.17463611873684053703E-1, 116 | 1.78685545332074536321E-1, 117 | 1.22253594771971293032E-2, 118 | 3.58696481881851580297E-4, 119 | 4.92435064317881464393E-6, 120 | 3.21956939101046018377E-8, 121 | 9.43720590350276732376E-11, 122 | 9.70507110881952025725E-14, 123 | }; 124 | __constant__ double GN4[] = { 125 | 8.71001698973114191777E-2, 126 | 6.11379109952219284151E-1, 127 | 3.97180296392337498885E-1, 128 | 7.48527737628469092119E-2, 129 | 5.38868681462177273157E-3, 130 | 1.61999794598934024525E-4, 131 | 1.97963874140963632189E-6, 132 | 7.82579040744090311069E-9, 133 | }; 134 | __constant__ double GD4[] = { 135 | /* 1.00000000000000000000E0,*/ 136 | 1.64402202413355338886E0, 137 | 6.66296701268987968381E-1, 138 | 9.88771761277688796203E-2, 139 | 6.22396345441768420760E-3, 140 | 1.73221081474177119497E-4, 141 | 2.02659182086343991969E-6, 142 | 7.82579218933534490868E-9, 143 | }; 144 | __constant__ double GN8[] = { 145 | 6.97359953443276214934E-1, 146 | 3.30410979305632063225E-1, 147 | 3.84878767649974295920E-2, 148 | 1.71718239052347903558E-3, 149 | 3.48941165502279436777E-5, 150 | 3.47131167084116673800E-7, 151 | 1.70404452782044526189E-9, 152 | 3.85945925430276600453E-12, 153 | 3.14040098946363334640E-15, 154 | }; 155 | __constant__ double GD8[] = { 156 | /* 1.00000000000000000000E0,*/ 157 | 1.68548898811011640017E0, 158 | 4.87852258695304967486E-1, 159 | 4.67913194259625806320E-2, 160 | 1.90284426674399523638E-3, 161 | 3.68475504442561108162E-5, 162 | 3.57043223443740838771E-7, 163 | 1.72693748966316146736E-9, 164 | 3.87830166023954706752E-12, 165 | 3.14040098946363335242E-15, 166 | }; 167 | 168 | /* Sine/cosine integrals. */ 169 | 170 | __device__ void sici(double x, double *si, double *ci) { 171 | double z, c, s, f, g; 172 | short sign; 173 | 174 | if (x < 0.0) { 175 | sign = -1; 176 | x = -x; 177 | } else 178 | sign = 0; 179 | 180 | if (x == 0.0) { 181 | *si = 0; 182 | *ci = -DBL_MAX; 183 | return; 184 | } 185 | 186 | if (x > 1.0e9) { 187 | *si = PIO2 - cos(x)/x; 188 | *ci = sin(x)/x; 189 | } 190 | 191 | if (x > 4.0) 192 | goto asympt; 193 | 194 | z = x*x; 195 | s = x*polevl(z, SN, 5)/polevl(z, SD, 5); 196 | c = z*polevl(z, CN, 5)/polevl(z, CD, 5); 197 | 198 | if (sign) 199 | s = -s; 200 | 201 | *si = s; 202 | *ci = EUL + log(x) + c; 203 | return; 204 | 205 | asympt: 206 | s = sin(x); 207 | c = cos(x); 208 | z = 1.0/(x*x); 209 | 210 | if (x < 8.0) { 211 | f = polevl(z, FN4, 6)/(x*p1evl(z, FD4, 7)); 212 | g = z*polevl(z, GN4, 7)/p1evl(z, GD4, 7); 213 | } else { 214 | f = polevl(z, FN8, 8)/(x*p1evl(z, FD8, 8)); 215 | g = z*polevl(z, GN8, 8)/p1evl(z, GD8, 9); 216 | } 217 | *si = PIO2 - f*c - g*s; 218 | if (sign) 219 | *si = -(*si); 220 | *ci = f*s - g*c; 221 | return; 222 | } 223 | 224 | __device__ void si(double x, double *si) { 225 | double z, c, s, f, g; 226 | short sign; 227 | 228 | if (x < 0.0) { 229 | sign = -1; 230 | x = -x; 231 | } else 232 | sign = 0; 233 | 234 | if (x == 0.0) { 235 | *si = 0; 236 | return; 237 | } 238 | 239 | if (x > 1.0e9) { 240 | *si = PIO2 - cos(x)/x; 241 | } 242 | 243 | if (x > 4.0) 244 | goto asympt; 245 | 246 | z = x*x; 247 | s = x*polevl(z, SN, 5)/polevl(z, SD, 5); 248 | 249 | if (sign) 250 | s = -s; 251 | 252 | *si = s; 253 | return; 254 | 255 | asympt: 256 | s = sin(x); 257 | c = cos(x); 258 | z = 1.0/(x*x); 259 | 260 | if (x < 8.0) { 261 | f = polevl(z, FN4, 6)/(x*p1evl(z, FD4, 7)); 262 | g = z*polevl(z, GN4, 7)/p1evl(z, GD4, 7); 263 | } else { 264 | f = polevl(z, FN8, 8)/(x*p1evl(z, FD8, 8)); 265 | g = z*polevl(z, GN8, 8)/p1evl(z, GD8, 9); 266 | } 267 | *si = PIO2 - f*c - g*s; 268 | if (sign) 269 | *si = -(*si); 270 | return; 271 | } 272 | 273 | #endif /* !defined(SPECIAL_FUNCTIONS_HIP_H) */ 274 | -------------------------------------------------------------------------------- /include/pimc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file pimc.h 3 | * @author Adrian Del Maestro 4 | * @date 10.27.2008 5 | * 6 | * @brief PathIntegralMonteCarlo class definition. 7 | */ 8 | 9 | #ifndef PIMC_H 10 | #define PIMC_H 11 | 12 | #include "common.h" 13 | #include "communicator.h" 14 | #include "estimator.h" 15 | 16 | class Path; 17 | class LookupTable; 18 | class MoveBase; 19 | class EstimatorBase; 20 | 21 | /** A std::vector containing measurable estimators */ 22 | typedef boost::ptr_vector estimator_vector; 23 | 24 | /** A std::vector containing Monte Carlo updates */ 25 | typedef boost::ptr_vector move_vector; 26 | 27 | // ======================================================================== 28 | // PathIntegralMonteCarlo Class 29 | // ======================================================================== 30 | /** 31 | * The main 32 | * driver class for the entire path integral monte carlo program. 33 | * 34 | * Holds the path, action, move and estimator objects along with methods 35 | * which actually perform the monte carlo sampling procedure. 36 | */ 37 | class PathIntegralMonteCarlo { 38 | public: 39 | PathIntegralMonteCarlo (boost::ptr_vector &,MTRand &, boost::ptr_vector &, 40 | boost::ptr_vector &, const bool); 41 | ~PathIntegralMonteCarlo (); 42 | 43 | 44 | /* The equilibration relaxation */ 45 | void equilStepDiagonal(); 46 | 47 | bool equilStepRelaxmu(); 48 | bool equilStepRelaxC0(); 49 | 50 | void equilStep(const uint32, const bool, const bool); 51 | 52 | /* The actual monte carlo step */ 53 | void step(); 54 | 55 | /* Output results of the simulation */ 56 | void finalOutput(); 57 | 58 | /* Save the PIMC state to disk */ 59 | void saveState(const int finalSave = 0); 60 | 61 | /* Output the world-line configurations in the protein databank format */ 62 | void outputPDB(); 63 | 64 | int numStoredBins; ///< Number of stored estimators 65 | int numDiagonal; ///< Number of consecutive diagonal configs 66 | int numConfig; ///< Number of configurations; 67 | int numCoMAttempted; ///< Number of Center of Mass moves 68 | int prevNumCoMAttempted; ///< Number of Center of Mass moves attempted 69 | int numCoMAccepted; ///< Number of equil CoM moves accepted 70 | int numDisplaceAttempted; ///< Number of equil Displace moves 71 | int numDisplaceAccepted; ///< Number of equil Displace moves accepted 72 | int numMuAttempted; ///< Number of moves between mu adjustments 73 | int numNAttempted; ///< The number of particle measurements 74 | int numStepsAttempted; ///< Number of steps for relaxing C0 75 | 76 | void printWormState(); 77 | std::string printHistogram(); 78 | 79 | private: 80 | MTRand &random; // The global random number generator 81 | 82 | int configNumber; // The output configuration number 83 | int numImagTimeSweeps; // Partitioning used for updates 84 | int numSteps; // The number of steps performed during equilibration 85 | int numUpdates; // The maximum number of updates per step. 86 | uint32 binSize; // The maximum number measurements per bin. 87 | int numParticles; // The number of particles 88 | 89 | int N0; ///< The initial/target number of particles 90 | bool foundmu; ///< Have we found the optimal μ? 91 | bool foundC0; ///< Have we found the optimal C0? 92 | double muFactor; ///< Used for scaling muShift stepsize 93 | double bestmu; ///< The previously best value of mu. 94 | int bestPN; ///< The previously best value of PN. 95 | double bestDiffAveN; ///< The currently best value of aveN; 96 | bool inWindow; ///< Is the number of particles in the window? 97 | 98 | int sgnAveN; ///< What is the relative sign betwen aveN and N0? 99 | 100 | DynamicArray PN; ///< Number probability distribution (used in relaxmu) 101 | bool relaxmuMessage; ///< For printing a message when μ relaxation begins 102 | bool relaxC0Message; ///< For printing a message when μ relaxation begins 103 | bool equilMessage; ///< For printing a message when equilibration begins 104 | bool equilODMessage; ///< For printing a message when OD equilibration begins 105 | std::vector C0Vals; ///< Record of previously attempted values of C0 106 | std::vector diagFracVals; ///< Record fo diagonal fraction (for linear regression). 107 | 108 | double targetDiagFrac; ///< The target diagonal fraction we are trying to obtain. 109 | int sgnDiagFrac; ///< What is the relative sign for C0 relaxation 110 | double shiftC0; ///< How much are we shifting C0? 111 | uint32 barStepSize; ///< Used for printing a status bar. 112 | uint32 numRemainingSteps; ///< The number of remaining steps in the equilibration stage. 113 | uint32 numBars; ///< Used for printing out progress bar 114 | 115 | uint32 Npaths; // Number of paths 116 | 117 | std::vector stateStrings; // A std::vector of state std::strings from the last bin 118 | 119 | bool startWithState; // Are we starting from a saved state 120 | bool success; // Track move success/failure 121 | 122 | boost::ptr_vector &pathPtrVec; // The std::vector of all paths 123 | Path &path; // A reference to the first path in the path std::vector 124 | 125 | boost::ptr_vector &movePtrVec; // Vector of all move_vectors 126 | move_vector &move; // A reference to the first move_vector 127 | 128 | boost::ptr_vector &estimatorPtrVec; // Vector of estimators for 129 | // each path followed by multipath 130 | estimator_vector &estimator; // A reference to the first estimator_vector 131 | 132 | std::vector attemptDiagProb; // The cumulative diagonal attempt Probabilities 133 | std::vector attemptOffDiagProb; // The cumulative off-diagonal attempt Probabilities 134 | 135 | std::map moveIndex; // A std::map to keep track of move names and indices 136 | std::map estimatorIndex; // A std::map to keep track of estimator names and indices 137 | 138 | /* Output estimators to disk */ 139 | void output(); 140 | 141 | /* perform an iterative linear regrssion for C0 calculation */ 142 | double linearRegressionC0(); 143 | 144 | /* Load the PIMC state from disk */ 145 | void loadState(); 146 | 147 | /* Load classical or quantum initial states */ 148 | void loadClassicalState(DynamicArray &, DynamicArray &, int); 149 | void loadQuantumState(DynamicArray &, DynamicArray &, DynamicArray&, int, int); 150 | 151 | /* Shuffle the offDiag move list, returning it in moves*/ 152 | void shuffleMoves(); 153 | 154 | /* Perform a Metropolis update */ 155 | std::string update(const double,const int,const int); 156 | 157 | }; 158 | 159 | #endif 160 | 161 | -------------------------------------------------------------------------------- /src/cmc.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmc.cpp 3 | * @brief Classical Monte Carlo simulation 4 | * @author Adrian Del Maestro 5 | * @date 08.13.2012 6 | */ 7 | 8 | #include "common.h" 9 | #include "constants.h" 10 | #include "container.h" 11 | #include "potential.h" 12 | #include "cmc.h" 13 | #include "communicator.h" 14 | 15 | // --------------------------------------------------------------------------- 16 | // --------------------------------------------------------------------------- 17 | // CLASSICAL MONTE CARLO CLASS ----------------------------------------------- 18 | // --------------------------------------------------------------------------- 19 | // --------------------------------------------------------------------------- 20 | 21 | /**************************************************************************//** 22 | * Constructor. 23 | ******************************************************************************/ 24 | ClassicalMonteCarlo::ClassicalMonteCarlo (PotentialBase *_externalPtr, 25 | PotentialBase *_interactionPtr, MTRand &_random, const Container *_boxPtr, 26 | DynamicArray &initialPos) : 27 | externalPtr(_externalPtr), 28 | interactionPtr(_interactionPtr), 29 | random(_random), 30 | boxPtr(_boxPtr), 31 | config(initialPos) 32 | { 33 | /* The number of particles */ 34 | numParticles = config.extents()[0]; 35 | 36 | 37 | /* Set the fugacity z*/ 38 | z = exp(constants()->mu()/constants()->T())/pow(constants()->dBWavelength(),NDIM); 39 | 40 | /* Compute the initial total potential energy */ 41 | energy = getTotalEnergy(); 42 | 43 | /* Initialize acceptance tracking */ 44 | numMoveTotal = 0; 45 | numMoveAccept = 0; 46 | 47 | numDeleteTotal = 0; 48 | numDeleteAccept = 0; 49 | 50 | numInsertTotal = 0; 51 | numInsertAccept = 0; 52 | 53 | /* Initialize measurements */ 54 | aveEnergy = 0.0; 55 | aveNumParticles = 0.0; 56 | aveEoN = 0.0; 57 | } 58 | 59 | /**************************************************************************//** 60 | * Destructor. 61 | ******************************************************************************/ 62 | ClassicalMonteCarlo::~ClassicalMonteCarlo () 63 | { 64 | // empty destructor 65 | } 66 | 67 | /**************************************************************************//** 68 | * Compute the total energy. 69 | ******************************************************************************/ 70 | double ClassicalMonteCarlo::getTotalEnergy() 71 | { 72 | double locEnergy = 0.0; 73 | sep = dVec{}; 74 | for (int part1 = 0; part1 < numParticles; part1++) { 75 | locEnergy += externalPtr->V(config(part1)); 76 | 77 | for (int part2 = part1+1; part2 < numParticles; part2++) { 78 | sep = config(part1)-config(part2); 79 | boxPtr->putInside(sep); 80 | locEnergy += interactionPtr->V(sep); 81 | } 82 | } 83 | return locEnergy; 84 | } 85 | 86 | /**************************************************************************//** 87 | * Perform the monte carlo simulation. 88 | ******************************************************************************/ 89 | void ClassicalMonteCarlo::run(uint32 numMCSteps, bool gce) { 90 | //int numMeasure = 0; 91 | double x; 92 | for(uint32 n = 1; n < numMCSteps; n++) { 93 | int m = 0; 94 | do { 95 | if (gce) 96 | x = random.rand(); 97 | else 98 | x = 0.0; 99 | 100 | /* Perform updates */ 101 | if (x < 1.0/3.0) 102 | moveParticle(); 103 | else if (x < 2.0/3.0) 104 | deleteParticle(); 105 | else 106 | insertParticle(); 107 | 108 | /* Update observables */ 109 | aveEnergy += energy; 110 | aveNumParticles += numParticles; 111 | aveEoN += energy/(1.0*numParticles); 112 | //numMeasure++; 113 | 114 | m++; 115 | } while (m < numParticles); 116 | 117 | // if ((n % 50) == 0) 118 | // measure(numMeasure); 119 | } 120 | 121 | /* Update the config array */ 122 | config.resizeAndPreserve(numParticles); 123 | } 124 | 125 | /**************************************************************************//** 126 | * Perform a simple positional update 127 | * 128 | ******************************************************************************/ 129 | void ClassicalMonteCarlo::moveParticle() { 130 | 131 | dVec oldPos{}; 132 | double oldV,newV; 133 | 134 | numMoveTotal++; 135 | 136 | int p = random.randInt(numParticles-1); 137 | 138 | /* Compute the old energy of particle p*/ 139 | oldV = externalPtr->V(config(p)); 140 | for (int p2 = 0; p2 < numParticles; p2++) { 141 | if (p != p2) { 142 | sep = config(p)-config(p2); 143 | boxPtr->putInside(sep); 144 | oldV += interactionPtr->V(sep); 145 | } 146 | } 147 | 148 | oldPos = config(p); 149 | 150 | /* The new random position */ 151 | config(p) = boxPtr->randUpdate(random,oldPos); 152 | 153 | /* Compute the new energy of particle p*/ 154 | newV = externalPtr->V(config(p)); 155 | for (int p2 = 0; p2 < numParticles; p2++) { 156 | if (p != p2) { 157 | sep = config(p)-config(p2); 158 | boxPtr->putInside(sep); 159 | newV += interactionPtr->V(sep); 160 | } 161 | } 162 | 163 | deltaV = newV - oldV; 164 | 165 | /* Now the metropolis step */ 166 | if (random.rand() < exp(-deltaV/constants()->T())) { 167 | energy += deltaV; 168 | numMoveAccept++; 169 | } 170 | else { 171 | config(p) = oldPos; 172 | } 173 | } 174 | 175 | /**************************************************************************//** 176 | * Perform a simple insert move. 177 | * 178 | ******************************************************************************/ 179 | void ClassicalMonteCarlo::insertParticle() { 180 | 181 | dVec newPos{}; 182 | 183 | numInsertTotal++; 184 | 185 | newPos = boxPtr->randPosition(random); 186 | 187 | /* Compute the old energy of particle p*/ 188 | deltaV = externalPtr->V(newPos); 189 | for (int p2 = 0; p2 < numParticles; p2++) { 190 | sep = newPos-config(p2); 191 | boxPtr->putInside(sep); 192 | deltaV += interactionPtr->V(sep); 193 | } 194 | 195 | double factor = z*boxPtr->volume/(numParticles+1); 196 | 197 | /* Now the metropolis step */ 198 | if (random.rand() < factor*exp(-deltaV/constants()->T())) { 199 | energy += deltaV; 200 | if (config.extents()[0] < static_cast(numParticles+1)) 201 | config.resizeAndPreserve(numParticles+1); 202 | config(numParticles) = newPos; 203 | numParticles++; 204 | numInsertAccept++; 205 | } 206 | } 207 | 208 | /**************************************************************************//** 209 | * Perform a simple delete move. 210 | * 211 | ******************************************************************************/ 212 | void ClassicalMonteCarlo::deleteParticle() { 213 | 214 | numDeleteTotal++; 215 | 216 | int p = random.randInt(numParticles-1); 217 | 218 | /* Compute the old energy of particle p*/ 219 | deltaV = -externalPtr->V(config(p)); 220 | for (int p2 = 0; p2 < numParticles; p2++) { 221 | if (p != p2) { 222 | sep = config(p)-config(p2); 223 | boxPtr->putInside(sep); 224 | deltaV -= interactionPtr->V(sep); 225 | } 226 | } 227 | 228 | double factor = numParticles/(z*boxPtr->volume); 229 | 230 | /* Now the metropolis step */ 231 | if (random.rand() < factor*exp(-deltaV/constants()->T())) { 232 | energy += deltaV; 233 | config(p) = config(numParticles-1); 234 | numParticles--; 235 | numDeleteAccept++; 236 | } 237 | } 238 | 239 | /**************************************************************************//** 240 | * Perform measurements 241 | * 242 | ******************************************************************************/ 243 | void ClassicalMonteCarlo::measure(int &numMeasure) { 244 | std::cout << aveEnergy/(numMeasure) << "\t" << aveNumParticles/(numMeasure) 245 | << "\t" << (3.0/2.0)*constants()->T() + aveEoN/(numMeasure) 246 | << "\t" << aveNumParticles/(numMeasure*boxPtr->volume) 247 | << "\t" << 1.0*numMoveAccept/(1.0*numMoveTotal) 248 | << "\t" << 1.0*numInsertAccept/(1.0*numInsertTotal) 249 | << "\t" << 1.0*numDeleteAccept/(1.0*numDeleteTotal) << std::endl; 250 | aveEnergy = 0.0; 251 | aveEoN = 0.0; 252 | aveNumParticles = 0.0; 253 | numMeasure = 0; 254 | } 255 | -------------------------------------------------------------------------------- /src/pdrive.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file pdrive.cpp 3 | * @brief A dimensionally independent worm algorithm path integral monte carlo code driver. 4 | * @author Adrian Del Maestro 5 | * @date 10.14.2008 6 | */ 7 | 8 | #include "common.h" 9 | #include "constants.h" 10 | #include "container.h" 11 | #include "path.h" 12 | #include "potential.h" 13 | #include "action.h" 14 | #include "wavefunction.h" 15 | #include "pimc.h" 16 | #include "lookuptable.h" 17 | #include "communicator.h" 18 | #include "setup.h" 19 | #include "cmc.h" 20 | #include "move.h" 21 | 22 | /** 23 | * Main driver. 24 | * Read in all program options from the user using boost::program_options and setup the simulation 25 | * cell, initial conditions and both the interaction and external potential. Either equilibrate or 26 | * restart a simulation, then start measuring. We output all the simulation parameters to disk as a 27 | * log file so that it can be restart again assigning it a unique PIMCID. 28 | * @see http://www.boost.org/doc/libs/release/doc/html/program_options.html 29 | */ 30 | int main (int argc, char *argv[]) { 31 | 32 | /* Get initial time */ 33 | time_t start_time = time(NULL); 34 | time_t current_time; //current time 35 | bool wallClockReached = false; 36 | 37 | uint32 seed = 139853; // The seed for the random number generator 38 | 39 | Setup& setup = Setup::instance(); 40 | 41 | /* Attempt to parse the command line options */ 42 | try { 43 | setup.getOptions(argc,argv); 44 | } 45 | catch(std::exception& ex) { 46 | std::cerr << "error: " << ex.what() << "\n"; 47 | return 1; 48 | } 49 | catch(...) { 50 | std::cerr << "Exception of unknown type!\n"; 51 | } 52 | 53 | /* Parse the setup options and possibly exit */ 54 | if (setup.parseOptions()) 55 | return 1; 56 | 57 | /* The global random number generator, we add the process number to the seed (for 58 | * use in parallel simulations.*/ 59 | seed = setup.seed(seed); 60 | MTRand random(seed); 61 | 62 | /* Get the simulation box */ 63 | setup.set_cell(); 64 | Container *boxPtr = setup.get_cell(); 65 | 66 | /* Create the worldlines */ 67 | if (setup.worldlines()) 68 | return 1; 69 | 70 | /* Setup the simulation constants */ 71 | setup.setConstants(); 72 | 73 | /* Setup the simulation communicator */ 74 | setup.communicator(); 75 | 76 | /* Get number of paths to use */ 77 | int Npaths = constants()->Npaths(); 78 | 79 | /* Create and initialize the Nearest Neighbor Lookup Table */ 80 | boost::ptr_vector lookupPtrVec; 81 | for(int i=0; inumTimeSlices(), 84 | constants()->initialNumParticles())); 85 | } 86 | 87 | /* Create and initialize the potential pointers */ 88 | PotentialBase *interactionPotentialPtr = setup.interactionPotential(); 89 | PotentialBase *externalPotentialPtr = setup.externalPotential(); 90 | 91 | /* This functionality allows us to use the code directly to generate 92 | * graphene potential binary or plain-text lookup tables (and convert 93 | * between them) */ 94 | std::vector grapheneLUTOptions= {"graphenelut3dtobinary", "graphenelut3dtotext","graphenelut3dgenerate"}; 95 | if (std::find(grapheneLUTOptions.begin(),grapheneLUTOptions.end(), constants("external")) != grapheneLUTOptions.end()) 96 | return 99; 97 | 98 | 99 | /* Get the initial conditions associated with the external potential */ 100 | /* Must use the copy constructor as we return a copy */ 101 | DynamicArray initialPos = 102 | externalPotentialPtr->initialConfig(boxPtr,random,constants()->initialNumParticles()); 103 | 104 | /* Perform a classical canonical pre-equilibration to obtain a suitable 105 | * initial state if N > 0*/ 106 | if (!constants()->restart() && (constants()->initialNumParticles() > 0) ) { 107 | ClassicalMonteCarlo CMC(externalPotentialPtr,interactionPotentialPtr,random,boxPtr, 108 | initialPos); 109 | CMC.run(constants()->numEqSteps(),0); 110 | } 111 | 112 | /* Setup the path data variable */ 113 | boost::ptr_vector pathPtrVec; 114 | for(int i=0; inumTimeSlices(), 117 | initialPos,constants()->numBroken())); 118 | } 119 | 120 | //PotentialBase *externalPotentialPtr = setup.externalPotential(); 121 | /* The Trial Wave Function (constant for pimc) */ 122 | WaveFunctionBase *waveFunctionPtr = setup.waveFunction(pathPtrVec.front(),lookupPtrVec.front()); 123 | 124 | /* Setup the action */ 125 | boost::ptr_vector actionPtrVec; 126 | for(int i=0; i > movesPtrVec; 134 | for(int i=0; i > estimatorsPtrVec; 141 | for(int i=0; i 0) { 147 | for(uint32 j = 0; j < estimatorsPtrVec.back().size(); j++) 148 | estimatorsPtrVec.back().at(j).appendLabel(str(format("%d") % (i+1))); 149 | } 150 | } 151 | 152 | /* Setup the multi-path estimators */ 153 | if(Npaths>1){ 154 | estimatorsPtrVec.push_back(setup.estimators(pathPtrVec,actionPtrVec,random)); 155 | } 156 | 157 | /* Setup the pimc object */ 158 | PathIntegralMonteCarlo pimc(pathPtrVec,random,movesPtrVec,estimatorsPtrVec, 159 | !setup.params["start_with_state"].as().empty()); 160 | 161 | /* A silly banner */ 162 | if (PIGS) 163 | std::cout << std::endl 164 | << " _____ _____ _____ _____" << std::endl 165 | << "| __ \\ |_ _| / ____| / ____|" << std::endl 166 | << "| |__) | | | | | __ | (___" << std::endl 167 | << "| ___/ | | | | |_ | \\___ \\" << std::endl 168 | << "| | _| |_ | |__| | ____) |" << std::endl 169 | << "|_| |_____| \\_____| |_____/" << std::endl 170 | << std::endl; 171 | else 172 | std::cout << std::endl 173 | << " _____ _____ __ __ _____" << std::endl 174 | << " | __ \\ |_ _| | \\/ | / ____|" << std::endl 175 | << " | |__) | | | | \\ / | | | " << std::endl 176 | << " | ___/ | | | |\\/| | | | " << std::endl 177 | << " | | _| |_ | | | | | |____ " << std::endl 178 | << " |_| |_____| |_| |_| \\_____|" << std::endl 179 | << std::endl; 180 | 181 | /* If this is a fresh run, we equilibrate and output simulation parameters to disk */ 182 | if (!constants()->restart()) { 183 | 184 | /* Equilibrate */ 185 | std::cout << format("[PIMCID: %s] - Pre-Equilibration Stage.") % constants()->id() << std::endl; 186 | for (uint32 n = 0; n < constants()->numEqSteps(); n++) 187 | pimc.equilStep(n,setup.params("relax"),setup.params("relaxmu")); 188 | 189 | /* If we have relaxed the chemical potential, need to update file names 190 | * in the grand canonical ensemble */ 191 | if (!setup.params("canonical") && setup.params("relaxmu")) { 192 | communicate()->updateNames(); 193 | } 194 | 195 | /* Output simulation details/parameters */ 196 | setup.outputOptions(argc,argv,seed,boxPtr,lookupPtrVec.front().getNumNNGrid()); 197 | } 198 | 199 | std::cout << format("[PIMCID: %s] - Measurement Stage.") % constants()->id() << std::endl; 200 | 201 | /* Sample */ 202 | int oldNumStored = 0; 203 | int outNum = 0; 204 | int numOutput = setup.params["output_config"].as(); 205 | uint32 n = 0; 206 | do { 207 | pimc.step(); 208 | if (pimc.numStoredBins > oldNumStored) { 209 | oldNumStored = pimc.numStoredBins; 210 | std::cout << format("[PIMCID: %s] - Bin #%5d stored to disk.") % constants()->id() 211 | % oldNumStored << std::endl; 212 | } 213 | n++; 214 | 215 | /* Output configurations to disk */ 216 | if ((numOutput > 0) && ((n % numOutput) == 0)) { 217 | pathPtrVec.front().outputConfig(outNum); 218 | outNum++; 219 | } 220 | 221 | /* Check if we've reached the wall clock limit*/ 222 | if(constants()->wallClockOn()){ 223 | current_time = time(NULL); 224 | if ( uint32(current_time) > (uint32(start_time) + constants()->wallClock()) ){ 225 | wallClockReached = true; 226 | break; 227 | } 228 | } 229 | } while (pimc.numStoredBins < setup.params["number_bins_stored"].as()); 230 | if (wallClockReached) 231 | std::cout << format("[PIMCID: %s] - Wall clock limit reached.") % constants()->id() << std::endl; 232 | else 233 | std::cout << format("[PIMCID: %s] - Measurement complete.") % constants()->id() << std::endl; 234 | 235 | /* Output Results */ 236 | if (!constants()->saveStateFiles()) 237 | pimc.saveState(1); 238 | pimc.finalOutput(); 239 | 240 | /* Free up memory */ 241 | delete interactionPotentialPtr; 242 | delete externalPotentialPtr; 243 | delete boxPtr; 244 | delete waveFunctionPtr; 245 | 246 | return 0; 247 | } 248 | -------------------------------------------------------------------------------- /include/lookuptable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file lookuptable.h 3 | * @author Adrian Del Maestro 4 | * @date 03.16.2009 5 | * 6 | * @brief LookupTable class definition 7 | */ 8 | 9 | #ifndef LOOKUPTABLE_H 10 | #define LOOKUPTABLE_H 11 | 12 | #include "common.h" 13 | #include "constants.h" 14 | #include "container.h" 15 | 16 | class Path; 17 | 18 | // ======================================================================== 19 | // LookupTable Class 20 | // ======================================================================== 21 | /** 22 | * The particle (bead) lookup table. 23 | * 24 | * Holds the lookup table and methods for finding where in the simulation 25 | * cell a particle is located, and which particles are close enough 26 | * to interact. Accomplishes this by partitioning the simulation cell 27 | * and storing the box at ever time slice where a bead is located. 28 | */ 29 | class LookupTable { 30 | 31 | public: 32 | LookupTable(const Container *, const int, const int); 33 | ~LookupTable(); 34 | 35 | const Container *boxPtr; ///< The simulation cell 36 | 37 | int numUniqueNN; ///< The number of unique nearest neighbors of each box 38 | int numNN; ///< The total number of nearest neighbors of each box 39 | 40 | DynamicArray beadList; ///< The cutoff dynamic list of interacting beads 41 | DynamicArray fullBeadList; ///< The full dynamic list of interacting beads 42 | DynamicArray beadSep; ///< The separation between beads 43 | int numBeads; ///< The cutoff number of active beads in beadList; 44 | int fullNumBeads; ///< The full number of active beads in beadList; 45 | 46 | /** Return the number of NN grid boxes */ 47 | iVec getNumNNGrid() {return numNNGrid;} 48 | /** Return the total number of grid boxes */ 49 | int getTotNumGridBoxes() {return totNumGridBoxes;} 50 | 51 | /* Update the NN table interaction list */ 52 | void updateInteractionList(const Path &, const beadLocator &); 53 | void updateFullInteractionList(const beadLocator &, const int); 54 | void updateFullInteractionList(const int, const int); 55 | void updateGrid(const Path &); 56 | void updateGrid(const DynamicArray &); 57 | 58 | void printGrid(); 59 | 60 | /* Remove a bead from the grid */ 61 | void delBead(const beadLocator &); 62 | void addBead(const beadLocator &, const dVec &); 63 | void updateBead(const beadLocator &, const dVec &); 64 | 65 | /* Returns the grid index where the suplied position resides */ 66 | inline iVec gridIndex(const dVec &); 67 | 68 | /* Returns the grid number where the suplied position resides */ 69 | inline int gridNumber(const dVec &); 70 | 71 | /* Converts a grid number to a grid index */ 72 | inline iVec gridIndex(int); 73 | 74 | /* Converts a grid index to a grid number */ 75 | inline int gridNumber(const iVec &); 76 | 77 | /** Resize the bead and grid lists */ 78 | void resizeList(int _numParticles) { 79 | beadList.resize(_numParticles); 80 | fullBeadList.resize(_numParticles); 81 | beadSep.resize(_numParticles); 82 | grid.resizeAndPreserve(numLookupTimeSlices,_numParticles); 83 | beadLabel.resizeAndPreserve(numLookupTimeSlices,_numParticles); 84 | } 85 | 86 | /* Determine if two positions are in neighboring grid boxes */ 87 | bool gridNeighbors(const beadLocator&, const beadLocator&); 88 | 89 | /** Determine if two beads are in the same grid box */ 90 | bool gridShare(const beadLocator &bead1, const beadLocator &bead2) { 91 | return all(grid(bead1), grid(bead2)); 92 | } 93 | 94 | private: 95 | int numLookupTimeSlices; // The number of time slices that 96 | int totNumGridBoxes; // The total number of nn grid boxes 97 | 98 | iVec numNNGrid; // The number of nn grid boxes in each direction 99 | iVec gIndex; // A commonly used grid box index vector 100 | 101 | double rc2; // A local copy of the potential cutoff squared 102 | 103 | std::array nnIndex; // Comonly used nn index vector 104 | std::array nI; // Used for indexing numLabels 105 | std::array hI; // Used for indexing hash 106 | 107 | DynamicArray gridNN; // The nearest neighbors of each grid box 108 | DynamicArray gridNNReduced; // The nn reduced to contain no back links 109 | 110 | dVec sizeNNGrid; // The size of the nn grid boxes in each direction 111 | 112 | DynamicArray hash; // The main worldline lookup array 113 | DynamicArray grid; // The grid index of a bead 114 | DynamicArray beadLabel; // The label of a bead in a cell 115 | DynamicArray numLabels; // The number of beads in a cell 116 | 117 | std::array hashSize; // The current size of the hash array 118 | 119 | beadLocator swap; // Used when deleting/updating beads 120 | 121 | void setupNNGrid(); // We initialize the nearest neighbor grid 122 | 123 | /* Return tiny vectors suitable for indexing the numLabel and hash array */ 124 | inline std::array numLabelIndex(const beadLocator&); 125 | inline std::array numLabelIndex(const iVec&, const int); 126 | inline std::array hashIndex(const beadLocator&, const int); 127 | inline std::array hashIndex(const iVec&, const int, const int); 128 | }; 129 | 130 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 131 | // INLINE FUNCTION DEFINITIONS 132 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 133 | 134 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 135 | /** 136 | * Given a particle position, return the grid index for the nearest 137 | * neighbor lookup table. 138 | */ 139 | inline iVec LookupTable::gridIndex(const dVec &pos) { 140 | iVec index; // The grid index in each dimension 141 | for (int i = 0; i < NDIM; i++) { 142 | index[i] = static_cast( abs( pos[i] + 0.5 * boxPtr->side[i] - EPS ) 143 | / (sizeNNGrid[i] + EPS) ); 144 | PIMC_ASSERT(index[i](abs( pos[i] + 0.5 * boxPtr->side[i] - EPS ) / (sizeNNGrid[i] + EPS)); 162 | } 163 | PIMC_ASSERT(gNumber LookupTable::numLabelIndex(const beadLocator &beadIndex) { 205 | std::array index; 206 | for (int i = 0; i < NDIM; i++) 207 | index[i] = grid(beadIndex)[i]; 208 | index[NDIM] = beadIndex[0]; 209 | return index; 210 | } 211 | 212 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 213 | /** 214 | * Given a grid Index, and slice, return a NDIM+1 iVector used for indexing the numLabel 215 | * array. 216 | */ 217 | inline std::array LookupTable::numLabelIndex(const iVec &gI, const int slice) { 218 | std::array index; 219 | for (int i = 0; i < NDIM; i++) 220 | index[i] = gI[i]; 221 | index[NDIM] = slice; 222 | return index; 223 | } 224 | 225 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 226 | /** 227 | * Given a bead locator and label, return a NDIM+2 iVector used for indexing the hash 228 | * array. 229 | */ 230 | inline std::array LookupTable::hashIndex(const beadLocator &beadIndex, 231 | const int label) { 232 | std::array index; 233 | for (int i = 0; i < NDIM; i++) 234 | index[i] = grid(beadIndex)[i]; 235 | index[NDIM] = beadIndex[0]; 236 | index[NDIM+1] = label; 237 | return index; 238 | } 239 | 240 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 241 | /** 242 | * Given a grid Index, slice and label, return a NDIM+2 iVector used for indexing the hash 243 | * array. 244 | */ 245 | inline std::array LookupTable::hashIndex(const iVec &gI, const int slice, 246 | const int label) { 247 | std::array index; 248 | for (int i = 0; i < NDIM; i++) 249 | index[i] = gI[i]; 250 | index[NDIM] = slice; 251 | index[NDIM+1] = label; 252 | return index; 253 | } 254 | 255 | #endif 256 | -------------------------------------------------------------------------------- /src/constants.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file constants.cpp 3 | * @author Adrian Del Maestro 4 | * 5 | * @brief ConstantParameters class implementation. 6 | */ 7 | 8 | #include "constants.h" 9 | #include 10 | 11 | // --------------------------------------------------------------------------- 12 | // --------------------------------------------------------------------------- 13 | // CONSTANT PARAMETERS CLASS ------------------------------------------------ 14 | // --------------------------------------------------------------------------- 15 | // --------------------------------------------------------------------------- 16 | 17 | /**************************************************************************//** 18 | * An empty constructor which simply sets all constants to null. 19 | ******************************************************************************/ 20 | ConstantParameters::ConstantParameters() 21 | { 22 | /* empty constructor */ 23 | } 24 | 25 | /**************************************************************************//** 26 | * Initialize all constants from command line, XMl and defaults. 27 | * 28 | * We initialize all constant parameters used in the simulation. The value of 29 | * lambda = hbar^2/2 m k_B is computed in units where lenghts are measured in 30 | * angstroms and energies in kelvin. 31 | ******************************************************************************/ 32 | void ConstantParameters::initConstants(po::variables_map ¶ms) { 33 | 34 | /* Create the local (and accessible) copy of the command line options */ 35 | params_ = params; 36 | 37 | /* We use boost to generate a UUID for the simulation */ 38 | if (params["restart"].empty()) { 39 | 40 | id_ = boost::uuids::to_string(boost::uuids::random_generator()()); 41 | 42 | /* Add a possible user specified label */ 43 | std::string label_ = params["label"].as(); 44 | if (label_.length() > 12) 45 | label_ = label_.substr(0,12); 46 | 47 | id_.replace(id_.end()-label_.length(),id_.end(),label_); 48 | restart_ = false; 49 | } 50 | else { 51 | id_ = params["restart"].as(); 52 | restart_ = true; 53 | } 54 | 55 | /* Are we starting from a supplied state file? */ 56 | startWithState_ = !params["start_with_state"].as().empty(); 57 | 58 | /* Set the wall clock state */ 59 | if (params["wall_clock"].empty()) { 60 | wallClockOn_ = false; 61 | wallClock_ = 0; 62 | } 63 | /* Set wallClock_ in seconds*/ 64 | else { 65 | wallClockOn_ = true; 66 | std::string wallClockparam = params["wall_clock"].as(); 67 | 68 | /* If we detect a hyphen, we interpret as days-hours. */ 69 | if (wallClockparam.find('-') != std::string::npos) { 70 | std::size_t apos_pos = wallClockparam.find('-'); 71 | wallClock_ = (stof(wallClockparam.substr(0, apos_pos)) * 24 + stof(wallClockparam.substr(apos_pos+1)))*3600; 72 | 73 | /* If we have a colon, we interpret as hours:mins:seconds */ 74 | } else if (wallClockparam.find(':') != std::string::npos) { 75 | std::size_t colon_pos = wallClockparam.find(':'); 76 | wallClock_ = stof(wallClockparam.substr(0,colon_pos))*3600 + stof(wallClockparam.substr(colon_pos+1,2))*60 + stof(wallClockparam.substr(colon_pos+4,2)); 77 | 78 | /* Finally, if neither are present, we interpret as a number of hours */ 79 | } else { 80 | wallClock_ = uint32(floor(stof(wallClockparam)*3600)); 81 | } 82 | } 83 | 84 | /* Are we working in the grand canonical ensemble? */ 85 | canonical_ = !params["canonical"].empty(); 86 | 87 | /* Are we saving a state file every bin? */ 88 | saveStateFiles_ = params["no_save_state"].empty(); 89 | 90 | /* Do we want variable length diagonal updates? */ 91 | varUpdates_ = params["var_updates"].empty(); 92 | 93 | /* Set the particle number window */ 94 | window_ = canonical_ && !params["window"].empty(); 95 | if (window_) 96 | windowWidth_ = params["window"].as(); 97 | else 98 | windowWidth_ = 0; 99 | 100 | /* Set the ensemble weight */ 101 | gaussianEnsemble_ = canonical_ && !params["gaussian_window_width"].empty(); 102 | if (gaussianEnsemble_) 103 | gaussianEnsembleSD_ = params["gaussian_window_width"].as(); 104 | else 105 | gaussianEnsembleSD_ = 0.0; 106 | 107 | /* The maximum winding number sampled */ 108 | maxWind_ = params["max_winding"].as(); 109 | 110 | /* Assigned values */ 111 | b_ = int (ceil(log(1.0*params["update_length"].as()) / log(2.0)-EPS)); 112 | 113 | /* We need to make sure b_ < numTimeSlices */ 114 | while (ipow(2,b_) >= params["number_time_slices"].as()) 115 | b_--; 116 | 117 | /* Assigned values */ 118 | Mbar_ = params["update_length"].as(); 119 | T_ = params["temperature"].as(); 120 | imagTimeLength_ = params["imaginary_time_length"].as(); 121 | mu_ = params["chemical_potential"].as(); 122 | m_ = params["mass"].as(); 123 | lambda_ = 24.24 / m_; 124 | rc_ = params["potential_cutoff"].as(); 125 | rc2_ = rc_*rc_; 126 | C0_ = params["worm_constant"].as(); 127 | numTimeSlices_ = params["number_time_slices"].as(); 128 | aCC_ = params["carbon_carbon_dist"].as(); 129 | if (PIGS) 130 | tau_ = 1.0/((numTimeSlices_-1)*T_); 131 | else 132 | tau_ = 1.0/(numTimeSlices_*T_); 133 | V_ = params["volume"].as(); 134 | L_ = params["side"].as()[NDIM-1]; 135 | numEqSteps_ = params["number_eq_steps"].as(); 136 | binSize_ = params["bin_size"].as(); 137 | 138 | graphenelut3d_file_prefix_ = params["graphenelut3d_file_prefix"].as(); 139 | virialWindow_ = params["virial_window"].as(); 140 | 141 | if (!params["wavevector"].empty() && !params["wavevector_type"].empty()) { 142 | wavevector_ = params["wavevector"].as(); 143 | wavevectorType_ = params["wavevector_type"].as(); 144 | } 145 | 146 | initialNumParticles_ = params["number_particles"].as(); 147 | numBroken_ = params["number_broken"].as(); 148 | 149 | spatialSubregionOn_ = !params["spatial_subregion"].empty(); 150 | if (spatialSubregionOn_) 151 | spatialSubregion_ = params["spatial_subregion"].as(); 152 | 153 | endFactor_ = params["end_factor"].as(); 154 | Npaths_ = params["number_paths"].as(); 155 | 156 | actionType_ = params["action"].as(); 157 | 158 | /* Computed values */ 159 | dBWavelength_ = 2.0*sqrt(M_PI * lambda_ / T_); 160 | comDelta_ = 0.04*dBWavelength_; 161 | displaceDelta_ = 0.04*dBWavelength_; 162 | getC(); 163 | 164 | /* Set the move probabilities */ 165 | 166 | /* At present, the pigs code has only diagonal moves */ 167 | if (PIGS) { 168 | attemptProb_["open"] = 0.0; 169 | attemptProb_["insert"] = 0.0; 170 | attemptProb_["close"] = 0.0; 171 | attemptProb_["advance head"] = 0.0; 172 | attemptProb_["recede head"] = 0.0; 173 | attemptProb_["advance tail"] = 0.0; 174 | attemptProb_["recede tail"] = 0.0; 175 | attemptProb_["remove"] = 0.0; 176 | attemptProb_["swap head"] = 0.0; 177 | attemptProb_["swap tail"] = 0.0; 178 | attemptProb_["diagonal"] = 0.6; 179 | attemptProb_["center of mass"] = 0.1; 180 | attemptProb_["displace"] = 0.0; 181 | attemptProb_["end staging"] = 0.3; 182 | attemptProb_["mid staging"] = 0.0; 183 | attemptProb_["swap break"] = 0.0; 184 | } 185 | else { 186 | attemptProb_["open"] = 0.4; 187 | attemptProb_["insert"] = 0.4; 188 | attemptProb_["close"] = 0.15; 189 | attemptProb_["advance head"] = 0.075 + 0.05*BOLTZMANNONS; 190 | attemptProb_["recede head"] = 0.075 + 0.05*BOLTZMANNONS; 191 | attemptProb_["advance tail"] = 0.075 + 0.05*BOLTZMANNONS; 192 | attemptProb_["recede tail"] = 0.075 + 0.05*BOLTZMANNONS; 193 | attemptProb_["swap head"] = 0.1*(1-BOLTZMANNONS); 194 | attemptProb_["swap tail"] = 0.1*(1-BOLTZMANNONS); 195 | attemptProb_["remove"] = 0.15; 196 | attemptProb_["diagonal"] = 0.19; 197 | attemptProb_["center of mass"] = 0.01; 198 | attemptProb_["displace"] = 0.0; 199 | attemptProb_["end staging"] = 0.0; 200 | attemptProb_["swap break"] = 0.0; 201 | attemptProb_["mid staging"] = 0.0; 202 | } 203 | 204 | // Open + Insert + Diagonal + CoM Probability != 1 205 | double totProb = attemptProb_["close"] + attemptProb_["advance head"] + attemptProb_["recede head"] 206 | + attemptProb_["advance tail"] + attemptProb_["recede tail"] + attemptProb_["remove"] 207 | + attemptProb_["swap head"] + attemptProb_["swap tail"] + attemptProb_["diagonal"] 208 | + attemptProb_["center of mass"] + attemptProb_["displace"] + attemptProb_["end staging"] 209 | + attemptProb_["mid staging"]+attemptProb_["swap break"]; 210 | 211 | if (abs(totProb - 1.0) > EPS) { 212 | std::cout << "Close + AdvanceHead + RecedeHead + AdvanceTail + RecedeTail + Remove + SwapHead " 213 | << "+ SwapTail + Diagonal + CoM Probability != 1" << std::endl; 214 | std::cout << totProb << std::endl; 215 | exit(EXIT_FAILURE); 216 | } 217 | PIMC_ASSERT(totProb-1.0 < EPS); 218 | 219 | totProb = attemptProb_["open"] + attemptProb_["insert"] + attemptProb_["diagonal"] 220 | + attemptProb_["center of mass"] + attemptProb_["displace"] + attemptProb_["swap break"] 221 | + attemptProb_["end staging"] + attemptProb_["mid staging"]; 222 | 223 | if (abs(totProb - 1.0) > EPS) { 224 | std::cout << "Open + Insert + Diagonal + CoM Probability != 1" << std::endl; 225 | std::cout << totProb << std::endl; 226 | exit(EXIT_FAILURE); 227 | } 228 | PIMC_ASSERT(totProb-1.0 < EPS); 229 | } 230 | 231 | /**************************************************************************//** 232 | * This public method returns an instance of the constant object, Only one 233 | * can ever exist at a time. 234 | ******************************************************************************/ 235 | ConstantParameters* ConstantParameters::getInstance () 236 | { 237 | static ConstantParameters inst; 238 | return &inst; 239 | } 240 | -------------------------------------------------------------------------------- /src/communicator.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file communicator.cpp 3 | * @author Adrian Del Maestro 4 | * 5 | * @brief Communicator class implementation. 6 | */ 7 | 8 | #include "communicator.h" 9 | 10 | /* Filesystem is tricky as it is not yet widely supported. We try to address 11 | * that here. */ 12 | #if defined(USE_STD_FILESYSTEM) 13 | #include 14 | namespace fs = std::filesystem; 15 | #elif defined(USE_EXPERIMENTAL_FILESYSTEM) 16 | #include 17 | namespace fs = std::experimental::filesystem; 18 | #else 19 | #error "No filesystem support found" 20 | #endif 21 | 22 | // --------------------------------------------------------------------------- 23 | // --------------------------------------------------------------------------- 24 | // FILE CLASS ---------------------------------------------------------------- 25 | // --------------------------------------------------------------------------- 26 | // --------------------------------------------------------------------------- 27 | 28 | /**************************************************************************//** 29 | * Constructor. 30 | * 31 | * Given a file type/label, ensemble type, data label and out directory, 32 | * create a unique file name and backup file name. 33 | * 34 | * @param _type The file type: state, log, etc 35 | * @param _data The unique data std::string identifier 36 | * @param ensemble ce: canonical, gce: grand canonical 37 | * @param outDir The output directory 38 | ******************************************************************************/ 39 | File::File(std::string _type, std::string _data, std::string ensemble, std::string outDir) { 40 | 41 | /* The file name */ 42 | name = str(format("%s/%s-%s-%s.dat") % outDir % ensemble % _type % _data); 43 | 44 | /* Create a backup name */ 45 | bakname = str(format("%s/%s-%s-%s.bak") % outDir % ensemble % _type % _data); 46 | 47 | /* Determine if the file already exists */ 48 | exists_ = fs::exists(name); 49 | 50 | /* Has the file been prepared for writing? */ 51 | prepared_ = false; 52 | } 53 | 54 | /**************************************************************************//** 55 | * Constructor. 56 | * 57 | * Create a filename from a std::string. 58 | * 59 | * @param _name A file name. 60 | ******************************************************************************/ 61 | File::File(std::string _name) : name(_name), bakname() { 62 | 63 | } 64 | 65 | /**************************************************************************//** 66 | * Close the file. 67 | ******************************************************************************/ 68 | void File::close() { 69 | if (rwfile.is_open()) 70 | rwfile.close(); 71 | } 72 | 73 | /**************************************************************************//** 74 | * Open the file. 75 | * 76 | * @param mode A valid file rw mode 77 | ******************************************************************************/ 78 | void File::open(std::ios_base::openmode mode) { 79 | 80 | /* Convert the filename to a c std::string, and open the file */ 81 | rwfile.open(name.c_str(), mode); 82 | if (!rwfile) { 83 | std::cerr << "Unable to process file: " << name << std::endl; 84 | exit(EXIT_FAILURE); 85 | } 86 | } 87 | 88 | /**************************************************************************//** 89 | * Open the file. 90 | * 91 | * @param mode A valid file rw mode 92 | * @param _name A valid file name 93 | ******************************************************************************/ 94 | void File::open(std::ios_base::openmode mode, std::string _name) { 95 | 96 | /* Convert the filename to a c std::string, and open the file */ 97 | rwfile.open(_name.c_str(), mode); 98 | if (!rwfile) { 99 | std::cerr << "Unable to process file: " << _name << std::endl; 100 | exit(EXIT_FAILURE); 101 | } 102 | } 103 | 104 | /**************************************************************************//** 105 | * Reset a file. 106 | * 107 | * This method is used to prepare a file for writing that is meant to be 108 | * overwritten. In order to be safe, we write to a .bak version of the file. 109 | ******************************************************************************/ 110 | void File::reset() { 111 | 112 | /* Close the current file */ 113 | close(); 114 | 115 | /* Open a backup file and replace any content if it exists */ 116 | open(std::ios::out|std::ios::trunc,bakname); 117 | 118 | /* Write the generic header to the file */ 119 | } 120 | 121 | /**************************************************************************//** 122 | * Rename a file. 123 | * 124 | * After we have performed a write to a .bak file, we rename it to .dat 125 | ******************************************************************************/ 126 | void File::rename() { 127 | 128 | close(); 129 | 130 | /* Perform the rename */ 131 | fs::rename(bakname.c_str(), name.c_str()); 132 | } 133 | 134 | // --------------------------------------------------------------------------- 135 | // --------------------------------------------------------------------------- 136 | // COMMUNICATOR CLASS -------------------------------------------------------- 137 | // --------------------------------------------------------------------------- 138 | // --------------------------------------------------------------------------- 139 | 140 | /**************************************************************************//** 141 | * Initialize all input/output files. 142 | * 143 | * If we are in the grand-canonical ensemble, then initialize all output 144 | * files with the form gce-xxx-T-L-mu-tau-ID.dat, whereas if we are in 145 | * the canonical ensemble we label as ce-xxx-T-N-n-tau-ID.dat. 146 | ******************************************************************************/ 147 | void Communicator::init(double _tau, bool outputWorldline, std::string _initName, 148 | std::string _fixedName) 149 | { 150 | 151 | /* Set local class variables */ 152 | baseDir = "OUTPUT"; 153 | initName = _initName; 154 | fixedName = _fixedName; 155 | tau = _tau; 156 | 157 | 158 | /* Determine the ensemble and unique parameter file std::string or dataname */ 159 | if (!constants()->canonical()) { 160 | ensemble = "gce"; 161 | dataName = str(format("%06.3f-%07.3f-%+08.3f-%7.5f-%s") % constants()->T() 162 | % constants()->L() % constants()->mu() % tau % constants()->id()); 163 | } 164 | else { 165 | ensemble = "ce"; 166 | dataName = str(format("%06.3f-%04d-%06.3f-%7.5f-%s") % constants()->T() 167 | % constants()->initialNumParticles() 168 | % (1.0*constants()->initialNumParticles()/constants()->V()) 169 | % tau % constants()->id()); 170 | } 171 | 172 | /* Check to make sure the correct directory structure for OUTPUT files is 173 | * in place. */ 174 | fs::path outputPath(baseDir); 175 | fs::create_directory(outputPath); 176 | 177 | /* If we have cylinder output files, add the required directory. */ 178 | if (constants("external").find("tube") != std::string::npos) { 179 | fs::path cylPath(baseDir + "/CYLINDER"); 180 | fs::create_directory(cylPath); 181 | } 182 | 183 | /* A header line for the files */ 184 | header = str(format("# PIMCID: %s\n") % constants()->id()); 185 | 186 | /* Depending on whether or not we are restarting the simulations, the open mode 187 | * changes. */ 188 | if (constants()->restart()) { 189 | mode = std::ios::out|std::ios::app; 190 | } 191 | else { 192 | mode = std::ios::out; 193 | } 194 | } 195 | 196 | /**************************************************************************//** 197 | * Initialze a file based on a type. 198 | ******************************************************************************/ 199 | void Communicator::initFile(std::string type) { 200 | 201 | /* Check a possible initialization file */ 202 | if (type.find("init") != std::string::npos ) { 203 | 204 | /* We need to determine the name of the state file. i.e. does it need 205 | * an integer appended after it? */ 206 | std::string stateName = "state"; 207 | 208 | /* If we have a numerical label, append it to the name of state */ 209 | if (type != "init") 210 | stateName += stateName.substr(4, std::string::npos); 211 | 212 | /* There are only two reasons we would need an init file, either we are 213 | * restarting, or starting from a given initialization file */ 214 | if (constants()->restart()) 215 | file_.insert(type, new File(stateName,dataName,ensemble,baseDir)); 216 | else 217 | file_.insert(type, new File(initName)); 218 | 219 | file_.at(type).open(std::ios::in); 220 | } 221 | /* Initialize a possible fixed coordinate file */ 222 | else if (type == "fixed") { 223 | file_.insert(type,new File(fixedName)); 224 | file_.at(type).open(std::ios::in); 225 | } 226 | /* All other file types act normally */ 227 | else { 228 | std::string outDir = baseDir; 229 | std::string ctype = type; 230 | 231 | /* Deal with possible cylinder output files */ 232 | if (type.find("cyl_") != std::string::npos) { 233 | outDir = baseDir + "/CYLINDER"; 234 | ctype.erase(0,4); 235 | } 236 | 237 | /* Construct the file and open it */ 238 | file_.insert(type, new File(ctype,dataName,ensemble,outDir)); 239 | file_.at(type).open(mode); 240 | 241 | /* Write the header line if the file doesn't exist */ 242 | if (!file_.at(type).exists()) 243 | file_.at(type).stream() << header; 244 | } 245 | } 246 | 247 | /**************************************************************************//** 248 | * Update the data name and rename any existing files 249 | ******************************************************************************/ 250 | void Communicator::updateNames() { 251 | 252 | /* We create a new dataName based on the posibility of updated paramters. */ 253 | 254 | /* Determine the ensemble and unique parameter file std::string or dataname */ 255 | if (!constants()->canonical()) { 256 | dataName = str(format("%06.3f-%07.3f-%+08.3f-%7.5f-%s") % constants()->T() 257 | % constants()->L() % constants()->mu() % tau % constants()->id()); 258 | } 259 | else { 260 | dataName = str(format("%06.3f-%04d-%06.3f-%7.5f-%s") % constants()->T() 261 | % constants()->initialNumParticles() 262 | % (1.0*constants()->initialNumParticles()/constants()->V()) 263 | % tau % constants()->id()); 264 | } 265 | 266 | /* Perform the rename for each file in the map */ 267 | for (auto const& [key, filePtr] : file_) 268 | { 269 | 270 | /* We don't want to update init or fixed files */ 271 | if ( (key.find("init") == std::string::npos) && 272 | (key.find("fixed") == std::string::npos) ) { 273 | 274 | std::string oldName(filePtr->name); 275 | 276 | /* Replace with the new data name, we need to do this for both name and 277 | * backup name. */ 278 | filePtr->name.replace(filePtr->name.end()-dataName.length()-4,filePtr->name.end()-4,dataName); 279 | filePtr->bakname.replace(filePtr->bakname.end()-dataName.length()-4,filePtr->bakname.end()-4,dataName); 280 | 281 | /* Perform the rename */ 282 | fs::rename(oldName.c_str(), filePtr->name.c_str()); 283 | } 284 | } 285 | } 286 | /**************************************************************************//** 287 | * This public method gets an instance of the Communicator object, only one 288 | * can ever exist at a time. 289 | ******************************************************************************/ 290 | Communicator* Communicator::getInstance () 291 | { 292 | static Communicator inst; 293 | return &inst; 294 | } 295 | -------------------------------------------------------------------------------- /include/action.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file action.h 3 | * @author Adrian Del Maestro 4 | * @date 10.14.2008 5 | * 6 | * @brief Action class definitions. 7 | */ 8 | 9 | #include "constants.h" 10 | 11 | #ifndef ACTION_H 12 | #define ACTION_H 13 | 14 | class Path; 15 | class PotentialBase; 16 | class LookupTable; 17 | class WaveFunctionBase; 18 | 19 | // ======================================================================== 20 | // ActionBase Class 21 | // ======================================================================== 22 | /** 23 | * Holds a base class that all action classes will be derived from. 24 | * 25 | * Implements the details of the action, including the potential and kinetic 26 | * pieces. Two types of actions, local and non-local derive from this base 27 | * class and the actually used actions then derive from these. 28 | */ 29 | class ActionBase { 30 | 31 | public: 32 | ActionBase (const Path &, LookupTable &, PotentialBase *, 33 | PotentialBase *, WaveFunctionBase *, bool _local=true, 34 | std::string _name="Base", double _endFactor=1.0, int _period=1); 35 | virtual ~ActionBase(); 36 | 37 | /** Returns the action name */ 38 | std::string getActionName () { return name; } 39 | 40 | /** The full kinetic Action */ 41 | double kineticAction (); 42 | /** The kinetic Action at a single slice */ 43 | double kineticAction (const beadLocator &); 44 | /** The kinetic Action for wlLength slices */ 45 | double kineticAction (const beadLocator &, int wlLength); 46 | 47 | /** The effective potential inter-ACTION for various pass conditions. */ 48 | virtual double potentialAction() {return 0.0;} 49 | virtual double potentialAction (const beadLocator &, const beadLocator &); 50 | virtual double potentialAction (const beadLocator &) { return 0.0; } 51 | 52 | /* The bare potential action and its correction */ 53 | virtual double barePotentialAction (const beadLocator &) { return 0.0; } 54 | virtual double potentialActionCorrection (const beadLocator &) {return 0.0; } 55 | virtual double potentialActionCorrection (const beadLocator &, const beadLocator &) { return 0.0; } 56 | 57 | /* Various derivatives of the potential action */ 58 | virtual double derivPotentialActionTau (int) { return 0.0; } 59 | virtual double derivPotentialActionLambda (int) { return 0.0; } 60 | virtual double secondderivPotentialActionTau (int) { return 0.0; } 61 | 62 | /* Various derivatives of the potential action with a cutoff */ 63 | virtual double derivPotentialActionTau (int,double) { return 0.0; } 64 | virtual double derivPotentialActionLambda (int,double) { return 0.0; } 65 | 66 | /* gradient of the potential action */ 67 | virtual dVec gradPotentialAction(int) { return dVec{}; } 68 | 69 | /* r \dot gradU -> for virial estimator. 70 | * It is necessary to split the terms in order to compute 71 | * the specific heat efficiently.*/ 72 | virtual double rDOTgradUterm1(int) { return 0.0; } 73 | virtual double rDOTgradUterm2(int) { return 0.0; } 74 | 75 | /* (r-R) \dot gradU -> for centroid virial estimator. 76 | * It is necessary to split the terms in order to compute 77 | * the specific heat efficiently.*/ 78 | virtual double deltaDOTgradUterm1(int) { return 0.0; } 79 | virtual double deltaDOTgradUterm2(int) { return 0.0; } 80 | 81 | /* return virial kinetic energy estimator term */ 82 | virtual double virKinCorr(int) { return 0.0; } 83 | 84 | /* The bare local potential at a single time slice */ 85 | virtual std::array potential(int) { return {0.0, 0.0}; } 86 | virtual double potential(int,double) { return 0.0; } 87 | 88 | /** The public method that sets the tau scaling factor. */ 89 | void setShift(int _shift) { shift = _shift; } 90 | 91 | /** Get the tau scaling factor. */ 92 | int getShift() { return shift; } 93 | 94 | /** The free-particle density matrix */ 95 | double rho0(const dVec&, const dVec&, int); 96 | double rho0(const beadLocator&, const beadLocator&, int); 97 | double rho0(const dVec&, const int); 98 | 99 | /** The ensemble particle number weighting factor */ 100 | double ensembleWeight(const int); 101 | 102 | /** Is the action local in imaginary time? */ 103 | const bool local; 104 | 105 | /* The period of the action */ 106 | const int period; 107 | 108 | PotentialBase *externalPtr; ///< The external potential 109 | PotentialBase *interactionPtr; ///< The interaction potential 110 | 111 | DynamicArray sepHist; ///< A histogram of separations 112 | DynamicArray cylSepHist; ///< A histogram of separations for a cylinder 113 | 114 | protected: 115 | std::string name; ///< The name of the action 116 | 117 | LookupTable &lookup; ///< We need a non-constant reference for updates 118 | const Path &path; ///< A reference to the paths 119 | WaveFunctionBase *waveFunctionPtr; ///< A pointer to a trial wave function object 120 | double endFactor; ///< Mutiplictive factor of the potential action on ends 121 | 122 | int shift; ///< The scaling factor for tau 123 | 124 | /* These definitions are needed for weighting in the canonical ensemble */ 125 | bool canonical; ///< Are we in the canonical ensemble? 126 | int numBeads0; ///< The target number of beads 127 | bool window; // Whether or not to force particle numberin to window 128 | int windowWidth; // Half width of particle number window 129 | bool gaussianEnsemble; // Whether or not to use gaussian ensemble weight 130 | double gaussianEnsembleSD; // Standard deviation of guassian ensemble weight 131 | 132 | /** The local shifted value of tau. */ 133 | double tau() {return shift * constants()->tau();} 134 | 135 | beadLocator bead2,bead3; // Bead indexers 136 | dVec sep,sep2; // The spatial separation between beads. 137 | double dSep; // The discretization for the separation histogram 138 | double dPerSep; // The PBC discretization for the separation histogram 139 | 140 | /* Update the separation histogram */ 141 | void updateSepHist(const dVec &); 142 | }; 143 | 144 | // ======================================================================== 145 | // LocalAction Class 146 | // ======================================================================== 147 | /** 148 | * A base class to be inherited by actions that are local in imaginary time. 149 | * 150 | */ 151 | class LocalAction : public ActionBase { 152 | 153 | public: 154 | LocalAction (const Path &, LookupTable &, PotentialBase *, 155 | PotentialBase *, WaveFunctionBase *, const std::array&, 156 | const std::array&, bool _local=true, std::string _name="Local", 157 | double _endFactor=1.0, int _period=1); 158 | virtual ~LocalAction(); 159 | 160 | /* The potential action */ 161 | double potentialAction (); 162 | double potentialAction (const beadLocator &); 163 | 164 | /* The bare potential action and its correction */ 165 | double barePotentialAction (const beadLocator &); 166 | double potentialActionCorrection (const beadLocator &); 167 | double potentialActionCorrection (const beadLocator &, const beadLocator &); 168 | 169 | /* Various derivatives of the potential action */ 170 | double derivPotentialActionTau (int); 171 | double derivPotentialActionLambda (int); 172 | double secondderivPotentialActionTau (int); 173 | double derivPotentialActionTau (int,double); 174 | double derivPotentialActionLambda (int,double); 175 | 176 | /* gradient of the potential action */ 177 | virtual dVec gradPotentialAction(int slice) { return gradU(slice); } 178 | 179 | /* R \dot gradU -> for virial estimators */ 180 | double rDOTgradUterm1(int); 181 | double rDOTgradUterm2(int); 182 | 183 | /* delta \dot gradU -> for centroid virial estimators */ 184 | virtual double deltaDOTgradUterm1(int slice) { return deltadotgradUterm1(slice); } 185 | virtual double deltaDOTgradUterm2(int slice) { return deltadotgradUterm2(slice); } 186 | 187 | /* Returns virial kinetic energy correction term. */ 188 | virtual double virKinCorr(int slice) { return virialKinCorrection(slice); } 189 | 190 | /* The bare local potential at a single time slice */ 191 | virtual std::array potential(int slice) { return V(slice); } 192 | virtual double potential(int slice, double maxR) { return V(slice,maxR); } 193 | 194 | protected: 195 | int eo; ///< Is a slice even or odd? 196 | 197 | std::array VFactor; ///< The even/odd slice potential factor 198 | std::array gradVFactor; ///< The even/odd slice correction factor 199 | 200 | /* The full potential for a single bead and all beads at a single 201 | * time slice. */ 202 | double V(const beadLocator&); 203 | double V(const int, const double); 204 | 205 | /* For the potential at a given time slice we separate the interaction 206 | * and potential parts */ 207 | std::array V(const int); 208 | 209 | /* The gradient of the potential squared for a single bead and all beads 210 | * at a single time slice. */ 211 | double gradVSquared(const beadLocator&); 212 | double gradVSquared(const int); 213 | double gradVSquared(const int, const double); 214 | 215 | /* The full potential with the NN lookup table for a single bead and all 216 | * beads at a single time slice. */ 217 | double Vnn(const beadLocator&); 218 | double Vnn(const int); 219 | 220 | /* The bare potential action for a trajectory */ 221 | double bareUnn(const beadLocator &, const beadLocator &); 222 | 223 | /* The gradient of the potential squared for a single bead using the 224 | * nearest neighbor lookup table */ 225 | double gradVnnSquared(const beadLocator&); 226 | 227 | /* gradient and Laplacian of potential energy */ 228 | dVec gradientV(const int); 229 | 230 | /* T-matrix needed for grad((gradV)^2) */ 231 | dMat tMatrix(const int); 232 | 233 | /* r \dot gradU -> for virial estimator */ 234 | double RdotgradUterm1(const int); 235 | double RdotgradUterm2(const int); 236 | 237 | /* delta \dot gradU -> for centroid virial estimator */ 238 | double deltadotgradUterm1(const int); 239 | double deltadotgradUterm2(const int); 240 | 241 | /* virial kinetic energy term */ 242 | double virialKinCorrection(const int); 243 | 244 | /* gradient of potential action */ 245 | dVec gradU(const int); 246 | 247 | }; 248 | 249 | // ======================================================================== 250 | // NonLocalAction Class 251 | // ======================================================================== 252 | /** 253 | * A base class to be inherited by actions that are non-local in imaginary 254 | * time. 255 | * 256 | * @see Section IV.F in D. M. Ceperley, Rev. Mod. Phys. 67, 279–355 (1995). 257 | */ 258 | class NonLocalAction : public ActionBase { 259 | 260 | public: 261 | NonLocalAction (const Path &, LookupTable &, PotentialBase *, 262 | PotentialBase *, WaveFunctionBase *, bool _local=false, 263 | std::string _name="Non-local"); 264 | virtual ~NonLocalAction(); 265 | 266 | /* The potential Action */ 267 | double potentialAction (); 268 | double potentialAction (const beadLocator &); 269 | 270 | /* Derivatives of the potential action */ 271 | double derivPotentialActionTau (int); 272 | double derivPotentialActionLambda (int); 273 | 274 | /* The bare local external and interaction potential at a single time slice */ 275 | virtual std::array potential(int slice) { return U(slice); } 276 | 277 | protected: 278 | std::array U(int); 279 | 280 | private: 281 | std::vector NNbead; //Records which beads where already visited for NN operation 282 | }; 283 | #endif 284 | -------------------------------------------------------------------------------- /include/path.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file path.h 3 | * @author Adrian Del Maestro 4 | * @date 10.14.2008 5 | * 6 | * @brief Path class definition. 7 | */ 8 | 9 | #ifndef PATH_H 10 | #define PATH_H 11 | 12 | #include "common.h" 13 | #include "constants.h" 14 | #include "container.h" 15 | #include "worm.h" 16 | 17 | class LookupTable; 18 | 19 | // ======================================================================== 20 | // Path Class 21 | // ======================================================================== 22 | /** 23 | * The space-time trajectories. 24 | * 25 | * Holds the actual particle wordlines, consisting of a fixed number of 26 | * time slices for each particle with periodic boundary conditions in 27 | * imaginary time. 28 | */ 29 | class Path { 30 | 31 | public: 32 | Path (const Container *, LookupTable &, int, const DynamicArray&, int numberBroken = 0); 33 | ~Path(); 34 | 35 | /* Path* clone() const{ return new Path(*this); } */ 36 | 37 | const int numTimeSlices; ///< A local constant copy of the number of time slices 38 | int breakSlice; ///< The location of the break in the path (0=>no break) 39 | std::vector brokenWorldlinesL; ///< A list of particles with broken worldlines on left of break 40 | std::vector brokenWorldlinesR; ///< A list of particles with broken worldlines on right of break 41 | std::vector closedWorldlines; ///< A list of particles with closed worldlines on left of break 42 | 43 | const Container *boxPtr; ///< A constant reference to the container class 44 | Worm worm; ///< Details on the worm 45 | 46 | LookupTable &lookup; ///< A reference to the nearest neighbor lookup table. 47 | 48 | DynamicArray numBeadsAtSlice; ///< The number of active beads at a given time slice 49 | 50 | /** Get the size of the worldline array */ 51 | int getNumParticles() const {return beads.extents()[1];} 52 | 53 | /** The number of active particles */ 54 | int getTrueNumParticles() const {return ( worm.getNumBeadsOn() / numTimeSlices );} 55 | 56 | /** Operator Overloading to skip having to specifically grab .beads */ 57 | const dVec& operator() (int slice, int ptcl) const { 58 | PIMC_ASSERT(slice>=0 && slice < numTimeSlices); 59 | return beads(slice,ptcl); } 60 | /** Operator Overloading to skip having to specifically grab .beads */ 61 | dVec& operator() (int slice, int ptcl) { 62 | PIMC_ASSERT(slice>=0 && slice < numTimeSlices); 63 | return beads(slice,ptcl); } 64 | /** Operator Overloading to skip having to specifically grab .beads */ 65 | const dVec& operator() (const beadLocator &beadIndex) const { 66 | PIMC_ASSERT(beadIndex[0]>=0 && beadIndex[0]=0 && beadIndex[0] void printLinks(Tstream &); 87 | 88 | /** Output the world-line configurations in a generic format */ 89 | void outputConfig(int) const; 90 | 91 | /** Move one link forward in imaginary time */ 92 | beadLocator& next(int slice, int ptcl) {return nextLink(slice,ptcl);} 93 | /** Move one link forward in imaginary time */ 94 | const beadLocator& next(int slice, int ptcl) const {return nextLink(slice,ptcl);} 95 | /** Move one link forward in imaginary time */ 96 | beadLocator& next(const beadLocator &beadIndex) {return nextLink(beadIndex);} 97 | /** Move one link forward in imaginary time */ 98 | const beadLocator& next(const beadLocator &beadIndex) const {return nextLink(beadIndex);} 99 | 100 | /** Move one link backward in imaginary time */ 101 | beadLocator& prev(int slice, int ptcl) {return prevLink(slice,ptcl);} 102 | /** Move one link backward in imaginary time */ 103 | const beadLocator& prev(int slice, int ptcl) const {return prevLink(slice,ptcl);} 104 | /** Move one link backward in imaginary time */ 105 | beadLocator& prev(const beadLocator &beadIndex) {return prevLink(beadIndex);} 106 | /** Move one link backward in imaginary time */ 107 | const beadLocator& prev(const beadLocator &beadIndex) const {return prevLink(beadIndex);} 108 | 109 | /** Move an integer number of links forward in imaginary time */ 110 | beadLocator next(int,int,int) const; 111 | beadLocator next(const beadLocator&,int) const; 112 | 113 | /** Move an integer number of links backward in imaginary time */ 114 | beadLocator prev(int,int,int) const; 115 | beadLocator prev(const beadLocator&,int) const; 116 | 117 | /** Add a bead to the worldline configuration at a given slice */ 118 | beadLocator addBead(const int, const dVec &); 119 | /** Add a bead at the next time slice */ 120 | beadLocator addNextBead(const beadLocator&, const dVec &); 121 | /** Add a bead at the previous time slice */ 122 | beadLocator addPrevBead(const beadLocator&, const dVec &); 123 | 124 | /** Remove a bead from the world-line configuration */ 125 | void delBead(const beadLocator&); 126 | /** Delete a bead and move forwards */ 127 | beadLocator delBeadGetNext(const beadLocator&); 128 | /** Delete a bead and move backwards */ 129 | beadLocator delBeadGetPrev(const beadLocator&); 130 | 131 | /** Break the link to right of bead **/ 132 | void breakLink(const beadLocator&); 133 | /** Make a link between beads **/ 134 | void makeLink(const beadLocator&,const beadLocator&); 135 | /** Break the link to right of bead t center slice AND update lists **/ 136 | void removeCenterLink(const beadLocator&); 137 | /** Make a link between beads at center slice AND update lists **/ 138 | void addCenterLink(const beadLocator&,const beadLocator&); 139 | /** Checks to see if worldline is broken**/ 140 | bool isBroken(const beadLocator&) const; 141 | /** Returns factor for broken worldines**/ 142 | double breakFactor(const beadLocator&,const beadLocator&) const; 143 | /** Checks to see if bead is in subregion A/B at break slice + 1 **/ 144 | bool inSubregionA(const beadLocator&) const; 145 | bool inSubregionB(const beadLocator&) const; 146 | /** Check if only subregion worldlines are broken, for debugging **/ 147 | bool checkSubregionLinks() const; 148 | 149 | /** Update the position of a bead in the worldine configuration */ 150 | void updateBead(const beadLocator&, const dVec&); 151 | 152 | /** Used when debugging worm configurations */ 153 | void printWormConfig(DynamicArray &); 154 | 155 | /** Initialize any loaded state by left packing the array */ 156 | void leftPack(); 157 | 158 | /** Reset broken/closed worldline std::vectors **/ 159 | void resetBrokenClosedVecs(); 160 | 161 | private: 162 | friend class PathIntegralMonteCarlo; // Friends for I/O 163 | 164 | DynamicArray beads; // The wordline array 165 | DynamicArray prevLink, nextLink; // Bead connection matrices 166 | 167 | beadLocator lastBeadIndex; // Holds the index of the last bead on a slice 168 | }; 169 | 170 | /* inline Path* new_clone(Path const& other){ */ 171 | /* return other.clone(); */ 172 | /* } */ 173 | 174 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 175 | // INLINE FUNCTION DEFINITIONS 176 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 177 | 178 | /** Return the separation std::vector between two particles in the same timeslice */ 179 | inline dVec Path::getSeparation(const beadLocator &bead1, const beadLocator &bead2) const { 180 | dVec sep; 181 | sep = (*this)(bead1) - (*this)(bead2); 182 | boxPtr->putInBC(sep); 183 | return sep; 184 | } 185 | 186 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 187 | 188 | /** Return the velocity between two time slices of a given particle as a ndim-vector */ 189 | inline dVec Path::getVelocity (const beadLocator &beadIndex) const { 190 | dVec vel; 191 | 192 | constexpr std::array compareArr = { XXX, XXX }; 193 | if (all(beadIndex, compareArr) || all(next(beadIndex), compareArr)) { 194 | vel.fill(0.0); 195 | return (vel); 196 | } 197 | 198 | /* Calculate the 'velocity' and implement periodic boundary conditions */ 199 | vel = beads(next(beadIndex)) - beads(beadIndex); 200 | boxPtr->putInBC(vel); 201 | 202 | return (vel); 203 | } 204 | 205 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 206 | 207 | /** Return the pointer to the first element in the beads array */ 208 | inline auto Path::get_beads_data_pointer() const { 209 | return (*this).beads.data(); 210 | } 211 | 212 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 213 | 214 | /** Return the extents of the beads array */ 215 | inline auto Path::get_beads_extents() const { 216 | return (*this).beads.extents(); 217 | } 218 | 219 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 220 | 221 | /** Move an integer number of links forward in imaginary time */ 222 | inline beadLocator Path::next(int slice, int ptcl, int numLinks) const { 223 | PIMC_ASSERT(slice>=0 && slice=0); 224 | beadLocator bI{slice,ptcl}; 225 | for (int m = 0; m < numLinks; m++) 226 | bI = next(bI); 227 | return bI; 228 | } 229 | 230 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 231 | 232 | /** Move an integer number of links forward in imaginary time */ 233 | inline beadLocator Path::next(const beadLocator &beadIndex, int numLinks) const { 234 | PIMC_ASSERT(beadIndex[0]>=0 && beadIndex[0]=0); 235 | beadLocator bI; 236 | bI = beadIndex; 237 | for (int m = 0; m < numLinks; m++) 238 | bI = next(bI); 239 | return bI; 240 | } 241 | 242 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 243 | 244 | /** Move an integer number of links backward in imaginary time */ 245 | inline beadLocator Path::prev(int slice, int ptcl, int numLinks) const { 246 | PIMC_ASSERT(slice>=0 && slice=0); 247 | beadLocator bI{slice,ptcl}; 248 | for (int m = 0; m < numLinks; m++) 249 | bI = prev(bI); 250 | return bI; 251 | } 252 | 253 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 254 | 255 | /** Move an integer number of links backward in imaginary time */ 256 | inline beadLocator Path::prev(const beadLocator &beadIndex, int numLinks) const { 257 | PIMC_ASSERT(beadIndex[0]>=0 && beadIndex[0]=0); 258 | beadLocator bI; 259 | bI = beadIndex; 260 | for (int m = 0; m < numLinks; m++) 261 | bI = prev(bI); 262 | return bI; 263 | } 264 | 265 | // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 266 | 267 | /** Output bead-link info, used for debugging.*/ 268 | template 269 | void Path::printLinks(Tstream &outStream) { 270 | int numParticles = getNumParticles(); 271 | for (int m = numTimeSlices-1; m >= 0; m--) { 272 | beadLocator beadIndex; 273 | for (int n = 0; n < numParticles; n++) { 274 | beadIndex = {m,n}; 275 | outStream << std::setw(2) << prevLink(beadIndex)[1] << " "; 276 | } 277 | 278 | outStream << "\t"; 279 | for (int n = 0; n < numParticles; n++) { 280 | beadIndex = {m,n}; 281 | outStream << std::setw(2) << nextLink(beadIndex)[1] << " "; 282 | } 283 | outStream << std::endl; 284 | } 285 | outStream << std::endl; 286 | } 287 | 288 | #endif 289 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18.1) 2 | 3 | project(pimc.e LANGUAGES CXX) 4 | 5 | # Must use GNUInstallDirs to install libraries into correct 6 | # locations on all platforms. 7 | include(GNUInstallDirs) 8 | 9 | # Set module path 10 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) 11 | 12 | # Set c++ standard 13 | set(CMAKE_CXX_STANDARD 17) 14 | set(CMAKE_STANDARD_REQUIRED TRUE) 15 | 16 | include(CheckCXXSourceCompiles) 17 | set(CMAKE_REQUIRED_FLAGS "-std=c++17") 18 | 19 | # --------- Filesystem Header Test --------- 20 | check_cxx_source_compiles( 21 | " 22 | #include 23 | int main() { 24 | std::filesystem::path p; 25 | return 0; 26 | } 27 | " HAVE_STD_FILESYSTEM) 28 | 29 | if (HAVE_STD_FILESYSTEM) 30 | message(STATUS "Found ") 31 | add_compile_definitions(USE_STD_FILESYSTEM) 32 | else() 33 | check_cxx_source_compiles( 34 | " 35 | #include 36 | int main() { 37 | std::experimental::filesystem::path p; 38 | return 0; 39 | } 40 | " HAVE_EXPERIMENTAL_FILESYSTEM) 41 | if (HAVE_EXPERIMENTAL_FILESYSTEM) 42 | message(STATUS "Found ") 43 | add_compile_definitions(USE_EXPERIMENTAL_FILESYSTEM) 44 | else() 45 | message(FATAL_ERROR "Neither nor are available") 46 | endif() 47 | endif() 48 | # --------- End Filesystem Header Test --------- 49 | 50 | # --------- MDSpan Header Test --------- 51 | # === 1) Check for standard === 52 | check_cxx_source_compiles( 53 | " 54 | #include 55 | int main() { 56 | std::mdspan> m(nullptr, 3, 4); 57 | (void)m; 58 | return 0; 59 | } 60 | " 61 | HAVE_STD_MDSPAN 62 | ) 63 | 64 | if(HAVE_STD_MDSPAN) 65 | message(STATUS "Found ") 66 | add_compile_definitions(USE_STD_MDSPAN) 67 | else() 68 | # === 2) Check for === 69 | check_cxx_source_compiles( 70 | " 71 | #include 72 | int main() { 73 | std::experimental::mdspan> m(nullptr, 3, 4); 74 | (void)m; 75 | return 0; 76 | } 77 | " 78 | HAVE_EXPERIMENTAL_MDSPAN 79 | ) 80 | 81 | if(HAVE_EXPERIMENTAL_MDSPAN) 82 | message(STATUS "Found ") 83 | add_compile_definitions(USE_EXPERIMENTAL_MDSPAN) 84 | else() 85 | # === 3) Download the single-header reference implementation === 86 | 87 | # (A) Define where to place the reference header 88 | set(REFERENCE_MDSPAN_NAME "mdspan.h") 89 | set(REFERENCE_MDSPAN_BINARY "${CMAKE_BINARY_DIR}/mdspan_downloaded.hpp") 90 | set(REFERENCE_MDSPAN_INSTALL "${CMAKE_CURRENT_SOURCE_DIR}/include/${REFERENCE_MDSPAN_NAME}") 91 | 92 | # (B) Download using CMake's file(DOWNLOAD) command. 93 | file(DOWNLOAD 94 | "https://raw.githubusercontent.com/kokkos/mdspan/single-header/mdspan.hpp" 95 | "${REFERENCE_MDSPAN_BINARY}" 96 | #EXPECTED_MD5 "72604e49ef586d353c51257eb30ff027" 97 | STATUS DOWNLOAD_STATUS 98 | ) 99 | 100 | list(GET DOWNLOAD_STATUS 0 DOWNLOAD_STATUS_CODE) 101 | list(GET DOWNLOAD_STATUS 1 DOWNLOAD_STATUS_STRING) 102 | 103 | if(NOT ${DOWNLOAD_STATUS_CODE} EQUAL 0) 104 | message(FATAL_ERROR "mdspan.hpp download failed: ${DOWNLOAD_STATUS_STRING}") 105 | endif() 106 | 107 | # (C) Create the local include directory if it doesn't exist 108 | file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include") 109 | 110 | # (D) Rename (copy) the downloaded file to mdspan.h in our include dir 111 | file(COPY 112 | "${REFERENCE_MDSPAN_BINARY}" 113 | DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/include" 114 | FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ 115 | ) 116 | 117 | file(RENAME 118 | "${CMAKE_CURRENT_SOURCE_DIR}/include/mdspan_downloaded.hpp" 119 | "${REFERENCE_MDSPAN_INSTALL}" 120 | ) 121 | 122 | # (E) Test if the newly downloaded file compiles 123 | check_cxx_source_compiles( 124 | " 125 | #include \"${REFERENCE_MDSPAN_INSTALL}\" 126 | int main() { 127 | std::mdspan> m(nullptr, 3, 4); 128 | (void)m; 129 | return 0; 130 | } 131 | " 132 | HAVE_REFERENCE_MDSPAN 133 | ) 134 | 135 | if(HAVE_REFERENCE_MDSPAN) 136 | message(STATUS "Downloaded and verified the mdspan reference implementation.") 137 | add_compile_definitions(USE_REFERENCE_MDSPAN) 138 | else() 139 | message(FATAL_ERROR 140 | "Neither , , nor the downloaded reference " 141 | "implementation compiled successfully.") 142 | endif() 143 | endif() 144 | endif() 145 | 146 | # --------- End MDSpan Header Test --------- 147 | 148 | # Enable GPU support 149 | set(GPU_COMPILE_FLAGS "") 150 | set(GPU_LINK_FLAGS "") 151 | set(GPU_BACKEND "none" CACHE STRING "Enable gpu accleration: cuda, hip, sycl, none (default: none)") 152 | if (NOT ${GPU_BACKEND} STREQUAL "none") 153 | add_definitions(-D USE_GPU=1) 154 | if (${GPU_BACKEND} STREQUAL "cuda") 155 | add_definitions(-D USE_CUDA=1) 156 | set(CMAKE_CUDA_STANDARD 17) 157 | set(CMAKE_CUDA_STANDARD_REQUIRED TRUE) 158 | if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) 159 | set(CMAKE_CUDA_ARCHITECTURES 80) 160 | endif() 161 | message("CUDA architectures set to ${CMAKE_CUDA_ARCHITECTURES}.") 162 | enable_language(CUDA) 163 | include_directories("${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}") 164 | elseif(${GPU_BACKEND} STREQUAL "hip") 165 | add_definitions(-D USE_HIP=1) 166 | elseif(${GPU_BACKEND} STREQUAL "sycl") 167 | add_definitions(-D USE_SYCL=1) 168 | if (NOT SYCL_FLAGS) 169 | list(APPEND GPU_COMPILE_FLAGS 170 | "-fsycl" 171 | "-fsycl-enable-function-pointers" 172 | ) 173 | list(APPEND GPU_LINK_FLAGS 174 | "-fsycl" 175 | "-fsycl-enable-function-pointers" 176 | ) 177 | else() 178 | list(APPEND GPU_COMPILE_FLAGS 179 | ${SYCL_FLAGS} 180 | ) 181 | list(APPEND GPU_LINK_FLAGS 182 | ${SYCL_FLAGS} 183 | ) 184 | endif() 185 | else() 186 | message(FATAL_ERROR "Unknown GPU implementation '${GPU_BACKEND}'," 187 | " please select from 'cuda, hip, sycl, none'.") 188 | endif() 189 | 190 | # Set number of threads per block 191 | set(GPU_BLOCK_SIZE "1024" CACHE STRING "Set gpu block size (default: 1024)") 192 | add_definitions(-D GPU_BLOCK_SIZE=${GPU_BLOCK_SIZE}) 193 | 194 | # Set sub-group size (warpsize/wavefront/SIMD lanes/etc.) 195 | if(${GPU_BACKEND} STREQUAL "hip") 196 | set(SUB_GROUP_SIZE "64" CACHE STRING "Set sub-group size (default: 32)") 197 | message("HIP detected. Set SUB_GROUP_SIZE to ${SUB_GROUP_SIZE}.") 198 | else() 199 | set(SUB_GROUP_SIZE "32" CACHE STRING "Set sub-group size (default: 32)") 200 | endif() 201 | add_definitions(-D SUB_GROUP_SIZE=${SUB_GROUP_SIZE}) 202 | 203 | # Set number of GPU streams 204 | set(MAX_GPU_STREAMS "1" CACHE STRING "Set number of gpu streams (default: 1)") 205 | add_definitions(-D MAX_GPU_STREAMS=${MAX_GPU_STREAMS}) 206 | endif() 207 | 208 | # Check for static build 209 | if(STATIC) 210 | message("Static build specified, setting library suffixes to ${CMAKE_STATIC_LIBRARY_SUFFIX}.") 211 | set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) 212 | set(BUILD_SHARED_LIBS OFF) 213 | list(APPEND CMAKE_EXE_LINKER_FLAGS "-static") 214 | list(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG "-static") 215 | set(Boost_USE_STATIC_LIBS ON) 216 | endif() 217 | 218 | # Determine the dimension of space (default = 3) 219 | if (NOT NDIM) 220 | set(NDIM 3) 221 | endif() 222 | add_definitions(-D NDIM=${NDIM}) 223 | 224 | # Determine if we want to compile for boltzmannons 225 | if (BOLTZMANNONS) 226 | add_compile_definitions(BOLTZMANNONS) 227 | endif() 228 | 229 | # Set default build flags 230 | if (NOT DEFAULT_CXX_FLAGS) 231 | set(DEFAULT_CXX_FLAGS "-Wall -fno-math-errno -O3") 232 | #set(DEFAULT_CXX_FLAGS "-march=native -Wall -fno-math-errno -O3") 233 | endif() 234 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DEFAULT_CXX_FLAGS}") 235 | 236 | # Determine executable name 237 | set(exe pimc.e) 238 | if(CMAKE_BUILD_TYPE MATCHES Debug) 239 | set(exe pimcd.e) 240 | elseif(CMAKE_BUILD_TYPE MATCHES PIGS) 241 | set(exe pigs.e) 242 | elseif(CMAKE_BUILD_TYPE MATCHES PIGSDebug) 243 | set(exe pigsd.e) 244 | endif() 245 | 246 | # Find source files ( better to list explicitly https://stackoverflow.com/questions/1027247/specify-source-files-globally-with-glob ) 247 | file( GLOB PIMC_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp ) 248 | if (${GPU_BACKEND} STREQUAL "cuda") 249 | file( GLOB PIMC_CUDA ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cu ) 250 | add_executable(${exe} ${PIMC_SRC} ${PIMC_CUDA}) 251 | set_target_properties( ${exe} PROPERTIES CUDA_SEPARABLE_COMPILATION ON) 252 | 253 | #if(APPLE) 254 | # # We need to add the path to the driver (libcuda.dylib) as an rpath, 255 | # # so that the static cuda runtime can find it at runtime. 256 | # set_property(TARGET ${exe} 257 | # PROPERTY 258 | # BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}) 259 | #endif() 260 | else() 261 | add_executable(${exe} ${PIMC_SRC}) 262 | endif() 263 | 264 | # Define headers for target 265 | target_include_directories(${exe} PUBLIC 266 | $ 267 | $ 268 | PRIVATE src) 269 | 270 | # Set debug flags 271 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DPIMC_DEBUG") 272 | 273 | # Add PIGS build mode 274 | set(CMAKE_CXX_FLAGS_PIGS "${CMAKE_CXX_FLAGS} -DPIGS") 275 | set(CMAKE_CXX_FLAGS_PIGS "${CMAKE_CXX_FLAGS_PIGS}" CACHE STRING 276 | "Flags used by the C++ compiler during PIGS builds." 277 | FORCE ) 278 | set(CMAKE_C_FLAGS_PIGS "" CACHE STRING 279 | "Flags used by the C compiler during PIGS builds." 280 | FORCE ) 281 | set(CMAKE_EXE_LINKER_FLAGS_PIGS 282 | "${CMAKE_EXE_LINKER_FLAGS}" CACHE STRING 283 | "Flags used for linking binaries during PIGS builds." 284 | FORCE ) 285 | set(CMAKE_SHARED_LINKER_FLAGS_PIGS 286 | "${CMAKE_SHARED_LINKER_FLAGS}" CACHE STRING 287 | "Flags used by the shared libraries linker during PIGS builds." 288 | FORCE ) 289 | 290 | # Add PIGSDEBUG build mode 291 | set(CMAKE_CXX_FLAGS_PIGSDEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DPIGS") 292 | set(CMAKE_CXX_FLAGS_PIGSDEBUG "${CMAKE_CXX_FLAGS_PIGSDEBUG}" CACHE STRING 293 | "Flags used by the C++ compiler during PIGS debug builds." 294 | FORCE ) 295 | set(CMAKE_C_FLAGS_PIGSDEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING 296 | "Flags used by the C compiler during PIGS debug builds." 297 | FORCE ) 298 | set(CMAKE_EXE_LINKER_FLAGS_PIGSDEBUG 299 | "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING 300 | "Flags used for linking binaries during PIGS debug builds." 301 | FORCE ) 302 | set(CMAKE_SHARED_LINKER_FLAGS_PIGSDEBUG 303 | "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING 304 | "Flags used by the shared libraries linker during PIGS debug builds." 305 | FORCE ) 306 | 307 | mark_as_advanced( 308 | CMAKE_CXX_FLAGS_PIGS 309 | CMAKE_C_FLAGS_PIGS 310 | CMAKE_EXE_LINKER_FLAGS_PIGS 311 | CMAKE_SHARED_LINKER_FLAGS_PIGS 312 | CMAKE_CXX_FLAGS_PIGSDEBUG 313 | CMAKE_C_FLAGS_PIGSDEBUG 314 | CMAKE_EXE_LINKER_FLAGS_PIGSDEBUG 315 | CMAKE_SHARED_LINKER_FLAGS_PIGSDEBUG ) 316 | 317 | if(NOT CMAKE_BUILD_TYPE) 318 | set(CMAKE_BUILD_TYPE None 319 | CACHE STRING "Choose the type of build : None Debug Release PIGS PIGSDebug." 320 | FORCE) 321 | endif() 322 | 323 | # Find Boost 324 | find_package( Boost 1.71.0 REQUIRED COMPONENTS program_options serialization ) 325 | 326 | # Add include directories 327 | include_directories( ${Boost_INCLUDE_DIRS} ) 328 | 329 | # Add compile flags 330 | target_compile_options(${exe} PRIVATE ${GPU_COMPILE_FLAGS}) 331 | target_link_options(${exe} PRIVATE ${GPU_LINK_FLAGS}) 332 | 333 | # Link libraries 334 | target_link_libraries (${exe} ${Boost_LIBRARIES} ) 335 | 336 | # Link filesystem library -lstdc++fs for old compilers 337 | if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)) 338 | message("Linking filesystem libraries -lstdc++fs for older compilers") 339 | target_link_libraries(${exe} stdc++fs) 340 | endif() 341 | 342 | # 'make install' to the correct locations (provided by GNUInstallDirs). 343 | install(TARGETS ${exe} EXPORT ${exe}Config 344 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 345 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 346 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # This is for Windows 347 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 348 | 349 | # This makes the project importable from the install directory 350 | # Put config file in per-project dir (name MUST match), can also 351 | # just go into 'cmake'. 352 | install(EXPORT ${exe}Config DESTINATION share/${exe}/cmake) 353 | 354 | # This makes the project importable from the build directory 355 | export(TARGETS ${exe} FILE ${exe}Config.cmake) 356 | 357 | # Unit tests 358 | # We need to make some of these 359 | enable_testing() 360 | -------------------------------------------------------------------------------- /include/constants.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file constants.h 3 | * @author Adrian Del Maestro 4 | * @date 03.17.2009 St Patrick's Day 5 | * 6 | * @brief ConstantParameters class definition. 7 | */ 8 | 9 | #ifndef CONSTANTS_H 10 | #define CONSTANTS_H 11 | 12 | #include "common.h" 13 | #include 14 | 15 | /* For generating a unique GUID */ 16 | #include 17 | #include 18 | #include 19 | 20 | namespace po = boost::program_options; 21 | 22 | // ======================================================================== 23 | // ConstantParameters Class 24 | // ======================================================================== 25 | /** 26 | * Constant simulation parameters. 27 | * 28 | * Holds a number of parameters that will need to be accessed throughout 29 | * the simulation and allows their access via the singleton design 30 | * pattern. 31 | * @see http://en.wikipedia.org/wiki/Singleton_pattern 32 | * 33 | * The design principle includes just passing through the 34 | * boost::propgram_options params object if the data is only minimally used 35 | * (e.g. in an object constructor) or setting an explicit constant if it is 36 | * used more frequently (e.g. temperature). 37 | */ 38 | class ConstantParameters 39 | { 40 | public: 41 | static ConstantParameters* getInstance(); 42 | 43 | void initConstants(po::variables_map &); 44 | 45 | /* All the get methods */ 46 | 47 | /** Safe way to access the command line parameters array */ 48 | template 49 | Type params(std::string parName) const { 50 | 51 | if (!params_[parName].empty()) 52 | return params_[parName].as(); 53 | else { 54 | std::cerr << std::endl << "ERROR: command line parameter " 55 | << parName << " is not set!" << std::endl; 56 | exit(EXIT_FAILURE); 57 | } 58 | } 59 | 60 | double T() const {return T_;} ///< Get temperature. 61 | double imagTimeLength() const { return imagTimeLength_;} ///< Get the extent in imaginary time. 62 | double mu() const {return mu_;} ///< Get chemical potential. 63 | double tau() const {return tau_;} ///< Get imaginary time step 64 | double m() const {return m_;} ///< Get mass. 65 | double lambda() const {return lambda_;} ///< Get lambda = hbar^2/(2mk_B) 66 | double rc() const {return rc_;} ///< Get potential cutoff 67 | double rc2() const {return rc2_;} ///< Get potential cutoff squared 68 | double C0() const {return C0_;} ///< Get worm factor C0 69 | double C() const {return C_;} ///< Get full worm constant 70 | double V() const {return V_;} ///< Get cell volume 71 | double L() const {return L_;} ///< Get maximum side length 72 | double comDelta() const {return comDelta_;} ///< Get center of mass shift 73 | double displaceDelta() const {return displaceDelta_;} ///< Get center of mass shift 74 | double aCC() const {return aCC_;} // The graphene/graphite carbon-carbon distance 75 | int virialWindow() const {return virialWindow_;} ///< Get centroid virial window size. 76 | 77 | /** Get deBroglie wavelength */ 78 | double dBWavelength() const {return dBWavelength_;} ///< Get deBroglie wavelength 79 | /** Get density matrix normalization factor */ 80 | double rho0Norm(int M, int d) const {return ( pow((4.0*M_PI*lambda_*M*tau_),-0.5*d));} 81 | /** Get (4lambda/tau)^{-1} */ 82 | double fourLambdaTauInv() const { return (0.25 / (lambda_ * tau_)); } 83 | 84 | /** Get the move attempt probability */ 85 | double attemptProb(std::string type) { 86 | if (attemptProb_.count(type)) 87 | return attemptProb_[type]; 88 | else { 89 | std::cerr << "Get: Attempt probability for " << type << " does not exist!" << std::endl; 90 | exit(EXIT_FAILURE); 91 | return 0.0; 92 | } 93 | } 94 | 95 | /* Set the move attempt probability */ 96 | void setAttemptProb(std::string type,double prob) { 97 | attemptProb_[type] = prob; 98 | /* if (attemptProb_.count(type)) */ 99 | /* attemptProb_[type] = prob; */ 100 | /* else { */ 101 | /* std::cerr << "Set: Attempt probability for " << type << " does not exist!" << std::endl; */ 102 | /* exit(EXIT_FAILURE); */ 103 | /* } */ 104 | } 105 | 106 | bool restart() const {return restart_;} ///< Get restart state 107 | bool wallClockOn() const {return wallClockOn_;} ///< Get wallclockOn 108 | uint32 wallClock() const {return wallClock_;} ///< Get wallclock limit 109 | bool canonical() const { return canonical_;} ///< Get ensemble 110 | bool window() const { return window_;} ///< Get window on/off 111 | bool startWithState() const { return startWithState_;} ///< Are we starting from a state? 112 | int windowWidth() const { return windowWidth_;} ///< Get window 1/2 width 113 | bool gaussianEnsemble() const { return gaussianEnsemble_;} ///< Get enesemble weight on/off 114 | double gaussianEnsembleSD() const { return gaussianEnsembleSD_;} ///< Get enesemble weight standard dev. 115 | bool varUpdates() const {return varUpdates_;} ///< Fixed or variable length diagonal updates 116 | 117 | int Mbar() {return Mbar_;} ///< Get Mbar 118 | int b() {return b_;} ///< Get bisection level 119 | int numTimeSlices() {return numTimeSlices_;} ///< Get number of time slices 120 | int initialNumParticles() { return initialNumParticles_;} ///< Get initial number of particles 121 | int maxWind() { return maxWind_;} ///< Get the maximum winding number sampled 122 | std::string id() {return id_;} ///< Get simulation UUID 123 | uint32 numEqSteps() {return numEqSteps_;} ///< Get the number of equilibration steps 124 | int numBroken() {return numBroken_;} //< Get number of broken paths 125 | double spatialSubregion() {return spatialSubregion_;} //< Get size of subregion 126 | bool spatialSubregionOn() {return spatialSubregionOn_;} //< Get subregion on/off 127 | int Npaths() {return Npaths_;} //< Get number of paths 128 | uint32 binSize() {return binSize_;} //< Get the number of measurments per bin. 129 | 130 | double endFactor() const {return endFactor_;} ///< Get end factor 131 | std::string actionType() const {return actionType_;} ///< Get wave action type 132 | std::string graphenelut3d_file_prefix() const {return graphenelut3d_file_prefix_;} ///< Get GrapheneLUT3D file prefix _serialized.{dat|txt} 133 | std::string wavevector() const {return wavevector_;} ///< Get wavevectors for scattering functions 134 | std::string wavevectorType() const {return wavevectorType_;} ///< Get wavevector types for scattering functions 135 | 136 | /* Set methods */ 137 | void setmu(double _mu) {mu_ = _mu;} ///< Set the value of the chemical potential 138 | void setCoMDelta(double _comDelta) {comDelta_ = _comDelta;} ///< Set the CoM move size 139 | void setDisplaceDelta(double _displaceDelta) {displaceDelta_ = _displaceDelta;} ///< Set the displace move size 140 | 141 | /* Increment/decrement methods */ 142 | void shiftC0(double frac) {C0_ += frac*C0_; getC();} ///< Shift the value of C0 143 | void setC0(double _C0) {C0_ = _C0; getC();} ///< Set the value of C0 144 | void getC() {C_ = C0_ / (1.0*Mbar_*numTimeSlices_*V_);} ///< Get the value of the worm constant 145 | void shiftCoMDelta(double frac) {comDelta_ += frac*comDelta_; } ///< Shift the CoM move size 146 | void shiftDisplaceDelta(double frac) {displaceDelta_ += frac*displaceDelta_; } ///< Shift the displace move size 147 | void shiftmu (double frac) { mu_ += frac; } ///< Shift the chemical potential 148 | 149 | bool saveStateFiles() { return saveStateFiles_;} ///< Are we saving states every MC bin? 150 | 151 | protected: 152 | ConstantParameters(); 153 | ConstantParameters(const ConstantParameters&); ///< Protected constructor 154 | ConstantParameters& operator= (const ConstantParameters&); ///< Overload Singleton equals 155 | 156 | private: 157 | po::variables_map params_; // Local copy of the full set of command line parameters 158 | 159 | double T_; // Temperature [K] 160 | double imagTimeLength_; // Temperature [K] 161 | double mu_; // Chemical Potential [K] 162 | double tau_; // Imaginary time step (tau = beta/numTimeSlices) 163 | double lambda_; // hbar^2 / (2*mass*k_B) [K A^2] 164 | double m_; // The particle mass 165 | double dBWavelength_; // Thermal de Broglie wavelength 166 | double comDelta_; // The size of center of mass move 167 | double displaceDelta_; // The size of the displace move shift 168 | 169 | double rc_; // The potential cutoff length 170 | double rc2_; // The potential cutoff length squared 171 | double C0_; // Worm probability constant [PRE 74, 036701 (2006)] 172 | double C_; // Worm normalization factor 173 | double V_; // The volume of the system 174 | double L_; // The linear 'length' of the system 175 | double aCC_; // The graphene/graphite carbon-carbon distance 176 | 177 | int Mbar_; // Maximum worm algorithm trial length 178 | int b_; // The maximum number of levels 179 | int numTimeSlices_; // Number of imaginary time slices 180 | int initialNumParticles_; // The initial number of particles 181 | int numBroken_; // The number of broken paths 182 | double spatialSubregion_; // The limits of the spatial sub region for EE 183 | bool spatialSubregionOn_; // True if using a spatial subregion for EE 184 | int Npaths_; // Number of paths used 185 | 186 | uint32 numEqSteps_; // Number of equilibration steps 187 | 188 | bool restart_; // Are we restarting the simulation 189 | uint32 wallClock_; // The wall clock limit in seconds 190 | bool wallClockOn_; // Is the wall clock on? 191 | bool canonical_; // Are we in the canonical ensemble? 192 | bool window_; // Are we using a particle number window? 193 | bool startWithState_; // Are we starting from a supplied state? 194 | int windowWidth_; // Half width of particle number window 195 | bool gaussianEnsemble_; // Are we using gaussian ensemble weight? 196 | double gaussianEnsembleSD_; // Standard deviation of ensemble weight 197 | bool varUpdates_; // Perform variable length diagonal updates 198 | 199 | std::string id_; // The unique simulation UUID 200 | // 201 | double endFactor_; // The multiplicative factor of the potential on end beads 202 | std::string actionType_; // The type of action 203 | 204 | int virialWindow_; // Window size for centroid virial estimator 205 | int maxWind_; // The maximum winding number sampled 206 | uint32 binSize_; // The number of measurments per bin. 207 | 208 | bool saveStateFiles_; // Are we saving a state file every MC bin? 209 | std::string graphenelut3d_file_prefix_; // GrapheneLUT3D file prefix _{V,gradV,grad2V}.npy 210 | std::string wavevector_; // Input for wavevectors 211 | std::string wavevectorType_; // Type of input for wavevectors 212 | 213 | std::map attemptProb_; // The move attempt probabilities 214 | }; 215 | 216 | /**************************************************************************//** 217 | * Global public access to the constants. 218 | ******************************************************************************/ 219 | inline ConstantParameters* constants() { 220 | ConstantParameters *temp = ConstantParameters::getInstance(); 221 | return temp; 222 | } 223 | 224 | template 225 | inline Type constants(std::string parName) { 226 | return ConstantParameters::getInstance()->params(parName); 227 | } 228 | 229 | #endif 230 | 231 | -------------------------------------------------------------------------------- /include/dynamic_array_math.h: -------------------------------------------------------------------------------- 1 | #ifndef DYNAMIC_ARRAY_MATH_H 2 | #define DYNAMIC_ARRAY_MATH_H 3 | 4 | #include "dynamic_array.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | //------------------------------------------------------------------------------ 14 | // Helper: Create a DynamicArray from a given extents array. 15 | //------------------------------------------------------------------------------ 16 | namespace dynamic_array_math { 17 | 18 | template 19 | DynamicArray create_dynamic_array_from_extents_impl( 20 | const std::array& extents, 21 | std::index_sequence) 22 | { 23 | // Unpack the extents into the DynamicArray constructor. 24 | return DynamicArray( extents[I]... ); 25 | } 26 | 27 | template 28 | DynamicArray create_dynamic_array_from_extents( 29 | const std::array& extents) 30 | { 31 | return create_dynamic_array_from_extents_impl( 32 | extents, std::make_index_sequence{}); 33 | } 34 | 35 | } // namespace dynamic_array_math 36 | 37 | //------------------------------------------------------------------------------ 38 | // Element-wise Operations 39 | //------------------------------------------------------------------------------ 40 | 41 | // Element-wise addition 42 | template 43 | auto operator+(const DynamicArray& a, const DynamicArray& b) 44 | -> DynamicArray::type, Rank> 45 | { 46 | if (a.extents() != b.extents()) 47 | throw std::invalid_argument("DynamicArray dimensions must match for addition."); 48 | using result_t = typename std::common_type::type; 49 | DynamicArray result = 50 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 51 | std::transform(a.begin(), a.end(), b.begin(), result.begin(), std::plus()); 52 | return result; 53 | } 54 | 55 | // Element-wise subtraction 56 | template 57 | auto operator-(const DynamicArray& a, const DynamicArray& b) 58 | -> DynamicArray::type, Rank> 59 | { 60 | if (a.extents() != b.extents()) 61 | throw std::invalid_argument("DynamicArray dimensions must match for subtraction."); 62 | using result_t = typename std::common_type::type; 63 | DynamicArray result = 64 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 65 | std::transform(a.begin(), a.end(), b.begin(), result.begin(), std::minus()); 66 | return result; 67 | } 68 | 69 | // Element-wise multiplication 70 | template 71 | auto operator*(const DynamicArray& a, const DynamicArray& b) 72 | -> DynamicArray::type, Rank> 73 | { 74 | if (a.extents() != b.extents()) 75 | throw std::invalid_argument("DynamicArray dimensions must match for element-wise multiplication."); 76 | using result_t = typename std::common_type::type; 77 | DynamicArray result = 78 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 79 | std::transform(a.begin(), a.end(), b.begin(), result.begin(), std::multiplies()); 80 | return result; 81 | } 82 | 83 | // Element-wise division 84 | template 85 | auto operator/(const DynamicArray& a, const DynamicArray& b) 86 | -> DynamicArray::type, Rank> 87 | { 88 | if (a.extents() != b.extents()) 89 | throw std::invalid_argument("DynamicArray dimensions must match for element-wise division."); 90 | using result_t = typename std::common_type::type; 91 | DynamicArray result = 92 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 93 | std::transform(a.begin(), a.end(), b.begin(), result.begin(), std::divides()); 94 | return result; 95 | } 96 | 97 | // Unary minus (element-wise negation) 98 | template 99 | auto operator-(const DynamicArray& a) 100 | -> DynamicArray 101 | { 102 | DynamicArray result = 103 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 104 | std::transform(a.begin(), a.end(), result.begin(), std::negate()); 105 | return result; 106 | } 107 | 108 | //------------------------------------------------------------------------------ 109 | // Compound Assignment Operators 110 | //------------------------------------------------------------------------------ 111 | 112 | // Compound assignment with another DynamicArray 113 | template 114 | DynamicArray& operator+=(DynamicArray& a, const DynamicArray& b) { 115 | if (a.extents() != b.extents()) 116 | throw std::invalid_argument("DynamicArray dimensions must match for addition assignment."); 117 | auto it_a = a.begin(); 118 | auto it_b = b.begin(); 119 | for (; it_a != a.end(); ++it_a, ++it_b) 120 | *it_a += *it_b; 121 | return a; 122 | } 123 | 124 | template 125 | DynamicArray& operator-=(DynamicArray& a, const DynamicArray& b) { 126 | if (a.extents() != b.extents()) 127 | throw std::invalid_argument("DynamicArray dimensions must match for subtraction assignment."); 128 | auto it_a = a.begin(); 129 | auto it_b = b.begin(); 130 | for (; it_a != a.end(); ++it_a, ++it_b) 131 | *it_a -= *it_b; 132 | return a; 133 | } 134 | 135 | template 136 | DynamicArray& operator*=(DynamicArray& a, const DynamicArray& b) { 137 | if (a.extents() != b.extents()) 138 | throw std::invalid_argument("DynamicArray dimensions must match for multiplication assignment."); 139 | auto it_a = a.begin(); 140 | auto it_b = b.begin(); 141 | for (; it_a != a.end(); ++it_a, ++it_b) 142 | *it_a *= *it_b; 143 | return a; 144 | } 145 | 146 | template 147 | DynamicArray& operator/=(DynamicArray& a, const DynamicArray& b) { 148 | if (a.extents() != b.extents()) 149 | throw std::invalid_argument("DynamicArray dimensions must match for division assignment."); 150 | auto it_a = a.begin(); 151 | auto it_b = b.begin(); 152 | for (; it_a != a.end(); ++it_a, ++it_b) 153 | *it_a /= *it_b; 154 | return a; 155 | } 156 | 157 | //------------------------------------------------------------------------------ 158 | // Scalar Operations 159 | //------------------------------------------------------------------------------ 160 | 161 | // Multiply DynamicArray by a scalar 162 | template 163 | auto operator*(const DynamicArray& a, const U& scalar) 164 | -> DynamicArray::type, Rank> 165 | { 166 | using result_t = typename std::common_type::type; 167 | DynamicArray result = 168 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 169 | std::transform(a.begin(), a.end(), result.begin(), 170 | [scalar](const T& x) { return x * scalar; }); 171 | return result; 172 | } 173 | 174 | // Multiply scalar by DynamicArray 175 | template 176 | auto operator*(const U& scalar, const DynamicArray& a) 177 | -> DynamicArray::type, Rank> 178 | { 179 | return a * scalar; 180 | } 181 | 182 | // Divide DynamicArray by a scalar 183 | template 184 | auto operator/(const DynamicArray& a, const U& scalar) 185 | -> DynamicArray::type, Rank> 186 | { 187 | using result_t = typename std::common_type::type; 188 | DynamicArray result = 189 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 190 | std::transform(a.begin(), a.end(), result.begin(), 191 | [scalar](const T& x) { return x / scalar; }); 192 | return result; 193 | } 194 | 195 | // Divide scalar by DynamicArray (element-wise: scalar divided by each element) 196 | template 197 | auto operator/(const U& scalar, const DynamicArray& a) 198 | -> DynamicArray::type, Rank> 199 | { 200 | using result_t = typename std::common_type::type; 201 | DynamicArray result = 202 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 203 | std::transform(a.begin(), a.end(), result.begin(), 204 | [scalar](const T& x) { return scalar / x; }); 205 | return result; 206 | } 207 | 208 | // Add scalar to DynamicArray 209 | template 210 | auto operator+(const DynamicArray& a, const U& scalar) 211 | -> DynamicArray::type, Rank> 212 | { 213 | using result_t = typename std::common_type::type; 214 | DynamicArray result = 215 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 216 | std::transform(a.begin(), a.end(), result.begin(), 217 | [scalar](const T& x) { return x + scalar; }); 218 | return result; 219 | } 220 | 221 | // Add DynamicArray to scalar 222 | template 223 | auto operator+(const U& scalar, const DynamicArray& a) 224 | -> DynamicArray::type, Rank> 225 | { 226 | return a + scalar; 227 | } 228 | 229 | // Subtract scalar from DynamicArray 230 | template 231 | auto operator-(const DynamicArray& a, const U& scalar) 232 | -> DynamicArray::type, Rank> 233 | { 234 | using result_t = typename std::common_type::type; 235 | DynamicArray result = 236 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 237 | std::transform(a.begin(), a.end(), result.begin(), 238 | [scalar](const T& x) { return x - scalar; }); 239 | return result; 240 | } 241 | 242 | // Subtract DynamicArray from scalar 243 | template 244 | auto operator-(const U& scalar, const DynamicArray& a) 245 | -> DynamicArray::type, Rank> 246 | { 247 | using result_t = typename std::common_type::type; 248 | DynamicArray result = 249 | dynamic_array_math::create_dynamic_array_from_extents(a.extents()); 250 | std::transform(a.begin(), a.end(), result.begin(), 251 | [scalar](const T& x) { return scalar - x; }); 252 | return result; 253 | } 254 | 255 | // Compound assignment for scalar addition 256 | template 257 | DynamicArray& operator+=(DynamicArray& a, const U& scalar) { 258 | for (auto& x : a) 259 | x += scalar; 260 | return a; 261 | } 262 | 263 | // Compound assignment for scalar subtraction 264 | template 265 | DynamicArray& operator-=(DynamicArray& a, const U& scalar) { 266 | for (auto& x : a) 267 | x -= scalar; 268 | return a; 269 | } 270 | 271 | // Compound assignment for scalar multiplication 272 | template 273 | DynamicArray& operator*=(DynamicArray& a, const U& scalar) { 274 | for (auto& x : a) 275 | x *= scalar; 276 | return a; 277 | } 278 | 279 | // Compound assignment for scalar division 280 | template 281 | DynamicArray& operator/=(DynamicArray& a, const U& scalar) { 282 | for (auto& x : a) 283 | x /= scalar; 284 | return a; 285 | } 286 | 287 | //------------------------------------------------------------------------------ 288 | // Reduction Functions 289 | //------------------------------------------------------------------------------ 290 | 291 | // Sum of all elements in a DynamicArray. 292 | template 293 | T sum(const DynamicArray& a) { 294 | return std::accumulate(a.begin(), a.end(), T()); 295 | } 296 | 297 | // Product of all elements in a DynamicArray. 298 | template 299 | T product(const DynamicArray& a) { 300 | return std::accumulate(a.begin(), a.end(), T(1), std::multiplies()); 301 | } 302 | 303 | // Minimum element in a DynamicArray. 304 | template 305 | T min(const DynamicArray& a) { 306 | if (a.size() == 0) 307 | throw std::invalid_argument("DynamicArray is empty; cannot compute minimum."); 308 | return *std::min_element(a.begin(), a.end()); 309 | } 310 | 311 | // Maximum element in a DynamicArray. 312 | template 313 | T max(const DynamicArray& a) { 314 | if (a.size() == 0) 315 | throw std::invalid_argument("DynamicArray is empty; cannot compute maximum."); 316 | return *std::max_element(a.begin(), a.end()); 317 | } 318 | 319 | // Dot product for 1D DynamicArrays (vectors). 320 | template 321 | T dot(const DynamicArray& a, const DynamicArray& b) { 322 | if (a.size() != b.size()) 323 | throw std::invalid_argument("Vector sizes must match for dot product."); 324 | T result = T(); 325 | auto it_a = a.begin(); 326 | auto it_b = b.begin(); 327 | for (; it_a != a.end(); ++it_a, ++it_b) 328 | result += (*it_a * *it_b); 329 | return result; 330 | } 331 | 332 | //------------------------------------------------------------------------------ 333 | // Matrix Multiplication (for 2D DynamicArrays) 334 | //------------------------------------------------------------------------------ 335 | 336 | // Conventional matrix multiplication: if A is MxN and B is NxP, 337 | // then the product is an MxP matrix. 338 | // (Note: This is provided as a free function named 'matmul' to avoid 339 | // conflict with element-wise multiplication.) 340 | template 341 | auto matmul(const DynamicArray& A, const DynamicArray& B) 342 | -> DynamicArray::type, 2> 343 | { 344 | auto A_extents = A.extents(); 345 | auto B_extents = B.extents(); 346 | if (A_extents[1] != B_extents[0]) 347 | throw std::invalid_argument("Matrix multiplication dimension mismatch."); 348 | using result_t = typename std::common_type::type; 349 | DynamicArray result(A_extents[0], B_extents[1]); 350 | for (std::size_t i = 0; i < A_extents[0]; ++i) { 351 | for (std::size_t j = 0; j < B_extents[1]; ++j) { 352 | result(i, j) = result_t(); 353 | for (std::size_t k = 0; k < A_extents[1]; ++k) 354 | result(i, j) += A(i, k) * B(k, j); 355 | } 356 | } 357 | return result; 358 | } 359 | 360 | #endif // DYNAMIC_ARRAY_MATH_H 361 | 362 | -------------------------------------------------------------------------------- /include/common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file common.h 3 | * @author Adrian Del Maestro 4 | * @date 10.13.2008 5 | * @brief Global common header with shared dependencies and methods. 6 | * @details We use DynamicArray and std::array for all arrays and used boost::format to simplify 7 | * input and output. 8 | * @see include/dynamic_array.h 9 | * @see http://www.boost.org/doc/libs/release/libs/format/index.html 10 | */ 11 | 12 | #ifndef COMMON_H 13 | #define COMMON_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include // has std::bind 29 | #include 30 | 31 | #include "array_math.h" 32 | #include "dynamic_array_math.h" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | #include // find minima using Brent's method 42 | 43 | /* Debugging librarys and definitions. There is only an effect if 44 | * the code is compiled with PIMC_DEBUG on.*/ 45 | #ifdef PIMC_DEBUG 46 | 47 | /** A PIMC debugging message */ 48 | #define PIMC_DEBUG_MESSAGE(X)\ 49 | { std::cerr << "[pimc] " << __FILE__ << ": " << __LINE__ << " " << X << std::endl; } 50 | 51 | /** Rename assert method */ 52 | #define PIMC_ASSERT(X) assert(X) 53 | 54 | #else // !PIMC_DEBUG 55 | 56 | /** A PIMC debugging message */ 57 | #define PIMC_DEBUG_MESSAGE(X) 58 | 59 | /** Rename assert method */ 60 | #define PIMC_ASSERT(X) 61 | 62 | #endif // ifdef PIMC_DEBUG 63 | 64 | /* Determine if we are performing a PIGS (T=0) or PIMC (T>0) simulation */ 65 | #ifndef PIGS 66 | #define PIGS false 67 | #endif 68 | 69 | /* Determine if we are studying boltzmannons */ 70 | #ifndef BOLTZMANNONS 71 | #define BOLTZMANNONS false 72 | #endif 73 | 74 | /* Used for getting the repo version number into the code */ 75 | #ifndef REPO_VERSION 76 | #define REPO_VERSION "none" 77 | #endif 78 | 79 | /* We Default to turning on the NN lookup table. Comment this line out for testing 80 | * small systems where the lookup table might actually slow things down. */ 81 | #define NN_TABLE ///< Turn on the nearest neighbor particle lookup table 82 | 83 | #include "MersenneTwister.h" 84 | 85 | #define NPCFSEP 50 ///< Spatial separations to be used in the pair correlation function 86 | #define NOBDMSEP 50 ///< Spatial separations to be used in the one body density matrix 87 | #define NRADSEP 200 ///< Spatial separations to be used in the radial density 88 | #define NGRIDSEP 51 ///< Spatial separations to be used in each dimension of the particle position grid 89 | #define EPS 1.0E-7 ///< A small number 90 | #define DBL_EPS std::numeric_limits::epsilon() //< Smallest double 91 | #define BIG 1.0E30 ///< A big number 92 | #define LBIG 69.07755279 ///< The log of a big number 93 | #define XXX -1 ///< Used to refer to a nonsense beadIndex 94 | 95 | using boost::format; 96 | 97 | /** Unsigned integer type, at least 32 bits */ 98 | typedef unsigned long uint32; 99 | 100 | /** A NDIM x NDIM matrix of type double */ 101 | typedef std::array, NDIM> dMat; 102 | 103 | /** A NDIM-vector of type double */ 104 | typedef std::array dVec; 105 | 106 | /** A NDIM-vector of type integer*/ 107 | typedef std::array iVec; 108 | 109 | /** time-slice,bead-number world line index */ 110 | typedef std::array beadLocator; 111 | 112 | /** Integer array iterator */ 113 | typedef DynamicArray::iterator intIter; 114 | 115 | /** Constant integer array iterator */ 116 | typedef DynamicArray::const_iterator cintIter; 117 | 118 | /** beadLocator array iterator */ 119 | typedef DynamicArray::iterator beadIter; 120 | 121 | /** Each bead can have three possible states */ 122 | enum beadState {HEADTAIL,SPECIAL,NONE}; 123 | 124 | /** Each move can operate on only the digaonal ensemble, only the 125 | * off-diagonal ensemble, or both */ 126 | enum ensemble {DIAGONAL, OFFDIAGONAL, ANY}; 127 | 128 | /** Return the integer value of a number raised to a power */ 129 | inline int ipow (int base, int power) { 130 | return static_cast(floor(pow(1.0*base,1.0*power) + EPS)); 131 | } 132 | 133 | /** Minimum of two inputs */ 134 | template 135 | inline Ttype& min(Ttype& x, Ttype& y) { return (x < y ? x : y); } 136 | 137 | /** Maximum of two inputs */ 138 | template 139 | inline Ttype& max(Ttype& x, Ttype& y) { return (x > y ? x : y); } 140 | 141 | /** A python-like enumerate 142 | * @see https://www.reedbeta.com/blog/python-like-enumerate-in-cpp17/ 143 | * */ 144 | template ())), 146 | typename = decltype(std::end(std::declval()))> 147 | constexpr auto enumerate(T && iterable) 148 | { 149 | struct iterator 150 | { 151 | size_t i; 152 | TIter iter; 153 | bool operator != (const iterator & other) const { return iter != other.iter; } 154 | void operator ++ () { ++i; ++iter; } 155 | auto operator * () const { return std::tie(i, *iter); } 156 | }; 157 | struct iterable_wrapper 158 | { 159 | T iterable; 160 | auto begin() { return iterator{ 0, std::begin(iterable) }; } 161 | auto end() { return iterator{ 0, std::end(iterable) }; } 162 | }; 163 | return iterable_wrapper{ std::forward(iterable) }; 164 | } 165 | 166 | // Weighted average function for 1D containers. 167 | template 168 | auto weighted_average(const Container& container) -> double { 169 | // Get the extent (assumes a 1D container). 170 | const std::size_t n = container.extents()[0]; 171 | 172 | // Use double for accumulation. 173 | double weightedTotal = 0.0; 174 | double total = 0.0; 175 | 176 | for (std::size_t i = 0; i < n; ++i) { 177 | auto value = container(i); 178 | weightedTotal += static_cast(i) * static_cast(value); 179 | total += static_cast(value); 180 | } 181 | 182 | // FIXME not sure if I should throw here instead of returning 0.0 183 | return total == 0.0 ? 0.0 : weightedTotal / total; 184 | } 185 | 186 | template 187 | void apply_matrix_vector_product( 188 | std::array& resultVector, 189 | const std::array& inputVector, 190 | const std::array, Dimension>& transformationMatrix) 191 | { 192 | for (std::size_t row = 0; row < Dimension; ++row) { 193 | resultVector[row] += std::inner_product( 194 | transformationMatrix[row].begin(), 195 | transformationMatrix[row].end(), 196 | inputVector.begin(), 197 | ResultType{0} 198 | ); 199 | } 200 | } 201 | 202 | template 203 | double dot(const Container& a, const Container& b) { 204 | return std::inner_product(a.begin(), a.end(), b.begin(), 0.0); 205 | } 206 | 207 | template 208 | bool all(const Container& c, Predicate pred) { 209 | return std::all_of(c.begin(), c.end(), pred); 210 | } 211 | 212 | template 213 | bool all(const std::array& arr, T value) { 214 | for (const auto& elem : arr) { 215 | if (elem != value) { 216 | return false; 217 | } 218 | } 219 | return true; 220 | } 221 | 222 | // Helper function to generate an array filled with a given value 223 | template 224 | constexpr std::array make_array_impl(const T& value, std::index_sequence) { 225 | return {{ (static_cast(Is), value)... }}; 226 | } 227 | 228 | // Helper to make and fill array of given type and size 229 | template 230 | constexpr std::array make_array(const T& value) { 231 | return make_array_impl(value, std::make_index_sequence{}); 232 | } 233 | 234 | // Overload that deduces type and size from a given array type. 235 | template 236 | constexpr ArrayType make_array(const typename ArrayType::value_type& value) { 237 | return make_array_impl::value>( 239 | value, 240 | std::make_index_sequence::value>{}); 241 | } 242 | 243 | // FIXME These stream overloads should be backwards compatible. Should probably move to communicator.h 244 | // Overload for printing any std::array 245 | template 246 | std::ostream& operator<<(std::ostream& os, const std::array& arr) { 247 | os << "("; 248 | for (std::size_t i = 0; i < N; ++i) { 249 | os << arr[i]; 250 | if (i < N - 1) { 251 | os << ","; 252 | } 253 | } 254 | os << ")"; 255 | return os; 256 | } 257 | 258 | // Overload for printing 2D DynamicArray 259 | template 260 | std::ostream& operator<<(std::ostream& os, const DynamicArray& arr) { 261 | auto extents = arr.extents(); 262 | os << "(" << 0 << "," << extents[0] - 1 << ") x (" 263 | << 0 << "," << extents[1] - 1 << ")\n"; 264 | os << "[ "; 265 | for (std::size_t i = 0; i < extents[0]; ++i) { 266 | for (std::size_t j = 0; j < extents[1]; ++j) { 267 | os << arr(i, j) << " "; 268 | } 269 | if (i < extents[0] - 1) 270 | os << "\n "; 271 | } 272 | os << "]" << std::endl; 273 | return os; 274 | } 275 | 276 | // Overload for streaming into std::array 277 | template 278 | std::istream& operator>>(std::istream& is, std::array& a) { 279 | char ch; 280 | // Expect an opening '('. 281 | is >> ch; 282 | if (ch != '(') { 283 | is.setstate(std::ios::failbit); 284 | return is; 285 | } 286 | for (std::size_t i = 0; i < N; ++i) { 287 | is >> a[i]; 288 | if (i < N - 1) { 289 | // Expect a comma. 290 | is >> ch; 291 | if (ch != ',') { 292 | is.setstate(std::ios::failbit); 293 | return is; 294 | } 295 | } 296 | } 297 | // Expect a closing ')'. 298 | is >> ch; 299 | if (ch != ')') { 300 | is.setstate(std::ios::failbit); 301 | } 302 | return is; 303 | } 304 | 305 | // Overload for streaming into 2D DynamicArray 306 | template 307 | std::istream& operator>>(std::istream& is, DynamicArray& arr) 308 | { 309 | // Should start with: (0,extents[0]-1) x (0,extents[1]-1) 310 | int rowStart, rowEnd, colStart, colEnd; 311 | char ch; 312 | 313 | // Read the first '(' 314 | is >> ch; // should be '(' 315 | if (!is || ch != '(') { 316 | is.setstate(std::ios::failbit); 317 | return is; 318 | } 319 | 320 | // Read rowStart, then comma 321 | is >> rowStart >> ch; // rowStart, then ',' 322 | if (!is || ch != ',') { 323 | is.setstate(std::ios::failbit); 324 | return is; 325 | } 326 | 327 | // Read rowEnd, then ')' 328 | is >> rowEnd >> ch; // rowEnd, then ')' 329 | if (!is || ch != ')') { 330 | is.setstate(std::ios::failbit); 331 | return is; 332 | } 333 | 334 | // Read 'x' 335 | is >> ch; // should be 'x' 336 | if (!is || ch != 'x') { 337 | is.setstate(std::ios::failbit); 338 | return is; 339 | } 340 | 341 | // Read '(' for columns 342 | is >> ch; // should be '(' 343 | if (!is || ch != '(') { 344 | is.setstate(std::ios::failbit); 345 | return is; 346 | } 347 | 348 | // Read colStart, then comma 349 | is >> colStart >> ch; // colStart, then ',' 350 | if (!is || ch != ',') { 351 | is.setstate(std::ios::failbit); 352 | return is; 353 | } 354 | 355 | // Read colEnd, then ')' 356 | is >> colEnd >> ch; // colEnd, then ')' 357 | if (!is || ch != ')') { 358 | is.setstate(std::ios::failbit); 359 | return is; 360 | } 361 | 362 | // Resize arr to (rowEnd - rowStart + 1) x (colEnd - colStart + 1) 363 | arr.resize(std::size_t(rowEnd - rowStart + 1), 364 | std::size_t(colEnd - colStart + 1)); 365 | 366 | // Next we expect a line beginning with '[' 367 | // so skip forward until we see '[': 368 | while (is >> ch) { 369 | if (ch == '[') 370 | break; 371 | } 372 | if (!is) { 373 | is.setstate(std::ios::failbit); 374 | return is; 375 | } 376 | 377 | // Now read arr's contents, row by row 378 | auto extents = arr.extents(); 379 | for (std::size_t i = 0; i < extents[0]; ++i) { 380 | for (std::size_t j = 0; j < extents[1]; ++j) { 381 | if (!(is >> arr(i, j))) { 382 | is.setstate(std::ios::failbit); 383 | return is; 384 | } 385 | } 386 | } 387 | 388 | // Consume characters until the closing ']' is found 389 | while (is >> ch) { 390 | if (ch == ']') 391 | break; 392 | } 393 | if (!is) { 394 | is.setstate(std::ios::failbit); 395 | return is; 396 | } 397 | 398 | return is; 399 | } 400 | 401 | // Returns true if no element in the container equals the given value. 402 | template 403 | constexpr bool noneEquals(const Container& container, const T& value) { 404 | return std::none_of(container.begin(), container.end(), [&value](const auto& elem) { 405 | return elem == value; 406 | }); 407 | } 408 | 409 | // Returns true if any element in the container equals the given value. 410 | template 411 | constexpr bool anyEquals(const Container& container, const T& value) { 412 | return std::any_of(container.begin(), container.end(), [&value](const auto& elem) { 413 | return elem == value; 414 | }); 415 | } 416 | 417 | // Returns true if all elements in the container equal the given value. 418 | template 419 | constexpr bool allEquals(const Container& container, const T& value) { 420 | return std::all_of(container.begin(), container.end(), [&value](const auto& elem) { 421 | return elem == value; 422 | }); 423 | } 424 | 425 | // Helper function that performs elementwise comparison using a fold expression. 426 | // The parameter pack I... represents a compile-time sequence of indices. 427 | template 428 | constexpr bool all_impl(const std::array& a, const std::array& b, std::index_sequence) { 429 | // The fold expression below expands to a series of element comparisons: 430 | // (a[0] == b[0]) && (a[1] == b[1]) && ... && (a[N-1] == b[N-1]) 431 | return ((a[I] == b[I]) && ...); 432 | } 433 | 434 | // Primary function that compares two std::array objects elementwise. 435 | // It generates a compile-time sequence of indices [0, 1, ..., N-1] using std::make_index_sequence. 436 | template 437 | constexpr bool all(const std::array& a, const std::array& b) { 438 | // std::make_index_sequence{} creates an index sequence for all valid array indices. 439 | // The helper function all_impl is then called with this sequence to perform the comparisons. 440 | return all_impl(a, b, std::make_index_sequence{}); 441 | } 442 | 443 | #endif 444 | 445 | -------------------------------------------------------------------------------- /include/setup.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file setup.h 3 | * @author Adrian Del Maestro 4 | * @date 04.06.2011 5 | * 6 | * @brief Parses command line input and sets up the details of the simulation. 7 | */ 8 | 9 | #ifndef SETUP_H 10 | #define SETUP_H 11 | 12 | #include "common.h" 13 | #include "factory.h" 14 | #include 15 | #include 16 | 17 | /** The three possible states of a parameter */ 18 | enum ParamState {UNSET,DEFAULTED,SET}; 19 | 20 | namespace po = boost::program_options; 21 | namespace pt = boost::property_tree; 22 | 23 | class Container; 24 | class PotentialBase; 25 | class WaveFunctionBase; 26 | class ActionBase; 27 | class Path; 28 | class LookupTable; 29 | class MoveBase; 30 | class EstimatorBase; 31 | 32 | std::ostream& operator<<(std::ostream&, const std::vector&); 33 | std::string getList (const std::vector &, char sep=' '); 34 | bool isStringInVector(const std::string, const std::vector&); 35 | 36 | // ======================================================================== 37 | // Parameters Class 38 | // ======================================================================== 39 | /** 40 | * Simulation Parameters. 41 | * 42 | * @see http://stackoverflow.com/questions/7174781/boost-program-options-notifier-for-options-with-no-value 43 | * in the future to change default value of no value options to be bool 44 | * 45 | */ 46 | class Parameters { 47 | public: 48 | Parameters() {}; 49 | 50 | /** Add a parameter to the map without a default value */ 51 | template 52 | void add(std::string, std::string, std::string); 53 | 54 | /** Add a parameter to the map with a default value */ 55 | template 56 | void add(std::string, std::string, std::string, const Ttype); 57 | 58 | /** Set a parameter from a value */ 59 | template 60 | void set(const std::string&, const Ttype); 61 | 62 | /** Set a parameter from an xml node*/ 63 | template 64 | void set(const std::string&, const pt::ptree &); 65 | 66 | /** Insert options into the options_description data structure to be 67 | * read from the command line. */ 68 | void setupCommandLine(boost::ptr_map&); 69 | 70 | /** Update parameters from command line */ 71 | void update(int,char*[],po::options_description&); 72 | 73 | /** Update parameters from an xml file */ 74 | void update(const pt::ptree &); 75 | 76 | /** print out the parameter map */ 77 | void print(); 78 | 79 | /** Parameters() returns the full map */ 80 | const po::variables_map& operator()() const {return params;} 81 | po::variables_map& operator()() { return params;} 82 | 83 | /** Parmaters(key) returns the existence of a parameter */ 84 | const bool operator()(const std::string & key) const { return !(state.at(key) == UNSET); } 85 | 86 | /** Parmaters[key] returns the variable value at key */ 87 | const po::variable_value & operator[](const std::string & key) const {return params[key];} 88 | po::variable_value & operator[](const std::string & key) {return params.at(key);} 89 | 90 | private: 91 | 92 | using Extractor = std::map; 93 | 94 | po::variables_map params; ///< Parameter map 95 | std::map type; ///< Parameter types 96 | std::map pClass; ///< Class of the parameters 97 | std::map state; ///< State of a parameter 98 | std::map shortName; ///< Short name of a parameter (optional) 99 | std::map helpMessage; ///< Help message for a parameter 100 | Extractor extract; ///< Stores how to print each element 101 | 102 | /** Split a std::string at a delimeter */ 103 | std::vector split(const std::string &, char); 104 | 105 | template 106 | po::typed_value* initValue(const std::string &); 107 | 108 | /** Get a node from an xml file */ 109 | bool getNode(const pt::ptree &xmlParams, pt::ptree &node, const std::string key) { 110 | boost::optional child = xmlParams.get_child_optional(key); 111 | if (!child) 112 | return false; 113 | else 114 | node = *child; 115 | return true; 116 | } 117 | }; 118 | 119 | /**************************************************************************//** 120 | * Initialize a parameter in the map 121 | * 122 | * @param _label longName,shortName where shortName is optional 123 | * @param _helpMessage a command line help message 124 | * @param _pClass the class of parameter 125 | ******************************************************************************/ 126 | template 127 | void Parameters::add(std::string _label, std::string _helpMessage, std::string _pClass) { 128 | 129 | /* We break the label up at a possible comma and store the short-name in a 130 | * map*/ 131 | std::vector label = split(_label,','); 132 | std::string key = label[0]; 133 | if (label.size() > 1) 134 | shortName.emplace(key,label[1]); 135 | else 136 | shortName.emplace(key,""); 137 | 138 | /* Add the help message to a map */ 139 | helpMessage.emplace(key,_helpMessage); 140 | 141 | /* Add the parameter class to a map */ 142 | pClass.emplace(key,_pClass); 143 | 144 | /* Add the type to the appropriate map */ 145 | type.emplace(std::pair(key,typeid(Ttype))); 146 | 147 | /* Stores the function signature to print an element */ 148 | extract.emplace(std::pair 149 | (key,[](const po::variable_value& v) {std::cout << v.as();})); 150 | 151 | /* Initialize the parameter state */ 152 | state.emplace(key,UNSET); 153 | 154 | /* Insert an empty parameter */ 155 | params.insert(std::make_pair(key, po::variable_value())); 156 | 157 | /* update the parameters map */ 158 | po::notify(params); 159 | } 160 | 161 | /**************************************************************************//** 162 | * Initialize a parameter in the map with a default value 163 | * 164 | * @param _label longName,shortName where shortName is optional 165 | * @param _helpMessage a command line help message 166 | * @param _pClass the class of parameter 167 | * @param _defaultValue the default value of the parameter 168 | ******************************************************************************/ 169 | template 170 | void Parameters::add(std::string _label, std::string _helpMessage, std::string _pClass, 171 | const Ttype _defaultValue) { 172 | 173 | /* We perform a standard initialization */ 174 | add(_label,_helpMessage,_pClass); 175 | 176 | /* Get the long name */ 177 | std::vector label = split(_label,','); 178 | std::string key = label[0]; 179 | 180 | /* Insert the default value into the parameter map */ 181 | set(key,_defaultValue); 182 | 183 | /* Set the parameter state */ 184 | state.at(key) = DEFAULTED; 185 | } 186 | 187 | /**************************************************************************//** 188 | * Set the value of a parameter in the map from a value. 189 | * 190 | * @param key name of the parameter 191 | * @param val value of the parameter 192 | ******************************************************************************/ 193 | template 194 | void Parameters::set(const std::string& key, const Ttype val) { 195 | if (params.count(key)) { 196 | po::variables_map::iterator it(params.find(key)); 197 | po::variable_value & v(it->second); 198 | v.value() = val; 199 | } 200 | else { 201 | params.insert(std::make_pair(key, po::variable_value(val, false))); 202 | po::notify(params); 203 | 204 | /* insert the type */ 205 | type.emplace(std::pair(key,typeid(Ttype))); 206 | 207 | /* Stores the function signature to print an element */ 208 | extract.emplace(std::pair 209 | (key,[](const po::variable_value& v) {std::cout << v.as();})); 210 | } 211 | 212 | state[key] = SET; 213 | } 214 | 215 | /**************************************************************************//** 216 | * Set the value of a parameter in the map from an xml node 217 | * 218 | * @param key name of the parameter 219 | * @param xml node 220 | ******************************************************************************/ 221 | template 222 | void Parameters::set(const std::string& key, const pt::ptree &xml) { 223 | if (!xml.count(key)) 224 | return; 225 | 226 | /* command line overrides xml file */ 227 | if (state[key] == UNSET || state[key] == DEFAULTED) { 228 | set(key,xml.get(key)); 229 | state[key] = SET; 230 | } 231 | } 232 | 233 | /**************************************************************************//** 234 | * Get a value std::string to initialize the command line options. 235 | * 236 | ******************************************************************************/ 237 | template 238 | po::typed_value* Parameters::initValue(const std::string& key) { 239 | if (state[key] == DEFAULTED) 240 | return po::value()->default_value(params[key].as()); 241 | else 242 | return po::value(); 243 | } 244 | 245 | // ======================================================================== 246 | // Setup Class 247 | // ======================================================================== 248 | /** 249 | * Setup the simulation. 250 | * 251 | * This class uses boost::program_options to parse command line input 252 | * specifying all possible simulation options. In the future I would like 253 | * to implement the use of configuration files for static options as well. 254 | * We then parse the options, checking for correctness, and define all 255 | * simulation constants. We setup the container and potential pointers 256 | * and finally provide a method to output all the parameters to a log 257 | * file on disk. 258 | * 259 | * @see http://www.boost.org/doc/libs/release/doc/html/program_options.html 260 | */ 261 | class Setup { 262 | public: 263 | static Setup& instance() { 264 | static Setup setup; 265 | return setup; 266 | } 267 | 268 | /* Get the options from the command line */ 269 | void getOptions(int, char*[]); 270 | /* Parse the options and check for errors (needs to be more complete) */ 271 | bool parseOptions(); 272 | 273 | /* Setup the worldlines */ 274 | bool worldlines(); 275 | 276 | /* Setup the physical simulation cell */ 277 | void set_cell(); 278 | 279 | /* Get pointer to physical simulation cell */ 280 | Container* get_cell() const { 281 | return boxPtr; 282 | } 283 | 284 | /* Setup the simulation constants */ 285 | void setConstants(); 286 | 287 | /* Setup the communicator */ 288 | void communicator(); 289 | 290 | /* Define the random seed */ 291 | uint32 seed(const uint32); 292 | 293 | /* Output all options to disk */ 294 | void outputOptions(int, char*[], const uint32, const Container*, const iVec&); 295 | 296 | /* Setup the interaction potential */ 297 | PotentialBase * interactionPotential(); 298 | 299 | /* Setup the external potential */ 300 | PotentialBase * externalPotential(); 301 | 302 | /* Setup the trial wave function */ 303 | WaveFunctionBase * waveFunction(const Path &, LookupTable &); 304 | 305 | /* Setup the action */ 306 | ActionBase * action(const Path &, LookupTable &, PotentialBase*, PotentialBase *, WaveFunctionBase *); 307 | 308 | /* Setup the move array */ 309 | boost::ptr_vector * moves(Path &, ActionBase *, MTRand &); 310 | 311 | /* Setup the estimator array */ 312 | boost::ptr_vector * estimators(Path &, ActionBase *, MTRand &); 313 | boost::ptr_vector * estimators(boost::ptr_vector &, 314 | boost::ptr_vector &, MTRand&); 315 | 316 | Parameters params; ///< All simulation parameters 317 | 318 | private: 319 | Setup(); 320 | Setup(const Setup&) = delete; 321 | Setup& operator=(const Setup&) = delete; 322 | 323 | std::vector interactionPotentialName; ///< The allowed interaction potential names 324 | std::vector externalPotentialName; ///< The allowed external potential names 325 | std::vector waveFunctionName; ///< The allowed trial wave function names 326 | std::vector randomGeneratorName; ///< The allowed random number generator names 327 | std::vector actionName; ///< The allowed action names 328 | std::vector estimatorName; ///< The allowed estimator names 329 | std::vector moveName; ///< The allowed move names 330 | std::vector optionClassNames; ///< The allowed option class names 331 | std::vector wavevectorTypeName; ///< The allowed wavevector type names 332 | 333 | std::string interactionNames; ///< The interaction output list 334 | std::string externalNames; ///< The external output list 335 | std::string waveFunctionNames; ///< The wavefunction output list 336 | std::string randomGeneratorNames; ///< The random number generator output list 337 | std::string actionNames; ///< The action output list 338 | std::string estimatorNames; ///< The estimator list 339 | std::string moveNames; ///< The move list 340 | std::string wavevectorTypeNames; ///< The wavevector types list 341 | 342 | /* The factories needed to instantiate objects */ 343 | MoveFactory moveFactory; 344 | EstimatorFactory estimatorFactory; 345 | MultiEstimatorFactory multiEstimatorFactory; 346 | WaveFunctionFactory waveFunctionFactory; 347 | 348 | bool definedCell; ///< The user has physically set the sim. cell 349 | Container* boxPtr = nullptr; ///< Pointer to simulation cell 350 | 351 | boost::ptr_map optionClasses; ///< A map of different option types 352 | po::options_description cmdLineOptions; ///< All options combined 353 | 354 | /** process and clean up the command line options */ 355 | void cleanCommandLineOptions(int, char*[], std::vector &, std::vector &, 356 | std::vector&); 357 | void update(int,char*[],po::options_description&); 358 | 359 | /** Initialize all possible parameters*/ 360 | void initParameters(); 361 | 362 | /* Get a formatted list of xml options */ 363 | std::string getXMLOptionList(const std::vector &, const std::string); 364 | }; 365 | 366 | #endif 367 | --------------------------------------------------------------------------------