diff --git a/.github/workflows/scripts/checkQEDTableGenerator.sh b/.github/workflows/scripts/checkQEDTableGenerator.sh new file mode 100755 index 00000000000..e14a7a2d6f2 --- /dev/null +++ b/.github/workflows/scripts/checkQEDTableGenerator.sh @@ -0,0 +1,77 @@ + +#!/usr/bin/env bash +# +# Copyright 2022 Luca Fedeli +# +# License: BSD-3-Clause-LBNL + +set -eu -o pipefail + +export OMP_NUM_THREADS=2 + +# +# Generate QED lookup tables using external tool +# +./build/bin/qed_table_generator \ + --table BW --mode DP --dndt_chi_min 0.01 \ + --dndt_chi_max 100 --dndt_how_many 64 \ + --pair_chi_min 0.01 --pair_chi_max 100 \ + --pair_chi_how_many 64 --pair_frac_how_many 64 \ + -o bw_table_tool +./build/bin/qed_table_generator \ + --table QS --mode DP --dndt_chi_min 0.001 \ + --dndt_chi_max 100 --dndt_how_many 64 \ + --em_chi_min 0.001 --em_chi_max 100 \ + --em_chi_how_many 64 --em_frac_how_many 64 \ + --em_frac_min 1e-12 -o qs_table_tool + +# +# Generate QED lookup tables using WarpX +# +./build/bin/warpx.2d \ + ./Examples/Tests/qed/quantum_synchrotron/inputs_2d \ + qed_bw.lookup_table_mode = "generate" \ + qed_bw.tab_dndt_chi_min = 0.01 \ + qed_bw.tab_dndt_chi_max = 100.0 \ + qed_bw.tab_dndt_how_many = 64 \ + qed_bw.tab_pair_chi_min = 0.01 \ + qed_bw.tab_pair_chi_max = 100.0 \ + qed_bw.tab_pair_chi_how_many = 64 \ + qed_bw.tab_pair_frac_how_many = 64 \ + qed_bw.save_table_in = "bw_table" \ + qed_qs.lookup_table_mode = "generate" \ + qed_qs.tab_dndt_chi_min = 0.001 \ + qed_qs.tab_dndt_chi_max = 100.0 \ + qed_qs.tab_dndt_how_many = 64 \ + qed_qs.tab_em_chi_min = 0.001 \ + qed_qs.tab_em_frac_min = 1.0e-12 \ + qed_qs.tab_em_chi_max = 100.0 \ + qed_qs.tab_em_chi_how_many = 64 \ + qed_qs.tab_em_frac_how_many = 64 \ + qed_qs.save_table_in = "qs_table" + +# +# Convert lookup tables (generated with WarpX and with the external tool) in human-readable format +# +./build/bin/qed_table_reader -i qs_table --table QS --mode DP -o qs_table +./build/bin/qed_table_reader -i qs_table_tool --table QS --mode DP -o qs_table_tool +./build/bin/qed_table_reader -i bw_table --table BW --mode DP -o bw_table +./build/bin/qed_table_reader -i bw_table_tool --table BW --mode DP -o bw_table_tool + +# +# Compare the generated lookup tables +# +diff bw_table_dndt bw_table_tool_dndt +diff bw_table_pair bw_table_tool_pair +diff qs_table_phot_em qs_table_tool_phot_em +diff qs_table_dndt qs_table_tool_dndt + +# +# Run a WarpX simulation using the lookup tables generated by the external tool +# +./build/bin/warpx.2d \ + ./Examples/Tests/qed/quantum_synchrotron/inputs_2d \ + qed_bw.lookup_table_mode = "load" \ + qed_bw.load_table_from = "bw_table_tool" \ + qed_qs.lookup_table_mode = "load" \ + qed_qs.load_table_from = "qs_table_tool" diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index dcb975aaa66..2997e9cdd16 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -46,7 +46,7 @@ jobs: du -hs ~/.cache/ccache build_1D_2D: - name: GCC 1D & 2D w/ MPI + name: GCC 1D & 2D w/ MPI, QED tools runs-on: ubuntu-22.04 if: github.event.pull_request.draft == false env: @@ -78,7 +78,9 @@ jobs: -DWarpX_DIMS="1;2" \ -DWarpX_EB=OFF \ -DWarpX_PSATD=ON \ - -DWarpX_QED_TABLE_GEN=ON + -DWarpX_QED_TABLE_GEN=ON \ + -DWarpX_QED_TOOLS=ON + cmake --build build -j 4 ./build/bin/warpx.1d Examples/Physics_applications/laser_acceleration/inputs_1d ./build/bin/warpx.2d Examples/Physics_applications/laser_acceleration/inputs_2d @@ -86,6 +88,10 @@ jobs: ccache -s du -hs ~/.cache/ccache + - name: run QED table tools + run: | + .github/workflows/scripts/checkQEDTableGenerator.sh + build_3D_sp: name: GCC 3D & RZ w/ MPI, single precision runs-on: ubuntu-22.04 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ddc685c733..e1d5dca6e3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,15 +71,19 @@ option(WarpX_ASCENT "Ascent in situ diagnostics" OFF) option(WarpX_EB "Embedded boundary support" OFF) cmake_dependent_option(WarpX_GPUCLOCK "Add GPU kernel timers (cost function)" ON - "WarpX_COMPUTE STREQUAL CUDA OR WarpX_COMPUTE STREQUAL HIP" OFF) + "WarpX_COMPUTE STREQUAL CUDA OR WarpX_COMPUTE STREQUAL HIP" + OFF) option(WarpX_LIB "Build WarpX as a library" OFF) option(WarpX_MPI "Multi-node support (message-passing)" ON) option(WarpX_OPENPMD "openPMD I/O (HDF5, ADIOS)" ON) option(WarpX_PSATD "spectral solver support" OFF) option(WarpX_PYTHON "Python bindings" OFF) option(WarpX_SENSEI "SENSEI in situ diagnostics" OFF) -option(WarpX_QED "QED support (requires PICSAR)" ON) -option(WarpX_QED_TABLE_GEN "QED table generation (requires PICSAR and Boost)" OFF) +option(WarpX_QED "QED support (requires PICSAR)" ON) +option(WarpX_QED_TABLE_GEN "QED table generation (requires PICSAR and Boost)" + OFF) +option(WarpX_QED_TOOLS "Build external tool to generate QED lookup tables (requires PICSAR and Boost)" + OFF) set(WarpX_DIMS_VALUES 1 2 3 RZ) set(WarpX_DIMS 3 CACHE STRING "Simulation dimensionality <1;2;3;RZ>") @@ -111,6 +115,13 @@ if(NOT WarpX_PARTICLE_PRECISION IN_LIST WarpX_PARTICLE_PRECISION_VALUES) message(FATAL_ERROR "WarpX_PARTICLE_PRECISION (${WarpX_PARTICLE_PRECISION}) must be one of ${WarpX_PARTICLE_PRECISION_VALUES}") endif() +set(WarpX_QED_TABLES_GEN_OMP_VALUES AUTO ON OFF) +set(WarpX_QED_TABLES_GEN_OMP AUTO CACHE STRING "Enables OpenMP support for QED lookup tables generation (AUTO/ON/OFF)") +set_property(CACHE WarpX_QED_TABLES_GEN_OMP PROPERTY STRINGS ${WarpX_QED_TABLES_GEN_OMP_VALUES}) +if(NOT WarpX_QED_TABLES_GEN_OMP IN_LIST WarpX_QED_TABLES_GEN_OMP_VALUES) + message(FATAL_ERROR "WarpX_QED_TABLES_GEN_OMP (${WarpX_QED_TABLES_GEN_OMP}) must be one of ${WarpX_QED_TABLES_GEN_OMP_VALUES}") +endif() + set(WarpX_COMPUTE_VALUES NOACC OMP CUDA SYCL HIP) set(WarpX_COMPUTE OMP CACHE STRING "On-node, accelerated computing backend (NOACC/OMP/CUDA/SYCL/HIP)") set_property(CACHE WarpX_COMPUTE PROPERTY STRINGS ${WarpX_COMPUTE_VALUES}) @@ -402,6 +413,9 @@ if(WarpX_LIB) add_subdirectory(Source/Python) add_subdirectory(Source/Utils) endif() +if(WarpX_QED_TOOLS) + add_subdirectory(Tools/QedTablesUtils) +endif() # Interprocedural optimization (IPO) / Link-Time Optimization (LTO) if(WarpX_IPO) diff --git a/Docs/source/install/cmake.rst b/Docs/source/install/cmake.rst index 4474b3509fe..7ff8986cf36 100644 --- a/Docs/source/install/cmake.rst +++ b/Docs/source/install/cmake.rst @@ -101,6 +101,8 @@ CMake Option Default & Values Descr ``WarpX_PYTHON`` ON/**OFF** Python bindings ``WarpX_QED`` **ON**/OFF QED support (requires PICSAR) ``WarpX_QED_TABLE_GEN`` ON/**OFF** QED table generation support (requires PICSAR and Boost) +``WarpX_QED_TOOLS`` ON/**OFF** Build external tool to generate QED lookup tables (requires PICSAR and Boost) +``WarpX_QED_TABLES_GEN_OMP`` **AUTO**/ON/OFF Enables OpenMP support for QED lookup tables generation ``WarpX_SENSEI`` ON/**OFF** SENSEI in situ visualization ============================= ============================================ ========================================================= diff --git a/Docs/source/usage/parameters.rst b/Docs/source/usage/parameters.rst index a615c9c8a87..bf66c24ccb9 100644 --- a/Docs/source/usage/parameters.rst +++ b/Docs/source/usage/parameters.rst @@ -3319,6 +3319,8 @@ Lookup tables store pre-computed values for functions used by the QED modules. * ``qed_bw.save_table_in`` (`string`): where to save the lookup table + Alternatively, the lookup table can be generated using a standalone tool (see :ref:`qed tools section `). + * ``load``: a lookup table is loaded from a pre-generated binary file. The following parameter must be specified: @@ -3356,6 +3358,8 @@ Lookup tables store pre-computed values for functions used by the QED modules. * ``qed_qs.save_table_in`` (`string`): where to save the lookup table + Alternatively, the lookup table can be generated using a standalone tool (see :ref:`qed tools section `). + * ``load``: a lookup table is loaded from a pre-generated binary file. The following parameter must be specified: diff --git a/Docs/source/usage/workflows.rst b/Docs/source/usage/workflows.rst index e68ec9391be..b68810a4345 100644 --- a/Docs/source/usage/workflows.rst +++ b/Docs/source/usage/workflows.rst @@ -12,6 +12,7 @@ This section collects typical user workflows and best practices for WarpX. workflows/domain_decomposition workflows/plot_distribution_mapping workflows/debugging + workflows/generate_lookup_tables_with_tools.rst workflows/libensemble workflows/plot_timestep_duration workflows/psatd_stencil diff --git a/Docs/source/usage/workflows/generate_lookup_tables_with_tools.rst b/Docs/source/usage/workflows/generate_lookup_tables_with_tools.rst new file mode 100644 index 00000000000..7417b7a1f96 --- /dev/null +++ b/Docs/source/usage/workflows/generate_lookup_tables_with_tools.rst @@ -0,0 +1,45 @@ +.. _generate-lookup-tables-with-tools: + +Generate QED lookup tables using the standalone tool +==================================================== + +We provide tools to generate and convert into a human-readable format the QED lookup tables. +Such tools can be compiled with ``cmake`` by setting the flag ``WarpX_QED_TOOLS=ON`` (this +requires both ``PICSAR`` and ``Boost`` libraries). The tools are compiled alongside the WarpX executable +in the folder ``bin``. We report here the help message displayed by the tools: + +.. code-block:: console + + $ ./qed_table_reader -h + ### QED Table Reader ### + Command line options: + -h [NO ARG] Prints all command line arguments + -i [STRING] Name of the file to open + --table [STRING] Either BW (Breit-Wheeler) or QS (Quantum Synchrotron) + --mode [STRING] Precision of the calculations: either DP (double) or SP (single) + -o [STRING] filename to save the lookup table in human-readable format + + $ ./qed_table_generator -h + ### QED Table Generator ### + Command line options: + -h [NO ARG] Prints all command line arguments + --table [STRING] Either BW (Breit-Wheeler) or QS (Quantum Synchrotron) + --mode [STRING] Precision of the calculations: either DP (double) or SP (single) + --dndt_chi_min [DOUBLE] minimum chi parameter for the dNdt table + --dndt_chi_max [DOUBLE] maximum chi parameter for the dNdt table + --dndt_how_many [INTEGR] number of points in the dNdt table + --pair_chi_min [DOUBLE] minimum chi for the pair production table (BW only) + --pair_chi_max [DOUBLE] maximum chi for the pair production table (BW only) + --pair_chi_how_many [INTEGR] number of chi points in the pair production table (BW only) + --pair_frac_how_many [INTEGR] number of frac points in the pair production table (BW only) + --em_chi_min [DOUBLE] minimum chi for the photon emission table (QS only) + --em_chi_max [DOUBLE] maximum chi for the photon emission production table (QS only) + --em_frac_min [DOUBLE] minimum frac for the photon emission production table (QS only) + --em_chi_how_many [INTEGR] number of chi points in the photon emission table (QS only) + --em_frac_how_many [INTEGR] number of frac points in the photon emission table (QS only) + -o [STRING] filename to save the lookup table + +These tools are meant to be compatible with WarpX: ``qed_table_generator`` should generate +tables that can be loaded into WarpX and ``qed_table_reader`` should be able to read tables generated with WarpX. +It is not safe to use these tools to generate a table on a machine using a different endianness with respect to +the machine where the table is used. diff --git a/Regression/Checksum/benchmarks_json/LaserAcceleration_single_precision_comms.json b/Regression/Checksum/benchmarks_json/LaserAcceleration_single_precision_comms.json index 30eef0cedb7..90493698df0 100644 --- a/Regression/Checksum/benchmarks_json/LaserAcceleration_single_precision_comms.json +++ b/Regression/Checksum/benchmarks_json/LaserAcceleration_single_precision_comms.json @@ -22,4 +22,4 @@ "particle_momentum_z": 4.231730764749506e-20, "particle_weight": 12926557617.187498 } -} \ No newline at end of file +} diff --git a/Tools/QedTablesUtils/CMakeLists.txt b/Tools/QedTablesUtils/CMakeLists.txt new file mode 100644 index 00000000000..09399316096 --- /dev/null +++ b/Tools/QedTablesUtils/CMakeLists.txt @@ -0,0 +1,35 @@ +# Common argument parser functions ############################################ +# +# TODO: Move to ABLASTR +set(arg_parser_src + Source/ArgParser/QedTablesArgParser.cpp + Source/ArgParser/QedTablesArgParser.H +) + + +# Build QED lookup tables generator ########################################### +# +add_executable(qed_table_generator + Source/QedTableGenerator.cpp + ${arg_parser_src} +) +add_executable(WarpX::qed_table_generator ALIAS qed_table_generator) + +target_link_libraries(qed_table_generator PRIVATE PXRMP_QED) + +target_compile_features(qed_table_generator PUBLIC cxx_std_17) +set_target_properties(qed_table_generator PROPERTIES CXX_EXTENSIONS OFF) + + +# Build QED lookup tables reader ############################################## +# +add_executable(qed_table_reader + Source/QedTableReader.cpp + ${arg_parser_src} +) +add_executable(WarpX::qed_table_reader ALIAS qed_table_reader) + +target_link_libraries(qed_table_reader PRIVATE PXRMP_QED) + +target_compile_features(qed_table_reader PUBLIC cxx_std_17) +set_target_properties(qed_table_reader PROPERTIES CXX_EXTENSIONS OFF) diff --git a/Tools/QedTablesUtils/Source/ArgParser/QedTablesArgParser.H b/Tools/QedTablesUtils/Source/ArgParser/QedTablesArgParser.H new file mode 100644 index 00000000000..f05b84ddca8 --- /dev/null +++ b/Tools/QedTablesUtils/Source/ArgParser/QedTablesArgParser.H @@ -0,0 +1,58 @@ +#ifndef QED_TABLES_ARG_PARSER_ +#define QED_TABLES_ARG_PARSER_ + +#include +#include +#include +#include +#include +#include +#include + +namespace ArgParser +{ + /* Possible types of parameters of command line arguments (no argument, int, double, or std::string) */ + enum class ArgType { NoArg, Integer, Double, String }; + + /* This type represents the type of a command line argument: if it exists it is either an int, a double, or a std::string */ + using ArgVal = std::optional>; + + /* The type of a possible command line argument */ + using Key = std::tuple; + + /* The type of the map of the parsed command line arguments */ + using ParsedArgs = std::unordered_map; + + /** + * \brief Gets the value out of an ArgVal (std::optional>) object + * + * \tparam T the type to return (must be int, double, or std::string) + * \param[in] arg_val the ArgVal object + * \return the value in arg_val + */ + template + T GetVal(const ArgVal& arg_val) + { + return std::get(*arg_val); + } + + /** + * \brief Function to parse the command line arguments + * + * \param[in] keys the list of possible command line arguments + * \param[in] argc the number of command line arguments + * \param[in] argv all the command line arguments + * \return the parsed command line arguments + */ + ParsedArgs ParseArgs (const std::vector& keys, const int argc, char const* const* argv); + + /** + * \brief Prints the command line options + * + * \param[in] cmd_list the list of possible command line arguments + */ + void PrintHelp (const std::vector& cmd_list); +}; + + +#endif //QED_TABLES_ARG_PARSER_ diff --git a/Tools/QedTablesUtils/Source/ArgParser/QedTablesArgParser.cpp b/Tools/QedTablesUtils/Source/ArgParser/QedTablesArgParser.cpp new file mode 100644 index 00000000000..41d27477dcf --- /dev/null +++ b/Tools/QedTablesUtils/Source/ArgParser/QedTablesArgParser.cpp @@ -0,0 +1,108 @@ +#include "QedTablesArgParser.H" + +#include + +using namespace ArgParser; +using namespace std; + +namespace +{ +void +WarnMsg(const string& msg) +{ + cout << "!!! Parse Warning: " + msg + "\n"; +} + +void +ErrMsg(const string& msg) +{ + cout << "### Parse Error: " + msg + "\n"; + exit(1); +} + +vector +ArgvToStrVec(const int argc, char const* const* argv ) +{ + auto sargs = vector{}; + for (int i = 0; i < argc; ++i) + sargs.push_back(std::string{argv[i]}); + return sargs; +} + +optional> +GetArgType(const std::vector& keys, vector::iterator& it) +{ + const auto str = *it; + it++; + for (const auto& kk : keys){ + if (get<0>(kk) == str) + { + return std::make_pair(get<0>(kk), get<1>(kk)); + } + } + return nullopt; +} + +ArgVal +ReadArg(const ArgType arg_type, vector::iterator& it) +{ + if(arg_type == ArgType::NoArg) return nullopt; + if(arg_type == ArgType::String) return *(it++); + if(arg_type == ArgType::Integer) return stoi(*(it++)); + if(arg_type == ArgType::Double) return stod(*(it++)); + + ErrMsg("Failed to parse type!"s); + + return nullopt; +} + +} + +ParsedArgs +ArgParser::ParseArgs (const std::vector& keys, const int argc, char const* const* argv) +{ + auto parsed_args = ParsedArgs{}; + + auto sargs = ArgvToStrVec(argc, argv); + auto it = sargs.begin() + 1; // the first argument is always the executable name + while (it < sargs.end()){ + const auto tt = *it; + auto res = GetArgType(keys, it); + if (res != nullopt){ + const auto& [key, arg_type] = *res; + const auto arg = ReadArg(arg_type, it); + if (parsed_args.find(key) != parsed_args.end()) + WarnMsg("Rewriting '"+ key +"' argument !"); + parsed_args[key] = arg; + }else{ + WarnMsg("Can't parse '"+ tt +"' !"); + } + } + + return parsed_args; +} + +void +ArgParser::PrintHelp (const vector& cmd_list) +{ + cout << "Command line options: " << endl; + + for (const auto& el : cmd_list){ + const auto type = get<1>(el); + string stype = "[??????]"; + if (type == ArgType::NoArg) + stype = "[NO ARG]"; + else if (type == ArgType::String) + stype = "[STRING]"; + else if (type == ArgType::Double) + stype = "[DOUBLE]"; + else if (type == ArgType::Integer) + stype = "[INTEGR]"; + + cout << get<0>(el) + << " " << stype + << " " << get<2>(el) + << endl; + } + +} diff --git a/Tools/QedTablesUtils/Source/QedTableCommons.H b/Tools/QedTablesUtils/Source/QedTableCommons.H new file mode 100644 index 00000000000..40551b9e13c --- /dev/null +++ b/Tools/QedTablesUtils/Source/QedTableCommons.H @@ -0,0 +1,26 @@ +#ifndef QED_TABLES_COMMONS_ +#define QED_TABLES_COMMONS_ + +#include +#include + +template +bool Contains (const ContainerType& container, const ElementType& el) +{ + return container.find(el) != std::end(container); +} + +void AbortWithMessage(const std::string& msg) +{ + std::cout << "### ABORT : " << msg << std::endl; + std::cout << "___________________________" << std::endl; + exit(1); +} + +void SuccessExit() +{ + std::cout << "___________________________" << std::endl; + exit(0); +} + +#endif //QED_TABLES_COMMONS_ diff --git a/Tools/QedTablesUtils/Source/QedTableGenerator.cpp b/Tools/QedTablesUtils/Source/QedTableGenerator.cpp new file mode 100644 index 00000000000..dfbde1df050 --- /dev/null +++ b/Tools/QedTablesUtils/Source/QedTableGenerator.cpp @@ -0,0 +1,239 @@ +#include "QedTableCommons.H" +#include "ArgParser/QedTablesArgParser.H" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ArgParser; +using namespace std; + +namespace pxr_sr = picsar::multi_physics::utils::serialization; +namespace pxr_bw = picsar::multi_physics::phys::breit_wheeler; +namespace pxr_qs = picsar::multi_physics::phys::quantum_sync; + +const auto line_commands = vector{ + {"-h" , ArgType::NoArg , "Prints all command line arguments"}, + {"--table" , ArgType::String , "Either BW (Breit-Wheeler) or QS (Quantum Synchrotron)"}, + {"--mode" , ArgType::String, "Precision of the calculations: either DP (double) or SP (single)"}, + {"--dndt_chi_min" , ArgType::Double , "minimum chi parameter for the dNdt table"}, + {"--dndt_chi_max" , ArgType::Double , "maximum chi parameter for the dNdt table"}, + {"--dndt_how_many" , ArgType::Integer, "number of points in the dNdt table"}, + {"--pair_chi_min" , ArgType::Double , "minimum chi for the pair production table (BW only)"}, + {"--pair_chi_max" , ArgType::Double , "maximum chi for the pair production table (BW only)"}, + {"--pair_chi_how_many" , ArgType::Integer, "number of chi points in the pair production table (BW only)"}, + {"--pair_frac_how_many", ArgType::Integer, "number of frac points in the pair production table (BW only)"}, + {"--em_chi_min" , ArgType::Double , "minimum chi for the photon emission table (QS only)"}, + {"--em_chi_max" , ArgType::Double , "maximum chi for the photon emission production table (QS only)"}, + {"--em_frac_min" , ArgType::Double , "minimum frac for the photon emission production table (QS only)"}, + {"--em_chi_how_many" , ArgType::Integer, "number of chi points in the photon emission table (QS only)"}, + {"--em_frac_how_many" , ArgType::Integer, "number of frac points in the photon emission table (QS only)"}, + {"-o" , ArgType::String , "filename to save the lookup table"} +}; + +void GenerateTable (const ParsedArgs& args); +template +void GenerateTableBW (const ParsedArgs& args, const string& outfile_name); +template +void GenerateTableQS (const ParsedArgs& args, const string& outfile_name); + +int main (int argc, char** argv) +{ + cout << "### QED Table Generator ###" << endl; + const auto args_map = ParseArgs(line_commands, argc, argv); + + if (args_map.empty() || Contains(args_map, "-h")){ + PrintHelp(line_commands); + } + else{ + GenerateTable(args_map); + } + + SuccessExit(); +} + + +void GenerateTable (const ParsedArgs& args) +{ + if (!Contains(args, "--table")) + AbortWithMessage("'--table' argument must be provided"); + + if (!Contains(args, "--mode")) + AbortWithMessage("'--mode' argument must be provided"); + + if (!Contains(args, "-o")) + AbortWithMessage("'-o' argument must be provided"); + + const auto which_table = GetVal(args.at("--table")); + const auto mode = GetVal(args.at("--mode")); + const auto outfile_name = GetVal(args.at("-o")); + + bool use_double = false; + + if (mode == "DP"s) + use_double = true; + else if (mode == "SP"s) + use_double = false; + else + AbortWithMessage("'--mode' must be eiter 'DP' or 'SP'"); + + if (which_table == "BW"s){ + if (use_double) + GenerateTableBW(args, outfile_name); + else + GenerateTableBW(args, outfile_name); + } + else if (which_table == "QS"s) + if (use_double) + GenerateTableQS(args, outfile_name); + else + GenerateTableQS(args, outfile_name); + else + AbortWithMessage("'--table' must be eiter 'QS' or 'BW'"); +} + +template +void GenerateTableBW (const ParsedArgs& args, const string& outfile_name) +{ + cout << " Generating BW table " << + (is_same::value ? "(double "s : "(single "s) << " precision)\n"s; + + if (!Contains(args, "--dndt_chi_min") || !Contains(args, "--dndt_chi_max") || + !Contains(args, "--dndt_how_many") || !Contains(args, "--pair_chi_min") || + !Contains(args, "--pair_chi_max") || !Contains(args, "--pair_chi_how_many") || + !Contains(args, "--pair_frac_how_many")) + AbortWithMessage("All the BW table arguments must be provided (check with -h)"); + + const auto dndt_table_params = + pxr_bw::dndt_lookup_table_params{ + static_cast(GetVal(args.at("--dndt_chi_min"))), + static_cast(GetVal(args.at("--dndt_chi_max"))), + GetVal(args.at("--dndt_how_many")) + }; + + const auto pair_prod_table_params = + pxr_bw::pair_prod_lookup_table_params{ + static_cast(GetVal(args.at("--pair_chi_min"))), + static_cast(GetVal(args.at("--pair_chi_max"))), + GetVal(args.at("--pair_chi_how_many")), + GetVal(args.at("--pair_frac_how_many")) + }; + + std::cout << " Params: \n"; + std::cout << " - dndt_chi_min : " << dndt_table_params.chi_phot_min << "\n"; + std::cout << " - dndt_chi_max : " << dndt_table_params.chi_phot_max << "\n"; + std::cout << " - dndt_how_many : " << dndt_table_params.chi_phot_how_many << "\n"; + std::cout << " - pair_chi_min : " << pair_prod_table_params.chi_phot_min << "\n"; + std::cout << " - pair_chi_max : " << pair_prod_table_params.chi_phot_max << "\n"; + std::cout << " - pair_chi_how_many : " << pair_prod_table_params.chi_phot_how_many << "\n"; + std::cout << " - pair_frac_how_many : " << pair_prod_table_params.frac_how_many << "\n"; + std::cout << " ----------------------- " << "\n\n"; + + auto dndt_table = + pxr_bw::dndt_lookup_table>{ + dndt_table_params}; + + auto pair_prod_table = + pxr_bw::pair_prod_lookup_table>{ + pair_prod_table_params}; + + dndt_table.generate(true); //Progress bar is displayed + pair_prod_table.generate(true); //Progress bar is displayed + + const auto data_dndt = dndt_table.serialize(); + const auto data_pair_prod = pair_prod_table.serialize(); + + const uint64_t size_first = data_dndt.size(); + + vector res{}; + pxr_sr::put_in(size_first, res); + for (const auto& tmp : data_dndt) + pxr_sr::put_in(tmp, res); + for (const auto& tmp : data_pair_prod) + pxr_sr::put_in(tmp, res); + + auto of = std::ofstream{outfile_name, std::ios_base::binary}; + of.write(res.data(), res.size()); + of.close(); + + cout << " Done! \n"; +} + +template +void GenerateTableQS (const ParsedArgs& args, const string& outfile_name) +{ + cout << " Generating QS table " << + (is_same::value ? "(double "s : "(single "s) << " precision)\n"s; + + if (!Contains(args, "--dndt_chi_min") || !Contains(args, "--dndt_chi_max") || + !Contains(args, "--dndt_how_many") || !Contains(args, "--em_chi_min") || + !Contains(args, "--em_chi_max") || !Contains(args, "--em_frac_min") || + !Contains(args, "--em_chi_how_many") || !Contains(args, "--em_frac_how_many")) + AbortWithMessage("All the QS table arguments must be provided (check with -h)"); + + const auto dndt_table_params = + pxr_qs::dndt_lookup_table_params{ + static_cast(GetVal(args.at("--dndt_chi_min"))), + static_cast(GetVal(args.at("--dndt_chi_max"))), + GetVal(args.at("--dndt_how_many")) + }; + + const auto phot_em_table_params = + pxr_qs::photon_emission_lookup_table_params{ + static_cast(GetVal(args.at("--em_chi_min"))), + static_cast(GetVal(args.at("--em_chi_max"))), + static_cast(GetVal(args.at("--em_frac_min"))), + GetVal(args.at("--em_chi_how_many")), + GetVal(args.at("--em_frac_how_many")) + }; + + std::cout << " Params: \n"; + std::cout << " - dndt_chi_min : " << dndt_table_params.chi_part_min << "\n"; + std::cout << " - dndt_chi_max : " << dndt_table_params.chi_part_max << "\n"; + std::cout << " - dndt_how_many : " << dndt_table_params.chi_part_how_many << "\n"; + std::cout << " - phot_em_chi_min : " << phot_em_table_params.chi_part_min << "\n"; + std::cout << " - phot_em_chi_max : " << phot_em_table_params.chi_part_max << "\n"; + std::cout << " - phot_em_frac_min : " << phot_em_table_params.frac_min << "\n"; + std::cout << " - phot_em_chi_how_many : " << phot_em_table_params.chi_part_how_many << "\n"; + std::cout << " - phot_em_frac_how_many : " << phot_em_table_params.frac_how_many << "\n"; + std::cout << " ----------------------- " << "\n\n"; + + auto dndt_table = + pxr_qs::dndt_lookup_table>{ + dndt_table_params}; + + auto phot_em_table = + pxr_qs::photon_emission_lookup_table>{ + phot_em_table_params}; + + dndt_table.generate(true); //Progress bar is displayed + phot_em_table.generate(true); //Progress bar is displayed + + const auto data_dndt = dndt_table.serialize(); + const auto data_phot_em = phot_em_table.serialize(); + + const uint64_t size_first = data_dndt.size(); + + vector res{}; + pxr_sr::put_in(size_first, res); + for (const auto& tmp : data_dndt) + pxr_sr::put_in(tmp, res); + for (const auto& tmp : data_phot_em) + pxr_sr::put_in(tmp, res); + + auto of = std::ofstream{outfile_name, std::ios_base::binary}; + of.write(res.data(), res.size()); + of.close(); + + cout << " Done! \n"; +} diff --git a/Tools/QedTablesUtils/Source/QedTableReader.cpp b/Tools/QedTablesUtils/Source/QedTableReader.cpp new file mode 100644 index 00000000000..ae689a87643 --- /dev/null +++ b/Tools/QedTablesUtils/Source/QedTableReader.cpp @@ -0,0 +1,240 @@ +#include "QedTableCommons.H" +#include "ArgParser/QedTablesArgParser.H" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ArgParser; +using namespace std; + +namespace pxr_sr = picsar::multi_physics::utils::serialization; +namespace pxr_bw = picsar::multi_physics::phys::breit_wheeler; +namespace pxr_qs = picsar::multi_physics::phys::quantum_sync; + +const auto line_commands = vector{ + {"-h" , ArgType::NoArg , "Prints all command line arguments"}, + {"-i" , ArgType::String , "Name of the file to open"}, + {"--table" , ArgType::String , "Either BW (Breit-Wheeler) or QS (Quantum Synchrotron)"}, + {"--mode" , ArgType::String , "Precision of the calculations: either DP (double) or SP (single)"}, + {"-o" , ArgType::String , "filename to save the lookup table in human-readable format"} +}; + +void ReadTable (const ParsedArgs& args); +template +void ReadTableBW (const string& input_file, const string& outfile_name); +template +void ReadTableQS ( + const string& input_file, const string& outfile_name); + +/*Wrapper class to access protected data*/ +template +class bw_pair_production_table_wrapper : + public pxr_bw::pair_prod_lookup_table> +{ + public: + void write_table_data(std::ofstream& of) const; +}; + +/*Wrapper class to access protected data*/ +template +class qs_photon_emission_table_wrapper : + public pxr_qs::photon_emission_lookup_table> +{ + public: + void write_table_data(std::ofstream& of) const; +}; + +int main (int argc, char** argv) +{ + cout << "### QED Table Reader ###" << endl; + const auto args_map = ParseArgs(line_commands, argc, argv); + + if (args_map.empty() || Contains(args_map, "-h")){ + PrintHelp(line_commands); + } + else{ + ReadTable(args_map); + } + + SuccessExit(); +} + +void ReadTable (const ParsedArgs& args) +{ + if (!Contains(args, "--table")) + AbortWithMessage("'--table' argument must be provided"); + + if (!Contains(args, "--mode")) + AbortWithMessage("'--mode' argument must be provided"); + + if (!Contains(args, "-o")) + AbortWithMessage("'-o' argument must be provided"); + + if (!Contains(args, "-i")) + AbortWithMessage("'-i' argument must be provided"); + + const auto which_table = GetVal(args.at("--table")); + const auto mode = GetVal(args.at("--mode")); + const auto input_file = GetVal(args.at("-i")); + const auto outfile_name = GetVal(args.at("-o")); + + bool use_double = false; + + if (mode == "DP"s) + use_double = true; + else if (mode == "SP"s) + use_double = false; + else + AbortWithMessage("'--mode' must be eiter 'DP' or 'SP'"); + + if (which_table == "BW"s){ + if (use_double) + ReadTableBW(input_file, outfile_name); + else + ReadTableBW(input_file, outfile_name); + } + else if (which_table == "QS"s) + if (use_double) + ReadTableQS(input_file, outfile_name); + else + ReadTableQS(input_file, outfile_name); + else + AbortWithMessage("'--table' must be eiter 'QS' or 'BW'"); +} + +template +void ReadTableBW (const string& input_file, const string& outfile_name) +{ + cout << " Reading BW table " << + (is_same::value ? "(double "s : "(single "s) << " precision)\n"s; + + auto ifs = ifstream(input_file, std::ios::binary); + auto raw_data = vector(istreambuf_iterator(ifs), {}); + ifs.close(); + + auto raw_iter = raw_data.begin(); + const auto size_first = pxr_sr::get_out(raw_iter); + if(size_first <= 0 || size_first >= raw_data.size() ) + AbortWithMessage("Something is wrong with " + input_file); + + const auto raw_dndt_table = vector{ + raw_iter, raw_iter+size_first}; + + const auto raw_pair_prod_table = vector{ + raw_iter+size_first, raw_data.end()}; + + const auto dndt_table = + pxr_bw::dndt_lookup_table>{raw_dndt_table}; + const auto pair_prod_table = + pxr_bw::pair_prod_lookup_table>{raw_pair_prod_table}; + + if (!dndt_table.is_init() || !pair_prod_table.is_init()) + AbortWithMessage("Something went wrong with lookup table initialization"); + + auto of_dndt = ofstream{outfile_name + "_dndt"}; + of_dndt << std::setprecision(std::numeric_limits::digits10 + 1); + const auto coord_dndt = dndt_table.get_all_coordinates(); + for (const auto& cc : coord_dndt ) + of_dndt << cc << " " << dndt_table.interp(cc) << "\n"; + of_dndt.close(); + + auto of_pair = ofstream{outfile_name + "_pair"}; + of_pair << std::setprecision(std::numeric_limits::digits10 + 1); + const auto wrapper = bw_pair_production_table_wrapper{pair_prod_table}; + wrapper.write_table_data(of_pair); + of_pair.close(); +} + +template +void ReadTableQS ( + const string& input_file, const string& outfile_name) +{ + cout << " Reading QS table " << + (is_same::value ? "(double "s : "(single "s) << " precision)\n"s; + + auto ifs = ifstream(input_file, std::ios::binary); + auto raw_data = vector(istreambuf_iterator(ifs), {}); + ifs.close(); + + auto raw_iter = raw_data.begin(); + const auto size_first = pxr_sr::get_out(raw_iter); + if(size_first <= 0 || size_first >= raw_data.size() ) + AbortWithMessage("Something is wrong with " + input_file); + + const auto raw_dndt_table = vector{ + raw_iter, raw_iter+size_first}; + + const auto raw_phot_em_table = vector{ + raw_iter+size_first, raw_data.end()}; + + const auto dndt_table = + pxr_qs::dndt_lookup_table>{raw_dndt_table}; + const auto phot_em_table = + pxr_qs::photon_emission_lookup_table>{raw_phot_em_table}; + + if (!dndt_table.is_init() || !phot_em_table.is_init()) + AbortWithMessage("Something went wrong with lookup table initialization"); + + auto of_dndt = ofstream{outfile_name + "_dndt"}; + of_dndt << std::setprecision(std::numeric_limits::digits10 + 1); + const auto coord_dndt = dndt_table.get_all_coordinates(); + for (const auto& cc : coord_dndt ) + of_dndt << cc << " " << dndt_table.interp(cc) << "\n"; + of_dndt.close(); + + auto of_phot_em = ofstream{outfile_name + "_phot_em"}; + of_phot_em << std::setprecision(std::numeric_limits::digits10 + 1); + + const auto wrapper = qs_photon_emission_table_wrapper{phot_em_table}; + wrapper.write_table_data(of_phot_em); + of_phot_em.close(); + + return; +} + +template +void +bw_pair_production_table_wrapper::write_table_data( + std::ofstream& of) const +{ + const auto how_many_x = this->m_table.get_how_many_x(); + const auto how_many_y = this->m_table.get_how_many_y(); + for (int i = 0; i < how_many_x; ++i){ + for (int j = 0; j < how_many_y; ++j){ + const auto xcoord = this->m_table.get_x_coord(i); + const auto ycoord = this->m_table.get_y_coord(j); + const auto val = this->m_table.get_val(i,j); + of << std::exp(xcoord) << " " << ycoord*std::exp(xcoord) + << " " << val << "\n"; + } + } +} + +template +void +qs_photon_emission_table_wrapper::write_table_data( + std::ofstream& of) const +{ + const auto how_many_x = this->m_table.get_how_many_x(); + const auto how_many_y = this->m_table.get_how_many_y(); + for (int i = 0; i < how_many_x; ++i){ + for (int j = 0; j < how_many_y; ++j){ + const auto xcoord = this->m_table.get_x_coord(i); + const auto ycoord = this->m_table.get_y_coord(j); + const auto val = this->m_table.get_val(i,j); + of << std::exp(xcoord) << " " << std::exp(ycoord)*std::exp(xcoord) + << " " << std::exp(val) << "\n"; + } + } +} diff --git a/cmake/WarpXFunctions.cmake b/cmake/WarpXFunctions.cmake index a189a8649d7..6e0e2ca5d1d 100644 --- a/cmake/WarpXFunctions.cmake +++ b/cmake/WarpXFunctions.cmake @@ -461,6 +461,7 @@ function(warpx_print_summary) message(" OPENPMD: ${WarpX_OPENPMD}") message(" QED: ${WarpX_QED}") message(" QED table generation: ${WarpX_QED_TABLE_GEN}") + message(" QED tools: ${WarpX_QED_TOOLS}") message(" SENSEI: ${WarpX_SENSEI}") message("") endfunction() diff --git a/cmake/dependencies/PICSAR.cmake b/cmake/dependencies/PICSAR.cmake index a1e93a9e33c..9086421356f 100644 --- a/cmake/dependencies/PICSAR.cmake +++ b/cmake/dependencies/PICSAR.cmake @@ -14,18 +14,27 @@ function(find_picsar) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Enable or disable QED lookup tables generation - - # If table generation is enabled, enable or disable - # openMP support depending on WarpX_COMPUTE - if(WarpX_QED_TABLE_GEN) + if(WarpX_QED_TABLE_GEN OR WarpX_QED_TOOLS) set(PXRMP_QED_TABLEGEN ON CACHE INTERNAL "") - if(WarpX_COMPUTE STREQUAL OMP) - set(PXRMP_QED_OMP ON CACHE INTERNAL "") + else() + set(PXRMP_QED_TABLEGEN OFF CACHE INTERNAL "") + endif() + + # Enable or disable OpenMP for lookup tables generation + if(PXRMP_QED_TABLEGEN) + if(WarpX_QED_TABLES_GEN_OMP STREQUAL AUTO) + find_package(OpenMP REQUIRED CXX) + if(OpenMP_CXX_FOUND) + set(PXRMP_QED_OMP ON CACHE INTERNAL "") + else() + set(PXRMP_QED_OMP OFF CACHE INTERNAL "") + endif() + elseif(WarpX_QED_TABLES_GEN_OMP STREQUAL ON) + set(PXRMP_QED_OMP ON CACHE INTERNAL "") else() - set(PXRMP_QED_OMP OFF CACHE INTERNAL "") + set(PXRMP_QED_OMP OFF CACHE INTERNAL "") endif() else() - set(PXRMP_QED_TABLEGEN OFF CACHE INTERNAL "") set(PXRMP_QED_OMP OFF CACHE INTERNAL "") endif()