Alkylation Process Optimization (PROCESS)#

process.py

"""
## GAMSSOURCE: https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_process.html
## LICENSETYPE: Demo
## MODELTYPE: NLP
## KEYWORDS: nonlinear programming, alkylation process, chemical engineering


Alkylation Process Optimization (PROCESS)

Optimization of a alkylation process.


Bracken, J, and McCormick, G P, Chapter 4. In Selected Applications
of Nonlinear Programming. John Wiley and Sons, New York, 1968.
"""

from __future__ import annotations

import os

from gamspy import Container, Equation, Model, Problem, Sense, Variable
from gamspy.math import sqr


def main():
    m = Container(
        system_directory=os.getenv("SYSTEM_DIRECTORY", None),
    )

    # Variables
    olefin = Variable(
        m, name="olefin", type="positive", description="olefin feed (bpd)"
    )
    isor = Variable(
        m, name="isor", type="positive", description="isobutane recycle (bpd)"
    )
    acid = Variable(
        m,
        name="acid",
        type="positive",
        description="acid addition rate (1000lb per day)",
    )
    alkylate = Variable(
        m, name="alkylate", type="positive", description="alkylate yield (bpd)"
    )
    isom = Variable(
        m, name="isom", type="positive", description="isobutane makeup (bpd)"
    )
    strength = Variable(
        m,
        name="strength",
        type="positive",
        description="acid strength (weight pct)",
    )
    octane = Variable(
        m, name="octane", type="positive", description="motor octane number"
    )
    ratio = Variable(
        m,
        name="ratio",
        type="positive",
        description="isobutane makeup to olefin ratio",
    )
    dilute = Variable(
        m, name="dilute", type="positive", description="acid dilution factor"
    )
    f4 = Variable(
        m, name="f4", type="positive", description="f-4 performance number"
    )

    profit = Variable(m, name="profit")
    rangey = Variable(m, name="rangey")
    rangem = Variable(m, name="rangem")
    ranged = Variable(m, name="ranged")
    rangef = Variable(m, name="rangef")

    # Equations
    yield1 = Equation(
        m, name="yield1", description="alkylate yield definition"
    )
    rngyield = Equation(
        m, name="rngyield", description="ranged alkylate yield definition"
    )
    makeup = Equation(
        m, name="makeup", description="isobutane makeup definition"
    )
    sdef = Equation(m, name="sdef", description="acid strength definition")
    motor = Equation(m, name="motor", description="motor octane number")
    rngmotor = Equation(
        m, name="rngmotor", description="ranged motor octane number"
    )
    drat = Equation(m, name="drat", description="isobutane to olefin ratio")
    ddil = Equation(m, name="ddil", description="dilution definition")
    rngddil = Equation(
        m, name="rngddil", description="ranged dilution definition"
    )
    df4 = Equation(m, name="df4", description="f-4 definition")
    rngdf4 = Equation(m, name="rngdf4", description="ranged f-4 definition")
    dprofit = Equation(m, name="dprofit", description="profit definition")

    yield1[...] = alkylate == olefin * (
        1.12 + 0.13167 * ratio - 0.00667 * sqr(ratio)
    )
    makeup[...] = alkylate == olefin + isom - 0.22 * alkylate
    sdef[...] = acid == alkylate * dilute * strength / (98 - strength) / 1000
    motor[...] = octane == 86.35 + 1.098 * ratio - 0.038 * sqr(
        ratio
    ) - 0.325 * (89 - strength)
    drat[...] = ratio == (isor + isom) / olefin
    ddil[...] = dilute == 35.82 - 0.222 * f4
    df4[...] = f4 == -133 + 3 * octane
    dprofit[...] = (
        profit
        == 0.063 * alkylate * octane
        - 5.04 * olefin
        - 0.035 * isor
        - 10 * acid
        - 3.36 * isom
    )
    rngyield[...] = rangey * alkylate == olefin * (
        1.12 + 0.13167 * ratio - 0.00667 * sqr(ratio)
    )
    rngmotor[...] = rangem * octane == 86.35 + 1.098 * ratio - 0.038 * sqr(
        ratio
    ) - 0.325 * (89 - strength)
    rngddil[...] = ranged * dilute == 35.82 - 0.222 * f4
    rngdf4[...] = rangef * f4 == -133 + 3 * octane

    # Define Models
    process = Model(
        m,
        name="process",
        equations=[yield1, makeup, sdef, motor, drat, ddil, df4, dprofit],
        problem=Problem.NLP,
        sense=Sense.MAX,
        objective=profit,
    )
    rproc = Model(
        m,
        name="rproc",
        equations=[
            rngyield,
            makeup,
            sdef,
            rngmotor,
            drat,
            rngddil,
            rngdf4,
            dprofit,
        ],
        problem=Problem.NLP,
        sense=Sense.MAX,
        objective=profit,
    )

    rangey.lo[...] = 0.9
    rangey.up[...] = 1.1
    rangey.l[...] = 1
    rangem.lo[...] = 0.9
    rangem.up[...] = 1.1
    rangem.l[...] = 1
    ranged.lo[...] = 0.9
    ranged.up[...] = 1.1
    ranged.l[...] = 1
    rangef.lo[...] = 0.9
    rangef.up[...] = 1.1
    rangef.l[...] = 1

    strength.lo[...] = 85
    strength.up[...] = 93
    octane.lo[...] = 90
    octane.up[...] = 95
    ratio.lo[...] = 3
    ratio.up[...] = 12
    dilute.lo[...] = 1.2
    dilute.up[...] = 4
    f4.lo[...] = 145
    f4.up[...] = 162
    olefin.lo[...] = 10
    olefin.up[...] = 2000
    isor.up[...] = 16000
    acid.up[...] = 120
    alkylate.up[...] = 5000
    isom.up[...] = 2000

    olefin.l[...] = 1745
    isor.l[...] = 12000
    acid.l[...] = 110
    alkylate.l[...] = 3048
    isom.l[...] = 1974
    strength.l[...] = 89.2
    octane.l[...] = 92.8
    ratio.l[...] = 8
    dilute.l[...] = 3.6
    f4.l[...] = 145
    profit.l[...] = 872

    process.solve()
    print(f"Profit in model 'process': {profit.records.level[0]:.2f}")
    rproc.solve()
    print(f"Profit in model 'rproc': {profit.records.level[0]:.2f}")


if __name__ == "__main__":
    main()