4 #include "../icedb/shape.hpp" 5 #include "../private/hdf5_supplemental.hpp" 6 #include "../private/Shape_impl.hpp" 15 if (out) (*out) <<
"The number of scattering elements is not set." << std::endl;
19 if (out) (*out) <<
"The number of particle constituents is not set." << std::endl;
23 if (out) (*out) <<
"Particle ID is not set." << std::endl;
28 if (out) (*out) <<
"particle_scattering_element_coordinates is not set. " 29 "Particles need to have scattering elements." << std::endl;
33 if (out) (*out) <<
"particle_scattering_element_coordinates has " 34 "the wrong dimensions. It should have dimensions of " 35 "[number_of_particle_scattering_elements][3], yielding a total of " 38 <<
" elements." << std::endl;
42 if (out) (*out) <<
"number_of_particle_constituents is not set. " 43 "Particles need to have a composition." << std::endl;
57 gsl::not_null<const NewShapeRequiredProperties*> required, std::ostream *out)
const 61 if (!this->particle_scattering_element_number.empty()) {
62 if (required->number_of_particle_scattering_elements != this->particle_scattering_element_number.size()) {
64 if (out) (*out) <<
"number_of_particle_scattering_elements is not equal to particle_scattering_element_number." << std::endl;
67 if (required->number_of_particle_constituents > 1) {
68 if (this->particle_constituent_number.empty() || this->particle_constituent_number.size() != required->number_of_particle_constituents) {
70 if (out) (*out) <<
"particle_constituent_number is not set. " 71 "This is an essential dimension scale that the rest of the particle " 72 "data depends on." << std::endl;
75 if (this->particle_scattering_element_composition_whole.empty()
76 && this->particle_scattering_element_composition_fractional.empty())
79 if (out) (*out) <<
"particle_scattering_element_composition_whole and " 80 "particle_scattering_element_composition_fractional are not set, but one is required. " 84 if (!this->particle_scattering_element_composition_whole.empty()
85 && !this->particle_scattering_element_composition_fractional.empty())
88 if (out) (*out) <<
"particle_scattering_element_composition_whole and " 89 "particle_scattering_element_composition_fractional are both set, but only one is allowed. " 93 if (!this->particle_scattering_element_composition_whole.empty()) {
94 if (this->particle_scattering_element_composition_whole.size()
95 != required->number_of_particle_scattering_elements)
98 if (out) (*out) <<
"particle_scattering_element_composition_whole " 99 "has the wrong size. It should have a size of number_of_particle_scattering_elements." 103 if (!this->particle_scattering_element_composition_fractional.empty()) {
104 if (this->particle_scattering_element_composition_fractional.size() !=
105 (required->number_of_particle_scattering_elements * required->number_of_particle_constituents)) {
107 if (out) (*out) <<
"particle_scattering_element_composition_fractional has " 108 "the wrong dimensions. It should have dimensions of " 109 "[number_of_particle_scattering_elements][number_of_particle_constituents], yielding a total of " 110 << required->number_of_particle_scattering_elements * required->number_of_particle_constituents <<
" elements. " 111 "Instead, it currently has " << this->particle_scattering_element_composition_fractional.size()
112 <<
" elements." << std::endl;
118 if (this->particle_scattering_element_radius.size()) {
119 if (this->particle_scattering_element_radius.size() != required->number_of_particle_scattering_elements) {
121 if (out) (*out) <<
"particle_scattering_element_radius has the wrong size. " 122 "It should have dimensions of [number_of_particle_scattering_elements]. " 123 "particle_scattering_element_radius has a current size of " << particle_scattering_element_radius.size()
124 <<
", and this should be " << required->number_of_particle_scattering_elements
129 if (particle_constituent_single_name.size() && required->number_of_particle_constituents != 1) {
131 if (out) (*out) <<
"particle_constituent_single_name is a valid attribute only when a single non-ice constituent exists." 134 if (particle_constituent_single_name.size() && this->particle_constituent_name.size()) {
136 if (out) (*out) <<
"particle_constituent_single_name and particle_constituent_name are mutually exclusive." 139 if (this->particle_constituent_name.size()) {
140 if (this->particle_constituent_name.size() != required->number_of_particle_constituents) {
142 if (out) (*out) <<
"particle_constituent_name has the wrong size. " 143 "It should have dimensions of [number_of_particle_constituents]. " 147 if (required->number_of_particle_constituents > 1 && this->particle_constituent_name.empty()) {
149 if (out) (*out) <<
"number_of_particle_constituents > 1, so particle_constituent_name " 150 "is required." << std::endl;
166 return isShape(grp->getHDF5Group().get());
173 = Attributes::CanHaveAttributes::readAttribute<std::string>(group, Group::_icedb_obj_type_identifier);
174 if (obj_type.
data.size() != 1)
return false;
175 if (obj_type.
data[0] != Shape::_icedb_obj_type_shape_identifier)
return false;
192 if (out) (*out) <<
"This is not a valid shape. Missing the appropriate " 199 if (out) (*out) <<
"Missing the particle_id attribute." << std::endl;
203 if (out) (*out) <<
"The particle_id attribute has the wrong type." << std::endl;
206 auto attr = Attributes::CanHaveAttributes::readAttribute<std::string>(group,
"particle_id");
207 if (attr.data.size() != 1) {
209 if (out) (*out) <<
"The particle_id attribute has the wrong size. It should be a scalar." << std::endl;
212 if (!attr.data[0].size()) {
214 if (out) (*out) <<
"The particle_id attribute is empty." << std::endl;
218 if (out) (*out) <<
"TODO: Finish these checks!" << std::endl;
232 const std::string &uid,
233 gsl::not_null<const NewShapeRequiredProperties*> required,
240 const std::string &uid,
241 gsl::not_null<const NewShapeRequiredProperties*> required,
246 return createShape(grp->getHDF5Group(), uid, required, optional);
250 return createShape(grp->getHDF5Group(), uid, required, optional);
255 const std::string &uid,
256 gsl::not_null<const NewShapeRequiredProperties*> required,
259 Expects(required->isValid(&(std::cerr)));
260 if (required->requiresOptionalPropertiesStruct()) Expects(optional);
261 if (optional) Expects(optional->
isValid(required));
266 res->writeAttribute<std::string>(Group::_icedb_obj_type_identifier, { 1 }, { Shape::_icedb_obj_type_shape_identifier });
267 res->writeAttribute<std::string>(
"particle_id", { 1 }, { required->particle_id });
272 bool createTblPSEN =
false;
276 if (required->NC4_compat) createTblPSEN =
true;
278 std::unique_ptr<icedb::Tables::Table> tblPSEN;
280 tblPSEN = res->createTable<uint64_t>(
"particle_scattering_element_number",
281 {
static_cast<size_t>(required->number_of_particle_scattering_elements) });
291 bool createTblPCN =
false;
295 if (required->NC4_compat) createTblPCN =
true;
297 std::unique_ptr<icedb::Tables::Table> tblPCN;
299 tblPCN = res->createTable<uint8_t>(
"particle_constituent_number",
300 {
static_cast<size_t>(required->number_of_particle_constituents) });
309 std::unique_ptr<icedb::Tables::Table> tblXYZ;
310 if (required->NC4_compat) {
311 tblXYZ = res->createTable<uint8_t>(
"particle_axis", { 3 }, { 0, 1, 2 });
315 constexpr
size_t max_x = 20000;
316 const std::vector<size_t> chunks{
317 (max_x < required->number_of_particle_scattering_elements) ?
318 max_x : required->number_of_particle_scattering_elements, 3 };
322 bool considerInts = (required->particle_scattering_element_coordinates_are_integral) ?
true :
false;
323 bool useUint16s =
false, useUint8s =
false;
338 auto me = std::max_element(required->particle_scattering_element_coordinates.cbegin(), required->particle_scattering_element_coordinates.cend());
341 if (mx < UINT8_MAX - 2) useUint8s =
true;
342 else if (mx < UINT16_MAX - 2) useUint16s =
true;
346 std::vector<uint8_t> crds_ints(required->number_of_particle_scattering_elements * 3);
347 for (
size_t i = 0; i < crds_ints.size(); ++i) {
348 crds_ints[i] =
static_cast<uint8_t
>(required->particle_scattering_element_coordinates[i]);
350 auto tblPSEC = res->createTable<uint8_t>(
351 "particle_scattering_element_coordinates",
352 {
static_cast<size_t>(required->number_of_particle_scattering_elements), 3 },
354 if (tblPSEN) tblPSEC->attachDimensionScale(0, tblPSEN.get());
355 if (tblXYZ) tblPSEC->attachDimensionScale(1, tblXYZ.get());
357 else if (useUint16s) {
358 std::vector<uint16_t> crds_ints(required->number_of_particle_scattering_elements*3);
359 for (
size_t i = 0; i < crds_ints.size(); ++i) {
360 crds_ints[i] =
static_cast<uint16_t
>(required->particle_scattering_element_coordinates[i]);
362 auto tblPSEC = res->createTable<uint16_t>(
363 "particle_scattering_element_coordinates",
364 {
static_cast<size_t>(required->number_of_particle_scattering_elements), 3 },
366 if (tblPSEN) tblPSEC->attachDimensionScale(0, tblPSEN.get());
367 if (tblXYZ) tblPSEC->attachDimensionScale(1, tblXYZ.get());
369 auto tblPSEC = res->createTable<
float>(
"particle_scattering_element_coordinates",
370 {
static_cast<size_t>(required->number_of_particle_scattering_elements), 3 },
371 required->particle_scattering_element_coordinates, &chunks);
372 if (tblPSEN) tblPSEC->attachDimensionScale(0, tblPSEN.get());
373 if (tblXYZ) tblPSEC->attachDimensionScale(1, tblXYZ.get());
383 res->writeAttribute<std::string>(
"particle_single_constituent_name",
388 const std::vector<size_t> cs{
389 (max_x < required->number_of_particle_scattering_elements) ?
390 max_x : required->number_of_particle_scattering_elements,
391 static_cast<size_t>(required->number_of_particle_constituents)
393 auto tblPSEC2a = res->createTable<
float>(
"particle_scattering_element_composition_fractional",
394 {
static_cast<size_t>(required->number_of_particle_scattering_elements),
395 static_cast<size_t>(required->number_of_particle_constituents) },
397 if (tblPSEN) tblPSEC2a->attachDimensionScale(0, tblPSEN.get());
398 if (tblPCN) tblPSEC2a->attachDimensionScale(1, tblPCN.get());
402 const std::vector<size_t> cs{
403 (max_x < required->number_of_particle_scattering_elements) ?
404 max_x : required->number_of_particle_scattering_elements
406 auto tblPSEC2b = res->createTable<uint8_t>(
407 "particle_scattering_element_composition_whole",
408 {
static_cast<size_t>(required->number_of_particle_scattering_elements) },
410 if (tblPSEN) tblPSEC2b->attachDimensionScale(0, tblPSEN.get());
421 auto tblPSER = res->createTable<
float>(
"particle_scattering_element_radius",
422 {
static_cast<size_t>(required->number_of_particle_scattering_elements) },
424 if (tblPSEN) tblPSER->attachDimensionScale(0, tblPSEN.get());
437 auto id = Attributes::CanHaveAttributes::readAttribute<std::string>(shape.get(),
"particle_id");
gsl::span< const uint8_t > particle_scattering_element_composition_whole
static bool isValid(gsl::not_null< H5::Group *> group, std::ostream *out=nullptr)
Is "group" a valid shape, according to the spec.?
static Shape_Type createShape(Groups::Group &grpshp, const std::string &uid, gsl::not_null< const NewShapeRequiredProperties *> required, const NewShapeCommonOptionalProperties *optional=nullptr)
Create a new shape.
void setDimensionScale(const std::string &dimensionScaleName)
Designate this table as a dimension scale.
virtual Group_HDF_shared_ptr getHDF5Group() const =0
Get the fundamental HDF5 object that the group is built on.
std::shared_ptr< H5::Group > Group_HDF_shared_ptr
A group is similar to a folder / directory. It can have Attributes and Tables.
static const std::string _icedb_obj_type_shape_identifier
Each shape 'group' has an attribute with this identifier. Used for shape collection and searching...
std::string particle_id
ATTRIBUTE: Unique Particle Identifier.
A high-level class to manipulate particle shapes.
virtual Group_ptr createGroup(const std::string &groupName)=0
Create a group.
gsl::span< const float > particle_scattering_element_radius
virtual bool doesGroupExist(const std::string &groupName) const =0
Does a group with this name exist?
float particle_scattering_element_spacing
OPTIONAL ATTRIBUTE: Physical spacing between adjacent grid points (in meters). Used in DDA...
float hint_max_scattering_element_dimension
EXPERIMENTAL HINT: Specify the maximum scattering element dimension.
std::vector< DataType > data
Shape_impl(const std::string &id, Groups::Group::Group_HDF_shared_ptr grp)
virtual Group_ptr openGroup(const std::string &groupName) const =0
Opens a group.
std::string particle_constituent_single_name
uint8_t number_of_particle_constituents
uint64_t number_of_particle_scattering_elements
Structure containing a list of all of the common optional data for creating a new shape in the databa...
gsl::span< const float > particle_scattering_element_coordinates
const std::string particle_unique_id
This is the unique identifier for this shape.
gsl::span< const uint64_t > particle_scattering_element_number
DIMENSION: The id number for each scattering element. Single dimension.
Shape(const std::string &uid)
void writeAll(const gsl::span< const DataType > &outData) const
Write the passed data to the table. Writes whole table.
bool isValid(gsl::not_null< const NewShapeRequiredProperties *> required, std::ostream *errout=nullptr) const
bool requiresOptionalPropertiesStruct() const
bool isShape() const
Is this object actually a shape?
static Shape_Type openShape(Groups::Group &grpshp)
gsl::span< const float > particle_scattering_element_composition_fractional
This class defines an attribute.
std::unique_ptr< Shape > Shape_Type
The preferred C++ type for referencing a shape.
gsl::span< const uint8_t > particle_constituent_number
DIMENSION: The id number of each particle's constituent. Single dimension.
std::type_index getAttributeTypeId(const std::string &attributeName) const
Returns the type of an attribute.
static const std::string _icedb_obj_type_identifier
The tag used in icedb to identify a group.
const std::string name
The name of the group.
bool doesAttributeExist(const std::string &attributeName) const
Does the object have an attribute with the given name?
bool isValid(std::ostream *errout=nullptr) const