Process Engineering Project

Project for testing the implementation of different Process Engineering concepts.

Attention:

I haven’t yet studied the technical vocabulary in english for this subject. It may occur that some translations are imprecise or incorrect.

This started as a code for implementing an equation ordering algorithm (EOA). A complex process engineering problem contains many equations that must be solved for a complete description of the system. This modeling establishes an algorithm for picking the order in which the equations are solved in order to minimize the computational burden.

This inspired me to attempt to develop the algorithm in such a way that it fetches the equations’ variables automatically. Equations are defined as functions, the values of which should equal zero. The following image shows how a set of equations is transformed.

Equations

We can then define these functions in python and pass them to the equation ordering algorithm (aoe2()). Just by passing the functions, the algorithm is able to identify their arguments. This is done with the inspect module. We can even specify the values of the known variables (in this case, x1 = 1).

# Some outputs have been hidden
from main import *
def f1(x1, x2):
    return x1 + x2

def f2(x1, x2, x3, x4):
    return x2*x1 + x3 - x4

def f3(x3, x4):
    return x3 - x4

def f4(x4, x5):
    return x4 + 5*x5

_ = aoe2(f1, f2, f3, f4, x1=1)

# Output shows:
# Equation sequence:
#   - f1;
#   - f3;
#   - f2;
#   - f4;
#
# Variable sequence:
#   - x2;
#   - x3;
#   - x4;
#   - x5;
#
# Opening variables:
# [comment]: variables we must give a first guess
# for solving.
#   - x4;
#
# Project Variables:
# [comment]: known variables.
#   - x1;

In this case, we had the same amount of equations and variables (because we specified the value of x1). In cases where we have more variables than equations, the algorithm will propose project variables that minimize the size of iterative loops.

The following image illustrates the process of picking the order in which the equations are to be solved. We see that x1 is already dimmed since the beginning since it’s a known variable. The matrix illustrated is called the Incidence Matrix.

_images/Imagem1.png

Another algorithm I intend on implementing is a procedure for choosing the order in which the system’s equipments are to be simulated. Each equipment has its own set of equations, that themselves are ordered through the EO algorithm. Since the equipments are interconnected in a complex manner, the order in which they are solved can also be optimized to minimize computational burden, but the algorithm is a little different.

So far, I’ve finished developing an algorithm for identifying loops in processes. For example, the following block diagram:

Block Diagram

Can be modelled with the Flow and Equipment classes, and integrated to a Process class in the following way:

# Some outputs have been hidden
from main import *
from substances import *
p = Process()
# Notice we aren't defining the stream's compositions.
F1 = Flow("F1")
F2 = Flow("F2")
F3 = Flow("F3")
F4 = Flow("F4")
F5 = Flow("F5")
F6 = Flow("F6")
F7 = Flow("F7")
F8 = Flow("F8")
F9 = Flow("F9")
F10 = Flow("F10")
F11 = Flow("F11")
A = Equipment("A")
B = Equipment("B")
C = Equipment("C")
D = Equipment("D")
E = Equipment("E")
F = Equipment("F")

# Adding the objects to the process:
p.add_objects(F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,D,B,C,A,E,F)
# Adding links:
p.D.add_inflows(F1,F10)
p.D.add_outflows(F2)
p.A.add_inflows(F5, F8, F9)
p.A.add_outflows(F6)
p.B.add_inflows(F6)
p.B.add_outflows(F7, F9)
p.C.add_inflows(F7)
p.C.add_outflows(F8,F10)
p.E.add_inflows(F2, F4)
p.E.add_outflows(F3)
p.F.add_inflows(F3)
p.F.add_outflows(F4, F11)
# Defining the composition of the incoming streams:
F5.add_substances(Water)
F1.add_substances(Water)
# Updating the other streams' compositions based on those:
p.update_compositions()

The cycles present in this block diagram can be found through the moa() function:

from main import *
cycle_list = moa(p)
# Ignoring output for clarity
for cycle in cycle_list:
     for data in cycle:
         print(*(arg.name for arg in data))

# Output is:
# F3 F4
# E F E
# F6 F9
# A B A
# F6 F7 F8
# A B C A

The algorithm will also pick the streams that must give an initial guess for in order to open the processes’ cycles and solve the problem. This is done in such a way that it minimizes the number of streams we have to estimate, minimizing again the computational burden.

Note

Implementation isn’t yet finished, the algorithm isn’t able to take known stream information into account just yet.

_images/Imagem2.png

This is what is pushing me to develop classes for representing streams and equipments, so that I can integrate them more easily, and in the future integrate both approaches. A highlight is that the Flow class (that represents process streams) dynamically generates its restriction method in a way that it can be used by the equation ordering algorithm (given a few details) and also represent an unique equation for only that process stream.

