modelica / ModelicaStandardLibrary

Free (standard conforming) library to model mechanical (1D/3D), electrical (analog, digital, machines), magnetic, thermal, fluid, control systems and hierarchical state machines. Also numerical functions and functions for strings, files and streams are included.
https://doc.modelica.org
BSD 3-Clause "New" or "Revised" License
466 stars 166 forks source link

SweptVolume should have two Translational Flanges #3883

Open jonas-hagen opened 2 years ago

jonas-hagen commented 2 years ago

The current Modelica.Fluid.Machines.SweptVolume has a single Flange_b and an arrow, but is missing a Flange_a.

I tried to make a model where one SweptVolume drives another one, such that they act against each another (think along the lines of der(SweptVolume1.V) = - der(SweptVolume2.V)). This seemed not to be possible with the one-flanged Modelica.Fluid.Machines.SweptVolume and I just could not interpret the meaning of the arrow in this context.

I came up with the following Model, which extends Modelica.Mechanics.Translational.Interfaces.PartialCompliant and thus has two flanges and an arrow. This solved my problem (see image below) and in my opinion makes it much easier to understand the arrow and combine this element with other Translational models.

Here is my alternative swept volume:

model SweptVolumeAlternative
  "Varying cylindric volume depending on the position of the piston"
  extends Modelica.Mechanics.Translational.Interfaces.PartialCompliant;
  import Modelica.Constants.pi;
  import SI = Modelica.Units.SI;

  parameter SI.Area pistonCrossArea "Cross sectional area of piston";
  parameter SI.Volume clearance "Remaining volume at zero piston stroke";

  SI.Volume V "Fluid volume";

  // Mass and energy balance, ports
  extends Modelica.Fluid.Vessels.BaseClasses.PartialLumpedVessel(
    final fluidVolume = V,
    heatTransfer(surfaceAreas={pistonCrossArea+2*sqrt(pistonCrossArea*pi)*(s_rel+clearance/pistonCrossArea)}));

equation
  assert(s_rel >= 0, "Piston stroke (given by s_rel) must not be smaller than zero!");

  // volume size
  V = clearance + s_rel * pistonCrossArea;

  0 = f + (medium.p - system.p_ambient) * pistonCrossArea;

  // energy balances
  Wb_flow = medium.p * pistonCrossArea * (-der(s_rel));

  // definition of port pressures
  for i in 1:nPorts loop
    vessel_ps_static[i] = medium.p;
  end for;

  annotation (
    Icon(graphics = {Polygon(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Backward, points = {{-52, 62}, {-48, 62}, {-48, -30}, {-52, -30}, {-52, 62}}), Line(visible = false, points = {{-100, 0}, {-52, 0}}, color = {198, 0, 0}), Polygon(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Backward, points = {{-48, -90}, {48, -90}, {48, 70}, {52, 70}, {52, -94}, {-52, -94}, {-52, 70}, {-48, 70}, {-48, -90}}), Rectangle(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Forward, extent = {{-48, 40}, {48, 30}}), Polygon(origin = {70, 14}, lineColor = {95, 127, 95}, fillColor = {95, 127, 95}, fillPattern = FillPattern.Solid, points = {{15, 0}, {-15, 10}, {-15, -10}, {15, 0}}), Polygon(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Backward, points = {{48, 60}, {52, 60}, {52, -34}, {48, -34}, {48, 60}}), Rectangle(lineColor = {0, 0, 255}, fillColor = {170, 213, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-50, 36}, {50, -90}}), Text(lineColor = {0, 0, 255}, extent = {{-150, 110}, {150, 150}}, textString = "%name"), Rectangle(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Forward, extent = {{-6, 92}, {6, 40}}), Line(origin = {-26.7511, 10.9537}, points = {{-40, 2}, {86, 2}}, color = {95, 127, 95})}));

end SweptVolumeAlternative;

