Thin-walled tank/Arrays

From ASCEND
Jump to: navigation, search

Thin-walled tank tutorial
←Return to start

See also

Introduction

See also Arrays and sets.

Often we want to write a model containing the same type of part repeatedly. We introduce arrays along with the ability to write loops to allow us to write the model code one time, where we index the code over the elements.

Also we often wish to characterize an entity built out of an arbitrary number of repeating units. For example, a hotel chain might wish to design a type of hotel building whose number of floors and number of units on each floor is arbitrary - within limits - but whose guest rooms are the same for all instances of this type of building. The model would be an array of rooms over an array of floors. When using arrays in such a hotel model, we can reference the bottom floor, the top floor, or any floor whose index we can relate to bottom and top - such as the floor at or near the middle - floor (N+1)/2 - without knowing a priori the actual number of floors. The modeler's intention could be to code the model, debug that code with different test values for the number of floors and rooms, and then make this model available for others to use.

In ASCEND, we can have arrays of variables and, as with this hotel example, we can have arrays of instances of complex things. We can have an array of arrays of arrays (of arrays of arrays).

It should be noted that a spreadsheet program is fine for handling arrays with known fixed dimension. However, a spreadsheet program is not well suited to handle arrays of arbitrary dimension. We would have to write macros to generate the actual arrays within the spreadsheet once we have decided on the size of the array - something most of us would not be skilled at doing.


A collection of thin-walled tank farms

Okay, we have to stretch a bit to come up with a model based on our thin-walled tank, but modeling a collection of thin-walled tank farms might be one way to have such a need. We are a company that intends to build tank farms in several key locations throughout the country. Each farm will have several tanks located at it, and we wish to compute the total metal mass in each location as well as the total overall metal mass.

We shall create our model using the thin_walled_tank model of the previous section. We first model a tank farm. Following our earlier approach, we shall write and debug this model before using it as a part of our larger model. Thus we include a method that can set up a test case for it.

MODEL tank_farm;

    NT                  IS_A integer_constant;

    metal_density       IS_A mass_density;
    metal_mass_farm     IS_A mass;

    tank[1..NT]         IS_A partitioned_thin_walled_tank;

    metal_density, tank[1..NT].metal_density ARE_THE_SAME;

    (* an alternate way to write the above two lines of code would be

        FOR i IN [1..NT] CREATE
           tank[i]      IS_A partitioned_thin_walled_tank;
           metal_density, tank[i].metal_density ARE_THE_SAME;
        END FOR;
    *)

    massFarm: metal_mass_farm = SUM[tank[1..NT].metal_mass];

METHODS

    METHOD specify;
        FOR i IN [1..NT] DO

            RUN tank[i].specify;
        END FOR;
    END specify;

END tank_farm;

MODEL test_tank_farm;
    tankFarm    IS_A tank_farm;

    tankFarm.NT :==  3;

METHODS

    METHOD values;
        tankFarm.metal_density              := 7.85 {g/cm^3};
        tankFarm.tank[1].side.D             := 5 {m};
        tankFarm.tank[2].side.D             := 6 {m};
        tankFarm.tank[3].side.D             := 7 {m};
        tankFarm.tank[1..3].side.H          := 6 {m};
        tankFarm.tank[1..3].wall_thickness  := 1.5 {cm};
    END values;
    METHOD specify;
        RUN tankFarm.tank[1..3].specify;

    END specify;

END test_tank_farm;

We now model the collection of tank farms specific to our company.

MODEL our_tank_farms;
    locations             IS_A set OF symbol_constant;
    locations             :== ['SanFrancisco','St Louis','Pittsburgh'];
    total_mass_all_farms  IS_A mass;

    (* set up tank farms *)
    tankfarm[locations]   IS_A tank_farm;
    tankfarm['SanFrancisco'].NT    :== 2;
    tankfarm['St Louis'].NT        :== 4;
    tankfarm['Pittsburgh'].NT      :== 1;

    (* equations *)
    massAllFarms: total_mass_all_farms = SUM[tankfarm[locations].metal_mass_farm];

METHODS

    METHOD specify;
        FOR i IN [locations] DO
            RUN tankfarm[i].specify;
        END FOR;
    END specify;

    METHOD valuesSF;
        tankfarm['SanFrancisco'].metal_density := 7.85 {g/cm^3};
        tankfarm['SanFrancisco'].tank[1].side.D             := 4.5 {m};
        tankfarm['SanFrancisco'].tank[2].side.D             := 3 {m};
        tankfarm['SanFrancisco'].tank[1..2].side.H         := 6 {m};
        tankfarm['SanFrancisco'].tank[1..2].wall_thickness := 1.5 {cm};
    END valuesSF;

    METHOD valuesSTL;
        tankfarm['St Louis'].metal_density             := 7.85 {g/cm^3};
        tankfarm['St Louis'].tank[1].side.D            := 4 {m};
        tankfarm['St Louis'].tank[2].side.D            := 4 {m};
        tankfarm['St Louis'].tank[3].side.D            := 5 {m};
        tankfarm['St Louis'].tank[4].side.D            := 5 {m};
        tankfarm['St Louis'].tank[1..2].side.H         := 6 {m};
        tankfarm['St Louis'].tank[3..4].side.H         := 7 {m};
        tankfarm['St Louis'].tank[1..4].wall_thickness := 1.7 {cm};
    END valuesSTL;

    METHOD valuesPIT;
        tankfarm['Pittsburgh'].metal_density          := 7.85 {g/cm^3};
        tankfarm['Pittsburgh'].tank[1].side.D         := 8 {m};
        tankfarm['Pittsburgh'].tank[1].side.H         := 10 {m};
        tankfarm['Pittsburgh'].tank[1].wall_thickness := 1.85 {cm};
    END valuesPIT;

    METHOD values;
        RUN valuesSF;
        RUN valuesSTL;
        RUN valuesPIT;
    END values;

    METHOD setup;
        RUN specify;
        RUN values;
    END setup;
END our_tank_farms;

We have put these two models together in a file called twt0420.a4c, Adding in the appropriate INCLUDE statements completes the tank farm model file, which you can test using ASCEND.

Things to observe from this example

There are a few things we should observe about this example. For more details on all this, see the syntax document for ASCEND and the wiki page on arrays and sets.


  1. We indexed the tanks within each farm using integer constants (i.e., of type integer_constant). We indexed our tank farms using symbol constants. Both are legal as indices for arrays.
  2. We can indicate indices as constants (e.g., 1 or 'Pittsburgh') or for integer constants as ranges (e.g., 1..NT). Not illustrated is that one can select among array elements with a list, too (e.g., 1..2, 4)
  3. We actually set up an interesting two dimensional array in this example. The first (think of it as being the rows of the array) index is for the tank farms; the second (think of this as being the columns) is over the tanks in each farm. The number of tanks varies from farm to farm so the array is not rectangular.
  4. We reference a row/column element as tank_farm['St Louis'].tank[2]. Note how clear this reference is; we do not need to wonder what the first index in an array is over - it is over tank farms.

And other things to know about set handling in ASCEND

  1. ASCEND lets you also do some pretty fancy set manipulation, such as forming the UNION, INTERSECTION and DIFFERENCE to form sets as combinations of other sets.


Continue with the last section, Parameterised models