Skip to content

Commit 86e7c9a

Browse files
committed
Initial introduction of FieldContainer
1 parent 3227e5e commit 86e7c9a

File tree

6 files changed

+927
-0
lines changed

6 files changed

+927
-0
lines changed

tests/grtestutils/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ add_library(grtestutils
8181
# -> these shouldn't include headers from the googletest subdirectory
8282
cmd.hpp cmd.cpp
8383
GrackleCtxPack.cpp GrackleCtxPack.hpp
84+
field_container.cpp field_container.hpp
85+
field_info_detail.cpp field_info_detail.hpp
8486
iterator_adaptor.hpp
8587
os.hpp os.cpp
8688
param.cpp param.hpp

tests/grtestutils/GrackleCtxPack.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ class GrackleCtxPack {
113113
// getter functions
114114
const code_units& initial_units() const { return this->initial_units_; }
115115
chemistry_data* my_chemistry() { return this->my_chemistry_.get(); }
116+
const chemistry_data* my_chemistry() const {
117+
return this->my_chemistry_.get();
118+
}
116119
chemistry_data_storage* my_rates() { return this->my_rates_.get(); }
117120

118121
/// create an initialized instance
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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

Comments
 (0)