Skip to content

Commit

Permalink
adds support & unit tests for multiple fuel types
Browse files Browse the repository at this point in the history
  • Loading branch information
liamlaverty committed Apr 22, 2024
1 parent 00d16d3 commit ea87381
Show file tree
Hide file tree
Showing 5 changed files with 348 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public class CalculatorTests
/// Tests a known and pre-calculated set of inputs for a RoRoPassengerShip
/// </summary>
[TestMethod]
public void TestCalculator()
public void TestCalculatorSingleFuel()
{
var _calc = new ShipCarbonIntensityCalculator();

var result = _calc.CalculateAttainedCiiRating(
ShipType.RoRoPassengerShip,
grossTonnage: 25000,
deadweightTonnage: 0,
distanceTravelled: 150000,
ShipType.RoRoPassengerShip,
grossTonnage: 25000,
deadweightTonnage: 0,
distanceTravelled: 150000,
TypeOfFuel.DIESEL_OR_GASOIL,
fuelConsumption: 1.9e+10,
2019
Expand All @@ -42,6 +42,78 @@ public void TestCalculator()
Assert.IsTrue(result.Results.Count(result => result.IsEstimatedYear) == 11);
}

/// <summary>
/// Tests a known and pre-calculated set of inputs for a RoRoPassengerShip in the multi-fuel scenario
/// </summary>
[TestMethod]
public void TestCalculatorMultiFuel()
{
var _calc = new ShipCarbonIntensityCalculator();

var result = _calc.CalculateAttainedCiiRating(
ShipType.RoRoPassengerShip,
grossTonnage: 25000,
deadweightTonnage: 0,
distanceTravelled: 150000,
new List<FuelTypeConsumption> {
new FuelTypeConsumption
{
FuelConsumption = 1.9e+10,
FuelType = TypeOfFuel.DIESEL_OR_GASOIL
}
},
2019
);

System.Diagnostics.Debug.WriteLine("Basic result is:");

string json = JsonConvert.SerializeObject(result, Formatting.Indented);
System.Diagnostics.Debug.WriteLine(json);

Assert.IsNotNull(result);
Assert.AreEqual(result.Results.Count(), 12);

Assert.IsTrue(result.Results.Count(result => result.IsMeasuredYear) == 1);
Assert.IsTrue(result.Results.Count(result => result.IsEstimatedYear) == 11);
}


[TestMethod]
public void TestCalculatorMultiFuelSameResultAsSingleFuel()
{
var _calc = new ShipCarbonIntensityCalculator();

var resultMultiFuel = _calc.CalculateAttainedCiiRating(
ShipType.RoRoPassengerShip,
grossTonnage: 25000,
deadweightTonnage: 0,
distanceTravelled: 150000,
new List<FuelTypeConsumption> {
new FuelTypeConsumption
{
FuelConsumption = 1.9e+10,
FuelType = TypeOfFuel.DIESEL_OR_GASOIL
}
},
2019
);

var resultSingleFuel = _calc.CalculateAttainedCiiRating(
ShipType.RoRoPassengerShip,
grossTonnage: 25000,
deadweightTonnage: 0,
distanceTravelled: 150000,
TypeOfFuel.DIESEL_OR_GASOIL,
fuelConsumption: 1.9e+10,
2019
);

var singleFuelAsJsonObj = JsonConvert.SerializeObject(resultSingleFuel);
var multiFuelAsJsonObj = JsonConvert.SerializeObject(resultMultiFuel);

Assert.AreEqual(singleFuelAsJsonObj, multiFuelAsJsonObj);
}



/// <summary>
Expand Down Expand Up @@ -141,7 +213,7 @@ public void TestRoRoPassengerShipReturnsExpectedValues(
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2029, ImoCiiRating.E, 7.240951252672751, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2030, ImoCiiRating.E, 7.0664704995963, 8.549333333333333)]
[TestMethod]
public void TestBulkCarrierReturnsExpectedValues(
public void TestMultiFuelBulkCarrierReturnsExpectedValues(
ShipType shipType,
double deadweightTonnage,
double grossTonnage,
Expand Down Expand Up @@ -184,5 +256,85 @@ public void TestBulkCarrierReturnsExpectedValues(
Assert.AreEqual(result.Results.First(c => c.Year == year).Rating, expectedRating, $"{nameof(expectedRating)} value was incorrect");
Assert.AreNotEqual(result.Results.First(c => c.Year == year).IsMeasuredYear, result.Results.First(c => c.Year == year).IsEstimatedYear);
}






/// <summary>
/// Tests a known and pre-calculated set of inputs for a RoRoPassengerShip in the multi-fuel scenario
/// </summary>
/// <param name="shipType"></param>
/// <param name="deadweightTonnage"></param>
/// <param name="grossTonnage"></param>
/// <param name="typeOfFuel"></param>
/// <param name="fuelConsumptionInGrams"></param>
/// <param name="year"></param>
/// <param name="expectedRating"></param>
/// <param name="expectedRequiredCii"></param>
/// <param name="expectedAttainedCii"></param>
/// <param name="expectedArRatio"></param>
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2019, ImoCiiRating.C, 8.724037653822592, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2020, ImoCiiRating.C, 8.636797277284366, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2021, ImoCiiRating.C, 8.54955690074614, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2022, ImoCiiRating.C, 8.462316524207914, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2023, ImoCiiRating.C, 8.287835771131462, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2024, ImoCiiRating.C, 8.11335501805501, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2025, ImoCiiRating.D, 7.938874264978558, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2026, ImoCiiRating.D, 7.764393511902107, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2027, ImoCiiRating.D, 7.589912758825655, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2028, ImoCiiRating.D, 7.415432005749203, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2029, ImoCiiRating.E, 7.240951252672751, 8.549333333333333)]
[DataRow(ShipType.BulkCarrier, 25000, 0, TypeOfFuel.DIESEL_OR_GASOIL, 1e+10, 2030, ImoCiiRating.E, 7.0664704995963, 8.549333333333333)]
[TestMethod]
public void TestBulkCarrierReturnsExpectedValues(
ShipType shipType,
double deadweightTonnage,
double grossTonnage,
TypeOfFuel typeOfFuel,
double fuelConsumptionInGrams,
int year,
ImoCiiRating expectedRating,
double expectedRequiredCii,
double expectedAttainedCii)
{
double expectedArRatio = expectedAttainedCii / expectedRequiredCii;

var _calc = new ShipCarbonIntensityCalculator();

var result = _calc.CalculateAttainedCiiRating(
shipType,
grossTonnage: grossTonnage,
deadweightTonnage: deadweightTonnage,
distanceTravelled: 150000,
new List<FuelTypeConsumption> {
new FuelTypeConsumption
{
FuelConsumption = fuelConsumptionInGrams,
FuelType = typeOfFuel
}
},
year
);


string json = JsonConvert.SerializeObject(result, Formatting.Indented);
System.Diagnostics.Debug.WriteLine(json);

Assert.IsNotNull(result);
Assert.AreEqual(result.Results.Count(), 12);

Assert.IsTrue(result.Results.Count(result => result.IsMeasuredYear) == 1);
Assert.IsTrue(result.Results.Count(result => result.IsEstimatedYear) == 11);

Assert.AreEqual(result.Results.First(c => c.Year == year).Year, year, $"{nameof(year)} value was incorrect");
Assert.AreEqual(result.Results.First(c => c.Year == year).VectorBoundariesForYear.ShipType, shipType, $"{nameof(shipType)} value was incorrect");
Assert.AreEqual(result.Results.First(c => c.Year == year).RequiredCii, expectedRequiredCii, $"{nameof(expectedRequiredCii)} value was incorrect");
Assert.AreEqual(result.Results.First(c => c.Year == year).AttainedRequiredRatio, expectedArRatio, $"{nameof(expectedArRatio)} value was incorrect");
Assert.AreEqual(result.Results.First(c => c.Year == year).AttainedCii, expectedAttainedCii, $"{nameof(expectedAttainedCii)} value was incorrect");
Assert.AreEqual(result.Results.First(c => c.Year == year).Rating, expectedRating, $"{nameof(expectedRating)} value was incorrect");
Assert.AreNotEqual(result.Results.First(c => c.Year == year).IsMeasuredYear, result.Results.First(c => c.Year == year).IsEstimatedYear);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ public class CalculationResult
public CalculationResult(IEnumerable<ResultYear> results)
{
Results = results;

}



/// <summary>
/// Contains a collection of CII Ratings for each year
/// between 2019 and 2030
Expand All @@ -35,6 +34,11 @@ public class ResultYear
///
/// if true, the CII rating, and all other values are measured
/// if false, the CII rating, and all other values are estimates
///
/// If true, the <see cref="CalculatedCo2eEmissions"/>, <see cref="CalculatedShipCapacity"/>, and
/// <see cref="CalculatedTransportWork"/> will all be generated against this year. If false, these
/// properties are equivalent to the most recent year data was provided for (for example, if this year is
/// 2026, and data exists for 2020 and 2021, the properties will match the 2021 data).
/// </summary>
public bool IsMeasuredYear { get; set; }

Expand All @@ -45,11 +49,40 @@ public class ResultYear
/// if false, the CII rating, and all other values are measured
/// </summary>
public bool IsEstimatedYear { get { return !IsMeasuredYear; } }

/// <summary>
/// The year this result references
/// </summary>
public int Year { get; set; }

/// <summary>
/// The ship's IMO CII Rating, from A to E
/// </summary>
public ImoCiiRating Rating { get; set; }

/// <summary>
/// The ship's required carbon intensity for this year
/// </summary>
public double RequiredCii { get; set; }

/// <summary>
/// The ship's attained Carbon Intensity Indicator for this year
/// </summary>
public double AttainedCii { get; set; }

/// <summary>
/// The Co2e Emissions calculated for this year
/// </summary>
public double CalculatedCo2eEmissions { get; set; }
/// <summary>
/// The Ship Capacity calculated for this year
/// </summary>
public double CalculatedShipCapacity { get; set; }
/// <summary>
/// The Transport Work calculated for this year
/// </summary>
public double CalculatedTransportWork { get; set; }

/// <summary>
/// This is the ratio of Attained:Required CII
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using EtiveMor.OpenImoCiiCalculator.Core.Models.MeasurementModels;
using EtiveMor.OpenImoCiiCalculator.Core.Services;
using EtiveMor.OpenImoCiiCalculator.Core.Services.Impl;
using System.Security.Cryptography.X509Certificates;
using Microsoft.VisualBasic.FileIO;

namespace EtiveMor.OpenImoCiiCalculator.Core
{
Expand All @@ -26,15 +28,80 @@ public ShipCarbonIntensityCalculator()
}

/// <summary>
/// Calculate the attained CII rating for a ship for a given year
///
/// This method accepts multiple fuel types.
/// </summary>
/// <param name="shipType"></param>
/// <param name="shipType">The type of ship</param>
/// <param name="grossTonnage">in long-tons</param>
/// <param name="deadweightTonnage">in long-tons</param>
/// <param name="distanceTravelled">distance travelled in nautical miles</param>
/// <param name="fuelType"></param>
/// <param name="fuelType">The type of fuel</param>
/// <param name="fuelConsumption">quantity of fuel consumed in grams</param>
/// <returns></returns>
/// <returns>
/// A <see cref="CalculationResult"/> containing details of the ship's carbon intensity rating
/// </returns>
public CalculationResult CalculateAttainedCiiRating(
ShipType shipType,
double grossTonnage,
double deadweightTonnage,
double distanceTravelled,
IEnumerable<FuelTypeConsumption> fuelTypeConsumptions,
int targetYear)
{
if (fuelTypeConsumptions == null || fuelTypeConsumptions.Count() == 0)
{
throw new ArgumentException("FuelTypeConsumptions must be provided");
}
double shipCo2Emissions = 0;
foreach (var consumption in fuelTypeConsumptions)
{
shipCo2Emissions += _shipMassOfCo2EmissionsService.GetMassOfCo2Emissions(consumption.FuelType, consumption.FuelConsumption);
}
var shipCapacity = _shipCapacityService.GetShipCapacity(shipType, deadweightTonnage, grossTonnage);
var transportWork = _shipTransportWorkService.GetShipTransportWork(shipCapacity, distanceTravelled);

List<ResultYear> results = new List<ResultYear>();
for (int year = 2019; year <= 2030; year++)
{
var attainedCiiInYear = _carbonIntensityIndicatorService.GetAttainedCarbonIntensity(shipCo2Emissions, transportWork);
var requiredCiiInYear = _carbonIntensityIndicatorService.GetRequiredCarbonIntensity(shipType, shipCapacity, year);

var vectors = _ratingBoundariesService.GetBoundaries(new Ship(shipType, deadweightTonnage, grossTonnage), requiredCiiInYear, year);
var rating = GetImoCiiRatingFromVectors(vectors, attainedCiiInYear, year);

results.Add(new ResultYear
{
IsMeasuredYear = targetYear == year,
Year = year,
AttainedCii = attainedCiiInYear,
RequiredCii = requiredCiiInYear,
Rating = rating,
VectorBoundariesForYear = vectors,
CalculatedCo2eEmissions = shipCo2Emissions,
CalculatedShipCapacity = shipCapacity,
CalculatedTransportWork = transportWork
});
}

return new CalculationResult(results);
}

/// <summary>
/// Calculate the attained CII rating for a ship for a given year
///
/// This method accepts exactly one fuel type. For multiple fuel
/// types, use the <seealso cref="CalculateAttainedCiiRating(ShipType, double, double, double, IEnumerable{FuelTypeConsumption}, int)"/> method
/// </summary>
/// <param name="shipType">The type of ship</param>
/// <param name="grossTonnage">in long-tons</param>
/// <param name="deadweightTonnage">in long-tons</param>
/// <param name="distanceTravelled">distance travelled in nautical miles</param>
/// <param name="fuelType">The type of fuel</param>
/// <param name="fuelConsumption">quantity of fuel consumed in grams</param>
/// <returns>
/// A <see cref="CalculationResult"/> containing details of the ship's carbon intensity rating
/// </returns>
public CalculationResult CalculateAttainedCiiRating(
ShipType shipType,
double grossTonnage,
Expand Down Expand Up @@ -64,7 +131,10 @@ public CalculationResult CalculateAttainedCiiRating(
AttainedCii = attainedCiiInYear,
RequiredCii = requiredCiiInYear,
Rating = rating,
VectorBoundariesForYear = vectors
VectorBoundariesForYear = vectors,
CalculatedCo2eEmissions = shipCo2Emissions,
CalculatedShipCapacity = shipCapacity,
CalculatedTransportWork = transportWork
});
}

Expand Down Expand Up @@ -102,5 +172,17 @@ private ImoCiiRating GetImoCiiRatingFromVectors(ShipDdVectorBoundaries boundarie
}

}

public class AnnaulConsumption
{
public int TargetYear { get; set; }
public IEnumerable<FuelTypeConsumption> FuelConsumption { get; set; }
}

public class FuelTypeConsumption
{
public TypeOfFuel FuelType { get; set; }
public double FuelConsumption { get; set; }
}

}
Loading

0 comments on commit ea87381

Please sign in to comment.