E S Fraga: Jacaranda blog
Table of Contents
Introduction
This document presents a collection of notes and news items for the Jacaranda system for automated design and optimisation sorted in reverse chronological order.
Visit my home pages for links to my pages on general research, teaching and other interests.
Optimisation with external models
In the previous blog entry, I described how Jacaranda has been extended to allow models to be written in other languages, specifically in GAMS. Octave is also supported. This blog entry shows how these models can be used by the optimisation methods implemented within Jacaranda. An example employing the basic genetic algorithm is presented.
The key to using a model written in an external modelling system is
the definition of an object which instantiates the
ModelBasedObjectiveFunction class. The following example uses the external gams model which defines a MINLP described by Westerlund & Westerlund
(2003).
use jacaranda.util.opt
ModelBasedObjectiveFunction model
model gams
code westerlund.gms # the base gams model code
name westerlund # the GAMS model to use
command "/opt/gams/22.8/gams" # how to run gams on this system
# next two lines initialise GAMS variables x and y
# from Jacaranda's own x (continuous) and y (integer) variables
# defined by the Jacaranda model object
in x[0] x.fx
in y[0] y.fx
# the final value of the z GAMS variable will be copied
# back into Jacaranda's z variable
out z.l z
# define the task for GAMS
objective "solve westerlund using minlp minimizing z"
result "z" # what to return upon evaluation
end
# lower and upper bounds
a 1 1 # lower bound on both x and y variables
b 6 6 # and upper bound as well
# evaluate/solve the model using x=1.1 and y=1 as initial
# values and return the criteria values (z in our case)
evaluate 1.1 1
print
show
end
This objective function instance will make use of an external model
written using the GAMS modelling language and will be solved using
GAMS. This optimisation problem has one real variable (x[0] in
Jacaranda's own modelling language) and one integer variables (y[0]
in Jacaranda) which map to x and y in GAMS. In the GAMS model,
these variables are fixed and the model in GAMS is a square
system. The result of the GAMS solution will be in z which is copied
back to the same named variable in Jacaranda.
Once defined as an objective function, it can be used anywhere in Jacaranda where an objective function is allowed. This includes, for instance, the genetic algorithm classes described in an earlier blog entry. The evolution of the solutions obtained by this genetic algorithm for this problem is illustrated in this figure:

