Skip to content

Commit

Permalink
Merge pull request #17 from Etive-Mor/support-multi-fuel-types
Browse files Browse the repository at this point in the history
Support multi fuel types
  • Loading branch information
liamlaverty committed Apr 22, 2024
2 parents 00d16d3 + f837676 commit 0385a72
Show file tree
Hide file tree
Showing 7 changed files with 528 additions and 68 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -62,31 +62,6 @@ public void TestGetMassOfCo2EmissionsThrowsExceptionOnInvalidFuel(TypeOfFuel fue
Assert.ThrowsException<ArgumentException>(() => fuelCalculation.GetMassOfCo2Emissions(fuelType, fuelConsumption));
}

/// <summary>
/// Tests that, when passed a zero value for fuel consumption, an ArgumentOutOfRangeException is thrown.
/// </summary>
[TestMethod]
[DataRow(TypeOfFuel.DIESEL_OR_GASOIL)]
[DataRow(TypeOfFuel.LIGHTFUELOIL)]
[DataRow(TypeOfFuel.HEAVYFUELOIL)]
[DataRow(TypeOfFuel.LIQUIFIEDPETROLEUM_PROPANE)]
[DataRow(TypeOfFuel.LIQUIFIEDPETROLEUM_BUTANE)]
[DataRow(TypeOfFuel.ETHANE)]
[DataRow(TypeOfFuel.LIQUIFIEDNATURALGAS)]
[DataRow(TypeOfFuel.METHANOL)]
[DataRow(TypeOfFuel.ETHANOL)]
[DataRow(TypeOfFuel.UNKNOWN)]
[DataRow(TypeOfFuel.OTHER)]
public void TestGetMassOfCo2EmissionsThrowsExceptionOnZeroConsumptionValue(TypeOfFuel fuelType)
{
// Arrange, set the fuel consumption value to 0 grams (an invalid number)
var fuelConsumption = 0;

var fuelCalculation = new ShipMassOfCo2EmissionsCalculatorService();

// Act & Assert
Assert.ThrowsException<ArgumentOutOfRangeException>(() => fuelCalculation.GetMassOfCo2Emissions(fuelType, fuelConsumption));
}

/// <summary>
/// Tests that, when passed a negative value for fuel consumption, an ArgumentOutOfRangeException is thrown.
Expand Down
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 @@ -24,7 +24,7 @@ internal class ShipMassOfCo2EmissionsCalculatorService : IShipMassOfCo2Emissions
/// </exception>
public double GetMassOfCo2Emissions(TypeOfFuel fuelType, double fuelConsumptionMassInGrams)
{
if (fuelConsumptionMassInGrams <= 0)
if (fuelConsumptionMassInGrams < 0)
{
throw new ArgumentOutOfRangeException("Fuel consumption mass must be a positive value",
nameof(fuelConsumptionMassInGrams));
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; }

Check warning on line 179 in EtiveMor.OpenImoCiiCalculator/EtiveMor.OpenImoCiiCalculator.Core/ShipCarbonIntensityCalculator.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'FuelConsumption' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 179 in EtiveMor.OpenImoCiiCalculator/EtiveMor.OpenImoCiiCalculator.Core/ShipCarbonIntensityCalculator.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'FuelConsumption' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,87 @@
using EtiveMor.OpenImoCiiCalculator.Core.Models.Enums;
using EtiveMor.OpenImoCiiCalculator.Core.Services.Impl;
using Newtonsoft.Json;
using System.Net.Http.Headers;

namespace EtiveMor.OpenImoCiiCalculator.DemoConsoleApp
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("---------------------");
Console.WriteLine("Generating a multi-fuel ship report...");
Console.WriteLine("---------------------");

MainMultiFuelCalculation(args);

Console.WriteLine("---------------------");
Console.WriteLine("Completed the multi-fuel ship report...");
Console.WriteLine("---------------------");


Console.WriteLine("---------------------");
Console.WriteLine("Generating a single-fuel ship report...");
Console.WriteLine("---------------------");

MainOneFuelCalculation(args);

Console.WriteLine("---------------------");
Console.WriteLine("Completed the single-fuel ship report...");
Console.WriteLine("---------------------");
}



/// <summary>
/// Runs the single fuel calculation with sample data
/// </summary>
/// <param name="args"></param>
static void Old_MainOneFuelCalculation(string[] args)
{
Console.WriteLine("Generating a ship result now...");

var calculator = new ShipCarbonIntensityCalculator();

double fuelConsumptionInMegaTons = 19_000;

var result = calculator.CalculateAttainedCiiRating(
ShipType.RoRoPassengerShip,
grossTonnage: 25_000,
deadweightTonnage: 0,
distanceTravelled: 150_000,
TypeOfFuel.DIESEL_OR_GASOIL,
fuelConsumption: fuelConsumptionInMegaTons * 1_000_000,
2019);


string json = JsonConvert.SerializeObject(result, Formatting.Indented);
Console.WriteLine(json);
Console.WriteLine("Press any key to finish");
Console.ReadKey();
}



/// <summary>
/// Runs the single fuel calculation with sample data
/// </summary>
/// <param name="args"></param>
static void MainOneFuelCalculation(string[] args)
{
Console.WriteLine("Generating a ship result now...");

var calculator = new ShipCarbonIntensityCalculator();

double fuelConsumptionInMegaTons = 19_000;

var result = calculator.CalculateAttainedCiiRating(
ShipType.RoRoPassengerShip,
grossTonnage: 25000,
grossTonnage: 25_000,
deadweightTonnage: 0,
distanceTravelled: 150000,
distanceTravelled: 150_000,
TypeOfFuel.DIESEL_OR_GASOIL,
fuelConsumption: 1.9e+10,
fuelConsumption: fuelConsumptionInMegaTons * 1_000_000,
2019);


Expand All @@ -28,5 +91,44 @@ static void Main(string[] args)
Console.WriteLine("Press any key to finish");
Console.ReadKey();
}



/// <summary>
/// Runs the multi-fuel calculation with sample data
/// </summary>
/// <param name="args"></param>
static void MainMultiFuelCalculation(string[] args)
{
var calculator = new ShipCarbonIntensityCalculator();

double fuelConsumptionDieselInMegaTons = 12_500;
double fuelConsumptionLightFuelInMegaTons = 10_000; // 35_000;


var result = calculator.CalculateAttainedCiiRating(
ShipType.RoRoPassengerShip,
grossTonnage: 25_000,
deadweightTonnage: 0,
distanceTravelled: 150_000,
new List<FuelTypeConsumption> {
new FuelTypeConsumption
{
FuelConsumption = fuelConsumptionDieselInMegaTons * 1_000_000,
FuelType = TypeOfFuel.DIESEL_OR_GASOIL
},
new FuelTypeConsumption
{
FuelConsumption = fuelConsumptionLightFuelInMegaTons * 1_000_000,
FuelType = TypeOfFuel.LIGHTFUELOIL
}
},
2019);

string json = JsonConvert.SerializeObject(result, Formatting.Indented);
Console.WriteLine(json);
Console.WriteLine("Press any key to finish");
Console.ReadKey();
}
}
}
Loading

0 comments on commit 0385a72

Please sign in to comment.