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