Published in the Jacaranda blog.
Although the Jacaranda system comes with a number of pre-defined process unit models (e.g. Distillation), there are many problems in conceptual design that only require simple models. These simple models may not require complex physical property values and may consist of, for instance, idealised mass and energy balances. For these cases, it may be worthwhile to define ad hoc simple models.
Jacaranda provides a generic model for such cases: units.Unit,1
intended for use with streams supporting vapour liquid equilibria
properties (although methods for estimating specific VLE properties
won't actually be accessible).
Defining an actual model instance using this generic model consists of a number of steps: specifying the process streams that interact with the unit, definining design variables (to allow for analysis and optimisation), defining the equations that describe the unit operation, and defining the equations that can be used for analysis or evaluation (e.g. values used by the criteria definitions). These are described in detail below through the use of a simple example.
The problem we wish to consider is the production of HF, as described
in Laing & Fraga, 1997. Potential candidate designs for the process
need to consider a wide range of units with varying degrees of detail.
The units required include a kiln (essentially a reactor), an acid
blender, an absorber, a quench unit and distillation. The
distillation unit is modelled through the detailed (albeit short-cut)
model available in Jacaranda (units.vle.Distillation) whereas the
others can be represented using simpler models.
There are three types of streams which interact with process units: input (a.k.a. feed) streams, makeup streams (feed streams whose definition depends on the unit operation) and the outputs of the unit. Although makeup streams are really input streams, they differ from input streams in that they are defined as a result of the unit design. The specific input streams, however, will be specified to the unit before the design is attempted.
The kiln unit has one input stream, the main feed, two output streams, the gas stream which is vapour and is the main product of the unit and the waste stream which is in solid phase, and an air make-up stream, of known composition but with the flow rate to be determined by the design model:
use uk.ac.ucl.che.esf.fish.units Unit kiln input feed output gas output waste makeup air air
The feed stream will be specified by Jacaranda prior to any design being attempted.
Output streams are created by the Unit model itself. The general
syntax of the output command is:
output NAME [TYPE]
where the square brackets indicate that the type of the output stream
is optional. If specified, this should be a class which implements
the ps.StreamExpressionInterface. If the type is not given, as in the
example above, the system will create a stream of the default type,
units.vle.Stream
The syntax for the makeup command is
makeup NAME INSTANCE
where the instance should be an actual stream which describes the composition of the makeup stream to be used. The amount or rate of that stream will be defined by the design model equations.
All streams, whether input, output or makeup, will have variables
available for use in the design equations. The actual variables
defined will depend on the stream definition. For the default base of
units.vle.Stream, the following variables are defined: F, the
amount or flow of the stream; x, the molar or mass composition in
fractions; P, the pressure in atm.; T, the temperature in Kelvin;
and, state, the state of the stream (0 is solid, 1 is liquid and 2
is vapour). For input streams, these variables are defined and set
before the design is evaluated; for output streams, the design
equations should give values to all of these variables as they will
then be used to define the actual output streams. For makeup streams,
the composition, x, will have been defined but all others will be
undefined and should be set by the design model.
Before attempting a design, Jacaranda will query the unit model to see if the input streams specified are appropriate or not. In other words, the unit will be given a chance to indicate whether the feed streams assigned to the unit are suitable for that unit. The unit does this by specifying a set of conditions for the feed:
feedconditions LOGICAL_EXPRESSION
which, for the kiln example, looks like this:
feedconditions "feed.x[CaF2]>epsilon & feed.x[H2SO4] > epsilon"
This is using the feed input stream defined above and looks to see if
the stream contains any significant amounts of
and
.
Most units will require heating or cooling (or both). Requests for
heating or cooling are defined using the heat transfer request (HTR)
type in Jacaranda. Such requests are defined using the htr command:
htr NAME
which creates a set of variables for specifying the necessary
information for a heat request, much as stream variables are defined.
The components of a heat transfer request are Q, the duty (in kW with
negative values indicating that heating is required and positive
values indicating that the unit has an excess of heat so cooling is
required); T1, the inlet temperature for the process stream to be
heated or cooled; T2, the outlet temperature of the process stream;
and, U, the heat transfer coefficient
for the process stream side of any exchange.
For the kiln unit, we define:
htr heat
Design variables are variables which alter the behaviour or design of a unit. These variables are intended for Jacaranda to manipulate, either through the synthesis procedure or through generic optimisation methods within Jacaranda. For the synthesis procedure, it is sufficient to indicate that the variable is of type specification; for the general optimisation use, the variables must also be defined as tunable.
For the kiln unit, we define one such variable:
new specification "Single pass conversion of CaF2" RealSet conversion 0.95 0.96 0.97 0.98 0.99
The general format for defining a new variable is
new FUNCTION DESCRIPTION TYPE NAME VALUES
where FUNCTION is either specification or specification+tunable,
DESCRIPTION is a string which is purely decorative, TYPE is one of
Real, RealSet, Int, IntSet or Component, and VALUES describe the range
of values the variable should consider when used in either synthesis
or optimisation modes. For a RealSet variable, the values are a list
of discrete values. For other types, the values will be specified in
different ways. For instance, for the Real type, the definition would
look like one of the following:
new specification "Continuous design variable" Real x1 VALUE new specification "Continuous design variable" Real x2 MIN MAX N new specification "Continuous design variable" Real x3 VALUE MIN MAX N
In the first case, the variable is given the specified value and the
minimum and maximum values this variable can have are also this
value. This is not particularly useful for design (either for
synthesis or optimisation) but could be useful in debugging. The more
common case is the second where the definition says that
.
When using the synthesis procedures in Jacaranda, N indicates the
number of discrete values for this variable within the interval
specified. These discrete values will be uniformly distributed across
the interval, including both end-points if
. If a log
based distribution of the discrete points is required, one can use the
LogReal type instead of Real.
The final case is the same as the second except that the variable is initialised to have the specific value given which may or may not correspond to one of the discrete values the system would normally use. This will not affect the synthesis procedures but will be useful for the process optimisation methods in Jacaranda.
When Jacaranda wishes to generate a design of the unit, it will
evaluate the equations given using the designequations command. These
equations are evaluated by the uk.ac.ucl.che.esf.util.expr expression
evaluator. This is essentially a vector based calculator and does not
solve a system of simultaneous equations. If solving a complex system
of equations is required, the simple unit model is probably not the
approach one should take for defining the model. Alternative
approaches are beyond the scope of this short note so readers are
encouraged to approach the author for suggestions.
For the kiln model, the following are snippets of the equations we use with some commentary:
designequations
# initialize the individual stream flows. we use the feed stream
# composition vector to create new vectors of the correct size.
gas.f = 0*feed.x
waste.f = 0*feed.x
feed.f = feed.F*feed.x # feed stream individual component flows
The feed stream will have been defined by Jacaranda and the
appropriate variables (F, x, T, ...) defined. These variables are
accessed by the stream name (as given in the input, output and makeup
commands above) followed by the full stop (.) and then the actual
variable name. The expression
feed.f = feed.F*feed.x
creates a vector of feed component flows based on the total flow, F, and the composition, x, of the feed stream.
# the air intake is directly related to the feed stream flow rate
air.F = air.ratio * feed.F
air.f = air.F * air.x
These equations define the actual amount of the air makeup stream
required. Recall that a makeup stream will have the composition
already defined.
# determine extents of reactions
extent = {0, 0, 0}
if feed.f[CaCO3] > feed.f[H2SO4]
extent[0] = 0
extent[1] = feed.f[H2SO4]
else
extent[1] = feed.f[CaCO3]
if feed.f[CaF2] > (feed.f[H2SO4]-extent[1])
extent[0] = (feed.f[H2SO4]-extent[1])*conversion
else
extent[0] = feed.f[CaF2]*conversion
endif
endif
if feed.f[SiO2] > (4*(extent[0]-feed.f[HF]))
extent[2] = (feed.f[HF]+extent[0])/4
else
extent[2] = feed.f[SiO2]
endif
These equations determine the extends of reaction. There are three reactions and it is important to note that the expression evaluator in Jacaranda uses a zero-based indexing for vectors.
Given the extents of reaction, the output streams can now be defined based on a simple extents of reaction mass balance procedure:
# now define the actual output stream compositions
gas.f[H2SO4] = feed.f[H2SO4] - extent[0] - extent[1]
gas.f[HF] = feed.f[HF] + 2*extent[0] - 4*extent[2]
gas.f[H2O] = extent[1]
gas.f[CO2] = extent[1] + air.f[CO2]
gas.f[SiF4] = extent[2]
gas.f[O2] = air.f[O2]
gas.f[N2] = air.f[N2]
gas.F = $gas.f # total gas flow
gas.x = gas.f/gas.F # and actual composition
gas.T = feed.T
gas.P = feed.P
gas.state = vapour
waste.f[CaF2] = feed.f[CaF2] - extent[0]
waste.f[CaCO3] = feed.f[CaCO3] - extent[1]
waste.f[SiO2] = feed.f[SiO2] - extent[2]
waste.f[CaSO4] = extent[0] + extent[1]
waste.F = $waste.f # total waste stream flow
waste.x = waste.f/waste.F # and composition
waste.T = feed.T
waste.P = feed.P
waste.state = solid
Note the use of the $ operator which means sum of all elements of the
vector to calculate the total flow of the gas and waste streams.
Given the specifications on the output streams, we can now design the actual physical unit. This includes a simple quadrature rule for evaluating an integral numerically:
# finally, design the actual reactor which is based on a numerical
# integration, as described above.
nsteps = 100
N = 2/3
M = 1/3
k450 = 0.247
E = 38363
k = k450 * exp(-1 * E * (1/feed.T - 1/450)/R)
Xf = conversion
Xo = preconversion # preconversion
Rc = feed.f[CaF2]/(feed.f[CaF2]+feed.f[CaCO3]) # CaF2:CaCO3 ratio
Ra = (feed.f[H2SO4]-extent[1])/feed.f[CaF2] # Acid:CaF2 ratio
dX = (Xf-Xo)/nsteps
rio = (1.0 - (1.0-Xo)^M) / ( k*(Rc*Rc*(Ra-Xo)*(Ra-Xo)*(1.0-Xo)^N) )
X = Xo + dX
t = 0 # residence time in minutes
while X <= Xf
ri = (1.0 - (1.0-X)^M) / ( k*(Rc*Rc*(Ra-X)*(Ra-X)*(1.0-X)^N) )
t = t + dX*(ri+rio)/2
rio = ri
X = X + dX
endwhile
volume = feed.F*t*60 # remember to convert to seconds
diameter = (volume*4/(Pi*htod))^(1/3)
height = diameter*htod
Finally, given the extents of reaction, we can solve the energy balance equations to tell us the amount of heating or cooling required. The numbers calculated are used to define a heat transfer request (HTR) which was defined above:
# now calculate the heat balance; recall that Q for a heat
# transfer request will have a positive value for cooling and a
# negative value if heating is required so we need to negate the value
# we get from the heats of reaction directly.
heat.Q = - extent*{53.7, 91.1, -189.4} # values are heats of reaction [kJ/kmol]
heat.T1 = feed.T
heat.T2 = feed.T
heat.P = feed.P
heat.U = 1
end # of design equations
Once the design has been generated, Jacaranda will evaluate the model equations which will typically be used to give values to the variables used to evaluate the criteria for comparing alternative process designs and for optimisation. These variables will be problem dependent. For the kiln model, the only variable we need is the capital cost of the unit:
model
capcost = 1917 * diameter^1.066
end
end # of Unit kiln definition
1. In this blog, class names are typically abbreviated by removing
the leading uk.ac.ucl.che.esf.fish. prefix. Unless otherwise
noted, all classes should have this prefix to be fully qualified.