HYBRID Code Standards - idaholab/HYBRID GitHub Wiki

Hybrid Code Standards

A large portion of the Hybrid Repository is Modelica models. Therefore Modelica Code Standards are required.

Modelica Code Standards

This page provides a checklist that should be used when contributing a new class (model, block, connector, function, package, etc.) to the libraries that comprise NHES models.

General

  1. Follow the conventions of the Modelica Standard Library (MSL), which are as follows:
    Note, in the html documentation of any Modelica library, the headings "h1, h2, h3" should not be used. These headings are reserved for the automatically generated documentation and headings. Additional headings in the html documentation should start with "h4."
    In the Modelica package, the following conventions are used:
  • Comments and annotations always start with a capital letter, e.g.,

    <!-- language-all: lang-none -->
        parameter Real a = 1 "Arbitrary factor";
    
  • Class and instance names are usually written in upper and lower case letters, e.g., "ElectricCurrent". An underscore is only used at the end of a name to characterize a lower or upper index, e.g., "pin_a" may be rendered as “pina”.

  • Class names always start with an upper case letter.

  • Instance names, i.e., names of component instances and variables (with the exception of constants), usually start with a lower case letter with only a few exceptions based on common terminology (such as "T" for a temperature variable).

  • Constant names, i.e., names of variables declared with the "constant" prefix, follow the usual naming conventions (upper and lower case letters) and usually start with an upper case letter, e.g. UniformGravity, SteadyState.

  • The two connectors of a domain that have identical declarations and different icons are usually distinguished by "_a", "_b" or "_p", "_n", e.g., Flange_a/Flange_b, HeatPort_a, HeatPort_b.

  • The instance name of a component is always displayed in its icon (= text string "%name") in blue color. A connector class has the instance name definition in the diagram layer and not in the icon layer. Parameter values, e.g., resistance, mass, gear ratio, are displayed in the icon in black color in a smaller font size than the instance name.

  • A connector class has the instance name definition in the diagram layer and not in the icon layer.

  • A main package usually has the following subpackages:

    • UsersGuide, containing an overall description of the library and how to use it.
    • Examples, containing models demonstrating the usage of the library.
    • Interfaces, containing connectors and partial models.
    • Types, containing type, enumeration, and selected definitions.
    • BaseClasses, containing models, partial models, etc. that are not of interest to the user.

    In addition to the MSL conventions, the following conventions are used:

  • Names of models, blocks and packages should start with an upper-case letter and be a noun or a noun with a combination of adjectives and nouns. Use camel-case notation to combine multiple words, such as HeatTransfer.

  • Parameter and variables names are usually a character, such as T for temperature and p for pressure, or a combination of the first three characters of a word, such as higPreSetPoi for “high pressure set point”.

  • Comments should be added to each class (package, model, function, etc.). The first character should be an upper case letter.

  • Where applicable, all variables, including protected variables, must have units.

  1. All classes, with the exception of models within BaseClasses and constants, must have icons.
  2. Examples, i.e., regression tests, should be in a directory such as Electrolysis.Examples.
  3. Do not copy sections of code. Use object inheritance.

Type Declarations

  1. Declare all public parameters before protected ones.
  2. Declare variables and final parameters that are not of interest to users as protected.
  3. Set default parameter values as follows:
  • If a parameter value can range over a large region, do not provide a default value. Examples are nominal mass flow rates.

  • If a parameter value does not vary significantly but needs to be verified by the user, provide a default value by using its starting attribute. For example, for a heat exchanger, use

        parameter Real eps(start=0.8, min=0, max=1, unit="1")
        "Heat exchanger effectiveness";
    
    Do not use
    
        parameter Real eps=0.8(unit="1")
        "Heat exchanger effectiveness";
    

