Importing Physical Types

In the previous section, we learned how to reference types defined in other packages. This spares the developer from having to constantly define things in their local model. Instead, they can place definitions in packages and then reference those packages.

However, references with long fully qualified names can be tedious to type over and over again. For that reason, Modelica includes an import statement that allows us to use a definition as if it were defined locally.

Recall again, this example from a previous discussion on Physical Types:

within ModelicaByExample.BasicEquations.CoolingExample;
model NewtonCoolingWithTypes "Cooling example with physical types"
  // Types
  type Temperature=Real(unit="K", min=0);
  type ConvectionCoefficient=Real(unit="W/(m2.K)", min=0);
  type Area=Real(unit="m2", min=0);
  type Mass=Real(unit="kg", min=0);
  type SpecificHeat=Real(unit="J/(K.kg)", min=0);

  // Parameters
  parameter Temperature T_inf=298.15 "Ambient temperature";
  parameter Temperature T0=363.15 "Initial temperature";
  parameter ConvectionCoefficient h=0.7 "Convective cooling coefficient";
  parameter Area A=1.0 "Surface area";
  parameter Mass m=0.1 "Mass of thermal capacitance";
  parameter SpecificHeat c_p=1.2 "Specific heat";

  // Variables
  Temperature T "Temperature";
initial equation
  T = T0 "Specify initial value for T";
equation
  m*c_p*der(T) = h*A*(T_inf-T) "Newton's law of cooling";
end NewtonCoolingWithTypes;

The previous section described how we could avoid defining these types locally by using types from the Modelica Standard Library. But we can also use the import command to import those types from the Modelica Standard Library once and then use them without having to specify their fully qualified names. The resulting code would look something like:

within ModelicaByExample.PackageExamples;
model NewtonCooling
  "Cooling example importing physical types from the Modelica Standard Library"
  import Modelica.SIunits.Temperature;
  import Modelica.SIunits.Mass;
  import Modelica.SIunits.Area;
  import ConvectionCoefficient = Modelica.SIunits.CoefficientOfHeatTransfer;
  import SpecificHeat = Modelica.SIunits.SpecificHeatCapacity;

  // Parameters
  parameter Temperature T_inf=300.0 "Ambient temperature";
  parameter Temperature T0=280.0 "Initial temperature";
  parameter ConvectionCoefficient h=0.7 "Convective cooling coefficient";
  parameter Area A=1.0 "Surface area";
  parameter Mass m=0.1 "Mass of thermal capacitance";
  parameter SpecificHeat c_p=1.2 "Specific heat";

  // Variables
  Temperature T "Temperature";
initial equation
  T = T0 "Specify initial value for T";
equation
  m*c_p*der(T) = h*A*(T_inf-T) "Newton's law of cooling";
end NewtonCooling;

Here we have replaced the type definitions with import statements. Note how the highlighted lines are identical to the previous code. Let’s look at two of these import statements more closely to understand what effect they have on the model. Let’s start with the following import statement:

  import Modelica.SIunits.Temperature;

This imports the type Modelica.SIunits.Temperature into the current model. By default, the name of this imported type will be the last name in the fully qualified name, i.e., Temperature. This means that with this import statement present, we can simply use the type name Temperature and that will automatically refer back to Modelica.SIunits.Temperature.

Now let’s look at another import statement:

  import ConvectionCoefficient = Modelica.SIunits.CoefficientOfHeatTransfer;

The syntax here is a little bit different. In this case, the type that we are importing is Modelica.SIunits.CoefficientOfHeatTransfer. But instead of creating a local type based on the last name in the fully qualified name, i.e., CoefficientOfHeatTransfer we are specifying that the local type should be ConvectionCoefficient. In this case, this allows us to use the name we originally used in our earliest examples. In this way, we can avoid refactoring any code that used the previous name. Another reason for specifying an alternative name (other than the default one that the Modelica compiler would normally assign) would be to avoid name collision. Imagine we wished to import two types from two different packages, e.g.,

import Modelica.SIunits.Temperature; // Celsius
import ImperialUnits.Temperature;    // Fahrenheit

This would leave us two types both named Temperature. By defining an alternative name for the local alias, we could do something like this:

import DegK = Modelica.SIunits.Temperature; // Kelvin
import DegR = ImperialUnits.Temperature;    // Rankine

