PowerGrids / PowerGrids

This repository contains the code for PowerGrids, a Modelica library for electro-mechanical modelling of power systems.
Mozilla Public License 2.0
37 stars 17 forks source link

Propagate UStart and UPhaseStart values from Bus to connected components #62

Closed AndreaBartolini closed 7 months ago

AndreaBartolini commented 1 year ago

In general the UStart value (default = UNom) and the UPhaseStart value (default = 0) should be set by the user in every component of the network based on the results of the initial power flow problem. This creates a redundancy because in case of connected components the UStart is the same for all of that. One possibility to solve this redundancy is to use buses to connect the components and to propagate the UStart value from the Bus to the components connected to it, by adding input/output variables to terminalAC. This has been partially discussed in the issue #49 (last 14 comments), the discussion is moved here because it is an extension of the original issue and the implementation of the solution is independent from the one necesary to close the #49.

casella commented 1 year ago

I made some further reflections on this topic. I agree with @ceraolo that the current configuration, in which you are asked values of UStart and UPhase for each component involved in a connection set, is unnecessarily redundant and potentially harmful, and it would be much better if one only had to provide that information on buses, even if that makes adding buses at all connection points compulsory. After all, power engineers are used at putting those buses there all the time anyway.

I actually see two ways of doing that. One is to make UStart and UPhaseStart final in all components except buses, binding them to some global default value, possibly set in the system object. In this way, UStart and UPhaseStart would show up only in the initialization menu of buses. The standard start attribute priority selection mechanism which is already in place in Modelica 3.5 would then guarantee that the values set in the buses are picked. This requires no changes in the connector definition.

However, this only works if the default final values for those start parameters in non-bus components are fixed once and for all in the library. If, e.g., they were parameters in the system object to define global default UStart and UPhaseStart, and they could be changed when instantiating the system object, then the binding equation for those defaults would have the same priority as the ones providing UStart modifiers in buses, so we'd be back to square one.

Also, this solution is a bit fragile, because one could forget to add the bus in some connection sets, and then the bus-less connected components model would get a very bad global default start attribute for voltage, possibly leading to initialization failure. However, the model would be legal and the compiler would issue no warnings of sort and compile it. This is not a recommendable outcome.

If we instead make buses compulsory, the problem is solved in a very robust way:

If we combine this design choice with what I proposed in #60, and with recent changes done by #66, then the connector design would become

type ReferenceAngularSpeed "Overconstrained type for frequency reference"
  extends SI.PerUnit;
  function equalityConstraint
    input ReferenceAngularSpeed omega1;
    input ReferenceAngularSpeed omega2;
    output SI.PerUnit residue[0];
  end equalityConstraint;
end ReferenceAngularSpeed; 

connector PowerTerminalACBase "Base class for all AC power connectors"
  Types.ComplexVoltage v "Phase-to-ground voltage phasor";
  flow Types.ComplexCurrent i "Line current phasor";
  ReferenceAngularSpeed omegaRef "Reference angular speed for phasors";
end PowerTerminalACBase;

connector PowerTerminalAC "Base class for non-bus AC power connectors"
  extends PowerTerminalACBase;
  input Types.ComplexVoltage UStart "Start value of phase-to-phase voltage";
  input Types.Angle UPhaseStart "Start value of phase-to-phase voltage angle";
end PowerTerminalAC;

connector PowerTerminalACBus "Base class for bus AC power connector"
  extends PowerTerminalACBase;
  output Types.ComplexVoltage UStart "Start value of phase-to-phase voltage";
  output Types.Angle UPhaseStart "Start value of phase-to-phase voltage angle";
end PowerTerminalACBus;

Buses would put their UStart and UPhaseStart parameter values on the power connector, and this would be received by all connected components to set their corresponding fixed = false UStart and UPhaseStart parameter values via initial equations.

Of course we would need to define OnePortAC base class, and a OnePortACBus base class, which differ from this point of view only.

The good news is that all this trickery will be confined to the OnePortAC, OnePortACBus and TwoPortAC classes. Users defining new components just need to extend from one of them, and simply add their model's specific equations. So, from the user's point of view, there's only the added benefit of not needing to worry about start values of voltages except in buses. The only drawback is that buses become compulsory, but since power engineers put them there all the time anyway, that's no big deal.

It goes without saying that PStart and QStart will always have to be provided in all components except buses (where they are structurally equal to zero). This involves some redundancy when only two components are connected through a bus, since their respected PStart and QStart values are the same, except for the sign. However, I see no simple way to avoid the need to provide them both.

