1 A nominal blend
Problem 01 | Blending with Uncertain Feed Composition | Level 1: Guided problem
1.1 Problem Statement
A plant blends 100 t/d of a liquid intermediate. Impurity must not exceed 7 wt%. Costs and available flows are deterministic. Impurity has no beneficial role, so only upward deviations matter for the quality upper bound. There are no volume changes, storage, or blending losses.
| Feed | Cost (USD/t) | Available (t/d) | Nominal impurity | Maximum upward deviation |
|---|---|---|---|---|
| A | 100 | 60 | 0.02 | 0.01 |
| B | 80 | 60 | 0.08 | 0.02 |
| C | 55 | 60 | 0.14 | 0.03 |
All fractions are mass fractions. Deviations of 0.01 mean one percentage point, not a 1% relative change.
Your task. Find the least-cost blend using nominal compositions. Then evaluate that same blend when every impurity takes its upper value. Do not re-optimize during this stress test.
1.1.1 Before you code
Which feed is cheapest? Why can it not supply the entire blend? Will a minimum-cost solution necessarily leave a quality margin?
1.1.2 Deliverables
- Define decision variables, units, objective, and constraints. State which data and assumptions are fixed.
- Predict one feature of the solution and explain why it should occur.
- Build and solve a Pyomo model. Check balances and bounds independently.
- Interpret the result and investigate the follow-up question below. For an open-ended challenge, state and defend your chosen policy separately from the reference solution.
1.2 Model Formulation
Let \(x_i\) be feed \(i\) in t/d, with \(0\le x_i\le60\). Define \(c_i\) as cost, \(a_i\) as nominal impurity, and \(d_i\) as maximum upward deviation. Let \(Q=100\) t/d and \(L=0.07\).
The mass balance and cost objective are \[\sum_i x_i=Q,\qquad \min C=\sum_i c_i x_i.\] The impurity constraint compares impurity mass flow with \(LQ\). Multiplying a fixed quality limit by the fixed product rate avoids a ratio.
At nominal composition, enforce \[\sum_i a_i x_i\le LQ.\] This is an LP: all coefficients are known constants. A binding quality constraint means the nominal design has no headroom for upward composition errors.
1.3 Pyomo Implementation
The code below is the model-building portion of models/blending.py. The level argument selects this problem’s assumptions. Run the complete module from the source bundle to reproduce the solution, including its independent checks:
~/.venvs/optim/bin/python -m models.blending 1"""Blend design: nominal, box-robust, and budget-robust quality."""
import itertools
import pyomo.environ as pyo
from models.common import value, solve
COST = {"A": 100, "B": 80, "C": 55} # USD/t
NOMINAL = {"A": 0.02, "B": 0.08, "C": 0.14} # mass fraction
DELTA = {"A": 0.01, "B": 0.02, "C": 0.03}
CAP = {"A": 60, "B": 60, "C": 60} # t/d
TOTAL = 100 # t/d
LIMIT = 0.07 # maximum impurity mass fraction
def build(level, gamma=1.5):
m = pyo.ConcreteModel(name="Blend quality")
m.I = pyo.Set(initialize=list(COST))
m.x = pyo.Var(m.I, domain=pyo.NonNegativeReals, bounds=lambda m, i: (0, CAP[i]))
m.mass = pyo.Constraint(expr=sum(m.x[i] for i in m.I) == TOTAL)
nominal = sum(NOMINAL[i] * m.x[i] for i in m.I)
if level == 1:
m.quality = pyo.Constraint(expr=nominal <= LIMIT * TOTAL)
elif level == 2:
m.quality = pyo.Constraint(
expr=nominal + sum(DELTA[i] * m.x[i] for i in m.I) <= LIMIT * TOTAL
)
else:
m.p = pyo.Var(domain=pyo.NonNegativeReals)
m.q = pyo.Var(m.I, domain=pyo.NonNegativeReals)
m.support = pyo.Constraint(
m.I, rule=lambda m, i: m.p + m.q[i] >= DELTA[i] * m.x[i]
)
m.quality = pyo.Constraint(
expr=nominal + gamma * m.p + sum(m.q[i] for i in m.I) <= LIMIT * TOTAL
)
m.cost = pyo.Objective(expr=sum(COST[i] * m.x[i] for i in m.I))
m._gamma = gamma
return mThe common solve function calls appsi_highs, checks optimal termination before loading a solution, and checks constraint residuals, bounds, and integer domains. After building the model, use:
from models.common import solve
m = solve(build(1))1.4 Optimal Solution
The reference objective is 8,125.0000 USD/d. This value is optimal for the explicitly stated model and data.
| Feed | Flow (t/d) |
|---|---|
| A | 58.3333 |
| B | 0.0000 |
| C | 41.6667 |
| Quantity | Value |
|---|---|
| Nominal impurity (%) | 7.0000 |
| Full-box impurity (%) | 8.8333 |
| Protected impurity (%) | 7.0000 |
| Gamma | 0.0000 |
1.4.1 Check your solution
Independently calculate both total flow and impurity mass flow. Report the stressed composition even though the nominal solver reports an optimal solution.
The automated residual, bound, and integrality audit passed with a maximum violation of 8.88e-16 in model units. Domain-specific checks passed. Model units differ across equations, so this numerical audit does not replace dimensional analysis.
1.5 Brief Discussion
The nominal blend costs 8,125.00 USD/d but reaches 8.833% impurity at the full upper corner. An optimal nominal solution can therefore violate the specification under uncertainty.
1.5.1 Extension to investigate
Predict the effect of reducing feed C availability to 20 t/d, then solve. Explain whether availability or quality now drives the result.