Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use enum for ctype indication in the C-API #306

Merged
merged 9 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,31 @@ template <class T>
struct get_component_nan;

// ctype string
template <class T, bool is_enum = std::is_enum_v<T>>
template <class T>
struct ctype_t;
template <>
struct ctype_t<double, false> {
static constexpr const char* value = "double";
struct ctype_t<double> {
static constexpr CType value = CType::c_double;
};
template <>
struct ctype_t<int32_t, false> {
static constexpr const char* value = "int32_t";
struct ctype_t<int32_t> {
static constexpr CType value = CType::c_int32;
};
template <>
struct ctype_t<int8_t, false> {
static constexpr const char* value = "int8_t";
struct ctype_t<int8_t> {
static constexpr CType value = CType::c_int8;
};

template <>
struct ctype_t<RealValue<false>, false> {
static constexpr const char* value = "double[3]";
struct ctype_t<RealValue<false>> {
static constexpr CType value = CType::c_double3;
};
template <class T>
TonyXiang8787 marked this conversation as resolved.
Show resolved Hide resolved
struct ctype_t<T, true> : ctype_t<std::underlying_type_t<T>> {};
requires std::is_enum_v<T>
struct ctype_t<T> : ctype_t<std::underlying_type_t<T>> {
};
template <class T>
constexpr const char* ctype_v = ctype_t<T>::value;
constexpr CType ctype_v = ctype_t<T>::value;

// set nan
inline void set_nan(double& x) {
Expand Down Expand Up @@ -115,14 +117,15 @@ struct MetaAttributeImpl {
// attribute in global namespace
struct PGM_MetaAttribute {
using Idx = power_grid_model::Idx;
using CType = power_grid_model::CType;
template <class T>
using trait_pointer_to_member = power_grid_model::meta_data::trait_pointer_to_member<T>;
template <class StructType, auto member_ptr>
using MetaAttributeImpl = power_grid_model::meta_data::MetaAttributeImpl<StructType, member_ptr>;
using RawDataConstPtr = power_grid_model::meta_data::RawDataConstPtr;
using RawDataPtr = power_grid_model::meta_data::RawDataPtr;
template <class T>
static constexpr const char* ctype_v = power_grid_model::meta_data::ctype_v<T>;
static constexpr CType ctype_v = power_grid_model::meta_data::ctype_v<T>;

template <class StructType, auto member_ptr,
class ValueType = typename trait_pointer_to_member<decltype(member_ptr)>::value_type>
Expand All @@ -140,7 +143,7 @@ struct PGM_MetaAttribute {

// meta data
std::string name;
std::string ctype{};
CType ctype{};
size_t offset{};
size_t size{};
size_t component_size{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ enum class FaultPhase : IntS {
nan = na_IntS
};

enum class CType : IntS { c_int32 = 0, c_int8 = 1, c_double = 2, c_double3 = 3 };

} // namespace power_grid_model

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,17 @@ enum PGM_ErrorCode {
PGM_batch_error = 2 /**< some error occurred which is in the batch calculation */
};

/**
* @brief Enumeration of C basic data types
*
*/
enum PGM_CType {
PGM_int32 = 0, /**< int32_t */
PGM_int8 = 1, /**< int8_t */
PGM_double = 2, /**< double */
PGM_double3 = 3, /**< double[3] */
};

#ifdef __cplusplus
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,10 @@ PGM_API char const* PGM_meta_attribute_name(PGM_Handle* handle, PGM_MetaAttribut
*
* @param handle
* @param attribute pointer to attribute
* @return Type of the attribute in char const*. The string is a valid C type name. The pointer is permanantly valid.
* @return Type of the attribute as in enum PGM_CType.
*
* Valid types are:
* - int32_t
* - int8_t
* - double
* - double[3]
*/
PGM_API char const* PGM_meta_attribute_ctype(PGM_Handle* handle, PGM_MetaAttribute const* attribute);
PGM_API PGM_Idx PGM_meta_attribute_ctype(PGM_Handle* handle, PGM_MetaAttribute const* attribute);
TonyXiang8787 marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief Get the ofsset of an attribute in a component
Expand Down
4 changes: 2 additions & 2 deletions power_grid_model_c/power_grid_model_c/src/meta_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ PGM_MetaAttribute const* PGM_meta_get_attribute_by_name(PGM_Handle* handle, char
char const* PGM_meta_attribute_name(PGM_Handle*, PGM_MetaAttribute const* attribute) {
return attribute->name.c_str();
}
char const* PGM_meta_attribute_ctype(PGM_Handle*, PGM_MetaAttribute const* attribute) {
return attribute->ctype.c_str();
PGM_Idx PGM_meta_attribute_ctype(PGM_Handle*, PGM_MetaAttribute const* attribute) {
return static_cast<PGM_Idx>(attribute->ctype);
}
size_t PGM_meta_attribute_offset(PGM_Handle*, PGM_MetaAttribute const* attribute) {
return attribute->offset;
Expand Down
2 changes: 1 addition & 1 deletion src/power_grid_model/core/power_grid_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def meta_attribute_name(self, attribute: AttributePtr) -> str: # type: ignore[e
pass # pragma: no cover

@make_c_binding
def meta_attribute_ctype(self, attribute: AttributePtr) -> str: # type: ignore[empty-body]
def meta_attribute_ctype(self, attribute: AttributePtr) -> int: # type: ignore[empty-body]
pass # pragma: no cover

@make_c_binding
Expand Down
14 changes: 12 additions & 2 deletions src/power_grid_model/core/power_grid_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from ctypes import Array, c_char_p, c_void_p
from dataclasses import dataclass
from enum import IntEnum
from typing import Any, Dict, Mapping, Optional, Union

import numpy as np
Expand All @@ -17,7 +18,16 @@
from power_grid_model.core.power_grid_core import AttributePtr, ComponentPtr, DatasetPtr, IdxPtr
from power_grid_model.core.power_grid_core import power_grid_core as pgc

_CTYPE_NUMPY_MAP = {"double": "f8", "int32_t": "i4", "int8_t": "i1", "double[3]": "(3,)f8"}

# constant enum for ctype
class PGMCType(IntEnum):
int32 = 0
int8 = 1
double = 2
double3 = 3


_CTYPE_NUMPY_MAP = {PGMCType.double: "f8", PGMCType.int32: "i4", PGMCType.int8: "i1", PGMCType.double3: "(3,)f8"}
_ENDIANNESS = "<" if pgc.is_little_endian() == 1 else ">"
_NAN_VALUE_MAP = {
f"{_ENDIANNESS}f8": np.nan,
Expand Down Expand Up @@ -126,7 +136,7 @@ def _generate_meta_attributes(component: ComponentPtr) -> dict:
for i in range(n_attrs):
attribute: AttributePtr = pgc.meta_get_attribute_by_idx(component, i)
attr_name: str = pgc.meta_attribute_name(attribute)
attr_ctype: str = pgc.meta_attribute_ctype(attribute)
attr_ctype: int = pgc.meta_attribute_ctype(attribute)
attr_offset: int = pgc.meta_attribute_offset(attribute)
attr_np_type = f"{_ENDIANNESS}{_CTYPE_NUMPY_MAP[attr_ctype]}"
attr_nan = _NAN_VALUE_MAP[attr_np_type]
Expand Down
2 changes: 1 addition & 1 deletion tests/c_api_tests/test_c_api_meta_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ TEST_CASE("C API Meta Data") {
CHECK(PGM_meta_get_attribute_by_name(hl, dataset_name, component_name, attribute_name) ==
attribute);
CHECK(attribute_name == component->attributes[idx_attribute].name);
CHECK(PGM_meta_attribute_ctype(hl, attribute) == attribute->ctype);
CHECK(PGM_meta_attribute_ctype(hl, attribute) == static_cast<Idx>(attribute->ctype));
CHECK(PGM_meta_attribute_offset(hl, attribute) == attribute->offset);
}
}
Expand Down
24 changes: 12 additions & 12 deletions tests/cpp_unit_tests/test_meta_data_generation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,50 +18,50 @@ TEST_CASE("Test column row conversion") {
auto const node = meta_map.get_component("node");
auto const node_attr = node.attributes;
CHECK(node_attr[0].name == "id");
CHECK(node_attr[0].ctype == "int32_t");
CHECK(node_attr[0].ctype == CType::c_int32);
CHECK(node_attr[1].name == "u_rated");
CHECK(node_attr[1].ctype == "double");
CHECK(node_attr[1].ctype == CType::c_double);

auto const sym_voltage_sensor = meta_map.get_component("sym_voltage_sensor");
auto const sensor_attr = sym_voltage_sensor.attributes;
CHECK(sensor_attr[0].name == "id");
CHECK(sensor_attr[0].ctype == "int32_t");
CHECK(sensor_attr[0].ctype == CType::c_int32);
CHECK(sensor_attr[1].name == "measured_object");
CHECK(sensor_attr[1].ctype == "int32_t");
CHECK(sensor_attr[1].ctype == CType::c_int32);
}

SUBCASE("Test meta ouput data generation") {
auto const meta_map = meta_data::meta_data().get_dataset("asym_output");
auto const node = meta_map.get_component("node");
auto const node_attr = node.attributes;
CHECK(node_attr[0].name == "id");
CHECK(node_attr[0].ctype == "int32_t");
CHECK(node_attr[0].ctype == CType::c_int32);
CHECK(node_attr[2].name == "u_pu");
CHECK(node_attr[2].ctype == "double[3]");
CHECK(node_attr[2].ctype == CType::c_double3);

auto const sym_voltage_sensor = meta_map.get_component("sym_voltage_sensor");
auto const sensor_attr = sym_voltage_sensor.attributes;
CHECK(sensor_attr[0].name == "id");
CHECK(sensor_attr[0].ctype == "int32_t");
CHECK(sensor_attr[0].ctype == CType::c_int32);
CHECK(sensor_attr[2].name == "u_residual");
CHECK(sensor_attr[2].ctype == "double[3]");
CHECK(sensor_attr[2].ctype == CType::c_double3);
}

SUBCASE("Test meta update data generation") {
auto const meta_map = meta_data::meta_data().get_dataset("update");
auto const load = meta_map.get_component("asym_load");
auto const load_attr = load.attributes;
CHECK(load_attr[0].name == "id");
CHECK(load_attr[0].ctype == "int32_t");
CHECK(load_attr[0].ctype == CType::c_int32);
CHECK(load_attr[2].name == "p_specified");
CHECK(load_attr[2].ctype == "double[3]");
CHECK(load_attr[2].ctype == CType::c_double3);

auto const sym_voltage_sensor = meta_map.get_component("sym_voltage_sensor");
auto const sensor_attr = sym_voltage_sensor.attributes;
CHECK(sensor_attr[0].name == "id");
CHECK(sensor_attr[0].ctype == "int32_t");
CHECK(sensor_attr[0].ctype == CType::c_int32);
CHECK(sensor_attr[1].name == "u_sigma");
CHECK(sensor_attr[1].ctype == "double");
CHECK(sensor_attr[1].ctype == CType::c_double);
}
}

Expand Down
40 changes: 24 additions & 16 deletions tests/cpp_validation_tests/test_validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,30 @@ void parse_single_object(RawDataPtr ptr, json const& j, MetaComponent const& met
continue;
}
MetaAttribute const& attr = meta.get_attribute(it.key());
if (attr.ctype == "int8_t") {
int8_t const value = it.value().get<int8_t>();
attr.set_value(ptr, &value, position);
}
else if (attr.ctype == "int32_t") {
int32_t const value = it.value().get<int32_t>();
attr.set_value(ptr, &value, position);
}
else if (attr.ctype == "double") {
// single double
double const value = it.value().get<double>();
attr.set_value(ptr, &value, position);
}
else if (attr.ctype == "double[3]") {
std::array<double, 3> const value = it.value().get<std::array<double, 3>>();
attr.set_value(ptr, &value, position);
using enum CType;
switch (attr.ctype) {
case c_int8: {
int8_t const value = it.value().get<int8_t>();
attr.set_value(ptr, &value, position);
break;
}
case c_int32: {
int32_t const value = it.value().get<int32_t>();
attr.set_value(ptr, &value, position);
break;
}
case c_double: {
double const value = it.value().get<double>();
attr.set_value(ptr, &value, position);
break;
}
case c_double3: {
std::array<double, 3> const value = it.value().get<std::array<double, 3>>();
attr.set_value(ptr, &value, position);
break;
}
default:
throw MissingCaseForEnumError("CType for attribute", attr.ctype);
}
}
}
Expand Down