AndreaBartolini commented 1 year ago

I agree with the proposed "robust" solution, that works independently from the "arcane priority rules" and from theirs implementation in the different tools (OpenModelica, Dymola and so on). The proposed robust solution probably solves also the issue #56, that again depends on the arcane priority rules (and theirs implementation).

casella commented 1 year ago

I agree with the proposed "robust" solution, that works independently from the "arcane priority rules" and from theirs implementation in the different tools (OpenModelica, Dymola and so on).

👍

The proposed robust solution probably solves also the issue #56, that again depends on the arcane priority rules (and theirs implementation).

Absolutely.

AndreaBartolini commented 1 year ago

The proposed solution generates the following error in OpenModelica (not in Dymola)

[1] 11:39:00 Translation Error
[C:/dev/OM64bit/OMCompiler/Compiler/NFFrontEnd/NFCeval.mo: 1126:9-1126:67]: Internal error NFCeval.evalBinaryDiv failed to evaluate ‘loadPQ.UStart / 1.732050807568877‘

It does not prevent the simulation to run, and the start values are propagated as expected.

AndreaBartolini commented 1 year ago

Regarding the EquivalentGrid, it is defined as a Bus:

model EquivalentGrid "Equivalent grid model characterized by short circuit capacity"
  extends PowerGrids.Electrical.Buses.BaseClasses.BusBase(
    e = eSource,
    Z = ZGrid,
    UStart = URef, UPhaseStart = 0);

that means that it will propagate its UStart and UPhaseStart values to the connected components via the BusBase class, therefore it replaces the Bus and cannot be connected to a Bus.

In my opinion this can be acceptable, the unique difference is in the Icon and this may confuses a bit the user.

The same is valid also for the Ground model, with the sole difference that it extends directly the Bus interface :

model Ground
  extends Icons.Ground;
  PowerGrids.Interfaces.TerminalACBus terminalAC(UStart = 0, UPhaseStart = 0) annotation(
    Placement(visible = true, transformation(origin = {-54, 48}, extent = {{-100, -100}, {100, 100}}, rotation = 0), iconTransformation(origin = {-3.55271e-15, 4.44089e-16}, extent = {{-8, -8}, {8, 8}}, rotation = 0)));
equation
  terminalAC.v = Complex(0);
end Ground;
AndreaBartolini commented 1 year ago

Here a possible change of the EquivalentGrid and Ground icons to better explain the concept to the user... immagine

AndreaBartolini commented 1 year ago

@max-privato @casella Since there are a lot of examples that use the EquvalentGrid and/or the Ground I'll wait for feedback before to modify them (the intermediate bus connected to the Grid or Ground shall be removed).

casella commented 1 year ago

I like the icons, but I'd have the ground symbol centered, even if this means you can only connect it "on one side". Alternatively, we could put the ground symbol on the right, rotated counter-clockwise by 90°

@ceraolo what do you think?

ceraolo commented 1 year ago

The symbol of equivalent grid should be square (not rectangular).

Regarding ground I'm confused: I've never seen any ground in PowerGrids examples, Is it really needed? AFAICU, using unifilar diagrams for balanced Power Systems could well be done without the need of any groud...

casella commented 1 year ago

I think it was just used to check that transmission lines worked as expected, by connecting them to a voltage source on one side and to ground on the other side. But we could as well use an infinite bus with voltage set to zero.

I think @ceraolo is right, we probably don't need the Ground component in this library.

@AndreaBartolini what do you think?

AndreaBartolini commented 1 year ago

Currently the ground component is used only in the TestEquivalentGrid scenario immagine Maybe the component is redundant but I don't see any problem in keeping it in the library.

But out of the icons... the critical point is if we want or not to consider the EquivalentGrid (and the ground) as bus, this means that for example the ENTSOE circuit: immagine works only by removing the NTHV bus, because now we cannoct connect two buses because both of them have output variables on the connector.

AndreaBartolini commented 1 year ago

For the same reason I've changed the IEEE14busShort4 by making replaceable the buses and by redeclaring the Bus4 as Fault type, while in the previous version the FaultBus was simply connected to the Bus4

casella commented 1 year ago

I'm a great fan of Ockham's razor, so I'm in favour of removing the Ground component and use the infinite bus with zero voltage as a replacement in the few tests where it is used.

Regarding the second question, the equivalent grid is conceptually similar to the InfiniteBus, even though it has a non-zero impedance, so it seems reasonable to me that it replaces NTHV in that example.

