In standard Modelica fluid flow sources, normally either the flow rate or the pressure is specified. For example, the following boundary setups (P meaning pressure boundary, F meaning flow boundary) would typically surround a pipe component:
P - Pipe - P
F - Pipe - P
However, sometimes it can be convenient/desirable to specify both the flow rate and the pressure on the same side and let the other side be determined:
(P, F) - Pipe - ()
In my experience, this works just fine in Modelica tools if you create these sources and solve them at the system level. The issue is that, since the (P, F) component is locally overdetermined (+1 equation) and the () component is locally underdetermined (-1 equation), those components throw check errors locally since Modelica tools assume you always want locally balanced components. With this in mind, are there any best practices for creating overdetermined/underdetermined components in Modelica for this scenario? At the very least to tell the tool that this is intentional/don't throw check errors?
In Dymola it will work, but for bad models and check of classes it can cause confusing diagnostics. They can be avoided by using:
annotation (defaultConnectionStructurallyInconsistent=true)
(Inside those two models.)
Technically this is a bit extended meaning compared to the standard, https://specification.modelica.org/master/annotations.html#annotations-for-the-graphical-user-interface but it will work.
Related
Modelica modeling is the first principle modeling, so how to test the model and set an effective benchmark is important, for example, I could design a fluid network as my wish, but when building a dynamic simulation model, I need to know the detailed geometry structure and parameters to set up every piece of my model. Usually, I would build a steady-state model with simple energy and mass conservation laws, then design every piece of equipment based on the corresponding design manual, but when I put every dynamic component together, when simulation till steady-state, the result is different from the steady-state model more or less. So I was wondering if I should modify my workflow to make the dynamic model agree with the steady-state model. Any suggestions are welcome.
#dymola #modelica
To my understanding of the question, your parameter values are fixed and physically known. I would attempt the following approach as a heuristic to identify the (few) component(s) that one needs to carefully investigate in order to understand how they influence or violates the assumed first principles.
This is just as a first trial and it could be subject to further improvement and fine-tuning.
Consider the set of significant set of variables xd(p,t) \in R^n and parameters p. Note that p also includes significant start values. p in R^m includes only the set of additional parameters not available in the steady state model.
Denote the corresponding variables of the steady state model by x_s
Denote a time point where the dynamic model is "numerically" in "semi-" steady-state by t*
Consider the function C(xd(p,t*),xs) = ||D||^2 with D = xd(p,t*) - xs
It could be beneficial to describe C as a vector rather than a single valued function.
Compute the partial derivatives of C w.t. p expressed in terms of dxd/dp, i.e.
dC/dp = d[D^T D]/dp
= d[(x_d-x_s)^T (x_d - x_s)]/dp
= (dx_d/dp)^T D + ...
Consider scaling the above function, i.e. dC/dp * p/C (avoid expected numerical issues via some epsilon-tricks)
Here you get a ranking of most significant parameters which are causing the apparent differences. The hopefully few number of components including these parameters could be the ones causing such violation.
If this still does not help, may be due to expected high correlation among parameters, I would go further and consider a dummy parameter identification problem, out of which a more rigorous ranking of significant model parameters can be obtained.
If the Modelica language had capabilities for expressing dynamic parameter sensitivities, all the above computation can be easily carried out as a single Modelica model (with a slightly modified formulation).
For instance, if we had something like der(x,p) corresponding to dx/dp, one could simply state
dcdp = der(C,p)
An alternative approach is proposed via the DerXP library
In the Thermal Power Library from Modelon, there are two kinds of connectors: flow connector and volume connector.
Based on the tutorial shipped with the library, these two kinds of connectors should NOT be connected with the same kind of connector.
But I checked their code, it seems the codes are the same.
I checked the code in the ThermoSysPro library from EDF and ThermoPower library, too. They also use two kinds of connectors, and the recommendation of connecting principle is also the same.
So I read the code of “MixVolume” and “SteamTurbineStodola”, which include volume connectors and flow connectors respectively, but I am not sure the difference between these two kinds of connectors.
My question is :
Could someone tell me the philosophy of using such two kinds of connectors in thermo-hydraulic systems, and in the code of every component, how should I deal with them so they work like they’re designed for.
Here is a very short and simplified explanation applying to thermo-hydraulic systems.
In flow models (pipes, valves etc.) enthalpy is unchanged and mass flow/pressure drop are related with a static equation.
In volume models pressure and enthalpy are dynamic state variables, that is, mass and energy conservation is "elastic".
As a rule of thumb, you should build thermo-hydraulic system models of alternating flow and volume models (in a staggered grid scheme) to decouple nonlinear systems.
For the dynamic pipe model in the top figure in your post the connectors merely indicate that, internally, the pipe model begins with a volume model and ends with a flow model.
Claytex has a nice blog post on the subject here https://www.claytex.com/blog/how-to-avoid-computationally-expensive-fluid-networks-in-dymola/
Also the authors of the Modelica Buildings Library have done a great effort explaining this in various papers. See e.g. https://buildings.lbl.gov/publications/simulation-speed-analysis-and
These kind of connectors are indeed the same due to modelica language specification. You can only connect two connectors that are interchangeable, that have the exact same amount and type of flow and potential variables. At every node all flows have to sum up to zero and all potentials have to be the same, therefore they have to be type consistent.
The difference is just information wise for the modeler or someone trying to understand the model and all components have been designed with such a thing in mind. It is easiest to understand with electrical components, where you have positive and negative pins which indicate in which direction the current should flow, but this is actually never really forced. Positive and negative pins are, ignoring their name, identical.
Although i don't know the connectors you are talking about i would assume that the VolumePort is a connector of something that has a volume and passes that information, whereas FlowPort passes the information about the mass flow rate. Usually a pipe i guess (?). Broken down to abstract dae theory one could say the names indicate if the potential or the flow variable are considered unknown for the component.
I have to emphasize that these are only indicators and that it is never actually forced by the model or the compiler. It is just how it should logically resolve in the end if you respect these restrictions of only connecting VolumePortto FlowPort connectors.
I wonder if there a way to "debug" a modelica code, I mean debugging the code line by line and you can see how variables change, things like that?
I know that the modelica code is translated into C, I just want to know if there's a possibility to do that somehow, if there is, I believe it's gonna be a great improvement for any of the simulation environments. Thanks.
HY
This is a good question and it comes up a lot. But first, let's step back for a second.
The idea of debugging "line by line" is something comes from imperative programming languages. By "imperative" I mean that a program is simply a sequence of instructions to be carried out in the specified order.
When someone debugs Java or Python, this "line by line" approach makes sense because the statements are the fundamental way behavior is represented. This "line by line" approach could also be extended to modeling formalisms like block diagrams (e.g. Simulink) because, while graphical, they are also imperative (i.e. they constitute steps to be carried out in a specified order).
But Modelica is not an imperative language. There is no notion of steps, statements or instructions. Instead, we have omnipresent equations. So thinking linearly about debugging doesn't work in Modelica. It is true that you could think about debugging the C code generated from Modelica, but that is typically not very useful because it bears only a partial resemblance to the equations.
So how do you debug Modelica code? Well, debugging Modelica code is really debugging Modelica equations. Normally, Modelica models are composed of components. The equations that are generated when components are connected are automatically generated so lets stipulate that the Modelica compiler generates those correctly. So what's left is the equations in the component models.
The simplest way to approach this is to test each component individually (or at least in the smallest possible models). I often say that trying to debug Modelica components by throwing them all together in a big model is like listening to an orchestra and trying to figure out the one instrument that is out of tune. The fact that these equations in Modelica tend to form simultaneous systems of equations means that errors, when they occur, can propagate immediately to a number of variables.
So your best bet is to go through and create tests for each individual component and verify the behavior of the component. My experience is that when you do this, you can track down and eliminate bugs pretty easily.
Update: You shouldn't need to add outputs to other people's component models to debug them. An output can be created at any level, e.g.
model SystemModel
SomeoneElsesComponent a;
SomeOtherGuysComponent b;
end SystemModel;
model SystemModel_Debug
extends SystemModel;
output Real someNestedSignalFromA = a.someSubsystem.someSubcomponent.someSignal;
output Real someOtherNestedSignalFromB = b.anotherSubsystem.anotherSignal;
end SystemModel_Debug;
Of course, this becomes impractical if you have multiple instantiations of a signal component. In those cases, I admit that it is easier to modify the underlying model. But if they make their models replaceable, you can use the same trick as above (extends their model, add a bunch of custom outputs and then redeclare your model in place of the original).
There is a transformation debugger in OpenModelica now. You can find here which variable is evaluated from which equation.
In the known paper Impossibility of Distributed Consensus with one Faulty Process (JACM85), FLP (Fisher, Lynch and Paterson) proved the surprising result that no completely asynchronous consensus protocol can tolerate even a single unannounced process death.
In Lemma 3, after showing that D contains both 0-valent and 1-valent configurations, it says:
Call two configurations neighbors if one results from the other in a single step. By an easy induction, there exist neighbors C₀, C₁ ∈ C such that Dᵢ = e(Cᵢ) is i-valent, i = 0, 1.
I can follow the whole proof except when they claim the existence of such C₀ and C₁. Could you please give me some hints?
D (the set of possible configurations after applying e to elements of C) contains both 0-valent and 1-valent configurations (and is assumed to contain no bivalent configurations).
That is — e maps every element in C to either a 0-valent or a 1-valent configuration. By definition of C, there must be a root element that is connected to all other elements by a series of "neighbour" relationships, so there must be a boundary point where an element in C that leads to a 0-valent configuration after e is neighbours with an element in C that leads to a 1-valent configuration after e.
I once went down the path of reading all these papers only to discover its a complete waste of time.
The result is not surprising at all.
The paper you mention "[Impossibility of Distributed Consensus with One Faulty
Process]" 1
is a long list of complex mathematical proofs that simply equate to:
1) Consensus is a deterministic state
2) one (or more) faulty systems within an environment is a non deterministic environment
3) No deterministic state, action or outcome can ever be reached within a non deterministic environment.
The end. No further thought is required.
This is how it works in the real world outside of acadamia.
If you wish for agents to reach consensus then Synchronous (Timing model) approximation constructs have to be added to make the environment deterministic within a given set of constraints. For example simple constructs like Timeouts, Ack/Nack, Handshake, Witness, or way more complex constructs.
The closer you wish to get to a Synchronous deterministic model the more complex the constructs become. A hypothetical Synchronous model would have infinitely complex constructs. Also bearing in mind that a fully deterministic Synchronous model can never be achieved in a non trivial distributed system. This is because in any non trivial dynamic multi variate system with a variable initial state there exists an infinite number of possible states, actions and outcomes at any point in time. Chaos Theory
Consider the complexity of a construct for detecting a dropped TCP packets because of buffer overflow errors in a router at hop number 21. And the complexity of detecting the same buffer overflow error dropping the detection signal from the construct itself.
Define a mapping f such that f(C) = 0, if e(C) is 0-valent, otherwise, f(C) = 1, if e(C) is 1-valent.
Because e(C) could not be bivalent, if we assume that D has no bivalent configuration, f(C) could only be either 0 or 1.
Arrange accessible configurations from the initial bivalent configuration in a tree, there must be two neighbors C0, C1 in the tree that f(C0) != f(C1). Because, if not, all f(C) are the same, which means that D has only either all 0-valent configurations or all 1-valent configurations.
I am looking at refactoring some very complex code which is a subsystem of a project I have at work. Part of my examination of this code is that it is incredibly complex, and contains a lot of inputs, intermediate values and outputs depending on some core business logic.
I want to redesign this code to be easier to maintain as well as executing a hell of a lot faster, so to start off with I have been trying to look at each of the parameters and their dependencies on each other. This has lead to quite a large and tangled graph and I would like a mechanism for simplifying this graph.
A while back I came across a technique in a book about SOA design called "Matrix Design Decomposition" which uses a matrix of outputs and the dependencies they have on the inputs, applies some form of matrix algebra and can generate Business Process diagrams for those dependencies.
I know there is a web tool available at http://www.designdecomposition.com/ however it is limited in the number of input/output dependencies you can have. I have tried looking around for the algorithmic source for this tool (so I could attempt to implement it myself without the size limitation), however I have had no luck.
Does anybody know a similar technique that I could use? Currently I am even considering taking the dependency matrix and applying some Genetic Algorithms to see if evolution can come up with a simpler workflow...
Cheers,
Aidos
EDIT:
I will explain the motivation:
The original code was written for a system which computed all of the values (about 60) every time the user performed an operation (adding, removing or modifying certain properties of a item). This code was written over ten years ago and is definitely showing signs of age - others have added more complex calculations into the system and now we are getting completely unreasonable performance (up to 2 minutes before control is returned to the user). It has been decided to detach the calculations from the user actions and provide a button to "recalculate" the values.
My problem arises because there are so many calculations that are going on and they are based on the assumption that all of the required data will be available for their computation - now when I try to re-implement the calculations I keep encountering problems because I haven't got the result for a different calculation that this calculation relies on.
This is where I want to use the matrix-decomposition approach. The MD approach allows me to specify all of the inputs and outputs and gives me the "simplest" workflow that I can use for generating all of the outputs.
I can then use this "workflow" to know the precedence of the calculations I need to perform to get the same result without generating any exceptions. It also shows me which parts of the calculation system I can parallelise and where the fork and join points will be (I won't worry about that part just yet). At the moment all I have is an insanely large matrix with lots of dependencies showing in it, with no idea where to start.
I will elaborate from my comment a little more:
I don't want to use the solution from the EA process in the actual program. I want to take the dependency matrix and decompose it into modules that I will then code manually - this is purely a design aid - I am just interested in what the inputs/outputs for these modules will be. Basically a representation of the complex interdependencies between these calculations, as well as some idea of precedence.
Say I have A requires B and C. D requires A and E. F requires B, A and E, I want to effectively partition the problem space from a complex set of dependencies into a "workflow" that I can examine to get a better understanding. Once I have this understanding I can come up with a better design / implementation that is still human readable, so for the example I know I need to calculate A, then C, then D, then F.
--
I know this seems kind of strange, if you take a look at the website I linked to before the matrix based decomposition there should give you some understanding of what I am thinking of...
kquinn, If it's the piece of code I think he's referring to (I used to work there), it's already a black box solution that no human can understand as is. He's not looking to make it more complicated, less in fact. What he's trying to achieve is a whole heap of interlinked calculations.
What currently happens, is that whenever anything changes, it's an avalanche of events which cause a whole bunch of calculations to fire off, which in turn causes a whole bunch more events which continues on until finally it reaches a state of equilibrium.
What I assume he wants to do is find the dependencies for those outlying calculations and work in from there so they can be rewritten and find a way for the calculations from happening for the sake of it, rather than because they need to.
I can't offer much advice in regards to simplifying the graph, as unfortunately it's not something I have much experience in. That said, I would start looking for those outlying calculations which have no dependencies, and just traverse the graph from there. Start building up a new framework that includes the core business logic of each calculation in the simplest possible way, and refactor the crap out of it along the way.
If this is, as you say, "core business logic", then you really don't want to be screwing around with fancy decompositions and evolutionary algorithms that produce a "black box" solution that no one in the world understands or is capable of modifying. I would be very surprised if any of these techniques actually yielded any useful result; the human brain is still incomprehensibly more capable than any machine at untangling complicated relationships.
What you want to do is traditional refactoring: clean up the individual procedures, streamlining them and merging them where possible. Your goal is to make the code clear, so your successor doesn't have to go through the same process.
What language are you using?
Your problem should be pretty easy to model using Java Executors and Future<> tasks, but a similar framework is perhaps availabe on your chosen platform as well?
Also, if I understand this correctly, you want to generate a critical path for a large set of interdependent calculations -- is that something done dynamically, or do you "just" need a static analysis?
Regarding an algorithmic solution; pick up the closest copy of your numerical analysis textbook and refresh your memory on singular value decompositions and LU factorization; I'm guessing from the top off my head that this is what lies behind the tool you linked to.
EDIT: Since you're using Java, I'll give a brief outline of a suggestion proposal:
-> Use a threadpool executor to parallellize all calculations easily
-> Solve interdependencies with an object map of Future<> or FutureTask<>:s, i.e. if you variables are A, B and C, where A = B + C, do something like this:
static final Map<String, FutureTask<Integer>> mapping = ...
static final ThreadPoolExecutor threadpool = ...
FutureTask<Integer> a = new FutureTask<Integer>(new Callable<Integer>() {
public Integer call() {
Integer b = mapping.get("B").get();
Integer c = mapping.get("C").get();
return b + c;
}
}
);
FutureTask<Integer> b = new FutureTask<Integer>(...);
FutureTask<Integer> c = new FutureTask<Integer>(...);
map.put("A", a);
map.put("B", a);
map.put("C", a);
for ( FutureTask<Integer> task : map.values() )
threadpool.execute(task);
Now, if I'm not totally off (and I may very well be, it was a while since I worked in Java), you should be able to solve the apparent deadlock problem by tuning the thread pool size, or use a growing thread pool. (You still have to make sure that there are no interdependent tasks though, such as if A = B + C, and B = A + 1...)
If the black-box is linear you can discover all the coefficients by simply concatenating many vectors of input and many vectors of output.
you have input x[i] and output y[i], then you create a matrix Y whose columns are y[0], y[1], ... y[n], and a matrix X whose columns are x[0], x[1], ..., x[n]. There will be a transformation Y = T * X, then you may determine T = Y * inverse(X).
But since you said it is complex I bet it is not linear. Then if you still want a general framework you can use this a factor-graph
https://ieeexplore.ieee.org/document/910572
I would be curious if you can do this.
What I think is easier is to understand the code and rewrite it using the best practices.