1 #ifndef OPENMC_LATTICE_H
2 #define OPENMC_LATTICE_H
3 
4 #include <cstdint>
5 #include <string>
6 #include <unordered_map>
7 
8 #include "hdf5.h"
9 #include "pugixml.hpp"
10 
11 #include "openmc/array.h"
12 #include "openmc/constants.h"
13 #include "openmc/memory.h"
14 #include "openmc/position.h"
15 #include "openmc/vector.h"
16 
17 namespace openmc {
18 
19 //==============================================================================
20 // Module constants
21 //==============================================================================
22 
23 constexpr int32_t NO_OUTER_UNIVERSE{-1};
24 
25 enum class LatticeType {
26   rect, hex
27 };
28 
29 //==============================================================================
30 // Global variables
31 //==============================================================================
32 
33 class Lattice;
34 
35 namespace model {
36   extern std::unordered_map<int32_t, int32_t> lattice_map;
37   extern vector<unique_ptr<Lattice>> lattices;
38 } // namespace model
39 
40 //==============================================================================
41 //! \class Lattice
42 //! \brief Abstract type for ordered array of universes.
43 //==============================================================================
44 
45 class LatticeIter;
46 class ReverseLatticeIter;
47 
48 class Lattice
49 {
50 public:
51   int32_t id_;                         //!< Universe ID number
52   std::string name_;                   //!< User-defined name
53   LatticeType type_;
54   vector<int32_t> universes_;          //!< Universes filling each lattice tile
55   int32_t outer_ {NO_OUTER_UNIVERSE};  //!< Universe tiled outside the lattice
56   vector<int32_t> offsets_;            //!< Distribcell offset table
57 
58   explicit Lattice(pugi::xml_node lat_node);
59 
~Lattice()60   virtual ~Lattice() {}
61 
62   virtual int32_t const& operator[](array<int, 3> const& i_xyz) = 0;
63 
64   virtual LatticeIter begin();
65   LatticeIter end();
66 
67   virtual ReverseLatticeIter rbegin();
68   ReverseLatticeIter rend();
69 
70   //! Convert internal universe values from IDs to indices using universe_map.
71   void adjust_indices();
72 
73   //! Allocate offset table for distribcell.
allocate_offset_table(int n_maps)74   void allocate_offset_table(int n_maps)
75   {offsets_.resize(n_maps * universes_.size(), C_NONE);}
76 
77   //! Populate the distribcell offset tables.
78   int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map,
79     std::unordered_map<int32_t, int32_t>& univ_count_memo);
80 
81   //! \brief Check lattice indices.
82   //! \param i_xyz[3] The indices for a lattice tile.
83   //! \return true if the given indices fit within the lattice bounds.  False
84   //!   otherwise.
85   virtual bool are_valid_indices(array<int, 3> const& i_xyz) const = 0;
86 
87   //! \brief Find the next lattice surface crossing
88   //! \param r A 3D Cartesian coordinate.
89   //! \param u A 3D Cartesian direction.
90   //! \param i_xyz The indices for a lattice tile.
91   //! \return The distance to the next crossing and an array indicating how the
92   //!   lattice indices would change after crossing that boundary.
93   virtual std::pair<double, array<int, 3>> distance(
94     Position r, Direction u, const array<int, 3>& i_xyz) const = 0;
95 
96   //! \brief Find the lattice tile indices for a given point.
97   //! \param r A 3D Cartesian coordinate.
98   //! \param u Direction of a particle
99   //! \param result resulting indices to save to
100   virtual void get_indices(
101     Position r, Direction u, array<int, 3>& result) const = 0;
102 
103   //! \brief Get coordinates local to a lattice tile.
104   //! \param r A 3D Cartesian coordinate.
105   //! \param i_xyz The indices for a lattice tile.
106   //! \return Local 3D Cartesian coordinates.
107   virtual Position get_local_position(
108     Position r, const array<int, 3>& i_xyz) const = 0;
109 
110   //! \brief Check flattened lattice index.
111   //! \param indx The index for a lattice tile.
112   //! \return true if the given index fit within the lattice bounds.  False
113   //!   otherwise.
is_valid_index(int indx)114   virtual bool is_valid_index(int indx) const
115   {return (indx >= 0) && (indx < universes_.size());}
116 
117   //! \brief Get the distribcell offset for a lattice tile.
118   //! \param The map index for the target cell.
119   //! \param i_xyz[3] The indices for a lattice tile.
120   //! \return Distribcell offset i.e. the largest instance number for the target
121   //!  cell found in the geometry tree under this lattice tile.
122   virtual int32_t& offset(int map, array<int, 3> const& i_xyz) = 0;
123 
124   //! \brief Get the distribcell offset for a lattice tile.
125   //! \param The map index for the target cell.
126   //! \param indx The index for a lattice tile.
127   //! \return Distribcell offset i.e. the largest instance number for the target
128   //!  cell found in the geometry tree for this lattice index.
129   virtual int32_t offset(int map, int indx) const = 0;
130 
131   //! \brief Convert an array index to a useful human-readable string.
132   //! \param indx The index for a lattice tile.
133   //! \return A string representing the lattice tile.
134   virtual std::string index_to_string(int indx) const = 0;
135 
136   //! \brief Write lattice information to an HDF5 group.
137   //! \param group_id An HDF5 group id.
138   void to_hdf5(hid_t group_id) const;
139 
140 protected:
141   bool is_3d_;  //!< Has divisions along the z-axis?
142 
143   virtual void to_hdf5_inner(hid_t group_id) const = 0;
144 };
145 
146 //==============================================================================
147 //! An iterator over lattice universes.
148 //==============================================================================
149 
150 class LatticeIter
151 {
152 public:
153   int indx_;  //!< An index to a Lattice universes or offsets array.
154 
LatticeIter(Lattice & lat,int indx)155   LatticeIter(Lattice &lat, int indx)
156     : indx_(indx), lat_(lat)
157   {}
158 
159   bool operator==(const LatticeIter &rhs) {return (indx_ == rhs.indx_);}
160 
161   bool operator!=(const LatticeIter &rhs) {return !(*this == rhs);}
162 
163   int32_t& operator*() {return lat_.universes_[indx_];}
164 
165   LatticeIter& operator++()
166   {
167     while (indx_ < lat_.universes_.size()) {
168       ++indx_;
169       if (lat_.is_valid_index(indx_)) return *this;
170     }
171     indx_ = lat_.universes_.size();
172     return *this;
173   }
174 
175 protected:
176   Lattice& lat_;
177 };
178 
179 //==============================================================================
180 //! A reverse iterator over lattice universes.
181 //==============================================================================
182 
183 class ReverseLatticeIter : public LatticeIter
184 {
185 public:
ReverseLatticeIter(Lattice & lat,int indx)186   ReverseLatticeIter(Lattice &lat, int indx)
187     : LatticeIter {lat, indx}
188   {}
189 
190   ReverseLatticeIter& operator++()
191   {
192     while (indx_ > -1) {
193       --indx_;
194       if (lat_.is_valid_index(indx_)) return *this;
195     }
196     indx_ = -1;
197     return *this;
198   }
199 };
200 
201 //==============================================================================
202 
203 class RectLattice : public Lattice
204 {
205 public:
206   explicit RectLattice(pugi::xml_node lat_node);
207 
208   int32_t const& operator[](array<int, 3> const& i_xyz);
209 
210   bool are_valid_indices(array<int, 3> const& i_xyz) const;
211 
212   std::pair<double, array<int, 3>> distance(
213     Position r, Direction u, const array<int, 3>& i_xyz) const;
214 
215   void get_indices(Position r, Direction u, array<int, 3>& result) const;
216 
217   Position get_local_position(Position r, const array<int, 3>& i_xyz) const;
218 
219   int32_t& offset(int map, array<int, 3> const& i_xyz);
220 
221   int32_t offset(int map, int indx) const;
222 
223   std::string index_to_string(int indx) const;
224 
225   void to_hdf5_inner(hid_t group_id) const;
226 
227 private:
228   array<int, 3> n_cells_;         //!< Number of cells along each axis
229   Position lower_left_;           //!< Global lower-left corner of the lattice
230   Position pitch_;                //!< Lattice tile width along each axis
231 };
232 
233 //==============================================================================
234 
235 class HexLattice : public Lattice
236 {
237 public:
238   explicit HexLattice(pugi::xml_node lat_node);
239 
240   int32_t const& operator[](array<int, 3> const& i_xyz);
241 
242   LatticeIter begin();
243 
244   ReverseLatticeIter rbegin();
245 
246   bool are_valid_indices(array<int, 3> const& i_xyz) const;
247 
248   std::pair<double, array<int, 3>> distance(
249     Position r, Direction u, const array<int, 3>& i_xyz) const;
250 
251   void get_indices(Position r, Direction u, array<int, 3>& result) const;
252 
253   Position get_local_position(Position r, const array<int, 3>& i_xyz) const;
254 
255   bool is_valid_index(int indx) const;
256 
257   int32_t& offset(int map, array<int, 3> const& i_xyz);
258 
259   int32_t offset(int map, int indx) const;
260 
261   std::string index_to_string(int indx) const;
262 
263   void to_hdf5_inner(hid_t group_id) const;
264 
265 private:
266   enum class Orientation {
267       y, //!< Flat side of lattice parallel to y-axis
268       x  //!< Flat side of lattice parallel to x-axis
269   };
270 
271   //! Fill universes_ vector for 'y' orientation
272   void fill_lattice_y(const vector<std::string>& univ_words);
273 
274   //! Fill universes_ vector for 'x' orientation
275   void fill_lattice_x(const vector<std::string>& univ_words);
276 
277   int n_rings_;                   //!< Number of radial tile positions
278   int n_axial_;                   //!< Number of axial tile positions
279   Orientation orientation_;       //!< Orientation of lattice
280   Position center_;               //!< Global center of lattice
281   array<double, 2> pitch_;        //!< Lattice tile width and height
282 };
283 
284 //==============================================================================
285 // Non-member functions
286 //==============================================================================
287 
288 void read_lattices(pugi::xml_node node);
289 
290 } //  namespace openmc
291 #endif // OPENMC_LATTICE_H
292