If anyone happens to know how to deal with the overlapping HeatPort_a and Flange_a on the left side of the Icon, please leave a comment!

Bildschirmfoto vom 2021-10-22 12-21-44

What are your thoughts on that? Any chance that something like that could be included in the MSL?

casella commented 2 years ago

@jonas-hagen, could you just define a mechanical translational component with equations:

model Adaptor
  extends Modelica.Mechanics.Rotational.Interfaces.PartialTwoFlanges;
equation
  flange_a.s + flange_b.s = c;
  flange_a.f = flange_b.f;
end Adaptor;

and then use it to connect two SweptVolume models?

sergniko commented 2 years ago

If anyone happens to know how to deal with the overlapping HeatPort_a and Flange_a on the left side of the Icon, please leave a comment!

Faced same issue then tried to do the same - for some reason I was unable to reposition HeatPort_a. Inheritance on slides - it was easy :) But in reality - not.

sergniko commented 2 years ago

@jonas-hagen, could you just define a mechanical translational component with equations:

model Adaptor
  extends Modelica.Mechanics.Rotational.Interfaces.PartialTwoFlanges;
equation
  flange_a.s + flange_b.s = c;
  flange_a.f = flange_b.f;
end Adaptor;

and then use it to connect two SweptVolume models?

I getting error: [1] 19:46:35 Translation Error [Adaptor: 4:3-4:30]: Variable c not found in scope Adaptor.

casella commented 2 years ago

@sergniko, @jonas-hagen, the idea of O-O modelling is to break down the functionality into modules that can be connected - this allows to keep the number of basic models low, avoiding combinatorial explosion of the number of model variants.

The SweptVolume model describes the coupling between the thermo-fluid domain and the 1D mechanical domain. There is one volume and one piston with one position coordinate and one total force applied to it by the fluid force. If you need more flexibility on the mechanical side, there's no need to develop another fluid model, just write a very simple mechanical one that does what you need.

Unless you need a model with two pistons, one on either side - that would be another story.

sergniko commented 2 years ago

Unless you need a model with two pistons, one on either side - that would be another story.

We need one volume - two flanges. SweptVolume in it current release can't be used to make hydraulic cylinder model - i think replacing it with same model but with two flanges is better. You can always combine it with fixed translational component to get current SweptVolume but without negative coordinate restriction.

jonas-hagen commented 2 years ago

The SweptVolume model describes the coupling between the thermo-fluid domain and the 1D mechanical domain. There is one volume and one piston with one position coordinate and one total force applied to it by the fluid force.

@casella For me, a piston consists of two parts that are pushed apart. They move relative to each another when a force is applied between them. This concept is captured by PartialCompliant. The relevant 1D coordinate is the relative distance between the piston and its housing because it defines the volume.

the idea of O-O modelling is to break down the functionality into modules

I see your point. It is just not always very clearly obvious what these modules should be and there is no right and wrong. I think my suggestion adds value and does not only solve a single problem.

You can always combine it with fixed translational component to get current SweptVolume but without negative coordinate restriction.

That is what I thought first too. But I was unable to produce the model I described above in any way. Maybe you could provide an example of an Adaptor-thing, so that I can understand better how that would look like?

Edit: I will try your example Adaptor that you posted! Sorry, I overlooked it at first.

beutlich commented 2 years ago

If anyone happens to know how to deal with the overlapping HeatPort_a and Flange_a on the left side of the Icon, please leave a comment!

It is possible to move/scale the inherited icon or diagram using the IconMap and DiagramMap annotation of the extends clause. Here is my attempt. I applied it to the mechanical flanges rather than the heat and fluid port.

