Skip to content

Reference ​

The functions and types for setting up, running and measuring a process. A process is described in layers, from the physics to the operation. Each layer is a plain object that can be edited, saved and reused on its own:

LayerObjects
GasGas, Feed, Component
MaterialsAdsorbent with an isotherm by component (dual_site_langmuir, langmuir), Column, Wall
FlowsheetFlowsheet, beds (add_bed!) and devices with roles (add_device!)
Operationa Cycle of steps (Pressurise, Adsorb, Blowdown, Evacuate, Purge, Equalise, Idle, Concurrent, or your own), TimeStepping
ProcessProcess: simulate, cyclic_steady_state, performance
Designadd_variable!, performance_gradient, optimise!
Filesread_process, write_process, load_adsorbent; see Process files
ResultsProcessResult, write_results, plots; see Results and plots

The Building a process from its parts example uses each layer in turn. To add your own kinds of step or unit, see Extending Mocca.

Units ​

Everything is in plain SI units: Pa, K, m, s, mol, kg and J.

Mocca.Units Module
julia
Mocca.Units

Mocca works in plain SI units throughout: Pa, K, m, s, mol, kg and J. These constants convert other units to SI by multiplication, so 0.1bar is 1e4 (Pa) and -36.6kJ_per_mol is -36600.0 (J/mol):

julia
using Mocca.Units
Evacuate(40.0; to = 0.1bar)

Units.celsius converts a temperature in °C to K. Files read with read_process may give a number with one of these units as a string, such as "0.1 bar".

source
Mocca.Units.celsius Function

Temperature in K of T °C.

source

Gas and feed ​

Mocca.Interface.Component Type
julia
Component(name; formula = name, cas = "", molar_mass, heat_capacity, viscosity)

A chemical component: its molar mass [kg/mol], gas heat capacity [J/(kg·K)] and gas viscosity [Pa·s], both near 25 °C. Mocca knows common gases by name (see component); add others with register_component!.

source
Mocca.Interface.component Function
julia
component(name) → Component

The component called name, for example "CO2". Known: CO2, N2, O2, Ar, H2O, CH4, H2, CO, He, and any added with register_component!.

source
Mocca.Interface.register_component! Function
julia
register_component!(c::Component)

Make c known by name, so that gases, compositions and isotherms can use it. Replaces a component of the same name.

source
Mocca.Interface.Gas Type
julia
Gas(names; molar_masses, heat_capacities, viscosity, density, diffusivity = 1.6e-5)

A gas mixture of the named components, in order. The order sets the order of compositions and loadings everywhere; by convention the first component is the one to capture (it is the key component of purity and recovery).

Properties default to those of the components (see component), and can be overridden, all at once as a vector in gas order or for some components by name, such as heat_capacities = (CO2 = 697.6,):

  • molar_masses [kg/mol] and heat_capacities [J/(kg·K)] per component;

  • viscosity [Pa·s] of the mixture. By default that of the feed, the Herning–Zipperer mixture of the component viscosities;

  • density [kg/m³] of the mixture, by default the ideal gas at the feed pressure and temperature. The built-in units do not use it;

  • diffusivity [m²/s]: molecular diffusivity, one value or one per component. It sets the macropore diffusion of the default linear driving force and, through the first component, the axial dispersion. The default is that of CO2 in N2 at 25 °C.

source
Mocca.Interface.composition Function
julia
composition(gas, spec; trace = 1e-10) → Vector{Float64}

Mole fractions in gas order. spec is a vector in gas order, or fractions by name, such as (CO2 = 0.15, N2 = 0.85) or Dict("CO2" => 0.15, "N2" => 0.85). Components not named get trace, to keep every fraction positive, and the named ones are scaled down to make room. Fractions must sum to one.

source
Mocca.Interface.Feed Type
julia
Feed(gas; composition, temperature = 298.15, pressure = 101325.0, light_product)

The feed gas of a flowsheet: its composition (see composition), temperature [K] and pressure [Pa]. light_product is the composition of the gas leaving the top of a bed during adsorption, used where light product flows back into a bed (for example in light product pressurisation). By default it is the feed with the component captured reduced to a trace: the first component, or the key_component of the Process the feed is used in.