main.aoe2(*fns: Callable, **xs: Union[float, int])[source]

Equation Oriented Modeling Algorithm.

The name aoe stands for “Algorítmo de Ordenação de Equações”, which means “Equation Ordering Algorithm”. The ‘2’ in the name stands for version 2.

Parameters
  • *fns – Functions that represent the equations that must equal 0.

  • **xs – Specified/Known variable values.

Returns

  • The order in which the equations should be solved (expressed through a list called func_seq).

  • The order in which the variables should be solved for (expressed through a list called var_seq).

  • A list with the project variables (those that must be specified or optimized).

Return type

A tuple with the

class main.Substance[source]

Class for a chemical substance.

Class Attributes:

_name: The molecule’s _name mm: Molar mass (kg/kmol). composition: The number of atoms of each element that the molecule has. atomic_mass: Look-up table for atomic masses.

static add_substances(cls_inst: Union[main.Flow, main.Equipment], *substances: main.Substance)[source]

Method for adding substances to the current.

Parameters
  • substancesSubstance objects of the substances we want to add.

  • info – Additional info we want to add the the flow’s attributes. It doesn’t have to be related the the substances that are being added.

static remove_substances(cls_inst: Union[main.Flow, main.Equipment], *substances: main.Substance)[source]

Method for removing substances from a current or equipment.

class main.Flow(name: str, *substances: main.Substance, **info: float)[source]

A process current.

TODO: There still need to be constant updates of the w, wmol, x, xmol

quantities.

Class Attributes:

tolerance: Tolerance for mass/molar fraction sum errors.

composition

A list with the substances present in the flow.

w

Flow rate (mass per unit time).

x

A dict for storing the value of the mass fractions. Each entry corresponds to a component. Sum must equal one. Unknown values are marked as None.

wmol

Flow rate (mol per unit time).

xmol

Molar fractions.

T

Temperature (in K).

static restriction(flow: main.Flow)float[source]

Mass fraction restriction equation (sum(x) = 1).

Warning

As of now, the code ignores the None values (considers them as equal to zero). No Exception is raised.

Parameters

flow – A Flow object

Returns

The sum of the stream’s mass fractions minus 1.

add_substances(*substances: main.Substance, **info: float)[source]

Method for adding substances to the current.

Parameters
  • substancesSubstance objects of the substances we want to add.

  • info – Additional info we want to add the the flow’s attributes. It doesn’t have to be related the the substances that are being added.

class main.Equipment(name: str)[source]

Class for equipments

TODO: There still need to be constant updates of the w, wmol, x, xmol

quantities.

static component_mass_balance(equipment: main.Equipment, substance: main.Substance)float[source]

Component Mass Balance for substance a given substance and equipment. TODO: maybe raise an error if the return value goes over the tolerance.

add_inflows(*inflows: main.Flow)[source]

Method for adding a current to the inflows. Automatically adds new substances to the class’s composition attribute. :param *inflows: Flow objects we want to add to the inflow.

add_outflows(*outflows: main.Flow)[source]

Method for adding a current to the outflows.

Parameters

*outflowsFlow objects we want to add to the inflow.

remove_flow(flow: Union[str, main.Flow])[source]

Method for removing a current from the in and outflows.

Parameters

flow – Either a Flow object or the name of an instance of one.

add_reaction(**kwargs)[source]

Adds a chemical reaction to the equipment.

Parameters

**kwargs

Returns:

toggle_reaction()[source]

TODO: update everything else that is related to chemical reactions. (mass balances etc.).

update_composition(update_outflows: bool = False)[source]

Updates the equipment’s composition attribute, based on its streams.

This may also update its outflow streams if the equipment’s reaction attribute is False (meaning that no reaction takes place in the equipment) and the update_outflows argument is True.

This is to avoid problems when generating errors when creating processes through the Process.sequential() method. If the outflows are updated as the process is being created, then it will overwrite and delete substances. However, when all connections are already established, it may be useful to use update_outflows = True.

Note

This implementation is only valid for an Equipment that does not involve a chemical reaction, because it removes substances that do not enter the equipment. For an equipment with reaction see Reactor.

class main.Process[source]

Process object

update_compositions(update_outflows: bool = False)[source]

Method for updating equipments’ and streams’ compositions. May be unfinished

main.moa(process: main.Process, *known_variables)[source]

Module ordering algorithm. Orders different process modules (equipments) in order for solving problems.

Parameters
  • process – A Process object with all of connected equipments and streams for ordering.

  • *known_variables – The variables that are considered to be known.

class substances.Water[source]
class substances.Ethanol[source]

Indices and tables