11package space.kscience.controls.constructor.models.continuous
22
33import space.kscience.controls.constructor.*
4- import space.kscience.controls.constructor.units.Amount
5- import space.kscience.controls.constructor.units.AmountAlgebra
6- import space.kscience.controls.constructor.units.Numeric
7- import space.kscience.controls.constructor.units.UnitsOfMeasurement
4+ import space.kscience.controls.constructor.units.*
85import space.kscience.dataforge.context.Context
96
107public interface SeparationRule <U : UnitsOfMeasurement , T : Amount <U >> {
@@ -13,6 +10,31 @@ public interface SeparationRule<U : UnitsOfMeasurement, T : Amount<U>> {
1310 public fun forward (input : T ): Map <String , T >
1411
1512 public fun backward (output : Map <String , Numeric <U >>): Numeric <U >
13+
14+ public companion object {
15+ public fun <U : UnitsOfMeasurement , T : Amount <U >> proportional (
16+ algebra : AmountAlgebra <U , T >,
17+ fractions : Map <String , Double >,
18+ ): SeparationRule <U , T > = object : SeparationRule <U , T > {
19+
20+ private val norm = fractions.values.sum()
21+
22+ override val productionKeys: Collection <String > get() = fractions.keys
23+
24+ override fun forward (input : T ): Map <String , T > = fractions.mapValues {
25+ with (algebra) {
26+ input * (it.value / norm)
27+ }
28+ }
29+
30+ override fun backward (
31+ output : Map <String , Numeric <U >>
32+ ): Numeric <U > = output.minOf { (key, value) ->
33+ value / (fractions.getValue(key) / norm)
34+ }
35+
36+ }
37+ }
1638}
1739
1840public class ContinuousSeparate <U : UnitsOfMeasurement , T : Amount <U >>(
@@ -50,8 +72,15 @@ public class ContinuousSeparate<U : UnitsOfMeasurement, T : Amount<U>>(
5072 mapState(production) { it[key]!! }
5173 }
5274
53- public val productionCapacity: DeviceState <Map <String , T >> = mapState(supplyRequest) {
54- rule.forward(it)
75+ public val productionCapacity: DeviceState <Map <String , T >> = combineState(
76+ first = supplyRequest,
77+ second = jointConsumationRequest
78+ ) { supply: T , consumation: Map <String , Numeric <U >> ->
79+ with (algebra) {
80+ val productionLimit = rule.backward(consumation)
81+ val expectedProduction = supply.coerceValueIn(zero.. productionLimit)
82+ rule.forward(expectedProduction)
83+ }
5584 }
5685
5786 public val individualProductionCapacity: Map <String , DeviceState <T >> = rule.productionKeys.associateWith { key ->
@@ -66,12 +95,18 @@ public class ContinuousSeparate<U : UnitsOfMeasurement, T : Amount<U>>(
6695
6796}
6897
69- public fun <U : UnitsOfMeasurement , T : Amount <U >> ContinuousSeparate <U , T >.asConsumer (
98+ public fun <U : UnitsOfMeasurement , T : Amount <U >> ContinuousSeparate <U , T >.asProducer (
7099 key : String
71100): ContinuousProducerInterface <U , T > = consumationRequest[key]?.let { specificConsumationRequest ->
72101 object : ContinuousProducerInterface <U , T > {
73102 override val production: DeviceState <T > get() = individualProduction[key]!!
74103 override val productionCapacity: DeviceState <T > = individualProductionCapacity[key]!!
75104 override val consumerRequest: LateBindDeviceState <Numeric <U >> get() = specificConsumationRequest
76105 }
77- } ? : error(" No supplier with key $key found" )
106+ } ? : error(" No supplier with key $key found" )
107+
108+
109+ public fun <U : UnitsOfMeasurement , T : Amount <U >> ContinuousFlowModel.separator (
110+ algebra : AmountAlgebra <U , T >,
111+ separationRule : SeparationRule <U , T >
112+ ): ContinuousSeparate <U , T > = model(ContinuousSeparate <U , T >(context, algebra, separationRule))
0 commit comments