化学组件

在最后一个基于组件建模的例子里,我们会再次回顾在向量与数组章节内介绍的化学系统。不过,这次我们将创建各种效应的组件模型,并演示Modelica内的连接是如何自动确保种类的守恒。

种类

我们在本例中将要处理的物质类型由以下enumeration定义:

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

请注意,这个定义在一个名为ABX的包内。这表示该组件模型要在涉及ABX的系统内正常工作。

Mixture

下列connector定义也包含在ABX包内(这可以在Interfaces子包中找到):

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

在这里我们看到,我们的Mixture连接器使用浓度为穿越变量,浓度变化率为流变量。虽然,在这种情况下flow变量不是严格意义上的守恒量的流。但在本例中,由于所有反应都包含在相同的容器内,这样的定义足够了。

请注意,连接器里的CR均为数组。而其下标由enumeration类型给出。我们之前就看到过枚举类的这种用法。

Solution

我们的第一个组件模型用于追踪控制体积内各种化学物质的浓度。正如前面所提到的,由于所有反应发生在同一体积内,我们实际上不需要指定控制体积的大小。

Solution模型很简单。如同在本章前面部分讨论过的RegionalPopulation模型,与模型唯一连接器相关联的横跨变量的变化率等于该连接器中的flow变量:

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
    annotation(Dialog(group="Initialization",showStartAttribute=true));
equation
  der(mixture.C) = mixture.R;
end Solution;

反应

Reaction

正如我们之前所看到的,该系统有三种化学反应。我们将研究的每个具体的反应,都会扩展自以下partial模型:

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}})));
protected
  ConcentrationRate consumed[Species];
  ConcentrationRate produced[Species];
  Modelica.SIunits.Concentration C[Species] = mixture.C;
equation
  consumed = -produced;
  mixture.R = consumed;
end Reaction;

我们看到,每个反应有反应系数kMixture类型的连接器mixture。而mixture连接器则连接到反应发生的Solution部件中。内部向量值变量consumedproduced起到的作用类似于在本章前面部分介绍过的SinkOrSource内的declinegrowth变量(即使用这些变量,我们就可以将每个反应的作用以一种直观的方法描述出来。)

A+B->X

第一个完整反应模型中,我们将考虑的是一个A分子,一个B分子合成一个X分子。使用Reaction模型,我们可以如下对这种反应进行建模:

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

该模型的第一个特点在于,它是由非字母数字字符组成的。具体来说,模型的名称中包含+->只要名称是用单引号字符引用,这在Modelica是允许的。反应速率R与继承自Reaction模型的consumed以及produced变量配合使用。由此就可以清楚描述该反应中反应物和产物的方程式。

A+B<-X

我们会考虑的下一个反应是将一个X分子转换成(回)一个A分子和一个B分子。这与之前的反应相反。该反应的Modelica代码为:

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

同样,方程清楚表达了哪些种类是反应物(即反应中的消耗),而那些是产物(即反应所产生的物质)。

X+B->R+S

我们的最后一个反应将X分子和B分子转化成R分子和S分子:

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

我们不追踪RS物质的浓度。因为,它们不过是副产物,不参与任何其它反应。本模型与前述模型同样遵循我们熟悉的模式。不同点在于,A类物质不参与反应。

系统

我们可以将Solution模型和不同的反应模型相结合,如下:

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}})));
equation
  connect('A+B<-X'.mixture, solution.mixture) annotation (Line(
      points={{30,0},{10,0}}, color={0,0,0},
      smooth=Smooth.None));
  connect('X+B->R+S'.mixture, solution.mixture) annotation (Line(
      points={{30,-40},{20,-40},{20,0},{10,0}},
      color={0,0,0},
      smooth=Smooth.None));
  connect('A+B->X'.mixture, solution.mixture) annotation (Line(
      points={{30,40},{20,40},{20,0},{10,0}},
      color={0,0,0},
      smooth=Smooth.None));
end ABX_System;

注意solution组件内的修改语句如何用来设置solution组件内物质的初始浓度。另外,反应系数是用每个反应组分的修改语句指定的。最后,每个反应组分都连接到solution.mixture连接器。

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

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

结论

你可能会记得,在我们之前对这个化学系统的讨论中,推导出的方程组为:

\[\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}\]

每个方程表示特定种类的增量。方程右边的每项都用于计算该特定物种流入控制体积的净流量。哪怕牵涉相对少量的种类,手工构建该系统都会很容易引入错误。但通过使用面向组件方法,我们从不需要推导上述方程组。其结果是,这些方程会自动生成。通过自动化这个过程,我们能够避免许多潜在的错误。我们也不再需要花时间去找出并修复这些错误。