Created with <3 with dartpad.dev.
Last active
November 7, 2022 07:14
-
-
Save JacobYZ/ebfbf02aa40e4925c822dc71026f6086 to your computer and use it in GitHub Desktop.
crimson-eucalyptus-7759
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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