NEURON
nrnoc_ml.h
Go to the documentation of this file.
1 #pragma once
2 #include <cstddef> // std::ptrdiff_t, std::size_t
3 #include <limits> // std::numeric_limits
4 #include <vector> // std::vector
5 
6 struct Node;
7 struct Prop;
8 
9 namespace neuron::container {
10 struct generic_data_handle;
11 }
13 
14 // Only include a forward declaration to help avoid translated MOD file code relying on its layout
16 struct storage;
17 }
18 
19 /**
20  * @brief A view into a set of mechanism instances.
21  *
22  * This is a view to a set of mechanism instances that are contiguous in the
23  * underlying storage. This is inherently something that only makes sense if
24  * the underlying data are sorted. In this case, Memb_list essentially
25  * contains a pointer to the underlying storage struct and a single offset into
26  * it. This covers use-cases like Memb_list inside NrnThread -- the data are
27  * partitioned by NrnThread in nrn_sort_mech_data so all the instances of a
28  * particular mechanism in a particular thread are next to each other in the
29  * storage.
30  *
31  * Because this type is passed from NEURON library code into code generated from MOD files, it is
32  * prone to ABI issues -- particularly when dealing with Python wheels.
33  */
34 struct Memb_list {
35  /**
36  * @brief Construct a null Memb_list that does not refer to any thread/type.
37  */
38  Memb_list() = default;
39 
40  /**
41  * @brief Construct a Memb_list that knows its type + underlying storage.
42  *
43  * Defined in .cpp to hide neuron::container::Mechanism::storage layout from translated MOD file
44  * code.
45  */
46  explicit Memb_list(int type);
47 
48  /**
49  * @brief Uninitialize, freeing any allocated mem for nodes.
50  */
51  ~Memb_list() noexcept;
52 
53  // Move is ok. Copy is restricted
54  Memb_list(Memb_list&&) noexcept;
55  Memb_list& operator=(Memb_list&&) noexcept;
56 
57  /**
58  * @brief Allocate memory for node_count nodes.
59  * @param also_pdata Allocate also pdata Datum's
60  */
61  void nodes_alloc(int node_count, bool also_pdata);
62 
63  /**
64  * @brief Free memory allocated for nodes (with nodes_alloc)
65  */
66  void nodes_free();
67 
69  /* nodeindices contains all nodes this extension is responsible for,
70  * ordered according to the matrix. This allows to access the matrix
71  * directly via the nrn_actual_* arrays instead of accessing it in the
72  * order of insertion and via the node-structure, making it more
73  * cache-efficient */
74  int* nodeindices{};
75  Datum** pdata{};
76  Prop** prop{};
77  Datum* _thread{}; /* thread specific data (when static is no good) */
78  int nodecount{};
79  /**
80  * @brief Get a vector of double* representing the model data.
81  *
82  * Calling .data() on the return value yields a double** that is similar to
83  * the old _data member, with the key difference that its indices are
84  * transposed. Now, the first index corresponds to the variable and the
85  * second index corresponds to the instance of the mechanism. This method
86  * is useful for interfacing with CoreNEURON but should be deprecated and
87  * removed along with the translation layer between NEURON and CoreNEURON.
88  *
89  * Defined in .cpp to hide neuron::container::Mechanism::storage layout from translated MOD file
90  * code.
91  */
92  [[nodiscard]] std::vector<double*> data();
93 
94  template <std::size_t variable>
95  [[nodiscard]] double& fpfield(std::size_t instance) {
96  return data(instance, variable);
97  }
98 
99  template <std::size_t variable>
100  [[nodiscard]] double* dptr_field(std::size_t instance) {
101  return dptr_field(instance, variable);
102  }
103 
105  std::size_t instance,
107 
108  /**
109  * @brief Get the `variable`-th floating point value in `instance` of the mechanism.
110  *
111  * Defined in .cpp to hide neuron::container::Mechanism::storage layout from translated MOD file
112  * code.
113  */
114  [[nodiscard]] __attribute__((pure)) double& data(std::size_t instance,
115  int variable,
116  int array_index = 0);
117 
118  /**
119  * @brief Get the `variable`-th pointer-to-double in `instance` of the mechanism.
120  *
121  * Defined in .cpp to hide the full definition of Datum from translated MOD file code.
122  */
123  [[nodiscard]] __attribute__((pure)) double* dptr_field(std::size_t instance, int variable);
124 
125  /**
126  * @brief Get the `variable`-th floating point value in `instance` of the mechanism.
127  *
128  * Defined in .cpp to hide neuron::container::Mechanism::storage layout from translated MOD file
129  * code.
130  */
131  [[nodiscard]] __attribute__((pure)) double const& data(std::size_t instance,
132  int variable,
133  int array_index = 0) const;
134 
135 
136  /**
137  * @brief Get the number of fields/variables of this mechanism.
138  */
139  [[nodiscard]] int get_num_variables() const;
140 
141  /**
142  * @brief Get the array_dims of field `variable`.
143  */
144  [[nodiscard]] int get_array_dims(int variable) const;
145 
146  /**
147  * @brief Get the array_dims of field `variable`.
148  */
149  [[nodiscard]] int const* get_array_dims() const;
150 
151  /**
152  * @brief Get the array_dims of field `variable`.
153  */
154  [[nodiscard]] int get_array_prefix_sums(int variable) const;
155 
156  /**
157  * @brief Get the array_dims of field `variable`.
158  */
159  [[nodiscard]] int const* get_array_prefix_sums() const;
160 
161 
162  /**
163  * @brief Calculate a legacy index of the given pointer in this mechanism data.
164  *
165  * This used to be defined as ptr - ml->_data[0] if ptr belonged to the
166  * given mechanism, i.e. an offset from the zeroth element of the zeroth
167  * mechanism. This is useful when interfacing with CoreNEURON and for
168  * parameter exchange with other MPI ranks.
169  *
170  * Defined in .cpp to hide neuron::container::Mechanism::storage layout from translated MOD file
171  * code.
172  */
173  [[nodiscard]] std::ptrdiff_t legacy_index(double const* ptr) const;
174 
175  /**
176  * @brief Calculate a legacy index from a data handle.
177  */
178  [[nodiscard]] std::ptrdiff_t legacy_index(
179  neuron::container::data_handle<double> const& dh) const {
180  return legacy_index(static_cast<double const*>(dh));
181  }
182 
183  /**
184  * @brief Get the offset of this Memb_list into global storage for this type.
185  *
186  * In the simplest case then this Memb_list represents all instances of a
187  * particular type in a particular thread, which are contiguous because the
188  * data have been sorted by a call like
189  * auto const cache_token = nrn_ensure_model_data_are_sorted()
190  * and this offset has been set to be
191  * cache_token.thread_cache(thread_id).mechanism_offset.at(mechanism_type)
192  * so that the first argument to data(i, j) is an offset inside this thread,
193  * not the global structure.
194  */
195  [[nodiscard]] std::size_t get_storage_offset() const {
197  return m_storage_offset;
198  }
199 
200  /**
201  * @brief Set the offset of this Memb_list into global storage for this type.
202  *
203  * See the documentation for @ref get_storage_offset.
204  *
205  * @todo At the moment this is set as part of sorting/permuting data, but it
206  * is not automatically invalidated when the cache / sorted status is
207  * reset. Consider if these offsets can be more explicitly tied to the
208  * lifetime of the cache data.
209  */
210  void set_storage_offset(std::size_t offset) {
211  m_storage_offset = offset;
212  }
213 
214  /**
215  * @brief Set the pointer to the underlying data container.
216  *
217  * This is a quasi-private method that you should think twice before
218  * calling. Normally m_storage would automatically be set by the constructor
219  * taking an integer mechanism type.
220  */
222  m_storage = storage;
223  }
224 
225  /**
226  * @brief Get the mechanism type.
227  *
228  * Defined in .cpp to hide neuron::container::Mechanism::storage layout from translated MOD file
229  * code.
230  */
231  [[nodiscard]] int type() const;
232 
233  [[nodiscard]] int _type() const {
234  return type();
235  }
236 
237  private:
238  /**
239  * @brief Pointer to the global mechanism data structure for this mech type.
240  */
242 
243  /**
244  * @brief Offset of this thread+mechanism into the global mechanism data.
245  *
246  * This is locally a piece of "cache" information like node_data_offset --
247  * the question is whether Memb_list itself is also considered a
248  * transient/cache type, in which case this is fine, or if it's considered
249  * permanent...in which case this value should probably not live here.
250  */
252 
253  /**
254  * @brief Whether this memlist owns its nodes memory or whether we are a view
255  * Has implications on memory management
256  */
257  bool m_owns_nodes{false};
258 
259  // No copying since one may own memory and double free would occur
260  Memb_list(const Memb_list&) = delete;
261  Memb_list& operator=(const Memb_list&) = default; // private, used by move ctrs
262 };
__attribute__((noreturn)) void sigsegvcatch(int)
Definition: hoc.cpp:749
#define assert(ex)
Definition: hocassrt.h:24
size_t get_num_variables(T const &t)
constexpr std::size_t invalid_row
A view into a set of mechanism instances.
Definition: nrnoc_ml.h:34
void set_storage_offset(std::size_t offset)
Set the offset of this Memb_list into global storage for this type.
Definition: nrnoc_ml.h:210
int const * get_array_prefix_sums() const
Get the array_dims of field variable.
Definition: memblist.cpp:125
double & fpfield(std::size_t instance)
Definition: nrnoc_ml.h:95
neuron::container::data_handle< double > data_handle(std::size_t instance, neuron::container::field_index field) const
Definition: memblist.cpp:76
Memb_list()=default
Construct a null Memb_list that does not refer to any thread/type.
int _type() const
Definition: nrnoc_ml.h:233
bool m_owns_nodes
Whether this memlist owns its nodes memory or whether we are a view Has implications on memory manage...
Definition: nrnoc_ml.h:257
int nodecount
Definition: nrnoc_ml.h:78
std::ptrdiff_t legacy_index(neuron::container::data_handle< double > const &dh) const
Calculate a legacy index from a data handle.
Definition: nrnoc_ml.h:178
void nodes_free()
Free memory allocated for nodes (with nodes_alloc)
Definition: memblist.cpp:36
int * nodeindices
Definition: nrnoc_ml.h:74
Memb_list(const Memb_list &)=delete
int type() const
Get the mechanism type.
Definition: memblist.cpp:177
Memb_list & operator=(const Memb_list &)=default
Node ** nodelist
Definition: nrnoc_ml.h:68
~Memb_list() noexcept
Uninitialize, freeing any allocated mem for nodes.
Definition: memblist.cpp:58
neuron::container::Mechanism::storage * m_storage
Pointer to the global mechanism data structure for this mech type.
Definition: nrnoc_ml.h:241
void set_storage_pointer(neuron::container::Mechanism::storage *storage)
Set the pointer to the underlying data container.
Definition: nrnoc_ml.h:221
std::ptrdiff_t legacy_index(double const *ptr) const
Calculate a legacy index of the given pointer in this mechanism data.
Definition: memblist.cpp:131
Datum ** pdata
Definition: nrnoc_ml.h:75
std::vector< double * > data()
Get a vector of double* representing the model data.
Definition: memblist.cpp:64
int const * get_array_dims() const
Get the array_dims of field variable.
Definition: memblist.cpp:115
Prop ** prop
Definition: nrnoc_ml.h:76
std::size_t m_storage_offset
Offset of this thread+mechanism into the global mechanism data.
Definition: nrnoc_ml.h:251
std::size_t get_storage_offset() const
Get the offset of this Memb_list into global storage for this type.
Definition: nrnoc_ml.h:195
double * dptr_field(std::size_t instance)
Definition: nrnoc_ml.h:100
Datum * _thread
Definition: nrnoc_ml.h:77
void nodes_alloc(int node_count, bool also_pdata)
Allocate memory for node_count nodes.
Definition: memblist.cpp:19
Definition: section.h:105
Definition: section.h:231
Underlying storage for all instances of a particular Mechanism.
Struct used to index SoAoS data, such as array range variables.
Non-template stable handle to a generic value.