|
3 | 3 |
|
4 | 4 | #include "particlezoo/Particle.h" |
5 | 5 | #include "particlezoo/PDGParticleCodes.h" |
6 | | -#include "particlezoo/IAEA/IAEAphspFile.h" |
| 6 | +#include "particlezoo/PhaseSpaceFileReader.h" |
| 7 | +#include "particlezoo/utilities/formats.h" |
7 | 8 |
|
8 | 9 | namespace py = pybind11; |
9 | 10 | using namespace ParticleZoo; |
10 | 11 |
|
11 | 12 | PYBIND11_MODULE(_pz, m) { |
12 | 13 | m.doc() = "Python bindings for ParticleZoo core and IAEA reader"; |
13 | 14 |
|
14 | | - // ParticleType enum (expose only sentinel values; use helpers for full mapping) |
15 | | - py::enum_<ParticleType>(m, "ParticleType") |
16 | | - .value("Unsupported", ParticleType::Unsupported) |
17 | | - .value("PseudoParticle", ParticleType::PseudoParticle); |
| 15 | + // Ensure built-in formats are registered before any factory calls |
| 16 | + try { FormatRegistry::RegisterStandardFormats(); } catch (...) { /* idempotent; ignore */ } |
| 17 | + |
| 18 | + // ParticleType enum (full mapping from X-macro via helper in header) |
| 19 | + auto pyParticleType = py::enum_<ParticleType>(m, "ParticleType"); |
| 20 | + for (const auto &entry : getAllParticleTypes()) { |
| 21 | + pyParticleType.value(std::string(entry.first).c_str(), entry.second); |
| 22 | + } |
| 23 | + // ensure enum is closed/usable |
| 24 | + pyParticleType.export_values(); |
| 25 | + |
| 26 | + // Convenience: return all particle types as a dict name -> enum value |
| 27 | + m.def("all_particle_types", [](){ |
| 28 | + py::dict d; |
| 29 | + for (const auto &entry : getAllParticleTypes()) { |
| 30 | + d[py::str(entry.first)] = entry.second; |
| 31 | + } |
| 32 | + return d; |
| 33 | + }, "Return a mapping of ParticleType names to enum values"); |
18 | 34 |
|
19 | 35 | // Property enums |
20 | 36 | py::enum_<IntPropertyType>(m, "IntPropertyType") |
@@ -75,26 +91,66 @@ PYBIND11_MODULE(_pz, m) { |
75 | 91 | .def("set_incremental_histories", &Particle::setIncrementalHistories) |
76 | 92 | ; |
77 | 93 |
|
78 | | - // IAEA Reader |
79 | | - using IAEAReader = IAEAphspFile::Reader; |
80 | | - py::class_<IAEAReader>(m, "IAEAReader") |
81 | | - .def(py::init<const std::string&, const UserOptions&>(), |
82 | | - py::arg("filename"), py::arg("options") = UserOptions{}) |
83 | | - .def("get_number_of_particles", static_cast<std::uint64_t (IAEAReader::*)() const>(&IAEAReader::getNumberOfParticles)) |
84 | | - .def("get_number_of_particles_by_type", static_cast<std::uint64_t (IAEAReader::*)(ParticleType) const>(&IAEAReader::getNumberOfParticles), py::arg("particle_type")) |
85 | | - .def("get_number_of_original_histories", &IAEAReader::getNumberOfOriginalHistories) |
86 | | - .def("has_more_particles", &IAEAReader::hasMoreParticles) |
87 | | - .def("get_next_particle", static_cast<Particle (IAEAReader::*)()>(&IAEAReader::getNextParticle)) |
88 | | - .def("get_file_size", &IAEAReader::getFileSize) |
89 | | - .def("get_file_name", &IAEAReader::getFileName) |
90 | | - .def("close", &IAEAReader::close) |
91 | | - .def("__iter__", [](IAEAReader &self) -> IAEAReader& { return self; }, py::return_value_policy::reference_internal) |
92 | | - .def("__next__", [](IAEAReader &self) { |
| 94 | + // PhaseSpaceFileReader (abstract base; created via FormatRegistry factories) |
| 95 | + py::class_<PhaseSpaceFileReader, std::unique_ptr<PhaseSpaceFileReader>>(m, "PhaseSpaceFileReader") |
| 96 | + .def("get_number_of_particles", &PhaseSpaceFileReader::getNumberOfParticles) |
| 97 | + .def("get_number_of_original_histories", &PhaseSpaceFileReader::getNumberOfOriginalHistories) |
| 98 | + .def("get_histories_read", &PhaseSpaceFileReader::getHistoriesRead) |
| 99 | + .def("get_particles_read", static_cast<std::uint64_t (PhaseSpaceFileReader::*)()>(&PhaseSpaceFileReader::getParticlesRead)) |
| 100 | + .def("has_more_particles", &PhaseSpaceFileReader::hasMoreParticles) |
| 101 | + .def("get_next_particle", static_cast<Particle (PhaseSpaceFileReader::*)()>(&PhaseSpaceFileReader::getNextParticle)) |
| 102 | + .def("get_file_size", &PhaseSpaceFileReader::getFileSize) |
| 103 | + .def("get_file_name", &PhaseSpaceFileReader::getFileName) |
| 104 | + .def("get_phsp_format", &PhaseSpaceFileReader::getPHSPFormat) |
| 105 | + .def("move_to_particle", &PhaseSpaceFileReader::moveToParticle, py::arg("index")) |
| 106 | + .def("is_x_constant", &PhaseSpaceFileReader::isXConstant) |
| 107 | + .def("is_y_constant", &PhaseSpaceFileReader::isYConstant) |
| 108 | + .def("is_z_constant", &PhaseSpaceFileReader::isZConstant) |
| 109 | + .def("is_px_constant", &PhaseSpaceFileReader::isPxConstant) |
| 110 | + .def("is_py_constant", &PhaseSpaceFileReader::isPyConstant) |
| 111 | + .def("is_pz_constant", &PhaseSpaceFileReader::isPzConstant) |
| 112 | + .def("is_weight_constant", &PhaseSpaceFileReader::isWeightConstant) |
| 113 | + .def("get_constant_x", &PhaseSpaceFileReader::getConstantX) |
| 114 | + .def("get_constant_y", &PhaseSpaceFileReader::getConstantY) |
| 115 | + .def("get_constant_z", &PhaseSpaceFileReader::getConstantZ) |
| 116 | + .def("get_constant_px", &PhaseSpaceFileReader::getConstantPx) |
| 117 | + .def("get_constant_py", &PhaseSpaceFileReader::getConstantPy) |
| 118 | + .def("get_constant_pz", &PhaseSpaceFileReader::getConstantPz) |
| 119 | + .def("get_constant_weight", &PhaseSpaceFileReader::getConstantWeight) |
| 120 | + .def("close", &PhaseSpaceFileReader::close) |
| 121 | + .def("__iter__", [](PhaseSpaceFileReader &self) -> PhaseSpaceFileReader& { return self; }, py::return_value_policy::reference_internal) |
| 122 | + .def("__next__", [](PhaseSpaceFileReader &self) { |
93 | 123 | if (!self.hasMoreParticles()) throw py::stop_iteration(); |
94 | 124 | return self.getNextParticle(); |
95 | 125 | }) |
96 | 126 | ; |
97 | 127 |
|
| 128 | + // SupportedFormat struct |
| 129 | + py::class_<SupportedFormat>(m, "SupportedFormat") |
| 130 | + .def_property_readonly("name", [](const SupportedFormat& f){ return f.name; }) |
| 131 | + .def_property_readonly("description", [](const SupportedFormat& f){ return f.description; }) |
| 132 | + .def_property_readonly("file_extension", [](const SupportedFormat& f){ return f.fileExtension; }) |
| 133 | + .def_property_readonly("file_extension_can_have_suffix", [](const SupportedFormat& f){ return f.fileExtensionCanHaveSuffix; }) |
| 134 | + ; |
| 135 | + |
| 136 | + // FormatRegistry static interface |
| 137 | + py::class_<FormatRegistry>(m, "FormatRegistry") |
| 138 | + .def_static("register_standard_formats", &FormatRegistry::RegisterStandardFormats) |
| 139 | + .def_static("supported_formats", &FormatRegistry::SupportedFormats) |
| 140 | + .def_static("formats_for_extension", &FormatRegistry::FormatsForExtension, py::arg("extension")) |
| 141 | + .def_static("extension_for_format", &FormatRegistry::ExtensionForFormat, py::arg("format_name")) |
| 142 | + ; |
| 143 | + |
| 144 | + // Convenience factory functions for readers |
| 145 | + m.def("create_reader", [](const std::string& filename){ |
| 146 | + FormatRegistry::RegisterStandardFormats(); |
| 147 | + return FormatRegistry::CreateReader(filename, UserOptions{}); |
| 148 | + }, py::arg("filename")); |
| 149 | + m.def("create_reader_for_format", [](const std::string& format, const std::string& filename){ |
| 150 | + FormatRegistry::RegisterStandardFormats(); |
| 151 | + return FormatRegistry::CreateReader(format, filename, UserOptions{}); |
| 152 | + }, py::arg("format_name"), py::arg("filename")); |
| 153 | + |
98 | 154 | // Expose a simple alias to create a Particle by PDG code |
99 | 155 | m.def("particle_from_pdg", [](int pdg, float kineticEnergy, float x, float y, float z, float px, float py, float pz, bool isNewHistory, float weight){ |
100 | 156 | ParticleType t = getParticleTypeFromPDGID(static_cast<std::int32_t>(pdg)); |
|
0 commit comments