Chemical Components

For our last example of component oriented modeling, we’ll return to the Chemical System we discussed in the chapter on Vectors and Arrays. However, this time we will create component models for the various effects and show how connections in Modelica automatically ensure conservation of species.


The species we will be dealing with in this example are defined by the following enumeration:

within ModelicaByExample.Components.ChemicalReactions.ABX;
type Species = enumeration(A, B, X);

Note that this definition exists within a package called ABX. This indicates that the component models are designed to work with this three species system involving A, B and X.


Also contained in the ABX package is the following connector definition (which can be found in the Interfaces sub-package):

within ModelicaByExample.Components.ChemicalReactions.ABX.Interfaces;
connector Mixture
  Modelica.SIunits.Concentration C[Species];
  flow ConcentrationRate R[Species];
end Mixture;

Here we see that our Mixture connector uses concentrations as the across variables and a concentration rate as the flow variable. Although the flow variable in this case is not strictly the flow of a conserved quantity, it will suffice in this example since all reactions are contained within the same volume.

Note that both C and R in this connector are arrays where the subscript is given by an enumeration type. We saw earlier how Enumerations can be used in this way.


Our first component model is used to track the concentration of the various chemical species within a control volume. As alluded to earlier, since all reactions occur within the same volume, we don’t need to actually specify the size of the control volume.

The Solution model is quite simple. Like the RegionalPopulation model discussed earlier in this chapter, the rate of change of the across variable associated with its sole connector is equal to the flow variable on that same connector:

within ModelicaByExample.Components.ChemicalReactions.ABX.Components;
model Solution "A mixture of species A, B and X"
  Interfaces.Mixture mixture
    annotation (Placement(transformation(extent={{90,-10},{110,10}})));
  Modelica.SIunits.Concentration C[Species]=mixture.C
  der(mixture.C) = mixture.R;
end Solution;



As we saw previously, this system has three reactions. Each of the specific reactions we’ll examine extend from the following partial model:

within ModelicaByExample.Components.ChemicalReactions.ABX.Interfaces;
partial model Reaction "A reaction potentially involving species A, B and X"
  parameter Real k "Reaction coefficient";
  Mixture mixture
    annotation (Placement(transformation(extent={{-110,-10},{-90,10}})));
  ConcentrationRate consumed[Species];
  ConcentrationRate produced[Species];
  Modelica.SIunits.Concentration C[Species] = mixture.C;
  consumed = -produced;
  mixture.R = consumed;
end Reaction;

We see that each reaction has a reaction coefficient, k, and a Mixture connector, mixture, that ultimately connects it to the Solution where the reaction is to take place. The internal vector variables consumed and produced play a role that is similar to the decline and growth variables in the SinkOrSource discussed earlier in this chapter (i.e., they allow us to write contributions from individual reactions using an intuitive terminology).


The first complete reaction model we will consider is the one that turns one molecule of A and one molecule of B into one molecule of X. Using the Reaction model, we can model this reaction as follows:

model 'A+B->X' "A+B -> X"
  extends Interfaces.Reaction;
  Interfaces.ConcentrationRate R = k*C[Species.A]*C[Species.B];
  consumed[Species.A] = R;
  consumed[Species.B] = R;
  produced[Species.X] = R;
end 'A+B->X';

The first thing to note about this model is that it is composed of non-alphanumeric characters. Specifically, the name of this model contains +, - and >. This is permitted in Modelica as long as the name is quoted using single quote characters. The rate of the reaction, R, is used in conjunction with the consumed and produced variables inherited from the Reaction model to create equations that clearly describe both the reactants and the products in this reaction.


The next reaction we will consider is one that takes one molecule of X and transforms it (back) into one molecule of A and one molecule of B. This is the reverse of the previous reaction. The Modelica code for this reaction would be:

model 'A+B<-X' "A+B <- X"
  extends Interfaces.Reaction;
  Interfaces.ConcentrationRate R = k*C[Species.X];
  produced[Species.A] = R;
  produced[Species.B] = R;
  consumed[Species.X] = R;
end 'A+B<-X';

Again, the equations convey clearly which species are reactants (i.e., are consumed in the reaction) and which are the products (i.e., those species that are produced in the reaction).


Finally, our last reaction converts molecules of X and B into molecules of R and S:

model 'X+B->R+S' "X+B->R+S"
  extends Interfaces.Reaction;
  Interfaces.ConcentrationRate R = k*C[Species.B]*C[Species.X];
  consumed[Species.A] = 0;
  consumed[Species.B] = R;
  consumed[Species.X] = R;
end 'X+B->R+S';

We do not track the concentration of the R and S species since they are simply byproducts and do not participate in any other reactions. This model follows the same familiar pattern as before with the exception that the A species is not involved.


We can combine the Solution model along with the various reaction models as follows:

within ModelicaByExample.Components.ChemicalReactions.Examples;
model ABX_System "Model of simple two reaction system"
  ABX.Components.Solution solution(C(each fixed=true, start={1,1,0}))
    annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
  ABX.Components.'A+B->X' 'A+B->X'(k=0.1)
    annotation (Placement(transformation(extent={{30,30},{50,50}})));
  ABX.Components.'A+B<-X' 'A+B<-X'(k=0.1)
    annotation (Placement(transformation(extent={{30,-10},{50,10}})));
  ABX.Components.'X+B->R+S' 'X+B->R+S'(k=10)
    annotation (Placement(transformation(extent={{30,-50},{50,-30}})));
  connect('A+B<-X'.mixture, solution.mixture) annotation (Line(
      points={{30,0},{10,0}}, color={0,0,0},
  connect('X+B->R+S'.mixture, solution.mixture) annotation (Line(
  connect('A+B->X'.mixture, solution.mixture) annotation (Line(
end ABX_System;

Note how modifications to the solution component are used to set the initial concentration of species within the solution component. Also, the reaction coefficients are specified via modifications to each of the reaction components. Finally, each of the reaction components is attached to the solution.mixture connector.

Simulating this system for 10 seconds yields the following concentration trajectories:

#.. plot:: ../plots/ # :include-source: no


From our earlier discussion of this chemical system, you may recall that the resulting system of equations was:

\[\begin{split}\frac{\mathrm{d}[A]}{\mathrm{d}t} &= -k_1 [A] [B] + k_2 [X] \\ \frac{\mathrm{d}[B]}{\mathrm{d}t} &= -k_1 [A] [B] + k_2 [X] -k_3 [B] [X] \\ \frac{\mathrm{d}[X]}{\mathrm{d}t} &= k_1 [A] [B] - k_2 [X] -k_3 [B] [X]\end{split}\]

Each equation represents the accumulation of a particular species and each term on the right hand side of those equations is computing the net flow of that particular species into the control volume. Constructing this system by hand for even a relatively small number of participating species is rife with opportunities to introduce errors. By using a component oriented approach instead, we never had to assemble such a system of equations. As a result, these equations were generated automatically. By automating this process, we can avoid many potential errors and the time required to identify and fix them.