as this can lead to errors that are difficult to detect if a modeler forgets to overwrite the default value of 0.8 with the actual value. The model will simulate, but gives wrong results due to unsuited parameter values and there will be no warning. On the other hand, using parameter Real eps(start=0.8) will give a warning and, hence, users can assign better values.

  • If a parameter value can be precomputed based on other parameters, set its value to the appropriate equation. For example,

        Parameter Medium.MassFlowRate m_flow_small(min=0) = 
        1E-4*m_flow_nominal;
    
  • If a parameter value should not be changed by a user, use the final keyword. For example, use

        final parameter Modelica.SIunits.Frequency fn=60
        "Nominal frequency";
    
  1. For parameters and variables, provide values for the min and max attributes where applicable. Be aware that these bounds are not enforced by the simulator. If the min and max attributes are set, each violation of these bounds during the simulation may raise a warning.
    Compilers may allow suppression of these warnings. In Dymola, violation of bounds can be checked using

     Advanced.AssertAllInsideMinMax=true;
    
  2. For any variable or parameter that may need to be solved numerically, provide a value for the start and nominal attribute.

  3. Use types from Modelica.SIunits where possible.

Equations and Algorithms

  1. Avoid events (i.e., discrete behaviors that are generated by conditional expressions) where possible.
  2. If possible, only divide by quantities that cannot be zero. For example, if x may equal zero, use y=x, not 1=y/x, as the latter version indicates to a simulator that it is safe to divide by x.
  3. Use the assert function to check for invalid values of parameters or variables. For example, use assert(phi>=0, "Relative humidity must not be negative.").
  4. For computational efficiency, equations shall, were possible, be differentiable and have a continuous first derivative.
  5. Avoid equations where the first derivative with respect to another variable is zero. For example, if x, y are variables, and x = f(y), avoid y = 0 for x<0 and y=x^2 otherwise. The reason is that if a simulator tries to solve 0=f(x), then any value of x <= 0 is a solution, which can cause instability in the solver. Note that this problem does not exist for constant functions, as their first derivate will replaced due to optimization within the solver.
  6. Do not replace an equation with a constant that has a single value unless the derivative of the original equation is zero for this value. For example, if computing a pressure drop dp may involve computing a long equation, but one knows that the result is always zero if the volume flow rate V_flow is zero, one may be inclined to use a construct of the form dp = smooth(1, if V_flow == 0 then 0 else f(V_flow));. The problem with this formulation is that for V_flow=0, the derivative is dp/dV_flow = 0. However, the limit dp/dV_flow, as |V_flow| tends to zero, may be non-zero. Hence, the first derivative has a discontinuity at V_flow=0, which can cause a solver to fail to solve the equation because the smooth statement declared that the first derivative exists and is continuous.
  7. Make sure that the derivatives of equations are bounded on compact sets. For example, instead of using y=sign(x) * sqrt(abs(x)), approximate the equation with a differentiable function that has a finite derivative near zero.

Templated Development.

The NHES system in the Hybrid repository has the templating structure seen below.

Template_System

The top level is the overall system package which incorporates all of the Modelica models held within the NHES package. Then inside of the package are the different subpackages (Systems, Electrical, Thermal, etc…). Within each of the subpackages are further subpackages as seen in the Systems package. Within the Systems package there are further subpackages called SubSystem Category (Examples, PrimaryHeatSystem, EnergyStorage, etc…). Then within these SubSystem Categories there is yet another level of subpackage that is called SubSystem_Specific. Within the SubSystem_Specific category is where development takes place and potential configurations of the different processes take shape. Inside each SubSystem_Specific there is a template that includes Examples, Subsystem Dummy, CS_Dummy, ED_Dummy, Data, BaseClasses, and usually a Components folder. For existing systems the Examples folder contains a runnable example the user can execute to see how the code runs at a top level and what scenarios it is capable of running.

Package Order

  1. Packages are first sorted alphabetically:

     Actuators
     Boilers
     Chillers
     HeatExchangers
    
  2. After alphabetical sorting, the following packages, if they exist, are moved to the front:

     UsersGuide
     Examples
    

    and the following packages, if they exist, are moved to the end:

     Sources
     Sensors
     Media
     Interfaces
     Types
     Data
     Utilities (functions, records, etc.)
     Icons
     BaseClasses
    

Functions

  1. Use the smoothOrder annotation if a function is differentiable.

Regression Tests

  1. Implement at least one regression test for each model and block, and run the regression tests. Regression tests should cover all branches of if-then constructs. Construction of Regression Tests within the HYBRID system is available in the "Developing Regression Tests" wiki page.
⚠️ **GitHub.com Fallback** ⚠️