def choose_tech(VE,D,j,N,energy,prices_lamp,tt,interes): method=strategy(VE[j,2]) #returns the strategy to use over the different profiles #(1)rational, (2) social, (3) conservative #Rational method if method==1: #180 hours of consume in average per month cost=np.zeros((3,139)) #Payments over time of the different techs cost_present=np.zeros(3) #Total present cost #Analysis of energy consume for i in range(139): if VE[j,3]==1: cost[0,i]=(-40*180/100)*energy[i+tt]*0.8 cost[1,i]=(-15*180/100)*energy[i+tt]*0.8 cost[2,i]=(-9*180/100)*energy[i+tt]*0.8 elif VE[j,3]==2: cost[0,i]=(-40*180/100)*energy[i+tt]*1.2 cost[1,i]=(-15*180/100)*energy[i+tt]*1.2 cost[2,i]=(-9*180/100)*energy[i+tt]*1.2 #LED lamp cost cost[2,0]=cost[2,0]-prices_lamp[2,tt] #Fluorescent lamp cost (1:36:139) for i in range(0,138,36): cost[1,i]=cost[1,i]-prices_lamp[1,tt+i] #Incandescent lamp cost (i=1:4:139) for i in range(0,138,4): cost[0,i]=cost[0,i]-prices_lamp[0,tt+i] #Cost in present value cost_present[0]=-np.npv(interes,cost[0,:]) cost_present[1]=-np.npv(interes,cost[1,:]) cost_present[2]=-np.npv(interes,cost[2,:]) #Selection of the best npv performance tech=cost_present.argmin() tech=tech+1 #Conservative method if method==3: tech=VE[j,0] #Social method if method==2: S_t=np.zeros(3) #Counter of technologies in vicinity D_N=D.neighbors(j) #Returns the list of neighbors D_N_len=len(D_N) #Dimension of neighbors list for k in range(D_N_len): #Iteration of evaluation S_t[VE[D_N[k],0]-1]=S_t[VE[D_N[k],0]-1]+1 tech=S_t.argmax()+1 return(tech)
def outputRow(): #NOTE: The fields of the db row, such a loan_id, are no longer available when this is called. discountRate = principalDiscountRates[finalStatus] numeratorNARdiscount = prev_balance_end * discountRate cashflowLen = len(cashflow) while cashflow[cashflowLen-1]==0: cashflowLen -= 1 cashflow.resize(max(cashflowLen, receivedMonthIndex+1)) npv = np.npv(monthlyDiscountRate-1, cashflow) if printCashflow: print(cashflow) if finalStatus != 'Charged Off': cashflow[receivedMonthIndex] += prev_balance_end * (1-discountRate) / prev_investment if printCashflow: print(cashflow) npvForecast = np.npv(monthlyDiscountRate-1, cashflow) irrForecast = (1+np.irr(cashflow))**12 - 1 finalStatusIsComplete = finalStatus in ["Charged Off", "Default", "Fully Paid"] output.append(( prev_loan_id, finalStatus, prev_mob, missedPayment, firstMissed, dueWhenFirstMissed, receivedAfterMissed, riskFreeRate, npv, npvForecast, firstMissedOrLastObserved, (numeratorNAR-numeratorNARdiscount)/prev_investment, denominatorNAR/prev_investment, finalStatusIsComplete, irrForecast, #cashflow ))
def net_present_value_aggregate_for_portfolio(self): """ Gets the portfolio's aggregate net present value. Returns: The portfolio's aggregate net present value. """ npv = np.npv(self.discount_rate / 12, list(self.aggregate_flows_df['total_payments'])) return float(npv)
def net_present_value_for_loan(self, loan): """ Calculates a loan's net present value from its cash flows. Args: loan: The loan which is being valued. Returns: The net present value of the loan. """ cash_flows = self.cash_flows_df[self.cash_flows_df['loan_df_pk'] == loan.name] npv = np.npv(self.discount_rate / 12, cash_flows['total_payments']) return npv
def create_company_simulation(simulation_id, stock_id): getcontext().prec = 4 mu = 0.02 sigma = 0.1 simulation = Simulation.objects.get(pk=simulation_id) stock = Stock.objects.get(pk=stock_id) ticker = Ticker.objects.get(simulation=simulation) company = TickerCompany(ticker=ticker, stock=stock, symbol=stock.symbol, name="Company %s" % stock.symbol) company.save() rounds = ticker.nb_rounds + 1 brownian_motion = geometric_brownian(rounds, mu, sigma, ticker.initial_value, rounds/(ticker.nb_days*rounds), stock_id) i = 0 simulation_dividends = [] simulation_net_income = [] for sim_round in range(0, rounds): round_dividend = 0 round_net_income = 0 for sim_day in range(1, ticker.nb_days+1): # We have each round/day and the corresponding dividend daily_dividend = brownian_motion[i] daily_net_income = brownian_motion[i] / float(ticker.dividend_payoff_rate) * 100 * stock.quantity c = CompanyFinancial(company=company, daily_dividend=Decimal(daily_dividend), daily_net_income=Decimal(daily_net_income), sim_round=sim_round, sim_day=sim_day, sim_date=sim_round*100+sim_day) c.save() round_dividend += daily_dividend round_net_income += daily_net_income i += 1 simulation_dividends.append(round_dividend) simulation_net_income.append(round_net_income) # Share price estimation G = simulation_dividends[-1]/simulation_dividends[-2]-1 R = 0.15 g = R drift = 0 simulation_stock_price = [] previous_company_income = None for sim_round in range(0, rounds): stock_price = np.npv(0.15, simulation_dividends[sim_round:rounds]) + (simulation_dividends[-1]*(1+g)/(R-G))/np.power(1+R, rounds-sim_round) simulation_stock_price.append(stock_price) if previous_company_income: drift = simulation_net_income[sim_round] / float(previous_company_income.net_income) - 1 previous_company_income.drift = Decimal(drift) previous_company_income.save() company_share = CompanyShare(company=company, share_value=Decimal(stock_price), dividends=Decimal(simulation_dividends[sim_round]), net_income=Decimal(simulation_net_income[sim_round]), drift=Decimal(drift), sim_round=sim_round) company_share.save() previous_company_income = company_share if sim_round == 0: stock.price = Decimal(stock_price) stock.save() return company.id
def metrics(price, percentDown, closingCosts,repairCosts,rate,term,fedTaxRate,stTaxRate,capitalGains,propTaxRate,insPremiumYr, HOA,hoaIncRate, repairsYr, vacancyPc, propMgmtMo, rent, rentIncRate,appreciationRate, inflation,bldgValPct,sellYear): years = linspace(0, term, term+1) cashflowND = [0]*len(years) for year in years: y = int(year) if y <= sellYear: payment, downPayment, cashToClose, cashToOperate = loanCalcs(price, percentDown, closingCosts, repairCosts, rate, term) equity, mortBal, appVal, interestYr = equityCalcs(y, price, downPayment, payment, rate, appreciationRate) capex = capexF(y, sellYear, repairsYr, cashToOperate, appVal, price) revenue, vacancy = revenueF(rent, rentIncRate, vacancyPc, y) opexTotal, opexLessDS, deductibles = opexF(payment, propTaxRate, insPremiumYr, HOA, hoaIncRate, propMgmtMo, price, y, interestYr, vacancy) NOI = NOIF(revenue, opexLessDS) if y is 1: NOI1=NOI deductions = deductionsF(deductibles, price, bldgValPct) taxes = taxesF(price, appVal, revenue, deductions, capex, fedTaxRate, stTaxRate, capitalGains, y, sellYear) cashflowND[y] = cashflowATF(revenue, opexTotal, taxes, capex, equity, y, sellYear) capRateYr1 = price/NOI1 NFV = sum(cashflowND) PV10 = npv(.1,cashflowND) ROR = irr(cashflowND) cashPayout = payoutCalc(cashflowND, cashToOperate) cashOnCashYr1 = cashToOperate/cashflowND[1] moCashflowYr1 = cashflowND[1]/12. metricsDict = { "NFV" : NFV, "PV10" : PV10, "ROR" : ROR, "capRateYr1" : capRateYr1, "cashPayout" : cashPayout, "cashOnCashYr1" : cashOnCashYr1, "moCashflowYr1" : moCashflowYr1, "cashToClose" : cashToClose, "cashToOperate" : cashToOperate, } # print "NFV = $%s" %"{:,}".format(int(NFV)) # print "PV10 = $%s" %"{:,}".format(int(PV10)) # print "IRR = %s" %round(ROR*100,2) + '%' # print "Cash payout occurs in year %s" %cashPayout # print "Cash on cash return in year 1 = %s" %int(cashOnCashYr1)+'%' # print "Monthly cashflow in year 1 = $%s" % int(moCashflowYr1) #return NFV, PV10, ROR, capRateYr1, cashPayout, cashOnCashYr1, moCashflowYr1, cashToClose, cashToOperate return metricsDict
def mirr(values, finance_rate, reinvest_rate): """ Modified internal rate of return. Parameters ---------- values : array_like Cash flows (must contain at least one positive and one negative value) or nan is returned. finance_rate : scalar Interest rate paid on the cash flows reinvest_rate : scalar Interest rate received on the cash flows upon reinvestment Returns ------- out : float Modified internal rate of return """ values = np.asarray(values) initial = values[0] values = values[1:] n = values.size pos = values * (values>0) neg = values * (values<0) if not (pos.size > 0 and neg.size > 0): return np.nan numer = np.abs(np.npv(reinvest_rate, pos)) denom = np.abs(np.npv(finance_rate, neg)) if initial>0: return ((initial + numer) / denom)**(1.0/n)*(1+reinvest_rate) - 1 else: return ((numer / (-initial + denom)))**(1.0/n)*(1+reinvest_rate) - 1
def eq_subvention(montant, duree, taux): """ Calcule l' "équivalent subvention" par rapport à un taux 0% pour chacune des différentes combinaisons d'hypothèses possibles""" # RAZ des résultats equivalent_subvention = np.zeros((len(montant), len(duree), len(taux))) part_subventionee = np.zeros((len(montant), len(duree), len(taux))) # Calcule de l' "équivalent subvention" for i in range(len(montant)): for j in range(len(duree)): # Périodicité des remboursements per = np.arange(duree[j]) + 1 for k in range(len(taux)): # Calcule l'échancier des intérêts perçus echeancier_interets = -np.ipmt(taux[k], per, duree[j], montant[i]) # Calcule et enregistre l' "équivalent subvention" comparé # à un taux 0 pour le jeu d'hypothèses considéré, les flux # d'intérêt étant actualisés à 4% equivalent_subvention[i, j, k] = np.npv(0.04, echeancier_interets) # ou alternativemen, sans actualiser: # equivalent_subvention[i,j,k]=np.sum(echeancier_interets) part_subventionee[i, j, k] = (equivalent_subvention[i, j, k] / montant[i]) * 100 return equivalent_subvention, part_subventionee
def calc_npv(r, ubi, inputs, n): x = np.zeros((ubi['Years Post Transfer'], n)) y = np.zeros((ubi['Years Post Transfer'], n)) # iterate through years of benefits for j in range(1, ubi['Years Post Transfer'] + 1): # sum benefits during program if(j < r): x[j - 1] += ubi['Expected baseline per capita consumption (nominal USD)']* \ np.power((1.0 + inputs['UBI']['Expected annual consumption increase (without the UBI program)']), float(j))* \ inputs['UBI']['Work participation adjustment'] + \ ubi['Annual quantity of transfer money used for immediate consumtion (pre-discounting)'] # benefits after program else: x[j - 1] += ubi['Expected baseline per capita consumption (nominal USD)']* \ np.power((1.0 + inputs['UBI']['Expected annual consumption increase (without the UBI program)']), float(j)) # investments calculations for k in range(n): if(j < r + inputs['UBI']['Duration of investment benefits (in years) - UBI'][k]): x[j - 1][k] += ubi['Annual return for each year of transfer investments (pre-discounting)'][k]* \ np.min([j, inputs['UBI']['Duration of investment benefits (in years) - UBI'][k], \ r, (inputs['UBI']['Duration of investment benefits (in years) - UBI'][k] + r - j)]) if(j > r): x[j - 1][k] += ubi['Value eventually returned from one years investment (pre-discounting)'][k] # log transform and subtact baseline y[j - 1] = np.log(x[j - 1]) y[j - 1] -= np.log(ubi['Expected baseline per capita consumption (nominal USD)']* \ np.power((1.0 + inputs['UBI']['Expected annual consumption increase (without the UBI program)']), float(j))) # npv on yearly data z = np.zeros(n) for i in range(n): z[i] = np.npv(inputs['Shared']['Discount rate'][i], y[:, i]) return z
depreciation_rate = 200 change_opex = labor_savings+forklift_savings+floor_salaries ## Gather income statements income_0 = income_statement(name='Year 0', sales=0, cogs=0, sga=0, da=0, interest=0, tax_rate=tax_rate).get_income_statement( depreciation_rate=0, delta_capex=equipment_buy, delta_workingcap=0) income_1 = income_statement(name='Year 1', sales=0, cogs=0, sga=change_opex, da=depreciation_rate, interest=0, tax_rate=tax_rate).get_income_statement( depreciation_rate=depreciation_rate, delta_capex=0, delta_workingcap=0) income_2 = income_statement(name='Year 2', sales=0, cogs=0, sga=change_opex, da=depreciation_rate, interest=0, tax_rate=tax_rate).get_income_statement(depreciation_rate=depreciation_rate, delta_capex=0, delta_workingcap=0) income_3 = income_statement(name='Year 3', sales=0, cogs=0, sga=change_opex, da=depreciation_rate, interest=0, tax_rate=tax_rate).get_income_statement(depreciation_rate=depreciation_rate, delta_capex=equipment_sell, delta_workingcap=0) income = pd.concat([income_0, income_1, income_2, income_3], axis=1) print(income) NPV = np.npv(discount_rate, income.ix['FreeCashFlow']) IRR = np.irr(income.ix['FreeCashFlow']) payback_period = abs(income.ix['FreeCashFlow'][0]) / income.ix['FreeCashFlow'][1:].sum() print(''' NPV ................................ %.2f IRR ................................ %.2f Payback Period ................................ %.2f '''%(NPV, IRR, payback_period)) # In[167]: income.ix['FreeCashFlow'][1:]
def robust_npv(values, rate=0.03): try: return np.npv(rate, values) except: return np.nan
def npv(flow, r=disc_fac): sum = 0 for i in range(flow.shape[1]): sum += np.npv(r, flow[:, i]) return sum
def taxEquityFlip(PPARateSixYearsTE, discRate, totalCost, allYearGenerationMWh, distAdderDirect, loanYears, firstYearLandLeaseCosts, firstYearOPMainCosts, firstYearInsuranceCosts, numberPanels): #Output Tax Equity Flip [C] coopInvestmentTaxEquity = -totalCost * (1 - 0.53) #Output Tax Equity Flip [D] financeCostCashTaxEquity = 0 #Output Tax Equity Flip [E] cashToSPEOForPPATE = [] #Output Tax Equity Flip [F] derivedCostEnergyTE = 0 #Output Tax Equity Flip [G] OMInsuranceETCTE = [] #Output Tax Equity Flip [H] cashFromSPEToBlockerTE = [] #Output Tax Equity Flip [I] cashFromBlockerTE = 0 #Output Tax Equity Flip [J] distAdderTaxEquity = distAdderDirect #Output Tax Equity Flip [K] netCoopPaymentsTaxEquity = [] #Output Tax Equity Flip [L] costToCustomerTaxEquity = [] #Output Tax Equity Flip [L64] NPVLoanTaxEquity = 0 #Output Tax Equity Flip [F72] Rate_Levelized_Equity = 0 ## Tax Equity Flip Formulas #Output Tax Equity Flip [D] #TEI Calcs [E] financeCostOfCashTE = 0 coopFinanceRateTE = 2.7 / 100 if (coopFinanceRateTE == 0): financeCostOfCashTE = 0 else: payment = pmt(coopFinanceRateTE, loanYears, -coopInvestmentTaxEquity) financeCostCashTaxEquity = payment #Output Tax Equity Flip [E] SPERevenueTE = [] for i in range(1, len(allYearGenerationMWh) + 1): SPERevenueTE.append(PPARateSixYearsTE * allYearGenerationMWh[i]) if ((i >= 1) and (i <= 6)): cashToSPEOForPPATE.append(-SPERevenueTE[i - 1]) else: cashToSPEOForPPATE.append(0) #Output Tax Equity Flip [F] derivedCostEnergyTE = cashToSPEOForPPATE[0] / allYearGenerationMWh[1] #Output Tax Equity Flip [G] #TEI Calcs [F] [U] [V] landLeaseTE = [] OMTE = [] insuranceTE = [] for i in range(1, len(allYearGenerationMWh) + 1): landLeaseTE.append(firstYearLandLeaseCosts * math.pow((1 + .01), (i - 1))) OMTE.append(-firstYearOPMainCosts * math.pow((1 + .01), (i - 1))) insuranceTE.append(-firstYearInsuranceCosts * math.pow((1 + .025), (i - 1))) if (i < 7): OMInsuranceETCTE.append(float(landLeaseTE[i - 1])) else: OMInsuranceETCTE.append( float(OMTE[i - 1]) + float(insuranceTE[i - 1]) + float(landLeaseTE[i - 1])) #Output Tax Equity Flip [H] #TEI Calcs [T] SPEMgmtFeeTE = [] EBITDATE = [] EBITDATEREDUCED = [] managementFee = 10000 for i in range(1, len(SPERevenueTE) + 1): SPEMgmtFeeTE.append(-managementFee * math.pow((1 + .01), (i - 1))) EBITDATE.append( float(SPERevenueTE[i - 1]) + float(OMTE[i - 1]) + float(insuranceTE[i - 1]) + float(SPEMgmtFeeTE[i - 1])) if (i <= 6): cashFromSPEToBlockerTE.append(float(EBITDATE[i - 1]) * .01) else: cashFromSPEToBlockerTE.append(0) EBITDATEREDUCED.append(EBITDATE[i - 1]) #Output Tax Equity Flip [I] #TEI Calcs [Y21] cashRevenueTE = -totalCost * (1 - 0.53) buyoutAmountTE = 0 for i in range(1, len(EBITDATEREDUCED) + 1): buyoutAmountTE = buyoutAmountTE + EBITDATEREDUCED[i - 1] / ( math.pow(1 + 0.12, i)) buyoutAmountTE = buyoutAmountTE * 0.05 cashFromBlockerTE = -(buyoutAmountTE) + 0.0725 * cashRevenueTE #Output Tax Equity Flip [K] [L] for i in range(1, len(allYearGenerationMWh) + 1): if (i == 6): netCoopPaymentsTaxEquity.append(financeCostCashTaxEquity + cashToSPEOForPPATE[i - 1] + cashFromSPEToBlockerTE[i - 1] + OMInsuranceETCTE[i - 1] + cashFromBlockerTE) else: netCoopPaymentsTaxEquity.append(financeCostCashTaxEquity + cashFromSPEToBlockerTE[i - 1] + cashToSPEOForPPATE[i - 1] + OMInsuranceETCTE[i - 1]) costToCustomerTaxEquity.append(netCoopPaymentsTaxEquity[i - 1] - distAdderTaxEquity[i - 1]) #Output Tax Equity Flip [L37] NPVLoanTaxEquity = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + costToCustomerTaxEquity) #Output - Tax Equity [F42] Rate_Levelized_TaxEquity = -NPVLoanTaxEquity / NPVallYearGenerationMWh #TEI Calcs - Achieved Return [AW 21] #[AK] MACRDepreciation = [] MACRDepreciation.append(-0.99 * 0.2 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.32 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.192 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.1152 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.1152 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.0576 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) #[AI] [AL] [AN] cashRevenueTEI = [] #[AI] slDepreciation = [] #[AL] totalDistributions = [] #[AN] cashRevenueTEI.append(-totalCost * 0.53) for i in range(1, 7): cashRevenueTEI.append(EBITDATE[i - 1] * 0.99) slDepreciation.append(totalCost / 25) totalDistributions.append(-cashRevenueTEI[i]) #[AJ] ITC = totalCost * 0.9822 * 0.3 * 0.99 #[AM] taxableIncLoss = [0] taxableIncLoss.append(cashRevenueTEI[1] + MACRDepreciation[0]) #[AO] capitalAcct = [] capitalAcct.append(totalCost * 0.53) condition = capitalAcct[0] - 0.5 * ITC + taxableIncLoss[ 1] + totalDistributions[0] if condition > 0: capitalAcct.append(condition) else: capitalAcct.append(0) #[AQ] ratioTE = [0] #[AP] reallocatedIncLoss = [] #AO-1 + AN + AI + AK + AJ for i in range(0, 5): reallocatedIncLoss.append(capitalAcct[i + 1] + totalDistributions[i + 1] + MACRDepreciation[i + 1] + cashRevenueTEI[i + 2]) ratioTE.append(reallocatedIncLoss[i] / (cashRevenueTEI[i + 2] + MACRDepreciation[i + 1])) taxableIncLoss.append( cashRevenueTEI[i + 2] + MACRDepreciation[i + 1] - ratioTE[i + 1] * (MACRDepreciation[i + 1] - totalDistributions[i + 1])) condition = capitalAcct[i + 1] + taxableIncLoss[ i + 2] + totalDistributions[i + 1] if condition > 0: capitalAcct.append(condition) else: capitalAcct.append(0) #[AR] taxesBenefitLiab = [0] for i in range(1, 7): taxesBenefitLiab.append(-taxableIncLoss[i] * 0.35) #[AS] [AT] buyoutAmount = 0 taxFromBuyout = 0 for i in range(0, len(EBITDATEREDUCED)): buyoutAmount = buyoutAmount + .05 * EBITDATEREDUCED[i] / (math.pow( 1.12, (i + 1))) taxFromBuyout = -buyoutAmount * 0.35 #[AU] [AV] totalCashTax = [] cumulativeCashTax = [0] for i in range(0, 7): if i == 1: totalCashTax.append(cashRevenueTEI[i] + ITC + taxesBenefitLiab[i] + 0 + 0) cumulativeCashTax.append(cumulativeCashTax[i] + totalCashTax[i]) elif i == 6: totalCashTax.append(cashRevenueTEI[i] + 0 + taxesBenefitLiab[i] + buyoutAmount + taxFromBuyout) cumulativeCashTax.append(cumulativeCashTax[i] + totalCashTax[i] + buyoutAmount + taxFromBuyout) else: totalCashTax.append(cashRevenueTEI[i] + 0 + taxesBenefitLiab[i] + 0 + 0) cumulativeCashTax.append(cumulativeCashTax[i] + totalCashTax[i]) #[AW21] if (cumulativeCashTax[7] > 0): cumulativeIRR = round(irr(totalCashTax), 4) else: cumulativeIRR = 0 # Deleteme: Variable Dump for debugging # variableDump = {} # variableDump["TaxEquity"] = {} # variableDump["TaxEquity"]["coopInvestmentTaxEquity"] = coopInvestmentTaxEquity # variableDump["TaxEquity"]["financeCostCashTaxEquity"] = financeCostCashTaxEquity # variableDump["TaxEquity"]["cashToSPEOForPPATE"] = cashToSPEOForPPATE # variableDump["TaxEquity"]["derivedCostEnergyTE"] = derivedCostEnergyTE # variableDump["TaxEquity"]["OMInsuranceETCTE"] = OMInsuranceETCTE # variableDump["TaxEquity"]["cashFromSPEToBlockerTE"] = cashFromSPEToBlockerTE # variableDump["TaxEquity"]["cashFromBlockerTE"] = cashFromBlockerTE # variableDump["TaxEquity"]["distAdderTaxEquity"] = distAdderTaxEquity # variableDump["TaxEquity"]["netCoopPaymentsTaxEquity"] = netCoopPaymentsTaxEquity # variableDump["TaxEquity"]["NPVLoanTaxEquity"] = NPVLoanTaxEquity return cumulativeIRR, Rate_Levelized_TaxEquity, NPVLoanTaxEquity
energySaleChange = sum(energySaleDRyear) - sum(energySaleArray) peakDemandRed = PeakDemandCharge - PeakDemandChargeDR # Calculating the Purchase Cost, Operation and Maint. Cost and Total Cost outData["AnnualOpCost"] = [- AnnDROM for x in lifeYears[0:]] LifetimeOperationCost = (sum(outData["AnnualOpCost"])) outData["LifetimeOperationCost"] = abs(LifetimeOperationCost) outData["lifePurchaseCosts"] = [-1.0 * DrTechCost] + [0 for x in lifeYears[1:]] outData["TotalCost"] = abs(outData["LifetimeOperationCost"] + DrTechCost) # Outputs of the Program Lifetime Cash Flow figure outData["EnergySaleChangeBenefit"] = [energySaleChange * ScalingAnnual ** x for x in range(lifeSpan)] outData["PeakDemandReduction"] = [peakDemandRed * ScalingAnnual ** x for x in range(lifeSpan)] BenefitCurve = [x+y for x,y in zip(outData["EnergySaleChangeBenefit"], outData["PeakDemandReduction"])] outData["TotalBenefit"] = sum(BenefitCurve) outData["BenefittoCostRatio"] = float(outData["TotalBenefit"] / outData["TotalCost"]) netBenefit = [x+y+z for x,y,z in zip(outData["AnnualOpCost"],outData["lifePurchaseCosts"],BenefitCurve)] outData["npv"] = npv(DiscountRate, netBenefit) outData["cumulativeNetBenefit"] = [sum(netBenefit[0:i+1]) for i,d in enumerate(netBenefit)] outData["SimplePaybackPeriod"] = DrTechCost / (outData["TotalBenefit"] / lifeSpan) # Stdout/stderr. outData["stdout"] = "Success" outData["stderr"] = "" # Write the output. with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile: json.dump(outData, outFile, indent=4) # Update the runTime in the input file. endTime = datetime.datetime.now() inputDict["runTime"] = str(datetime.timedelta(seconds=int((endTime - startTime).total_seconds()))) with open(pJoin(modelDir,"allInputData.json"),"w") as inFile: json.dump(inputDict, inFile, indent=4) except: # If input range wasn't valid delete output, write error to disk.
def work(modelDir, inputDict): ''' Run the model in its directory.''' if inputDict['dispatch_type'] == 'prediction': return workForecast(modelDir, inputDict) out = {} try: with open(pJoin(modelDir, 'demand.csv'), 'w') as f: f.write(inputDict['demandCurve'].replace('\r', '')) with open(pJoin(modelDir, 'demand.csv')) as f: demand = [float(r[0]) for r in csv.reader(f)] assert len(demand) == 8760 with open(pJoin(modelDir, 'temp.csv'), 'w') as f: lines = inputDict['tempCurve'].split('\n') out["tempData"] = [float(x) if x != '999.0' else float(inputDict['setpoint']) for x in lines[:-1]] correctData = [x+'\n' if x != '999.0' else inputDict['setpoint']+'\n' for x in lines][:-1] f.write(''.join(correctData)) assert len(correctData) == 8760 except: raise Exception("CSV file is incorrect format. Please see valid format " "definition at <a target='_blank' href = 'https://github.com/dpinney/" "omf/wiki/Models-~-storagePeakShave#demand-file-csv-format'>\nOMF Wiki " "storagePeakShave - Demand File CSV Format</a>") # # created using calendar = {'1': 31, '2': 28, ..., '12': 31} # m = [calendar[key]*24 for key in calendar] # monthHours = [(sum(m[:i]), sum(m[:i+1])) for i, _ in enumerate(m)] monthHours = [(0, 744), (744, 1416), (1416, 2160), (2160, 2880), (2880, 3624), (3624, 4344), (4344, 5088), (5088, 5832), (5832, 6552), (6552, 7296), (7296, 8016), (8016, 8760)] P_lower, P_upper, E_UL = pyVbat(modelDir, inputDict) P_lower, P_upper, E_UL = list(P_lower), list(P_upper), list(E_UL) out["minPowerSeries"] = [-1*x for x in P_lower] out["maxPowerSeries"] = P_upper out["minEnergySeries"] = [-1*x for x in E_UL] out["maxEnergySeries"] = E_UL VBpower, out["VBenergy"] = pulpFunc(inputDict, demand, P_lower, P_upper, E_UL, monthHours) out["VBpower"] = VBpower out["dispatch_number"] = [len([p for p in VBpower[s:f] if p != 0]) for (s, f) in monthHours] peakDemand = [max(demand[s:f]) for s, f in monthHours] energyMonthly = [sum(demand[s:f]) for s, f in monthHours] demandAdj = [d+p for d, p in zip(demand, out["VBpower"])] peakAdjustedDemand = [max(demandAdj[s:f]) for s, f in monthHours] energyAdjustedMonthly = [sum(demandAdj[s:f]) for s, f in monthHours] rms = all([x == 0 for x in P_lower]) and all([x == 0 for x in P_upper]) out["dataCheck"] = 'VBAT returns no values for your inputs' if rms else '' out["demand"] = demand out["peakDemand"] = peakDemand out["energyMonthly"] = energyMonthly out["demandAdjusted"] = demandAdj out["peakAdjustedDemand"] = peakAdjustedDemand out["energyAdjustedMonthly"] = energyAdjustedMonthly cellCost = float(inputDict["unitDeviceCost"])*float(inputDict["number_devices"]) eCost = float(inputDict["electricityCost"]) dCharge = float(inputDict["demandChargeCost"]) out["VBdispatch"] = [dal-d for dal, d in zip(demandAdj, demand)] out["energyCost"] = [em*eCost for em in energyMonthly] out["energyCostAdjusted"] = [eam*eCost for eam in energyAdjustedMonthly] out["demandCharge"] = [peak*dCharge for peak in peakDemand] out["demandChargeAdjusted"] = [pad*dCharge for pad in out["peakAdjustedDemand"]] out["totalCost"] = [ec+dcm for ec, dcm in zip(out["energyCost"], out["demandCharge"])] out["totalCostAdjusted"] = [eca+dca for eca, dca in zip(out["energyCostAdjusted"], out["demandChargeAdjusted"])] out["savings"] = [tot-tota for tot, tota in zip(out["totalCost"], out["totalCostAdjusted"])] annualEarnings = sum(out["savings"]) - float(inputDict["unitUpkeepCost"])*float(inputDict["number_devices"]) cashFlowList = [annualEarnings] * int(inputDict["projectionLength"]) cashFlowList.insert(0, -1*cellCost) out["NPV"] = npv(float(inputDict["discountRate"])/100, cashFlowList) out["SPP"] = cellCost / annualEarnings out["netCashflow"] = cashFlowList out["cumulativeCashflow"] = [sum(cashFlowList[:i+1]) for i, d in enumerate(cashFlowList)] out["stdout"] = "Success" return out
# fv = np.fv(0.01, 5, -100, -1000) print(round(fv, 2)) # # 现值 = numpy.pv(利率, 期数, 每期支付, 终值) # 将多少钱1%的年利率存入银行5年,每年加存100元, # 到期后本息合计fv元? # pv = np.pv(0.01, 5, -100, fv) print(pv) # # 净现值 = numpy.npv(利率, 现金流) # 将1000元以1%的年利率存入银行5年,每年加存100元, # 相当于一次存入多少钱? # npv = np.npv(0.01, [-1000, -100, -100, -100, -100, -100]) print(round(npv, 2)) fv = np.fv(0.01, 5, 0, npv) print(round(fv, 2)) # # 内部收益率 = numpy.irr(现金流) # 将1000元存入银行5年,以后逐年提现100元、200元、300元、 # 400元、500元,银行利率达到多少,可在最后一次提现后偿 # 清全部本息? # irr = np.irr([-1000, 100, 200, 300, 400, 500]) print(round(irr, 2)) npv = np.npv(irr, [-1000, 100, 200, 300, 400, 500]) print(round(npv, 2)) # # 每期支付 = numpy.pmt(利率, 期数, 现值)
def work(modelDir, inputDict): ''' Model processing done here. ''' dispatchStrategy = str(inputDict.get('dispatchStrategy')) if dispatchStrategy == 'prediction': return forecastWork(modelDir, inputDict) out = {} # See bottom of file for out's structure cellCapacity, dischargeRate, chargeRate, cellQuantity, demandCharge, cellCost, retailCost = \ [float(inputDict[x]) for x in ('cellCapacity', 'dischargeRate', 'chargeRate', 'cellQuantity', 'demandCharge', 'cellCost', 'retailCost')] projYears, batteryCycleLife = [int(inputDict[x]) for x in ('projYears', 'batteryCycleLife')] discountRate = float(inputDict.get('discountRate')) / 100.0 dodFactor = float(inputDict.get('dodFactor')) / 100.0 # Efficiency calculation temporarily removed inverterEfficiency = float(inputDict.get('inverterEfficiency')) / 100.0 # Note: inverterEfficiency is squared to get round trip efficiency. battEff = float(inputDict.get('batteryEfficiency')) / 100.0 * (inverterEfficiency ** 2) with open(pJoin(modelDir, 'demand.csv'), 'w') as f: f.write(inputDict['demandCurve']) if dispatchStrategy == 'customDispatch': with open(pJoin(modelDir, 'dispatchStrategy.csv'), 'w') as f: f.write(inputDict['customDispatchStrategy']) dc = [] # main data table try: dates = [(dt(2011, 1, 1) + timedelta(hours=1)*x) for x in range(8760)] with open(pJoin(modelDir, 'demand.csv')) as f: reader = csv.reader(f) for row, date in zip(reader, dates): dc.append({ 'power': float(row[0]), # row is a list of length 1 'month': date.month - 1, 'hour': date.hour }) assert len(dc) == 8760 except: if str(sys.exc_info()[0]) != "<type 'exceptions.SystemExit'>": raise Exception("CSV file is incorrect format. Please see valid " "format definition at <a target='_blank' href = 'https://github.com/" "dpinney/omf/wiki/Models-~-storagePeakShave#demand-file-csv-format'>" "\nOMF Wiki storagePeakShave - Demand File CSV Format</a>") # list of 12 lists of monthly demands demandByMonth = [[t['power'] for t in dc if t['month']==x] for x in range(12)] monthlyPeakDemand = [max(lDemands) for lDemands in demandByMonth] battCapacity = cellQuantity * cellCapacity * dodFactor battDischarge = cellQuantity * dischargeRate battCharge = cellQuantity * chargeRate SoC = battCapacity if dispatchStrategy == 'optimal': ps = [battDischarge] * 12 # keep shrinking peak shave (ps) until every month doesn't fully expend the battery while True: SoC = battCapacity incorrect_shave = [False] * 12 for row in dc: month = row['month'] if not incorrect_shave[month]: powerUnderPeak = monthlyPeakDemand[month] - row['power'] - ps[month] charge = (min(powerUnderPeak, battCharge, battCapacity - SoC) if powerUnderPeak > 0 else -1 * min(abs(powerUnderPeak), battDischarge, SoC)) if charge == -1 * SoC: incorrect_shave[month] = True SoC += charge row['netpower'] = row['power'] + charge row['battSoC'] = SoC ps = [s-1 if incorrect else s for s, incorrect in zip(ps, incorrect_shave)] if not any(incorrect_shave): break elif dispatchStrategy == 'daily': start = int(inputDict.get('startPeakHour')) end = int(inputDict.get('endPeakHour')) for r in dc: # Discharge if hour is within peak hours otherwise charge charge = (-1*min(battDischarge, SoC) if start <= r['hour'] <= end else min(battCharge, battCapacity - SoC)) r['netpower'] = r['power'] + charge SoC += charge r['battSoC'] = SoC elif dispatchStrategy == 'customDispatch': try: with open(pJoin(modelDir,'dispatchStrategy.csv')) as f: reader = csv.reader(f) for d, r in zip(dc, reader): d['dispatch'] = int(r[0]) assert all(['dispatch' in r for r in dc]) # ensure each row is filled except: if str(sys.exc_info()[0]) != "<type 'exceptions.SystemExit'>": raise Exception("Dispatch Strategy file is in an incorrect " "format. Please see valid format definition at <a target " "= '_blank' href = 'https://github.com/dpinney/omf/wiki/" "Models-~-storagePeakShave#custom-dispatch-strategy-file-" "csv-format'>\nOMF Wiki storagePeakShave - Custom " "Dispatch Strategy File Format</a>") for r in dc: # Discharge if there is a 1 in the dispatch strategy csv, otherwise charge the battery. charge = (-1*min(battDischarge, SoC) if r['dispatch'] == 1 else min(battCharge, battCapacity-SoC)) r['netpower'] = r['power'] + charge SoC += charge r['battSoC'] = SoC # ------------------------- CALCULATIONS ------------------------- # netByMonth = [[t['netpower'] for t in dc if t['month']==x] for x in range(12)] monthlyPeakNet = [max(net) for net in netByMonth] ps = [h-s for h, s in zip(monthlyPeakDemand, monthlyPeakNet)] dischargeByMonth = [[i-j for i, j in zip(k, l) if i-j < 0] for k, l in zip(netByMonth, demandByMonth)] # Monthly Cost Comparison Table out['monthlyDemand'] = [sum(lDemand)/1000 for lDemand in demandByMonth] out['monthlyDemandRed'] = [t-p for t, p in zip(out['monthlyDemand'], ps)] out['ps'] = ps out['benefitMonthly'] = [x*demandCharge for x in ps] # Demand Before and After Storage Graph out['demand'] = [t['power']*1000.0 for t in dc] # kW -> W out['demandAfterBattery'] = [t['netpower']*1000.0 for t in dc] # kW -> W out['batteryDischargekW'] = [d-b for d, b in zip(out['demand'], out['demandAfterBattery'])] out['batteryDischargekWMax'] = max(out['batteryDischargekW']) # Battery State of Charge Graph # Turn dc's SoC into a percentage, with dodFactor considered. out['batterySoc'] = SoC = [t['battSoC']/battCapacity*100*dodFactor + (100-100*dodFactor) for t in dc] # Estimate number of cyles the battery went through. Sums the percent of SoC. cycleEquivalents = sum([SoC[i]-SoC[i+1] for i, x in enumerate(SoC[:-1]) if SoC[i+1] < SoC[i]]) / 100.0 out['cycleEquivalents'] = cycleEquivalents out['batteryLife'] = batteryCycleLife / cycleEquivalents # Cash Flow Graph # inserting battery efficiency only into the cashflow calculation # cashFlowCurve is $ in from peak shaving minus the cost to recharge the battery every day of the year cashFlowCurve = [sum(ps)*demandCharge for year in range(projYears)] cashFlowCurve.insert(0, -1 * cellCost * cellQuantity) # insert initial investment # simplePayback is also affected by the cost to recharge the battery every day of the year out['SPP'] = (cellCost*cellQuantity)/(sum(ps)*demandCharge) out['netCashflow'] = cashFlowCurve out['cumulativeCashflow'] = [sum(cashFlowCurve[:i+1]) for i, d in enumerate(cashFlowCurve)] out['NPV'] = npv(discountRate, cashFlowCurve) battCostPerCycle = cellQuantity * cellCost / batteryCycleLife lcoeTotCost = cycleEquivalents*retailCost + battCostPerCycle*cycleEquivalents out['LCOE'] = lcoeTotCost / (cycleEquivalents*battCapacity) # Other out['startDate'] = '2011-01-01' # dc[0]['datetime'].isoformat() out['stderr'] = '' # Seemingly unimportant. Ask permission to delete. out['stdout'] = 'Success' out['months'] = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] return out
def work(modelDir, inputDict): ''' Run the model in its directory. ''' # Copy spcific climate data into model directory inputDict["climateName"] = zipCodeToClimateName(inputDict["zipCode"]) shutil.copy(pJoin(__neoMetaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"), pJoin(modelDir, "climate.tmy2")) # Set up SAM data structures. ssc = nrelsam2013.SSCAPI() dat = ssc.ssc_data_create() # Required user inputs. ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2") ssc.ssc_data_set_number(dat, "system_size", float(inputDict.get("systemSize", 100))) derate = float(inputDict.get("pvModuleDerate", 99.5))/100 \ * float(inputDict.get("mismatch", 99.5))/100 \ * float(inputDict.get("diodes", 99.5))/100 \ * float(inputDict.get("dcWiring", 99.5))/100 \ * float(inputDict.get("acWiring", 99.5))/100 \ * float(inputDict.get("soiling", 99.5))/100 \ * float(inputDict.get("shading", 99.5))/100 \ * float(inputDict.get("sysAvail", 99.5))/100 \ * float(inputDict.get("age", 99.5))/100 \ * float(inputDict.get("inverterEfficiency", 92))/100 ssc.ssc_data_set_number(dat, "derate", derate) # TODO: Should we move inverter efficiency to 'inv_eff' below (as done in PVWatts?) # Doesn't seem to affect output very much # ssc.ssc_data_set_number(dat, "inv_eff", float(inputDict.get("inverterEfficiency", 92))/100) ssc.ssc_data_set_number(dat, "track_mode", float(inputDict.get("trackingMode", 0))) ssc.ssc_data_set_number(dat, "azimuth", float(inputDict.get("azimuth", 180))) # Advanced inputs with defaults. ssc.ssc_data_set_number(dat, "rotlim", float(inputDict.get("rotlim", 45))) ssc.ssc_data_set_number(dat, "gamma", float(inputDict.get("gamma", 0.5))/100) # Complicated optional inputs. if (inputDict.get("tilt",0) == "-"): tilt_eq_lat = 1.0 manualTilt = 0.0 else: tilt_eq_lat = 0.0 manualTilt = float(inputDict.get("tilt",0)) ssc.ssc_data_set_number(dat, "tilt", manualTilt) ssc.ssc_data_set_number(dat, "tilt_eq_lat", tilt_eq_lat) # Run PV system simulation. mod = ssc.ssc_module_create("pvwattsv1") ssc.ssc_module_exec(mod, dat) # Setting options for start time. simLengthUnits = inputDict.get("simLengthUnits","hours") simStartDate = inputDict.get("simStartDate", "2014-01-01") # Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html startDateTime = simStartDate + " 00:00:00 UTC" # Timestamp output. outData = {} outData["timeStamps"] = [dt.datetime.strftime( dt.datetime.strptime(startDateTime[0:19],"%Y-%m-%d %H:%M:%S") + dt.timedelta(**{simLengthUnits:x}),"%Y-%m-%d %H:%M:%S") + " UTC" for x in range(int(inputDict.get("simLength", 8760)))] # Geodata output. outData["city"] = ssc.ssc_data_get_string(dat, "city") outData["state"] = ssc.ssc_data_get_string(dat, "state") outData["lat"] = ssc.ssc_data_get_number(dat, "lat") outData["lon"] = ssc.ssc_data_get_number(dat, "lon") outData["elev"] = ssc.ssc_data_get_number(dat, "elev") # Weather output. outData["climate"] = {} outData["climate"]["Global Horizontal Radiation (W/m^2)"] = ssc.ssc_data_get_array(dat, "gh") outData["climate"]["Plane of Array Irradiance (W/m^2)"] = ssc.ssc_data_get_array(dat, "poa") outData["climate"]["Ambient Temperature (F)"] = ssc.ssc_data_get_array(dat, "tamb") outData["climate"]["Cell Temperature (F)"] = ssc.ssc_data_get_array(dat, "tcell") outData["climate"]["Wind Speed (m/s)"] = ssc.ssc_data_get_array(dat, "wspd") # Power generation and clipping. outData["powerOutputAc"] = ssc.ssc_data_get_array(dat, "ac") invSizeWatts = float(inputDict.get("inverterSize", 0)) * 1000 outData["InvClipped"] = [x if x < invSizeWatts else invSizeWatts for x in outData["powerOutputAc"]] try: outData["percentClipped"] = 100 * (1.0 - sum(outData["InvClipped"]) / sum(outData["powerOutputAc"])) except ZeroDivisionError: outData["percentClipped"] = 0.0 # Cashflow outputs. lifeSpan = int(inputDict.get("lifeSpan",30)) lifeYears = range(1, 1 + lifeSpan) retailCost = float(inputDict.get("retailCost",0.0)) degradation = float(inputDict.get("degradation",0.5))/100 installCost = float(inputDict.get("installCost",0.0)) discountRate = float(inputDict.get("discountRate", 7))/100 outData["oneYearGenerationWh"] = sum(outData["powerOutputAc"]) outData["lifeGenerationDollars"] = [retailCost*(1.0/1000)*outData["oneYearGenerationWh"]*(1.0-(x*degradation)) for x in lifeYears] outData["lifeOmCosts"] = [-1.0*float(inputDict["omCost"]) for x in lifeYears] outData["lifePurchaseCosts"] = [-1.0 * installCost] + [0 for x in lifeYears[1:]] srec = inputDict.get("srecCashFlow", "").split(",") outData["srecCashFlow"] = map(float,srec) + [0 for x in lifeYears[len(srec):]] outData["netCashFlow"] = [x+y+z+a for (x,y,z,a) in zip(outData["lifeGenerationDollars"], outData["lifeOmCosts"], outData["lifePurchaseCosts"], outData["srecCashFlow"])] outData["cumCashFlow"] = map(lambda x:x, _runningSum(outData["netCashFlow"])) outData["ROI"] = roundSig(sum(outData["netCashFlow"]), 3) / (-1*roundSig(sum(outData["lifeOmCosts"]), 3) + -1*roundSig(sum(outData["lifePurchaseCosts"], 3))) outData["NPV"] = roundSig(npv(discountRate, outData["netCashFlow"]), 3) outData["lifeGenerationWh"] = sum(outData["powerOutputAc"])*lifeSpan outData["lifeEnergySales"] = sum(outData["lifeGenerationDollars"]) try: # The IRR function is very bad. outData["IRR"] = roundSig(irr(outData["netCashFlow"]), 3) except: outData["IRR"] = "Undefined" # Monthly aggregation outputs. months = {"Jan":0,"Feb":1,"Mar":2,"Apr":3,"May":4,"Jun":5,"Jul":6,"Aug":7,"Sep":8,"Oct":9,"Nov":10,"Dec":11} totMonNum = lambda x:sum([z for (y,z) in zip(outData["timeStamps"], outData["powerOutputAc"]) if y.startswith(simStartDate[0:4] + "-{0:02d}".format(x+1))]) outData["monthlyGeneration"] = [[a, totMonNum(b)] for (a,b) in sorted(months.items(), key=lambda x:x[1])] # Heatmaped hour+month outputs. hours = range(24) from calendar import monthrange totHourMon = lambda h,m:sum([z for (y,z) in zip(outData["timeStamps"], outData["powerOutputAc"]) if y[5:7]=="{0:02d}".format(m+1) and y[11:13]=="{0:02d}".format(h+1)]) outData["seasonalPerformance"] = [[x,y,totHourMon(x,y) / monthrange(int(simStartDate[:4]), y+1)[1]] for x in hours for y in months.values()] # Stdout/stderr. outData["stdout"] = "Success" outData["stderr"] = "" return outData
import numpy as np # (1) 生成5个随机数作为现金流的取值。插入-100作为初始值。 cashflows = np.random.randint(100, size=5) cashflows = np.insert(cashflows, 0, -100) print("Cashflows", cashflows) # (2) 根据上一步生成的现金流数据,调用npv函数计算净现值。利率按3%计算 print("Net present value", np.npv(0.03, cashflows))
def work(modelDir, inputDict): ''' Run the model in a separate process. web.py calls this to run the model. This function will return fast, but results take a while to hit the file system.''' o = {} (cellCapacity, dischargeRate, chargeRate, cellQuantity, cellCost) = \ [float(inputDict[x]) for x in ('cellCapacity', 'dischargeRate', 'chargeRate', 'cellQuantity', 'cellCost')] inverterEfficiency = float(inputDict.get("inverterEfficiency")) / 100.0 battEff = float( inputDict.get("batteryEfficiency")) / 100.0 * (inverterEfficiency**2) discountRate = float(inputDict.get('discountRate')) / 100.0 dodFactor = float(inputDict.get('dodFactor')) / 100.0 projYears = int(inputDict.get('projYears')) dischargePriceThreshold = float(inputDict.get('dischargePriceThreshold')) chargePriceThreshold = float(inputDict.get('chargePriceThreshold')) batteryCycleLife = int(inputDict.get('batteryCycleLife')) # Put demand data in to a file for safe keeping. with open(pJoin(modelDir, 'demand.csv'), 'w') as f: f.write(inputDict['demandCurve']) with open(pJoin(modelDir, 'priceCurve.csv'), 'w') as f: f.write(inputDict['priceCurve']) # Most of our data goes inside the dc "table" dates = [dt(2011, 1, 1) + timedelta(hours=1) * x for x in range(8760)] dc = [] try: with open(pJoin(modelDir, 'demand.csv'), newline='') as f: for row, date in zip(csv.reader(f), dates): dc.append({'month': date.month - 1, 'power': float(row[0])}) assert len(dc) == 8760 except: if str(sys.exc_info()[0]) != "<type 'exceptions.SystemExit'>": raise Exception("Demand CSV file is incorrect format.") #Add price to dc table try: with open(pJoin(modelDir, 'priceCurve.csv'), newline='') as f: for row, d in zip(csv.reader(f), dc): d['price'] = float(row[0]) assert all(['price' in r for r in dc]) except: if str(sys.exc_info()[0]) != "<type 'exceptions.SystemExit'>": raise Exception("Price Curve File is in an incorrect format.") battCapacity = cellQuantity * cellCapacity * dodFactor battSoC = battCapacity for r in dc: #If price of energy is above price threshold and battery has charge, discharge battery if r['price'] >= dischargePriceThreshold: charge = -1 * min(cellQuantity * dischargeRate, battSoC) elif r['price'] <= chargePriceThreshold: charge = min(cellQuantity * chargeRate, battCapacity - battSoC) else: charge = 0 r['netpower'] = r['power'] + charge r['battSoC'] = battSoC battSoC += charge # There's definitely a nicer way to make this for loop, apologies monthlyCharge = [] monthlyDischarge = [] monthlyDischargeSavings = [] monthlyChargeCost = [] # Calculate the monthly cost to charge and savings by discharging for x in range(12): chargeCost = 0 dischargeSavings = 0 chargePower = 0 dischargePower = 0 for r in dc: if r['month'] == x: diff = r['netpower'] - r['power'] if diff > 0: chargePower += diff chargeCost += diff * r['price'] if diff < 0: dischargePower += -1 * diff dischargeSavings += -1 * diff * r['price'] monthlyCharge.append(chargePower) monthlyDischarge.append(dischargePower) monthlyDischargeSavings.append(dischargeSavings) monthlyChargeCost.append(chargeCost) # include BattEff into calculations monthlyCharge = [t / battEff for t in monthlyCharge] monthlyChargeCost = [t / battEff for t in monthlyChargeCost] # Monthly Cost Comparison Table o['energyOffset'] = monthlyDischarge o['dischargeSavings'] = monthlyDischargeSavings o['kWhtoRecharge'] = monthlyCharge o['costToRecharge'] = monthlyChargeCost # NPV, SPP are below # Demand Before and After Storage Graph o['demand'] = [t['power'] * 1000.0 for t in dc] o['demandAfterBattery'] = [t['netpower'] * 1000.0 for t in dc] o['batteryDischargekW'] = [ d - b for d, b in zip(o['demand'], o['demandAfterBattery']) ] o['batteryDischargekWMax'] = max(o['batteryDischargekW']) # Price Input Graph o['price'] = [r['price'] for r in dc] # Battery SoC Graph o['batterySoc'] = SoC = [ t['battSoC'] / battCapacity * 100.0 * dodFactor + (100 - 100 * dodFactor) for t in dc ] cycleEquivalents = sum([ SoC[i] - SoC[i + 1] for i, x in enumerate(SoC[:-1]) if SoC[i + 1] < SoC[i] ]) / 100.0 o['cycleEquivalents'] = cycleEquivalents o['batteryLife'] = batteryCycleLife / cycleEquivalents # Cash Flow Graph yearlyDischargeSavings = sum(monthlyDischargeSavings) yearlyChargeCost = sum(monthlyChargeCost) cashFlowCurve = [yearlyDischargeSavings - yearlyChargeCost] * projYears cashFlowCurve.insert(0, -1 * cellCost * cellQuantity) o['benefitNet'] = [ ds - cc for cc, ds in zip(o['costToRecharge'], o['dischargeSavings']) ] o['netCashflow'] = cashFlowCurve o['cumulativeCashflow'] = [ sum(cashFlowCurve[:i + 1]) for i, d in enumerate(cashFlowCurve) ] o['NPV'] = npv(discountRate, cashFlowCurve) o['SPP'] = (cellCost * cellQuantity) / (yearlyDischargeSavings - yearlyChargeCost) battCostPerCycle = cellQuantity * cellCost / batteryCycleLife lcoeTotCost = (cycleEquivalents * cellQuantity * cellCapacity * chargePriceThreshold) + (battCostPerCycle * cycleEquivalents) o['LCOE'] = lcoeTotCost / (cycleEquivalents * cellCapacity * cellQuantity) # Other o['startDate'] = '2011-01-01' o["stdout"] = "Success" o["stderr"] = "" return o
def pv(self): return np.npv(self.interest, [0] + self.cash_flows)
econ['expenses_variable']=(config['expenses']['variable']['oil']*econ['gross_sales_oil']+config['expenses']['variable']['gas']*econ['gross_sales_gas']+config['expenses']['variable']['ngl']*econ['gross_sales_ngl'])*config['working_interest'] econ['expenses_total']=(econ['expenses_variable']+config['expenses']['fixed'])*config['working_interest'] econ['gross_revenue_after_sevtax_and_expenses']=econ['gross_sales_total']-econ['severance_total']-econ['expenses_total'] econ['ad_valorum_tax']=econ['gross_revenue_after_sevtax_and_expenses']*config['taxes']['ad_valorum'] econ['gross_revenue_after_sevtax_and_expenses_and_advaltax']=econ['gross_revenue_after_sevtax_and_expenses']-econ['ad_valorum_tax'] econ['capital']=0.0 econ.ix[0,'capital']=(config['capital']['idc']+config['capital']['icc']+config['capital']['land'])*config['working_interest'] econ['gross_cash_flow']=econ['gross_revenue_after_sevtax_and_expenses_and_advaltax']-econ['capital'] econ['net_nondiscounted_cash_flow']=(econ['gross_revenue_after_sevtax_and_expenses_and_advaltax']*config['net_revenue_interest'])-econ['capital'] econ['cum_net_nondiscounted_cashflow']=econ['net_nondiscounted_cash_flow'].cumsum() econ['net_discounted_cashflow']=econ['net_nondiscounted_cash_flow']/(1+annual_to_monthly_rate(config['discount_rate_annual']))**econ['standard_time'] econ['cum_net_discounted_cashflow']=econ['net_discounted_cashflow'].cumsum() econ.to_excel(r'C:\Users\WaltN\Desktop\GitHub\curvey\output\econ.xlsx') npv=round(np.npv(annual_to_monthly_rate(config['discount_rate_annual']),econ['net_nondiscounted_cash_flow']), 2) irr=round(np.irr(econ['net_discounted_cashflow']), 2) print(''' NPV: ${} IRR: {} '''.format(npv, irr))
def taxEquityFlip(PPARateSixYearsTE, discRate, totalCost, allYearGenerationMWh, distAdderDirect, loanYears, firstYearLandLeaseCosts, firstYearOPMainCosts, firstYearInsuranceCosts, numberPanels): # Output Tax Equity Flip [C] coopInvestmentTaxEquity = -totalCost * (1 - 0.53) # Output Tax Equity Flip [D] financeCostCashTaxEquity = 0 # Output Tax Equity Flip [E] cashToSPEOForPPATE = [] # Output Tax Equity Flip [F] derivedCostEnergyTE = 0 # Output Tax Equity Flip [G] OMInsuranceETCTE = [] # Output Tax Equity Flip [H] cashFromSPEToBlockerTE = [] # Output Tax Equity Flip [I] cashFromBlockerTE = 0 # Output Tax Equity Flip [J] distAdderTaxEquity = distAdderDirect # Output Tax Equity Flip [K] netCoopPaymentsTaxEquity = [] # Output Tax Equity Flip [L] costToCustomerTaxEquity = [] # Output Tax Equity Flip [L64] NPVLoanTaxEquity = 0 # Output Tax Equity Flip [F72] Rate_Levelized_Equity = 0 # Tax Equity Flip Formulas # Output Tax Equity Flip [D] # TEI Calcs [E] financeCostOfCashTE = 0 coopFinanceRateTE = 2.7 / 100 if (coopFinanceRateTE == 0): financeCostOfCashTE = 0 else: payment = pmt( coopFinanceRateTE, loanYears, -coopInvestmentTaxEquity) financeCostCashTaxEquity = payment # Output Tax Equity Flip [E] SPERevenueTE = [] for i in range(1, len(allYearGenerationMWh) + 1): SPERevenueTE.append( PPARateSixYearsTE * allYearGenerationMWh[i]) if ((i >= 1) and (i <= 6)): cashToSPEOForPPATE.append(-SPERevenueTE[i - 1]) else: cashToSPEOForPPATE.append(0) # Output Tax Equity Flip [F] derivedCostEnergyTE = cashToSPEOForPPATE[ 0] / allYearGenerationMWh[1] # Output Tax Equity Flip [G] # TEI Calcs [F] [U] [V] landLeaseTE = [] OMTE = [] insuranceTE = [] for i in range(1, len(allYearGenerationMWh) + 1): landLeaseTE.append( firstYearLandLeaseCosts * math.pow((1 + .01), (i - 1))) OMTE.append(-firstYearOPMainCosts * math.pow((1 + .01), (i - 1))) insuranceTE.append(- firstYearInsuranceCosts * math.pow((1 + .025), (i - 1))) if (i < 7): OMInsuranceETCTE.append(float(landLeaseTE[i - 1])) else: OMInsuranceETCTE.append( float(OMTE[i - 1]) + float(insuranceTE[i - 1]) + float(landLeaseTE[i - 1])) # Output Tax Equity Flip [H] # TEI Calcs [T] SPEMgmtFeeTE = [] EBITDATE = [] EBITDATEREDUCED = [] managementFee = 10000 for i in range(1, len(SPERevenueTE) + 1): SPEMgmtFeeTE.append(-managementFee * math.pow((1 + .01), (i - 1))) EBITDATE.append(float(SPERevenueTE[ i - 1]) + float(OMTE[i - 1]) + float(insuranceTE[i - 1]) + float(SPEMgmtFeeTE[i - 1])) if (i <= 6): cashFromSPEToBlockerTE.append(float(EBITDATE[i - 1]) * .01) else: cashFromSPEToBlockerTE.append(0) EBITDATEREDUCED.append(EBITDATE[i - 1]) # Output Tax Equity Flip [I] # TEI Calcs [Y21] cashRevenueTE = -totalCost * (1 - 0.53) buyoutAmountTE = 0 for i in range(1, len(EBITDATEREDUCED) + 1): buyoutAmountTE = buyoutAmountTE + \ EBITDATEREDUCED[i - 1] / (math.pow(1 + 0.12, i)) buyoutAmountTE = buyoutAmountTE * 0.05 cashFromBlockerTE = - (buyoutAmountTE) + 0.0725 * cashRevenueTE # Output Tax Equity Flip [K] [L] for i in range(1, len(allYearGenerationMWh) + 1): if (i == 6): netCoopPaymentsTaxEquity.append(financeCostCashTaxEquity + cashToSPEOForPPATE[ i - 1] + cashFromSPEToBlockerTE[i - 1] + OMInsuranceETCTE[i - 1] + cashFromBlockerTE) else: netCoopPaymentsTaxEquity.append(financeCostCashTaxEquity + cashFromSPEToBlockerTE[ i - 1] + cashToSPEOForPPATE[i - 1] + OMInsuranceETCTE[i - 1]) costToCustomerTaxEquity.append( netCoopPaymentsTaxEquity[i - 1] - distAdderTaxEquity[i - 1]) # Output Tax Equity Flip [L37] NPVLoanTaxEquity = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + costToCustomerTaxEquity) # Output - Tax Equity [F42] Rate_Levelized_TaxEquity = - \ NPVLoanTaxEquity / NPVallYearGenerationMWh # TEI Calcs - Achieved Return [AW 21] #[AK] MACRDepreciation = [] MACRDepreciation.append(-0.99 * 0.2 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.32 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.192 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.1152 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.1152 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.0576 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) #[AI] [AL] [AN] cashRevenueTEI = [] # [AI] slDepreciation = [] # [AL] totalDistributions = [] # [AN] cashRevenueTEI.append(-totalCost * 0.53) for i in range(1, 7): cashRevenueTEI.append(EBITDATE[i - 1] * 0.99) slDepreciation.append(totalCost / 25) totalDistributions.append(-cashRevenueTEI[i]) #[AJ] ITC = totalCost * 0.9822 * 0.3 * 0.99 #[AM] taxableIncLoss = [0] taxableIncLoss.append(cashRevenueTEI[1] + MACRDepreciation[0]) #[AO] capitalAcct = [] capitalAcct.append(totalCost * 0.53) condition = capitalAcct[0] - 0.5 * ITC + \ taxableIncLoss[1] + totalDistributions[0] if condition > 0: capitalAcct.append(condition) else: capitalAcct.append(0) #[AQ] ratioTE = [0] #[AP] reallocatedIncLoss = [] #AO-1 + AN + AI + AK + AJ for i in range(0, 5): reallocatedIncLoss.append(capitalAcct[ i + 1] + totalDistributions[i + 1] + MACRDepreciation[i + 1] + cashRevenueTEI[i + 2]) ratioTE.append( reallocatedIncLoss[i] / (cashRevenueTEI[i + 2] + MACRDepreciation[i + 1])) taxableIncLoss.append(cashRevenueTEI[i + 2] + MACRDepreciation[i + 1] - ratioTE[ i + 1] * (MACRDepreciation[i + 1] - totalDistributions[i + 1])) condition = capitalAcct[ i + 1] + taxableIncLoss[i + 2] + totalDistributions[i + 1] if condition > 0: capitalAcct.append(condition) else: capitalAcct.append(0) #[AR] taxesBenefitLiab = [0] for i in range(1, 7): taxesBenefitLiab.append(-taxableIncLoss[i] * 0.35) #[AS] [AT] buyoutAmount = 0 taxFromBuyout = 0 for i in range(0, len(EBITDATEREDUCED)): buyoutAmount = buyoutAmount + .05 * \ EBITDATEREDUCED[i] / (math.pow(1.12, (i + 1))) taxFromBuyout = -buyoutAmount * 0.35 #[AU] [AV] totalCashTax = [] cumulativeCashTax = [0] for i in range(0, 7): if i == 1: totalCashTax.append( cashRevenueTEI[i] + ITC + taxesBenefitLiab[i] + 0 + 0) cumulativeCashTax.append( cumulativeCashTax[i] + totalCashTax[i]) elif i == 6: totalCashTax.append( cashRevenueTEI[i] + 0 + taxesBenefitLiab[i] + buyoutAmount + taxFromBuyout) cumulativeCashTax.append( cumulativeCashTax[i] + totalCashTax[i] + buyoutAmount + taxFromBuyout) else: totalCashTax.append( cashRevenueTEI[i] + 0 + taxesBenefitLiab[i] + 0 + 0) cumulativeCashTax.append( cumulativeCashTax[i] + totalCashTax[i]) #[AW21] if (cumulativeCashTax[7] > 0): cumulativeIRR = round(irr(totalCashTax), 4) else: cumulativeIRR = 0 # Deleteme: Variable Dump for debugging # variableDump = {} # variableDump["TaxEquity"] = {} # variableDump["TaxEquity"]["coopInvestmentTaxEquity"] = coopInvestmentTaxEquity # variableDump["TaxEquity"]["financeCostCashTaxEquity"] = financeCostCashTaxEquity # variableDump["TaxEquity"]["cashToSPEOForPPATE"] = cashToSPEOForPPATE # variableDump["TaxEquity"]["derivedCostEnergyTE"] = derivedCostEnergyTE # variableDump["TaxEquity"]["OMInsuranceETCTE"] = OMInsuranceETCTE # variableDump["TaxEquity"]["cashFromSPEToBlockerTE"] = cashFromSPEToBlockerTE # variableDump["TaxEquity"]["cashFromBlockerTE"] = cashFromBlockerTE # variableDump["TaxEquity"]["distAdderTaxEquity"] = distAdderTaxEquity # variableDump["TaxEquity"]["netCoopPaymentsTaxEquity"] = netCoopPaymentsTaxEquity # variableDump["TaxEquity"]["NPVLoanTaxEquity"] = NPVLoanTaxEquity return cumulativeIRR, Rate_Levelized_TaxEquity, NPVLoanTaxEquity
econ_cap['cum_net_nondiscounted_cashflow'] = econ_cap[ 'net_nondiscounted_cash_flow'].cumsum() econ_cap['net_discounted_cashflow'] = econ_cap.apply( lambda row: row['net_nondiscounted_cash_flow'] / ((1 + annual_to_monthly_rate(config['discount_rate_annual']))** (row['standard_time'])), axis=1) econ_cap['cum_net_discounted_cashflow'] = econ_cap[ 'net_discounted_cashflow'].cumsum() econ_cap.to_excel(excel_output_file) npv = round( np.npv(annual_to_monthly_rate(config['discount_rate_annual']), econ_cap['net_nondiscounted_cash_flow']), 2) irr = round(np.irr(econ_cap['net_nondiscounted_cash_flow']), 2) pv5 = round( np.npv(annual_to_monthly_rate(0.05), econ_cap['net_nondiscounted_cash_flow']), 2) pv8 = round( np.npv(annual_to_monthly_rate(0.08), econ_cap['net_nondiscounted_cash_flow']), 2) pv10 = round( np.npv(annual_to_monthly_rate(0.10), econ_cap['net_nondiscounted_cash_flow']), 2) pv15 = round( np.npv(annual_to_monthly_rate(0.15), econ_cap['net_nondiscounted_cash_flow']), 2) pv20 = round( np.npv(annual_to_monthly_rate(0.20),
def work(modelDir, inputDict): ''' Run the model in its directory. ''' outData = {} # Get variables. lifeSpan = int(inputDict.get('lifeSpan',25)) lifeYears = list(range(1, 1 + lifeSpan)) hours = list(range(0, 24)) DrTechCost = float(inputDict.get('DrPurchInstallCost')) demandCharge = float(inputDict.get('demandCharge')) retailCost = float(inputDict.get('retailCost')) AnnDROM = float(inputDict.get('AnnualDROperationCost')) SubElas = float(inputDict.get('SubstitutionPriceElasticity')) DayElas = float(inputDict.get('DailyPriceElasticity')) wholesaleCost = float(inputDict.get('WholesaleEnergyCost')) ManagLoad = float(inputDict.get('LoadunderManagement')) / 100.0 DiscountRate = float(inputDict.get('DiscountRate')) / 100 ScalingAnnual = float(inputDict.get('ScalingAnnual'))/ 100 PeakRate = float(inputDict.get('PeakRate')) OffPeakRate = float(inputDict.get('OffPeakRate')) startmonth= int(inputDict.get('startMonth')) stopmonth = int(inputDict.get('stopMonth')) starthour = int(inputDict.get('startHour')) stophour = int(inputDict.get('stopHour')) rateCPP = float(inputDict.get('rateCPP')) rate24hourly = [float(x) for x in inputDict.get('rate24hourly').split(',')] ratePTR = float(inputDict.get('ratePTR')) numCPPDays = int(inputDict.get('numCPPDays')) rateStruct = inputDict.get('rateStruct') # Price vector creation. OffPeakDailyPrice1 = [OffPeakRate for x in hours[0:starthour]] PeakDailyPrice = [PeakRate for x in hours[starthour-1:stophour]] OffPeakDailyPrice2 = [OffPeakRate for x in hours[stophour+1:24]] ProgramPrices =[] ProgramPrices.extend(OffPeakDailyPrice1) ProgramPrices.extend(PeakDailyPrice) ProgramPrices.extend(OffPeakDailyPrice2) # Setting up the demand curve. with open(pJoin(modelDir,"demand.csv"),"w") as demandFile: demandFile.write(inputDict['demandCurve']) try: demandList = [] with open(pJoin(modelDir,"demand.csv"), newline='') as inFile: reader = csv.reader(inFile) for row in reader: demandList.append(row) #######demandList.append({'datetime': parse(row['timestamp']), 'power': float(row['power'])}) if len(demandList)!=8760: raise Exception except: errorMessage = "CSV file is incorrect format. Please see valid format definition at <a target='_blank' href='https://github.com/dpinney/omf/wiki/Models-~-demandResponse#walkthrough'>OMF Wiki demandResponse</a>" raise Exception(errorMessage) demandCurve = [float(x[0]) for x in demandList] outData['startDate'] = '2011-01-01'######demandList[0]['datetime'].isoformat() # Run the PRISM model. allPrismOutput = prism({ 'rateStructure': rateStruct, # options: 2tier, 2tierCPP, PTR, 3tier, 24hourly 'elasticitySubWOCPP': SubElas, # Substitution elasticty during non-CPP days. 'elasticityDailyWOCPP': DayElas, # Daily elasticity during non-CPP days. 'elasticitySubWCPP': SubElas, # Substitution elasticty during CPP days. Only required for 2tierCPP 'elasticityDailyWCPP': DayElas, # Daily elasticity during non-CPP days. Only reuquired for 2tierCPP 'startMonth': startmonth, # 1-12. Beginning month of the cooling season when the DR program will run. 'stopMonth': stopmonth, # 1-12. Ending month of the cooling season when the DR program will run. 'startHour': starthour, # 0-23. Beginning hour for on-peak and CPP rates. 'stopHour': stophour, # 0-23. Ending hour for on-peak and CPP rates. 'rateFlat': retailCost, # pre-DR Time-independent rate paid by residential consumers. 'rateOffPeak': OffPeakRate, 'rateOnPeak': PeakRate, # Peak hour rate on non-CPP days. 'rateCPP': rateCPP, # Peak hour rate on CPP days. Only required for 2tierCPP 'rate24hourly': rate24hourly, #Hourly energy price, only needed for 24hourly 'ratePTR': ratePTR, # Only required for PTR. $/kWh payment to customers for demand reduction on PTR days. Value is entered as a positive value, just like the other rate values, even though it is a rebate. 'numCPPDays': numCPPDays, # Number of CPP days in a cooling season. Only required for 2tierCPP 'origLoad': demandCurve }) # 8760 load values fullParticipationModLoad = allPrismOutput['modLoad'] modifiedLoad = [x*ManagLoad+y*(1-ManagLoad) for x,y in zip(fullParticipationModLoad,demandCurve)] # with open('modifiedLoad.csv', 'wb') as outFile: # for row in modifiedLoad: # outfile.write(str(row) + '\n') diff = [y-x for x,y in zip(modifiedLoad,demandCurve)] # Demand Before and After Program Plot outData['modifiedLoad'] = modifiedLoad outData['demandLoad'] = demandCurve outData['difference'] = diff outData['differenceMax'] = round(max(diff),0) outData['differenceMin'] = round(min(diff),0) # Getting the hourly prices for the whole year (8760 prices) ProgPricesArrayYear = ProgramPrices*365 OneYearwholesaleCost = [wholesaleCost for x in range(8760)] AnnualEnergy = sum(demandCurve) demandCurveJanuary = max(demandCurve[0:744]) demandCurveFebruary = max(demandCurve[745:1416]) demandCurveMarch = max(demandCurve[1417:2160]) demandCurveApril = max(demandCurve[2161:2880]) demandCurveMay = max(demandCurve[2881:3624]) demandCurveJune = max(demandCurve[3625:4344]) demandCurveJuly = max(demandCurve[4345:5088]) demandCurveAugust = max(demandCurve[5089:5832]) demandCurveSeptember = max(demandCurve[5833:6552]) demandCurveOctober = max(demandCurve[6553:7296]) demandCurveNovmber = max(demandCurve[6553:7296]) demandCurveDecember = max(demandCurve[7297:8760]) maxMontlyDemand = [demandCurveJanuary,demandCurveFebruary,demandCurveMarch, demandCurveApril,demandCurveMay,demandCurveJune,demandCurveJuly, demandCurveAugust,demandCurveSeptember,demandCurveOctober, demandCurveNovmber,demandCurveDecember] annualDemandCost = demandCharge * sum(maxMontlyDemand) PowerCost = - (AnnualEnergy * wholesaleCost + annualDemandCost) # Calculating the maximum montly peaks after applying DR modifiedLoadJanuary = max(modifiedLoad[0:744]) modifiedLoadFebruary = max(modifiedLoad[745:1416]) modifiedLoadMarch = max(modifiedLoad[1417:2160]) modifiedLoadApril = max(modifiedLoad[2161:2880]) modifiedLoadMay = max(modifiedLoad[2881:3624]) modifiedLoadJune = max(modifiedLoad[3625:4344]) modifiedLoadJuly = max(modifiedLoad[4345:5088]) modifiedLoadAugust = max(modifiedLoad[5089:5832]) modifiedLoadSeptember = max(modifiedLoad[5833:6552]) modifiedLoadOctober = max(modifiedLoad[6553:7296]) modifiedLoadNovmber = max(modifiedLoad[6553:7296]) modifiedLoadDecember = max(modifiedLoad[7297:8760]) maxMontlyDemandDR = [modifiedLoadJanuary,modifiedLoadFebruary,modifiedLoadMarch, modifiedLoadApril,modifiedLoadMay,modifiedLoadJune,modifiedLoadJuly, modifiedLoadAugust,modifiedLoadSeptember,modifiedLoadOctober, modifiedLoadNovmber,modifiedLoadDecember] # Calculating the Base Case Profit EnergySale = sum(demandCurve) * retailCost EnergyCost = sum(demandCurve) * wholesaleCost PeakDemandCharge = sum([x*demandCharge for x in maxMontlyDemand]) BaseCaseProfit = EnergySale - EnergyCost - PeakDemandCharge # Calculating the DR Case Profit EnergySaleDR = sum([z[0]*z[1] for z in zip(modifiedLoad,ProgPricesArrayYear)]) PeakDemandChargeDR = sum([x*demandCharge for x in maxMontlyDemandDR]) energyCostDR = sum(modifiedLoad) * wholesaleCost DRCaseProfit = EnergySaleDR - PeakDemandChargeDR # Outputs of First Year Financial Impact table. outData["BaseCase"] = [AnnualEnergy, EnergySale, abs(EnergyCost), PeakDemandCharge, 0] outData["DRCase"] = [sum(modifiedLoad),EnergySaleDR, abs(energyCostDR), PeakDemandChargeDR, DrTechCost] # Calculating the Benefit Cashflow and Total benefit energySaleDRyear = [x*y for x,y in zip(ProgPricesArrayYear, demandCurve)] oneYearRetail = [retailCost for x in range(8760)] energySaleArray = [x*y for x,y in zip(oneYearRetail, demandCurve)] energySaleChange = sum(energySaleDRyear) - sum(energySaleArray) peakDemandRed = PeakDemandCharge - PeakDemandChargeDR # Calculating the Purchase Cost, Operation and Maint. Cost and Total Cost outData["AnnualOpCost"] = [- AnnDROM for x in lifeYears[0:]] LifetimeOperationCost = (sum(outData["AnnualOpCost"])) outData["LifetimeOperationCost"] = abs(LifetimeOperationCost) outData["lifePurchaseCosts"] = [-1.0 * DrTechCost] + [0 for x in lifeYears[1:]] outData["TotalCost"] = abs(outData["LifetimeOperationCost"] + DrTechCost) # Outputs of the Program Lifetime Cash Flow figure outData["EnergySaleChangeBenefit"] = [energySaleChange * ScalingAnnual ** x for x in range(lifeSpan)] outData["PeakDemandReduction"] = [peakDemandRed * ScalingAnnual ** x for x in range(lifeSpan)] BenefitCurve = [x+y for x,y in zip(outData["EnergySaleChangeBenefit"], outData["PeakDemandReduction"])] outData["TotalBenefit"] = sum(BenefitCurve) outData["BenefittoCostRatio"] = float(outData["TotalBenefit"] / outData["TotalCost"]) netBenefit = [x+y+z for x,y,z in zip(outData["AnnualOpCost"],outData["lifePurchaseCosts"],BenefitCurve)] outData["npv"] = npv(DiscountRate, netBenefit) outData["cumulativeNetBenefit"] = [sum(netBenefit[0:i+1]) for i,d in enumerate(netBenefit)] outData["SimplePaybackPeriod"] = DrTechCost / (outData["TotalBenefit"] / lifeSpan) # Stdout/stderr. outData["stdout"] = "Success" outData["stderr"] = "" return outData
def forecastWork(modelDir, ind): ''' Run the model in its directory.''' (cellCapacity, dischargeRate, chargeRate, cellQuantity, cellCost) = \ [float(ind[x]) for x in ('cellCapacity', 'dischargeRate', 'chargeRate', 'cellQuantity', 'cellCost')] demandCharge = float(ind['demandCharge']) retailCost = float(ind['retailCost']) battEff = float(ind.get("batteryEfficiency")) / 100.0 dodFactor = float(ind.get('dodFactor')) / 100.0 projYears = int(ind.get('projYears')) batteryCycleLife = int(ind.get('batteryCycleLife')) battCapacity = cellQuantity * float(ind['cellCapacity']) * dodFactor o = {} try: with open(pJoin(modelDir, 'hist.csv'), 'w') as f: f.write(ind['histCurve'].replace('\r', '')) df = pd.read_csv(pJoin(modelDir, 'hist.csv'), parse_dates=['dates']) df['month'] = df['dates'].dt.month df['dayOfYear'] = df['dates'].dt.dayofyear assert df.shape[0] >= 26280 # must be longer than 3 years assert df.shape[1] == 5 except: raise Exception("CSV file is incorrect format.") confidence = float(ind['confidence'])/100 # ---------------------- MAKE PREDICTIONS ------------------------------- # # train model on previous data all_X = fc.makeUsefulDf(df) all_y = df['load'] predictions = fc.neural_net_predictions(all_X, all_y) dailyLoadPredictions = [predictions[i:i+24] for i in range(0, len(predictions), 24)] weather = df['tempc'][-8760:] dailyWeatherPredictions = [weather[i:i+24] for i in range(0, len(weather), 24)] month = df['month'][-8760:] dispatched = [False]*365 # decide to implement VBAT every day for a year VB_power, VB_energy = [], [] for i, (load24, temp24, m) in enumerate(zip(dailyLoadPredictions, dailyWeatherPredictions, month)): peak = max(load24) if fc.shouldDispatchPS(peak, m, df, confidence): dispatched[i] = True vbp, vbe = fc.pulp24hrBattery(load24, dischargeRate*cellQuantity, cellCapacity*cellQuantity, battEff) VB_power.extend(vbp) VB_energy.extend(vbe) else: VB_power.extend([0]*24) VB_energy.extend([0]*24) # -------------------- MODEL ACCURACY ANALYSIS -------------------------- # o['predictedLoad'] = predictions o['trainAccuracy'] = 0#round(model.score(X_train, y_train) * 100, 2) o['testAccuracy'] = 0#round(model.score(X_test, y_test) * 100, 2) # PRECISION AND RECALL maxDays = [] for month in range(1, 13): test = df[df['month'] == month] maxDays.append(test.loc[test['load'].idxmax()]['dayOfYear']) shouldHaveDispatched = [False]*365 for day in maxDays: shouldHaveDispatched[day] = True truePositive = len([b for b in [i and j for (i, j) in zip(dispatched, shouldHaveDispatched)] if b]) falsePositive = len([b for b in [i and (not j) for (i, j) in zip(dispatched, shouldHaveDispatched)] if b]) falseNegative = len([b for b in [(not i) and j for (i, j) in zip(dispatched, shouldHaveDispatched)] if b]) o['precision'] = round(truePositive / float(truePositive + falsePositive) * 100, 2) o['recall'] = round(truePositive / float(truePositive + falseNegative) * 100, 2) o['number_of_dispatches'] = len([i for i in dispatched if i]) o['MAE'] = round(sum([abs(l-m)/m*100 for l, m in zip(predictions, list(all_y[-8760:]))])/8760., 2) # ---------------------- FINANCIAL ANALYSIS ----------------------------- # # Calculate monthHours year = df[-8760:].copy() year.reset_index(inplace=True) year['hour'] = list(year.index) start = list(year.groupby('month').first()['hour']) finish = list(year.groupby('month').last()['hour']) monthHours = [(s, f+1) for (s, f) in zip(start, finish)] demand = list(all_y[-8760:]) peakDemand = [max(demand[s:f]) for s, f in monthHours] demandAdj = [d+p for d, p in zip(demand, VB_power)] peakDemandAdj = [max(demandAdj[s:f]) for s, f in monthHours] discharges = [f if f < 0 else 0 for f in VB_power] # Monthly Cost Comparison Table o['monthlyDemand'] = peakDemand o['monthlyDemandRed'] = peakDemandAdj o['ps'] = [p-s for p, s in zip(peakDemand, peakDemandAdj)] o['benefitMonthly'] = [x*demandCharge for x in o['ps']] # Demand Before and After Storage Graph o['demand'] = demand o['demandAfterBattery'] = demandAdj o['batteryDischargekW'] = VB_power o['batteryDischargekWMax'] = max(VB_power) batteryCycleLife = float(ind['batteryCycleLife']) # Battery State of Charge Graph # Turn dc's SoC into a percentage, with dodFactor considered. o['batterySoc'] = SoC = [100 - (e / battCapacity * 100) for e in VB_energy] # Estimate number of cyles the battery went through. Sums the percent of SoC. cycleEquivalents = sum([SoC[i]-SoC[i+1] for i, x in enumerate(SoC[:-1]) if SoC[i+1] < SoC[i]]) / 100.0 o['cycleEquivalents'] = cycleEquivalents o['batteryLife'] = batteryCycleLife / cycleEquivalents # Cash Flow Graph # inserting battery efficiency only into the cashflow calculation # cashFlowCurve is $ in from peak shaving minus the cost to recharge the battery every day of the year cashFlowCurve = [sum(o['ps'])*demandCharge for year in range(projYears)] cashFlowCurve.insert(0, -1 * cellCost * cellQuantity) # insert initial investment # simplePayback is also affected by the cost to recharge the battery every day of the year o['SPP'] = (cellCost*cellQuantity)/(sum(o['ps'])*demandCharge) o['netCashflow'] = cashFlowCurve o['cumulativeCashflow'] = [sum(cashFlowCurve[:i+1]) for i, d in enumerate(cashFlowCurve)] o['NPV'] = npv(float(ind['discountRate']), cashFlowCurve) battCostPerCycle = cellQuantity * cellCost / batteryCycleLife lcoeTotCost = cycleEquivalents*retailCost + battCostPerCycle*cycleEquivalents o['LCOE'] = lcoeTotCost / (cycleEquivalents*battCapacity) # Other o['startDate'] = '2011-01-01' # dc[0]['datetime'].isoformat() o['stderr'] = '' # Seemingly unimportant. Ask permission to delete. o['stdout'] = 'Success' o['months'] = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] return o
def __init__(self, 数据, 成本收入索引, 工程费用索引, 工程建设其他费用索引, 基本预备费, 收购费用, 建设投资, 维修费): # ========================== self.数据 = 数据 self.成本收入索引 = 成本收入索引 self.工程费用索引 = 工程费用索引 self.工程建设其他费用索引 = 工程建设其他费用索引 self.维修费_全年量 = self.成本收入取值(维修费, self.数据.数据索引['维修费_设定值']) self.基本预备费 = 基本预备费 self.收购费用 = 收购费用 self.供冷收入_税前 = self.成本收入取值(self.成本收入索引['供冷收入'], self.数据.数据索引['供冷收入_设定值']) self.供蒸汽收入_税前 = self.成本收入取值(self.成本收入索引['蒸汽收入'], self.数据.数据索引['供蒸汽收入_设定值']) self.发电收入_税前 = self.成本收入取值(self.成本收入索引['售电收入'], self.数据.数据索引['发电收入_设定值']) self.供热收入_税前 = self.成本收入取值(self.成本收入索引['供热收入'], self.数据.数据索引['供热收入_设定值']) self.光伏发电收入_税前 = self.成本收入取值(self.成本收入索引['光伏发电收入'], self.数据.数据索引['光伏发电收入_设定值']) self.天然气销售收入_税前 = self.数据.数据索引['额外天然气销售年总收入'] self.供冷配套费收入_税前 = self.成本收入取值(0, self.数据.数据索引['供冷配套费收入_设定值']) self.供热配套费收入_税前 = self.成本收入取值(0, self.数据.数据索引['供冷配套费收入_设定值']) self.工资支出_全年量 = self.成本收入索引['工资及福利'] self.光伏运维成本_全年量 = self.成本收入取值(0, self.数据.数据索引['光伏运维成本_设定值']) self.天然气支出_税前 = self.成本收入取值( self.成本收入索引['燃气费'] + self.数据.数据索引['额外天然气销售年总成本'], self.数据.数据索引['天然气支出_设定值']) self.水支出_税前 = self.成本收入取值(self.成本收入索引['水费'], self.数据.数据索引['水支出_设定值']) self.电支出_税前 = self.成本收入取值(self.成本收入索引['电费'], self.数据.数据索引['电支出_设定值']) self.变压器容量费_税前 = self.数据.数据索引['变压器容量费'] self.系统备用容量费_税前 = self.数据.数据索引['系统备用容量费'] self.土地租金_全年量_税前 = self.数据.数据索引['土地租金'] self.设备租金_全年量_税前 = self.数据.数据索引['设备租金'] # self.建筑费用 = 工程费用索引['工程费用']['建筑'] self.设备费用 = 工程费用索引['工程费用']['设备'] self.安装费用 = 工程费用索引['工程费用']['安装'] self.工程建设其他费用总和 = self.工程建设其他费用索引['工程建设其他费用合计'] # 土地费用 self.土地费用 = self.工程建设其他费用索引['土地费'] self.土地购置费投资 = self.工程建设其他费用索引['土地费'] self.无形资产投资 = 0 self.建设投资 = 建设投资 self.借款 = self.建设投资 * self.数据.数据索引['借款比例'] self.建设期利息 = self.借款 * self.数据.数据索引['借款利率'] * 1.1 / 2 # 等于工资一半 self.其他管理费用_全年量 = self.工资支出_全年量 * self.数据.数据索引['其他管理费用占工资比例'] self.达产率 = self.数据.数据索引['达产率'] # ========一级目录========== self.现金流入dict = {} self.现金流出dict = {} self.现金流入 = [0] * 21 self.现金流出 = [0] * 21 # ========二级目录========= self.销售收入 = {} self.补贴收入 = [0] * 21 self.回收固定资产余值 = 0 self.回收流动资金 = 0 self.增值税销项税额 = {} self.增值税进项税额 = dict() self.增值税 = [0] * 21 self.流动资金 = {} self.经营成本 = {} # self.销售税金及附加 = {} # self.所得税 = {} # self.利用原有固定资产 = {} # self.特种基金 = {} # ========三级目录========= # 销售收入 self.供冷收入 = [0] * 21 self.供热收入 = [0] * 21 self.发电收入 = [0] * 21 self.光伏发电收入 = [0] * 21 self.供蒸汽收入 = [0] * 21 self.天然气销售收入 = [0] * 21 self.供冷配套费收入 = [0] * 21 self.供热配套费收入 = [0] * 21 self.销售收入总和 = [0] * 21 # 固定资产余值 self.建筑类固定资产余值 = 0 self.设备及安装类固定资产余值 = 0 self.回收固定资产余值 = 0 # 销项税 self.供冷收入销项税 = [0] * 21 self.供蒸汽收入销项税 = [0] * 21 self.发电收入销项税 = [0] * 21 self.供热收入销项税 = [0] * 21 self.光伏发电收入销项税 = [0] * 21 self.天然气销售收入销项税 = [0] * 21 self.供冷配套费收入销项税 = [0] * 21 self.供热配套费收入销项税 = [0] * 21 self.增值税销项税额总和 = [0] * 21 # 进项税 self.天然气支出进项税 = [0] * 21 self.水支出进项税 = [0] * 21 self.电支出进项税 = [0] * 21 self.变压器容量费进项税 = [0] * 21 self.系统备用容量费进项税 = [0] * 21 self.增值税进项税额总和 = [0] * 21 # 增值税 self.增值税总和 = [0] * 21 # 销售税金及附加总和 self.销售税金及附加总和 = [0] * 21 # 流动资金 self.应收账款 = [0] * 21 self.天然气存货 = [0] * 21 self.电存货 = [0] * 21 self.水存货 = [0] * 21 self.现金 = [0] * 21 self.应付账款 = [0] * 21 self.流动资金总和 = [0] * 21 # 经营成本 self.天然气支出 = [0] * 21 self.水支出 = [0] * 21 self.电支出 = [0] * 21 self.变压器容量费 = [0] * 21 self.系统备用容量费 = [0] * 21 self.工资支出 = [0] * 21 self.光伏运维成本 = [0] * 21 self.土地租金 = [0] * 21 self.维修费 = [0] * 21 self.其他管理费用 = [0] * 21 self.经营成本总和 = [0] * 21 # 所得税 self.利润总和 = [0] * 21 self.EBIT = [0] * 21 self.所得税总和 = [0] * 21 # 折旧费 self.工程建设其他费用待摊费用 = 0 self.税后建筑类投资 = 0 self.税后设备及安装类投资 = 0 self.建筑类折旧费 = [0] * 21 self.设备及安装类折旧费 = [0] * 21 self.无形资产折旧费 = [0] * 21 self.土地购置费折旧费 = [0] * 21 self.折旧费 = dict() self.折旧费总和 = [0] * 21 # 财务费用 self.财务费用 = [0] * 21 # 成本费用总和 self.成本费用总和 = [0] * 21 # 净现金流 self.税后净现金流量 = [0] * 21 self.累计税后净现金流量 = [0] * 21 # ===================计算======================== self.计算销售收入() self.计算销项税() self.计算经营成本() self.计算进项税() self.计算增值税及销售税金及附加() self.计算流动资金() self.计算折旧费() self.计算财务费用() self.计算成本费用总和() self.计算所得税() self.计算回收固定资产余值() self.计算回收流动资金() self.计算现金流入总和() self.计算现金流出总和() self.计算税后净现金流量() self.计算累计税后净现金流量() self.内部收益率 = np.irr(self.税后净现金流量) self.计算投资回收期() self.年均销售收入 = sum(self.销售收入总和) / 20 self.年均总成本费用 = sum(self.成本费用总和) / 20 self.年均利润总额 = sum(self.利润总和) / 20 self.净现值 = np.npv(0.12, self.税后净现金流量) self.生成技经计算结果() self.生成技经计算明细列表() print('税后净现金流量', self.税后净现金流量) print('内部收益率', self.内部收益率) print('投资回收期', self.投资回收期) print('建设投资', self.建设投资) print('年均利润总额', self.年均利润总额) print('现金流入', self.现金流入) print('销售收入总和', self.销售收入总和) print('增值税销项税额总和', self.增值税销项税额总和) print('现金流出', self.现金流出) print('增值税进项税额总和', self.增值税进项税额总和) print('增值税总和', self.增值税总和) print('流动资金总和', self.流动资金总和) print('经营成本总和', self.经营成本总和) print('销售税金及附加总和', self.销售税金及附加总和) print('所得税总和', self.所得税总和) print('成本费用总和', self.成本费用总和) for key, value in self.经营成本.items(): print(key, value) print('折旧费总和', self.折旧费总和) print('年均总成本费用', self.年均总成本费用) print('财务费用', self.财务费用) print('年均销售收入', self.年均销售收入) print('利润总和', self.利润总和) print('维修费', self.维修费) for key, value in self.流动资金.items(): print(key, value)
firstYearLandLeaseCosts = float( inputDict.get("costAcre", 0)) * landAmount else: firstYearLandLeaseCosts = 0 for i in range(1, len(outData["allYearGenerationMWh"]) + 1): OMInsuranceETCDirect.append(-firstYearOPMainCosts * math.pow((1 + .01), (i - 1)) - firstYearInsuranceCosts * math.pow( (1 + .025), (i - 1)) - firstYearLandLeaseCosts * math.pow((1 + .01), (i - 1))) distAdderDirect.append( float(inputDict.get("distAdder", 0)) * outData["allYearGenerationMWh"][i]) netCoopPaymentsDirect.append( OMInsuranceETCDirect[i - 1] + netFinancingCostsDirect) costToCustomerDirect.append( (netCoopPaymentsDirect[i - 1] - distAdderDirect[i - 1])) # Output - Direct Loan [F53] NPVLoanDirect = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + costToCustomerDirect) NPVallYearGenerationMWh = npv(float(inputDict.get( "discRate", 0)) / 100, [0, 0] + outData["allYearGenerationMWh"].values()) Rate_Levelized_Direct = -NPVLoanDirect / NPVallYearGenerationMWh # Master Output [Direct Loan] outData["levelCostDirect"] = Rate_Levelized_Direct outData["costPanelDirect"] = abs(NPVLoanDirect / numberPanels) outData["cost10WPanelDirect"] = ( float(outData["costPanelDirect"]) / panelSize) * 10 # NCREBs Financing ncrebsRate = float(inputDict.get("NCREBRate", 4.060)) / 100 ncrebBorrowingRate = 1.1 * ncrebsRate ncrebPaymentPeriods = 44
# 率,不考虑通胀因素。 # mirr函数计算修正后内部收益率(modified internal rate of return),是内部收益率的改进 # 版本。 # nper函数计算定期付款的期数。 # rate函数计算利率(rate of interest)。 print u"终值" #fv函数参数为利率,参数,每期支付金额,现值 print "Future value",np.fv(0.03/4, 5*4,-10,1000) print u"现值" #pv函数参数为利率,参数,每期支付金额,终值 print "Present value",np.pv(0.03/4,5*4,-10,1376.09633204) #npv参数为利率和一个表示现金流的数组. cashflows = np.random.randint(100,size=5) cashflows = np.insert(cashflows,0,-100) print "Cashflows",cashflows print "Net present value",np.npv(0.03,cashflows) print u"内部收益率" print "Internal rate of return",np.irr([-100, 38, 48,90 ,17,36]) print u"分期付款" #pmt输入为利率和期数,总价,输出每期钱数 print "Payment",np.pmt(0.10/12,12*30,100000) #nper参数为贷款利率,固定的月供和贷款额,输出付款期数 print "Number of payments", np.nper(0.10/12,-100,9000) #rate参数为付款期数,每期付款资金,现值和终值计算利率 print "Interest rate",12*np.rate(167,-100,9000,0) print u"窗函数" #bartlett函数可以计算巴特利特窗 window = np.bartlett(42) print "bartlett",window
def workForecast(modelDir, ind): ''' Run the model in its directory.''' o = {} # Grab data from CSV, try: with open(pJoin(modelDir, 'hist.csv'), 'w') as f: f.write(ind['histCurve'].replace('\r', '')) df = pd.read_csv(pJoin(modelDir, 'hist.csv'), parse_dates=['dates']) df['month'] = df['dates'].dt.month df['dayOfYear'] = df['dates'].dt.dayofyear assert df.shape[0] >= 26280 # must be longer than 3 years assert df.shape[1] == 5 except: raise Exception("CSV file is incorrect format.") # train model on previous data all_X = fc.makeUsefulDf(df) all_y = df['load'] X_train, y_train = all_X[:-8760], all_y[:-8760] clf = linear_model.SGDRegressor(max_iter=10000, tol=1e-4) clf.fit(X_train, y_train) # ---------------------- MAKE PREDICTIONS ------------------------------- # X_test, y_test = all_X[-8760:], all_y[-8760:] predictions = clf.predict(X_test) dailyLoadPredictions = [predictions[i:i+24] for i in range(0, len(predictions), 24)] P_lower, P_upper, E_UL = vbat24hr(ind, df['tempc'][-8760:]) dailyPl = [P_lower[i:i+24] for i in range(0, len(P_lower), 24)] dailyPu = [P_upper[i:i+24] for i in range(0, len(P_upper), 24)] dailyEu = [E_UL[i:i+24] for i in range(0, len(E_UL), 24)] vbp, vbe = [], [] dispatched_d = [False]*365 # Decide what days to dispatch zipped = zip(dailyLoadPredictions, df['month'][-8760:], dailyPl, dailyPu, dailyEu) for i, (load, m, pl, pu, eu) in enumerate(zipped): peak = max(load) if fc.shouldDispatchPS(peak, m, df, float(ind['confidence'])/100): dispatched_d[i] = True p, e = fc.pulp24hrVbat(ind, load, pl, pu, eu) vbp.extend(p) vbe.extend(e) else: vbp.extend([0]*24) vbe.extend([0]*24) ### TESTING FOR ACCURACY ### assert len(dailyPl) == 365 assert all([len(i) == 24 for i in dailyPl]) VB_power, VB_energy = vbp, vbe # -------------------- MODEL ACCURACY ANALYSIS -------------------------- # o['predictedLoad'] = list(clf.predict(X_test)) o['trainAccuracy'] = round(clf.score(X_train, y_train) * 100, 2) o['testAccuracy'] = round(clf.score(X_test, y_test) * 100, 2) # PRECISION AND RECALL maxDays = [] for month in range(1, 13): test = df[df['month'] == month] maxDays.append(test.loc[test['load'].idxmax()]['dayOfYear']) shouldHaveDispatched = [False]*365 for day in maxDays: shouldHaveDispatched[day] = True truePositive = len([b for b in [i and j for (i, j) in zip(dispatched_d, shouldHaveDispatched)] if b]) falsePositive = len([b for b in [i and (not j) for (i, j) in zip(dispatched_d, shouldHaveDispatched)] if b]) falseNegative = len([b for b in [(not i) and j for (i, j) in zip(dispatched_d, shouldHaveDispatched)] if b]) o['confidence'] = ind['confidence'] o['precision'] = round(truePositive / float(truePositive + falsePositive) * 100, 2) o['recall'] = round(truePositive / float(truePositive + falseNegative) * 100, 2) o['number_of_dispatches'] = len([i for i in dispatched_d if i]) o['MAE'] = round(sum([abs(l-m)/m*100 for l, m in zip(predictions, list(y_test))])/8760., 2) # ---------------------- FINANCIAL ANALYSIS ----------------------------- # o['VBpower'], o['VBenergy'] = list(VB_power), list(VB_energy) # Calculate monthHours year = df[-8760:].copy() year.reset_index(inplace=True) year['hour'] = list(year.index) start = list(year.groupby('month').first()['hour']) finish = list(year.groupby('month').last()['hour']) monthHours = [(s, f+1) for (s, f) in zip(start, finish)] demand = list(y_test) peakDemand = [max(demand[s:f]) for s, f in monthHours] energyMonthly = [sum(demand[s:f]) for s, f in monthHours] demandAdj = [d+p for d, p in zip(demand, o['VBpower'])] peakAdjustedDemand = [max(demandAdj[s:f]) for s, f in monthHours] energyAdjustedMonthly = [sum(demandAdj[s:f]) for s, f in monthHours] o['demand'] = demand o['peakDemand'] = peakDemand o['energyMonthly'] = energyMonthly o['demandAdjusted'] = demandAdj o['peakAdjustedDemand'] = peakAdjustedDemand o['energyAdjustedMonthly'] = energyAdjustedMonthly cellCost = float(ind['unitDeviceCost'])*float(ind['number_devices']) eCost = float(ind['electricityCost']) dCharge = float(ind['demandChargeCost']) o['VBdispatch'] = [dal-d for dal, d in zip(demandAdj, demand)] o['energyCost'] = [em*eCost for em in energyMonthly] o['energyCostAdjusted'] = [eam*eCost for eam in energyAdjustedMonthly] o['demandCharge'] = [peak*dCharge for peak in peakDemand] o['demandChargeAdjusted'] = [pad*dCharge for pad in o['peakAdjustedDemand']] o['totalCost'] = [ec+dcm for ec, dcm in zip(o['energyCost'], o['demandCharge'])] o['totalCostAdjusted'] = [eca+dca for eca, dca in zip(o['energyCostAdjusted'], o['demandChargeAdjusted'])] o['savings'] = [tot-tota for tot, tota in zip(o['totalCost'], o['totalCostAdjusted'])] annualEarnings = sum(o['savings']) - float(ind['unitUpkeepCost'])*float(ind['number_devices']) cashFlowList = [annualEarnings] * int(ind['projectionLength']) cashFlowList.insert(0, -1*cellCost) o['NPV'] = np.npv(float(ind['discountRate'])/100, cashFlowList) o['SPP'] = cellCost / annualEarnings o['netCashflow'] = cashFlowList o['cumulativeCashflow'] = [sum(cashFlowList[:i+1]) for i, d in enumerate(cashFlowList)] o['stdout'] = 'Success' return o
lifeSpan = int(inputDict.get("lifeSpan",30)) lifeYears = range(1, 1 + lifeSpan) retailCost = float(inputDict.get("retailCost",0.0)) degradation = float(inputDict.get("degradation",0.5))/100 installCost = float(inputDict.get("installCost",0.0)) discountRate = float(inputDict.get("discountRate", 7))/100 outData["oneYearGenerationWh"] = sum(outData["powerOutputAc"]) outData["lifeGenerationDollars"] = [retailCost*(1.0/1000)*outData["oneYearGenerationWh"]*(1.0-(x*degradation)) for x in lifeYears] outData["lifeOmCosts"] = [-1.0*float(inputDict["omCost"]) for x in lifeYears] outData["lifePurchaseCosts"] = [-1.0 * installCost] + [0 for x in lifeYears[1:]] srec = inputDict.get("srecCashFlow", "").split(",") outData["srecCashFlow"] = map(float,srec) + [0 for x in lifeYears[len(srec):]] outData["netCashFlow"] = [x+y+z+a for (x,y,z,a) in zip(outData["lifeGenerationDollars"], outData["lifeOmCosts"], outData["lifePurchaseCosts"], outData["srecCashFlow"])] outData["cumCashFlow"] = map(lambda x:x, _runningSum(outData["netCashFlow"])) outData["ROI"] = roundSig(sum(outData["netCashFlow"]), 3) / (-1*roundSig(sum(outData["lifeOmCosts"]), 3) + -1*roundSig(sum(outData["lifePurchaseCosts"], 3))) outData["NPV"] = roundSig(npv(discountRate, outData["netCashFlow"]), 3) outData["lifeGenerationWh"] = sum(outData["powerOutputAc"])*lifeSpan outData["lifeEnergySales"] = sum(outData["lifeGenerationDollars"]) try: # The IRR function is very bad. outData["IRR"] = roundSig(irr(outData["netCashFlow"]), 3) except: outData["IRR"] = "Undefined" # Monthly aggregation outputs. months = {"Jan":0,"Feb":1,"Mar":2,"Apr":3,"May":4,"Jun":5,"Jul":6,"Aug":7,"Sep":8,"Oct":9,"Nov":10,"Dec":11} totMonNum = lambda x:sum([z for (y,z) in zip(outData["timeStamps"], outData["powerOutputAc"]) if y.startswith(simStartDate[0:4] + "-{0:02d}".format(x+1))]) outData["monthlyGeneration"] = [[a, totMonNum(b)] for (a,b) in sorted(months.items(), key=lambda x:x[1])] # Heatmaped hour+month outputs. hours = range(24) from calendar import monthrange totHourMon = lambda h,m:sum([z for (y,z) in zip(outData["timeStamps"], outData["powerOutputAc"]) if y[5:7]=="{0:02d}".format(m+1) and y[11:13]=="{0:02d}".format(h+1)])
def value_can_afford(monthly_payment): # this is a 10 year average freddie mac interest rate ten_year_average_interest = .055 return np.npv(ten_year_average_interest/12, [monthly_payment]*30*12)
def work(modelDir, ind): #print(ind) ''' Run the model in its directory.''' # drop inverter efficiency # drop DoD (cellCapacity, dischargeRate, chargeRate, cellQuantity, cellCost) = \ [float(ind[x]) for x in ('cellCapacity', 'dischargeRate', 'chargeRate', 'cellQuantity', 'cellCost')] battEff = float(ind.get("batteryEfficiency")) / 100.0 dodFactor = float(ind.get('dodFactor')) / 100.0 projYears = int(ind.get('projectionLength')) batteryCycleLife = int(ind.get('batteryCycleLife')) o = {} try: with open(pJoin(modelDir, 'hist.csv'), 'w') as f: f.write(ind['historicalData'])#.replace('\r', '')) df = pd.read_csv(pJoin(modelDir, 'hist.csv'), parse_dates=['dates']) df['month'] = df['dates'].dt.month df['dayOfYear'] = df['dates'].dt.dayofyear assert df.shape[0] >= 26280 # must be longer than 3 years assert df.shape[1] == 5 except ZeroDivisionError: raise Exception("CSV file is incorrect format.") # retrieve goal goal = ind['goal'] threshold = float(ind['transformerThreshold'])*1000 confidence = float(ind['confidence'])/100 # train model on previous data all_X = fc.makeUsefulDf(df) all_y = df['load'] X_train, y_train = all_X[:-8760], all_y[:-8760] clf = linear_model.SGDRegressor(max_iter=10000, tol=1e-4) clf.fit(X_train, y_train) # ---------------------- MAKE PREDICTIONS ------------------------------- # X_test, y_test = all_X[-8760:], all_y[-8760:] # Collect data necessary for dispatch calculations predictions = clf.predict(X_test) dailyLoadPredictions = [predictions[i:i+24] for i in range(0, len(predictions), 24)] weather = df['tempc'][-8760:] dailyWeatherPredictions = [weather[i:i+24] for i in range(0, len(weather), 24)] month = df['month'][-8760:] dispatched = [False]*365 # decide to implement VBAT every day for a year VB_power, VB_energy = [], [] for i, (load24, temp24, m) in enumerate(zip(dailyLoadPredictions, dailyWeatherPredictions, month)): peak = max(load24) if fc.shouldDispatchDeferral(peak, df, confidence, threshold): dispatched[i] = True vbp, vbe = fc.pulp24hrBattery(load24, dischargeRate*cellQuantity, cellCapacity*cellQuantity, battEff) VB_power.extend(vbp) VB_energy.extend(vbe) else: VB_power.extend([0]*24) VB_energy.extend([0]*24) # -------------------- MODEL ACCURACY ANALYSIS -------------------------- # o['predictedLoad'] = list(clf.predict(X_test)) o['trainAccuracy'] = round(clf.score(X_train, y_train) * 100, 2) o['testAccuracy'] = round(clf.score(X_test, y_test) * 100, 2) # PRECISION AND RECALL maxDays = [] for month in range(1, 13): test = df[df['month'] == month] maxDays.append(test.loc[test['load'].idxmax()]['dayOfYear']) shouldHaveDispatched = [False]*365 for day in maxDays: shouldHaveDispatched[day] = True truePositive = len([b for b in [i and j for (i, j) in zip(dispatched, shouldHaveDispatched)] if b]) falsePositive = len([b for b in [i and (not j) for (i, j) in zip(dispatched, shouldHaveDispatched)] if b]) falseNegative = len([b for b in [(not i) and j for (i, j) in zip(dispatched, shouldHaveDispatched)] if b]) o['precision'] = round(truePositive / float(truePositive + falsePositive) * 100, 2) o['recall'] = round(truePositive / float(truePositive + falseNegative) * 100, 2) o['number_of_dispatches'] = len([i for i in dispatched if i]) o['MAE'] = round(sum([abs(l-m)/m*100 for l, m in zip(predictions, list(y_test))])/8760., 2) # ---------------------- FINANCIAL ANALYSIS ----------------------------- # o['VBpower'], o['VBenergy'] = list(VB_power), list(VB_energy) # Calculate monthHours year = df[-8760:].copy() year.reset_index(inplace=True) year['hour'] = list(year.index) start = list(year.groupby('month').first()['hour']) finish = list(year.groupby('month').last()['hour']) monthHours = [(s, f+1) for (s, f) in zip(start, finish)] demand = list(y_test) peakDemand = [max(demand[s:f]) for s, f in monthHours] energyMonthly = [sum(demand[s:f]) for s, f in monthHours] demandAdj = [d+p for d, p in zip(demand, o['VBpower'])] peakAdjustedDemand = [max(demandAdj[s:f]) for s, f in monthHours] energyAdjustedMonthly = [sum(demandAdj[s:f]) for s, f in monthHours] o['demand'] = demand o['peakDemand'] = peakDemand o['energyMonthly'] = energyMonthly o['demandAdjusted'] = demandAdj o['peakAdjustedDemand'] = peakAdjustedDemand o['energyAdjustedMonthly'] = energyAdjustedMonthly initInvestment = cellCost*cellQuantity eCost = float(ind['electricityCost']) dCharge = float(ind['demandChargeCost']) o['VBdispatch'] = [dal-d for dal, d in zip(demandAdj, demand)] o['energyCost'] = [em*eCost for em in energyMonthly] o['energyCostAdjusted'] = [eam*eCost for eam in energyAdjustedMonthly] o['demandCharge'] = [peak*dCharge for peak in peakDemand] o['demandChargeAdjusted'] = [pad*dCharge for pad in o['peakAdjustedDemand']] o['totalCost'] = [ec+dcm for ec, dcm in zip(o['energyCost'], o['demandCharge'])] o['totalCostAdjusted'] = [eca+dca for eca, dca in zip(o['energyCostAdjusted'], o['demandChargeAdjusted'])] o['savings'] = [tot-tota for tot, tota in zip(o['totalCost'], o['totalCostAdjusted'])] annualEarnings = sum(o['savings']) # - something! cashFlowList = [annualEarnings] * int(ind['projectionLength']) cashFlowList.insert(0, -1*initInvestment) o['NPV'] = np.npv(float(ind['discountRate'])/100, cashFlowList) o['SPP'] = initInvestment / annualEarnings o['netCashflow'] = cashFlowList o['cumulativeCashflow'] = [sum(cashFlowList[:i+1]) for i, d in enumerate(cashFlowList)] o['dataCheck'] = 'Threshold exceeded' if any([threshold > i for i in demandAdj]) and goal == 'deferral' else '' o['transformerThreshold'] = threshold if goal == 'deferral' else None o['stdout'] = 'Success' return o
import numpy as np cashflows = [-45.45, 50] npv = np.npv(0.1, cashflows) print(round(50 / (1 + 0.1), 2)) print(round(npv, 2))
def work(modelDir, inputDict): ''' Run the model in its directory. ''' #Set static input data simLength = 8760 simStartDate = "2013-01-01" # Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html startDateTime = simStartDate + " 00:00:00 UTC" simLengthUnits = "hours" # Associate zipcode to climate data inputDict["climateName"] = omf.weather.zipCodeToClimateName( inputDict["zipCode"]) inverterSizeAC = float(inputDict.get("inverterSize", 0)) if (inputDict.get("systemSize", 0) == "-"): arraySizeDC = 1.3908 * inverterSizeAC else: arraySizeDC = float(inputDict.get("systemSize", 0)) numberPanels = (arraySizeDC * 1000 / 305) # Set constants panelSize = 305 trackingMode = 0 rotlim = 45.0 gamma = 0.45 if (inputDict.get("tilt", 0) == "-"): tilt_eq_lat = 1.0 manualTilt = 0.0 else: tilt_eq_lat = 0.0 manualTilt = float(inputDict.get("tilt", 0)) numberInverters = math.ceil(inverterSizeAC / 1000 / 0.5) # Copy specific climate data into model directory shutil.copy( pJoin(__neoMetaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"), pJoin(modelDir, "climate.tmy2")) # Set up SAM data structures. ssc = nrelsam2013.SSCAPI() dat = ssc.ssc_data_create() # Required user inputs. ssc.ssc_data_set_string(dat, b'file_name', bytes(modelDir + '/climate.tmy2', 'ascii')) ssc.ssc_data_set_number(dat, b'system_size', arraySizeDC) ssc.ssc_data_set_number( dat, b'derate', float(inputDict.get('inverterEfficiency', 96)) / 100 * float(inputDict.get('nonInverterEfficiency', 87)) / 100) ssc.ssc_data_set_number(dat, b'track_mode', float(trackingMode)) ssc.ssc_data_set_number(dat, b'azimuth', float(inputDict.get('azimuth', 180))) # Advanced inputs with defaults. ssc.ssc_data_set_number(dat, b'rotlim', float(rotlim)) ssc.ssc_data_set_number(dat, b'gamma', float(-gamma / 100)) ssc.ssc_data_set_number(dat, b'tilt', manualTilt) ssc.ssc_data_set_number(dat, b'tilt_eq_lat', 0.0) # Run PV system simulation. mod = ssc.ssc_module_create(b'pvwattsv1') ssc.ssc_module_exec(mod, dat) # Timestamp output. outData = {} outData["timeStamps"] = [ dt.datetime.strftime( dt.datetime.strptime(startDateTime[0:19], "%Y-%m-%d %H:%M:%S") + dt.timedelta(**{simLengthUnits: x}), "%Y-%m-%d %H:%M:%S") + " UTC" for x in range(simLength) ] # Geodata output. outData["minLandSize"] = round( (arraySizeDC / 1390.8 * 5 + 1) * math.cos(math.radians(22.5)) / math.cos(math.radians(30.0)), 0) landAmount = float(inputDict.get("landAmount", 6.0)) outData['city'] = ssc.ssc_data_get_string(dat, b'city').decode() outData['state'] = ssc.ssc_data_get_string(dat, b'state').decode() outData['lat'] = ssc.ssc_data_get_number(dat, b'lat') outData['lon'] = ssc.ssc_data_get_number(dat, b'lon') outData['elev'] = ssc.ssc_data_get_number(dat, b'elev') # Weather output. outData['climate'] = {} outData['climate'][ 'Global Horizontal Radiation (W/m^2)'] = ssc.ssc_data_get_array( dat, b'gh') outData['climate'][ 'Plane of Array Irradiance (W/m^2)'] = ssc.ssc_data_get_array( dat, b'poa') outData['climate']['Ambient Temperature (F)'] = ssc.ssc_data_get_array( dat, b'tamb') outData['climate']['Cell Temperature (F)'] = ssc.ssc_data_get_array( dat, b'tcell') outData['climate']['Wind Speed (m/s)'] = ssc.ssc_data_get_array( dat, b'wspd') # Power generation. outData['powerOutputAc'] = ssc.ssc_data_get_array(dat, b'ac') # Calculate clipping. outData['powerOutputAc'] = ssc.ssc_data_get_array(dat, b'ac') invSizeWatts = inverterSizeAC * 1000 outData["powerOutputAcInvClipped"] = [ x if x < invSizeWatts else invSizeWatts for x in outData["powerOutputAc"] ] try: outData["percentClipped"] = 100 * ( 1.0 - sum(outData["powerOutputAcInvClipped"]) / sum(outData["powerOutputAc"])) except ZeroDivisionError: outData["percentClipped"] = 0.0 #One year generation outData["oneYearGenerationWh"] = sum(outData["powerOutputAcInvClipped"]) #Annual generation for all years loanYears = 25 outData["allYearGenerationMWh"] = {} outData["allYearGenerationMWh"][1] = float( outData["oneYearGenerationWh"]) / 1000000 # outData["allYearGenerationMWh"][1] = float(2019.576) for i in range(2, loanYears + 1): outData["allYearGenerationMWh"][i] = float( outData["allYearGenerationMWh"][i - 1]) * ( 1 - float(inputDict.get("degradation", 0.8)) / 100) # Summary of Results. ###### ### Total Costs (sum of): Hardware Costs, Design/Engineering/PM/EPC/Labor Costs, Siteprep Costs, Construction Costs, Installation Costs, Land Costs ###### ### Hardware Costs pvModules = arraySizeDC * float(inputDict.get("moduleCost", 0)) * 1000 #off by 4000 racking = arraySizeDC * float(inputDict.get("rackCost", 0)) * 1000 inverters = numberInverters * float(inputDict.get("inverterCost", 0)) inverterSize = inverterSizeAC if (inverterSize <= 250): gear = 15000 elif (inverterSize <= 600): gear = 18000 else: gear = inverterSize / 1000 * 22000 balance = inverterSizeAC * 1.3908 * 134 combiners = math.ceil(numberPanels / 19 / 24) * float(1800) #* wireManagement = arraySizeDC * 1.5 transformer = 1 * 28000 weatherStation = 1 * 12500 shipping = 1.02 hardwareCosts = (pvModules + racking + inverters + gear + balance + combiners + wireManagement + transformer + weatherStation) * shipping ### Design/Engineering/PM/EPC/Labor Costs EPCmarkup = float(inputDict.get("EPCRate", 0)) / 100 * hardwareCosts #designCosts = float(inputDict.get("mechLabor",0))*160 + float(inputDict.get("elecLabor",0))*75 + float(inputDict.get("pmCost",0)) + EPCmarkup hoursDesign = 160 * math.sqrt(arraySizeDC / 1390) hoursElectrical = 80 * math.sqrt(arraySizeDC / 1391) designLabor = 65 * hoursDesign electricalLabor = 75 * hoursElectrical laborDesign = designLabor + electricalLabor + float( inputDict.get("pmCost", 0)) + EPCmarkup materialDesign = 0 designCosts = materialDesign + laborDesign ### Siteprep Costs surveying = 2.25 * 4 * math.sqrt(landAmount * 43560) concrete = 8000 * math.ceil(numberInverters / 2) fencing = 6.75 * 4 * math.sqrt(landAmount * 43560) grading = 2.5 * 4 * math.sqrt(landAmount * 43560) landscaping = 750 * landAmount siteMaterial = 8000 + 600 + 5500 + 5000 + surveying + concrete + fencing + grading + landscaping + 5600 blueprints = float(inputDict.get("mechLabor", 0)) * 12 mobilization = float(inputDict.get("mechLabor", 0)) * 208 mobilizationMaterial = float(inputDict.get("mechLabor", 0)) * 19.98 siteLabor = blueprints + mobilization + mobilizationMaterial sitePrep = siteMaterial + siteLabor ### Construction Costs (Office Trailer, Skid Steer, Storage Containers, etc) constrEquip = 6000 + math.sqrt(landAmount) * 16200 ### Installation Costs moduleAndRackingInstall = numberPanels * (15.00 + 12.50 + 1.50) pierDriving = 1 * arraySizeDC * 20 balanceInstall = 1 * arraySizeDC * 100 installCosts = moduleAndRackingInstall + pierDriving + balanceInstall + float( inputDict.get("elecLabor", 0)) * (72 + 60 + 70 + 10 + 5 + 30 + 70) ### Land Costs if (str(inputDict.get("landOwnership", 0)) == "Owned" or (str(inputDict.get("landOwnership", 0)) == "Leased")): landCosts = 0 else: landCosts = float(inputDict.get("costAcre", 0)) * landAmount ###### ### Total Costs ###### totalCosts = hardwareCosts + designCosts + sitePrep + constrEquip + installCosts + landCosts totalFees = float(inputDict.get("devCost", 0)) / 100 * totalCosts outData["totalCost"] = totalCosts + totalFees + float( inputDict.get("interCost", 0)) # Add to Pie Chart outData["costsPieChart"] = [ ["Land", landCosts], ["Design/Engineering/PM/EPC", designCosts], ["PV Modules", pvModules * shipping], ["Racking", racking * shipping], ["Inverters & Switchgear", (inverters + gear) * shipping], [ "BOS", hardwareCosts - pvModules * shipping - racking * shipping - (inverters + gear) * shipping ], [ "Site Prep, Constr. Eq. and Installation", (siteMaterial + constrEquip) + (siteLabor + installCosts) ] ] # Cost per Wdc outData["costWdc"] = (totalCosts + totalFees + float( inputDict.get("interCost", 0))) / (arraySizeDC * 1000) outData["capFactor"] = float(outData["oneYearGenerationWh"]) / ( inverterSizeAC * 1000 * 365.25 * 24) * 100 ###### ### Loans calculations for Direct, NCREB, Lease, Tax-equity, and PPA ###### ### Full Ownership, Direct Loan #Output - Direct Loan [C] projectCostsDirect = 0 #Output - Direct Loan [D] netFinancingCostsDirect = 0 #Output - Direct Loan [E] OMInsuranceETCDirect = [] #Output - Direct Loan [F] distAdderDirect = [] #Output - Direct Loan [G] netCoopPaymentsDirect = [] #Output - Direct Loan [H] costToCustomerDirect = [] #Output - Direct Loan [F53] Rate_Levelized_Direct = 0 ## Output - Direct Loan Formulas projectCostsDirect = 0 #Output - Direct Loan [D] payment = pmt( float(inputDict.get("loanRate", 0)) / 100, loanYears, outData["totalCost"]) interestDirectPI = outData["totalCost"] * float( inputDict.get("loanRate", 0)) / 100 principleDirectPI = (-payment - interestDirectPI) patronageCapitalRetiredDPI = 0 netFinancingCostsDirect = -(principleDirectPI + interestDirectPI - patronageCapitalRetiredDPI) #Output - Direct Loan [E] [F] [G] [H] firstYearOPMainCosts = (1.25 * arraySizeDC * 12) firstYearInsuranceCosts = (0.37 * outData["totalCost"] / 100) if (inputDict.get("landOwnership", 0) == "Leased"): firstYearLandLeaseCosts = float(inputDict.get("costAcre", 0)) * landAmount else: firstYearLandLeaseCosts = 0 for i in range(1, len(outData["allYearGenerationMWh"]) + 1): OMInsuranceETCDirect.append( -firstYearOPMainCosts * math.pow((1 + .01), (i - 1)) - firstYearInsuranceCosts * math.pow((1 + .025), (i - 1)) - firstYearLandLeaseCosts * math.pow((1 + .01), (i - 1))) distAdderDirect.append( float(inputDict.get("distAdder", 0)) * outData["allYearGenerationMWh"][i]) netCoopPaymentsDirect.append(OMInsuranceETCDirect[i - 1] + netFinancingCostsDirect) costToCustomerDirect.append( (netCoopPaymentsDirect[i - 1] - distAdderDirect[i - 1])) #Output - Direct Loan [F53] NPVLoanDirect = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + costToCustomerDirect) NPVallYearGenerationMWh = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + list(outData["allYearGenerationMWh"].values())) Rate_Levelized_Direct = -NPVLoanDirect / NPVallYearGenerationMWh #Master Output [Direct Loan] outData["levelCostDirect"] = Rate_Levelized_Direct outData["costPanelDirect"] = abs(NPVLoanDirect / numberPanels) outData["cost10WPanelDirect"] = (float(outData["costPanelDirect"]) / panelSize) * 10 ### NCREBs Financing ncrebsRate = float(inputDict.get("NCREBRate", 4.060)) / 100 ncrebBorrowingRate = 1.1 * ncrebsRate ncrebPaymentPeriods = 44 ncrebCostToCustomer = [] # TODO ASAP: FIX ARRAY OFFSETS START 0 for i in range(1, len(outData["allYearGenerationMWh"]) + 1): coopLoanPayment = 2 * pmt( ncrebBorrowingRate / 2.0, ncrebPaymentPeriods, outData["totalCost"]) if i <= ncrebPaymentPeriods / 2 else 0 ncrebsCredit = -0.7 * ( ipmt(ncrebsRate / 2, 2 * i - 1, ncrebPaymentPeriods, outData["totalCost"]) + ipmt(ncrebsRate / 2, 2 * i, ncrebPaymentPeriods, outData["totalCost"])) if i <= ncrebPaymentPeriods / 2 else 0 financingCost = ncrebsCredit + coopLoanPayment omCost = OMInsuranceETCDirect[i - 1] netCoopPayments = financingCost + omCost distrAdder = distAdderDirect[i - 1] costToCustomer = netCoopPayments + distrAdder ncrebCostToCustomer.append(costToCustomer) NPVLoanNCREB = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + ncrebCostToCustomer) Rate_Levelized_NCREB = -NPVLoanNCREB / NPVallYearGenerationMWh outData["levelCostNCREB"] = Rate_Levelized_NCREB outData["costPanelNCREB"] = abs(NPVLoanNCREB / numberPanels) outData["cost10WPanelNCREB"] = (float(outData["costPanelNCREB"]) / panelSize) * 10 ### Lease Buyback Structure #Output - Lease [C] projectCostsLease = outData["totalCost"] #Output - Lease [D] leasePaymentsLease = [] #Output - Lease [E] OMInsuranceETCLease = OMInsuranceETCDirect #Output - Lease [F] distAdderLease = distAdderDirect #Output - Lease [G] netCoopPaymentsLease = [] #Output - Lease [H] costToCustomerLease = [] #Output - Lease [H44] NPVLease = 0 #Output - Lease [H49] Rate_Levelized_Lease = 0 ## Tax Lease Formulas #Output - Lease [D] for i in range(0, 12): leaseRate = float(inputDict.get("taxLeaseRate", 0)) / 100.0 if i > 8: # Special behavior in later years: leaseRate = leaseRate - 0.0261 leasePaymentsLease.append(-1 * projectCostsLease / ((1.0 - (1.0 / (1.0 + leaseRate)**12)) / (leaseRate))) # Last year is different. leasePaymentsLease[11] += -0.2 * projectCostsLease for i in range(12, 25): leasePaymentsLease.append(0) #Output - Lease [G] [H] for i in range(1, len(outData["allYearGenerationMWh"]) + 1): netCoopPaymentsLease.append(OMInsuranceETCLease[i - 1] + leasePaymentsLease[i - 1]) costToCustomerLease.append(netCoopPaymentsLease[i - 1] - distAdderLease[i - 1]) #Output - Lease [H44]. Note the extra year at the zero point to get the discounting right. NPVLease = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + costToCustomerLease) #Output - Lease [H49] (Levelized Cost Three Loops) Rate_Levelized_Lease = -NPVLease / NPVallYearGenerationMWh #Master Output [Lease] outData["levelCostTaxLease"] = Rate_Levelized_Lease outData["costPanelTaxLease"] = abs(NPVLease / numberPanels) outData["cost10WPanelTaxLease"] = (float(outData["costPanelTaxLease"]) / float(panelSize)) * 10 ### Tax Equity Flip Structure # Tax Equity Flip Function def taxEquityFlip(PPARateSixYearsTE, discRate, totalCost, allYearGenerationMWh, distAdderDirect, loanYears, firstYearLandLeaseCosts, firstYearOPMainCosts, firstYearInsuranceCosts, numberPanels): #Output Tax Equity Flip [C] coopInvestmentTaxEquity = -totalCost * (1 - 0.53) #Output Tax Equity Flip [D] financeCostCashTaxEquity = 0 #Output Tax Equity Flip [E] cashToSPEOForPPATE = [] #Output Tax Equity Flip [F] derivedCostEnergyTE = 0 #Output Tax Equity Flip [G] OMInsuranceETCTE = [] #Output Tax Equity Flip [H] cashFromSPEToBlockerTE = [] #Output Tax Equity Flip [I] cashFromBlockerTE = 0 #Output Tax Equity Flip [J] distAdderTaxEquity = distAdderDirect #Output Tax Equity Flip [K] netCoopPaymentsTaxEquity = [] #Output Tax Equity Flip [L] costToCustomerTaxEquity = [] #Output Tax Equity Flip [L64] NPVLoanTaxEquity = 0 #Output Tax Equity Flip [F72] Rate_Levelized_Equity = 0 ## Tax Equity Flip Formulas #Output Tax Equity Flip [D] #TEI Calcs [E] financeCostOfCashTE = 0 coopFinanceRateTE = 2.7 / 100 if (coopFinanceRateTE == 0): financeCostOfCashTE = 0 else: payment = pmt(coopFinanceRateTE, loanYears, -coopInvestmentTaxEquity) financeCostCashTaxEquity = payment #Output Tax Equity Flip [E] SPERevenueTE = [] for i in range(1, len(allYearGenerationMWh) + 1): SPERevenueTE.append(PPARateSixYearsTE * allYearGenerationMWh[i]) if ((i >= 1) and (i <= 6)): cashToSPEOForPPATE.append(-SPERevenueTE[i - 1]) else: cashToSPEOForPPATE.append(0) #Output Tax Equity Flip [F] derivedCostEnergyTE = cashToSPEOForPPATE[0] / allYearGenerationMWh[1] #Output Tax Equity Flip [G] #TEI Calcs [F] [U] [V] landLeaseTE = [] OMTE = [] insuranceTE = [] for i in range(1, len(allYearGenerationMWh) + 1): landLeaseTE.append(firstYearLandLeaseCosts * math.pow((1 + .01), (i - 1))) OMTE.append(-firstYearOPMainCosts * math.pow((1 + .01), (i - 1))) insuranceTE.append(-firstYearInsuranceCosts * math.pow((1 + .025), (i - 1))) if (i < 7): OMInsuranceETCTE.append(float(landLeaseTE[i - 1])) else: OMInsuranceETCTE.append( float(OMTE[i - 1]) + float(insuranceTE[i - 1]) + float(landLeaseTE[i - 1])) #Output Tax Equity Flip [H] #TEI Calcs [T] SPEMgmtFeeTE = [] EBITDATE = [] EBITDATEREDUCED = [] managementFee = 10000 for i in range(1, len(SPERevenueTE) + 1): SPEMgmtFeeTE.append(-managementFee * math.pow((1 + .01), (i - 1))) EBITDATE.append( float(SPERevenueTE[i - 1]) + float(OMTE[i - 1]) + float(insuranceTE[i - 1]) + float(SPEMgmtFeeTE[i - 1])) if (i <= 6): cashFromSPEToBlockerTE.append(float(EBITDATE[i - 1]) * .01) else: cashFromSPEToBlockerTE.append(0) EBITDATEREDUCED.append(EBITDATE[i - 1]) #Output Tax Equity Flip [I] #TEI Calcs [Y21] cashRevenueTE = -totalCost * (1 - 0.53) buyoutAmountTE = 0 for i in range(1, len(EBITDATEREDUCED) + 1): buyoutAmountTE = buyoutAmountTE + EBITDATEREDUCED[i - 1] / ( math.pow(1 + 0.12, i)) buyoutAmountTE = buyoutAmountTE * 0.05 cashFromBlockerTE = -(buyoutAmountTE) + 0.0725 * cashRevenueTE #Output Tax Equity Flip [K] [L] for i in range(1, len(allYearGenerationMWh) + 1): if (i == 6): netCoopPaymentsTaxEquity.append(financeCostCashTaxEquity + cashToSPEOForPPATE[i - 1] + cashFromSPEToBlockerTE[i - 1] + OMInsuranceETCTE[i - 1] + cashFromBlockerTE) else: netCoopPaymentsTaxEquity.append(financeCostCashTaxEquity + cashFromSPEToBlockerTE[i - 1] + cashToSPEOForPPATE[i - 1] + OMInsuranceETCTE[i - 1]) costToCustomerTaxEquity.append(netCoopPaymentsTaxEquity[i - 1] - distAdderTaxEquity[i - 1]) #Output Tax Equity Flip [L37] NPVLoanTaxEquity = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + costToCustomerTaxEquity) #Output - Tax Equity [F42] Rate_Levelized_TaxEquity = -NPVLoanTaxEquity / NPVallYearGenerationMWh #TEI Calcs - Achieved Return [AW 21] #[AK] MACRDepreciation = [] MACRDepreciation.append(-0.99 * 0.2 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.32 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.192 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.1152 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.1152 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) MACRDepreciation.append(-0.99 * 0.0576 * (totalCost - totalCost * 0.5 * 0.9822 * 0.3)) #[AI] [AL] [AN] cashRevenueTEI = [] #[AI] slDepreciation = [] #[AL] totalDistributions = [] #[AN] cashRevenueTEI.append(-totalCost * 0.53) for i in range(1, 7): cashRevenueTEI.append(EBITDATE[i - 1] * 0.99) slDepreciation.append(totalCost / 25) totalDistributions.append(-cashRevenueTEI[i]) #[AJ] ITC = totalCost * 0.9822 * 0.3 * 0.99 #[AM] taxableIncLoss = [0] taxableIncLoss.append(cashRevenueTEI[1] + MACRDepreciation[0]) #[AO] capitalAcct = [] capitalAcct.append(totalCost * 0.53) condition = capitalAcct[0] - 0.5 * ITC + taxableIncLoss[ 1] + totalDistributions[0] if condition > 0: capitalAcct.append(condition) else: capitalAcct.append(0) #[AQ] ratioTE = [0] #[AP] reallocatedIncLoss = [] #AO-1 + AN + AI + AK + AJ for i in range(0, 5): reallocatedIncLoss.append(capitalAcct[i + 1] + totalDistributions[i + 1] + MACRDepreciation[i + 1] + cashRevenueTEI[i + 2]) ratioTE.append(reallocatedIncLoss[i] / (cashRevenueTEI[i + 2] + MACRDepreciation[i + 1])) taxableIncLoss.append( cashRevenueTEI[i + 2] + MACRDepreciation[i + 1] - ratioTE[i + 1] * (MACRDepreciation[i + 1] - totalDistributions[i + 1])) condition = capitalAcct[i + 1] + taxableIncLoss[ i + 2] + totalDistributions[i + 1] if condition > 0: capitalAcct.append(condition) else: capitalAcct.append(0) #[AR] taxesBenefitLiab = [0] for i in range(1, 7): taxesBenefitLiab.append(-taxableIncLoss[i] * 0.35) #[AS] [AT] buyoutAmount = 0 taxFromBuyout = 0 for i in range(0, len(EBITDATEREDUCED)): buyoutAmount = buyoutAmount + .05 * EBITDATEREDUCED[i] / (math.pow( 1.12, (i + 1))) taxFromBuyout = -buyoutAmount * 0.35 #[AU] [AV] totalCashTax = [] cumulativeCashTax = [0] for i in range(0, 7): if i == 1: totalCashTax.append(cashRevenueTEI[i] + ITC + taxesBenefitLiab[i] + 0 + 0) cumulativeCashTax.append(cumulativeCashTax[i] + totalCashTax[i]) elif i == 6: totalCashTax.append(cashRevenueTEI[i] + 0 + taxesBenefitLiab[i] + buyoutAmount + taxFromBuyout) cumulativeCashTax.append(cumulativeCashTax[i] + totalCashTax[i] + buyoutAmount + taxFromBuyout) else: totalCashTax.append(cashRevenueTEI[i] + 0 + taxesBenefitLiab[i] + 0 + 0) cumulativeCashTax.append(cumulativeCashTax[i] + totalCashTax[i]) #[AW21] if (cumulativeCashTax[7] > 0): cumulativeIRR = round(irr(totalCashTax), 4) else: cumulativeIRR = 0 # Deleteme: Variable Dump for debugging # variableDump = {} # variableDump["TaxEquity"] = {} # variableDump["TaxEquity"]["coopInvestmentTaxEquity"] = coopInvestmentTaxEquity # variableDump["TaxEquity"]["financeCostCashTaxEquity"] = financeCostCashTaxEquity # variableDump["TaxEquity"]["cashToSPEOForPPATE"] = cashToSPEOForPPATE # variableDump["TaxEquity"]["derivedCostEnergyTE"] = derivedCostEnergyTE # variableDump["TaxEquity"]["OMInsuranceETCTE"] = OMInsuranceETCTE # variableDump["TaxEquity"]["cashFromSPEToBlockerTE"] = cashFromSPEToBlockerTE # variableDump["TaxEquity"]["cashFromBlockerTE"] = cashFromBlockerTE # variableDump["TaxEquity"]["distAdderTaxEquity"] = distAdderTaxEquity # variableDump["TaxEquity"]["netCoopPaymentsTaxEquity"] = netCoopPaymentsTaxEquity # variableDump["TaxEquity"]["NPVLoanTaxEquity"] = NPVLoanTaxEquity return cumulativeIRR, Rate_Levelized_TaxEquity, NPVLoanTaxEquity # Function Calls Mega Sized Tax Equity Function Above z = 0 PPARateSixYearsTE = z / 100 nGoal = float(inputDict.get("taxEquityReturn", 0)) / 100 nValue = 0 for p in range(0, 3): while ((z < 50000) and (nValue < nGoal)): achievedReturnTE, Rate_Levelized_TaxEquity, NPVLoanTaxEquity = taxEquityFlip( PPARateSixYearsTE, inputDict.get("discRate", 0), outData["totalCost"], outData["allYearGenerationMWh"], distAdderDirect, loanYears, firstYearLandLeaseCosts, firstYearOPMainCosts, firstYearInsuranceCosts, numberPanels) nValue = achievedReturnTE z = z + math.pow(10, p) PPARateSixYearsTE = z / 100.0 z = z - math.pow(10, p) PPARateSixYearsTE = z / 100 #Master Output [Tax Equity] outData["levelCostTaxEquity"] = Rate_Levelized_TaxEquity outData["costPanelTaxEquity"] = abs(NPVLoanTaxEquity / numberPanels) outData["cost10WPanelTaxEquity"] = (float(outData["costPanelTaxEquity"]) / panelSize) * 10 ### PPA Comparison #Output - PPA [F] distAdderPPA = distAdderDirect #Output - PPA [G] netCoopPaymentsPPA = [] #Output - PPA [H] costToCustomerPPA = [] #Output - PPA [I] costToCustomerPPA = [] #Output - PPA [H40] NPVLoanPPA = 0 #Output - PPA [I40] Rate_Levelized_PPA = 0 ## PPA Formulas #Output - PPA [G] [H] for i in range(1, len(outData["allYearGenerationMWh"]) + 1): netCoopPaymentsPPA.append( -outData["allYearGenerationMWh"][i] * float(inputDict.get("firstYearEnergyCostPPA", 0)) * math.pow( (1 + float(inputDict.get("annualEscRatePPA", 0)) / 100), (i - 1))) costToCustomerPPA.append(netCoopPaymentsPPA[i - 1] - distAdderPPA[i - 1]) #Output - PPA [H58] NPVLoanPPA = npv( float(inputDict.get("discRate", 0)) / 100, [0, 0] + costToCustomerPPA) #Output - PPA [F65] Rate_Levelized_PPA = -NPVLoanPPA / NPVallYearGenerationMWh #Master Output [PPA] outData["levelCostPPA"] = Rate_Levelized_PPA outData["firstYearCostKWhPPA"] = float( inputDict.get("firstYearEnergyCostPPA", 0)) outData["yearlyEscalationPPA"] = float(inputDict.get( "annualEscRatePPA", 0)) # Add all Levelized Costs to Output outData["LevelizedCosts"] = [["Direct Loan", Rate_Levelized_Direct], ["NCREBs Financing", Rate_Levelized_NCREB], ["Lease Buyback", Rate_Levelized_Lease], ["Tax Equity Flip", Rate_Levelized_TaxEquity]] outData["LevelizedCosts"].append({ "name": "PPA Comparison", "y": Rate_Levelized_PPA, "color": "gold" }) # Stdout/stderr. outData["stdout"] = "Success" outData["stderr"] = "" return outData
def heavyProcessing(modelDir, inputDict): ''' Run the model in a separate process. web.py calls this to run the model. This function will return fast, but results take a while to hit the file system.''' # Delete output file every run if it exists try: # Ready to run. startTime = datetime.datetime.now() outData = {} # Get variables. cellCapacity = float(inputDict['cellCapacity']) (cellCapacity, dischargeRate, chargeRate, cellQuantity, demandCharge, cellCost) = \ [float(inputDict[x]) for x in ('cellCapacity', 'dischargeRate', 'chargeRate', 'cellQuantity', 'demandCharge', 'cellCost')] battEff = float(inputDict.get("batteryEfficiency", 92)) / 100.0 * float(inputDict.get("inverterEfficiency", 92)) / 100.0 * float(inputDict.get("inverterEfficiency", 92)) / 100.0 discountRate = float(inputDict.get('discountRate', 2.5)) / 100.0 retailCost = float(inputDict.get('retailCost', 0.07)) dodFactor = float(inputDict.get('dodFactor', 85)) / 100.0 projYears = int(inputDict.get('projYears',10)) startPeakHour = int(inputDict.get('startPeakHour',18)) endPeakHour = int(inputDict.get('endPeakHour',24)) dispatchStrategy = str(inputDict.get('dispatchStrategy')) batteryCycleLife = int(inputDict.get('batteryCycleLife',5000)) # Put demand data in to a file for safe keeping. with open(pJoin(modelDir,"demand.csv"),"w") as demandFile: demandFile.write(inputDict['demandCurve']) # If dispatch is custom, write the strategy to a file in the model directory if dispatchStrategy == 'customDispatch': with open(pJoin(modelDir,"dispatchStrategy.csv"),"w") as customDispatchFile: customDispatchFile.write(inputDict['customDispatchStrategy']) # Start running battery simulation. battCapacity = cellQuantity * cellCapacity * dodFactor battDischarge = cellQuantity * dischargeRate battCharge = cellQuantity * chargeRate # Most of our data goes inside the dc "table" try: dc = [] with open(pJoin(modelDir,"demand.csv")) as inFile: reader = csv.DictReader(inFile) for row in reader: dc.append({'datetime': parse(row['timestamp']), 'power': float(row['power'])}) if len(dc)!=8760: raise Exception except: e = sys.exc_info()[0] if str(e) == "<type 'exceptions.SystemExit'>": pass else: errorMessage = "CSV file is incorrect format. Please see valid format definition at <a target='_blank' href = 'https://github.com/dpinney/omf/wiki/Models-~-storagePeakShave#demand-file-csv-format'>\nOMF Wiki storagePeakShave - Demand File CSV Format</a>" raise Exception(errorMessage) for row in dc: row['month'] = row['datetime'].month-1 row['hour'] = row['datetime'].hour # row['weekday'] = row['datetime'].weekday() # TODO: figure out why we care about this. if dispatchStrategy == "optimal": outData['startDate'] = dc[0]['datetime'].isoformat() ps = [battDischarge for x in range(12)] dcGroupByMonth = [[t['power'] for t in dc if t['datetime'].month-1==x] for x in range(12)] monthlyPeakDemand = [max(dcGroupByMonth[x]) for x in range(12)] capacityLimited = True while capacityLimited: battSoC = battCapacity # Battery state of charge; begins full. battDoD = [battCapacity for x in range(12)] # Depth-of-discharge every month, depends on dodFactor. for row in dc: month = int(row['datetime'].month)-1 powerUnderPeak = monthlyPeakDemand[month] - row['power'] - ps[month] isCharging = powerUnderPeak > 0 isDischarging = powerUnderPeak <= 0 charge = isCharging * min( powerUnderPeak * battEff, # Charge rate <= new monthly peak - row['power'] battCharge, # Charge rate <= battery maximum charging rate. battCapacity - battSoC) # Charge rage <= capacity remaining in battery. discharge = isDischarging * min( abs(powerUnderPeak), # Discharge rate <= new monthly peak - row['power'] abs(battDischarge), # Discharge rate <= battery maximum charging rate. abs(battSoC+.001)) # Discharge rate <= capacity remaining in battery. # (Dis)charge battery battSoC += charge battSoC -= discharge # Update minimum state-of-charge for this month. battDoD[month] = min(battSoC,battDoD[month]) row['netpower'] = row['power'] + charge/battEff - discharge row['battSoC'] = battSoC capacityLimited = min(battDoD) < 0 ps = [ps[month]-(battDoD[month] < 0) for month in range(12)] peakShaveSum = sum(ps) elif dispatchStrategy == "daily": outData['startDate'] = dc[0]['datetime'].isoformat() battSoC = battCapacity for row in dc: month = int(row['datetime'].month)-1 discharge = min(battDischarge,battSoC) charge = min(battCharge, battCapacity-battSoC) #If hour is within peak hours and the battery has charge if row['hour'] >= startPeakHour and row['hour'] <= endPeakHour and battSoC >= 0: row['netpower'] = row['power'] - discharge battSoC -= discharge else: #If hour is outside peak hours and the battery isnt fully charged, charge it if battSoC < battCapacity: battSoC += charge row['netpower'] = row['power'] + charge/battEff else: row['netpower'] = row['power'] row['battSoC'] = battSoC dcGroupByMonth = [[t['power'] for t in dc if t['datetime'].month-1==x] for x in range(12)] simpleDCGroupByMonth = [[t for t in dc if t['datetime'].month-1==x] for x in range(12)] #Finding rows with max power monthlyPeakDemand = [max(dVals, key=lambda x: x['power']) for dVals in simpleDCGroupByMonth] ps = [] #Determining monthly peak shave for row in monthlyPeakDemand: ps.append(row['power']-row['netpower']) peakShaveSum = sum(ps) else: try: with open(pJoin(modelDir,'dispatchStrategy.csv')) as strategyFile: reader = csv.DictReader(strategyFile) rowCount = 0 for i, row in enumerate(reader): dc[i]['dispatch'] = int(row['dispatch']) rowCount+=1 if rowCount!= 8760: raise Exception except: e = sys.exc_info()[0] if str(e) == "<type 'exceptions.SystemExit'>": pass else: errorMessage = "Dispatch Strategy file is in an incorrect format. Please see valid format definition at <a target = '_blank' href = 'https://github.com/dpinney/omf/wiki/Models-~-storagePeakShave#custom-dispatch-strategy-file-csv-format'>\nOMF Wiki storagePeakShave - Custom Dispatch Strategy File Format</a>" raise Exception(errorMessage) outData['startDate'] = dc[0]['datetime'].isoformat() battSoC = battCapacity for row in dc: month = int(row['datetime'].month)-1 discharge = min(battDischarge,battSoC) charge = min(battCharge, battCapacity-battSoC) #If there is a 1 in the dispatch strategy csv, the battery discharges if row['dispatch']==1: row['netpower'] = row['power'] - discharge battSoC -= discharge else: if battSoC < battCapacity: battSoC += charge row['netpower'] = row['power'] + charge/battEff else: row['netpower'] = row['power'] row['battSoC'] = battSoC dcGroupByMonth = [[t['power'] for t in dc if t['datetime'].month-1==x] for x in range(12)] #Calculating how much the battery discharges each month dischargeGroupByMonth = [[t['netpower']-t['power'] for t in dc if t['datetime'].month-1==x] for x in range(12)] simpleDCGroupByMonth = [[t for t in dc if t['datetime'].month-1==x] for x in range(12)] monthlyPeakDemand = [max(dVals, key=lambda x: x['power']) for dVals in simpleDCGroupByMonth] ps = [] for row in monthlyPeakDemand: ps.append(row['power']-row['netpower']) peakShaveSum = sum(ps) chargePerMonth = [] #Calculate how much the battery charges per year for cashFlowCurve, SPP calculation, kWhToRecharge for row in dischargeGroupByMonth: total = 0 for num in row: if num > 0: total += num chargePerMonth.append(total) totalYearlyCharge = sum(chargePerMonth) #Calculations dcThroughTheMonth = [[t for t in iter(dc) if t['datetime'].month-1<=x] for x in range(12)] hoursThroughTheMonth = [len(dcThroughTheMonth[month]) for month in range(12)] if peakShaveSum == 0: peakShaveSum = -1 #peakShave of 0 means no benefits, so make it -1 if dispatchStrategy == 'optimal': cashFlowCurve = [peakShaveSum * demandCharge for year in range(projYears)] outData['SPP'] = (cellCost*cellQuantity)/(peakShaveSum*demandCharge) elif dispatchStrategy == 'daily': #cashFlowCurve is $ in from peak shaving minus the cost to recharge the battery every day of the year cashFlowCurve = [(peakShaveSum * demandCharge)-(battCapacity*365*retailCost) for year in range(projYears)] #simplePayback is also affected by the cost to recharge the battery every day of the year outData['SPP'] = (cellCost*cellQuantity)/((peakShaveSum*demandCharge)-(battCapacity*365*retailCost)) else: cashFlowCurve = [(peakShaveSum * demandCharge)-(totalYearlyCharge*retailCost) for year in range(projYears)] outData['SPP'] = (cellCost*cellQuantity)/((peakShaveSum*demandCharge)-(totalYearlyCharge*retailCost)) cashFlowCurve[0]-= (cellCost * cellQuantity) outData['netCashflow'] = cashFlowCurve outData['cumulativeCashflow'] = [sum(cashFlowCurve[0:i+1]) for i,d in enumerate(cashFlowCurve)] outData['NPV'] = npv(discountRate, cashFlowCurve) outData['demand'] = [t['power']*1000.0 for t in dc] outData['demandAfterBattery'] = [t['netpower']*1000.0 for t in dc] outData['batterySoc'] = [t['battSoC']/battCapacity*100.0*dodFactor + (100-100*dodFactor) for t in dc] # Estimate number of cyles the battery went through. SoC = outData['batterySoc'] cycleEquivalents = sum([SoC[i]-SoC[i+1] for i,x in enumerate(SoC[0:-1]) if SoC[i+1] < SoC[i]]) / 100.0 outData['cycleEquivalents'] = cycleEquivalents outData['batteryLife'] = batteryCycleLife/cycleEquivalents # # Output some matplotlib results as well. # plt.plot([t['power'] for t in dc]) # plt.plot([t['netpower'] for t in dc]) # plt.plot([t['battSoC'] for t in dc]) # for month in range(12): # plt.axvline(hoursThroughTheMonth[month]) # plt.savefig(pJoin(modelDir,"plot.png")) # Summary of results outData['months'] = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] totMonNum = [] monthlyDemand = [] for x in range (0, len(dcGroupByMonth)): totMonNum.append(sum(dcGroupByMonth[x])/1000) monthlyDemand.append([outData['months'][x], totMonNum[x]]) outData['monthlyDemand'] = totMonNum outData['ps'] = ps outData['monthlyDemandRed'] = [totMonNum - ps for totMonNum, ps in zip(totMonNum, ps)] outData['benefitMonthly'] = [x * demandCharge for x in outData['ps']] if dispatchStrategy == 'optimal': outData['kWhtoRecharge'] = [battCapacity - x for x in outData['ps']] elif dispatchStrategy == 'daily': #Battery is dispatched and charged everyday, ~30 days per month kWhtoRecharge = [battCapacity * 30 -x for x in range(12)] outData['kWhtoRecharge'] = kWhtoRecharge else: # kWhtoRecharge = [] for num in chargePerMonth: kWhtoRecharge.append(num) outData['kWhtoRecharge'] = kWhtoRecharge outData['costtoRecharge'] = [retailCost * x for x in outData['kWhtoRecharge']] benefitMonthly = outData['benefitMonthly'] costtoRecharge = outData['costtoRecharge'] outData['benefitNet'] = [benefitMonthly - costtoRecharge for benefitMonthly, costtoRecharge in zip(benefitMonthly, costtoRecharge)] # Battery KW demandAfterBattery = outData['demandAfterBattery'] demand = outData['demand'] outData['batteryDischargekW'] = [demand - demandAfterBattery for demand, demandAfterBattery in zip(demand, demandAfterBattery)] outData['batteryDischargekWMax'] = max(outData['batteryDischargekW']) battCostPerCycle = cellQuantity * cellCapacity * cellCost / batteryCycleLife lcoeTotCost = (cycleEquivalents * cellQuantity * cellCapacity * retailCost) + (battCostPerCycle * cycleEquivalents) loceTotEnergy = cycleEquivalents * cellQuantity * cellCapacity LCOE = lcoeTotCost / loceTotEnergy outData['LCOE'] = LCOE # Stdout/stderr. outData["stdout"] = "Success" outData["stderr"] = "" # Write the output. with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile: json.dump(outData, outFile, indent=4) # Update the runTime in the input file. endTime = datetime.datetime.now() inputDict["runTime"] = str(datetime.timedelta(seconds=int((endTime - startTime).total_seconds()))) with open(pJoin(modelDir,"allInputData.json"),"w") as inFile: json.dump(inputDict, inFile, indent=4) try: os.remove(pJoin(modelDir,"PPID.txt")) except: pass except: # If input range wasn't valid delete output, write error to disk. cancel(modelDir) thisErr = traceback.format_exc() print 'ERROR IN MODEL', modelDir, thisErr inputDict['stderr'] = thisErr with open(os.path.join(modelDir,'stderr.txt'),'w') as errorFile: errorFile.write(thisErr) with open(pJoin(modelDir,"allInputData.json"),"w") as inFile: json.dump(inputDict, inFile, indent=4)
timeRemaining = int(np.floor((5*240) - (exDrillTime + prodDrillTime))) # 5 years - exploration and production drill time randomWalk = gmr(40.3, timeRemaining, 1) # Generate spot oil prices for time remaining days # Arrays to be reset each simulation qProd =[] revProd = [] cProd = [] netProd = [] oilVal = [] for x in range(timeRemaining): prodQ = prodQt(i+1) qProd.append(prodQ) revProd.append(randomWalk[x]*prodQ) cProd.append(prodQ*prodCost) netProd.append(revProd[x]-cProd[x]) oilVal.append(randomWalk[x]) npvProd.append(np.npv(dailyRate, netProd)) NPVcProd.append(np.npv(dailyRate, cProd)) NPVrevProd.append(np.npv(dailyRate, revProd)) SUMqProd.append(np.sum(qProd)) npvOilVal.append(np.npv(dailyRate, oilVal)) finalRev.append(np.npv(dailyRate, netProd)-1000.0*(cPreDiscover[i]+cDryWell[i]+cDrill[i]+cLogging[i]+cBlowout[i])) else: finalRev.append(-1000.0*(cPreDiscover[i]+cDryWell[i]+cDrill[i]+cLogging[i]+cBlowout[i])) npvProd.append(0) print("Pre Discovery") print(descriptiveStats(cPreDiscover)) print(percentilesC(cPreDiscover)) print("Dry Well") print(descriptiveStats(cDryWell)) print(percentilesC(cDryWell))
def test_npv_decimal(self): assert_equal( np.npv(Decimal('0.05'), [-15000, 1500, 2500, 3500, 4500, 6000]), Decimal('122.894854950942692161628715'))
def heavyProcessing(modelDir, inputDict): ''' Run the model in a separate process. web.py calls this to run the model. This function will return fast, but results take a while to hit the file system.''' # Delete output file every run if it exists try: # Ready to run. startTime = datetime.datetime.now() outData = {} # Get variables. cellCapacity = float(inputDict['cellCapacity']) (cellCapacity, dischargeRate, chargeRate, cellQuantity, demandCharge, cellCost) = \ [float(inputDict[x]) for x in ('cellCapacity', 'dischargeRate', 'chargeRate', 'cellQuantity', 'demandCharge', 'cellCost')] battEff = float(inputDict.get("batteryEfficiency", 92)) / 100.0 * float(inputDict.get("inverterEfficiency", 92)) / 100.0 * float(inputDict.get("inverterEfficiency", 92)) / 100.0 discountRate = float(inputDict.get('discountRate', 2.5)) / 100.0 retailCost = float(inputDict.get('retailCost', 0.07)) dodFactor = float(inputDict.get('dodFactor', 85)) / 100.0 projYears = int(inputDict.get('projYears',10)) # Put demand data in to a file for safe keeping. with open(pJoin(modelDir,"demand.csv"),"w") as demandFile: demandFile.write(inputDict['demandCurve']) # Start running battery simulation. battCapacity = cellQuantity * cellCapacity * dodFactor battDischarge = cellQuantity * dischargeRate battCharge = cellQuantity * chargeRate # Most of our data goes inside the dc "table" try: dc = [] with open(pJoin(modelDir,"demand.csv")) as inFile: reader = csv.DictReader(inFile) for row in reader: dc.append({'datetime': parse(row['timestamp']), 'power': float(row['power'])}) if len(dc)<8760: raise Exception except: errorMessage = "CSV file is incorrect format. Please see valid format definition at\n <a target='_blank' href = 'https://github.com/dpinney/omf/wiki/Models-~-energyStorage#demand-file-csv-format'>OMF Wiki energyStorage</a>" raise Exception(errorMessage) for row in dc: row['month'] = row['datetime'].month-1 row['weekday'] = row['datetime'].weekday outData['startDate'] = dc[0]['datetime'].isoformat() ps = [battDischarge for x in range(12)] dcGroupByMonth = [[t['power'] for t in dc if t['datetime'].month-1==x] for x in range(12)] monthlyPeakDemand = [max(dcGroupByMonth[x]) for x in range(12)] capacityLimited = True while capacityLimited: battSoC = battCapacity # Battery state of charge; begins full. battDoD = [battCapacity for x in range(12)] # Depth-of-discharge every month, depends on dodFactor. for row in dc: month = int(row['datetime'].month)-1 powerUnderPeak = monthlyPeakDemand[month] - row['power'] - ps[month] isCharging = powerUnderPeak > 0 isDischarging = powerUnderPeak <= 0 charge = isCharging * min( powerUnderPeak * battEff, # Charge rate <= new monthly peak - row['power'] battCharge, # Charge rate <= battery maximum charging rate. battCapacity - battSoC) # Charge rage <= capacity remaining in battery. discharge = isDischarging * min( abs(powerUnderPeak), # Discharge rate <= new monthly peak - row['power'] abs(battDischarge), # Discharge rate <= battery maximum charging rate. abs(battSoC+.001)) # Discharge rate <= capacity remaining in battery. # (Dis)charge battery battSoC += charge battSoC -= discharge # Update minimum state-of-charge for this month. battDoD[month] = min(battSoC,battDoD[month]) row['netpower'] = row['power'] + charge/battEff - discharge row['battSoC'] = battSoC capacityLimited = min(battDoD) < 0 ps = [ps[month]-(battDoD[month] < 0) for month in range(12)] dcThroughTheMonth = [[t for t in iter(dc) if t['datetime'].month-1<=x] for x in range(12)] hoursThroughTheMonth = [len(dcThroughTheMonth[month]) for month in range(12)] peakShaveSum = sum(ps) outData['SPP'] = (cellCost*cellQuantity)/(peakShaveSum*demandCharge) cashFlowCurve = [peakShaveSum * demandCharge for year in range(projYears)] cashFlowCurve[0]-= (cellCost * cellQuantity) outData['netCashflow'] = cashFlowCurve outData['cumulativeCashflow'] = [sum(cashFlowCurve[0:i+1]) for i,d in enumerate(cashFlowCurve)] outData['NPV'] = npv(discountRate, cashFlowCurve) outData['demand'] = [t['power']*1000.0 for t in dc] outData['demandAfterBattery'] = [t['netpower']*1000.0 for t in dc] outData['batterySoc'] = [t['battSoC']/battCapacity*100.0*dodFactor + (100-100*dodFactor) for t in dc] # Estimate number of cyles the battery went through. SoC = outData['batterySoc'] outData['cycleEquivalents'] = sum([SoC[i]-SoC[i+1] for i,x in enumerate(SoC[0:-1]) if SoC[i+1] < SoC[i]]) / 100.0 # # Output some matplotlib results as well. # plt.plot([t['power'] for t in dc]) # plt.plot([t['netpower'] for t in dc]) # plt.plot([t['battSoC'] for t in dc]) # for month in range(12): # plt.axvline(hoursThroughTheMonth[month]) # plt.savefig(pJoin(modelDir,"plot.png")) # Summary of results outData['months'] = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] totMonNum = [] monthlyDemand = [] for x in range (0, len(dcGroupByMonth)): totMonNum.append(sum(dcGroupByMonth[x])/1000) monthlyDemand.append([outData['months'][x], totMonNum[x]]) outData['monthlyDemand'] = totMonNum outData['ps'] = ps outData['monthlyDemandRed'] = [totMonNum - ps for totMonNum, ps in zip(totMonNum, ps)] outData['benefitMonthly'] = [x * demandCharge for x in outData['ps']] outData['kWhtoRecharge'] = [battCapacity - x for x in outData['ps']] outData['costtoRecharge'] = [retailCost * x for x in outData['kWhtoRecharge']] benefitMonthly = outData['benefitMonthly'] costtoRecharge = outData['costtoRecharge'] outData['benefitNet'] = [benefitMonthly - costtoRecharge for benefitMonthly, costtoRecharge in zip(benefitMonthly, costtoRecharge)] # Battery KW demandAfterBattery = outData['demandAfterBattery'] demand = outData['demand'] outData['batteryDischargekW'] = [demand - demandAfterBattery for demand, demandAfterBattery in zip(demand, demandAfterBattery)] outData['batteryDischargekWMax'] = max(outData['batteryDischargekW']) # Stdout/stderr. outData["stdout"] = "Success" outData["stderr"] = "" # Write the output. with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile: json.dump(outData, outFile, indent=4) # Update the runTime in the input file. endTime = datetime.datetime.now() inputDict["runTime"] = str(datetime.timedelta(seconds=int((endTime - startTime).total_seconds()))) with open(pJoin(modelDir,"allInputData.json"),"w") as inFile: json.dump(inputDict, inFile, indent=4) try: os.remove(pJoin(modelDir,"PPID.txt")) except: pass except: # If input range wasn't valid delete output, write error to disk. cancel(modelDir) thisErr = traceback.format_exc() print 'ERROR IN MODEL', modelDir, thisErr inputDict['stderr'] = thisErr with open(os.path.join(modelDir,'stderr.txt'),'w') as errorFile: errorFile.write(thisErr) with open(pJoin(modelDir,"allInputData.json"),"w") as inFile: json.dump(inputDict, inFile, indent=4)
def test_npv(self): assert_almost_equal(np.npv(0.05,[-15000,1500,2500,3500,4500,6000]), 117.04, 2)
def get_roe_date(code, coefficient, required_rate_of_return, ref_year, df_stock, type): # ref_year = datetime.date.today() # date type # ref_year = ref_year.year - 1 # 현재 년도 실적 ROE는 없음으로 직전 년도를 기준으로 함. # required_rate_of_return는 현재 BBB- 5년를 사용하지만, 업종별, 종목별, 시장환경에 맞게 변경하여 판단이 필요함. try: year_capital = df_stock.loc['capital', ref_year] year_roe = df_stock.loc['roe', ref_year] / 100 # 단위 % 환산 spread = year_roe - required_rate_of_return # 단위 % - % 계산임으로 spread변수도 값이 %가 됨. # 테이블 계산을 위한 기본 setting index = ['coefficient', 'roe', 'net_profit', 'earing', 'capital'] df_table = pd.DataFrame({ref_year: [1, year_roe, 0, 0, year_capital]}, index=index) # 적정가치 구하기 roe_max_len = len(df_stock.columns) # 년도가 있는 컬럼의 최대 길이 구함 year_index = df_stock.columns.values.tolist() #array자료형을 list형으로 변환 year_index = year_index.index(ref_year) # ref_year를 기준으로 컬럼에서 위치 찾음 year_roe_count = roe_max_len - year_index year = copy(ref_year) # ref_year를 year로 copy하여 별도 변수로 사용 a is b로 테스트 calculated_coefficient = 0 calculated_roe = 0 calculated_net_profit = 0 calculated_earing = 0 calculated_capital = 0 for year_count in range(1, 11): #10년 동안 계산 calculated_coefficient = df_table.loc[ 'coefficient', year] - coefficient # dataframe에서 직전년도 roe와 계산 if calculated_coefficient < 0.0: #roe 0 이하이면 0으로 세팅 calculated_coefficient = 0.0 # 기준년을 참조하여 table상의 roe그대로 사용하고, roe참조가 끝나면 계산함. ''' if year_roe_count >= year_count: calculated_roe = df_stock.loc['roe',year] / 100 # 단위 % 환산 else: calculated_roe = spread * calculated_coefficient + required_rate_of_return # spread와 required_rate_of_return는 %단위로 환산되어있음. ''' calculated_roe = spread * calculated_coefficient + required_rate_of_return # spread와 required_rate_of_return는 %단위로 환산되어있음. calculated_net_profit = df_table.loc['capital', year] * calculated_roe calculated_earing = calculated_net_profit - df_table.loc[ 'capital', year] * required_rate_of_return # 단위 % 환산 calculated_capital = df_table.loc['capital', year] + calculated_net_profit if type == 'year': year = year + 1 # 1년 증가 elif type == 'quarter': year_month = datetime.strptime(year, '%Y%m') year_month = year_month + relativedelta(months=+3) year = year_month.strftime('%Y%m') seri_table = pd.Series([ calculated_coefficient, calculated_roe, calculated_net_profit, calculated_earing, calculated_capital ], name=year, index=index) df_table = pd.concat([df_table, seri_table], axis=1) # NPV구하기 pv_val = df_table.loc['earing'].values.tolist() pv_val = pv_val[1:] # pv = get_npv(required_rate_of_return, pv_val) #초기 투자금액은 0,np.npv(0.281,[-0, 39, 59, 55, 20]) pv = np.npv(required_rate_of_return, pv_val) rim = year_capital + pv # 적정주가 구하기 ''' stock_date = stock.loc['date',ref_year] # date type today = datetime.date.today() # date type date_delta = stock_date - today # timedelta type date_delta = date_delta.days # int type stock_value를 구할때 할인율의 산출일 기준으로 자승으로 곱하여 남은 날짜만큼 구하고 있음. 그러나, 이것은 과거데이타 이용 및 현재 가치 판단시에 과한것으로 판단되어 일단, 사용하지 않음 또한, 기준날짜 - 현재날짜 일때 ...컨센서스 데이타가 없을 때는 (-)값이 나와 엉뚱하게 과하게 나옴. stock_value1 = rim / (1 + required_rate_of_return)**(date_delta/365) ''' # RIM 값을 구한후 미래가치에 대해 spread값만큼 자승하여 현재 가치를 구함 # calculated_rim = rim / (1 + required_rate_of_return) roe를 해당 Year것을 사용하여 할인율 미적용함. share_outstanding = df_stock.loc['share_outstanding', ref_year] # ROE가 계산되는 year의 보통주식수 value_per_share = int( (rim / share_outstanding) * 100000000) # 단위:억원 환산, 정수처리 ''' # 자승하여 현재가지치구하지 않고 현재 year 기준으로 모든것을 구했음으로 미래가치 -> 현재가지 부분을 제외 share_outstanding = df_stock.loc['share_outstanding',ref_year] # ROE가 계산되는 year의 보통주식수 value_per_share = int((rim / share_outstanding) * 100000000) # 단위:억원 환산, 정수처리 ''' except: return (000000) # 종목정보 오류는 000000으로 세팅 else: return (value_per_share)