Validation Examples

As a result of optimizations, and the low level nature of the Power Grid Model’s mathematical core, the core exceptions may not always be clear to the user. Therefore an optional validation mechanism is supplied, which validates data structures and values off-line. It is recommended to always validate your data before constructing a PowerGridModel instance. An alternative approach would be to validate only when an exception is raised, but be aware that not all data errors will raise exceptions, most of them wil just yield invalid results without warning.

The basic methods and class definitions are available in the power_grid_model.validation module:

# Manual validation
#   validate_input_data() assumes that you won't be using update data in your calculation.
#   validate_batch_data() validates input_data in combination with batch/update data.
validate_input_data(input_data, calculation_type, symmetric) -> List[ValidationError]
validate_batch_data(input_data, update_data, calculation_type, symmetric) -> Dict[int, List[ValidationError]]

# Assertions
#   assert_valid_input_data() and assert_valid_batch_data() raise a ValidationException,
#   containing the list/dict of errors, when the data is invalid.
assert_valid_input_data(input_data, calculation_type, symmetric) raises ValidationException
assert_valid_batch_data(input_data, calculation_type, update_data, symmetric) raises ValidationException

# Utilities
#   errors_to_string() converts a set of errors to a human readable (multi-line) string representation
errors_to_string(errors, name, details)

Each validation error is an object which can be converted to a compact human-readable message using str(error). It contains three member variables component, field and ids, which can be used to gather more specific information about the validation error, e.g. which object IDs are involved.

class ValidationError:
    
    # Component(s): e.g. "node" or ["node", "line"]
    component: Union[str, List[str]]
    
    # Field(s): e.g. "id" or ["line_from", "line_to"] or [("node", "id"), ("line", "id")]
    field: Union[str, List[str], List[Tuple[str, str]]]

    # IDs: e.g. [1, 2, 3] or [("node", 1), ("line", 1)]
    ids: Union[List[int], List[Tuple[str, int]]] = []    
    

Note: The data types of input_data and update_data are the same as expected by the power grid model.

from power_grid_model import PowerGridModel, initialize_array

# A power grid containing several errors

# node
node_error = initialize_array("input", "node", 3)
node_error["id"] = [1, 2, 3]
node_error["u_rated"] = [10.5e3]

# line
line_error = initialize_array("input", "line", 3)
line_error["id"] = [4, 5, 6]
line_error["from_node"] = [1, 2, 3]
line_error["to_node"] = [2, 3, 4]
line_error["from_status"] = [True]
line_error["to_status"] = [True]
line_error["r1"] = [0.25]
line_error["x1"] = [0.2]
line_error["c1"] = [10e-6]
line_error["tan1"] = [0.0]

# Power Sensor
sensor_error = initialize_array("input", "sym_power_sensor", 2)
sensor_error["id"] = [6, 7]
sensor_error["measured_object"] = [3, 4]
sensor_error["measured_terminal_type"] = [0, 2]
sensor_error["p_measured"] = [0]
sensor_error["q_measured"] = [0]
sensor_error["power_sigma"] = [0]

error_data = {"node": node_error, "line": line_error, "sym_power_sensor": sensor_error}
# Without validation
model = PowerGridModel(error_data)
output_data = model.calculate_state_estimation(symmetric=True)
---------------------------------------------------------------------------
IDWrongType                               Traceback (most recent call last)
Cell In[2], line 2
      1 # Without validation
----> 2 model = PowerGridModel(error_data)
      3 output_data = model.calculate_state_estimation(symmetric=True)

File C:\src\power-grid-model\venv\Lib\site-packages\power_grid_model\core\power_grid_model.py:108, in PowerGridModel.__init__(self, input_data, system_frequency)
    106 prepared_input = prepare_input_view(input_data)
    107 self._model_ptr = pgc.create_model(system_frequency, input_data=prepared_input.get_dataset_ptr())
--> 108 assert_no_error()
    109 self._all_component_count = {k: v for k, v in prepared_input.get_info().total_elements().items() if v > 0}

File C:\src\power-grid-model\venv\Lib\site-packages\power_grid_model\core\error_handling.py:142, in assert_no_error(batch_size, decode_error)
    140 error = find_error(batch_size=batch_size, decode_error=decode_error)
    141 if error is not None:
--> 142     raise error

IDWrongType: Wrong type for object with id 4

Try validate_input_data() or validate_batch_data() to validate your data.
from power_grid_model.validation import assert_valid_input_data

