NEURON
memblist.cpp
Go to the documentation of this file.
3 #include "neuron/model_data.hpp"
4 #include "nrnassrt.h"
5 #include "nrnoc_ml.h"
6 
7 #include <cassert>
8 #include <iterator> // std::distance, std::next
9 #include <numeric> // std::accumulate
10 
11 extern void* emalloc(size_t);
12 
13 
15  : m_storage{&neuron::model().mechanism_data(type)} {
16  assert(type == m_storage->type());
17 }
18 
19 void Memb_list::nodes_alloc(int node_count, bool also_pdata) {
20  if (node_count == 0) {
21  return;
22  }
23  m_owns_nodes = true;
24  nodecount = node_count;
25  nodelist = (Node**) emalloc(node_count * sizeof(Node*));
26  nodeindices = (int*) emalloc(node_count * sizeof(int));
27  // Prop used by ode_map even when hoc_mech is false
28  prop = new Prop*[node_count];
29  if (also_pdata) {
30  pdata = (Datum**) emalloc(node_count * sizeof(Datum*));
31  } else {
32  pdata = nullptr;
33  }
34 }
35 
37  nodecount = 0;
39  free(std::exchange(nodelist, nullptr));
40  free(std::exchange(nodeindices, nullptr));
41  delete[] std::exchange(prop, nullptr);
42  free(std::exchange(pdata, nullptr));
43  m_owns_nodes = false; // make potentially reusable for a view
44 }
45 
46 Memb_list::Memb_list(Memb_list&& other) noexcept {
47  /// Other should not be used. But if it is, fine, but not the memory owner anymore
48  *this = other;
49  other.m_owns_nodes = false;
50 }
51 
53  *this = rhs;
54  rhs.m_owns_nodes = false;
55  return *this;
56 }
57 
59  if (m_owns_nodes) {
60  nodes_free();
61  }
62 }
63 
64 [[nodiscard]] std::vector<double*> Memb_list::data() {
68  auto const num_fields = m_storage->get_tag<Tag>().num_variables();
69  std::vector<double*> ret(num_fields, nullptr);
70  for (auto i = 0; i < num_fields; ++i) {
72  }
73  return ret;
74 }
75 
77  std::size_t instance,
81  auto const offset = m_storage_offset + instance;
84  field.field,
85  field.array_index);
86 }
87 
88 [[nodiscard]] double& Memb_list::data(std::size_t instance, int variable, int array_index) {
92  m_storage_offset + instance, variable, array_index);
93 }
94 
95 [[nodiscard]] double const& Memb_list::data(std::size_t instance,
96  int variable,
97  int array_index) const {
101  m_storage_offset + instance, variable, array_index);
102 }
103 
104 
105 [[nodiscard]] int Memb_list::get_num_variables() const {
107  return m_storage->get_num_variables<Tag>();
108 }
109 
110 [[nodiscard]] int Memb_list::get_array_dims(int variable) const {
112  return m_storage->get_array_dims<Tag>()[variable];
113 }
114 
115 [[nodiscard]] int const* Memb_list::get_array_dims() const {
117  return m_storage->get_array_dims<Tag>();
118 }
119 
120 [[nodiscard]] int Memb_list::get_array_prefix_sums(int variable) const {
122  return m_storage->get_array_dim_prefix_sums<Tag>()[variable];
123 }
124 
125 [[nodiscard]] int const* Memb_list::get_array_prefix_sums() const {
127  return m_storage->get_array_dim_prefix_sums<Tag>();
128 }
129 
130 
131 [[nodiscard]] std::ptrdiff_t Memb_list::legacy_index(double const* ptr) const {
133  // For a mechanism with (in order) range variables: a, b[2], c the mechanism data are
134  // ______________________
135  // instance 0 | a b[0] b[1] c |
136  // instance 1 | a' b'[0] b'[1] c' |
137  // instance 2 | a'' b''[0] b''[1] c'' |
138  //
139  // the old layout arranged this as:
140  // [a b[0], b[1], c, a', b'[0], b'[1], c', a'', b''[0], b''[1], c'']
141  // whereas the new layout has three different storage vectors:
142  // [a, a', a'']
143  // [b[0], b[1], b'[0], b'[1], b''[0], b''[1]]
144  // [c, c', c'']
145  // this method, given a pointer into one of the new layout vectors,
146  // calculates the (hypothetical) index into the old (single) vector
148  auto const size = m_storage->size(); // number of instances; 3 in the example above
149  auto const num_fields = m_storage->get_tag<Tag>().num_variables(); // ex: 3 (a, b, c)
150  auto const* const array_dims = m_storage->get_array_dims<Tag>(); // ex: [1, 2, 1]
151  auto const sum_of_array_dims = std::accumulate(array_dims, array_dims + num_fields, 0);
152  int sum_of_array_dims_of_previous_fields{};
153  for (auto field = 0; field < num_fields; ++field) { // a, b or c in the example above
154  auto const array_dim = array_dims[field];
155  assert(array_dim > 0);
156  auto const* const vec_data = &m_storage->get_field_instance<Tag>(0, field);
157  auto const index = std::distance(vec_data, ptr);
158  // storage vectors are size * array_dim long
159  if (index >= 0 && index < size * array_dim) {
160  auto const instance_offset = index / array_dim;
161  auto const array_index = index % array_dim;
162  assert(ptr == &m_storage->get_field_instance<Tag>(instance_offset, field, array_index));
163  return ((instance_offset - m_storage_offset) * sum_of_array_dims) +
164  sum_of_array_dims_of_previous_fields + array_index;
165  }
166  sum_of_array_dims_of_previous_fields += array_dim;
167  }
168  assert(sum_of_array_dims_of_previous_fields == sum_of_array_dims);
169  // ptr doesn't live in this mechanism data, cannot compute a legacy index
170  return -1;
171 }
172 
173 [[nodiscard]] double* Memb_list::dptr_field(std::size_t instance, int variable) {
174  return pdata[instance][variable].get<double*>();
175 }
176 
177 [[nodiscard]] int Memb_list::type() const {
178  assert(m_storage);
179  return m_storage->type();
180 }
#define i
Definition: md1redef.h:19
#define assert(ex)
Definition: hocassrt.h:24
#define rhs
Definition: lineq.h:6
void * emalloc(size_t)
std::optional< Model > model
Definition: container.cpp:59
size_t get_num_variables(T const &t)
constexpr std::size_t invalid_row
In mechanism libraries, cannot use auto const token = nrn_ensure_model_data_are_sorted(); because the...
Definition: tnode.hpp:17
void distance()
Definition: solve.cpp:226
#define nrn_assert(x)
assert()-like macro, independent of NDEBUG status
Definition: nrn_assert.h:33
short index
Definition: cabvars.h:11
short type
Definition: cabvars.h:10
A view into a set of mechanism instances.
Definition: nrnoc_ml.h:34
Memb_list & operator=(Memb_list &&) noexcept
Definition: memblist.cpp:52
int const * get_array_prefix_sums() const
Get the array_dims of field variable.
Definition: memblist.cpp:125
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.
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
void nodes_free()
Free memory allocated for nodes (with nodes_alloc)
Definition: memblist.cpp:36
int * nodeindices
Definition: nrnoc_ml.h:74
int type() const
Get the mechanism type.
Definition: memblist.cpp:177
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
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
double * dptr_field(std::size_t instance)
Definition: nrnoc_ml.h:100
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
Catch-all for floating point per-instance variables in the MOD file.
Definition: mechanism.hpp:21
short type() const
The type of this mechanism.
Definition: container.cpp:116
Struct used to index SoAoS data, such as array range variables.
Non-template stable handle to a generic value.
T get() const
Explicit conversion to any T.
int const * get_array_dims() const
Get a pointer to an array holding the array dimensions of the fields associated with this tag.
int const * get_array_dim_prefix_sums() const
Get a pointer to an array holding the prefix sum of array dimensions for this tag.
Tag::type & get_field_instance(std::size_t offset, int field_index, int array_index=0)
Get the offset-th element of the field_index-th instance of the column named by Tag.
std::size_t size() const
Get the size of the container.
constexpr Tag const & get_tag() const
Get the instance of the given tag type.
non_owning_identifier_without_container get_identifier(std::size_t offset) const
Get the offset-th identifier.
size_t get_num_variables() const
data_handle< typename Tag::type > get_field_instance_handle(non_owning_identifier_without_container id, int field_index, int array_index=0) const
Get a handle to the given element of the field_index-th column named by Tag.