using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Buffers.Text;
namespace EnthalpyCalc
{
public record struct Temperature(double Value)
{
public static implicit operator double(Temperature temp) => temp.Value;
}
public record class BaseComp(double [] IdealVapCP, double MW);
public class Program
{
const double BaseT = 273.15 + 25;
const double BaseT1 = BaseT;
const double BaseT2 = BaseT1 * BaseT1;
const double BaseT3 = BaseT2 * BaseT1;
const double BaseT4 = BaseT2 * BaseT2;
const double BaseT5 = BaseT4 * BaseT1;
static readonly Temperature TestTemp;
static readonly BaseComp TestBaseComp;
static Program()
{
TestTemp = new Temperature(256);
TestBaseComp = new BaseComp(new double[] { 1234, 4547, 2341, 9097, 8697 }, 5235.0);
}
static double StandardRun(Func<Temperature, BaseComp, double> computeEnthalpy)
{
double x = 0;
for(int i = 0; i < 500; i++)
x += computeEnthalpy(TestTemp, TestBaseComp);
return x;
}
static double UseLoops(Temperature Tk, BaseComp sc)
{
double VE = 0;
double temp = Tk;
double baseT = BaseT;
double[] cp = sc.IdealVapCP;
if (cp != null)
{
for (int i = 0; i < 5; i++)
{
VE += cp[i] * (temp - baseT) / (i + 1);
temp *= Tk;
baseT *= BaseT;
}
}
return VE * sc.MW;
}
static double UseLoopsPreRangeCheck(Temperature Tk, BaseComp sc)
{
double VE = 0;
double temp = Tk;
double baseT = BaseT;
double[] cp = sc.IdealVapCP;
if (cp != null && cp.Length >= 5)
{
for (int i = 0; i < 5; i++)
{
VE += cp[i] * (temp - baseT) / (i + 1);
temp *= Tk;
baseT *= BaseT;
}
}
return VE * sc.MW;
}
static double Plain0(Temperature Tk, BaseComp sc)
{
double VE = 0;
double Tk1 = Tk;
double[] cp = sc.IdealVapCP;
if (cp != null)
{
VE = cp[0] * (Tk1 - BaseT1)
+ cp[1] * (Tk1 * Tk1 - BaseT2) / 2
+ cp[2] * (Tk1 * Tk1 * Tk1 - BaseT3) / 3
+ cp[3] * (Tk1 * Tk1 * Tk1 * Tk1 - BaseT4) / 4
+ cp[4] * (Tk1 * Tk1 * Tk1 * Tk1 * Tk1 - BaseT5) / 5;
}
return VE * sc.MW;
}
static double Plain(Temperature Tk, BaseComp sc)
{
double VE = 0;
double Tk1 = Tk;
double Tk2 = Tk1 * Tk1;
double[] cp = sc.IdealVapCP;
if (cp != null)
{
VE = cp[0] * (Tk1 - BaseT1)
+ cp[1] * (Tk2 - BaseT2) / 2
+ cp[2] * (Tk2 * Tk1 - BaseT3) / 3
+ cp[3] * (Tk2 * Tk2 - BaseT4) / 4
+ cp[4] * (Tk1 * Tk2 * Tk2 - BaseT5) / 5;
}
return VE * sc.MW;
}
static double PlainPreRangeCheck(Temperature Tk, BaseComp sc)
{
double VE = 0;
double Tk1 = Tk;
double Tk2 = Tk1 * Tk1;
double[] cp = sc.IdealVapCP;
if (cp != null && cp.Length >= 5)
{
VE = cp[0] * (Tk1 - BaseT1)
+ cp[1] * (Tk2 - BaseT2) / 2
+ cp[2] * (Tk2 * Tk1 - BaseT3) / 3
+ cp[3] * (Tk2 * Tk2 - BaseT4) / 4
+ cp[4] * (Tk1 * Tk2 * Tk2 - BaseT5) / 5;
}
return VE * sc.MW;
}
static double PlainReverse(Temperature Tk, BaseComp sc)
{
double VE = 0;
double Tk1 = Tk;
double Tk2 = Tk1 * Tk1;
double[] cp = sc.IdealVapCP;
if (cp != null && cp.Length >= 5)
{
VE = cp[4] * (Tk1 * Tk2 * Tk2 - BaseT5) / 5
+ cp[3] * (Tk2 * Tk2 - BaseT4) / 4
+ cp[2] * (Tk2 * Tk1 - BaseT3) / 3
+ cp[1] * (Tk2 - BaseT2) / 2
+ cp[0] * (Tk1 - BaseT1);
}
return VE * sc.MW;
}
static double PlainPreRangeCheckReverse(Temperature Tk, BaseComp sc)
{
double VE = 0;
double Tk1 = Tk;
double Tk2 = Tk1 * Tk1;
double[] cp = sc.IdealVapCP;
if (cp != null && cp.Length >= 5)
{
VE = cp[4] * (Tk1 * Tk2 * Tk2 - BaseT5) / 5
+ cp[3] * (Tk2 * Tk2 - BaseT4) / 4
+ cp[2] * (Tk2 * Tk1 - BaseT3) / 3
+ cp[1] * (Tk2 - BaseT2) / 2
+ cp[0] * (Tk1 - BaseT1);
}
return VE * sc.MW;
}
[Benchmark] public void UseLoops() => StandardRun(UseLoops);
[Benchmark] public void UseLoopsPreRangeCheck() => StandardRun(UseLoopsPreRangeCheck);
[Benchmark] public void Plain0() => StandardRun(Plain0);
[Benchmark] public void Plain() => StandardRun(Plain);
[Benchmark] public void PlainPreRangeCheck() => StandardRun(PlainPreRangeCheck);
[Benchmark] public void PlainReverse() => StandardRun(PlainReverse);
[Benchmark] public void PlainPreRangeCheckReverse() => StandardRun(PlainPreRangeCheckReverse);
public static void Main()
{
Console.WriteLine("Benchmarking...");
BenchmarkRunner.Run(typeof(Program).Assembly);
}
}
}