AndreaBartolini commented 1 year ago

It seems no possible to use an InfiniteBus to implement the equivalent ground. The following model immagine with UNom = 0 and Z=0 in the INF_BUS produces a division-by-zero error, probably due to the following equation inside the BusBase (used to implement the infinite bus)

v = e + Z*i;

where in our case:

e = CM.fromPolar(0, 0),
Z = Complex(0, 0));

and the division-by-zero is probably generated by solving the equation by i.

Probably this is the reason for that the ground component was introduced.

ceraolo commented 1 year ago

The concept of ground has a history of misunderstanding, even among expecienced electrical engineers. I've read (and often rejected) papers which confused the ground as a circuit element with the earth (where we put our feet on). Two grounds in a circuit have the same potential; two points on earth at the two ends of a transmission line have a difference of potential which is undefined!! If you try to measure it, you'll get different values for different positions of the measuring wire, because of the magnetic field in the loop you're creating.

A ground symbol in PowerGrids library would mean a different concept again: a point in which the potentials of the three conductors are made equal to each other. This will add further confusion to a topic already subject to misunderstanding. I would strongly recommend not to use a ground symbol for this. Possible choices:

AndreaBartolini commented 1 year ago

I agree with @ceraolo about the general confusion around the ground concept, so we have at least to change the name and symbol to the current Ground component in PowerGrids.

Coming back to the current Ground component in PowerGrids, as far as I understand the critical point is to use a Bus with an internal Z (like InfiniteBus or BusFault) by forcing Z=0 to reproduce what is done in the Ground component that simply do:

terminalAC.v = Complex(0);

This cannot be done (as far as I understood) for the reasons explained in https://github.com/PowerGrids/PowerGrids/issues/62#issuecomment-1589496936

AndreaBartolini commented 1 year ago

about the EquivalentGrid, we have another case to manage, currently present in the ENTSOE TestCase3: immagine