Statistics for population as it evolves under the control of a genetic algorithm
The commands to generate this plot are created automatically by Jacaranda and placed in the org-mode formatted output file.
External models in Jacaranda
Every object in the Jacaranda system can have a model associated with it. By default, these models are written in the Jacaranda Expression language. This language supports vector based arithmetic but is essentially a calculator. Sometimes, a more powerful modelling language is required.
Jacaranda has been extended to allow the use of external modelling systems. A framework has been put in place. At the moment, only one external language interface has been defined: for the GAMS modelling system. With this interface, a model can be written in GAMS and Jacaranda can communicate with GAMS to transfer values into GAMS and back out again.
A small GAMS modelling example
Consider the following Jacaranda input file:
use jacaranda.base
define
variable x1upper 2.5 # this will be used to set a GAMS value below
end
EGO gamsmodel
model gams
code test.gms # where the base gams model code is
command "/opt/gams/22.8/gams" # how to run gams on this system
# use x1upper Jacaranda variable to set GAMS variable X1.UP
in x1upper X1.UP
# and take result from GAMS of z and place in Jacaranda's z value
out z.l z
objective "solve test using nlp minimizing z"
result z # evaluate this expression to generate result
end
evaluatemodel # do it!
print
end
This example creates a simple object which defines the model
associated with the object as being an external GAMS model. The GAMS
model is in the file test.gms and includes everything but the actual
solve directive. The solve directive is specified by the
objective statement in Jacaranda.
The test code for this example is here:
$TITLE Test Problem $OFFSYMXREF $OFFSYMLIST * Example from Problem 8.26 in "Engineering Optimization" * by Reklaitis, Ravindran and Ragsdell (1983) * Code from * http://www.che.boun.edu.tr/courses/che477/gms-mod.html#TEST.GMS * (from a course by Ignacio Grossmann) VARIABLES X1, X2, X3, Z ; POSITIVE VARIABLES X1, X2, X3 ; EQUATIONS CON1, CON2, CON3, OBJ ; CON1.. X2 - X3 =G= 0 ; CON2.. X1 - X3 =G= 0 ; CON3.. X1 - X2**2 + X1*X2 - 4 =E= 0 ; OBJ.. Z =E= SQR(X1) + SQR(X2) + SQR(X3) ; * Upper bounds X1.UP = 5 ; X2.UP = 3 ; X3.UP = 3 ; * Initial point X1.L = 4 ; X2.L = 2 ; X3.L = 2 ; MODEL TEST / ALL / ; OPTION LIMROW = 0; OPTION LIMCOL = 0;
The Jacaranda input defines a new value for the upper bound on X1
and the result of evaluating the model is the value of the z
variable, specifically the level of that variable, z.l. The in
and out directives specify how to bring values in to the model
from Jacaranda and then back out again.
The output from Jacaranda, in org-mode in Emacs, can be seen here:
where we can see that the result of solving the GAMS model is 7.25.
This is actually a higher value than the optimum because we have
restricted variable X1 to a smaller upper bound, to illustrate the
transfer of values from Jacaranda to GAMS, and the optimum lies above
this upper bound.
The result can be any expression and not just a single variable. The
expression uses Jacaranda's own modelling language but has access to
any variables exported from the GAMS model (z.l in this case). Any
number of variables can be imported into the GAMS model and any number
exported as well.
The Genetic Algorithm classes
One of the built-in optimisation tools in the Jacaranda system is based on genetic algorithms. This short note describes the layout of the relevant classes and illustrates their use with a simple MINLP problem. The aim is not only to illustrate their use but also to explain how these classes can be extended or used directly to build new targeted genetic algorithm solution methods.
All classes and interfaces described in this section are in the
jacaranda.util.opt package unless stated otherwise.
The GA classes in Jacaranda
The following figure shows the three base classes which make up the genetic algorithm system. The GA class is the main controlling class. It will have a single population which must be provided during the definition of an instance of the GA object. The population will consist of a set of chromosomes, with the initialisation requiring the provision of a single chromosome to seed the population. The population may also be given diversity and selection objects which are discussed below. The chromosome is an interface; there is at least one base implementation, also described below, but it is through defining a new chromosome implementation that the method can be tailored for specific problems.

Base class hierarchy for the Genetic Algorithm procedure in Jacaranda
An implementation of the Chromosome interface,
VariableEncodedChromosome, is available in Jacaranda, suitable for
general MINLP (mixed integer nonlinear programme) problems. These
problems are defined by a combination of real and integer decision or
optimisation variables, one or more objective functions, possibly
constraint equations, both equality and inequality, and bounds on the
decision variables. This general Chromosome implementation is
actually more general than this and is suitable for any object that
can be encoded into and decoded from a combination of real and integer
variables but whose fitness can be evaluated through an objective
function object.