source

Isotherms, adsorbents and columns ​

Isotherm parameters are given by component name, so an adsorbent does not depend on the order of the components of a gas, and components can be added or removed without editing parallel arrays.

Mocca.Interface.AbstractIsothermData Type
julia
AbstractIsothermData

Isotherm parameters given by component name, independent of the order of the components in a gas. build_isotherm turns them into an AbstractIsotherm for a particular Gas. Components of the gas without parameters do not adsorb; parameters for components the gas does not have are ignored, so one adsorbent can serve gases with different components.

Implement build_isotherm(data, gas; density) for a new kind, and register it with register_isotherm! to read and write it in files.

source
Mocca.Interface.dual_site_langmuir Function
julia
dual_site_langmuir(name => parameters, ...; reference_temperature = 298.15, basis = :volume)

Dual-site Langmuir isotherm data, one entry per component:

julia
dual_site_langmuir(
    "CO2" => (qsb = 3489.44, b0 = 8.65e-7, ΔUb = -36.64kJ_per_mol, qsd = 2872.35, d0 = 2.63e-8, ΔUd = -35.69kJ_per_mol),
    "N2" => (qsb = 6613.55, b0 = 2.50e-6, ΔUb = -15.8kJ_per_mol))

For each site, b (strong) and d (weak): saturation capacity qsb, qsd; affinity at infinite temperature b0, d0 [m³/mol], on a concentration basis; and internal energy of adsorption ΔUb, ΔUd [J/mol], negative. Omitted d-site values are zero. dUb and dUd may be written for ΔUb and ΔUd.

Capacities are in mol per m³ of adsorbent with basis = :volume, or mol/kg with basis = :mass. reference_temperature [K] is where the isosteric heat of adsorption is evaluated.

source
Mocca.Interface.langmuir Function
julia
langmuir(name => (qs = ..., b0 = ..., ΔU = ...), ...; reference_temperature = 298.15, basis = :volume)

Single-site Langmuir isotherm data by component: a dual_site_langmuir with an empty second site.

source
Mocca.Interface.build_isotherm Function
julia
build_isotherm(data, gas; density) → AbstractIsotherm

The isotherm for the components of gas, in its order. density [kg/m³] is the adsorbent density, which converts capacities given per kilogram. An AbstractIsotherm is used as it is.

source
Mocca.Interface.Adsorbent Type
julia
Adsorbent(name = ""; isotherm, density, heat_capacity, particle_diameter,
    particle_porosity, tortuosity = 3.0, adsorbed_heat_capacity = nothing,
    mass_transfer = nothing, reference = "")

An adsorbent material:

  • isotherm: isotherm data by component, such as dual_site_langmuir, or an AbstractIsotherm in the order of the gas it is used with;

  • density [kg/m³] and heat_capacity [J/(kg·K)] of the adsorbent;

  • particle_diameter [m], particle_porosity and tortuosity, which set the macropore diffusion of the default linear driving force;

  • adsorbed_heat_capacity [J/(kg·K)] of the adsorbed phase, per component (a vector in gas order or by name); by default the gas heat capacities;

  • mass_transfer: an AbstractMassTransfer; by default a LinearDrivingForce from the particle properties and the gas diffusivity;

  • reference: where the data come from.

Load one from the library with load_adsorbent.

source
Mocca.Interface.equilibrium_loading Function
julia
equilibrium_loading(adsorbent, gas; pressure, temperature, composition) → Vector

Equilibrium loading [mol/kg] of each component of gas on adsorbent, at a total pressure [Pa], temperature [K] and gas composition (see composition). Use it to check isotherm data and units.

source
Mocca.Interface.isotherm_table Function
julia
isotherm_table(adsorbent, gas, name; pressures, temperatures = [298.15]) → Matrix

Pure-component loading [mol/kg] of component name on adsorbent, one row per partial pressure [Pa] in pressures and one column per temperature [K] in temperatures. The other components are at trace levels.