With the new approach it is no possible to connect two buses together (see https://github.com/PowerGrids/PowerGrids/issues/62#issuecomment-1588699089), therefore it is no possible to realise the fault as done in the Test 3 without insert an impedance between the EquivalentGrid and the BusFault.

The only way to reproduce a fault-to-ground @ the EquivalentGrid node is to build an EquivalentGridFault component or, alternatively, to say that the EquavalentGrid is not a Bus (i.e. does not propagate the UStart and UPhaseStart values to the connected components)

ceraolo commented 1 year ago

OpenIpSL does not have busFault components: just Fault components (like the fault at bus 4 in the following example). image

AndreaBartolini commented 1 year ago

Conceptually a FaultToGround component is identical to the BusFault component, the only difference is that the interface should be OnePortAC instead of OnePortACBus (the first receives the UStart and UPhaseStart values, the second propagates them).

In order to avoid code duplication there are two possible ways:

  1. to substitute the BusFault component in the library with a new FaultToGround component (not back-compatible solution)
  2. to add the FaultToGround component by keeping the BusFault component in the library (back-compatible solution). This can be done without code duplication by extending a common basic model that implements the impedance with the breaker (the current BusFault model) together with the right interface (double extension).

In any case we should add a new package to store the FaultToGround component, Faults could be name...

ceraolo commented 1 year ago

In any case I doubt about the name FaultToGround. AFAIK, PowerGrids simulates, outside machines, only the direct sequence components. In that case, it can only consider symmetrical faults (the three wires bonded together), for which the presence of ground is not relevant. It would just be a three-phase fault.

casella commented 1 year ago

I agree it's best to have a separate fault model, not integrated with a bus. This allows to add faults without the need to replace the bus, which is a "dummy" component, only used for connecting components together and to specify the initial guess of voltage at the connection point in a unique way.

AndreaBartolini commented 1 year ago

What about the problem with Ground component? https://github.com/PowerGrids/PowerGrids/issues/62#issuecomment-1589496936

casella commented 1 year ago

Regarding the ground, I guess there was a misunderstanding on our side, that we interpreted the phasor equation v = 0 as connection to ground rather than as short-circuiting the three phases together 😅. In fact, I understand our interpretation would still be correct assuming that the zero-phase voltage is always zero, but Ockham's razor here suggest to avoid interpretation.

BTW, assuming the system is balanced, there can't be any net flow into the ground - that would require a non-zero zero sequence current. The current flowing in one phase wire always returns through the other two. So, the interpretation as ThreePhaseShort is the correct one.

Bottom line: my recommendations

@ceraolo, are we on the same page?

ceraolo commented 1 year ago

That's exactly what I meant in my previous comments. I've been considering bus with fault misleading for months, but I did not give high prioririty to this and therefore did not open tickets. Now, that bus are given a more precise (and sound) meaning, this need is stronger. The fact that keeping bus with fault causes errors in OM is a luck, since sends us in the right direction... and I already said what I think about that ground component (whose very existence did not know up to yesterday)

casella commented 1 year ago

The proposed solution generates the following error in OpenModelica (not in Dymola)


[1] 11:39:00 Translation Error
[C:/dev/OM64bit/OMCompiler/Compiler/NFFrontEnd/NFCeval.mo: 1126:9-1126:67]: Internal error NFCeval.evalBinaryDiv failed to evaluate ‘loadPQ.UStart / 1.732050807568877‘

Problem solved, see OpenModelica/OpenModelica#10820.

AndreaBartolini commented 1 year ago

The last run of the library continuous integration has shown a lot of simulation errors caused by old assignements of UStart and UPhaseStart parameters inside components. By removing them the simulation now runs properly.

With the new propagation of said parameters from the buses to the components the user shall define them only in buses, so I made final them inside the OnePortAC and TwoPortAC base classes.

This approach may cause some problems because OpenModelica sometimes add the displayUnit modifier to some parameters when parameters are modified from the parameter window, but I hope that this never happens for parameters declared as final

casella commented 1 year ago

This approach may cause some problems because OpenModelica sometimes add the displayUnit modifier to some parameters when parameters are modified from the parameter window, but I hope that this never happens for parameters declared as final

I think so. In case there are issues, Adeel will fix them in August.

AndreaBartolini commented 1 year ago

solved by PRs #86, #87 and #88

casella commented 7 months ago

@ceraolo, while checking the library with Dymola we realized that the whole design of this feature was fundamentally flawed.

The structure of the base classes we proposed was such that both OnePortAC and OnePortACBus were children of the same base classe OnePortACBase. In order to avoid code duplication, we sometimes define "naked" (VI) models, and then upgrade them to either power-flow or dynamic model by, among other things, redeclaring their connectors. However, we just found out that this was not really legal, because redeclare is only allowed with plug-compatible sub-classes, i.e. extended classes for which the additional parts of the interface can be default-connected, see the Modelica Language Specification Section 6.5.

Unfortunately, this was not the case, because OnePortAC had two additional inputs with respect to OnePortACBase, which cannot be default-connected.

The first main issue is that this is not legal Modelica. At the moment OpenModelica does not detect this issue and accepts the corresponding code, but Dymola actually does, and rejects the code. In the future, OpenModelica will also do so, as we add more stringent checks on these language aspects.

The second issue (which is in some sense a consequence of violating plug-compatibility) is that the components were not really safe from the point of view of system balancedness - if you forgot to put a bus in any connection set, there would have been two missing equations for the UStart and UPhaseStart inputs.

Bottom line, we had to get rid of this feature, and re-instate UStart, UPhaseStart, PStart, and QStart at each component ports. However, we think we were able to fulfil your end-user requirements anyway.

First of all, if you activate the embedded power flow, there is no need to input any start values for any components, since all start values are automatically obtained from the embedded power flow. This is made clear to the end user by disabling the input fields for all the XXStart parameters.

When you don't use the embedded power flow, we have solved the issue of avoiding the possibility of inputting inconsistent values (e.g. different values of UStart for ports connected together) by a pragmatic observation. As we proved in Bachmann and Casella 2021, the convergence of the Newton iterations is not affected by the initial guesses for all variables only appearing linearly in the problem. Now, in most connection sets you have one nonlinear component (e.g. a synchronous machine or a PQ load) and other linear components, e.g. transmission lines or transformers. For the latter ones, there is no need to input any start values at all. So, in practice, you will only have to input the start values for just one component in the connection set.

We then added one final parameter isLinear to each component of the library, which is set by the modeller writing the component, and states whether the model is linear or not. If it isn't, then the input fields of all the XXXStart parameters are disabled, so it is clear you don't need to worry about inputting any values in there.

So, at the end of the day, if you use the GUI you will always have a clear indication of which start value parameters you actually need to input: the ones whose input fields are enabled; all the other ones will be disabled. The good news is that this GUI feature is now fully functional also in OpenModelica, while it wasn't when we rolled out version 1.0.0 a few years ago.