Variable encoded chromosome uses an objective function object for evaluation
The mate and mutate methods use appropriate operations for MINLP
problems. Specifically, the crossover operation is based on a
multi-point crossover across both real and integer variables. The
mutation operator selects on variable, randomly from the set of both
real and integer variables, and gives it a new value randomly from the
domain for that variable. These operators are actually implemented by
the Encoding implementation. The default encoding used by the
VariableEncodedChromosome is the GeneralEncoding class.
Alternative encodings include the BoundaryMutationEncoding, which
replaces the mutation operation with one which emphasises a move to
the boundaries for the selected variable, and the BinaryEncoding,
which encodes each real and integer value in a prespecified number of
bits for each variable.
The NLP and MINLP classes implement the ObjectiveFunction
interface and provide the ability to define the actual objective
functions (Jacaranda support multi-objective optimisation fully),
equality and inequality constraints and the lower and upper bounds on
the decision variables.
An MINLP example
Octave interface to Jacaranda
Octave can be used with Jacaranda for access to more powerful or specific optimisation and data analysis methods. A new interface for Jacaranda from Octave has been defined.
Introduction
An interface to Jacaranda from Octave (a tool similar to, and often very compatible with, Matlab) is potentially very useful, especially in the context of optimisation. Jacaranda provides a framework for process definitions, including simple or complex physical properties and processing units. Although Jacaranda has a number of optimisation methods included, it is not meant to be all-encompassing. As much of the optimisation research world-wide uses Octave or Matlab, an interface from Octave (due to its open source nature in preference to the proprietary and closed source Matlab) can be useful.
Previous versions of Jacaranda have included such an interface. However, the interface was based on the use of socket communication which could be slow when many objective function evaluations were required. It was also not a very portable solution which, although not often an issue (Jacaranda runs well on almost any Linux distribution), there is not reason to be limiting in portability.
Recently, a generic interface from Octave to Java has been implemented by Michael Goffioul. Jacaranda has therefore been updated to make use of this interface as it provides a much more elegant solution than what Jacaranda had before and is also more efficient.
An example
The full Jacaranda distribution (provided to collaborators) includes an input file which demonstrates this interface. As the more general distribution does not include this particular input file, I include it here for illustration:
1 ## Test out the Octave Java interface to Jacaranda. 2 ## 3 ## Eric S Fraga 4 function jacaranda_test 5 persistent version; 6 if (isempty(version)) 7 version = "2008.08.05 23:55:43"; 8 printf ("ESF %s, Octave java to Jacaranda function evaluation\n", version) 9 endif 10 ## initialise the Jacaranda interface from Octave, using a test input 11 ## file which defines an appropriate objective function. The 12 ## particular example, from Rathore et al (1974) is the design of a 13 ## heat integrated distillation sequence. The input file will 14 ## generate at least one flowsheet design. This flowsheet will define 15 ## an objective function with 8 real optimisation variables and 3 16 ## criteria for optimisation. 17 ## 18 ## Note that the following assumes that the Jacaranda class files are 19 ## stored in the given location relative to this file and that, 20 ## therefore, Octave has been started in this directory. 21 [A B nx ny nf] = jacaranda_init ("../vle/rathore_hen.in", \ # input file 22 "rathore_hen-1-1", \ # objective function 23 "../../src/java") # Jacaranda classpath 24 ## now evaluate the flowsheet at a number of random points 25 N = 100; 26 Y = []; 27 n_infeasible = 0; 28 for i=1:N 29 x = A + rand(1,length(A)).*(B-A); 30 try 31 y = jacaranda_evaluate (x); 32 Y = [Y; y]; 33 catch 34 n_infeasible++; 35 end_try_catch 36 endfor 37 if n_infeasible > 0 38 printf ("There were %d infeasible design points (out of %d total) found.\n", n_infeasible, N); 39 endif 40 printf ("Minimum criteria values: %8.2e %8.2e %8.2e\n", min(Y)); 41 printf ("Maximum criteria values: %8.2e %8.2e %8.2e\n", max(Y)); 42 ## the results obtained above are plotted to give some indication of 43 ## the variation in the three criteria for random design points 44 plot (Y); 45 endfunction
I believe the comments describe clearly what is happening so I will leave it at this for now.
Defining simple unit models in Jacaranda
Simple unit models can be written using the Unit class in Jacaranda
with the equations written in the expr expression evaluator
available in Jacaranda.
Introduction
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 example problem
The problem we wish to consider is the production of HF, as described
in Laing & Fraga (A case study on synthesis in preliminary design,
Computers & Chemical Engineering 21:S53-S58, 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.
Process streams
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 jacaranda.design.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.
Input stream checking
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 \(CaF_2\) and
\(H_2SO_4\).
Heat transfer requests
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 \(\left(\frac{kW}{m^2 \mbox{K}}\right )\) for the process stream side of any exchange.
For the kiln unit, we define:
htr heat
Design
Variables
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 \(x_2 \in \left [ MIN , MAX \right ]\).
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 \(N>1\). 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.
Equations
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 jacaranda.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.
# values in the next equation are heats of reaction [kJ/kmol]
heat.Q = - extent*{53.7, 91.1, -189.4}
heat.T1 = feed.T
heat.T2 = feed.T
heat.P = feed.P
heat.U = 1
end # of design equations
Evaluation 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
The full model definition
The complete model definition, comprising all the pieces described above, can be found here:
This model is copyright Eric S Fraga, all rights reserved. Distribution and use not allowed without his permission.
Footnotes:
[1] In this blog, class names are typically abbreviated by removing
the leading jacaranda.design. prefix. Unless otherwise
noted, all classes should have this prefix to be fully qualified.