source
Mocca.Interface.Column Type
julia
Column(; length, radius, porosity, outer_radius = radius, axial_conductivity = 0.09,
    wall = Wall(), inner_heat_transfer = 8.6, outer_heat_transfer = 2.5,
    ambient_temperature = 298.15)

The geometry and heat transfer of a packed column:

  • length [m], inner radius [m] and bed porosity (void fraction between particles);

  • outer_radius [m] of the wall, needed when the bed has a wall (the default thermal model);

  • axial_conductivity [W/(m·K)] of the packed bed;

  • wall, a Wall;

  • inner_heat_transfer and outer_heat_transfer [W/(m²·K)], bed to wall and wall to surroundings, and ambient_temperature [K].

The heat transfer defaults are those of Haghpanah et al. (2013).

source
Mocca.Interface.Wall Type
julia
Wall(; density = 7800.0, heat_capacity = 502.0, conductivity = 16.0)

Column wall material, by default stainless steel: density [kg/m³], heat capacity [J/(kg·K)] and conductivity [W/(m·K)].

source

Flowsheets ​

Devices have roles. A role sets the device's default boundary condition and valve size, tells the steps which device to open, and tells performance which streams are feed and product.

Mocca.Interface.Flowsheet Type
julia
Flowsheet(gas::Gas, feed::Feed)

An empty flowsheet for gas, fed with feed. Add beds with add_bed! and devices with add_device!, and run it as a Process.

Devices have roles (feed, product, extract, ...) that give their default boundary conditions and valve sizes, tell the step templates which device to open, and tell performance which streams are feed and product. The units and connections are a UnitNetwork, so the lower-level functions, such as add_unit!, connect! and setup_flowsheet_model, work on a flowsheet too.

source
Mocca.Interface.add_bed! Function
julia
add_bed!(fs, name, adsorbent, column; ncells = 30, thermal = WithWall(),
    dispersion_velocity = :adsorption, dispersion = nothing, permeability = nothing)

Add a fixed bed of adsorbent in column to the flowsheet under name. Its ports are :bottom and :top.

The axial dispersion depends on the gas velocity. By default (dispersion_velocity = :adsorption) it is set from the interstitial velocity of the bed's adsorption step when a Process is built, or the largest adsorption velocity in the cycle for a bed fed from another; it then stays fixed as settings change. Give a velocity [m/s], or the dispersion [m²/s] itself, to fix it. It is the bed's AxialDispersion parameter, so it can also be set through parameters of a Process or a design variable. See fixed_bed_model for the other keywords.

source
Mocca.Interface.add_device! Function
julia
add_device!(fs, name, role; at, boundary = nothing)
add_device!(fs, name, :link; from, to)

Add a flow device with a role (see DEVICE_ROLES), connected to a bed port at = (bed, port), such as (:Bed, :bottom). A link joins from, a bed port, to to, another.

The boundary of an inlet or outlet device defaults to the feed temperature, a role composition (the feed for feed, extract and waste; the light product for product and light inlet) and a pressure that steps override: the feed pressure, or for extract and waste the lowest pressure of the bed in its cycle. Pass boundary (a PortCondition, or a NamedTuple with any of pressure, temperature and composition) to set it.

source
Mocca.Interface.DEVICE_ROLES Constant

Roles of flow devices:

RoleConnected byBoundaryMeaning
:feedits outletinletfeed gas into a bed; counts as feed
:light_inletits outletinletlight product into a bed, for light product pressurisation or purge
:productits inletoutletlight product (raffinate) out of a bed
:extractits inletoutletheavy product out of a bed, through a vacuum pump; counts as product
:wasteits inletoutletother gas out of a bed, such as a water purge
:linkboth portsnonebetween two beds: series feed, equalisation
source
Mocca.Interface.print_flowsheet_diagram Function
julia
print_flowsheet_diagram([io], fs)

Print each unit of fs with the devices at each of its ports, their roles and boundaries.

source

Cycles and steps ​

A step acts on a bed and opens the devices it needs, found by their roles; every other device stays closed. Each step that changes the pressure starts where the step before ended, wrapping around the cycle; give from to start elsewhere.

