1+ // ===----------------------------------------------------------------------===//
2+ //
3+ // See the LICENSE file for license and copyright information
4+ // SPDX-License-Identifier: NCSA AND BSD-3-Clause
5+ //
6+ // ===----------------------------------------------------------------------===//
7+ // /
8+ // / @file
9+ // / Implement logic pertaining to @ref FieldContainer
10+ // /
11+ // ===----------------------------------------------------------------------===//
12+
13+ #include " ./GrackleCtxPack.hpp"
14+ #include " ./field_container.hpp"
15+ #include " ./field_info_detail.hpp"
16+ #include " ./status.hpp"
17+
18+ #include " grackle.h"
19+ #include " status_reporting.h"
20+
21+ #include < cstring> // std::memcmp, std::memcpy
22+ #include < utility> // std::pair, std::move
23+
24+ namespace grtest {
25+ namespace field_detail {
26+
27+ // / Construct a name-pointer mapping based on @p ctx_pack
28+ // /
29+ // / The returned where the keys are the names of every active Grackle field
30+ // / and the associated values are all nullptr
31+ static MapType make_nullptr_map_ (const GrackleCtxPack& ctx_pack,
32+ bool exclude_metal) {
33+ MapType m;
34+ // fill up m with (field, nullptr) pairs for each field enabled by ctx_pack
35+ auto fn = [&m](const char * name, const FieldInfo& info) {
36+ if (!m.emplace (name, nullptr ).second ) {
37+ GR_INTERNAL_ERROR (" %s was inserted multiple times" , name);
38+ }
39+ };
40+ for_each_named_field (ctx_pack, fn);
41+
42+ if (exclude_metal) {
43+ auto search = m.find (" metal_density" );
44+ if (search != m.end ()) {
45+ m.erase (search);
46+ }
47+ }
48+ return m;
49+ }
50+
51+ // / Construct a `CorePack` instance by consuming @p premade_map
52+ // /
53+ // / @param premade_map A string to pointer mapping. The keys of this argument
54+ // / should specify the names for each desired Grackle field. We assume that
55+ // / the pointers associated with each key hold meaningless garbage values
56+ // / @param buf_size The number of elements to allocate per field
57+ static std::pair<CorePack, Status> setup_1d_CorePack (MapType&& premade_map,
58+ int buf_size) {
59+ if (buf_size <= 0 ) {
60+ return {CorePack{}, error::Adhoc (" buf_size must be positive" )};
61+ }
62+ std::size_t data_sz = premade_map.size () * buf_size;
63+
64+ CorePack pack{
65+ // the trailing parentheses when allocating an array of integers or
66+ // floating point values sets the initial values to 0
67+ /* prop_buf */ std::unique_ptr<int []>(new int [9 ]()),
68+ /* data_buf */ std::unique_ptr<gr_float[]>(new gr_float[data_sz]()),
69+ /* my_fields */
70+ std::unique_ptr<grackle_field_data>(new grackle_field_data),
71+ /* map */ std::move (premade_map)};
72+ if (gr_initialize_field_data (pack.my_fields .get ()) != GR_SUCCESS) {
73+ // this really should never fail
74+ return {CorePack{}, error::Adhoc (" gr_initialize_field_data failed" )};
75+ }
76+
77+ // setup grid properties
78+ pack.my_fields ->grid_dimension = pack.prop_buf .get ();
79+ pack.my_fields ->grid_start = pack.prop_buf .get () + 3 ;
80+ pack.my_fields ->grid_end = pack.prop_buf .get () + 6 ;
81+
82+ pack.my_fields ->grid_rank = 1 ;
83+ pack.my_fields ->grid_dimension [0 ] = buf_size;
84+ pack.my_fields ->grid_end [0 ] = buf_size - 1 ;
85+
86+ // distribute allocated field-memory among all the appropriate slots of
87+ // pack.my_fields and pack.map
88+ gr_float* ptr = pack.data_buf .get ();
89+ int counter = 0 ;
90+ auto fn = [ptr, buf_size, &counter, &pack](const char * name,
91+ const FieldInfo& finfo) {
92+ // return immediately if finfo.name isn't a key of `pack.map`
93+ MapType::iterator search = pack.map .find (name);
94+ if (search == pack.map .end ()) {
95+ return ; // finfo.name isn't a key of `map`
96+ }
97+ // get the pointer to the memory reserved for the current field
98+ gr_float* cur_ptr = ptr + (counter * buf_size);
99+ counter++;
100+ // update `pack.my_fields` to associate the current field with `cur_ptr`
101+ pack.my_fields .get ()->*finfo.relative_addr = cur_ptr;
102+ // update `map` to associate the current field with `cur_ptr`
103+ search->second = cur_ptr;
104+ };
105+ // this acts like a for-loop that passes a FieldInfo struct for every known
106+ // grackle-field into `fn`
107+ for_each_named_field (fn);
108+ return {std::move (pack), OkStatus ()};
109+ }
110+
111+ } // namespace field_detail
112+
113+ std::pair<FieldContainer, Status> FieldContainer::create_1d (
114+ const GrackleCtxPack& ctx_pack, int buf_size, bool disable_metal) {
115+ if (!ctx_pack.is_initialized ()) {
116+ return {FieldContainer{}, error::Adhoc (" ctx_pack isn't initialized" )};
117+ }
118+
119+ // construct a map for each relevant field (the values are all nullptr)
120+ field_detail::MapType m =
121+ field_detail::make_nullptr_map_ (ctx_pack, disable_metal);
122+ std::pair<field_detail::CorePack, Status> tmp =
123+ field_detail::setup_1d_CorePack (std::move (m), buf_size);
124+ if (tmp.second .is_err ()) {
125+ return {FieldContainer (), std::move (tmp.second )};
126+ } else {
127+ FieldContainer fc;
128+ fc.data_ = std::move (tmp.first );
129+ return {std::move (fc), OkStatus ()};
130+ }
131+ }
132+
133+ std::pair<FieldContainer, Status> FieldContainer::create (
134+ const GrackleCtxPack& ctx_pack, const GridLayout& layout,
135+ bool disable_metal) {
136+ if (layout.rank < 1 || layout.rank > 3 ) {
137+ return {FieldContainer (), error::Adhoc (" layout.rank must be 1, 2, or 3" )};
138+ }
139+ int total_count = 1 ;
140+ for (int i = 0 ; i < layout.rank ; i++) {
141+ if (layout.dimension [i] <= 0 ) {
142+ return {FieldContainer (),
143+ error::Adhoc (" layout.dimension[i] must be positive" )};
144+ } else if (layout.ghost_depth [i] < 0 ) {
145+ return {FieldContainer (),
146+ error::Adhoc (" layout.ghost_depth[i] is negative" )};
147+ } else if (layout.ghost_depth [i] * 2 >= layout.dimension [i]) {
148+ return {FieldContainer (),
149+ error::Adhoc (
150+ " layout.dimension[i] must exceed 2*layout.ghost_depth[i]" )};
151+ }
152+ total_count *= layout.dimension [i];
153+ }
154+
155+ std::pair<FieldContainer, Status> tmp =
156+ FieldContainer::create_1d (ctx_pack, total_count, disable_metal);
157+
158+ if (tmp.second .is_ok ()) {
159+ grackle_field_data* my_fields = tmp.first .data_ .my_fields .get ();
160+ tmp.first .data_ .my_fields ->grid_rank = layout.rank ;
161+ for (int i = 0 ; i < layout.rank ; i++) {
162+ int dim = layout.dimension [i];
163+ int ghost_depth = layout.ghost_depth [i];
164+ my_fields->grid_dimension [i] = dim;
165+ my_fields->grid_start [i] = ghost_depth;
166+ my_fields->grid_end [i] = dim - ghost_depth - 1 ;
167+ }
168+ }
169+ return tmp;
170+ }
171+
172+ FieldContainer FieldContainer::clone () const {
173+ // make a copy of m, and use it construct a new CorePack
174+ // -> the keys of `m` tell `setup_1d_CorePack` which Grackle fields get used
175+ // -> right after we create
176+ field_detail::MapType m = this ->data_ .map ;
177+ std::pair<field_detail::CorePack, Status> tmp =
178+ field_detail::setup_1d_CorePack (std::move (m), this ->elements_per_field ());
179+ // it shouldn't be possible for tmp.second.is_err() to return true
180+ FieldContainer out;
181+ out.data_ = std::move (tmp.first );
182+
183+ // copy over layout properties
184+ int rank = this ->rank ();
185+ for (int i = 0 ; i < rank; i++) {
186+ out.data_ .my_fields ->grid_start [i] = this ->data_ .my_fields ->grid_start [i];
187+ out.data_ .my_fields ->grid_end [i] = this ->data_ .my_fields ->grid_end [i];
188+ out.data_ .my_fields ->grid_dimension [i] =
189+ this ->data_ .my_fields ->grid_dimension [i];
190+ }
191+
192+ copy_into_helper_ (out);
193+ return out;
194+ }
195+
196+ void FieldContainer::copy_into_helper_ (FieldContainer& other) const {
197+ // I'm still not entirely sure how to best handle grid_dx, but this is here
198+ // to make sure we don't forget to propagate the logic when we ultimately
199+ // make a decision
200+ if (this ->get_ptr ()->grid_dx != other.get_ptr ()->grid_dx ) {
201+ GR_INTERNAL_ERROR (" did you forget to update grid_dx handling?" );
202+ }
203+
204+ const gr_float* src = this ->data_ .data_buf .get ();
205+ gr_float* dst = other.data_ .data_buf .get ();
206+ int length = this ->elements_per_field () * this ->n_fields ();
207+ std::memcpy (dst, src, length * sizeof (gr_float));
208+ }
209+
210+ bool FieldContainer::same_grid_props (const FieldContainer& other) const {
211+ const grackle_field_data* a = this ->data_ .my_fields .get ();
212+ const grackle_field_data* b = other.data_ .my_fields .get ();
213+
214+ if (a->grid_rank != b->grid_rank ) {
215+ return false ;
216+ }
217+ int rank = a->grid_rank ;
218+ std::size_t sz = rank * sizeof (int );
219+ bool s = std::memcmp (a->grid_start , b->grid_start , sz) == 0 ;
220+ bool e = std::memcmp (a->grid_end , b->grid_end , sz) == 0 ;
221+ bool d = std::memcmp (a->grid_dimension , b->grid_dimension , sz) == 0 ;
222+ return s && d && e;
223+ }
224+
225+ bool FieldContainer::same_fields (const FieldContainer& other) const {
226+ // this takes advantage of the fact that MapType is sorted
227+ MapType::const_iterator it_a = this ->data_ .map .begin ();
228+ MapType::const_iterator stop_a = this ->data_ .map .end ();
229+ MapType::const_iterator it_b = other.data_ .map .begin ();
230+
231+ for (; it_a != stop_a; ++it_a, ++it_b) {
232+ if (it_a->first != it_b->first ) {
233+ return false ;
234+ }
235+ }
236+ return true ;
237+ }
238+
239+ } // namespace grtest
0 commit comments