Skip to content

Commit

Permalink
env handling
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilipDeegan committed Jun 23, 2024
1 parent fc41581 commit 8421deb
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 42 deletions.
13 changes: 13 additions & 0 deletions pyphare/pyphare/cpp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ def build_config():
return cpp_etc_lib().phare_build_config()


def env_vars():
return cpp_etc_lib().phare_env_vars()


def print_env_vars_info():
for k, v in cpp_etc_lib().phare_env_vars().items():
print(f"{k}: {v.desc}")
print("Options:")
for k, v in v.options:

Check notice

Code scanning / CodeQL

Nested loops with same variable Note

Nested for statement uses loop variable 'k' of enclosing
for statement
.
Nested for statement uses loop variable 'v' of enclosing
for statement
.
print(f" {k}: {v}")
print("")


def build_config_as_json():
return json.dumps(build_config())

Expand Down
1 change: 1 addition & 0 deletions res/cmake/test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ if (test AND ${PHARE_EXEC_LEVEL_MIN} GREATER 0) # 0 = no tests
add_subdirectory(tests/core/data/maxwellian_particle_initializer)
add_subdirectory(tests/core/data/particle_initializer)
add_subdirectory(tests/core/utilities/box)
add_subdirectory(tests/core/utilities/env)
add_subdirectory(tests/core/utilities/range)
add_subdirectory(tests/core/utilities/index)
add_subdirectory(tests/core/utilities/indexer)
Expand Down
114 changes: 114 additions & 0 deletions src/core/env.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#ifndef PHARE_CORE_ENV_HPP
#define PHARE_CORE_ENV_HPP

// Single source for handling env vars

#include <array>
#include <cstdint>
#include <optional>
#include <string_view>
#include <unordered_map>
#include "core/utilities/types.hpp"
#include "core/utilities/mpi_utils.hpp"

namespace PHARE::env
{

struct Var
{
using value_type = std::string;
using results_type = std::unordered_map<std::string, std::string>;
auto constexpr static noop_results = [](Var const&) { return results_type{}; };

std::string_view const id;
std::string_view const desc;
std::vector<std::pair<std::string_view, std::string_view>> const options;

std::optional<value_type> const _default = std::nullopt;
std::function<results_type(Var const&)> const _results = noop_results;
std::optional<value_type> const v = get();
results_type const results_ = _results(*this);

std::optional<value_type> get() const
{
std::string _id{id};
if (_default)
return core::get_env(_id, *_default);
return core::get_env(_id);
}
auto& operator()() const { return v; }
auto& operator()(std::string const& s) const { return results_.at(s); }
// bool exists() const { return v != std::nullopt; }
// operator bool() const { return exists(); }
};

} // namespace PHARE::env

namespace PHARE
{
class Env
{
public:
template<typename T>
using map_t = std::unordered_map<std::string, T const* const>;

static Env& INSTANCE()
{
if (!self)
self = std::make_unique<Env>();
return *self;
}
static auto& reinit() { return *(self = std::make_unique<Env>()); }

env::Var const PHARE_LOG{
"PHARE_LOG",
"Write logs to $CWD/.log",
{{{"RANK_FILES", "Write logs $CWD/.log, a file per rank"},
{"DATETIME_FILES", "Write logs $CWD/.log, filename per rank and datetime"},
{"NONE", "print normally to std::cout"}}},
std::nullopt,
[](auto const& self) {
std::string_view constexpr file_key = "PHARE_LOG_FILE";
typename env::Var::results_type map;
if (auto const& opt = self())
{
auto const& val = *opt;
if (val == "RANK_FILES")
map.emplace(std::string(file_key),
".log/" + std::to_string(core::mpi::rank()) + ".out");
else if (val == "DATETIME_FILES")
{
auto date_time = core::mpi::date_time();
auto rank = std::to_string(core::mpi::rank());
auto size = std::to_string(core::mpi::size());
map.emplace(std::string(file_key),
".log/" + date_time + "_" + rank + "_of_" + size + ".out");
}
else if (val != "NONE")
throw std::runtime_error("PHARE_LOG invalid type, valid keys are "
"RANK_FILES/DATETIME_FILES/NONE");
}
return map;
} //
};
env::Var const PHARE_SCOPE_TIMING{
"PHARE_SCOPE_TIMING", "Enable function scope timing", {{{"1", "ON"}, {"0", "OFF"}}}, "0"};

map_t<env::Var> const vars = {{
{"PHARE_LOG", &PHARE_LOG},
{"PHARE_SCOPE_TIMING", &PHARE_SCOPE_TIMING},
}};

auto& operator()(std::string const& s) const
{
assert(vars.count(s));
return *vars.at(s);
}

private:
static inline std::unique_ptr<Env> self = nullptr;
};

} // namespace PHARE

