Skip to content

Commit

Permalink
improved handling if not earliest forested value if provided
Browse files Browse the repository at this point in the history
  • Loading branch information
lwluc committed Dec 13, 2024
1 parent f0de9c1 commit d596f0f
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
import de.envite.greenbpm.carbonreductor.core.domain.model.CarbonReductorConfiguration;
import de.envite.greenbpm.carbonreductor.core.domain.model.ExceptionHandlingEnum;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Milestone;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Threshold;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.ProcessDuration;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Threshold;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.location.Location;
import io.github.domainprimitives.type.ValueObject;
import org.springframework.stereotype.Component;

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;


@Component
Expand Down Expand Up @@ -54,9 +56,12 @@ private Threshold mapIfEnabled(boolean enabled, String thresholdValue) {
}

public Map<String, Object> mapFromDomain(CarbonReduction output, Map<String, Object> allVariables) {
final Double carbonWithoutOptimization = Optional.ofNullable(output.getCarbonWithoutOptimization())
.map(ValueObject::getValue)
.orElse(null);
Map<String, Object> variables = new HashMap<>();
variables.put("executionDelayed", output.getDelay().isExecutionDelayed());
variables.put("carbonWithoutOptimization", output.getCarbonWithoutOptimization().getValue());
variables.put("carbonWithoutOptimization", carbonWithoutOptimization);
variables.put("optimalForecastedCarbon", output.getOptimalForecastedCarbon().getValue());
variables.put("savedCarbonPercentage", output.getSavedCarbonPercentage().getValue());
variables.put("reducedCarbon", output.calculateReduction().getValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,29 @@ void should_map_all_fields_to_map() {
softAssertions.assertThat(result.get("milestone")).isEqualTo(mileStoneDateString);
softAssertions.assertAll();
}

@Test
void should_map_mandatory_fields_to_map() {
final String mileStoneDateString = "2023-09-08T14:13:40.764+02:00";
CarbonReduction carbonReduction = new CarbonReduction(
new Delay(true, 3),
null,
new Carbon(2.0),
new Percentage(3.0)
);
Map<String, Object> variables = Map.of("milestone", mileStoneDateString);

Map<String, Object> result = classUnderTest.mapFromDomain(carbonReduction, variables);

SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(result.get("executionDelayed")).isEqualTo(carbonReduction.getDelay().isExecutionDelayed());
softAssertions.assertThat(result.get("carbonWithoutOptimization")).isNull();
softAssertions.assertThat(result.get("optimalForecastedCarbon")).isEqualTo(carbonReduction.getOptimalForecastedCarbon().getValue());
softAssertions.assertThat(result.get("savedCarbonPercentage")).isEqualTo(carbonReduction.getSavedCarbonPercentage().getValue());
softAssertions.assertThat(result.get("reducedCarbon")).isEqualTo(carbonReduction.calculateReduction().getValue());
softAssertions.assertThat(result.get("delayedBy")).isEqualTo(carbonReduction.getDelay().getDelayedBy());
softAssertions.assertThat(result.get("milestone")).isEqualTo(mileStoneDateString);
softAssertions.assertAll();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
public class CarbonReductorOutputVariable {

private boolean executionDelayed;
private double carbonWithoutOptimization;
private Double carbonWithoutOptimization;
private double optimalForecastedCarbon;
private double savedCarbonPercentage;
private double carbonReduction;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import de.envite.greenbpm.carbonreductor.core.domain.model.CarbonReductorConfiguration;
import de.envite.greenbpm.carbonreductor.core.domain.model.ExceptionHandlingEnum;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Milestone;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Threshold;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.ProcessDuration;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Threshold;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.location.Location;
import io.github.domainprimitives.type.ValueObject;
import org.springframework.stereotype.Component;

import java.time.OffsetDateTime;
import java.time.format.DateTimeParseException;
import java.util.Optional;

import static java.lang.String.format;
import static java.time.format.DateTimeFormatter.ofPattern;
Expand Down Expand Up @@ -55,11 +57,14 @@ private ProcessDuration mapIfNotNull(String input) {
}

public CarbonReductorOutputVariable mapFromDomain(CarbonReduction output) {
final Double carbonWithoutOptimization = Optional.ofNullable(output.getCarbonWithoutOptimization())
.map(ValueObject::getValue)
.orElse(null);
CarbonReductorOutputVariable outputVariable = new CarbonReductorOutputVariable();
outputVariable.setExecutionDelayed(output.getDelay().isExecutionDelayed());
outputVariable.setDelayedBy(output.getDelay().getDelayedBy());
outputVariable.setOptimalForecastedCarbon(output.getOptimalForecastedCarbon().getValue());
outputVariable.setCarbonWithoutOptimization(output.getCarbonWithoutOptimization().getValue());
outputVariable.setCarbonWithoutOptimization(carbonWithoutOptimization);
outputVariable.setSavedCarbonPercentage(output.getSavedCarbonPercentage().getValue());
outputVariable.setCarbonReduction(output.calculateReduction().getValue());
return outputVariable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import de.envite.greenbpm.carbonreductor.core.domain.model.CarbonReduction;
import de.envite.greenbpm.carbonreductor.core.domain.model.CarbonReductorConfiguration;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Milestone;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Threshold;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.ProcessDuration;
import de.envite.greenbpm.carbonreductor.core.domain.model.input.Threshold;
import de.envite.greenbpm.carbonreductor.core.domain.model.output.Carbon;
import de.envite.greenbpm.carbonreductor.core.domain.model.output.Delay;
import de.envite.greenbpm.carbonreductor.core.domain.model.output.Percentage;
Expand Down Expand Up @@ -34,6 +34,15 @@ public static CarbonReduction createCarbonReductorOutput() {
);
}

public static CarbonReduction createCarbonReductorOutputWithoutCurrentValue() {
return new CarbonReduction(
new Delay(true, 3),
null,
new Carbon(2.0),
new Percentage(3.0)
);
}

public static CarbonReductorConfiguration createSLABasedCarbonReductorInput(OffsetDateTime timestamp) {
return new CarbonReductorConfiguration(
NORWAY_EAST.asLocation(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

import java.time.*;

import static de.envite.greenbpm.carbonreductorconnector.adapter.in.zeebe.test.utils.TestDataGenerator.createCarbonReductorOutput;
import static de.envite.greenbpm.carbonreductorconnector.adapter.in.zeebe.test.utils.TestDataGenerator.createInputVariables;
import static de.envite.greenbpm.carbonreductorconnector.adapter.in.zeebe.test.utils.TestDataGenerator.*;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

class CarbonReductorVariableMapperTest {
Expand Down Expand Up @@ -54,19 +53,38 @@ void should_throw_on_invalid_date() {
}
}

@Test
void should_map_all_fields_from_domain() {
CarbonReduction outputDDD = createCarbonReductorOutput();
@Nested
class MapFromDomain {
@Test
void should_map_all_fields_from_domain() {
CarbonReduction outputDDD = createCarbonReductorOutput();

CarbonReductorOutputVariable result = classUnderTest.mapFromDomain(outputDDD);

SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(result.isExecutionDelayed()).isEqualTo(outputDDD.getDelay().isExecutionDelayed());
softAssertions.assertThat(result.getDelayedBy()).isEqualTo(outputDDD.getDelay().getDelayedBy());
softAssertions.assertThat(result.getOptimalForecastedCarbon()).isEqualTo(outputDDD.getOptimalForecastedCarbon().getValue());
softAssertions.assertThat(result.getCarbonWithoutOptimization()).isEqualTo(outputDDD.getCarbonWithoutOptimization().getValue());
softAssertions.assertThat(result.getSavedCarbonPercentage()).isEqualTo(outputDDD.getSavedCarbonPercentage().getValue());
softAssertions.assertThat(result.getCarbonReduction()).isEqualTo(outputDDD.calculateReduction().getValue());
softAssertions.assertAll();
}

@Test
void should_map_mandatory_fields_from_domain() {
CarbonReduction outputDDD = createCarbonReductorOutputWithoutCurrentValue();

CarbonReductorOutputVariable result = classUnderTest.mapFromDomain(outputDDD);
CarbonReductorOutputVariable result = classUnderTest.mapFromDomain(outputDDD);

SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(result.isExecutionDelayed()).isEqualTo(outputDDD.getDelay().isExecutionDelayed());
softAssertions.assertThat(result.getDelayedBy()).isEqualTo(outputDDD.getDelay().getDelayedBy());
softAssertions.assertThat(result.getOptimalForecastedCarbon()).isEqualTo(outputDDD.getOptimalForecastedCarbon().getValue());
softAssertions.assertThat(result.getCarbonWithoutOptimization()).isEqualTo(outputDDD.getCarbonWithoutOptimization().getValue());
softAssertions.assertThat(result.getSavedCarbonPercentage()).isEqualTo(outputDDD.getSavedCarbonPercentage().getValue());
softAssertions.assertThat(result.getCarbonReduction()).isEqualTo(outputDDD.calculateReduction().getValue());
softAssertions.assertAll();
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(result.isExecutionDelayed()).isEqualTo(outputDDD.getDelay().isExecutionDelayed());
softAssertions.assertThat(result.getDelayedBy()).isEqualTo(outputDDD.getDelay().getDelayedBy());
softAssertions.assertThat(result.getOptimalForecastedCarbon()).isEqualTo(outputDDD.getOptimalForecastedCarbon().getValue());
softAssertions.assertThat(result.getCarbonWithoutOptimization()).isNull();
softAssertions.assertThat(result.getSavedCarbonPercentage()).isEqualTo(outputDDD.getSavedCarbonPercentage().getValue());
softAssertions.assertThat(result.getCarbonReduction()).isEqualTo(outputDDD.calculateReduction().getValue());
softAssertions.assertAll();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,15 @@

import de.envite.greenbpm.api.carbonawarecomputing.model.EmissionsData;
import de.envite.greenbpm.carbonreductor.core.domain.model.EmissionTimeframe;
import de.envite.greenbpm.carbonreductor.core.domain.model.emissionframe.EarliestForecastedValue;
import de.envite.greenbpm.carbonreductor.core.domain.model.emissionframe.ForecastedValue;
import de.envite.greenbpm.carbonreductor.core.domain.model.emissionframe.OptimalTime;

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class CarbonAwareComputingMapper {

public EmissionTimeframe mapToDomain(EmissionsData emissionsData) {
if (emissionsData.getTimestamp() != null && emissionsData.getTimestamp().isAfter(OffsetDateTime.now(ZoneOffset.UTC))) {
return new EmissionTimeframe(
new OptimalTime(emissionsData.getTimestamp()),
new EarliestForecastedValue(0.0),
new ForecastedValue(emissionsData.getValue())
);
}

return new EmissionTimeframe(
new OptimalTime(emissionsData.getTimestamp()),
new EarliestForecastedValue(emissionsData.getValue()),
null,
new ForecastedValue(emissionsData.getValue())
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public class CarbonReduction extends Aggregate {

private final Delay delay;

/**
* CO2eq if executed immediately.
* Could be null because some data provider only serve the {@link CarbonReduction#optimalForecastedCarbon}.
*/
private final Carbon carbonWithoutOptimization;
private final Carbon optimalForecastedCarbon;
private final Percentage savedCarbonPercentage;
Expand All @@ -26,13 +30,15 @@ public CarbonReduction(Delay delay, Carbon carbonWithoutOptimization, Carbon opt
@Override
protected void validate() {
validateNotNull(delay, "Delay");
validateNotNull(carbonWithoutOptimization, "original Carbon");
validateNotNull(optimalForecastedCarbon, "actual Carbon");
validateNotNull(savedCarbonPercentage, "saved Carbon");
evaluateValidations();
}

public Carbon calculateReduction() {
if (carbonWithoutOptimization == null) {
return optimalForecastedCarbon;
}
return new Carbon(carbonWithoutOptimization.getValue() - optimalForecastedCarbon.getValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,22 @@
@EqualsAndHashCode(callSuper = false)
public class EmissionTimeframe extends Aggregate {

/**
* Optimal execution time with lowest CO2eq for the specific timeframe.
* Value is represented by {@link EmissionTimeframe#optimalValue}.
*/
private final OptimalTime optimalTime;

/**
* Earliest forecasted value (CO2eq). Could be null because some data provider only serve the {@link EmissionTimeframe#optimalValue}.
* Usefully for comparing the savings.
*/
private final EarliestForecastedValue earliestForecastedValue;

/**
* Optimal forecasted value for the execution with lowest CO2eq for the specific timeframe.
* Execution time when this value could be reached is represented by {@link EmissionTimeframe#optimalTime}.
*/
private final ForecastedValue optimalValue;

public EmissionTimeframe(OptimalTime optimalTime, EarliestForecastedValue earliestForecastedValue, ForecastedValue optimalValue) {
Expand All @@ -25,21 +39,29 @@ public EmissionTimeframe(OptimalTime optimalTime, EarliestForecastedValue earlie
@Override
protected void validate() {
validateNotNull(optimalTime, "Optimal Time");
validateNotNull(earliestForecastedValue, "Rating");
validateNotNull(optimalValue, "ForecastedValue");
evaluateValidations();
}

public boolean isCleanerEnergyInFuture() {
if (earliestForecastedValue == null) {
return optimalTime.isInFuture();
}
final boolean emissionReduction = earliestForecastedValue.getValue() > optimalValue.getValue();
return emissionReduction && optimalTime.isInFuture();
}

public double calculateSavedCarbonDelta() {
if (earliestForecastedValue == null) {
return 0.0;
}
return earliestForecastedValue.getValue() - optimalValue.getValue();
}

public double calculateSavedCarbonPercentage() {
if (earliestForecastedValue == null) {
return 100;
}
double difference = earliestForecastedValue.getValue() - optimalValue.getValue();
return (difference / earliestForecastedValue.getValue()) * 100;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import de.envite.greenbpm.carbonreductor.core.domain.model.output.Percentage;
import de.envite.greenbpm.carbonreductor.core.usecase.in.DelayCalculator;
import de.envite.greenbpm.carbonreductor.core.usecase.out.CarbonEmissionQuery;
import io.github.domainprimitives.type.ValueObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -18,6 +19,7 @@
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.Optional;

import static de.envite.greenbpm.carbonreductor.core.domain.model.ExceptionHandlingEnum.CONTINUE_ON_EXCEPTION;

Expand Down Expand Up @@ -50,22 +52,27 @@ public CarbonReduction calculateDelay(CarbonReductorConfiguration input) throws
emissionTimeframe.calculateSavedCarbonDelta()
);

final Carbon carbonWithoutOptimization = Optional.ofNullable(emissionTimeframe.getEarliestForecastedValue())
.map(ValueObject::getValue)
.map(Carbon::new)
.orElse(null);

if (isDelayNecessary && isGreaterThanMinimumThreshold) {
final long optimalTime = emissionTimeframe.getOptimalTime().asOffsetDateTime().toInstant().toEpochMilli();
final long delayedBy = optimalTime - OffsetDateTime.now(ZoneOffset.UTC).toInstant().toEpochMilli();
final boolean executionDelayed = !input.isMeasurementOnly();
return new CarbonReduction(
new Delay(executionDelayed, delayedBy),
new Carbon(emissionTimeframe.getEarliestForecastedValue().getValue()),
carbonWithoutOptimization,
new Carbon(emissionTimeframe.getOptimalValue().getValue()),
new Percentage(emissionTimeframe.calculateSavedCarbonPercentage())
);
}
// execution is optimal currently
return new CarbonReduction(
new Delay(false, 0),
new Carbon(emissionTimeframe.getEarliestForecastedValue().getValue()),
new Carbon(emissionTimeframe.getEarliestForecastedValue().getValue()),
carbonWithoutOptimization,
new Carbon(emissionTimeframe.getOptimalValue().getValue()),
new Percentage(0.0)
);
}
Expand Down
Loading

0 comments on commit d596f0f

Please sign in to comment.