model SweptVolumeAlternative
  "Varying cylindric volume depending on the position of the piston"
  extends Modelica.Mechanics.Translational.Interfaces.PartialCompliant annotation (
    IconMap(extent = {{-100, -50}, {100, 150}}),
    DiagramMap(extent = {{-100, -50}, {100, 150}}));
  import Modelica.Constants.pi;
  import Modelica.Units.SI;

  parameter SI.Area pistonCrossArea "Cross sectional area of piston";
  parameter SI.Volume clearance "Remaining volume at zero piston stroke";

  SI.Volume V "Fluid volume";

  // Mass and energy balance, ports
  extends Modelica.Fluid.Vessels.BaseClasses.PartialLumpedVessel(
    final fluidVolume = V,
    heatTransfer(surfaceAreas={pistonCrossArea+2*sqrt(pistonCrossArea*pi)*(s_rel+clearance/pistonCrossArea)}));

equation 
  assert(s_rel >= 0, "Piston stroke (given by s_rel) must not be smaller than zero!");

  // volume size
  V = clearance + s_rel * pistonCrossArea;

  0 = f + (medium.p - system.p_ambient) * pistonCrossArea;

  // energy balances
  Wb_flow = medium.p * pistonCrossArea * (-der(s_rel));

  // definition of port pressures
  for i in 1:nPorts loop
    vessel_ps_static[i] = medium.p;
  end for;

  annotation (
    Icon(graphics={  Polygon(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Backward, points = {{-52, 62}, {-48, 62}, {-48, -30}, {-52, -30}, {-52, 62}}), Line(visible = false, points = {{-100, 0}, {-52, 0}}, color = {198, 0, 0}), Polygon(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Backward, points = {{-48, -90}, {48, -90}, {48, 70}, {52, 70}, {52, -94}, {-52, -94}, {-52, 70}, {-48, 70}, {-48, -90}}), Rectangle(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Forward, extent = {{-48, 40}, {48, 30}}), Polygon(origin = {70, 14}, lineColor = {95, 127, 95}, fillColor = {95, 127, 95}, fillPattern = FillPattern.Solid, points = {{15, 0}, {-15, 10}, {-15, -10}, {15, 0}}), Polygon(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Backward, points = {{48, 60}, {52, 60}, {52, -34}, {48, -34}, {48, 60}}), Rectangle(lineColor = {0, 0, 255}, fillColor = {170, 213, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-50, 36}, {50, -90}}), Text(lineColor = {0, 0, 255}, extent = {{-150, 110}, {150, 150}}, textString = "%name"), Rectangle(lineColor = {95, 95, 95}, fillColor = {135, 135, 135}, fillPattern = FillPattern.Forward, extent = {{-6, 92}, {6, 40}}), Line(origin = {-26.7511, 10.9537}, points = {{-40, 2}, {86, 2}}, color = {95, 127, 95})}));

end SweptVolumeAlternative;
sergniko commented 2 years ago

@jonas-hagen, you can create model similar to this: cyl

As for me it looks like one volume two flange, but it volume is depends on absolute position not relative - because SweptVolume fluid volume is always relative to s=0.

sergniko commented 2 years ago

It is possible to move/scale the inherited icon or diagram using the IconMap and DiagramMap annotation of the extends clause. Here is my attempt. I applied it to the mechanical flanges rather than the heat and fluid port.

in my OpenModelica v1.18.0 (64-bit) this is not working. Inherited ports stay unmovable and not responding if i change IconMap(extent = {{-100, -50}, {100, 150}}), DiagramMap(extent = {{-100, -50}, {100, 150}})); to other coordinates.

beutlich commented 2 years ago

in my OpenModelica v1.18.0 (64-bit) this is not working.

Could be related to https://trac.openmodelica.org/OpenModelica/ticket/5610 which got reopened.

casella commented 2 years ago

@jonas-hagen, could you just define a mechanical translational component with equations:


model Adaptor
  extends Modelica.Mechanics.Rotational.Interfaces.PartialTwoFlanges;
equation
  flange_a.s + flange_b.s = c;
  flange_a.f = flange_b.f;
end Adaptor;

I getting error: [1] 19:46:35 Translation Error [Adaptor: 4:3-4:30]: Variable c not found in scope Adaptor.