#endif /* PHARE_CORE_ERRORS_H */
1 change: 1 addition & 0 deletions src/core/utilities/mpi_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ std::size_t max(std::size_t const local, int mpi_size)




bool any(bool b)
{
int global_sum, local_sum = static_cast<int>(b);
Expand Down
16 changes: 16 additions & 0 deletions src/core/utilities/mpi_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ inline bool is_init()
return flag > 0;
}


struct Lifecycle
{ // mostly used in core tests without samrai
Lifecycle(int argc, char** argv)
{
if (MPI_Init(&argc, &argv) != MPI_SUCCESS)
throw std::runtime_error("MPI Initialization failed");
}
~Lifecycle()
{
if (MPI_Finalize() != MPI_SUCCESS)
std::cerr << "MPI Finalization failed" << std::endl;
}
};


template<typename Data>
NO_DISCARD auto mpi_type_for()
{
Expand Down
27 changes: 27 additions & 0 deletions src/core/utilities/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,15 @@ namespace core
T var;
};

template<typename T>
NO_DISCARD T from_string(std::string const& s)
{
T t;
std::stringstream ss(s);
ss >> t;
return t;
}

template<typename T>
NO_DISCARD std::string to_string_with_precision(T const& a_value, std::size_t const len)
{
Expand Down Expand Up @@ -246,6 +255,24 @@ namespace core
}


template<typename T>
NO_DISCARD inline std::optional<T> get_env_as(std::string const& key)
{
if (auto e = get_env(key))
return from_string<T>(*e);
return std::nullopt;
}


template<typename T>
NO_DISCARD inline T get_env_as(std::string const& key, T const& t)
{
if (auto e = get_env(key))
return from_string<T>(*e);
return t;
}



} // namespace core
} // namespace PHARE
Expand Down
15 changes: 4 additions & 11 deletions src/hdf5/detail/h5/h5_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,7 @@ class HighFiveFile

~HighFiveFile() {}

NO_DISCARD HiFile& file()
{
return h5file_;
}
NO_DISCARD HiFile& file() { return h5file_; }


template<typename T, std::size_t dim = 1>
Expand Down Expand Up @@ -146,15 +143,11 @@ class HighFiveFile
void write_attribute(std::string const& keyPath, std::string const& key, Data const& data)
{
// assumes all keyPaths and values are identical, and no null patches
// clang-format off
PHARE_DEBUG_DO(
PHARE_DEBUG_DO( //
auto const paths = core::mpi::collect(keyPath, core::mpi::size());
for (auto const& path : paths)
PHARE_LOG_LINE_STR(std::to_string(core::mpi::size()) << " " << path)
if (!core::all(paths, [&](auto const& path) { return path == paths[0]; }))
throw std::runtime_error("Function does not support different paths per mpi core");
if (!core::all(paths, [&](auto const& path) { return path == paths[0]; })) throw std::
runtime_error("Function does not support different paths per mpi core"); //
)
// clang-format on

constexpr bool data_is_vector = core::is_std_vector_v<Data>;

Expand Down
4 changes: 3 additions & 1 deletion src/phare/phare.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "core/def/phlop.hpp" // scope timing

#include "core/env.hpp" // scope timing

#include "simulator/simulator.hpp"
#include "core/utilities/algorithm.hpp"
#include "core/utilities/mpi_utils.hpp"
Expand Down Expand Up @@ -41,7 +43,7 @@ class SamraiLifeCycle
= std::make_shared<StreamAppender>(StreamAppender{&std::cout});
SAMRAI::tbox::Logger::getInstance()->setWarningAppender(appender);
PHARE_WITH_PHLOP( //
if (auto e = core::get_env("PHARE_SCOPE_TIMING", "false"); e == "1" || e == "true")
if (auto e = Env::INSTANCE().PHARE_SCOPE_TIMING(); e == "1" || e == "true")
phlop::ScopeTimerMan::INSTANCE()
.file_name(".phare_times." + std::to_string(core::mpi::rank()) + ".txt")
.init(); //
Expand Down
28 changes: 25 additions & 3 deletions src/python3/cpp_etc.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@

#include "pybind11/stl.h"
#include "pybind11/stl_bind.h"
#include "python3/pybind_def.hpp"
#include "simulator/simulator.hpp"

#include "core/env.hpp"
#include "core/def/phare_config.hpp"


#include "amr/wrappers/hierarchy.hpp" // for HierarchyRestarter::getRestartFileFullPath



namespace py = pybind11;

PYBIND11_MAKE_OPAQUE(std::unordered_map<std::string, PHARE::env::Var*>);

namespace PHARE::pydata
{
auto pybind_version()
Expand Down Expand Up @@ -55,5 +57,25 @@ PYBIND11_MODULE(cpp_etc, m)
});

m.def("phare_build_config", []() { return PHARE::build_config(); });

m.def("phare_env_exists",
[](std::string const& s) { return Env::INSTANCE().vars.count(s) > 0; });
m.def("phare_env_val", [](std::string const& s) { return Env::INSTANCE()(s)(); });
m.def("phare_env_result", [](std::string const& s) {
assert(Env::INSTANCE().vars.count(s) > 0);
return Env::INSTANCE().vars.at(s)->result();
});
py::class_<env::Var>(m, "phare_env_var")
.def_readonly("id", &env::Var::id)
.def_readonly("desc", &env::Var::desc)
.def_readonly("options", &env::Var::options)
.def_readonly("default", &env::Var::_default)
.def_readonly("result", &env::Var::r);

py::bind_map<std::unordered_map<std::string, env::Var*>>(m, "EnvVarMap");

m.def(
"phare_env_vars", []() -> auto& { return Env::INSTANCE().vars; },
py::return_value_policy::reference);
}
} // namespace PHARE::pydata
30 changes: 3 additions & 27 deletions src/simulator/simulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "phare_types.hpp"