Mocca.Interface.Cycle Type
julia
Cycle(steps)
Cycle(label => steps, label => steps, ...; cycle_time = nothing)

A cycle of steps (see AbstractStep), each run after the one before. Elements may also be Concurrent groups and plain Stages.

With several labelled sequences, such as one per bed of a two-bed process whose steps take different times, the sequences run side by side and are combined with parallel_stages: a shorter one is padded to cycle_time (by default the longest) with its devices closed. Each sequence tracks the pressures of its own beds.

source
Mocca.Interface.Pressurise Type
julia
Pressurise(duration; to = feed pressure, from = nothing, source = :feed, bed = nothing,
    device = nothing, ramp_rate = nothing, conductance = nothing, name = "")

Raise the bed from from (by default where the step before left it) to to [Pa], through the bed's feed device (source = :feed) or its light inlet (source = :light_product, light product pressurisation). The pressure on the far side of the valve follows an exponential ramp at ramp_rate [1/s].

source
Mocca.Interface.Adsorb Type
julia
Adsorb(duration; velocity = nothing, superficial_velocity = nothing, flow_rate = nothing,
    pressure = feed pressure, bed = nothing, feed_device = nothing, outlet = nothing,
    conductance = nothing, name = "")

Feed the bed at constant flow, given as one of an interstitial velocity [m/s], a superficial_velocity [m/s] or a flow_rate [m³/s at the bed inlet], with light product leaving the other end at pressure [Pa] through its product device, or through a link into another bed. A bed without a feed device of its own is fed through a link opened by the step of the bed before it, and takes no flow setting.

source
Mocca.Interface.Blowdown Type
julia
Blowdown(duration; to, from = nothing, through = :top, device = nothing, bed = nothing,
    ramp_rate = nothing, conductance = nothing, name = "")

Lower the bed to to [Pa] through an outlet device at its through end: the product device at the top (co-current), or a waste or extract device at the bottom (counter-current).

source
Mocca.Interface.Evacuate Type
julia
Evacuate(duration; to, from = nothing, through = :bottom, device = nothing, bed = nothing,
    ramp_rate = nothing, conductance = nothing, name = "")

Lower the bed to to [Pa] through an outlet device at its through end, by default the extract (vacuum) device at the bottom, which takes the heavy product.

source
Mocca.Interface.Purge Type
julia
Purge(duration; velocity = nothing, superficial_velocity = nothing, flow_rate = nothing,
    pressure = nothing, bed = nothing, conductance = nothing, name = "")

Light product enters through the bed's light inlet at a constant flow (one of an interstitial velocity, a superficial_velocity or a flow_rate) and leaves through the extract device at the other end, held at pressure [Pa], by default where the step before left the bed.

source
Mocca.Interface.Equalise Type
julia
Equalise(duration; beds, device = nothing, conductance = nothing, name = "")

Open the link between the two beds, such as (:A, :B), so that their pressures equalise; gas flows from the higher to the lower. Both beds are then taken to be at the mean of their start pressures, the start of the next ramp. The link is found from the beds, or given as device, which must join them.

source
Mocca.Interface.Idle Type
julia
Idle(duration; bed = nothing, name = "")

Keep the bed closed.

source
Mocca.Interface.Concurrent Type
julia
Concurrent(steps...; name = "")

Steps on different beds that run at the same time, as one stage of the cycle. They must have the same duration and open different devices. The stage is named after its steps, such as "A adsorption, B evacuation".

source
Mocca.Interface.TimeStepping Type
julia
TimeStepping(; max_dt = 1.0, first_dt = 0.05, keep_step_pattern = :auto)

