1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5
6 #ifndef MINT_ConnectivityArrayHelpers_HPP_
7 #define MINT_ConnectivityArrayHelpers_HPP_
8
9 #include "axom/config.hpp"
10
11 #include "axom/mint/deprecated/MCArray.hpp"
12 #include "axom/mint/config.hpp"
13 #include "axom/mint/mesh/CellTypes.hpp"
14
15 #include "axom/slic/interface/slic.hpp"
16
17 #ifdef AXOM_MINT_USE_SIDRE
18 #include "axom/sidre/core/sidre.hpp"
19 #include "axom/mint/deprecated/SidreMCArray.hpp"
20 #endif
21
22 #include <cmath> /* for std::ceil */
23 #include <string> /* for std:string */
24 #include <cstring> /* for std::srcmp */
25
26 namespace axom
27 {
28 namespace mint
29 {
30 namespace internal
31 {
32 #ifdef AXOM_MINT_USE_SIDRE
33
34 /*!
35 * \brief Initializes the members of a ConnectivityArray instance from a
36 * sidre::Group which already has data.
37 *
38 * \param [in] group the sidre::Group to create the ConnectivityArray from.
39 * \param [out] m_values a pointer to a pointer to the values array.
40 * \param [out] m_offsets a pointer to a pointer to the offsets array.
41 * \param [out] m_types a pointer to a pointer to the types array.
42 *
43 * \note if the offset/types pointers aren't given then this method does not
44 * check that the appropriate views exist.
45 * \note the given Group must conform to a single Blueprint topology.
46 *
47 * \pre group != nullptr
48 * \pre m_values != nullptr
49 */
initializeFromGroup(sidre::Group * group,axom::deprecated::MCArray<IndexType> ** m_values,axom::deprecated::MCArray<IndexType> ** m_offsets=nullptr,axom::deprecated::MCArray<CellType> ** m_types=nullptr)50 inline CellType initializeFromGroup(
51 sidre::Group* group,
52 axom::deprecated::MCArray<IndexType>** m_values,
53 axom::deprecated::MCArray<IndexType>** m_offsets = nullptr,
54 axom::deprecated::MCArray<CellType>** m_types = nullptr)
55 {
56 SLIC_ERROR_IF(group == nullptr, "sidre::Group pointer must not be null.");
57 SLIC_ERROR_IF(m_values == nullptr, "Pointer values array must not be null.");
58
59 SLIC_ERROR_IF(
60 !group->hasView("coordset"),
61 "sidre::Group "
62 << group->getPathName()
63 << " does not conform to mesh blueprint. No child view 'coordset'.");
64 SLIC_ERROR_IF(
65 !group->getView("coordset")->isString(),
66 "sidre::Group "
67 << group->getPathName()
68 << " does not conform to mesh blueprint. Child view 'coordset' "
69 << "does not hold a string.");
70
71 SLIC_ERROR_IF(
72 !group->hasView("type"),
73 "sidre::Group "
74 << group->getPathName()
75 << " does not conform to mesh blueprint. No child view 'type'.");
76 sidre::View* type_view = group->getView("type");
77 SLIC_ERROR_IF(!type_view->isString(),
78 "sidre::Group "
79 << group->getPathName()
80 << " does not conform to mesh blueprint. Child view 'type' "
81 << "does not hold a string.");
82 SLIC_ERROR_IF(std::strcmp(type_view->getString(), "unstructured") != 0,
83 "Incorrect type found. Expected 'unstructured' but got '"
84 << type_view->getString() << "'.");
85
86 SLIC_ERROR_IF(!group->hasGroup("elements"),
87 "sidre::Group "
88 << group->getPathName()
89 << " does not conform to mesh blueprint. No 'elements' group "
90 << "found.");
91 sidre::Group* elems_group = group->getGroup("elements");
92
93 SLIC_ERROR_IF(!elems_group->hasView("shape"),
94 "sidre::Group "
95 << group->getPathName()
96 << " does not conform to mesh blueprint. The elements group "
97 << "does not have a child view 'shape'.");
98
99 sidre::View* shape_view = elems_group->getView("shape");
100 std::string bp_name = shape_view->getString();
101 CellType cell_type = UNDEFINED_CELL;
102
103 for(IndexType i = 0; i < NUM_CELL_TYPES; ++i)
104 {
105 if(cell_info[i].blueprint_name == bp_name)
106 {
107 cell_type = cell_info[i].cell_type;
108 break;
109 }
110 }
111
112 SLIC_ERROR_IF(!elems_group->hasView("connectivity"),
113 "sidre::Group "
114 << group->getPathName()
115 << " does not conform to mesh blueprint. The elements group "
116 << "does not have a child view 'connectivity'.");
117
118 sidre::View* connec_view = elems_group->getView("connectivity");
119 *m_values = new sidre::deprecated::MCArray<IndexType>(connec_view);
120 SLIC_ERROR_IF(*m_values == nullptr, "Error in Array allocation.");
121
122 if(m_offsets != nullptr)
123 {
124 SLIC_ERROR_IF(!elems_group->hasView("offsets"),
125 "sidre::Group " << group->getPathName()
126 << " does not conform to mesh blueprint.");
127
128 sidre::View* offsets_view = elems_group->getView("offsets");
129 *m_offsets = new sidre::deprecated::MCArray<IndexType>(offsets_view);
130
131 SLIC_ERROR_IF(*m_offsets == nullptr, "Error in Array allocation.");
132 SLIC_ERROR_IF((*m_offsets)->numComponents() != 1,
133 "offsets array must have only 1 component not "
134 << (*m_offsets)->numComponents() << ".");
135
136 if((*m_offsets)->size() == 0)
137 {
138 (*m_offsets)->append(0);
139 }
140 SLIC_ERROR_IF((**m_offsets)[0] != 0,
141 "The offset of ID 0 must be 0 not " << (**m_offsets)[0] << ".");
142 }
143
144 if(m_types != nullptr)
145 {
146 SLIC_ERROR_IF(!elems_group->hasView("types"),
147 "sidre::Group " << group->getPathName()
148 << " does not conform to mesh blueprint.");
149
150 sidre::View* type_view = elems_group->getView("types");
151 *m_types = new sidre::deprecated::MCArray<CellType>(type_view);
152
153 SLIC_ERROR_IF(*m_types == nullptr, "Error in Array allocation.");
154 SLIC_ERROR_IF((*m_types)->numComponents() != 1,
155 "Types array must have only 1 component not "
156 << (*m_types)->numComponents() << ".");
157 }
158
159 return cell_type;
160 }
161
162 /*!
163 * \brief Initializes an empty sidre::Group to hold a ConnectivityArray.
164 *
165 * \param [out] group the empty sidre::Group.
166 * \param [in] coordset the name of the Blueprint coordinate set to associate
167 * this ConnectivityArray with.
168 * \param [in] create_offsets iff true will create a view for the offsets array.
169 * \param [in] create_types iff true will create a view for the types array.
170 *
171 * \pee group != nullptr
172 * \pre group->getNumGroups() == group->getNumViews() == 0
173 */
initializeGroup(sidre::Group * group,const std::string & coordset,CellType cell_type,bool create_offsets=false,bool create_types=false)174 inline void initializeGroup(sidre::Group* group,
175 const std::string& coordset,
176 CellType cell_type,
177 bool create_offsets = false,
178 bool create_types = false)
179 {
180 SLIC_ERROR_IF(group == nullptr, "sidre::Group pointer must not be null.");
181 SLIC_ERROR_IF(group->getNumGroups() != 0, "sidre::Group is not empty.");
182 SLIC_ERROR_IF(group->getNumViews() != 0, "sidre::Group is not empty.");
183
184 group->createView("coordset")->setString(coordset);
185 group->createView("type")->setString("unstructured");
186
187 const std::string bp_name = (cell_type == UNDEFINED_CELL)
188 ? "mixed"
189 : getCellInfo(cell_type).blueprint_name;
190
191 sidre::Group* elems_group = group->createGroup("elements");
192 elems_group->createView("shape")->setString(bp_name);
193
194 elems_group->createView("connectivity");
195
196 if(create_offsets)
197 {
198 elems_group->createView("offsets");
199 }
200
201 if(create_types)
202 {
203 elems_group->createView("types");
204 }
205 }
206
207 /*!
208 * \brief Sets the stride associated with a connectivity array.
209 *
210 * \param [out] group the group holding the connectivity array.
211 * \param [in] stride the stride to set.
212 *
213 * \pre group != nullptr
214 */
setStride(sidre::Group * group,IndexType stride)215 inline void setStride(sidre::Group* group, IndexType stride)
216 {
217 SLIC_ERROR_IF(group == nullptr, "sidre::Group pointer must not be null.");
218
219 sidre::Group* elems_group = group->getGroup("elements");
220 SLIC_ERROR_IF(elems_group == nullptr, "No group found");
221 elems_group->createView("stride")->setScalar(stride);
222 }
223
224 /*!
225 * \brief Returns the stride associated with a connectivity array.
226 *
227 * \param [in] group the group holding the connectivity array.
228 *
229 * \pee group != nullptr
230 */
getStride(const sidre::Group * group)231 inline IndexType getStride(const sidre::Group* group)
232 {
233 SLIC_ERROR_IF(group == nullptr, "sidre::Group pointer must not be null.");
234
235 const sidre::Group* elems_group = group->getGroup("elements");
236 SLIC_ERROR_IF(elems_group == nullptr, "No group found");
237 const sidre::View* stride_view = elems_group->getView("stride");
238 SLIC_ERROR_IF(stride_view == nullptr, "No view found");
239 return stride_view->getScalar();
240 }
241
242 #endif
243
244 /*!
245 * \brief Append multiple IDs to the members of a ConnectivityArray.
246 *
247 * \param [in] n_IDs the number of IDs to append.
248 * \param [in] values pointer to the values to append.
249 * \param [in] offsets the offsets array of length at least n_IDs + 1.
250 * \param [in/out] m_values a pointer to the values array.
251 * \param [in/out] m_offsets a pointer to the offsets array.
252 *
253 * \note The number of values to append is given by
254 * offsets[n_IDs + 1] - offsets[0] and the values array must be at least
255 * this long.
256 *
257 * \pre n_IDs >= 0
258 * \pre values != nullptr
259 * \pre offsets != nullptr
260 * \pre m_values != nullptr
261 * \pre m_offsets != nullptr
262 */
append(IndexType n_IDs,const IndexType * values,const IndexType * offsets,axom::deprecated::MCArray<IndexType> * m_values,axom::deprecated::MCArray<IndexType> * m_offsets)263 inline void append(IndexType n_IDs,
264 const IndexType* values,
265 const IndexType* offsets,
266 axom::deprecated::MCArray<IndexType>* m_values,
267 axom::deprecated::MCArray<IndexType>* m_offsets)
268 {
269 SLIC_ASSERT(values != nullptr);
270 SLIC_ASSERT(offsets != nullptr);
271 SLIC_ASSERT(m_values != nullptr);
272 SLIC_ASSERT(m_offsets != nullptr);
273
274 IndexType n_values_to_add = offsets[n_IDs] - offsets[0];
275 IndexType old_n_values = m_values->size();
276 IndexType old_n_offsets = m_offsets->size();
277
278 m_offsets->append(offsets + 1, n_IDs);
279 m_values->append(values, n_values_to_add);
280
281 /* Correct the appended offsets. */
282 IndexType* m_offsets_ptr = m_offsets->getData();
283 const IndexType correction = old_n_values - offsets[0];
284 for(IndexType i = 0; i < n_IDs; ++i)
285 {
286 m_offsets_ptr[old_n_offsets + i] += correction;
287 }
288 }
289
290 /*!
291 * \brief Sets the values of multiple IDs starting with the given ID.
292 *
293 * \param [in] start_ID the ID to start at.
294 * \param [in] values pointer to the values to set, of length at least
295 * the sum of the number of values of each ID to set.
296 * \param [in] n_IDs the number of IDs to set.
297 * \param [in/out] m_values a pointer to the values array.
298 * \param [in] m_offsets a pointer to the offsets axom::deprecated::MCArray.
299 *
300 * \pre start_ID >= 0 && start_ID + n_IDs < getNumberOfIDs()
301 * \pre values != nullptr
302 * \pre m_values != nullptr
303 */
set(IndexType start_ID,const IndexType * values,IndexType n_IDs,axom::deprecated::MCArray<IndexType> * m_values,axom::deprecated::MCArray<IndexType> * m_offsets)304 inline void set(IndexType start_ID,
305 const IndexType* values,
306 IndexType n_IDs,
307 axom::deprecated::MCArray<IndexType>* m_values,
308 axom::deprecated::MCArray<IndexType>* m_offsets)
309 {
310 SLIC_ASSERT(start_ID >= 0);
311 SLIC_ASSERT(start_ID + n_IDs <= m_offsets->size() - 1);
312 SLIC_ASSERT(values != nullptr);
313 SLIC_ASSERT(m_values != nullptr);
314
315 IndexType offset = (*m_offsets)[start_ID];
316 IndexType n_values = (*m_offsets)[start_ID + n_IDs] - offset;
317 m_values->set(values, n_values, offset);
318 }
319
320 /*!
321 * \brief Insert the values of new IDs before the given ID.
322 *
323 * \param [in] start_ID the ID to insert at.
324 * \param [in] n_IDs the number of IDs to insert.
325 * \param [in] values pointer to the values to insert.
326 * \param [in] offsets the offsets array of length at least n_IDs + 1.
327 * \param [in/out] m_values a pointer to the values axom::deprecated::MCArray.
328 * \param [in/out] m_offsets a pointer to the offsets axom::deprecated::MCArray.
329 *
330 * \note The number of values to insert is given by
331 * offsets[n_IDs + 1] - offsets[0] and the values array must be at least
332 * this long.
333 *
334 * \pre start_ID >= 0 && start_ID <= getNumberOfIDs()
335 * \pre n_IDs >= 0
336 * \pre values != nullptr
337 * \pre offsets != nullptr
338 * \pre m_values != nullptr
339 * \pre m_offsets != nullptr
340 */
insert(IndexType start_ID,IndexType n_IDs,const IndexType * values,const IndexType * offsets,axom::deprecated::MCArray<IndexType> * m_values,axom::deprecated::MCArray<IndexType> * m_offsets)341 inline void insert(IndexType start_ID,
342 IndexType n_IDs,
343 const IndexType* values,
344 const IndexType* offsets,
345 axom::deprecated::MCArray<IndexType>* m_values,
346 axom::deprecated::MCArray<IndexType>* m_offsets)
347 {
348 SLIC_ASSERT(start_ID >= 0);
349 SLIC_ASSERT(start_ID <= m_offsets->size() - 1);
350 SLIC_ASSERT(n_IDs >= 0);
351 SLIC_ASSERT(values != nullptr);
352 SLIC_ASSERT(offsets != nullptr);
353 SLIC_ASSERT(m_values != nullptr);
354 SLIC_ASSERT(m_offsets != nullptr);
355
356 IndexType n_values = offsets[n_IDs] - offsets[0];
357 IndexType* m_offsets_ptr = m_offsets->getData();
358 IndexType insert_pos = m_offsets_ptr[start_ID];
359
360 /* Increment the offsets after the insertion position. */
361 IndexType n_offsets = m_offsets->size();
362 for(IndexType i = start_ID + 1; i < n_offsets; ++i)
363 {
364 m_offsets_ptr[i] += n_values;
365 }
366
367 m_offsets->insert(offsets + 1, n_IDs, start_ID + 1);
368 m_values->insert(values, n_values, insert_pos);
369
370 /* Correct the inserted offsets. */
371 m_offsets_ptr = m_offsets->getData();
372 const IndexType correction = insert_pos - offsets[0];
373 for(IndexType i = 0; i < n_IDs; ++i)
374 {
375 m_offsets_ptr[start_ID + 1 + i] += correction;
376 }
377 }
378
379 /*!
380 * \brief Return the value capacity given the number of IDs, the ID_capacity,
381 * and the number of values.
382 *
383 * \param [in] n_IDs the number of IDs in the ConnectivityArray.
384 * \param [in] ID_capacity the ID capacity of the ConnectivityArray.
385 * \param [in] n_values the number of values in the ConnectivityArray.
386 * \param [in] value_capacity the value capacity of the ConnectivityArray.
387 * If this is not USE_DEFAULT it simply returns the given capacity, otherwise
388 * it calculates the capacity given the other three parameters.
389 */
calcValueCapacity(IndexType n_IDs,IndexType ID_capacity,IndexType n_values,IndexType value_capacity)390 inline IndexType calcValueCapacity(IndexType n_IDs,
391 IndexType ID_capacity,
392 IndexType n_values,
393 IndexType value_capacity)
394 {
395 if(value_capacity == USE_DEFAULT)
396 {
397 if(n_IDs == 0)
398 {
399 value_capacity = ID_capacity * MAX_CELL_NODES;
400 }
401 else
402 {
403 const double avg_n_vals = double(n_values) / n_IDs;
404 value_capacity = static_cast<IndexType>(std::ceil(avg_n_vals * n_IDs));
405 }
406 }
407
408 return value_capacity;
409 }
410
411 } /* namespace internal */
412 } /* namespace mint */
413 } /* namespace axom */
414
415 #endif /* MINT_ConnectivityArrayHelpers_HPP_ */
416