#include "core/def.hpp"
#include "core/env.hpp"
#include "core/logger.hpp"
#include "core/utilities/types.hpp"
#include "core/utilities/mpi_utils.hpp"
Expand Down Expand Up @@ -110,32 +111,7 @@ class Simulator : public ISimulator
private:
auto find_model(std::string name);

auto static log_file_name()
{
// ".log" directory is not created here, but in python if PHARE_LOG != "NONE"
if (auto log = core::get_env("PHARE_LOG"))
{
if (log == "RANK_FILES")
return ".log/" + std::to_string(core::mpi::rank()) + ".out";


if (log == "DATETIME_FILES")
{
auto date_time = core::mpi::date_time();
auto rank = std::to_string(core::mpi::rank());
auto size = std::to_string(core::mpi::size());
return ".log/" + date_time + "_" + rank + "_of_" + size + ".out";
}

if (log != "NONE")
throw std::runtime_error(
"PHARE_LOG invalid type, valid keys are RANK_FILES/DATETIME_FILES/NONE");
}

return std::string{""}; // unused
}

std::ofstream log_out{log_file_name()};
std::ofstream log_out{Env::INSTANCE().PHARE_LOG("PHARE_LOG_FILE")};
std::streambuf* coutbuf = nullptr;
std::shared_ptr<PHARE::amr::Hierarchy> hierarchy_;
std::unique_ptr<Integrator> integrator_;
Expand Down Expand Up @@ -186,7 +162,7 @@ namespace
inline auto logging(std::ofstream& log_out)
{
std::streambuf* buf = nullptr;
if (auto log = core::get_env("PHARE_LOG"); log != "NONE")
if (auto log = Env::INSTANCE().PHARE_LOG(); log and log != "NONE")
{
buf = std::cout.rdbuf();
std::cout.rdbuf(log_out.rdbuf());
Expand Down
21 changes: 21 additions & 0 deletions tests/core/utilities/env/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
cmake_minimum_required (VERSION 3.20.1)

project(test-phare-env)

set(SOURCES test_env.cpp)

add_executable(${PROJECT_NAME} ${SOURCES})

target_include_directories(${PROJECT_NAME} PRIVATE
${GTEST_INCLUDE_DIRS}
)

target_link_directories(${PROJECT_NAME} PUBLIC ${MPI_LIBRARY_PATH})

target_link_libraries(${PROJECT_NAME} PRIVATE
phare_core
MPI::MPI_C
${GTEST_LIBS}
)

add_phare_test(${PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR})
Loading

0 comments on commit 8421deb

Please sign in to comment.