SI Units

Note that this example imports imperial units just to demonstrate how a potential name clash might occur. But it is very bad practice to do this in practice. When using Modelica you should always use SI units and never use any other system of units. If you want to enter data or display results in other units, please use the displayUnit attribute discussed previously in the section on Attributes.

There is one last form of the import statement worth discussing which is the wildcard import statement. Importing units one unit at a time can be tedious. The wildcard import allows us to import all types from a given package at once. Recall the following earlier example:

within ModelicaByExample.BasicEquations.RotationalSMD;
model SecondOrderSystem "A second order rotational system"
  type Angle=Real(unit="rad");
  type AngularVelocity=Real(unit="rad/s");
  type Inertia=Real(unit="kg.m2");
  type Stiffness=Real(unit="N.m/rad");
  type Damping=Real(unit="N.m.s/rad");
  parameter Inertia J1=0.4 "Moment of inertia for inertia 1";
  parameter Inertia J2=1.0 "Moment of inertia for inertia 2";
  parameter Stiffness c1=11 "Spring constant for spring 1";
  parameter Stiffness c2=5 "Spring constant for spring 2";
  parameter Damping d1=0.2 "Damping for damper 1";
  parameter Damping d2=1.0 "Damping for damper 2";
  Angle phi1 "Angle for inertia 1";
  Angle phi2 "Angle for inertia 2";
  AngularVelocity omega1 "Velocity of inertia 1";
  AngularVelocity omega2 "Velocity of inertia 2";
initial equation
  phi1 = 0;
  phi2 = 1;
  omega1 = 0;
  omega2 = 0;
equation
  // Equations for inertia 1
  omega1 = der(phi1);
  J1*der(omega1) = c1*(phi2-phi1)+d1*der(phi2-phi1);
  // Equations for inertia 2
  omega2 = der(phi2);
  J2*der(omega2) = c1*(phi1-phi2)+d1*der(phi1-phi2)-c2*phi2-d2*der(phi2);
end SecondOrderSystem;

We could replace these type definitions with import statements, e.g.,

import Modelica.SIunits.Angle;
import Modelica.SIunits.AngularVelocity;
import Modelica.SIunits.Inertia;
import Stiffness = Modelica.SIunits.RotationalSpringConstant;
import Damping = Modelica.SIunits.RotationalDampingConstant;

However, the more types we bring in, the more import statements we need to add. Instead, we could write our model as follows:

within ModelicaByExample.PackageExamples;
model SecondOrderSystem
  "A second order rotational system importing types from Modelica Standard Library"
  import Modelica.SIunits.*;
  parameter Angle phi1_init = 0;
  parameter Angle phi2_init = 1;
  parameter AngularVelocity omega1_init = 0;
  parameter AngularVelocity omega2_init = 0;
  parameter Inertia J1=0.4;
  parameter Inertia J2=1.0;
  parameter RotationalSpringConstant c1=11;
  parameter RotationalSpringConstant c2=5;
  parameter RotationalDampingConstant d1=0.2;
  parameter RotationalDampingConstant d2=1.0;
  Angle phi1;
  Angle phi2;
  AngularVelocity omega1;
  AngularVelocity omega2;
initial equation
  phi1 = phi1_init;
  phi2 = phi2_init;
  omega1 = omega1_init;
  omega2 = omega2_init;
equation
  omega1 = der(phi1);
  omega2 = der(phi2);
  J1*der(omega1) = c1*(phi2-phi1)+d1*der(phi2-phi1);
  J2*der(omega2) = c1*(phi1-phi2)+d1*der(phi1-phi2)-c2*phi2-d2*der(phi2);
end SecondOrderSystem;

Note the highlighted import statement. This single (wildcard) import statement imports all definitions from Modelica.SIunits into the current model. With wildcard imports, there is no option to “rename” the types. They will have exactly the name locally as they have in the named package.

Before using wildcard imports, be sure to read this caveat.

In this chapter, we’ve seen how import statements can be used to import types from other packages. As it turns out, import statements are not always that useful. When models are being developed within a graphical modeling environment, tools generally use the least ambiguous and most explicit method for reference types: using fully qualified names. After all, when using a graphical tool the length of the name is not an issue because it doesn’t need to be typed. This also avoids issues with name lookup, naming conflicts, etc.