diff --git a/code_generation/data/attribute_classes/input.json b/code_generation/data/attribute_classes/input.json index 098bf92dc..e621f65d0 100644 --- a/code_generation/data/attribute_classes/input.json +++ b/code_generation/data/attribute_classes/input.json @@ -223,7 +223,7 @@ }, { "data_type": "double", - "names": ["uk", "pk", "i0", "p0"], + "names": ["uk", "pk", "i0", "p0", "i0_zero_sequence", "p0_zero_sequence"], "description": "short circuit and open testing parameters" }, { diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index ce113af7e..e34baa953 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -17,7 +17,7 @@ The base type for all power-grid-model components. #### Input | name | data type | unit | description | required | update | -| ---- | --------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | :------------------: | +|------|-----------|------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|:--------------------:| | `id` | `int32_t` | - | ID of a component. The ID should be unique across all components within the same scenario, e.g., you cannot have a node with `id=5` and another line with `id=5`. | ✔ | ❌ (see below) | If a component update is uniform and is updating all the elements with the same component type, IDs can be omitted or @@ -33,7 +33,7 @@ An example of the usage of optional IDs is given in [Power Flow Example](./Power #### Steady state output and Short circuit output | name | data type | unit | description | -| ----------- | --------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------- | +|-------------|-----------|------|------------------------------------------------------------------------------------------------------------------------------------| | `id` | `int32_t` | - | ID of a component, the ID should be unique across all components, e.g., you cannot have a node with `id=5` and a line with `id=5`. | | `energized` | `int8_t` | - | Indicates if a component is energized, i.e. connected to a source | @@ -48,13 +48,13 @@ Physically a node can be a busbar, a joint, or other similar component. #### Input | name | data type | unit | description | required | update | valid values | -| --------- | --------- | -------- | ----------------------- | :------: | :------: | :----------: | +|-----------|-----------|----------|-------------------------|:--------:|:--------:|:------------:| | `u_rated` | `double` | volt (V) | rated line-line voltage | ✔ | ❌ | `> 0` | #### Steady state output | name | data type | unit | description | -| --------- | ----------------- | -------------------------- | ----------------------------------------------------------------------------------------------- | +|-----------|-------------------|----------------------------|-------------------------------------------------------------------------------------------------| | `u_pu` | `RealValueOutput` | - | per-unit voltage magnitude | | `u_angle` | `RealValueOutput` | rad | voltage angle | | `u` | `RealValueOutput` | volt (V) | voltage magnitude, line-line for symmetric calculation, line-neutral for asymmetric calculation | @@ -69,7 +69,7 @@ The `p` and `q` output of injection follows the `generator` reference direction #### Short circuit output | name | data type | unit | description | -| --------- | ----------------- | -------- | -------------------------------- | +|-----------|-------------------|----------|----------------------------------| | `u_pu` | `RealValueOutput` | - | per-unit voltage magnitude | | `u_angle` | `RealValueOutput` | rad | voltage angle | | `u` | `RealValueOutput` | volt (V) | voltage magnitude (line-neutral) | @@ -88,7 +88,7 @@ In this case, the attribute `from_status` and `to_status` is always 1. #### Input | name | data type | unit | description | required | update | valid values | -| ------------- | --------- | ---- | ------------------------------ | :------: | :------: | :-------------: | +|---------------|-----------|------|--------------------------------|:--------:|:--------:|:---------------:| | `from_node` | `int32_t` | - | ID of node at from-side | ✔ | ❌ | a valid node ID | | `to_node` | `int32_t` | - | ID of node at to-side | ✔ | ❌ | a valid node ID | | `from_status` | `int8_t` | - | connection status at from-side | ✔ | ✔ | `0` or `1` | @@ -97,7 +97,7 @@ In this case, the attribute `from_status` and `to_status` is always 1. #### Steady state output | name | data type | unit | description | -| --------- | ----------------- | -------------------------- | ---------------------------------------------------------- | +|-----------|-------------------|----------------------------|------------------------------------------------------------| | `p_from` | `RealValueOutput` | watt (W) | active power flowing into the branch at from-side | | `q_from` | `RealValueOutput` | volt-ampere-reactive (var) | reactive power flowing into the branch at from-side | | `i_from` | `RealValueOutput` | ampere (A) | magnitude of current at from-side | @@ -111,7 +111,7 @@ In this case, the attribute `from_status` and `to_status` is always 1. #### Short circuit output | name | data type | unit | description | -| -------------- | ----------------- | ---------- | --------------------------------- | +|----------------|-------------------|------------|-----------------------------------| | `i_from` | `RealValueOutput` | ampere (A) | magnitude of current at from-side | | `i_from_angle` | `RealValueOutput` | rad | current angle at from-side | | `i_to` | `RealValueOutput` | ampere (A) | magnitude of current at to-side | @@ -129,7 +129,7 @@ If `i_n` is not provided, `loading` of line will be a `nan` value. #### Input | name | data type | unit | description | required | update | valid values | -| ------ | --------- | ---------- | -------------------------------------------------- | :---------------------------------------: | :------: | :--------------------------------: | +|--------|-----------|------------|----------------------------------------------------|:-----------------------------------------:|:--------:|:----------------------------------:| | `r1` | `double` | ohm (Ω) | positive-sequence serial resistance | ✔ | ❌ | `r1` and `x1` cannot be both `0.0` | | `x1` | `double` | ohm (Ω) | positive-sequence serial reactance | ✔ | ❌ | `r1` and `x1` cannot be both `0.0` | | `c1` | `double` | farad (F) | positive-sequence shunt capacitance | ✔ | ❌ | | @@ -185,38 +185,53 @@ An example of usage of transformer is given in [Transformer Examples](../example #### Input -| name | data type | unit | description | required | update | valid values | -| ------------------ | ----------------------------------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------------------------------------------------: | :------: | :--------------------------------------------------------------------: | -| `u1` | `double` | volt (V) | rated voltage at from-side | ✔ | ❌ | `> 0` | -| `u2` | `double` | volt (V) | rated voltage at to-side | ✔ | ❌ | `> 0` | -| `sn` | `double` | volt-ampere (VA) | rated power | ✔ | ❌ | `> 0` | -| `uk` | `double` | - | relative short circuit voltage, `0.1` means 10% | ✔ | ❌ | `>= pk / sn` and `> 0` and `< 1` | -| `pk` | `double` | watt (W) | short circuit (copper) loss | ✔ | ❌ | `>= 0` | -| `i0` | `double` | - | relative no-load current | ✔ | ❌ | `>= p0 / sn` and `< 1` | -| `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | -| `winding_from` | {py:class}`WindingType ` | - | from-side winding type | ✔ | ❌ | | -| `winding_to` | {py:class}`WindingType ` | - | to-side winding type | ✔ | ❌ | | -| `clock` | `int8_t` | - | clock number of phase shift. Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | ✔ | ❌ | `>= -12` and `<= 12` | -| `tap_side` | {py:class}`BranchSide ` | - | side of tap changer | ✔ | ❌ | | -| `tap_pos` | `int8_t` | - | current position of tap changer | ❌ default `tap_nom`, if no `tap_nom` default `0` | ✔ | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` | -| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | ✔ | ❌ | | -| `tap_max` | `int8_t` | - | position of tap changer at maximum voltage | ✔ | ❌ | | -| `tap_nom` | `int8_t` | - | nominal position of tap changer | ❌ default `0` | ❌ | `(tap_min <= tap_nom <= tap_max)` or `(tap_min >= tap_nom >= tap_max)` | -| `tap_size` | `double` | volt (V) | size of each tap of the tap changer | ✔ | ❌ | `>= 0` | -| `uk_min` | `double` | - | relative short circuit voltage at minimum tap | ❌ default same as `uk` | ❌ | `>= pk_min / sn` and `> 0` and `< 1` | -| `uk_max` | `double` | - | relative short circuit voltage at maximum tap | ❌ default same as `uk` | ❌ | `>= pk_max / sn` and `> 0` and `< 1` | -| `pk_min` | `double` | watt (W) | short circuit (copper) loss at minimum tap | ❌ default same as `pk` | ❌ | `>= 0` | -| `pk_max` | `double` | watt (W) | short circuit (copper) loss at maximum tap | ❌ default same as `pk` | ❌ | `>= 0` | -| `r_grounding_from` | `double` | ohm (Ω) | grounding resistance at from-side, if relevant | ❌ default `0` | ❌ | | -| `x_grounding_from` | `double` | ohm (Ω) | grounding reactance at from-side, if relevant | ❌ default `0` | ❌ | | -| `r_grounding_to` | `double` | ohm (Ω) | grounding resistance at to-side, if relevant | ❌ default `0` | ❌ | | -| `x_grounding_to` | `double` | ohm (Ω) | grounding reactance at to-side, if relevant | ❌ default `0` | ❌ | | +| name | data type | unit | description | required | update | valid values | +|--------------------|-------------------------------------------------------------|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------:|:--------:|:----------------------------------------------------------------------:| +| `u1` | `double` | volt (V) | rated voltage at from-side | ✔ | ❌ | `> 0` | +| `u2` | `double` | volt (V) | rated voltage at to-side | ✔ | ❌ | `> 0` | +| `sn` | `double` | volt-ampere (VA) | rated power | ✔ | ❌ | `> 0` | +| `uk` | `double` | - | relative short circuit voltage, `0.1` means 10% | ✔ | ❌ | `>= pk / sn` and `> 0` and `< 1` | +| `pk` | `double` | watt (W) | short circuit (copper) loss | ✔ | ❌ | `>= 0` | +| `i0` | `double` | - | relative no-load (magnetizing) current | ✔ | ❌ | `>= p0 / sn` and `< 1` | +| `p0` | `double` | watt (W) | no-load (iron / magnetizing) loss | ✔ | ❌ | `>= 0` | +| `i0_zero_sequence` | `double` | - | zero-sequence relative no-load (magnetizing) current | ❌ default `i0` | ❌ | `>= p0_zero_sequence / sn` and `< 1` | +| `p0_zero_sequence` | `double` | watt (W) | zero-sequence no-load (iron / magnetizing) loss | ❌ default `p0 + pk * (i0_zero_sequence^2 - i0^2)` | ❌ | `>= 0` | +| `winding_from` | {py:class}`WindingType ` | - | from-side winding type | ✔ | ❌ | | +| `winding_to` | {py:class}`WindingType ` | - | to-side winding type | ✔ | ❌ | | +| `clock` | `int8_t` | - | clock number of phase shift. Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | ✔ | ❌ | `>= -12` and `<= 12` | +| `tap_side` | {py:class}`BranchSide ` | - | side of tap changer | ✔ | ❌ | | +| `tap_pos` | `int8_t` | - | current position of tap changer | ❌ default `tap_nom`, if no `tap_nom` default `0` | ✔ | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` | +| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | ✔ | ❌ | | +| `tap_max` | `int8_t` | - | position of tap changer at maximum voltage | ✔ | ❌ | | +| `tap_nom` | `int8_t` | - | nominal position of tap changer | ❌ default `0` | ❌ | `(tap_min <= tap_nom <= tap_max)` or `(tap_min >= tap_nom >= tap_max)` | +| `tap_size` | `double` | volt (V) | size of each tap of the tap changer | ✔ | ❌ | `>= 0` | +| `uk_min` | `double` | - | relative short circuit voltage at minimum tap | ❌ default same as `uk` | ❌ | `>= pk_min / sn` and `> 0` and `< 1` | +| `uk_max` | `double` | - | relative short circuit voltage at maximum tap | ❌ default same as `uk` | ❌ | `>= pk_max / sn` and `> 0` and `< 1` | +| `pk_min` | `double` | watt (W) | short circuit (copper) loss at minimum tap | ❌ default same as `pk` | ❌ | `>= 0` | +| `pk_max` | `double` | watt (W) | short circuit (copper) loss at maximum tap | ❌ default same as `pk` | ❌ | `>= 0` | +| `r_grounding_from` | `double` | ohm (Ω) | grounding resistance at from-side, if relevant | ❌ default `0` | ❌ | | +| `x_grounding_from` | `double` | ohm (Ω) | grounding reactance at from-side, if relevant | ❌ default `0` | ❌ | | +| `r_grounding_to` | `double` | ohm (Ω) | grounding resistance at to-side, if relevant | ❌ default `0` | ❌ | | +| `x_grounding_to` | `double` | ohm (Ω) | grounding reactance at to-side, if relevant | ❌ default `0` | ❌ | | ```{note} It can happen that `tap_min > tap_max`. In this case the winding voltage is decreased if the tap position is increased. ``` +```{note} +By default, PGM uses the same magnetization current (and thus impedance) for positive- and zero-sequence circuit. +This is typically not the case for 3-leg core-type transformers. +Due to lack of iron-core pass for zero-sequence flux, +the zero-sequence magnetization current is usually significantly higher than positive sequence. +If you want to do asymmetrical calculation with 3-leg core-type transformers, +please set the attribute `i0_zero_sequence`. +If the transformer specification does not provide such an attribute, +a good guess will be `i0_zero_sequence = 1.0`. +See [OpenDSS Documentation](https://opendss.epri.com/3-PhaseTransformerModeling.html) +for detailed explanation. +``` + #### Electric Model `transformer` is described by a $\pi$ model, where $Z_{\text{series}}$ can be computed as @@ -256,7 +271,7 @@ the off-nominal ratio must be given to adapt the electrical parameters). #### Input | name | data type | unit | description | required | update | valid values | -| ------- | --------- | ---------------- | ----------------------------- | :--------------------: | :------: | :----------: | +|---------|-----------|------------------|-------------------------------|:----------------------:|:--------:|:------------:| | `r1` | `double` | ohm | positive-sequence resistance | ✔ | ❌ | | | `x1` | `double` | ohm | positive-sequence reactance | ✔ | ❌ | | | `g1` | `double` | siemens | positive-sequence conductance | ✔ | ❌ | | @@ -327,7 +342,7 @@ This representation holds for all values `r_aa` ... `r_nn`, `x_aa` ... `x_nn` an If the neutral values are not provided, the last row and column from the above matrix are omitted. | name | data type | unit | description | required | update | valid values | -| ------ | --------- | ---------- | --------------------------------- | ---------------------------- | :------: | :----------: | +|--------|-----------|------------|-----------------------------------|------------------------------|:--------:|:------------:| | `r_aa` | `double` | ohm (Ω) | Series serial resistance aa | ✔ | ❌ | `> 0` | | `r_ba` | `double` | ohm (Ω) | Series serial resistance ba | ✔ | ❌ | `> 0` | | `r_bb` | `double` | ohm (Ω) | Series serial resistance bb | ✔ | ❌ | `> 0` | @@ -362,7 +377,7 @@ For the r and x matrices providing values for the neutral phase is optional. To clarify which input values are required, please consult the tables below: | r_aa ... r_cc | r_na | r_nb | r_nc | r_nn | result | Validation Error | -| ------------- | -------- | -------- | -------- | -------- | -------- | ------------------------- | +|---------------|----------|----------|----------|----------|----------|---------------------------| | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | @@ -372,7 +387,7 @@ To clarify which input values are required, please consult the tables below: | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | MultiFieldValidationError | | x_aa ... x_cc | x_na | x_nb | x_nc | x_nn | result | Validation Error | -| ------------- | -------- | -------- | -------- | -------- | -------- | ------------------------- | +|---------------|----------|----------|----------|----------|----------|---------------------------| | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | @@ -387,7 +402,7 @@ Whenever both sets are supplied the powerflow calculations will use `c0`, `c1`. The table below provides guidance in providing valid input. | c_aa ... c_cc | c0 | c1 | result | Validation Error | -| ------------- | -------- | -------- | -------- | ------------------------- | +|---------------|----------|----------|----------|---------------------------| | ✔ | ✔ | ✔ | ✔ | | | ✔ | ✔ | ❌ | ✔ | | | ✔ | ❌ | ❌ | ✔ | | @@ -449,7 +464,7 @@ In reality such switches may not exist. #### Input | name | data type | unit | description | required | update | valid values | -| ---------- | --------- | ---- | --------------------------- | :------: | :------: | :-------------: | +|------------|-----------|------|-----------------------------|:--------:|:--------:|:---------------:| | `node_1` | `int32_t` | - | ID of node at side 1 | ✔ | ❌ | a valid node ID | | `node_2` | `int32_t` | - | ID of node at side 2 | ✔ | ❌ | a valid node ID | | `node_3` | `int32_t` | - | ID of node at side 3 | ✔ | ❌ | a valid node ID | @@ -460,7 +475,7 @@ In reality such switches may not exist. #### Steady state output | name | data type | unit | description | -| --------- | ----------------- | -------------------------- | ---------------------------------------------------------- | +|-----------|-------------------|----------------------------|------------------------------------------------------------| | `p_1` | `RealValueOutput` | watt (W) | active power flowing into the branch at side 1 | | `q_1` | `RealValueOutput` | volt-ampere-reactive (var) | reactive power flowing into the branch at side 1 | | `i_1` | `RealValueOutput` | ampere (A) | current at side 1 | @@ -478,7 +493,7 @@ In reality such switches may not exist. #### Short circuit output | name | data type | unit | description | -| ----------- | ----------------- | ---------- | ----------------------- | +|-------------|-------------------|------------|-------------------------| | `i_1` | `RealValueOutput` | ampere (A) | current at side 1 | | `i_1_angle` | `RealValueOutput` | rad | current angle at side 1 | | `i_2` | `RealValueOutput` | ampere (A) | current at side 2 | @@ -496,7 +511,7 @@ An example of usage of three-winding transformer is given in #### Input | name | data type | unit | description | required | update | valid values | -| --------------- | ----------------------------------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------- | :-----------------------------------------------------: | :------: | :--------------------------------------------------------------------: | +|-----------------|-------------------------------------------------------------|------------------|-----------------------------------------------------------------------------------------------------------|:-------------------------------------------------------:|:--------:|:----------------------------------------------------------------------:| | `u1` | `double` | volt (V) | rated voltage at side 1 | ✔ | ❌ | `> 0` | | `u2` | `double` | volt (V) | rated voltage at side 2 | ✔ | ❌ | `> 0` | | `u3` | `double` | volt (V) | rated voltage at side 3 | ✔ | ❌ | `> 0` | @@ -509,8 +524,8 @@ An example of usage of three-winding transformer is given in | `pk_12` | `double` | watt (W) | short circuit (copper) loss across side 1-2 | ✔ | ❌ | `>= 0` | | `pk_13` | `double` | watt (W) | short circuit (copper) loss across side 1-3 | ✔ | ❌ | `>= 0` | | `pk_23` | `double` | watt (W) | short circuit (copper) loss across side 2-3 | ✔ | ❌ | `>= 0` | -| `i0` | `double` | - | relative no-load current with respect to side 1 | ✔ | ❌ | `>= p0 / sn` and `< 1` | -| `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | +| `i0` | `double` | - | relative no-load (magnetizing) current with respect to side 1 | ✔ | ❌ | `>= p0 / sn` and `< 1` | +| `p0` | `double` | watt (W) | no-load (iron / magnetizing) loss | ✔ | ❌ | `>= 0` | | `winding_1` | {py:class}`WindingType ` | - | side 1 winding type | ✔ | ❌ | | | `winding_2` | {py:class}`WindingType ` | - | side 2 winding type | ✔ | ❌ | | | `winding_3` | {py:class}`WindingType ` | - | side 3 winding type | ✔ | ❌ | | @@ -567,14 +582,14 @@ The reference direction for power flows is mentioned in {hoverxreftooltip}`user_ #### Input | name | data type | unit | description | required | update | valid values | -| -------- | --------- | ---- | ----------------------------- | :------: | :------: | :-------------: | +|----------|-----------|------|-------------------------------|:--------:|:--------:|:---------------:| | `node` | `int32_t` | - | ID of the coupled node | ✔ | ❌ | a valid node ID | | `status` | `int8_t` | - | connection status to the node | ✔ | ✔ | `0` or `1` | #### Steady state output | name | data type | unit | description | -| ---- | ----------------- | -------------------------- | -------------- | +|------|-------------------|----------------------------|----------------| | `p` | `RealValueOutput` | watt (W) | active power | | `q` | `RealValueOutput` | volt-ampere-reactive (var) | reactive power | | `i` | `RealValueOutput` | ampere (A) | current | @@ -584,7 +599,7 @@ The reference direction for power flows is mentioned in {hoverxreftooltip}`user_ #### Short circuit output | name | data type | unit | description | -| --------- | ----------------- | ---------- | ------------- | +|-----------|-------------------|------------|---------------| | `i` | `RealValueOutput` | ampere (A) | current | | `i_angle` | `RealValueOutput` | rad | current angle | @@ -601,7 +616,7 @@ The impedance is specified by convention as short circuit power. #### Input | name | data type | unit | description | required | update | valid values | -| ------------- | --------- | ---------------- | -------------------------------------------------- | :--------------------------: | :------: | :----------: | +|---------------|-----------|------------------|----------------------------------------------------|:----------------------------:|:--------:|:------------:| | `u_ref` | `double` | - | reference voltage in per-unit | ✨ only for power flow | ✔ | `> 0` | | `u_ref_angle` | `double` | rad | reference voltage angle | ❌ default `0.0` | ✔ | | | `sk` | `double` | volt-ampere (VA) | short circuit power | ❌ default `1e10` | ❌ | `> 0` | @@ -643,7 +658,7 @@ $$ only the type of the load/generation with response to voltage. | name | data type | unit | description | required | update | -| ------ | ----------------------------------------------------------- | ---- | ----------------------------------------------- | :------: | :------: | +|--------|-------------------------------------------------------------|------|-------------------------------------------------|:--------:|:--------:| | `type` | {py:class}`LoadGenType ` | - | type of load/generator with response to voltage | ✔ | ❌ | #### Load/Generator Concrete Types @@ -653,7 +668,7 @@ They share similar attributes: specified active/reactive power. However, the reference direction and meaning of `RealValueInput` is different, as shown in the table below. | type name | reference direction | meaning of `RealValueInput` | -| ----------- | ------------------- | --------------------------- | +|-------------|---------------------|-----------------------------| | `sym_load` | load | `double` | | `sym_gen` | generator | `double` | | `asym_load` | load | `double[3]` | @@ -662,7 +677,7 @@ However, the reference direction and meaning of `RealValueInput` is different, a ##### Input | name | data type | unit | description | required | update | -| ------------- | ---------------- | -------------------------- | ------------------------ | :--------------------------: | :------: | +|---------------|------------------|----------------------------|--------------------------|:----------------------------:|:--------:| | `p_specified` | `RealValueInput` | watt (W) | specified active power | ✨ only for power flow | ✔ | | `q_specified` | `RealValueInput` | volt-ampere-reactive (var) | specified reactive power | ✨ only for power flow | ✔ | @@ -710,7 +725,7 @@ It behaves similar to a load/generator with type `const_impedance`. #### Input | name | data type | unit | description | required | update | -| ---- | --------- | ----------- | ----------------------------------- | :--------------------------------------: | :------: | +|------|-----------|-------------|-------------------------------------|:----------------------------------------:|:--------:| | `g1` | `double` | siemens (S) | positive-sequence shunt conductance | ✔ | ✔ | | `b1` | `double` | siemens (S) | positive-sequence shunt susceptance | ✔ | ✔ | | `g0` | `double` | siemens (S) | zero-sequence shunt conductance | ✨ only for asymmetric calculation | ✔ | @@ -738,7 +753,7 @@ The state estimator uses the data to evaluate the state of the grid with the hig #### Input | name | data type | unit | description | required | update | valid values | -| ----------------- | --------- | ---- | ------------------------- | :------: | :------: | :---------------: | +|-------------------|-----------|------|---------------------------|:--------:|:--------:|:-----------------:| | `measured_object` | `int32_t` | - | ID of the measured object | ✔ | ❌ | a valid object ID | #### Output @@ -757,7 +772,7 @@ It measures the magnitude and (optionally) the angle of the voltage of a `node`. #### Input | name | data type | unit | description | required | update | valid values | -| --------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------- | :--------------------------------: | :------: | :----------: | +|-----------|-----------|----------|-----------------------------------------------------------------------------------------------------------------|:----------------------------------:|:--------:|:------------:| | `u_sigma` | `double` | volt (V) | standard deviation of the measurement error. Usually this is the absolute measurement error range divided by 3. | ✨ only for state estimation | ✔ | `> 0` | #### Voltage Sensor Concrete Types @@ -768,14 +783,14 @@ In a `sym_voltage_sensor` the measured voltage is a line-to-line voltage. In a `asym_voltage_sensor` the measured voltage is a 3-phase line-to-ground voltage. | type name | meaning of `RealValueInput` | -| --------------------- | --------------------------- | +|-----------------------|-----------------------------| | `sym_voltage_sensor` | `double` | | `asym_voltage_sensor` | `double[3]` | ##### Input | name | data type | unit | description | required | update | valid values | -| ------------------ | ---------------- | -------- | -------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------: | :------: | :----------: | +|--------------------|------------------|----------|----------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------:|:--------:|:------------:| | `u_measured` | `RealValueInput` | volt (V) | measured voltage magnitude | ✨ only for state estimation | ✔ | `> 0` | | `u_angle_measured` | `RealValueInput` | rad | measured voltage angle (only possible with phasor measurement units) | ✨ only for state estimation when a current sensor with `global_angle` `angle_measurement_type` is present | ✔ | | @@ -792,7 +807,7 @@ For other calculation types, sensor output is undefined. ``` | name | data type | unit | description | -| ------------------ | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ | +|--------------------|-------------------|----------|--------------------------------------------------------------------------------------------------------------------------| | `u_residual` | `RealValueOutput` | volt (V) | residual value between measured voltage magnitude and calculated voltage magnitude | | `u_angle_residual` | `RealValueOutput` | rad | residual value between measured voltage angle and calculated voltage angle (only possible with phasor measurement units) | @@ -848,7 +863,7 @@ However, such mixing of sensor types is allowed as long as they are on different ##### Input | name | data type | unit | description | required | update | valid values | -| ------------------------ | ----------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------: | :------: | :--------------------------------------------------: | +|--------------------------|-------------------------------------------------------------------------------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------:|:--------:|:----------------------------------------------------:| | `measured_terminal_type` | {py:class}`MeasuredTerminalType ` | - | indicate if it measures an `appliance` or a `branch` | ✔ | ❌ | the terminal type should match the `measured_object` | | `power_sigma` | `double` | volt-ampere (VA) | standard deviation of the measurement error. Usually this is the absolute measurement error range divided by 3. See {hoverxreftooltip}`user_manual/components:Power Sensor Concrete Types`. | ✨ in certain cases for state estimation. See the explanation for [concrete types](#power-sensor-concrete-types) below. | ✔ | `> 0` | @@ -858,14 +873,14 @@ There are two concrete types of power sensor. They share similar attributes: the meaning of `RealValueInput` is different, as shown in the table below. | type name | meaning of `RealValueInput` | -| ------------------- | --------------------------- | +|---------------------|-----------------------------| | `sym_power_sensor` | `double` | | `asym_power_sensor` | `double[3]` | ##### Input | name | data type | unit | description | required | update | valid values | -| ------------ | ---------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------: | :------: | :----------: | +|--------------|------------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------:|:--------:|:------------:| | `p_measured` | `RealValueInput` | watt (W) | measured active power | ✨ only for state estimation | ✔ | | | `q_measured` | `RealValueInput` | volt-ampere-reactive (var) | measured reactive power | ✨ only for state estimation | ✔ | | | `p_sigma` | `RealValueInput` | watt (W) | standard deviation of the active power measurement error. Usually this is the absolute measurement error range divided by 3. | ❌ see the explanation below. | ✔ | `> 0` | @@ -874,7 +889,7 @@ They share similar attributes: the meaning of `RealValueInput` is different, as Valid combinations of `power_sigma`, `p_sigma` and `q_sigma` are: | `power_sigma` | `p_sigma` | `q_sigma` | result | -| :-----------: | :-------: | :-------: | :------: | +|:-------------:|:---------:|:---------:|:--------:| | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | | ❌ | | ✔ | | ✔ | ❌ | @@ -907,7 +922,7 @@ For other calculation types, sensor output is undefined. ``` | name | data type | unit | description | -| ------------ | ----------------- | -------------------------- | ---------------------------------------------------------------------------- | +|--------------|-------------------|----------------------------|------------------------------------------------------------------------------| | `p_residual` | `RealValueOutput` | watt (W) | residual value between measured active power and calculated active power | | `q_residual` | `RealValueOutput` | volt-ampere-reactive (var) | residual value between measured reactive power and calculated reactive power | @@ -949,7 +964,7 @@ However, such mixing of sensor types is allowed as long as they are on different ##### Input | name | data type | unit | description | required | update | valid values | -| ------------------------ | ----------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------: | :------: | :--------------------------------------------------: | +|--------------------------|-------------------------------------------------------------------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------:|:--------:|:----------------------------------------------------:| | `measured_terminal_type` | {py:class}`MeasuredTerminalType ` | - | indicate the side of the `branch` | ✔ | ❌ | the terminal type should match the `measured_object` | | `angle_measurement_type` | {py:class}`AngleMeasurementType ` | - | indicate whether the measured angle is a global angle or a local angle; (see the [electric model](#local-angle-current-sensors) below) | ✔ | ❌ | | | `i_sigma` | `double` | ampere (A) | standard deviation of the current (`i`) measurement error. Usually this is the absolute measurement error range divided by 3. | ✨ only for state estimation | ✔ | `> 0` | @@ -961,14 +976,14 @@ There are two concrete types of current sensor. They share similar attributes: the meaning of `RealValueInput` is different, as shown in the table below. | type name | meaning of `RealValueInput` | -| --------------------- | --------------------------- | +|-----------------------|-----------------------------| | `sym_current_sensor` | `double` | | `asym_current_sensor` | `double[3]` | ##### Input | name | data type | unit | description | required | update | -| ------------------ | ---------------- | ---------- | ------------------------------------------------------------------------------------------------------- | :--------------------------------: | :------: | +|--------------------|------------------|------------|---------------------------------------------------------------------------------------------------------|:----------------------------------:|:--------:| | `i_measured` | `RealValueInput` | ampere (A) | measured current (`i`) magnitude | ✨ only for state estimation | ✔ | | `i_angle_measured` | `RealValueInput` | rad | measured phase angle of the current (`i`; see the [electric model](#local-angle-current-sensors) below) | ✨ only for state estimation | ✔ | @@ -989,7 +1004,7 @@ For other calculation types, sensor output is undefined. ``` | name | data type | unit | description | -| ------------------ | ----------------- | ---------- | ------------------------------------------------------------------------------------------- | +|--------------------|-------------------|------------|---------------------------------------------------------------------------------------------| | `i_residual` | `RealValueOutput` | ampere (A) | residual value between measured current (`i`) and calculated current (`i`) | | `i_angle_residual` | `RealValueOutput` | rad | residual value between measured phase angle and calculated phase angle of the current (`i`) | @@ -1058,7 +1073,7 @@ A fault can only happen at a `node`. #### Input | name | data type | unit | description | required | update | valid values | -| -------------- | --------------------------------------------------------- | ------- | --------------------------------------------------- | :-----------------------------------------------------------------------------------------------------: | :------: | :---------------: | +|----------------|-----------------------------------------------------------|---------|-----------------------------------------------------|:-------------------------------------------------------------------------------------------------------:|:--------:|:-----------------:| | `status` | `int8_t` | - | whether the fault is active | ✔ | ✔ | `0` or `1` | | `fault_type` | {py:class}`FaultType ` | - | the type of the fault | ✨ only for short circuit | ✔ | | | `fault_phase` | {py:class}`FaultPhase ` | - | the phase(s) of the fault | ❌ default `FaultPhase.default_value` (see [below](#fault-types-fault-phases-and-default-values)) | ✔ | | @@ -1084,7 +1099,7 @@ A `fault` has no steady state output. #### Short circuit output | name | data type | unit | description | -| ----------- | ----------------- | ---------- | ------------- | +|-------------|-------------------|------------|---------------| | `i_f` | `RealValueOutput` | ampere (A) | current | | `i_f_angle` | `RealValueOutput` | rad | current angle | @@ -1099,7 +1114,7 @@ In case the `fault_phase` is not specified or is equal to `FaultPhase.default_va The supported values of `fault_phase`, as well as its default value, are listed in the table below. | `fault_type` | supported values of `fault_phase` | `FaultPhase.default_value` | description | -| ---------------------------------- | ------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------- | +|------------------------------------|---------------------------------------------------|----------------------------|------------------------------------------------------------------------| | `FaultType.three_phase` | `FaultPhase.abc` | `FaultPhase.abc` | Three phases are connected with fault impedance. | | `FaultType.single_phase_to_ground` | `FaultPhase.a`, `FaultPhase.b`, `FaultPhase.c` | `FaultPhase.a` | One phase is grounded with fault impedance, and other phases are open. | | `FaultType.two_phase` | `FaultPhase.bc`, `FaultPhase.ac`, `FaultPhase.ab` | `FaultPhase.bc` | Two phases are connected with fault impedance. | @@ -1117,7 +1132,7 @@ Which object types are supported as `regulated_object` is regulator type-depende #### Input | name | data type | unit | description | required | update | valid values | -| ------------------ | --------- | ---- | ----------------------------------------- | :------: | :------: | :-------------------------: | +|--------------------|-----------|------|-------------------------------------------|:--------:|:--------:|:---------------------------:| | `regulated_object` | `int32_t` | - | ID of the regulated object | ✔ | ❌ | a valid regulated object ID | | `status` | `int8_t` | - | connection status to the regulated object | ✔ | ✔ | `0` or `1` | @@ -1147,7 +1162,7 @@ The actual grid state is not changed after calculations are done. #### Input | name | data type | unit | description | required | update | valid values | -| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------- | :--------------------------: | :------: | :--------------------------------------------------------------: | +|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------------------------------------------------------------------------------------------------|:----------------------------:|:--------:|:----------------------------------------------------------------:| | `control_side` | {py:class}`BranchSide ` if the regulated object is a {hoverxreftooltip}`user_manual/components:transformer` and {py:class}`Branch3Side ` if it the regulated object is a {hoverxreftooltip}`user_manual/components:Three-Winding Transformer` | - | the controlled side of the transformer | ✨ only for power flow | ❌ | `control_side` should be the relatively further side to a source | | `u_set` | `double` | volt (V) | the voltage setpoint (at the center of the band) | ✨ only for power flow | ✔ | `>= 0` | | `u_band` | `double` | volt (V) | the width of the voltage band ($=2*\left(\Delta U\right)_{\text{acceptable}}$) | ✨ only for power flow | ✔ | `> 0` (see below) | @@ -1170,7 +1185,7 @@ Typical real-world power grids already satisfy these requirements and they shoul #### Steady state output | name | data type | unit | description | -| --------- | --------- | ---- | -------------------- | +|-----------|-----------|------|----------------------| | `tap_pos` | `int8_t` | - | optimal tap position | #### Short circuit output diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp index 76bed343c..15b6d7bfb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp @@ -195,6 +195,8 @@ struct TransformerInput { double pk{nan}; // short circuit and open testing parameters double i0{nan}; // short circuit and open testing parameters double p0{nan}; // short circuit and open testing parameters + double i0_zero_sequence{nan}; // short circuit and open testing parameters + double p0_zero_sequence{nan}; // short circuit and open testing parameters WindingType winding_from{static_cast(na_IntS)}; // winding type at each side WindingType winding_to{static_cast(na_IntS)}; // winding type at each side IntS clock{na_IntS}; // clock number diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp index 1d0c72917..a5fb7aef3 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp @@ -188,7 +188,7 @@ struct get_attributes_list { template<> struct get_attributes_list { - static constexpr std::array value{ + static constexpr std::array value{ // all attributes including base class meta_data_gen::get_meta_attribute<&TransformerInput::id>(offsetof(TransformerInput, id), "id"), @@ -203,6 +203,8 @@ struct get_attributes_list { meta_data_gen::get_meta_attribute<&TransformerInput::pk>(offsetof(TransformerInput, pk), "pk"), meta_data_gen::get_meta_attribute<&TransformerInput::i0>(offsetof(TransformerInput, i0), "i0"), meta_data_gen::get_meta_attribute<&TransformerInput::p0>(offsetof(TransformerInput, p0), "p0"), + meta_data_gen::get_meta_attribute<&TransformerInput::i0_zero_sequence>(offsetof(TransformerInput, i0_zero_sequence), "i0_zero_sequence"), + meta_data_gen::get_meta_attribute<&TransformerInput::p0_zero_sequence>(offsetof(TransformerInput, p0_zero_sequence), "p0_zero_sequence"), meta_data_gen::get_meta_attribute<&TransformerInput::winding_from>(offsetof(TransformerInput, winding_from), "winding_from"), meta_data_gen::get_meta_attribute<&TransformerInput::winding_to>(offsetof(TransformerInput, winding_to), "winding_to"), meta_data_gen::get_meta_attribute<&TransformerInput::clock>(offsetof(TransformerInput, clock), "clock"), diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index 381a03516..7d29b5679 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -18,6 +18,14 @@ namespace power_grid_model { class Transformer : public Branch { + private: + struct TransformerParams { + DoubleComplex y_series{}; + DoubleComplex y_shunt{}; + DoubleComplex y0_shunt{}; + double k{1.0}; + }; + public: using InputType = TransformerInput; using UpdateType = TransformerUpdate; @@ -33,6 +41,10 @@ class Transformer : public Branch { pk_{transformer_input.pk}, i0_{transformer_input.i0}, p0_{transformer_input.p0}, + i0_zero_sequence_{is_nan(transformer_input.i0_zero_sequence) ? i0_ : transformer_input.i0_zero_sequence}, + p0_zero_sequence_{is_nan(transformer_input.p0_zero_sequence) + ? p0_ + pk_ * (i0_zero_sequence_ * i0_zero_sequence_ - i0_ * i0_) + : transformer_input.p0_zero_sequence}, winding_from_{transformer_input.winding_from}, winding_to_{transformer_input.winding_to}, clock_{transformer_input.clock}, @@ -120,6 +132,8 @@ class Transformer : public Branch { double pk_; double i0_; double p0_; + double i0_zero_sequence_; + double p0_zero_sequence_; WindingType winding_from_; WindingType winding_to_; IntS clock_; @@ -156,7 +170,7 @@ class Transformer : public Branch { } // calculate transformer parameter - std::tuple transformer_params() const { + TransformerParams transformer_params() const { double const base_y_to = base_i_to_ * base_i_to_ / base_power_1p; // off nominal tap ratio auto const [u1, u2] = [this]() { @@ -192,29 +206,39 @@ class Transformer : public Branch { z_series.imag(uk_sign * (z_series_imag_squared > 0.0 ? std::sqrt(z_series_imag_squared) : 0.0)); // y series y_series = (1.0 / z_series) / base_y_to; + // shunt DoubleComplex y_shunt; - // Y = I0_2 / (U2/sqrt3) = i0 * (S / sqrt3 / U2) / (U2/sqrt3) = i0 * S * / U2 / U2 + // Y = I0 / (U2/sqrt3) = i0 * (S / sqrt3 / U2) / (U2/sqrt3) = i0 * S * / U2 / U2 double const y_shunt_abs = i0_ * sn_ / u2 / u2; // G = P0 / (U2^2) y_shunt.real(p0_ / u2 / u2); - auto const y_shunt_imag_squared = y_shunt_abs * y_shunt_abs - y_shunt.real() * y_shunt.real(); y_shunt.imag(y_shunt_imag_squared > 0.0 ? -std::sqrt(y_shunt_imag_squared) : 0.0); - - // y shunt y_shunt = y_shunt / base_y_to; + + // shunt zero sequence + DoubleComplex y0_shunt; + // Y0 = I0_0 / (U2/sqrt3) = i0_zero_sequence_ * (S / sqrt3 / U2) / (U2/sqrt3) = i0_zero_sequence_ * S / U2 / + // U2 + double const y0_shunt_abs = i0_zero_sequence_ * sn_ / u2 / u2; + // G0 = P0_0 / (U2^2) + y0_shunt.real(p0_zero_sequence_ / u2 / u2); + auto const y0_shunt_imag_squared = y0_shunt_abs * y0_shunt_abs - y0_shunt.real() * y0_shunt.real(); + y0_shunt.imag(y0_shunt_imag_squared > 0.0 ? -std::sqrt(y0_shunt_imag_squared) : 0.0); + y0_shunt = y0_shunt / base_y_to; + // return - return std::make_tuple(y_series, y_shunt, k); + return TransformerParams{.y_series = y_series, .y_shunt = y_shunt, .y0_shunt = y0_shunt, .k = k}; } // branch param BranchCalcParam sym_calc_param() const final { - auto const [y_series, y_shunt, k] = transformer_params(); + auto const [y_series, y_shunt, y0_shunt, k] = transformer_params(); return calc_param_y_sym(y_series, y_shunt, k * std::exp(1.0i * (clock_ * deg_30))); } BranchCalcParam asym_calc_param() const final { - auto const [y_series, y_shunt, k] = transformer_params(); + auto const [y_series, y_shunt, y0_shunt, k] = transformer_params(); // positive sequence auto const param1 = calc_param_y_sym(y_series, y_shunt, k * std::exp(1.0i * (clock_ * deg_30))); // negative sequence @@ -230,19 +254,37 @@ class Transformer : public Branch { } DoubleComplex const z0_series = 1.0 / y_series + 3.0 * (z_grounding_to_ + z_grounding_from_ / k / k); DoubleComplex const y0_series = 1.0 / z0_series; - param0 = calc_param_y_sym(y0_series, y_shunt, k * std::exp(1.0i * phase_shift_0)); + param0 = calc_param_y_sym(y0_series, y0_shunt, k * std::exp(1.0i * phase_shift_0)); } - // YNd - if (winding_from_ == WindingType::wye_n && winding_to_ == WindingType::delta && from_status()) { - DoubleComplex const z0_series = 1.0 / y_series + 3.0 * z_grounding_from_ / k / k; - DoubleComplex const y0_series = 1.0 / z0_series; - param0.yff() = (y0_series + y_shunt) / k / k; + // YN* + else if (winding_from_ == WindingType::wye_n && from_status()) { + // ground path always possible via magnetization branch + DoubleComplex y0 = y0_shunt; + if (winding_to_ == WindingType::delta) { + // additional path via zk + y0 += y_series; + } + if (y0 != DoubleComplex{0.0, 0.0}) { + // avoid division by zero + DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_from_ / k / k; + y0 = 1.0 / z0; + param0.yff() = y0 / k / k; + } } - // Dyn - if (winding_from_ == WindingType::delta && winding_to_ == WindingType::wye_n && to_status()) { - DoubleComplex const z0_series = 1.0 / y_series + 3.0 * z_grounding_to_; - DoubleComplex const y0_series = 1.0 / z0_series; - param0.ytt() = (y0_series + y_shunt); + // *yn + else if (winding_to_ == WindingType::wye_n && to_status()) { + // ground path always possible via magnetization branch + DoubleComplex y0 = y0_shunt; + if (winding_from_ == WindingType::delta) { + // additional path via zk + y0 += y_series; + } + if (y0 != DoubleComplex{0.0, 0.0}) { + // avoid division by zero + DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_to_; + y0 = 1.0 / z0; + param0.ytt() = y0; + } } // ZN* // Zero sequence impedance of zigzag winding is approximately 10% of positive sequence impedance diff --git a/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h b/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h index ce739b0ee..6af6842d3 100644 --- a/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h +++ b/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h @@ -122,6 +122,8 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_uk; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_pk; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_i0; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_p0; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_i0_zero_sequence; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_p0_zero_sequence; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_winding_from; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_winding_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_clock; diff --git a/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp b/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp index 00a190c4a..758c3c62a 100644 --- a/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp +++ b/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp @@ -111,6 +111,8 @@ PGM_MetaAttribute const* const PGM_def_input_transformer_uk = PGM_meta_get_attri PGM_MetaAttribute const* const PGM_def_input_transformer_pk = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "pk"); PGM_MetaAttribute const* const PGM_def_input_transformer_i0 = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "i0"); PGM_MetaAttribute const* const PGM_def_input_transformer_p0 = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "p0"); +PGM_MetaAttribute const* const PGM_def_input_transformer_i0_zero_sequence = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "i0_zero_sequence"); +PGM_MetaAttribute const* const PGM_def_input_transformer_p0_zero_sequence = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "p0_zero_sequence"); PGM_MetaAttribute const* const PGM_def_input_transformer_winding_from = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "winding_from"); PGM_MetaAttribute const* const PGM_def_input_transformer_winding_to = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "winding_to"); PGM_MetaAttribute const* const PGM_def_input_transformer_clock = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "clock"); diff --git a/tests/cpp_unit_tests/test_transformer.cpp b/tests/cpp_unit_tests/test_transformer.cpp index 6b6417911..b9d65c008 100644 --- a/tests/cpp_unit_tests/test_transformer.cpp +++ b/tests/cpp_unit_tests/test_transformer.cpp @@ -418,6 +418,7 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { .pk = 100e3, .i0 = 0.015, .p0 = 30.0e4, + .i0_zero_sequence = 1.0, .winding_from = WindingType::delta, .winding_to = WindingType::wye_n, .clock = 11, @@ -462,6 +463,18 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { } DoubleComplex const y_1_shunt = (y_shunt_real + 1i * y_shunt_imag) / base_y_to; + double const p0_zero_sequence = + input.p0 + input.pk * (input.i0_zero_sequence * input.i0_zero_sequence - input.i0 * input.i0); + double const y0_shunt_abs = input.i0_zero_sequence * input.sn / input.u2 / input.u2; + double const y0_shunt_real = p0_zero_sequence / input.u2 / input.u2; + double y0_shunt_imag; + if (y0_shunt_real > y0_shunt_abs) { + y0_shunt_imag = 0.0; + } else { + y0_shunt_imag = -std::sqrt(y0_shunt_abs * y0_shunt_abs - y0_shunt_real * y0_shunt_real); + } + DoubleComplex const y_0_shunt = (y0_shunt_real + 1i * y0_shunt_imag) / base_y_to; + DoubleComplex const tap_ratio_1 = k * std::exp(1.0i * (deg_30 * input.clock)); DoubleComplex const y_1_tt = (1.0 / z_1_series) + 0.5 * y_1_shunt; @@ -485,7 +498,7 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { DoubleComplex const y_0_ff = low_admittance; DoubleComplex const y_0_ft = 0.0; DoubleComplex const y_0_tf = 0.0; - DoubleComplex const y_0_tt = (1.0 / (z_1_series + 3.0 * z_grounding_to)) + y_1_shunt; + DoubleComplex const y_0_tt = (1.0 / (1.0 / (1.0 / z_1_series + y_0_shunt) + 3.0 * z_grounding_to)); // Sequence admittances -> phase addmitance ComplexTensor y_ff_diagonal; @@ -707,7 +720,7 @@ TEST_CASE("Test Transformer - Dyn11 - tap_max and tap_min flipped") { DoubleComplex const y_0_ff = low_admittance; DoubleComplex const y_0_ft = 0.0; DoubleComplex const y_0_tf = 0.0; - DoubleComplex const y_0_tt = (1.0 / (z_1_series + 3.0 * z_grounding_to)) + y_1_shunt; + DoubleComplex const y_0_tt = (1.0 / (1.0 / (1.0 / z_1_series + y_1_shunt) + 3.0 * z_grounding_to)); // Sequence admittances -> phase addmitance ComplexTensor y_ff_diagonal; diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json new file mode 100644 index 000000000..a51b55322 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 1, "energized": 1, "u_pu": [1, 1, 1], "u": [5773.5026918962576, 5773.5026918962576, 5773.5026918962576], "u_angle": [-2.6439876230271684e-44, -2.0943951023931953, 2.0943951023931953], "p": [881329.20767572254, 1037364.8940881646, 1081305.8982361141], "q": [226203.41305523555, 85377.466355255776, 290921.30803535768]}, + {"id": 2, "energized": 1, "u_pu": [1.0141430605715689, 0.96656989153700335, 1.0110998975479204], "u": [5855.1576901778626, 5580.4938706947623, 5837.5879802689487], "u_angle": [0.001939888439272864, -2.1247815189679589, 2.0324414694676975], "p": [-799999.99999999849, -1000000.0000000008, -1199999.9999999972], "q": [7.4587508688682828e-10, 1.7304176386161853e-09, 5.1725865757671641e-09]} + ], + "transformer": [ + {"id": 4, "energized": 1, "loading": 0.30705253328631577, "p_from": [881329.20767572254, 1037364.8940881646, 1081305.8982361141], "q_from": [226203.41305523555, 85377.466355255761, 290921.30803535768], "i_from": [157.59846030784894, 180.28437829560764, 193.9477496411763], "s_from": [909895.13482607121, 1040872.3433965337, 1119757.8546405528], "p_to": [-799999.99999999849, -1000000.0000000008, -1199999.9999999972], "q_to": [7.4606055156303146e-10, 1.7076212935884444e-09, 5.1782885887484745e-09], "i_to": [136.63167455626581, 179.19560941574917, 205.56435364331952], "s_to": [799999.99999999849, 1000000.0000000008, 1199999.9999999972]} + ], + "asym_load": [ + {"id": 6, "energized": 1, "p": [799999.99999999988, 1000000, 1200000], "q": [0, 0, 0], "i": [136.63167455626603, 179.19560941574903, 205.56435364331998], "s": [799999.99999999988, 1000000, 1200000], "pf": [1, 1, 1]} + ], + "source": [ + {"id": 7, "energized": 1, "p": [881329.20767572254, 1037364.8940881646, 1081305.8982361141], "q": [226203.41305523555, 85377.466355255761, 290921.30803535774], "i": [157.59846030784894, 180.28437829560764, 193.9477496411763], "s": [909895.13482607121, 1040872.3433965337, 1119757.8546405528], "pf": [0.96860525344405857, 0.99663027908213619, 0.96566047181979187]} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json.license b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/input.json b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json new file mode 100644 index 000000000..cc4a4de74 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "transformer": [ + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 10000000, "uk": 0.10000000000000001, "pk": 0, "i0": 0.050000000000000003, "p0": 0, "i0_zero_sequence": 1, "winding_from": 0, "winding_to": 1, "clock": 12, "tap_side": 0, "tap_pos": 0, "tap_min": 0, "tap_max": 0, "tap_nom": 0, "tap_size": 0} + ], + "asym_load": [ + {"id": 6, "node": 2, "status": 1, "type": 0, "p_specified": [800000, 1000000, 1200000], "q_specified": [0, 0, 0]} + ], + "source": [ + {"id": 7, "node": 1, "status": 1, "u_ref": 1, "sk": 1.0000000000000001e+50, "rx_ratio": 0, "z01_ratio": 1} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/input.json.license b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/params.json b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json new file mode 100644 index 000000000..6a2809e23 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json @@ -0,0 +1,7 @@ +{ + "calculation_method": [ + "newton_raphson" + ], + "rtol": 1e-07, + "atol": 1e-07 +} \ No newline at end of file diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/params.json.license b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0