///|
pub(all) struct SingleStageScenario {
name : String
feed_flow : Double
feed_concentration : Double
solvent_flow : Double
solvent_concentration : Double
distribution : Double
} derive(Debug, Eq, ToJson)
///|
pub fn SingleStageScenario::new(
name~ : String,
feed_flow~ : Double,
feed_concentration~ : Double,
solvent_flow~ : Double,
solvent_concentration? : Double = 0.0,
distribution~ : Double,
) -> SingleStageScenario raise @domain.ExtractionError {
if name.trim().length() == 0 {
raise @domain.ExtractionError::InvalidArgument(
message="scenario name cannot be blank",
)
}
@domain.require_positive("feed flow", feed_flow)
@domain.require_non_negative("feed concentration", feed_concentration)
@domain.require_positive("solvent flow", solvent_flow)
@domain.require_non_negative("solvent concentration", solvent_concentration)
@domain.require_non_negative("distribution coefficient", distribution)
{
name,
feed_flow,
feed_concentration,
solvent_flow,
solvent_concentration,
distribution,
}
}
///|
pub(all) struct ScenarioResult {
name : String
input : SingleStageScenario
result : @liquid.SingleStageResult
extraction_factor : Double
} derive(Debug, Eq, ToJson)
///|
pub fn run_single_stage_scenario(
scenario : SingleStageScenario,
) -> ScenarioResult raise @domain.ExtractionError {
let result = @liquid.single_stage_constant_k(
feed_flow=scenario.feed_flow,
feed_concentration=scenario.feed_concentration,
solvent_flow=scenario.solvent_flow,
solvent_concentration=scenario.solvent_concentration,
distribution=scenario.distribution,
)
{
name: scenario.name,
input: scenario,
result,
extraction_factor: @liquid.extraction_factor(
distribution=scenario.distribution,
solvent_flow=scenario.solvent_flow,
carrier_flow=scenario.feed_flow,
),
}
}
///|
pub fn run_single_stage_scenarios(
scenarios : ArrayView[SingleStageScenario],
) -> Array[ScenarioResult] raise @domain.ExtractionError {
if scenarios.length() == 0 {
raise @domain.ExtractionError::InsufficientData(required=1, actual=0)
}
let seen : Map[String, Unit] = Map([])
let results : Array[ScenarioResult] = []
for scenario in scenarios {
if seen.contains(scenario.name) {
raise @domain.ExtractionError::InvalidArgument(
message="duplicate scenario name '\{scenario.name}'",
)
}
seen[scenario.name] = ()
results.push(run_single_stage_scenario(scenario))
}
results
}
///|
pub fn sweep_distribution(
feed_flow~ : Double,
feed_concentration~ : Double,
solvent_flow~ : Double,
distributions : ArrayView[Double],
) -> Array[ScenarioResult] raise @domain.ExtractionError {
if distributions.length() == 0 {
raise @domain.ExtractionError::InsufficientData(required=1, actual=0)
}
run_single_stage_scenarios(
[
for index, distribution in distributions => {
SingleStageScenario::new(
name="K[\{index}]=\{distribution}",
feed_flow~,
feed_concentration~,
solvent_flow~,
distribution~,
)
}
],
)
}
///|
pub fn sweep_solvent_flow(
feed_flow~ : Double,
feed_concentration~ : Double,
solvent_flows : ArrayView[Double],
distribution~ : Double,
) -> Array[ScenarioResult] raise @domain.ExtractionError {
if solvent_flows.length() == 0 {
raise @domain.ExtractionError::InsufficientData(required=1, actual=0)
}
run_single_stage_scenarios(
[
for index, solvent_flow in solvent_flows => {
SingleStageScenario::new(
name="V[\{index}]=\{solvent_flow}",
feed_flow~,
feed_concentration~,
solvent_flow~,
distribution~,
)
}
],
)
}