Thin-walled tank/Building complex models

From ASCEND
Jump to: navigation, search

Thin-walled tank tutorial
←Return to start

See also

Introduction

In this part of the tutorial, we show how ASCEND supports "part/whole" modeling to aid the creation of complex models.

To understand a complex entity, we typically partition it into a set of interconnected less complex parts, recursively partitioning those parts until we reach relatively simple parts we can understand directly. As an example, a chemical plant comprises separation units, reaction vessels, tanks, pumps, heat exchangers and so forth interconnected in part by having the outflow of one part be the inflow into another. We further decompose a separation unit such as a distillation column into trays, a condenser, a reboiler and so forth.

Similarly we can decompose a home into a collection of floors interconnected by stairways. We further decompose the floors into the rooms and hallways on those floors. We can also have a heating and air conditioning system, a water distribution system, and an electrical distribution system - mimicking the standard blueprints we often create when planning its construction. Many of the parts may reference the same item - a faucet, for example, belonging to both a sink in a bathroom and the water distribution system. By referencing them in both parts but declaring them to be the same faucet, we interconnect our parts to construct our home.


Models in ASCEND comprise variables, equations relating those variables, and instances of more complex types. We interconnect these instances by sharing variables and subparts among them.

Aside from being a natural way to develop models so we can understand them, we gain many other benefits from a part/whole view. Most importantly, we can debug by first debugging the simple parts, then the more complex parts constructed from them, and so forth. More esoterically, it turns out that we can make better decisions when solving a complex model if we understand its part/whole construction - e.g., we can solve much faster because we can select pivots that cause substantially less fill when solving the underlying linearized equations for the Newton-based solver we are using. We can also construct a compiler that is an order of magnitude faster if it can know the model's part/whole structure.

We shall illustrate the way we can decompose a model into its parts with our thin-walled tank example. This example is so simple that this decomposition may appear to complicate our modeling life. Accept this effort only as a way to illustrate the part/whole capabilities of ASCEND.

See also Object-oriented modeling


Partitioning our thin-walled tank model

We can partition our thin-walled tank into three parts: two ends and a sidewall. They share a common tank diameter. A model for an end is:

MODEL tank_end;
    (* variables *)
    D   IS_A distance;

    A   IS_A area;

    (* equation *)
    A=3.1416*D^2/4;

METHODS
    METHOD specify;
        FIX D;
    END specify;

    METHOD values;
        D := 1 {m};
    END values;

END tank_end;

Debugging this model should be relatively simple. There are only two variables and one equation relating them. We can immediately see that the area should be 3.1416 m^2 when the diameter is 2 m. We could also change D interactively to 10 m and see if the area becomes 314.16 m^2 to further check it.

A model for the tank side would be:

MODEL tank_side;
    (* variables *)

    D,
    H   IS_A distance;
    A   IS_A area;

    (* equation *)
    A=3.1416*D*H;

METHODS

    METHOD specify;
        FIX D;
        FIX H;

    END specify;
    METHOD values;
        D := 1 {m};

        H := 10 {m};
    END values;
END tank_side;

Again debugging this model would be very quick. The area for our test case would be 31.416 m^2.

Constructing the whole model from its parts

We construct the overall tank model file, including the above two part models, by adding a top level model built of the parts. We interconnect the parts using ARE_THE_SAME statements to merge shared variables.

(* this is file twt0310.a4c *)
REQUIRE "atoms.a4l";

MODEL tank_end;
    (* variables *)
    D   IS_A distance;
    A   IS_A area;

    (* equation *)
    A=3.1416*D^2/4;

METHODS

    METHOD specify;
        FIX D;
    END specify;

    METHOD values;
        D := 1 {m};
    END values;

END tank_end;

MODEL tank_side;
    (* variables *)
    D,

    H   IS_A distance;
    A   IS_A area;

    (* equation *)

    A=3.1416*D*H;

METHODS
    METHOD specify;

        FIX D;
        FIX H;
    END specify;

    METHOD values;
        D := 1 {m};
        H := 10 {m};

    END values;
END tank_side;

MODEL partitioned_thin_walled_tank;

    (* variables *)
    wall_thickness  IS_A distance;
    wall_area       IS_A area;

    wall_vol        IS_A volume;
    metal_density   IS_A mass_density;
    metal_mass      IS_A mass;

    (* parts *)
    top,
    bottom          IS_A tank_end;
    side            IS_A tank_side;

    (* interconnecting *)
    top.D,
    bottom.D,
    side.D          ARE_THE_SAME;

    (* equations *)
    wall_area  = top.A + bottom.A + side.A;

    wall_vol   = wall_thickness*wall_area;
    metal_mass = metal_density*wall_vol;

METHODS
    METHOD specify;
        RUN top.specify;     (* fixes diameter *)

        RUN bottom.specify;  (* fixes diameter *)
        RUN side.specify;    (* fixes diameter and height *)

   (* Note that these three specify methods all FIX the diameter, and
   these three diameters are the same variable for our model.  There
   is no harm in setting the same fixed flag to TRUE three times
   so we have nothing to "touch up" here. Generally, running the
   specify methods for all the parts will fix some variables we

   will need to unfix or not fix some that we need yet to fix. *)
        FIX metal_thickness;
        FIX metal_density;
        FIX wall_thickness;

    END specify;

    METHOD values;
        side.D         := 20.0 {cm};

        side.H         := side.D/10.0;
        wall_thickness := 0.15 {cm};

        metal_density  := 7.85 {g/cm^3};
    END values;

    METHOD setup;

        RUN specify;
        RUN values;
    END setup;

END partitioned_thin_walled_tank;

We see two items related to syntax here that we should highlight.

First we reference a variable that is inside a part using a "dot" notation; e.g., we refer to the diameter for the top as top.D. We use the same notation to run a method belonging to a part; e.g., to run the specify METHOD for the bottom, we wrote RUN bottom.specify. This notation recurses; namely, a.b.c refers to c, a variable in part b of part a.

Second, we interconnected our model by declaring variables in the model to be the same variable - an activity we call "merging." Here we merged the diameters of the parts by declaring that top.D, bottom.D and side.D are the same variable. This merging generalizes: we can merge complete parts, not just variables. We could, were it appropriate, declare the top and bottom to be the same part if we wished with the statement

top, bottom ARE_THE_SAME;

Discussion

In this section of the tutorial, we illustrated that ASCEND supports part/whole modeling, a powerful concept for constructing complex models. Two capabilities are critical for part/whole modeling: (1) that we can build models out of instances of other model types and (2) that we can interconnect those parts when constructing the whole model.

Later in this tutorial we shall introduce two other ways to interconnect parts - through the use of passed parameters and through aliasing. Using passed parameters is an essential ingredient for improving the sharability of models. Aliasing decreases compiling times.


Continue with the next section, Arrays