|
| 1 | +//! \file ncrystal_load.h |
| 2 | +//! \brief Helper class taking care of loading NCrystal at runtime. |
| 3 | + |
| 4 | +#ifndef OPENMC_NCRYSTAL_LOAD_H |
| 5 | +#define OPENMC_NCRYSTAL_LOAD_H |
| 6 | + |
| 7 | +#include <algorithm> // for swap |
| 8 | +#include <functional> // for function |
| 9 | +#include <memory> // for shared_ptr |
| 10 | +#include <utility> // for move |
| 11 | + |
| 12 | +namespace NCrystalVirtualAPI { |
| 13 | + |
| 14 | +// NOTICE: Do NOT make ANY changes in the NCrystalVirtualAPI::VirtAPI_Type1_v1 |
| 15 | +// class, it is required to stay exactly constant over time and compatible with |
| 16 | +// the same definition used to compile the NCrystal library! But changes to |
| 17 | +// white space, comments, and formatting is of course allowed. This API was |
| 18 | +// introduced in NCrystal 4.1.0. |
| 19 | + |
| 20 | +//! Abstract base class for NCrystal interface which must be declared exactly as |
| 21 | +// it is in NCrystal itself. |
| 22 | + |
| 23 | +class VirtAPI_Type1_v1 { |
| 24 | +public: |
| 25 | + // Note: neutron must be an array of length 4 with values {ekin,ux,uy,uz} |
| 26 | + class ScatterProcess; |
| 27 | + virtual const ScatterProcess* createScatter(const char* cfgstr) const = 0; |
| 28 | + virtual const ScatterProcess* cloneScatter(const ScatterProcess*) const = 0; |
| 29 | + virtual void deallocateScatter(const ScatterProcess*) const = 0; |
| 30 | + virtual double crossSectionUncached( |
| 31 | + const ScatterProcess&, const double* neutron) const = 0; |
| 32 | + virtual void sampleScatterUncached(const ScatterProcess&, |
| 33 | + std::function<double()>& rng, double* neutron) const = 0; |
| 34 | + // Plumbing: |
| 35 | + static constexpr unsigned interface_id = 1001; |
| 36 | + virtual ~VirtAPI_Type1_v1() = default; |
| 37 | + VirtAPI_Type1_v1() = default; |
| 38 | + VirtAPI_Type1_v1(const VirtAPI_Type1_v1&) = delete; |
| 39 | + VirtAPI_Type1_v1& operator=(const VirtAPI_Type1_v1&) = delete; |
| 40 | + VirtAPI_Type1_v1(VirtAPI_Type1_v1&&) = delete; |
| 41 | + VirtAPI_Type1_v1& operator=(VirtAPI_Type1_v1&&) = delete; |
| 42 | +}; |
| 43 | + |
| 44 | +} // namespace NCrystalVirtualAPI |
| 45 | + |
| 46 | +namespace openmc { |
| 47 | + |
| 48 | +using NCrystalAPI = NCrystalVirtualAPI::VirtAPI_Type1_v1; |
| 49 | + |
| 50 | +//! Function which locates and loads NCrystal at runtime using the virtual API |
| 51 | +std::shared_ptr<const NCrystalAPI> load_ncrystal_api(); |
| 52 | + |
| 53 | +//! Class encapsulating exactly the parts of NCrystal needed by OpenMC |
| 54 | + |
| 55 | +class NCrystalScatProc final { |
| 56 | +public: |
| 57 | + //! Empty constructor which does not load NCrystal |
| 58 | + NCrystalScatProc() {} |
| 59 | + |
| 60 | + //! Load NCrystal and instantiate a scattering process |
| 61 | + //! \param cfgstr NCrystal cfg-string defining the material. |
| 62 | + NCrystalScatProc(const char* cfgstr) |
| 63 | + : api_(load_ncrystal_api()), p_(api_->createScatter(cfgstr)) |
| 64 | + {} |
| 65 | + |
| 66 | + // Note: Neutron state array is {ekin,ux,uy,uz} |
| 67 | + |
| 68 | + //! Returns total scattering cross section in units of barns per atom. |
| 69 | + //! \param neutron_state array {ekin,ux,uy,uz} with ekin (eV) and direction. |
| 70 | + double cross_section(const double* neutron_state) const |
| 71 | + { |
| 72 | + return api_->crossSectionUncached(*p_, neutron_state); |
| 73 | + } |
| 74 | + |
| 75 | + //! Returns total scattering cross section in units of barns per atom. |
| 76 | + //! \param rng function returning random numbers in the unit interval |
| 77 | + //! \param neutron_state array {ekin,ux,uy,uz} with ekin (eV) and direction. |
| 78 | + void scatter(std::function<double()>& rng, double* neutron_state) const |
| 79 | + { |
| 80 | + api_->sampleScatterUncached(*p_, rng, neutron_state); |
| 81 | + } |
| 82 | + |
| 83 | + //! Clones the object which is otherwise move-only |
| 84 | + NCrystalScatProc clone() const |
| 85 | + { |
| 86 | + NCrystalScatProc c; |
| 87 | + if (p_) { |
| 88 | + c.api_ = api_; |
| 89 | + c.p_ = api_->cloneScatter(p_); |
| 90 | + } |
| 91 | + return c; |
| 92 | + } |
| 93 | + |
| 94 | + // Plumbing (move-only semantics, but supports explicit clone): |
| 95 | + NCrystalScatProc(const NCrystalScatProc&) = delete; |
| 96 | + NCrystalScatProc& operator=(const NCrystalScatProc&) = delete; |
| 97 | + |
| 98 | + NCrystalScatProc(NCrystalScatProc&& o) : api_(std::move(o.api_)), p_(nullptr) |
| 99 | + { |
| 100 | + std::swap(p_, o.p_); |
| 101 | + } |
| 102 | + |
| 103 | + NCrystalScatProc& operator=(NCrystalScatProc&& o) |
| 104 | + { |
| 105 | + if (p_) { |
| 106 | + api_->deallocateScatter(p_); |
| 107 | + p_ = nullptr; |
| 108 | + } |
| 109 | + std::swap(api_, o.api_); |
| 110 | + std::swap(p_, o.p_); |
| 111 | + return *this; |
| 112 | + } |
| 113 | + |
| 114 | + ~NCrystalScatProc() |
| 115 | + { |
| 116 | + if (p_) |
| 117 | + api_->deallocateScatter(p_); |
| 118 | + } |
| 119 | + |
| 120 | +private: |
| 121 | + std::shared_ptr<const NCrystalAPI> api_; |
| 122 | + const NCrystalAPI::ScatterProcess* p_ = nullptr; |
| 123 | +}; |
| 124 | + |
| 125 | +} // namespace openmc |
| 126 | + |
| 127 | +#endif |
0 commit comments