How each stage is split into time steps: steps of at most max_dt [s], starting with first_dt and doubling, which carries the solver smoothly through the abrupt start of a stage (and keeps the cycle map smooth for Newton's method and gradients; see setup_schedule).

keep_step_pattern keeps the number of steps of each stage fixed when its duration changes, stretching them instead, which is what the gradients with respect to durations describe. :auto does this when the process has a duration among its design variables; the pattern is then that of the durations when the first such variable was added, or when reset_step_pattern! was last called.

source

Processes ​

Mocca.Interface.Process Type
julia
Process(fs, cycle; name = "", timestepping = TimeStepping(), key_component = 1,
    ambient_pressure = 101325.0, pump_efficiency = 0.72, heat_capacity_ratio = 1.4,
    ramp_rate = 0.5, initial_state = Dict(), parameters = Dict())

A cyclic adsorption process: the flowsheet fs (built with Flowsheet(gas, feed), add_bed! and add_device!) operated by cycle (see Cycle).

  • timestepping: see TimeStepping.

  • key_component: the component to capture, by index or name, for performance.

  • ambient_pressure [Pa]: vacuum pumps discharge to it and feed compressors take gas from it; pump_efficiency and heat_capacity_ratio are those of both.

  • ramp_rate [1/s]: of the pressure ramps of steps that do not set their own.

  • initial_state: per unit with holdup, a NamedTuple with any of pressure, temperature, wall_temperature and composition. By default each unit starts at the lowest pressure of its cycle (the feed pressure if no step sets it), at the feed temperature, full of light product, with the sorbent of a bed at equilibrium (see setup_unit_state).

  • parameters: per unit, values of its Jutul parameters to override, such as Dict(:Bed => Dict(:AdsorbentDensity => 1200.0)).

Simulate it with simulate, find its cyclic steady state with cyclic_steady_state, and measure it with performance.

The process keeps its own copies of fs and cycle, so changing them afterwards does not change the process, and several processes can be built from the same ones. Change a process through its design variables (see add_variable!); p.flowsheet and p.cycle are its copies.

source
Jutul.simulate Method
julia
simulate(p::Process; cycles = 1, state0 = initial_state(p), info_level = -1, kwarg...) → ProcessResult

Simulate cycles cycles of the process. Extra keywords go to simulate_process.

source
Mocca.Interface.initial_state Function
julia
initial_state(p) → Dict

The initial state of every unit; see initial_state in Process.

source
Mocca.Interface.stages Function
julia
stages(p::Process) → Vector{Stage}

The stages of the process's cycle, with the device settings of each.

source
Mocca.Interface.cyclic_steady_state Function
julia
cyclic_steady_state(p; method = :newton, tol = nothing, max_cycles = 500,
    warm_start = true, handover = 3, krylov = :auto, coarse_cells = 40,
    progress = isinteractive(), info_level = -1, kwarg...) → ProcessResult

The cyclic steady state of the process, with the states of its last cycle:

  • :newton (default): handover plain cycles (3), each from the end of the last, then Newton's method on the cycle map (see newton_cyclic_steady_state) to tol (default 1e-9). The plain cycles let the fastest modes die out, and Newton's method controls its steps, so it needs no closer start. A handover below 1 is a cycle change instead: Anderson acceleration until the change is below it. If Newton's method fails or does not converge, Anderson acceleration goes on to a change of 1e-1, and then if need be 1e-3, and Newton's method tries again from each. With warm_start, it starts from the last steady state found for this process, and its Jacobian, which is much faster when the settings have changed a little. With krylov = true, each Newton step is solved by GMRES instead of from the full Jacobian, which pays off for fine grids, where the variables far outnumber the slow modes of the cycle; false always builds the full Jacobian. The default, :auto, decides on each grid: GMRES when the beds have more than 800 variables (a bed of about 130 cells with two components, 100 with three), the full Jacobian below; krylov = n sets that number of variables to n. On a fine grid, with a bed of more than coarse_cells cells, the steady state is found first on beds of half as many cells (and so on, down to coarse_cells or fewer), each interpolated onto the next finer grid as the start of Newton's method there, which then needs only a few iterations; a coarser grid is converged to 1e-6 only. Starting fine grids cold is slow, and on some processes (such as the wet LPP VSA from about 80 cells) Newton's method does not converge from a few plain cycles. The coarser grids only give the start: the steady state is that of p. If Newton's method does not converge from the coarser grid's steady state, p is started from its initial state as above. Pass coarse_cells = nothing to start from the initial state on any grid.

  • :anderson: simulate_to_cyclic_steady_state to tol (default 1e-6).

  • :mass_balance: simulate_until_mass_balance on the key component, between the feed and light inlet devices and the outlet devices.

With progress, on by default in an interactive session such as the REPL, each cycle is printed as it finishes: how many have run, how much the state still changes over a cycle against tol, a bar of how far it has come, and an estimate of the cycles and time left. In a terminal the line is rewritten in place, so only the end of each phase stays on screen. progress can also be an IO to print to, or a CycleProgress.

source
Mocca.Interface.performance Function
julia
performance(r::ProcessResult) → NamedTuple

Performance of the process over the last cycle of r, from the streams through its devices (by their roles; see add_device!):

  • purity: mole fraction of the key component in the extract;

  • recovery: fraction of the key component fed that leaves in the extract;

  • specific_energy [kWh per tonne of key component in the extract]: vacuum pumps on every outlet device whose gas leaves below ambient pressure, and compressors on every inlet device whose gas enters a bed above it, as in Haghpanah et al. (2013);

  • productivity [mol of key component per m³ of adsorbent per s];

  • energy [J per cycle], cycle_time [s], the component totals [mol per cycle] of the feed, extract and light product, and the adsorbent_volume [m³] and adsorbent_mass [kg].

source
julia
performance(p::Process; kwarg...) → NamedTuple

Performance at cyclic steady state; keywords go to cyclic_steady_state.

source
Mocca.Interface.validate Function
julia
validate(p::Process) → Vector{MoccaInputError}

Check the description of a process and return the problems found, or an empty vector. Constructors already throw the first error they find; this also reports problems that do not stop a simulation but likely give wrong results:

  • a cycle that does not compile;

  • a unit with no devices, or a flowsheet without feed or extract devices;

  • a bed whose axial dispersion was set for a velocity far from that of its adsorption step;

  • design variables whose places cannot be read.

source
Mocca.Interface.MoccaInputError Type
julia
MoccaInputError(location, field, message)

An error in the description of a process, found when it is set up rather than inside the solver. location says where it is, such as "step 3 (blowdown) of the cycle" or "adsorbent 13X", and field names the setting, or is empty. validate returns them as a list instead of throwing.

source

Design variables, gradients and optimisation ​

Mocca.Interface.add_variable! Function
julia
add_variable!(p, name, places...; bounds = (-Inf, Inf), description = "")

Add a design variable name to the process, setting every one of places (see StepPlace, FeedPlace, ParameterPlace, or tuples such as ("evacuation", :to), (:feed, :pressure) and (:parameter, :Bed, :AdsorbentDensity)). Since pressures carry over from step to step, one place is usually enough: the evacuation pressure is also where the next pressurisation starts. bounds are needed by optimise!.

Read and set it with p[name] and p[name] = value.

source
Mocca.Interface.StepPlace Type
julia
StepPlace(step, field; sequence = "")

The field (such as :to, :velocity or :duration) of a step of the cycle, picked by its position (counting through all steps of the sequence, including those in Concurrent groups) or its name, such as "evacuation", or "A evacuation" for a step of bed A. In a cycle of several sequences, sequence is the label of the sequence.

source
Mocca.Interface.FeedPlace Type
julia
FeedPlace(field)

A field of the flowsheet's Feed: :pressure or :temperature.

source
Mocca.Interface.ParameterPlace Type
julia
ParameterPlace(unit, name)

The Jutul parameter name of unit, such as ParameterPlace(:Bed, :AdsorbentDensity), set to one value throughout the unit.

source
Mocca.Interface.performance_gradient Function
julia
performance_gradient(p; variables = all, steady_state = nothing, rtol = 1e-7,
    progress = isinteractive()) → NamedTuple

The performance of the process at cyclic steady state and its gradient with respect to the design variables (names; see add_variable!), by adjoints and the implicit function theorem (see cyclic_steady_state_gradient). Purity, recovery, specific energy and productivity follow from cycle sums by the quotient rule.

Returns metrics, the performance; gradients, a NamedTuple per measure of NamedTuples per variable, such as g.gradients.recovery.P_L; and the steady_state used. progress goes to cyclic_steady_state. The gas properties of a bed stay as they were when the process was built, and so does its axial dispersion unless a variable sets its AxialDispersion parameter.

source
Mocca.Interface.optimise! Function
julia
optimise!(p; variables = all, maximise = nothing, minimise = nothing,
    at_least = (;), at_most = (;), linear_constraints = [], scale = (;),
    weight = 1e3, max_it = 25, log = nothing, print_level = 0) → NamedTuple

Optimise the process at cyclic steady state with gradients (BFGS in the box of the variables' bounds, Jutul.unit_box_bfgs): maximise or minimise one performance measure, such as maximise = :recovery, subject to others held above or below targets, such as at_least = (purity = 0.9,). Measure constraints are quadratic penalties with weight on the shortfall in units of scale (per measure, 1 by default), so the result may miss them slightly. linear_constraints are (Dict(name => coefficient, ...), bound) pairs, meaning Σ coefficient·variable ≤ bound, such as (Dict(:P_L => 1.0, :P_I => -1.0), -0.01bar) for P_I ≥ P_L + 0.01 bar.

Variables whose bounds are equal stay fixed. Each evaluation finds the cyclic steady state from the last one. log(values, result) is called after each. Returns the best values (a NamedTuple), its metrics, the number of evaluations and the history of every evaluation, and leaves the process set to the best values.

source
Mocca.Interface.reset_step_pattern! Function
julia
reset_step_pattern!(p)

Take the current stage durations as the pattern of time steps that changed durations stretch (see TimeStepping).

source

Files and the library ​

Mocca.Interface.read_process Function
julia
read_process(path) → Process

Read a process from a JSON file written by write_process or by hand, or from the library by name (see library_processes). Numbers are SI, or strings with a unit such as "0.1 bar". An adsorbent may be given by the name of a library adsorbent or the path of an adsorbent file, relative to the process file.

source
Mocca.Interface.write_process Function
julia
write_process(path, p)

Write process p to a JSON file: its gas, feed, adsorbents, columns, units, devices, cycle, time stepping, options, initial state, parameter settings and design variables. Read it back with read_process.

source
Mocca.Interface.library_processes Function

Names of the processes in Mocca's library.

source
Mocca.Interface.load_adsorbent Function
julia
load_adsorbent(name) → Adsorbent

An adsorbent from the library by name (see library_adsorbents), or from a JSON file at the path name.

source
Mocca.Interface.save_adsorbent Function
julia
save_adsorbent(path, a; gas = nothing)

Write adsorbent a to a JSON file.

source
Mocca.Interface.library_adsorbents Function

Names of the adsorbents in Mocca's library.

source
Mocca.Interface.register_isotherm! Function
julia
register_isotherm!(name, T; read)

Make the isotherm data type T (an AbstractIsothermData) readable from files under "type": name: read(dict) builds it. Write it by adding a method of Mocca.isotherm_to_dict(data) that returns a Dict with "type" => name.

source

Ready-made processes ​

Mocca.Interface.four_stage_vsa_process Function
julia
four_stage_vsa_process(; ncells = 30, durations = (15.0, 15.0, 30.0, 40.0),
    P_H = 1e5, P_I = 0.2e5, P_L = 0.1e5, velocity = 1.0, ramp_rate = 0.5,
    timestepping = TimeStepping(), name = "four-stage VSA")

The single-bed, four-stage VSA cycle of Haghpanah et al. (2013): CO2/N2 (15/85) on zeolite 13X, with pressurisation, adsorption at interstitial velocity [m/s], co-current blowdown to P_I and counter-current evacuation to P_L [Pa].

julia
feed ──V_feed──┐                 ┌──V_product── raffinate
               bottom  Bed  top
extract ──V_vacuum──┘

As in the paper, vacuum pumps discharge at, and the feed compressor takes gas from, 1 bar.

source
Mocca.Interface.two_bed_vsa_process Function
julia
two_bed_vsa_process(; ncells = 30, feed_time = 15.0, pressurisation_time = 15.0,
    equalisation_time = 10.0, equalisation_conductance = 1e-6, P_H = 1e5, P_L = 0.1e5,
    velocity = 1.0, ramp_rate = 0.5, timestepping = TimeStepping())

Two beds, A and B, running the four-stage VSA cycle half a cycle apart, with a pressure equalisation valve joining their tops:

julia
feed ──V_feed_A──┐              ┌──V_product_A── raffinate
                 bottom  A  top ┤
extract ─V_vacuum_A┘            V_eq
feed ──V_feed_B──┐              │
                 bottom  B  top ┤
extract ─V_vacuum_B┘            └──V_product_B── raffinate

After a bed finishes adsorption it equalises with the other, evacuated bed, which saves feed gas and compression work:

StageBed ABed B
1pressurisation (feed)evacuation
2adsorptionevacuation
3equalisation (gives)equalisation (takes)
4evacuationpressurisation (feed)
5evacuationadsorption
6equalisation (takes)equalisation (gives)

After equalising, a bed is taken to be midway between the high and low pressures, where its pressurisation or evacuation starts. A bed evacuates through two stages, along one ramp to P_L.

source
Mocca.Interface.lpp_vsa_process Function
julia
lpp_vsa_process(; ncells = 30, velocity = 0.45, t_lpp = 20.0, t_ads = 78.4, t_bd = 37.9,
    t_evac = 111.6, P_H = 101325.0, P_I = 0.08e5, P_L = 0.03e5, ramp_rate = 0.5,
    timestepping = TimeStepping())

The single-bed VSA cycle with light product pressurisation (LPP) on zeolite 13X for wet flue gas, of section 3 of Krishnamurthy et al. (2014), at the operating conditions of its section 3.1. The light product is nitrogen.

julia
feed ──V_feed──┐                    ┌──V_product── raffinate
               bottom   Bed   top ──┤
CO2 ◄─V_vacuum─┘                    └──V_lpp────── light product
source
Mocca.Interface.dual_adsorbent_vsa_process Function
julia
dual_adsorbent_vsa_process(; ncells = 30, silica_gel_length = 0.41, zeolite_length = 1.0,
    velocity = 0.70, t_press = 20.0, t_ads = 46.20,
    silica_gel = (t_bd = 42.21, t_evac = 46.02, P_I = 0.48e5, P_L = 0.30e5),
    zeolite = (t_bd = 56.30, t_evac = 101.20, P_I = 0.07e5, P_L = 0.03e5),
    P_H = 101325.0, ramp_rate = 0.5, timestepping = TimeStepping())

The dual-adsorbent, two-bed VSA process of section 4 of Krishnamurthy et al. (2014): a silica gel bed that takes up the water, in series with a zeolite 13X bed that concentrates the CO2, at the minimum-energy conditions of its section 4.3. The beds' blowdown and evacuation times differ, so the cycle runs one sequence per bed side by side.

julia
feed ──V_feed──┐                      ┌──V_link──┐                   ┌──V_product── raffinate
               bottom  SilicaGel  top ┘          bottom  Zeolite  top┤
H2O ◄─V_waste──┘                                 │                   └──V_lpp────── light product
                                      CO2 ◄─V_vacuum┘
source
Mocca.Interface.haghpanah_2013_gas Function
julia
haghpanah_2013_gas()

CO2/N2 with the properties used by Haghpanah et al. (2013), Ind. Eng. Chem. Res. 52, 4249.

source
Mocca.Interface.haghpanah_2013_column Function
julia
haghpanah_2013_column(; length = 1.0)

The column of Haghpanah et al. (2013).

source
Mocca.Interface.krishnamurthy_2014_gas Function
julia
krishnamurthy_2014_gas()

Wet flue gas, CO2/N2/H2O, with the properties of Table S2 of Krishnamurthy et al. (2014), Ind. Eng. Chem. Res. 53, 14462: one gas heat capacity for the mixture, and a diffusivity per component (CO2–N2 for CO2 and N2, N2–H2O for water).

source
Mocca.Interface.krishnamurthy_2014_column Function
julia
krishnamurthy_2014_column(; length = 1.0)

The column of Table S2 of Krishnamurthy et al. (2014).

source

Index ​