Skip to content

Commit

Permalink
Compile propagators in a separate library (#462)
Browse files Browse the repository at this point in the history
Groups of related propagators are now compiled in separate translation units.

---------

Co-authored-by: Sebastian Keller <[email protected]>
  • Loading branch information
ChristopherBignamini and sekelle authored Nov 19, 2024
1 parent 4673595 commit f56fc7c
Show file tree
Hide file tree
Showing 29 changed files with 628 additions and 163 deletions.
1 change: 1 addition & 0 deletions domain/include/cstone/fields/field_states.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#pragma once

#include <array>
#include <algorithm>
#include <vector>
#include <variant>

Expand Down
2 changes: 1 addition & 1 deletion domain/include/cstone/halos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ endif()
if(CMAKE_CUDA_COMPILER OR CMAKE_HIP_COMPILER)
add_library(gather_halos_obj OBJECT gather_halos_gpu.cu)
target_include_directories(gather_halos_obj PRIVATE ${PROJECT_SOURCE_DIR}/include)
endif()
endif()
8 changes: 4 additions & 4 deletions domain/include/cstone/halos/halos.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ namespace detail
{

//! @brief check that only owned particles in [particleStart_:particleEnd_] are sent out as halos
void checkIndices(const SendList& sendList,
[[maybe_unused]] LocalIndex start,
[[maybe_unused]] LocalIndex end,
[[maybe_unused]] LocalIndex bufferSize)
static void checkIndices(const SendList& sendList,
[[maybe_unused]] LocalIndex start,
[[maybe_unused]] LocalIndex end,
[[maybe_unused]] LocalIndex bufferSize)
{
for (const auto& manifest : sendList)
{
Expand Down
1 change: 1 addition & 0 deletions main/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ endfunction()
add_subdirectory(init)
add_subdirectory(io)
add_subdirectory(observables)
add_subdirectory(propagator)
add_subdirectory(sphexa)

if (BUILD_ANALYTICAL)
Expand Down
4 changes: 2 additions & 2 deletions main/src/analytical_solutions/sedov_solution/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ set(SOURCES sedov_solution.cpp main.cpp)
add_executable(sedov_solution ${SOURCES})
target_include_directories(sedov_solution PRIVATE ${CSTONE_DIR} ${PROJECT_SOURCE_DIR}/main/src)
if(CMAKE_OSX_SYSROOT)
target_link_libraries(sedov_solution stdc++)
target_link_libraries(sedov_solution io stdc++)
else()
target_link_libraries(sedov_solution stdc++fs)
target_link_libraries(sedov_solution io stdc++fs)
endif()
install(TARGETS sedov_solution RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
2 changes: 1 addition & 1 deletion main/src/io/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function(enableH5Part exename)
endif()
endfunction()

add_library(io ifile_io_ascii.cpp ifile_io_hdf5.cpp)
add_library(io ifile_io_ascii.cpp ifile_io_hdf5.cpp arg_parser.cpp)
target_include_directories(io PRIVATE ${CSTONE_DIR} ${MPI_CXX_INCLUDE_PATH})
target_link_libraries(io PRIVATE ${MPI_CXX_LIBRARIES})
enableH5Part(io)
89 changes: 89 additions & 0 deletions main/src/io/arg_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <algorithm>

#include "arg_parser.hpp"

namespace sphexa
{

ArgParser::ArgParser(int argc, const char** argv)
: begin(argv)
, end(argv + argc)
{
}

std::vector<std::string> ArgParser::getCommaList(const std::string& option) const
{
std::string listWithCommas = get(option);

std::replace(listWithCommas.begin(), listWithCommas.end(), ',', ' ');

std::vector<std::string> list;
std::stringstream ss(listWithCommas);
std::string field;
while (ss >> field)
{
list.push_back(field);
}

return list;
}

bool ArgParser::exists(const std::string& option) const { return std::find(begin, end, option) != end; }

bool strIsIntegral(const std::string& str)
{
char* ptr;
std::strtol(str.c_str(), &ptr, 10);
return (*ptr) == '\0' && !str.empty();
}

bool isExtraOutputStep(size_t step, double t1, double t2, const std::vector<std::string>& extraOutputs)
{
auto matchStepOrTime = [step, t1, t2](const std::string& token)
{
double time = std::stod(token);
bool isIntegral = strIsIntegral(token);
return (isIntegral && std::stoul(token) == step) || (!isIntegral && t1 <= time && time < t2);
};

return std::any_of(extraOutputs.begin(), extraOutputs.end(), matchStepOrTime);
}

bool isOutputTime(double t1, double t2, const std::string& frequencyStr)
{
double frequency = std::stod(frequencyStr);
if (strIsIntegral(frequencyStr) || frequency == 0.0) { return false; }

double closestMultiple = int(t2 / frequency) * frequency;
return t2 > frequency && t1 <= closestMultiple && closestMultiple < t2;
}

bool isOutputStep(size_t step, const std::string& frequencyStr)
{
int frequency = std::stoi(frequencyStr);
return strIsIntegral(frequencyStr) && frequency != 0 && (step % frequency == 0);
}

std::string strBeforeSign(const std::string& str, const std::string& sign)
{
auto commaPos = str.find_first_of(sign);
return str.substr(0, commaPos);
}

std::string strAfterSign(const std::string& str, const std::string& sign)
{
auto commaPos = str.find_first_of(sign);
if (commaPos == std::string::npos) { return {}; }

return str.substr(commaPos + sign.size());
}

int numberAfterSign(const std::string& str, const std::string& sign)
{
std::string afterComma = strAfterSign(str, sign);
return strIsIntegral(afterComma) ? std::stoi(afterComma) : -1;
}

std::string removeModifiers(const std::string& initCond) { return strBeforeSign(strBeforeSign(initCond, ":"), ","); }

} // namespace sphexa
83 changes: 11 additions & 72 deletions main/src/io/arg_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,17 @@
#include <string>
#include <sstream>
#include <vector>
#include <cmath>
#include <cassert>

namespace sphexa
{

//! @brief returns true if all characters of @p str together represent a valid integral number
bool strIsIntegral(const std::string& str)
{
char* ptr;
std::strtol(str.c_str(), &ptr, 10);
return (*ptr) == '\0' && !str.empty();
}
bool strIsIntegral(const std::string& str);

class ArgParser
{
public:
ArgParser(int argc, const char** argv)
: begin(argv)
, end(argv + argc)
{
}
ArgParser(int argc, const char** argv);

//! @brief look for @p option in the supplied cmd-line arguments and convert to T if found
template<class T = std::string>
Expand All @@ -44,24 +33,9 @@ class ArgParser
}

//! @brief parse a comma-separated list
std::vector<std::string> getCommaList(const std::string& option) const
{
std::string listWithCommas = get(option);

std::replace(listWithCommas.begin(), listWithCommas.end(), ',', ' ');

std::vector<std::string> list;
std::stringstream ss(listWithCommas);
std::string field;
while (ss >> field)
{
list.push_back(field);
}

return list;
}
std::vector<std::string> getCommaList(const std::string& option) const;

bool exists(const std::string& option) const { return std::find(begin, end, option) != end; }
bool exists(const std::string& option) const;

private:
const char** begin;
Expand All @@ -77,17 +51,7 @@ class ArgParser
* @return true if @p step matches any integral numbers in @p extraOutput or
* if any floating point number therein falls into the interval @p [t1, t2)
*/
bool isExtraOutputStep(size_t step, double t1, double t2, const std::vector<std::string>& extraOutputs)
{
auto matchStepOrTime = [step, t1, t2](const std::string& token)
{
double time = std::stod(token);
bool isIntegral = strIsIntegral(token);
return (isIntegral && std::stoul(token) == step) || (!isIntegral && t1 <= time && time < t2);
};

return std::any_of(extraOutputs.begin(), extraOutputs.end(), matchStepOrTime);
}
bool isExtraOutputStep(size_t step, double t1, double t2, const std::vector<std::string>& extraOutputs);

/*! @brief Evaluate whether the current step should be output (to file) according to time frequency
*
Expand All @@ -96,49 +60,24 @@ bool isExtraOutputStep(size_t step, double t1, double t2, const std::vector<std:
* @param frequencyStr frequency time to output the simulation as string
* @return true if the interval [t1, t2] contains a positive integer multiple of the output frequency
*/
bool isOutputTime(double t1, double t2, const std::string& frequencyStr)
{
double frequency = std::stod(frequencyStr);
if (strIsIntegral(frequencyStr) || frequency == 0.0) { return false; }

double closestMultiple = int(t2 / frequency) * frequency;
return t2 > frequency && t1 <= closestMultiple && closestMultiple < t2;
}
bool isOutputTime(double t1, double t2, const std::string& frequencyStr);

/*! @brief Evaluate whether the current step should be output (to file) according to iteration frequency
*
* @param step simulation step number
* @param frequencyStr iteration frequency to output the simulation as string
* @return true if the step is an integral multiple of the output frequency
*/
bool isOutputStep(size_t step, const std::string& frequencyStr)
{
int frequency = std::stoi(frequencyStr);
return strIsIntegral(frequencyStr) && frequency != 0 && (step % frequency == 0);
}
bool isOutputStep(size_t step, const std::string& frequencyStr);

std::string strBeforeSign(const std::string& str, const std::string& sign)
{
auto commaPos = str.find_first_of(sign);
return str.substr(0, commaPos);
}
std::string strBeforeSign(const std::string& str, const std::string& sign);

//! @brief If the input string ends with @p sign followed by an integer, return the integer, otherwise return -1
std::string strAfterSign(const std::string& str, const std::string& sign)
{
auto commaPos = str.find_first_of(sign);
if (commaPos == std::string::npos) { return {}; }

return str.substr(commaPos + sign.size());
}
std::string strAfterSign(const std::string& str, const std::string& sign);

//! @brief If the input string ends with @p sign followed by an integer, return the integer, otherwise return -1
int numberAfterSign(const std::string& str, const std::string& sign)
{
std::string afterComma = strAfterSign(str, sign);
return strIsIntegral(afterComma) ? std::stoi(afterComma) : -1;
}
int numberAfterSign(const std::string& str, const std::string& sign);

std::string removeModifiers(const std::string& initCond) { return strBeforeSign(strBeforeSign(initCond, ":"), ","); }
std::string removeModifiers(const std::string& initCond);

} // namespace sphexa
29 changes: 29 additions & 0 deletions main/src/propagator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
set(PROP_SOURCES nbody.cpp std_hydro_grackle.cpp std_hydro.cpp ve_hydro.cpp ve_hydro_bdt.cpp)

add_library(propagator ${PROP_SOURCES})
target_include_directories(propagator PRIVATE ${PROJECT_SOURCE_DIR}/main/src ${COOLING_DIR} ${CSTONE_DIR}
${SPH_DIR} ${RYOANJI_DIR} ${MPI_CXX_INCLUDE_PATH})
target_link_libraries(propagator PRIVATE ${MPI_CXX_LIBRARIES} util OpenMP::OpenMP_CXX)
enableGrackle(propagator)

if (CMAKE_CUDA_COMPILER OR CMAKE_HIP_COMPILER)
add_library(propagator_gpu ${PROP_SOURCES})
target_compile_definitions(propagator_gpu PRIVATE USE_CUDA)
target_include_directories(propagator_gpu PRIVATE ${PROJECT_SOURCE_DIR}/main/src ${COOLING_DIR} ${CSTONE_DIR}
${SPH_DIR} ${RYOANJI_DIR} ${MPI_CXX_INCLUDE_PATH})
target_link_libraries(propagator_gpu PRIVATE ${MPI_CXX_LIBRARIES} cstone_gpu ryoanji sph_gpu util OpenMP::OpenMP_CXX)
enableGrackle(propagator_gpu)
if (GPU_DIRECT)
target_compile_definitions(propagator_gpu PRIVATE USE_GPU_DIRECT)
endif ()
endif ()

if (CMAKE_CUDA_COMPILER)
target_link_libraries(propagator_gpu PRIVATE CUDA::cudart)
endif ()

if (CMAKE_HIP_COMPILER)
target_link_libraries(propagator_gpu PRIVATE hip::host)
target_compile_definitions(propagator_gpu PRIVATE THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_HIP)
set_target_properties(propagator_gpu PROPERTIES LINKER_LANGUAGE CXX)
endif ()
33 changes: 9 additions & 24 deletions main/src/propagator/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,13 @@
*
* @author Sebastian Keller <[email protected]>
* @author Jose A. Escartin <[email protected]>
* @author ChristopherBignamini <[email protected]>
*/

#pragma once

#include <variant>

#include "ipropagator.hpp"
#include "nbody.hpp"
#include "std_hydro.hpp"
#include "ve_hydro.hpp"
#include "ve_hydro_bdt.hpp"
#ifdef SPH_EXA_HAVE_GRACKLE
#include "std_hydro_grackle.hpp"
#endif
#include "turb_ve.hpp"
#include "propagator.h"

namespace sphexa
{
Expand All @@ -51,33 +43,26 @@ template<class DomainType, class ParticleDataType>
std::unique_ptr<Propagator<DomainType, ParticleDataType>>
propagatorFactory(const std::string& choice, bool avClean, std::ostream& output, size_t rank, const InitSettings& s)
{
if (choice == "ve")
{
if (avClean) { return std::make_unique<HydroVeProp<true, DomainType, ParticleDataType>>(output, rank); }
else { return std::make_unique<HydroVeProp<false, DomainType, ParticleDataType>>(output, rank); }
}
if (choice == "ve") { return PropLib<DomainType, ParticleDataType>::makeHydroVeProp(output, rank, avClean); }
if (choice == "ve-bdt")
{
if (avClean) { return std::make_unique<HydroVeBdtProp<true, DomainType, ParticleDataType>>(output, rank, s); }
else { return std::make_unique<HydroVeBdtProp<false, DomainType, ParticleDataType>>(output, rank, s); }
return PropLib<DomainType, ParticleDataType>::makeHydroVeBdtProp(output, rank, s, avClean);
}
if (choice == "std") { return std::make_unique<HydroProp<DomainType, ParticleDataType>>(output, rank); }
if (choice == "std") { return PropLib<DomainType, ParticleDataType>::makeHydroProp(output, rank); }
#ifdef SPH_EXA_HAVE_GRACKLE
if (choice == "std-cooling")
{
return std::make_unique<HydroGrackleProp<DomainType, ParticleDataType>>(output, rank, s);
return PropLib<DomainType, ParticleDataType>::makeHydroGrackleProp(output, rank, s);
}
#endif
if (choice == "nbody") { return std::make_unique<NbodyProp<DomainType, ParticleDataType>>(output, rank); }
if (choice == "nbody") { return PropLib<DomainType, ParticleDataType>::makeNbodyProp(output, rank); }
if (choice == "turbulence")
{
if (avClean) { return std::make_unique<TurbVeBdtProp<true, DomainType, ParticleDataType>>(output, rank, s); }
else { return std::make_unique<TurbVeBdtProp<false, DomainType, ParticleDataType>>(output, rank, s); }
return PropLib<DomainType, ParticleDataType>::makeTurbVeBdtProp(output, rank, s, avClean);
}
if (choice == "turbulence-ve")
{
if (avClean) { return std::make_unique<TurbVeProp<true, DomainType, ParticleDataType>>(output, rank, s); }
else { return std::make_unique<TurbVeProp<false, DomainType, ParticleDataType>>(output, rank, s); }
return PropLib<DomainType, ParticleDataType>::makeTurbVeProp(output, rank, s, avClean);
}

throw std::runtime_error("Unknown propagator choice: " + choice);
Expand Down
3 changes: 3 additions & 0 deletions main/src/propagator/ipropagator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@

#include <variant>

#include "cstone/sfc/box.hpp"
#include "cstone/tree/accel_switch.hpp"
#include "io/ifile_io.hpp"
#include "sph/particles_data.hpp"
#include "util/pm_reader.hpp"
#include "util/timer.hpp"

Expand Down
Loading

0 comments on commit f56fc7c

Please sign in to comment.