Skip to content

Instantly share code, notes, and snippets.

@JacobYZ
Last active November 7, 2022 07:14
Show Gist options
  • Select an option

  • Save JacobYZ/ebfbf02aa40e4925c822dc71026f6086 to your computer and use it in GitHub Desktop.

Select an option

Save JacobYZ/ebfbf02aa40e4925c822dc71026f6086 to your computer and use it in GitHub Desktop.
crimson-eucalyptus-7759

crimson-eucalyptus-7759

Created with <3 with dartpad.dev.

import 'dart:core';
import 'dart:math';
class TriangularDistribution {
double lowerLimit; //a
double upperLimit; //b
double mode; //c
TriangularDistribution(
{required this.lowerLimit, required this.mode, required this.upperLimit});
double qtri(double p) {
double fc = (mode - lowerLimit) / (upperLimit - lowerLimit);
if (lowerLimit != upperLimit) {
if (p >= 0 && p <= fc) {
return lowerLimit +
sqrt((upperLimit - lowerLimit) * (mode - lowerLimit) * p);
}
if (p >= fc && p <= 1) {
return upperLimit -
sqrt((upperLimit - lowerLimit) * (upperLimit - mode) * (1 - p));
}
}
return mode;
}
}
class Crops {
String name;
bool isRainFed;
TriangularDistribution expectedYield;
TriangularDistribution waterApplied;
TriangularDistribution salePrice;
TriangularDistribution variableCost;
Crops(
{required this.name,
required this.isRainFed,
required this.expectedYield,
required this.waterApplied,
required this.variableCost,
required this.salePrice});
}
double grossMargin(
{required double expectedYield,
required double waterApplied,
required double salePrice,
required double variableCost,
required double waterPrice,
required bool isRainFed}) {
if (isRainFed == false) {
return expectedYield * salePrice - variableCost - waterApplied * waterPrice;
} else {
return expectedYield * salePrice - variableCost;
}
}
class TableRow {
int year;
String cropName;
double yield;
int price;
int vCost;
int GM_ha;
double cashOut;
int netMargin;
int cumulNetMargin;
TableRow(
{required this.year,
required this.cropName,
required this.yield,
required this.price,
required this.vCost,
required this.GM_ha,
required this.cashOut,
required this.netMargin,
required this.cumulNetMargin});
}
double PMT(PV, NPER, rate) {
double result = PV * (rate * pow(1 + rate, NPER)) / (pow(1 + rate, NPER) - 1);
return (result);
}
double getNPV(rate, initialCost, cashFlows) {
var npv = initialCost;
for (var i = 0; i < cashFlows.length; i++) {
npv += cashFlows[i] / pow(rate / 100 + 1, i + 1);
}
return npv;
}
double IRR(values, guess) {
// Credits: algorithm inspired by Apache OpenOffice
// Calculates the resulting amount
double irrResult(values, dates, rate) {
var r = rate + 1;
var result = values[0];
for (var i = 1; i < values.length; i++) {
result += values[i] / pow(r, (dates[i] - dates[0]) / 365);
}
return result;
}
// Calculates the first derivation
double irrResultDeriv(values, dates, rate) {
var r = rate + 1;
double result = 0;
for (var i = 1; i < values.length; i++) {
var frac = (dates[i] - dates[0]) / 365;
result -= frac * values[i] / pow(r, frac + 1);
}
return result;
}
// Initialize dates and check that values contains at least one positive value and one negative value
var dates = List.filled(values.length, 0, growable: false);
var positive = false;
var negative = false;
for (var i = 0; i < values.length; i++) {
dates[i] = (i == 0) ? 0 : dates[i - 1] + 365;
if (values[i] > 0) positive = true;
if (values[i] < 0) negative = true;
}
// Return error if values does not contain at least one positive value and one negative value
if (!positive || !negative) return 0;
// Initialize guess and resultRate
var guess = 0.1;
var resultRate = guess;
// Set maximum epsilon for end of iteration
var epsMax = 1e-10;
// Set maximum number of iterations
var iterMax = 100;
// Implement Newton's method
var newRate, epsRate, resultValue;
var iteration = 0;
var contLoop = true;
do {
resultValue = irrResult(values, dates, resultRate);
newRate =
resultRate - resultValue / irrResultDeriv(values, dates, resultRate);
epsRate = (newRate - resultRate).abs();
resultRate = newRate;
contLoop = (epsRate > epsMax) && ((resultValue).abs() > epsMax);
} while (contLoop && (++iteration < iterMax));
if (contLoop) return 0;
// Return internal rate of return
return resultRate;
}
void main() {
TriangularDistribution expectedYield =
TriangularDistribution(lowerLimit: 7.5, mode: 8.5, upperLimit: 9.5);
TriangularDistribution waterApplied =
TriangularDistribution(lowerLimit: 4.5, mode: 4.5, upperLimit: 4.5);
TriangularDistribution salePrice =
TriangularDistribution(lowerLimit: 235, mode: 275, upperLimit: 330);
TriangularDistribution variableCost =
TriangularDistribution(lowerLimit: 595, mode: 595, upperLimit: 595);
//Default Rice: pass
// TriangularDistribution expectedYield =
// TriangularDistribution(lowerLimit: 9, mode: 9.5, upperLimit: 10.5);
// TriangularDistribution waterApplied =
// TriangularDistribution(lowerLimit: 4.4, mode: 5.1, upperLimit: 6.4);
// TriangularDistribution salePrice =
// TriangularDistribution(lowerLimit: 260, mode: 330, upperLimit: 445);
// TriangularDistribution variableCost =
// TriangularDistribution(lowerLimit: 1515, mode: 1710, upperLimit: 1875);
//Finley Corn: pass
// TriangularDistribution expectedYield =
// TriangularDistribution(lowerLimit: 4, mode: 12, upperLimit: 17);
// TriangularDistribution waterApplied =
// TriangularDistribution(lowerLimit: 8, mode: 9, upperLimit: 10);
// TriangularDistribution salePrice =
// TriangularDistribution(lowerLimit: 270, mode: 300, upperLimit: 450);
// TriangularDistribution variableCost =
// TriangularDistribution(lowerLimit: 1560, mode: 1560, upperLimit: 1560);
//Finley Irrigated: pass
// TriangularDistribution expectedYield =
// TriangularDistribution(lowerLimit: 6, mode: 6.3, upperLimit: 6.5);
// TriangularDistribution waterApplied =
// TriangularDistribution(lowerLimit: 2, mode: 2, upperLimit: 2);
// TriangularDistribution salePrice =
// TriangularDistribution(lowerLimit: 250, mode: 250, upperLimit: 250);
// TriangularDistribution variableCost =
// TriangularDistribution(lowerLimit: 690, mode: 690, upperLimit: 690);
//Finley Dryland: pass
// TriangularDistribution expectedYield =
// TriangularDistribution(lowerLimit: 3.5, mode: 3.5, upperLimit: 3.5);
// TriangularDistribution waterApplied =
// TriangularDistribution(lowerLimit: 0, mode: 0, upperLimit: 0);
// TriangularDistribution salePrice =
// TriangularDistribution(lowerLimit: 250, mode: 250, upperLimit: 250);
// TriangularDistribution variableCost =
// TriangularDistribution(lowerLimit: 370, mode: 370, upperLimit: 370);
//Normanville Dryland Barley: pass
// TriangularDistribution expectedYield =
// TriangularDistribution(lowerLimit: 1, mode: 2.5, upperLimit: 5);
// TriangularDistribution waterApplied =
// TriangularDistribution(lowerLimit: 0, mode: 0, upperLimit: 0);
// TriangularDistribution salePrice =
// TriangularDistribution(lowerLimit: 300, mode: 300, upperLimit: 300);
// TriangularDistribution variableCost =
// TriangularDistribution(lowerLimit: 400, mode: 400, upperLimit: 400);
//Normanville Irrigated Barley:
// TriangularDistribution expectedYield =
// TriangularDistribution(lowerLimit: 4.5, mode: 7, upperLimit: 8);
// TriangularDistribution waterApplied =
// TriangularDistribution(lowerLimit: 3.5, mode: 4, upperLimit: 4.5);
// TriangularDistribution salePrice =
// TriangularDistribution(lowerLimit: 300, mode: 300, upperLimit: 300);
// TriangularDistribution variableCost =
// TriangularDistribution(lowerLimit: 390, mode: 395, upperLimit: 395);
//Normanville Canola: pass
// TriangularDistribution expectedYield =
// TriangularDistribution(lowerLimit: 1.5, mode: 2.5, upperLimit: 4);
// TriangularDistribution waterApplied =
// TriangularDistribution(lowerLimit: 3.5, mode: 4, upperLimit: 4.5);
// TriangularDistribution salePrice =
// TriangularDistribution(lowerLimit: 550, mode: 550, upperLimit: 550);
// TriangularDistribution variableCost =
// TriangularDistribution(lowerLimit: 400, mode: 400, upperLimit: 400);
bool isRainFed = false;
double waterPrice = 40;
double otherCapital = 0;
double systemLife = 20;
double interestRate = 3;
double systemCost_ha = 3250;
double area = 154;
double overheadCost_ha = 1250;
double opportunityCost = 0;
Crops wheat = Crops(
name: 'Wheat',
isRainFed: false,
expectedYield: expectedYield,
waterApplied: waterApplied,
variableCost: variableCost,
salePrice: salePrice);
Crops cotton = Crops(
name: 'Cotton',
isRainFed: isRainFed,
expectedYield:
TriangularDistribution(lowerLimit: 2.5, mode: 3, upperLimit: 3.5),
waterApplied: waterApplied,
variableCost: TriangularDistribution(
lowerLimit: 1185, mode: 1185, upperLimit: 1185),
salePrice: TriangularDistribution(
lowerLimit: 1715, mode: 2005, upperLimit: 2215));
TableRow t1 = TableRow(
year: DateTime.now().year,
cropName: wheat.name,
yield: 0,
price: 0,
vCost: 0,
GM_ha: 0,
cashOut: 0,
netMargin: 0,
cumulNetMargin: 0);
t1.year = DateTime.now().year;
t1.cropName = wheat.name;
t1.yield = wheat.expectedYield.qtri(0.5);
t1.price = wheat.salePrice.qtri(0.5).toInt();
t1.vCost = wheat.variableCost.qtri(0.5).toInt();
t1.GM_ha = grossMargin(
expectedYield: t1.yield,
waterApplied: waterApplied.mode,
salePrice: t1.price.toDouble(),
variableCost: t1.vCost.toDouble(),
waterPrice: waterPrice,
isRainFed: isRainFed)
.toInt();
double otherAnnualEquivalent =
PMT(otherCapital, systemLife, interestRate * 0.01);
double systemAnnualEquivalent =
PMT(systemCost_ha * area, systemLife, interestRate * 0.01);
double otherAnnualEquivalent_ha = otherAnnualEquivalent / area;
double systemAnnualEquivalent_ha = systemAnnualEquivalent / area;
double totalCapitalCost_ha =
otherAnnualEquivalent_ha + systemAnnualEquivalent_ha;
t1.cashOut = 0 - (totalCapitalCost_ha + overheadCost_ha + opportunityCost);
t1.netMargin = t1.GM_ha + t1.cashOut.toInt();
t1.cumulNetMargin = -3250 + t1.netMargin;
TableRow t2 = TableRow(
year: DateTime.now().year,
cropName: wheat.name,
yield: 0,
price: 0,
vCost: 0,
GM_ha: 0,
cashOut: 0,
netMargin: 0,
cumulNetMargin: 0);
t2.year = DateTime.now().year + 1;
t2.cropName = cotton.name;
t2.yield = cotton.expectedYield.qtri(0.5);
t2.price = cotton.salePrice.qtri(0.5).toInt();
t2.vCost = cotton.variableCost.qtri(0.5).toInt();
t2.GM_ha = grossMargin(
expectedYield: t2.yield,
waterApplied: waterApplied.mode,
salePrice: t2.price.toDouble(),
variableCost: t2.vCost.toDouble(),
waterPrice: waterPrice,
isRainFed: isRainFed)
.toInt();
// double otherAnnualEquivalent =
// PMT(otherCapital, systemLife, interestRate * 0.01);
// double systemAnnualEquivalent =
// PMT(systemCost_ha * area, systemLife, interestRate * 0.01);
// double otherAnnualEquivalent_ha = otherAnnualEquivalent / area;
// double systemAnnualEquivalent_ha = systemAnnualEquivalent / area;
// double totalCapitalCost_ha =
// otherAnnualEquivalent_ha + systemAnnualEquivalent_ha;
t2.cashOut = 0 - (totalCapitalCost_ha + overheadCost_ha + opportunityCost);
t2.netMargin = t2.GM_ha + t2.cashOut.toInt();
t2.cumulNetMargin = t1.cumulNetMargin + t2.netMargin;
print('Year Crop Yield Price Cost GM Outflow Net Cuml');
print(
'${t1.year} ${t1.cropName} ${t1.yield.toStringAsFixed(1)} ${t1.price} ${t1.vCost} ${t1.GM_ha} ${t1.cashOut.toInt()} ${t1.netMargin} ${t1.cumulNetMargin}');
print(
'${t2.year} ${t2.cropName} ${t2.yield.toStringAsFixed(1)} ${t2.price} ${t2.vCost} ${t2.GM_ha} ${t2.cashOut.toInt()} ${t2.netMargin} ${t2.cumulNetMargin}');
List<int> netMargin = [
129,
3114,
3191,
-731,
143,
3083,
3180,
-712,
149,
3120,
3185,
-712,
139,
3101,
3162,
-734,
134,
3104,
3176,
-706
];
double pv = getNPV(3, 0, netMargin);
print('Present value of future cash flows: $pv');
double invWorth = pv - systemCost_ha;
print('Investment worth: $invWorth');
double irr =
(10 * 100 * IRR([(-1 * systemCost_ha), ...netMargin], 0.1)).round() / 10;
print('Internal rate of return: $irr');
// print('Most Likely:');
// print(grossMargin(
// expectedYield: t.yield,
// waterApplied: waterApplied.mode,
// salePrice: t.price.toDouble(),
// variableCost: t.vCost.toDouble(),
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print('Crop Yield: ${expectedYield.qtri(0.5)}');
// print(grossMargin(
// expectedYield: expectedYield.qtri(0.25),
// waterApplied: waterApplied.mode,
// salePrice: salePrice.mode,
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.qtri(0.5),
// waterApplied: waterApplied.mode,
// salePrice: salePrice.mode,
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.qtri(0.75),
// waterApplied: waterApplied.mode,
// salePrice: salePrice.mode,
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print('Crop Price: ${salePrice.qtri(0.5)}');
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.mode,
// salePrice: salePrice.qtri(0.25),
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.mode,
// salePrice: salePrice.qtri(0.5),
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.mode,
// salePrice: salePrice.qtri(0.75),
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print('Water Applied:');
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.qtri(0.25),
// salePrice: salePrice.mode,
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.qtri(0.5),
// salePrice: salePrice.mode,
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.qtri(0.75),
// salePrice: salePrice.mode,
// variableCost: variableCost.mode,
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print('Variable Costs: ${variableCost.qtri(0.5)}');
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.mode,
// salePrice: salePrice.mode,
// variableCost: variableCost.qtri(0.25),
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.mode,
// salePrice: salePrice.mode,
// variableCost: variableCost.qtri(0.5),
// waterPrice: waterPrice,
// isRainFed: isRainFed));
// print(grossMargin(
// expectedYield: expectedYield.mode,
// waterApplied: waterApplied.mode,
// salePrice: salePrice.mode,
// variableCost: variableCost.qtri(0.75),
// waterPrice: waterPrice,
// isRainFed: isRainFed));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment