Skip to content

Conversation

furqan463
Copy link
Contributor

@furqan463 furqan463 commented Aug 24, 2025

Fixes #319
Fixes #321

Changes proposed in this PR include:

Extended "u1" and "u2" arrays from (n,) dimensions to (n,3) dimensions to remove value error.
multiplied phase loading percent with sqrt(3), (i * v / sqrt(3)) / (sn / 3) --> sqrt(3) * (i * v) / sn
divided total loading percent with sqrt(3) as v_ph = v / sqrt(3).

Electrical Mathematics:

Power per Phase = V_n * I_line_to_line # Basic Definition
Capacity per Phase = Sn / 3
Loading per Phase = Power per Phase / Capacity per Phase

ui = i_line_to_line * V_line_to_line
Loading per Phase = [ui / sqrt(3)] / [Sn / 3]
= [3 / sqrt(3)] * [ui] / [Sn]
= sqrt(3) * ui / Sn

Total Power = sum[Power_Phase_a, Power_Phase_b, Power_Phase_c]
= sum[ ui_a / sqrt(3), ui_b / sqrt(3), ui_c / sqrt(3)]
= [ sum(ui_a, ui_b, ui_c) / sqrt(3) ]
Total Loading = [sum(ui_a, ui_b, ui_c) / sqrt(3)] / Sn

Looking at it from another perspective which is more relevant in case of trafo_loading="current"
loading_per_phase = phase_current(line_to_line) / rated_current
rated_current (I_rated) = Sn / (sqrt(3) x V_line_to_line) #As for 3-Ph power system S = sqrt(3) * V * I
loading_per_phase = I_ph / I_rated
= I_ph / [Sn / (sqrt(3) x V_line_to_line)]
= sqrt(3) * [I_ph * V_line_to_line] / Sn

Checks before merge

  • Review the mathematics
  • Reproduce; verify that this fixes the issue
  • Code review
  • Add tests
  • Pass CI (Sonar Cloud may fail with HTML error code 403. That is not a problem with this PR)

In case of trafo_loading="current", a value error is generated while calculating "ui" from "i" and "u" because "i" is (n,3) array while "u" is (n,) array. fixed it by converted "u" to (n,3) array. Moreover, for phase wise loading, since "u" is line-to-line voltage, it needs to be converted to "line-to-ground" before multiplying, moreover to calculated loading percent, phase_power is to be divided by "sn_ph" instead of "sn" where "sn_ph" = "sn" / 3.

Signed-off-by: Engr. Ahmad Furqan <[email protected]>
fix/ PandaPower Transformer Loading
Copy link
Member

@mgovers mgovers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution @furqan463 ! We greatly appreciate you proposing the fix to the bug you found.

This is just a code review. Still TODO:

  • add some tests
  • review electrical engineering correctness
  • reproduce with a pandapower grid.

@mgovers mgovers added bug Something isn't working needs-unit-tests More unit tests are needed labels Aug 25, 2025
mgovers and others added 6 commits August 25, 2025 09:25
Signed-off-by: Martijn Govers <[email protected]>

Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>

Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
@nitbharambe
Copy link
Member

Nice spotting the bug!
For reference, as given in pandapower documentation:

image

As in their code:

https://github.com/e2nIEE/pandapower/blob/7b7ab33a8a9cc1b9802e168dfeea824eeb2ef266/pandapower/results_branch.py#L461-L465

The description and these two definitions are all different I suppose. (Atleast the naming is different :D) Makes it quite confusing.

Aligned with PandaPower code.

Signed-off-by: Engr. Ahmad Furqan <[email protected]>
@furqan463
Copy link
Contributor Author

@mgovers I've updated the description above elaborating mathematics involved. Moreover, thanks to @nitbharambe proposed changes match with existing code in PandaPower. I'm attaching a small code to reproduce the errors as well as testing the proposed changes. I'm trying to create unit tests, but while working on it, I've found some bugs with existing validation data.
pgm_test.py

@furqan463
Copy link
Contributor Author

@mgovers I've highlighted in relevant test code, why the unit test was not working for this function.
I'm trying to correct this unit test as well.

@mgovers mgovers changed the title Fix/ Pandapower 3-Ph transformer loading Calculation Pandapower converter: fix 3-Ph transformer loading Calculation Aug 26, 2025
@furqan463
Copy link
Contributor Author

@mgovers I've updated the validation unittest, now the test includes all components and since I loading pp_input to converter, all components are being converted and tested.
Now the for trafo_3ph, loading test will fail on original code for all 4 cases. However with amended code of pandapower_converter under trafo_loading=="current", loading for a & b phase will pass but for c and total will still fail.
Upon investigation I found out that the trafo loading data in validation files is for the case trafo_loading=="power", however, I found that the code for trafo_loading=="power" in pandapower_converter was also wrong, which now I corrected and amended unittest function to use trafo_loading="power", and now all test are passing.
However, for trafo_loading="current", we still need to generate validation data.

@furqan463 furqan463 force-pushed the main branch 2 times, most recently from cd0d3a7 to 73bf364 Compare August 26, 2025 16:16
furqan463 and others added 2 commits August 26, 2025 21:45
…and power and updating of validation tests

Signed-off-by: furqan463 <[email protected]>
…and power and updating of validation tests

DCO Remediation Commit for Engr. Ahmad Furqan <[email protected]>

I, Engr. Ahmad Furqan <[email protected]>, hereby add my Signed-off-by to this commit: 0e3f838
Signed-off-by: Engr. Ahmad Furqan <[email protected]>
@mgovers
Copy link
Member

mgovers commented Aug 27, 2025

Hi @furqan463,

Nice find again! I am thinking that maybe we can try to add your validation case as a validation case similar to

import pandapower as pp
import numpy as np
from math import sqrt


def create_net():
    net = pp.create_empty_network('test', f_hz=50)
    pp.create_bus(net, 11, 'source')
    pp.create_bus(net, 11, 'TF_HT')
    pp.create_bus(net, 0.4, 'TF_LT')

    pp.create_ext_grid(net, 0, 1.0, 0, s_sc_max_mva=100, rx_max = 0.1, x0x_max=1, r0x0_max=0.1)
    pp.create_line_from_parameters(net, 0, 1, 2, 0.33, 0.34,
                                0.001, 600, r0_ohm_per_km=0.66, x0_ohm_per_km=0.65, c0_nf_per_km=0.001,
                                g_us_per_km=0, g0_us_per_km=0)
    pp.create_transformer_from_parameters(net, 1,2, 1, 11, 0.415, 0,
                                        4, 0, 0.01, -30, vector_group='Dyn',
                                        vk0_percent=4, vkr0_percent=0, mag0_percent=100, mag0_rx=0, si0_hv_partial=0.9)
    pp.create_asymmetric_load(net, 2, 0.2, 0.19, 0.195,
                            0.05, 0.045, 0.035, 0, type='wye')
    return net


def check_result(net):
    v_hv = net.trafo.vn_hv_kv
    v_lv = net.trafo.vn_lv_kv
    i_max_hv = np.divide(net.trafo.sn_mva, v_hv* np.sqrt(3)) * 1e3
    i_max_lv = np.divide(net.trafo.sn_mva, v_lv* np.sqrt(3)) * 1e3


    i_a_hv = net.res_trafo_3ph.loc[:, 'i_a_hv_ka'] * 1000
    i_b_hv = net.res_trafo_3ph.loc[:, 'i_b_hv_ka'] * 1000
    i_c_hv = net.res_trafo_3ph.loc[:, 'i_c_hv_ka'] * 1000

    i_a_lv = net.res_trafo_3ph.loc[:, 'i_a_lv_ka'] * 1000
    i_b_lv = net.res_trafo_3ph.loc[:, 'i_b_lv_ka'] * 1000
    i_c_lv = net.res_trafo_3ph.loc[:, 'i_c_lv_ka'] * 1000

    np.testing.assert_allclose(np.maximum(i_a_hv / i_max_hv, i_a_lv / i_max_lv)*100, net.res_trafo_3ph.loading_a_percent)
    np.testing.assert_allclose(np.maximum(i_b_hv / i_max_hv, i_b_lv / i_max_lv)*100, net.res_trafo_3ph.loading_b_percent)
    np.testing.assert_allclose(np.maximum(i_c_hv / i_max_hv, i_c_lv / i_max_lv)*100, net.res_trafo_3ph.loading_c_percent)


def compare_result(actual, expected, *, rtol):
    np.testing.assert_allclose(actual.trafo.vn_hv_kv, expected.trafo.vn_hv_kv, rtol=rtol)
    np.testing.assert_allclose(actual.trafo.vn_lv_kv, expected.trafo.vn_lv_kv, rtol=rtol)
    np.testing.assert_allclose(actual.trafo.sn_mva, expected.trafo.sn_mva, rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loc[:, 'i_a_hv_ka'], expected.res_trafo_3ph.loc[:, 'i_a_hv_ka'], rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loc[:, 'i_b_hv_ka'], expected.res_trafo_3ph.loc[:, 'i_b_hv_ka'], rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loc[:, 'i_c_hv_ka'], expected.res_trafo_3ph.loc[:, 'i_c_hv_ka'], rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loc[:, 'i_a_lv_ka'], expected.res_trafo_3ph.loc[:, 'i_a_lv_ka'], rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loc[:, 'i_b_lv_ka'], expected.res_trafo_3ph.loc[:, 'i_b_lv_ka'], rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loc[:, 'i_c_lv_ka'], expected.res_trafo_3ph.loc[:, 'i_c_lv_ka'], rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loading_a_percent, expected.res_trafo_3ph.loading_a_percent, rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loading_b_percent, expected.res_trafo_3ph.loading_b_percent, rtol=rtol)
    np.testing.assert_allclose(actual.res_trafo_3ph.loading_c_percent, expected.res_trafo_3ph.loading_c_percent, rtol=rtol)


def test_pgm_pp_converter():
    pgm_net = create_net()
    pp_net = create_net()
    pp.runpp_pgm(pgm_net, symmetric=False)
    pp.runpp_3ph(pp_net)
    check_result(pgm_net)
    check_result(pp_net)
    compare_result(pgm_net, pp_net, rtol=0.04)


if __name__ == "__main__":
    test_pgm_pp_converter()

The current main has huge differences, while your branch passes, so your PR definitely solves the problem.

That said, I do still see some small differences between PGM and PP if I run that script (the compare_result step) of up to 4 percent (see the rtol), particularly in the b phase. However, this does not seem to be caused by the incorrect loading calculation, as the hand calculation seems to match for both calculation backends. Instead, the other result values seem to differ, but that could be caused by different local minima. I did not dig any further into this.

@mgovers
Copy link
Member

mgovers commented Aug 27, 2025

So far, it seems like you're solving the issues nicely, so I don't think my help is needed as of now. If you do need some input from me, I'm happy to help.

@mgovers
Copy link
Member

mgovers commented Sep 2, 2025

@furqan463 how is it going with the tests?

Since you found a bug and have already resolved it, I'm also OK with merging in its current state without extensive tests (after a minor clean-up). The tests can then be added as a follow-up. The reasoning behind that is that users can already use the PGM-IO with the bugfix.

What are your thoughts?

@furqan463
Copy link
Contributor Author

@mgovers agreed. I couldn't find time to finalise the tests, but agreed we can merge without tests, as the changes are broadly conceptual.

Signed-off-by: furqan463 <[email protected]>
@furqan463
Copy link
Contributor Author

Functions pp_trafo_output and pp_switch_output not being tested for the same reason as was for pp_trafo_output_3ph, the functions are returning from first if because pp_data is not passed to converter. These two functions are also appearing missed in coverage, resulting in coverage of only 89% for this file. Now trying to fix this.

… switch output, also corrected bugs in pp_trafo_output and pp_switch_output

Signed-off-by: furqan463 <[email protected]>
@furqan463
Copy link
Contributor Author

@mgovers I'm done now. There's one unittest failing that I'm not sure how to resolve. As I understand the test check exactly how we calculate "tan1" in pgm_input_line, but I changed the formula to avoid Nan values.

@mgovers
Copy link
Member

mgovers commented Sep 4, 2025

@mgovers I'm done now. There's one unittest failing that I'm not sure how to resolve. As I understand the test check exactly how we calculate "tan1" in pgm_input_line, but I changed the formula to avoid Nan values.

Awesome, @furqan463 , I'll have a look when i can 👍

Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
@mgovers mgovers removed the needs-unit-tests More unit tests are needed label Sep 4, 2025
@mgovers
Copy link
Member

mgovers commented Sep 5, 2025

@nitbharambe looks like this PR is now in a good-to-go state. Since I've also contributed significantly, can you please review?

@mgovers
Copy link
Member

mgovers commented Sep 5, 2025

OH apparently, CI is still failing; investigating.

Copy link
Member

@mgovers mgovers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

found the reason for the remaining validation tests.

To run the validation tests locally, please either use a test extension or run pytest tests/validation rather than just pytest, as the validation tests are excluded from pytest by default.

Signed-off-by: furqan463 <[email protected]>
Signed-off-by: furqan463 <[email protected]>
@furqan463
Copy link
Contributor Author

@mgovers please check now, I've updated the data file.
TODOs added for future.

@mgovers
Copy link
Member

mgovers commented Sep 6, 2025

@mgovers please check now, I've updated the data file. TODOs added for future.

Great! @nitbharambe and I will have a look on Monday.

  • concerning the license file for the json data, you can copy-paste one of the other files such that foo.json has a file foo.json.license. The .license files should be the same across the codebase.
  • please install the dev dependencies and run pre-commit run --all-files to run the formatter, linter and type checker. It will also run a check that checks whether you added the license file correctly.

@mgovers
Copy link
Member

mgovers commented Sep 9, 2025

@furqan463 We're doing final review. Please do not add new commits to this branch so that we can merge if everything is OK 👍

Copy link
Member

@nitbharambe nitbharambe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thanks for the contribution @furqan463!

@mgovers mgovers added this pull request to the merge queue Sep 9, 2025
Merged via the queue into PowerGridModel:main with commit 5437421 Sep 9, 2025
29 checks passed
@furqan463
Copy link
Contributor Author

Thanks a lot @mgovers for you kind support and hand-holding, as this was my first experience with open source contribution.
Thanks @nitbharambe for your support as well.

@mgovers
Copy link
Member

mgovers commented Sep 9, 2025

Anytime! Thank you very much for your contribution. You've been a great contributor. If you like, could you please share your experiences and maybe also any suggestions for improvements?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[IMPROVEMENT] Pandapower_convert gives NaN for tan1, the positive-sequence shunt loss factor [BUG] *Pandapower 3-Ph transformer loading Calculation*

3 participants