Repository: e2nIEE/pandapower

Issue:
build branches from trafo3w
**Issue**
In a very specific cases of 3winding transformer parameters, it may happen that short circuit impedance `z_sc` ends up as smaller than resistance  `r_sc`, specifically this results in [this line](https://github.com/lthurner/pandapower/blob/develop/pandapower/build_branch.py#L364) with negative value in sqrt (and nan value of `x_sc` and singular jacobian matrix).
**Error log**:
![image](https://user-images.githubusercontent.com/9588722/27687950-0ee21382-5cd9-11e7-92af-bdab47ed3444.png)

**Reason** for this behavior is the following: three winding transformers are first transformed to equivalent 2winding transformers (wye-delta transformation) and then branches are created using the same routines as for 2winding transformers (there is a reason for this: 3w and 2w transformer use the same build_branch routines, so in the developing phase any change for 2w holds for 3w). After wye-delta conversion resulting parameters does not represent any physical values, so they can get some unrealistic values (even negative values are possible). More specifically, after conversion of 3w transformers to 2w, resulting `vsc_percent` and `vscr_percent` of each transformer for some specific cases can get such values that `z_sc<r_sc`.

**Solution suggestion**:
Instead of transforming a 3winding transformer to 2winding and then building branches from 2winding transformers, a direct building of 3 branches from a 3winding transformer should be implemented. Also, first branch impedance should be calculated and then wye-delta conversion performed.
This should result with exactly the same branch values in all cases, but avoid this issue in such specific cases.



Discussion:
Yes this is a good idea, please go ahead. Please also add one of these special cases to the test suite so this behaviour is tested for the future.

Maybe while we are looking into 3W transformers we can also adress switches at 3W transformers as discussed in #30
There are some more issues within this issue that I mentioned when building branches from a 3winding trafo, which I noticed due to difference from branches parameters obtained using the current pandapower realease and the branches I got:

- when [calculating](https://github.com/lthurner/pandapower/blob/develop/pandapower/build_branch.py#L298) magnetising admittance, `sn_hv_kva` is used, and I think `min(sn_hv_kva, sn_mv_kva) `should be used !?  (if I am not terribly wrong?)
![image](https://user-images.githubusercontent.com/9588722/28774656-d2a4f28e-75ee-11e7-9a77-0b1ebce43c57.png)

- in the current implementation, first `vsc_percent` and `vscr_percent` are transformed delta-to-wye and then r and x are calculated from them for each of 3 branches. The right order should be to first calculate `x12, x23, x13` and than make wye-delta transformation. In other words, result is not the same if one first transforms `z12, z23, z13` to `z1, z2, z3` and then  calculates `x1, x2, x3`...than if one first calculates `x12, x23, x13` and then transforms them to `x1, x2, x3`

There are some less important things to be mentioned:

- documentation for the trafo3w should be updated in any case (there is no any mention of `min(sn_hv_kva, sn_mv_kva)`) 

- using `shift_mv_degree` and `shift_mv_degree` is not really clear to me? phase shift should be related to tap, so if there is one tap on a trafo3w, there should be only one phase_shift, then internally this tap should be calculated for each side? if I am not terribly wrong?

- by direct generation of branches from 3winding transformers, there is no need to define voltage level of the additional bus. All the values are calculated on the side of the additional bus, where we can assume base(nominal) voltage is equal to rated.

- why this: `b_img[b_img < 0] = 0` [here](https://github.com/lthurner/pandapower/blob/develop/pandapower/build_branch.py#L301) ?

Hi Jakov,

thanks for taking the time for this implementation, I think it is very good to get a vectorized implementation of the 3 winding transformers. Apart from the incompatibility with certain values there is also the time factor, we recently had a network with several hundred 3w transformers where the 3w conversion took up about 2/3 of the power flow time. This should speed up things nicely.

> when calculating magnetising admittance, sn_hv_kva is used, and I think min(sn_hv_kva, sn_mv_kva)should be used !? (if I am not terribly wrong?)

Where are these equations from? As far as I understand, all loss factors (like i0_percent for example) are in relation to the rated power of the whole transformer, which is sn_hv_kva. Using min(sn_hv_kva, sn_mv_kva) would mean always using sn_mv_kva, since sn_hv_kva>sn_mv_kva. Why should sn_mv_kva be the reference for the loss parameters?

> in the current implementation, first vsc_percent and vscr_percent are transformed delta-to-wye and then r and x are calculated from them for each of 3 branches. The right order should be to first calculate x12, x23, x13 and than make wye-delta transformation. In other words, result is not the same if one first transforms z12, z23, z13 to z1, z2, z3 and then calculates x1, x2, x3...than if one first calculates x12, x23, x13 and then transforms them to x1, x2, x3

Why do you think this would be the right order, do you have a source for that?

> using shift_mv_degree and shift_mv_degree is not really clear to me? phase shift should be related to tap, so if there is one tap on a trafo3w, there should be only one phase_shift, then internally this tap should be calculated for each side? if I am not terribly wrong?

The phase shift is not necessarily related to the tap changer, it is primarily related to the transformer vector group. The transformer can have a vector group so that the phase shifts of mv and lv side are different.

> documentation for the trafo3w should be updated in any case (there is no any mention of min(sn_hv_kva, sn_mv_kva))

Yes should definetly updated, lets do it after the refactoring is done

> by direct generation of branches from 3winding transformers, there is no need to define voltage level of the additional bus. All the values are calculated on the side of the additional bus, where we can assume base(nominal) voltage is equal to rated.

I don't quite understand what you mean... Don't you need to define a voltage level for the power flow to work? Or do you mean we don't need it because the values are always in per unit and therefore we just assume 1.0 pu as initial voltage?

> why this: b_img[b_img < 0] = 0 here ?

The magnitude of the magnetizing impedance is defined by i0_percent, the real part of the magnetizing impedance is defined by pfe_kw. If you chose an i0_percent that is small, and an pfe_kw that is large, the imaginary part of the magnetizing impedance would become negative and the transformer would have and capacitive behaviour. In that case the imaginary part is set to zero rather than to model capacitive behaviour in a transformer. This might however be the correct behaviour in 3W transformers where the transformers are only equivalent transformers and might have parameters which are not physically logical.

In general, I think we should base our validation on commercial software, which is the only way to know if the model is correct. That is what I tried to do with the test [here](https://github.com/lthurner/pandapower/blob/b86ea6dbe0ab92346d8b9ec718a5daf30f6f4d95/pandapower/test/loadflow/test_results.py#L349). The results in there are extracted from powerfactory, and the voltages match the results from pandapower with a tolerance of 1e-6. That should be the benchmark from my point of view, but we should also add new corner cases (e.g. the one that you experienced where an error occurs).
Hi Leon,
here are some comments to your answers (your quotation is in italic):

> when calculating magnetising admittance, sn_hv_kva is used, and I think min(sn_hv_kva, sn_mv_kva)should be used !? (if I am not terribly wrong?)

I've found that in some ABB's technical documentation, even in some university slides, but I cannot find proof for that it in some really relevant source. I would say even scheme from PowerFactory's technical reference ([TechRef_3-W-Transformer.pdf](https://github.com/lthurner/pandapower/files/1269364/TechRef_3-W-Transformer.pdf)) for a 3winding transformers shows that `min(sn_hv_kva, sn_mv_kva)` eventually makes sense:
![image](https://user-images.githubusercontent.com/9588722/29942262-88770098-8e95-11e7-8107-1252370fede8.png)
but actually afterwards they explicitly say: 
*reference power in PowerFactory is equal to HV-side rated power*
So we can believe to PowerFactory and use `sn_hv_kva`


> result is not the same if one first transforms z12, z23, z13 to z1, z2, z3 and then calculates x1, x2, x3...than if one first calculates x12, x23, x13 and then transforms them to x1, x2, x3
*Why do you think this would be the right order, do you have a source for that?*

This can be shown mathematically (I will show example on x1):
so if you calculate first x12, x23 and x13 and then do wye-delta conversion to get x1 from x12, x23 and x13:
![image](https://user-images.githubusercontent.com/9588722/29943724-d9378c1e-8e9a-11e7-96b0-f0b3664604b5.png)
alternatively, if you first do wye-delta transformation on z and r, i.e. transform z12, z13 and z23 to z1, z2 and z3 and then calculate x1:
![image](https://user-images.githubusercontent.com/9588722/29943816-3eb09662-8e9b-11e7-8d93-dc0cab001a3f.png)
now if you compare first and second equation, and develop them you can see that:
![image](https://user-images.githubusercontent.com/9588722/29943846-5c60c894-8e9b-11e7-82a3-b4f26ec15adf.png)

the question remains: which method is correct?
I believe (I will try to find some relevant reference) the first because impedance should be considered in wye-delta conversion as a vector, not only amplitude (as considered in the second case)...so in the first case this equation holds:
![image](https://user-images.githubusercontent.com/9588722/29944586-4be42864-8e9e-11e7-8697-7caa6e3a09df.png)

> *The phase shift is not necessarily related to the tap changer, it is primarily related to the transformer vector group. The transformer can have a vector group so that the phase shifts of mv and lv side are different.*

Oh, it is only now clear to me that by `shift_degree` you thought on transformer vector group and clock hour number, and not on a phase-shifting transformer. This is quite a different thing, so only now I also understand why `calculate_voltage_angles` defaults to `False` for transmission...
So for proper consideration of a phase-shifting transformer additional parameter (such as *du* in powerFactory) should be added?
hereafter is PowerFactory technical reference for 2w transformer to see what I mean about tap of a phase shifting transformer: 
[TechRef_2-W-Transformer_3Phase.pdf](https://github.com/lthurner/pandapower/files/1269365/TechRef_2-W-Transformer_3Phase.pdf)

>  there is no need to define voltage level of the additional bus.
*Or do you mean we don't need it because the values are always in per unit and therefore we just assume 1.0 pu as initial voltage?*

Exactly, that's what I meant...no reason which voltage level is assigned to auxiliary bus, since it is used only internally and its p.u. value will always be 1 p.u. :)

> In general, I think we should base our validation on commercial software

I completely agree...I'll try to make the model to pass all the validation tests in regard to PowerFactory results...

Hi Jakov,

looks like we agree in most aspects 👍 The question of wye-delta transformation is still open, but if you can investigate both approaches it would be interesting to compare the results.

> So for proper consideration of a phase-shifting transformer additional parameter (such as du in powerFactory) should be added?

In the two winding transformer model there is a parameter "trafo.tp_st_degree" to model phase shifting transformer, but it has not been implemented for 3W transformers yet.
I removed the code that is currently unused. For now I am closing this issue since nobody currently seems to be working on this and there also wasn't any test data supplied for a case where this problem occurrs. @jkrstulo if you want to continue working on this, feel free to reopen the issue and recover the code from this commit!

Resolving patch:
diff --git a/pandapower/build_branch.py b/pandapower/build_branch.py
--- a/pandapower/build_branch.py
+++ b/pandapower/build_branch.py
@@ -443,8 +443,10 @@ def _trafo_df_from_trafo3w(net):
             kt = _transformer_correction_factor(vsc, vscr, sn, 1.1)
             vsc_2w_delta *= kt
             vscr_2w_delta *= kt
-        vsc_2w = wye_delta(vsc_2w_delta, sn)
+        vsci_2w_delta = np.sqrt( vsc_2w_delta ** 2 - vscr_2w_delta ** 2)
         vscr_2w = wye_delta(vscr_2w_delta, sn)
+        vsci_2w = wye_delta(vsci_2w_delta, sn)
+        vsc_2w = np.sign(vsci_2w) * np.sqrt(vsci_2w ** 2 + vscr_2w ** 2)
         taps = [dict((tv, np.nan) for tv in tap_variables) for _ in range(3)]
         for k in range(3):
             taps[k]["tp_side"] = None
@@ -888,4 +890,4 @@ def _transformer_correction_factor(vsc, vscr, sn, cmax):
 
 def get_is_lines(net):
     _is_elements = net["_is_elements"]
-    _is_elements["line"] = net["line"][net["line"]["in_service"].values.astype(bool)]
\ No newline at end of file
+    _is_elements["line"] = net["line"][net["line"]["in_service"].values.astype(bool)]


Test patch: