Skip to content

Commit

Permalink
Impact block in process: add tests, evaluation and assessment.
Browse files Browse the repository at this point in the history
  • Loading branch information
jedesroches committed Aug 9, 2023
1 parent 9d001fe commit bee49f9
Show file tree
Hide file tree
Showing 13 changed files with 165 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Assessment(
.flatMap { it.biosphere }
.map { it.substance }
.filter { !observableSubstances.contains(it) }
val indicators = substanceCharacterizations
val indicators = (processes + substanceCharacterizations)
.flatMap { it.impacts }
.map { it.indicator }
controllablePorts = IndexedCollection(terminalProducts.plus(terminalSubstances).plus(indicators))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class Evaluator(
private val reduceLabelSelectors = ReduceLabelSelectors(symbolTable)
private val completeDefaultArguments = CompleteDefaultArguments(symbolTable)
private val reduce = Reduce(symbolTable)
private val completeTerminals = CompleteTerminals()

private val processResolver = ProcessResolver(symbolTable)
private val substanceCharacterizationResolver = SubstanceCharacterizationResolver(symbolTable)
Expand Down Expand Up @@ -73,7 +72,7 @@ class Evaluator(
.let(reduceLabelSelectors::apply)
.let(completeDefaultArguments::apply)
.let(reduce::apply)
.let(completeTerminals::apply)
.let(CompleteTerminals::apply)

val inputProductsModified = everyInputProduct.modify(reduced) { spec: EProductSpec ->
resolveProcessTemplateByProductSpec(spec)?.let { template ->
Expand All @@ -97,7 +96,7 @@ class Evaluator(
resolveSubstanceCharacterizationBySubstanceSpec(spec)?.let {
val substanceCharacterization = it
.let(reduce::apply)
.let(completeTerminals::apply)
.let(CompleteTerminals::apply)
trace.add(substanceCharacterization.toValue())
substanceCharacterization.referenceExchange.substance
} ?: spec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import arrow.optics.Every
import ch.kleis.lcaplugin.core.lang.evaluator.EvaluatorException
import ch.kleis.lcaplugin.core.lang.expression.*

class CompleteTerminals {
object CompleteTerminals {
private val everyInputExchange =
EProcessFinal.expression.inputs compose
Every.list()

fun apply(expression: EProcessFinal): EProcessFinal {
return completeSubstances(completeInputs(expression))
return completeProcessIndicators(completeSubstances(completeInputs(expression)))
}

fun apply(expression: ESubstanceCharacterization): ESubstanceCharacterization {
return completeIndicators(expression)
return completeSubstanceIndicators(expression)
}

private fun completeInputs(reduced: EProcessFinal): EProcessFinal {
Expand Down Expand Up @@ -61,24 +61,32 @@ class CompleteTerminals {
}
}

private fun completeIndicators(reduced: ESubstanceCharacterization): ESubstanceCharacterization {
return (ESubstanceCharacterization.impacts compose Every.list())
.modify(reduced) { exchange ->
val quantityExpression = exchange.quantity
val referenceUnit = when {
quantityExpression is EUnitLiteral ->
EQuantityScale(1.0, quantityExpression)
private fun completeIndicators(impacts: Collection<EImpact>): List<EImpact> =
impacts.map { impactExchange ->
val quantityExpression = impactExchange.quantity
val referenceUnit = when {
quantityExpression is EUnitLiteral ->
EQuantityScale(1.0, quantityExpression)

quantityExpression is EQuantityScale && quantityExpression.base is EUnitLiteral ->
EQuantityScale(1.0, quantityExpression.base)
quantityExpression is EQuantityScale && quantityExpression.base is EUnitLiteral ->
EQuantityScale(1.0, quantityExpression.base)

else -> throw EvaluatorException("quantity $quantityExpression is not reduced")
else -> throw EvaluatorException("quantity $quantityExpression is not reduced")
}

EImpact.indicator
.modify(impactExchange) {
EIndicatorSpec(it.name, referenceUnit)
}
}

EImpact.indicator
.modify(exchange) {
EIndicatorSpec(it.name, referenceUnit)
}
}
}
private fun completeProcessIndicators(reduced: EProcessFinal): EProcessFinal =
reduced.copy(
expression = reduced.expression.copy(
impacts = completeIndicators(reduced.expression.impacts)
)
)

private fun completeSubstanceIndicators(reduced: ESubstanceCharacterization): ESubstanceCharacterization =
reduced.copy(impacts = completeIndicators(reduced.impacts))
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ import ch.kleis.lcaplugin.core.HasUID

sealed interface MatrixRowIndex : Value, HasUID

sealed interface HasImpactList {
val impacts: List<ImpactValue>
}

data class ProcessValue(
val name: String,
val labels: Map<String, StringValue>,
val products: List<TechnoExchangeValue>,
val inputs: List<TechnoExchangeValue>,
val biosphere: List<BioExchangeValue>,
val impacts: List<ImpactValue>
) : Value, MatrixRowIndex
override val impacts: List<ImpactValue>
) : Value, HasImpactList, MatrixRowIndex

data class SubstanceCharacterizationValue(
val referenceExchange: BioExchangeValue,
val impacts: List<ImpactValue>,
) : Value, MatrixRowIndex
override val impacts: List<ImpactValue>,
) : Value, HasImpactList, MatrixRowIndex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ class ControllableMatrix(
val col = ports.indexOf(it.substance)
matrix.add(row, col, -it.quantity.referenceValue())
}

process.impacts
.filter { ports.contains(it.indicator) }
.forEach {
val col = ports.indexOf(it.indicator)
matrix.add(row, col, -it.quantity.referenceValue())
}
}

substanceCharacterizations.forEach { characterization ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,37 @@ import org.junit.Test
import kotlin.test.assertFailsWith

class EvaluatorTest {
@Test
fun eval_processWithImpacts_shouldReduceImpacts() {
// given
val symbolTable = SymbolTable.empty()
val instance = EProcessTemplateApplication(EProcessTemplate(
params = mapOf(),
locals = mapOf(),
body = EProcess(
"eProcess",
products = emptyList(),
labels = emptyMap(),
inputs = emptyList(),
biosphere = emptyList(),
impacts = listOf(
ImpactFixture.oneClimateChange
),
)
), emptyMap())
val evaluator = Evaluator(symbolTable)
val expected = ImpactValue(
QuantityValueFixture.oneUnit,
IndicatorValueFixture.climateChange,
)

// when
val actual = evaluator.eval(instance).processes.first().impacts.first()

// then
assertEquals(expected, actual)
}

@Test
fun eval_unresolvedSubstance_shouldBeTreatedAsTerminal() {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ class CompleteTerminalsTest {
impacts = emptyList(),
)
)
val completeTerminals = CompleteTerminals()

// when
val actual = completeTerminals.apply(process)
val actual = CompleteTerminals.apply(process)

// then
val expected = EProcessFinal(
Expand Down Expand Up @@ -63,10 +62,9 @@ class CompleteTerminalsTest {
EImpact(QuantityFixture.oneKilogram, EIndicatorSpec("cc"))
)
)
val completeTerminals = CompleteTerminals()

// when
val actual = completeTerminals.apply(expression).toValue()
val actual = CompleteTerminals.apply(expression).toValue()

// then
val expected = SubstanceCharacterizationValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import ch.kleis.lcaplugin.core.lang.value.IndicatorValue

class IndicatorValueFixture {
companion object {
val climateChange = IndicatorValue("climate change", UnitValueFixture.kg)
val climateChange = IndicatorValue("Climate Change", UnitValueFixture.unit)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ch.kleis.lcaplugin.core.lang.value.QuantityValue

class QuantityValueFixture {
companion object {
val oneUnit = QuantityValue(1.0, UnitValueFixture.unit)
val oneKilogram = QuantityValue(1.0, UnitValueFixture.kg)
val twoKilograms = QuantityValue(2.0, UnitValueFixture.kg)
val oneLitre = QuantityValue(1.0, UnitValueFixture.l)
Expand All @@ -13,7 +14,6 @@ class QuantityValueFixture {
val fiftyPercent = QuantityValue(50.0, UnitValueFixture.percent)
val hundredPercent = QuantityValue(100.0, UnitValueFixture.percent)
val twentyPiece = QuantityValue(20.0, UnitValueFixture.piece)
val thirtyPiece = QuantityValue(30.0, UnitValueFixture.piece)
val hundredPiece = QuantityValue(100.0, UnitValueFixture.piece)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ class UnitValueFixture {
val l = UnitValue(UnitSymbol.of("l"), 1.0e-3, DimensionFixture.volume)
val percent = UnitValue(UnitSymbol.of("percent"), 1.0e-2, Dimension.None)
val piece = UnitValue(UnitSymbol.of("piece"), 1.0, Dimension.None)
val unit = UnitValue(UnitSymbol.of("unit"), 1.0, Dimension.None)
}
}
42 changes: 42 additions & 0 deletions src/test/kotlin/ch/kleis/lcaplugin/e2e/E2ETest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ch.kleis.lcaplugin.core.lang.expression.EQuantityScale
import ch.kleis.lcaplugin.core.lang.expression.EUnitLiteral
import ch.kleis.lcaplugin.core.lang.fixture.DimensionFixture
import ch.kleis.lcaplugin.core.lang.fixture.UnitFixture
import ch.kleis.lcaplugin.core.lang.fixture.UnitValueFixture
import ch.kleis.lcaplugin.core.lang.value.FromProcessRefValue
import ch.kleis.lcaplugin.core.lang.value.ProductValue
import ch.kleis.lcaplugin.core.lang.value.QuantityValue
Expand Down Expand Up @@ -931,4 +932,45 @@ class E2ETest : BasePlatformTestCase() {
// when/then
Evaluator(symbolTable).eval(entryPoint)
}

@Test
fun test_processImpact_whenImpactBlockInProcess_shouldEvaluate() {
val pkgName = {}.javaClass.enclosingMethod.name
val vf = myFixture.createFile(
"$pkgName.lca", """
package $pkgName
process p {
products {
1 kg out
}
impacts {
1 u climate_change
}
}
""".trimIndent()
)
val file = PsiManager.getInstance(project).findFile(vf) as LcaFile
val parser = LcaLangAbstractParser(sequenceOf(file))

// when
val symbolTable = parser.load()
val entryPoint = EProcessTemplateApplication(symbolTable.getTemplate("p")!!, emptyMap())
val trace = Evaluator(symbolTable).trace(entryPoint)
val system = trace.getSystemValue()
val assessment = Assessment(system, trace.getEntryPoint())

// then
val result = assessment.inventory().impactFactors
val output = result.observablePorts.getElements().first()
val input = result.controllablePorts.get("climate_change")
val cf = result.value(output, input)

val delta = 1E-9
val expected = 1.0

assertEquals("climate_change", input.getDisplayName())
assertEquals(expected, cf.input.quantity().amount, delta)
assertEquals(UnitValueFixture.unit, cf.input.quantity().unit)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package ch.kleis.lcaplugin.language.ide.style

import com.intellij.psi.formatter.FormatterTestCase
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

@RunWith(JUnit4::class)
class LcaIndentBlockTest : FormatterTestCase() {
@Test
fun test_formattingLabels() {
Expand Down Expand Up @@ -545,6 +548,25 @@ labels {
)
}

@Test
fun test_impactBlockInProcess_shouldIndent() {
doTextTest("""
process p1 {
impacts {
1 u climate_change
}
}
""".trimIndent(),
"""
process p1 {
impacts {
1 u climate_change
}
}
""".trimIndent()
)
}

override fun getTestDataPath(): String {
return ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -983,30 +983,35 @@ class LcaLangAbstractParserTest : ParsingTestCase("", "lca", LcaParserDefinition
}

@Test
fun testParse_whenProcessHasImpacts_thenParses() {
// given
fun testParse_processWithImpacts_shouldParse() {
val pkgName = {}.javaClass.enclosingMethod.name
val file = parseFile(
"processWithImpacts", """
package testParse_whenProcessHasImpacts_thenParses
"$pkgName.lca", """
package $pkgName
process p1 {
process a {
products {
1 kg prod1
1 kg x
}
impacts {
1 unit climate_change
1 u cc
}
}
""".trimIndent()) as LcaFile
""".trimIndent()
) as LcaFile
val parser = LcaLangAbstractParser(
sequenceOf(file)
)
val symbolTable = parser.load()

val parser = LcaLangAbstractParser(sequenceOf(file))
// when
val template = symbolTable.getTemplate("a") as ProcessTemplateExpression
val actual =
(ProcessTemplateExpression.eProcessTemplate.body.impacts compose
Every.list() compose EImpact.indicator).firstOrNull(template)

// when then
try {
val symbolTable = parser.load()
} catch (e: Exception) {
fail("threw! $e")
}
// then
assertEquals("cc", actual?.name)
}

override fun getTestDataPath(): String {
Expand Down

0 comments on commit bee49f9

Please sign in to comment.