Sorry, of course you also need to declare the parameter c 😃

model Adaptor
  extends Modelica.Mechanics.Rotational.Interfaces.PartialTwoFlanges;
  parameter Modelica.Units.SI.Length c; // if you use Modelica Standard Library 4.0.0, otherwise Modelica.SIunits.Length
equation
  flange_a.s + flange_b.s = c;
  flange_a.f = flange_b.f;
end Adaptor;
casella commented 2 years ago

We need one volume - two flanges. SweptVolume in it current release can't be used to make hydraulic cylinder model

Yeah, I guess I get your point. The current model was designed with things like internal combustion engines or reciprocating compressors in mind - stuff that is fixed to a ground or chassis and pushes (or is pushed) by one single mechanical link.

What we can do here is to actually follow the rationale of Modelica.Mechanics. In there you find many component models that in certain contexts should just have one flange, the other one being fixed to ground, while in other cases they need two, with relative motion between them.

Of course one can build models with two flanges, and then connect one to a fixed ground in the first case, which is slightly inconvenient. What we did there was to provide models with a Boolean parameter useSupport (you may suggest another name for this case). If this parameter is false, the cylinder body is implicitly fixed to ground, i.e. you get the current SweptVolume. If it is true, then you get two flanges, one for the piston and one for the cylinder. This is implemented using conditional connectors.

We could do this in SweptVolume, and if we set useSupport = true by default, it will still be backwards compatible. We just need to decide where to put the second mechanical flange, since the bottom is already occupied by the fluid ports. We could put it on the right side, attached to the cylinder body.

Another alternative is to put the core code of SweptVolume in a base class, and then derive two models from it by inheritance, one with one mech flange, one with two. Unfortunately, I'm afraid you can't move connectors to a new position when inheriting (which in hindsight was not a particularly smart idea), so we'd have the same problem, that the position of the fluid connectors, that are defined in the base class, should be different in the extended class definitions.

What do you think?

tobolar commented 2 years ago

There is a comparable model Modelica.Mechanics.MultiBody.Examples.Loops.Utilities.GasForce2 for similar purpose. Considering only mechanical part of it could be helpful as a start point.

jonas-hagen commented 2 years ago

I would prefer one of the following options:

  1. Make SweptVolume extend Modelica.Mechanics.Translational.Interfaces.PartialCompliant, which would make it similar to a spring or damper with two ends that are moved relative to each other.
  2. Make SweptVolume extend Modelica.Mechanics.Translational.Interfaces.PartialElementaryOneFlangeAndSupport2 so that it gets a support and a useSupport flag and it would then be similar to a Modelica.Mechanics.Translational.Sources.Force.

Both would make sense for me.

sergniko commented 2 years ago

Both would make sense for me.

I support this also. Option 1 - I want it since I discovered OpenModelica :)

HansOlsson commented 2 years ago

I would prefer one of the following options:

  1. Make SweptVolume extend Modelica.Mechanics.Translational.Interfaces.PartialCompliant, which would make it similar to a spring or damper with two ends that are moved relative to each other.
  2. Make SweptVolume extend Modelica.Mechanics.Translational.Interfaces.PartialElementaryOneFlangeAndSupport2 so that it gets a support and a useSupport flag and it would then be similar to a Modelica.Mechanics.Translational.Sources.Force.

Both would make sense for me.

Only option 2 would be possible to make reasonably backwards compatible.

sergniko commented 2 years ago

Only option 2 would be possible to make reasonably backwards compatible.

In this case for option 1 I need a new component.

bilderbuchi commented 11 months ago

Here is another Modelica user getting confused when trying to model a telescopic piston with SweptVolume and only one mechanical connector: https://stackoverflow.com/questions/77299983/how-to-connect-a-mass-to-a-telescopic-piston

Having a conditional support flange on SweptVolume would really be useful.