Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi fuel types #17

Merged
merged 2 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

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 @@
}

/// <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 @@
AttainedCii = attainedCiiInYear,
RequiredCii = requiredCiiInYear,
Rating = rating,
VectorBoundariesForYear = vectors
VectorBoundariesForYear = vectors,
CalculatedCo2eEmissions = shipCo2Emissions,
CalculatedShipCapacity = shipCapacity,
CalculatedTransportWork = transportWork
});
}

Expand Down Expand Up @@ -102,5 +172,17 @@
}

}

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