# Assert valid data
assert_valid_input_data(error_data, symmetric=True)
model = PowerGridModel(error_data)
output_data = model.calculate_state_estimation(symmetric=True)
---------------------------------------------------------------------------
ValidationException                       Traceback (most recent call last)
Cell In[3], line 4
      1 from power_grid_model.validation import assert_valid_input_data
      3 # Assert valid data
----> 4 assert_valid_input_data(error_data, symmetric=True)
      5 model = PowerGridModel(error_data)
      6 output_data = model.calculate_state_estimation(symmetric=True)

File C:\src\power-grid-model\venv\Lib\site-packages\power_grid_model\validation\assertions.py:57, in assert_valid_input_data(input_data, calculation_type, symmetric)
     53 validation_errors = validate_input_data(
     54     input_data=input_data, calculation_type=calculation_type, symmetric=symmetric
     55 )
     56 if validation_errors:
---> 57     raise ValidationException(validation_errors, "input_data")

ValidationException: There are 5 validation errors in input_data:
   1. Fields line.id and sym_power_sensor.id are not unique for 2 lines/sym_power_sensors.
   2. Field 'to_node' does not contain a valid node id for 1 line.
   3. Field 'power_sigma' is not greater than zero for 2 sym_power_sensors.
   4. Field 'measured_object' does not contain a valid line/transformer id for 1 sym_power_sensor. (measured_terminal_type=branch_from)
   5. Field 'measured_object' does not contain a valid source id for 1 sym_power_sensor. (measured_terminal_type=source)
from power_grid_model.validation import ValidationException

# Assert valid data and display component ids
try:
    assert_valid_input_data(error_data, symmetric=True)
    model = PowerGridModel(error_data)
    output_data = model.calculate_state_estimation(symmetric=True)
except ValidationException as ex:
    for error in ex.errors:
        print(type(error).__name__, error.component, ":", error.ids)
MultiComponentNotUniqueError ['line', 'sym_power_sensor'] : [('line', 6), ('sym_power_sensor', 6)]
InvalidIdError line : [6]
NotGreaterThanError sym_power_sensor : [6, 7]
InvalidIdError sym_power_sensor : [6]
InvalidIdError sym_power_sensor : [7]
from power_grid_model.validation import validate_input_data, errors_to_string

# Validation only as exception handling
try:
    model = PowerGridModel(error_data)
    output_data = model.calculate_state_estimation(symmetric=True)
except RuntimeError as ex:
    errors = validate_input_data(error_data, symmetric=True)
    print(errors_to_string(errors))
There are 5 validation errors in the data:
   1. Fields line.id and sym_power_sensor.id are not unique for 2 lines/sym_power_sensors.
   2. Field 'to_node' does not contain a valid node id for 1 line.
   3. Field 'power_sigma' is not greater than zero for 2 sym_power_sensors.
   4. Field 'measured_object' does not contain a valid line/transformer id for 1 sym_power_sensor. (measured_terminal_type=branch_from)
   5. Field 'measured_object' does not contain a valid source id for 1 sym_power_sensor. (measured_terminal_type=source)
# Manual checking and display detailed information about the invalid data
errors = validate_input_data(error_data, symmetric=True)
print(errors_to_string(errors, details=True))
There are 5 validation errors in the data:

	Fields line.id and sym_power_sensor.id are not unique for 2 lines/sym_power_sensors.
		component: line/sym_power_sensor
		field: line.id and sym_power_sensor.id
		ids: [('line', 6), ('sym_power_sensor', 6)]

	Field 'to_node' does not contain a valid node id for 1 line.
		component: line
		field: 'to_node'
		ids: [6]
		ref_components: node
		filters: 

	Field 'power_sigma' is not greater than zero for 2 sym_power_sensors.
		component: sym_power_sensor
		field: 'power_sigma'
		ids: [6, 7]
		ref_value: zero

	Field 'measured_object' does not contain a valid line/transformer id for 1 sym_power_sensor. (measured_terminal_type=branch_from)
		component: sym_power_sensor
		field: 'measured_object'
		ids: [6]
		ref_components: line/transformer
		filters: (measured_terminal_type=branch_from)

	Field 'measured_object' does not contain a valid source id for 1 sym_power_sensor. (measured_terminal_type=source)
		component: sym_power_sensor
		field: 'measured_object'
		ids: [7]
		ref_components: source
		filters: (measured_terminal_type=source)