def test_industrialSite(): # # Model an energy system # Input parameters locations = {'industry_0'} commodityUnitDict = { 'electricity': r'MW$_{el}$', 'hydrogen': r'MW$_{H_{2},LHV}$', 'heat': r'MW$_{heat}$}' } commodities = {'electricity', 'hydrogen', 'heat'} numberOfTimeSteps, hoursPerTimeStep = 24 * 6, 1 / 6 #8760, 1 # 52560, 1/6 costUnit, lengthUnit = '1e3 Euro', 'km' # Code esM = fn.EnergySystemModel(locations=locations, commodities=commodities, numberOfTimeSteps=numberOfTimeSteps, commodityUnitsDict=commodityUnitDict, hoursPerTimeStep=hoursPerTimeStep, costUnit=costUnit, lengthUnit=lengthUnit, verboseLogLevel=0) # ## Add source component data = pd.read_excel( os.path.join(os.path.dirname(__file__), '_testInputFiles', 'generationTimeSeries_e825103.xlsx')) data = data.iloc[0:numberOfTimeSteps] operationRateFix = pd.DataFrame( data['e825103_2017_2.3MW_faults9'], index=range(numberOfTimeSteps)) # Dataset with least missing data operationRateFix.columns = ['industry_0'] # Input parameters name, commodity = 'Wind turbines', 'electricity' hasCapacityVariable = True capacityMax = pd.Series([10], index=['industry_0']) # 10 MW_el = 0.01 GW_el investPerCapacity, opexPerCapacity = 0, 30 # 30 €/kW = 30 1e6€/GW = 30 1e3€/MW interestRate, economicLifetime = 0.08, 20 esM.add( fn.Source(esM=esM, name=name, commodity=commodity, hasCapacityVariable=hasCapacityVariable, operationRateFix=operationRateFix, capacityMax=capacityMax, investPerCapacity=investPerCapacity, opexPerCapacity=opexPerCapacity, interestRate=interestRate, economicLifetime=economicLifetime)) # ## Add conversion components esM.add( fn.Conversion( esM=esM, name='PEMEC', physicalUnit=r'MW$_{el}$', commodityConversionFactors={ 'electricity': -1, 'hydrogen': 0.67 }, hasCapacityVariable=True, investPerCapacity=2300, opexPerCapacity=12.5, interestRate=0.08, # for 2018 CAPEX economicLifetime=5)) func = lambda x: 0.5 * (x - 2)**3 + (x - 2)**2 + 0.0001 esM.add( fn.ConversionPartLoad( esM=esM, name='AEC', physicalUnit=r'MW$_{el}$', commodityConversionFactors={ 'electricity': -1, 'hydrogen': 0.64 }, commodityConversionFactorsPartLoad={ 'electricity': -1, 'hydrogen': func }, # commodityConversionFactorsPartLoad=pwl, nSegments=2, hasCapacityVariable=True, bigM=99, investPerCapacity=1300, opexPerCapacity=18, interestRate=0.08, # for 2018 CAPEX economicLifetime=9)) # ## Add storage components esM.add( fn.Storage(esM=esM, name='Hydrogen tank (gaseous)', commodity='hydrogen', hasCapacityVariable=True, capacityVariableDomain='continuous', capacityPerPlantUnit=1, chargeRate=1, dischargeRate=1, sharedPotentialID=None, stateOfChargeMin=0.06, stateOfChargeMax=1, investPerCapacity=0.004, opexPerCapacity=0.004 * 0.02, interestRate=0.08, economicLifetime=20)) ### Industrial hydrogen demand operationRateFix = pd.DataFrame( 2 * np.ones(numberOfTimeSteps) * (hoursPerTimeStep), columns=['industry_0']) # constant hydrogen demand of 2 MW_GH2: esM.add( fn.Sink(esM=esM, name='Hydrogen demand', commodity='hydrogen', hasCapacityVariable=False, operationRateFix=operationRateFix)) # Heat output esM.add( fn.Sink(esM=esM, name='Heat output', commodity='heat', hasCapacityVariable=False)) # Input parameters timeSeriesAggregation = False solver = 'glpk' # Optimize esM.optimize(timeSeriesAggregation=timeSeriesAggregation, solver=solver)
def test_conversionPartLoad(): # Set up energy system model instance locations = {'GlassProductionSite'} commodities = {'electricity', 'heat', 'hydrogen', 'O2', 'CO2','rawMaterial'} commodityUnitDict = {'electricity': r'kW$_{el}$', 'heat':r'kW$_{heat}$}', 'hydrogen':r'kW$_{H2}$', 'O2': r'kg$_{O_{2}}$/h', 'CO2': r'kg$_{CO_{2}}$/h', 'rawMaterial': r'kg$_{R}}$/h'} numberOfTimeSteps=80 hoursPerTimeStep=0.25 esM = fn.EnergySystemModel(locations=locations, commodities=commodities, numberOfTimeSteps=numberOfTimeSteps, commodityUnitsDict=commodityUnitDict, hoursPerTimeStep=hoursPerTimeStep, costUnit='1 Euro', lengthUnit='km', verboseLogLevel=0) ### Sources ### # Electricity from grid esM.add(fn.Source(esM=esM, name='ElectricityGrid', commodity='electricity', hasCapacityVariable=False, commodityCost=0.070)) # Oxygen source from trailer esM.add(fn.Source(esM=esM, name='oxygenSource', commodity='O2', hasCapacityVariable=False, commodityCost=0.070)) # Raw material for glass furnace esM.add(fn.Source(esM=esM, name='rawMaterialSource', commodity='rawMaterial', hasCapacityVariable=False, commodityCost=0.20)) ### Conversion ### # PEM Electrolyzer # Get partLoadData from EC Campus Mainz Utilization = [0.0208023774145616,0.0222882615156017,0.0222882615156017,0.0222882615156017,0.025260029717682, 0.025260029717682,0.0267459138187221,0.0282317979197622,0.0297176820208024,0.0312035661218424, 0.0326894502228826,0.0341753343239227,0.0356612184249628,0.0371471025260029,0.038632986627043, 0.0416047548291233,0.0430906389301634,0.0445765230312035,0.0475482912332838,0.0430906389301634, 0.0490341753343239,0.050520059435364,0.0520059435364041,0.0549777117384844,0.0579494799405646, 0.0609212481426448,0.0638930163447251,0.0683506686478455,0.0713224368499256,0.075780089153046, 0.0787518573551263,0.0832095096582466,0.087667161961367,0.0921248142644873,0.0980683506686478, 0.104011887072808,0.108469539375928,0.114413075780089,0.120356612184249,0.12778603268945, 0.13521545319465,0.142644873699851,0.151560178306092,0.157503714710252,0.166419019316493, 0.173848439821693,0.181277860326894,0.190193164933135,0.196136701337295,0.202080237741456, 0.209509658246656,0.216939078751857,0.224368499257057,0.233283803863298,0.240713224368499, 0.246656760772659,0.25408618127786,0.26151560178306,0.270430906389301,0.276374442793462, 0.283803863298662,0.292719167904903,0.298662704309063,0.306092124814264,0.313521545319465, 0.319465081723625,0.328380386329866,0.335809806835066,0.343239227340267,0.349182763744427, 0.356612184249628,0.364041604754829,0.371471025260029,0.38038632986627,0.389301634472511, 0.398216939078751,0.407132243684992,0.416047548291233,0.423476968796433,0.430906389301634, 0.439821693907875,0.448736998514115,0.457652303120356,0.465081723625557,0.472511144130757, 0.481426448736998,0.490341753343239,0.497771173848439,0.50668647845468,0.514115898959881, 0.523031203566121,0.531946508172362,0.540861812778603,0.551263001485884,0.560178306092124, 0.567607726597325,0.576523031203566,0.585438335809806,0.595839524517087,0.604754829123328, 0.613670133729569,0.619613670133729,0.62852897473997,0.638930163447251,0.646359583952451, 0.656760772659732,0.664190193164933,0.673105497771173,0.684992570579494,0.692421991084695, 0.699851411589896,0.710252600297176,0.717682020802377,0.726597325408618,0.735512630014858, 0.744427934621099,0.75334323922734,0.762258543833581,0.769687964338781,0.780089153046062, 0.786032689450223,0.793462109955423,0.802377414561664,0.811292719167904,0.820208023774145, 0.829123328380386,0.838038632986627,0.846953937592867,0.858841010401188,0.867756315007429, 0.87667161961367,0.88707280832095,0.895988112927191,0.904903417533432,0.913818722139673, 0.924219910846954,0.933135215453194,0.942050520059435,0.947994056463595,0.958395245170876, 0.965824665676077,0.974739970282318,0.985141158989598,0.994056463595839] Efficiency = [0.03449362655834178,0.05655553999159559,0.04920156884717763,0.07616612971004356,0.09332539571368476, 0.115387309146939,0.13254657515058135,0.1497058411542229,0.1693164308726712,0.1864756968763127, 0.2036349628799551,0.2256968763132085,0.2404048186020449,0.25511276089088053,0.27472335060932884, 0.2918826166129703,0.30904188261661275,0.33110379604986695,0.34581173833870255,0.3212985011906424, 0.3629710043423449,0.38013027034598645,0.3923868889200161,0.4095461549236585,0.42425409721249496, 0.4365107157865246,0.44876733436055427,0.45857262921977887,0.4683779240790026,0.4830858663678382, 0.4953424849418686,0.5075991035158983,0.517404398375122,0.5247583695195407,0.5321123406639585, 0.5419176355231823,0.5517229303824059,0.5639795489564365,0.5713335201008543,0.5811388149600779, 0.5884927861044958,0.5933954335341085,0.5982980809637204,0.6007494046785262,0.6007494046785262, 0.6007494046785262,0.5982980809637204,0.5982980809637204,0.5958467572489144,0.5958467572489144, 0.5958467572489144,0.5933954335341085,0.5933954335341085,0.5933954335341085,0.5909441098193018, 0.5909441098193018,0.5909441098193018,0.5884927861044958,0.5884927861044958,0.5884927861044958, 0.5884927861044958,0.5884927861044958,0.5884927861044958,0.5860414623896899,0.5860414623896899, 0.5860414623896899,0.583590138674884,0.583590138674884,0.583590138674884,0.5811388149600779, 0.5811388149600779,0.5786874912452721,0.5762361675304661,0.5762361675304661,0.5737848438156602, 0.5737848438156602,0.5713335201008543,0.5713335201008543,0.5688821963860483,0.5688821963860483, 0.5664308726712425,0.5664308726712425,0.5639795489564365,0.5639795489564365,0.5615282252416306, 0.5590769015268245,0.5590769015268245,0.5590769015268245,0.5566255778120178,0.5566255778120178, 0.5541742540972119,0.5541742540972119,0.5517229303824059,0.5517229303824059,0.5517229303824059, 0.5492716066676,0.5492716066676,0.5492716066676,0.5492716066676,0.5468202829527942, 0.5443689592379882,0.5443689592379882,0.5443689592379882,0.5443689592379882,0.5419176355231823, 0.5394663118083762,0.5394663118083762,0.5370149880935703,0.5370149880935703,0.5345636643787645, 0.5345636643787645,0.5321123406639585,0.5321123406639585,0.5296610169491526,0.5296610169491526, 0.5272096932343466,0.5272096932343466,0.5272096932343466,0.5247583695195399,0.5247583695195399, 0.522307045804734,0.522307045804734,0.522307045804734,0.522307045804734,0.519855722089928, 0.519855722089928,0.519855722089928,0.517404398375122,0.5149530746603161,0.5125017509455102, 0.5125017509455102,0.5100504272307043,0.5100504272307043,0.5075991035158983,0.5051477798010924, 0.5051477798010924,0.5051477798010924,0.5026964560862865,0.5026964560862865,0.5026964560862865, 0.5026964560862865,0.5002451323714806,0.5002451323714806,0.49779380865667455] d = {'x':Utilization, 'y':Efficiency} partLoadData = pd.DataFrame(d) partLoadData nSegments = 4 esM.add(fn.ConversionPartLoad(esM=esM, name='PEMEC', physicalUnit=r'kW$_{el}$', commodityConversionFactors={'electricity':-1, 'hydrogen':1}, commodityConversionFactorsPartLoad={'electricity':-1, 'hydrogen': partLoadData}, nSegments=nSegments, hasCapacityVariable=True, bigM=99999, investPerCapacity=900, opexPerCapacity=900*0.01, interestRate=0.08, economicLifetime=10)) # Glass production - Hydrogen gas furnace capacityFix = 4985 annualLoss = 0.03 #After one year a glass melting furnace needs 3% more energy to maintain process quality due to increasing thermal losses operationRateFix = pd.DataFrame(np.linspace(capacityFix*(1-annualLoss/2),capacityFix*(1+annualLoss/2),num=numberOfTimeSteps),columns=['GlassProductionSite']) operationRateFix.mean() operationRateFix = operationRateFix/operationRateFix.mean() esM.add(fn.Conversion(esM=esM, name='hydrogenGasFurnace', physicalUnit= r'kW$_{H2}$', commodityConversionFactors={'hydrogen':-1, 'electricity':-0.020,'O2': -0.137, # stochiometric combustion: -0.238; lambda: -0.274 'rawMaterial': -0.209, 'heat':0.070, 'CO2':0.020}, # 'CO2':0.040 for H2 with german grid; 'CO2':0.021 for 100% renewable electricity hasCapacityVariable=True, capacityFix = capacityFix, operationRateFix=operationRateFix, investPerCapacity=1103.5, opexPerCapacity=652, interestRate=0.08, economicLifetime=10)) ### Sinks ### # Heat output esM.add(fn.Sink(esM=esM, name='Heat output', commodity='heat', hasCapacityVariable=False)) # CO2 output esM.add(fn.Sink(esM=esM, name='CO2 output', commodity='CO2', hasCapacityVariable=False)) # O2 output # We include this sink to enable feasibility of the optimization problem in case the electrolyzer produces slightly more oxygen than required in the hydrogen furnace (round-off error < 1%) - we only that for stochiometric combustion -> for lambda > 1 that shouldn't be necessary esM.add(fn.Sink(esM=esM, name='O2 output', commodity='O2', hasCapacityVariable=False)) ### Optimization ### # Input parameters timeSeriesAggregation=False solver='glpk' # Code esM.optimize(timeSeriesAggregation=timeSeriesAggregation, solver=solver) ### Test ### # Overall TAC srcSnkSummary = esM.getOptimizationSummary("SourceSinkModel", outputLevel=1) convSummary = esM.getOptimizationSummary("ConversionModel", outputLevel=1) convPartloadSummary = esM.getOptimizationSummary("ConversionPartLoadModel", outputLevel=1) TAC=(srcSnkSummary.loc[('ElectricityGrid', 'TAC', '[1 Euro/a]'),'GlassProductionSite']+ srcSnkSummary.loc[('oxygenSource', 'TAC', '[1 Euro/a]'),'GlassProductionSite']+ srcSnkSummary.loc[('rawMaterialSource', 'TAC', '[1 Euro/a]'),'GlassProductionSite']+ convSummary.loc[('hydrogenGasFurnace', 'TAC', '[1 Euro/a]'),'GlassProductionSite']+ convPartloadSummary.loc[('PEMEC', 'TAC', '[1 Euro/a]'),'GlassProductionSite']) np.testing.assert_allclose(TAC, 14016197.2088, rtol = 0.005) # relative toerlance < 0.5% # Electricity TAC np.testing.assert_allclose(srcSnkSummary.loc[('ElectricityGrid', 'TAC', '[1 Euro/a]'),'GlassProductionSite'], 6.23855e+06, rtol = 0.01) # relative toerlance < 1% # PEMEC summary np.testing.assert_allclose(convPartloadSummary.loc[('PEMEC', 'TAC', '[1 Euro/a]'),'GlassProductionSite'], 1.46349e+06, rtol = 0.002) # relative toerlance < 0.2% np.testing.assert_allclose(convPartloadSummary.loc[('PEMEC', 'capacity', '[kW$_{el}$]'),'GlassProductionSite'], 10225.1729065, rtol = 0.002) # relative toerlance < 0.2% np.testing.assert_allclose(convPartloadSummary.loc[('PEMEC', 'capexCap', '[1 Euro/a]'),'GlassProductionSite'], 1371467.06108539, rtol = 0.002) # relative toerlance < 0.2% np.testing.assert_allclose(convPartloadSummary.loc[('PEMEC', 'invest', '[1 Euro]'),'GlassProductionSite'], 9202655.61585, rtol = 0.002) # relative toerlance < 0.2% np.testing.assert_allclose(convPartloadSummary.loc[('PEMEC', 'opexCap', '[1 Euro/a]'),'GlassProductionSite'], 92026.5561585, rtol = 0.002) # relative toerlance < 0.2% np.testing.assert_allclose(convPartloadSummary.loc[('PEMEC', 'operation', '[kW$_{el}$*h/a]'),'GlassProductionSite'], 8.82488e+07, rtol = 0.01) # relative toerlance < 1% # PEM operation results opVarOptPartLoad = esM.componentModelingDict["ConversionPartLoadModel"].operationVariablesOptimum.loc[('PEMEC', 'GlassProductionSite')] opVarOptConstLoad = [2480.73776181,2481.6941601,2482.65055839,2483.60695668,2484.56335497,2485.51975325,2486.47615154, 2487.43254983,2488.38894812,2489.34534641,2490.3017447,2491.25814299,2492.21454128,2493.17093957,2494.12733785, 2495.08373614,2496.04013443,2496.99653272,2497.95293101,2498.9093293,2499.86572759,2500.82212588, 2501.77852417,2502.73492245,2503.69132074,2504.64771903,2505.60411732,2506.56051561,2507.5169139, 2508.47331219,2509.42971048,2510.38610877,2511.34250706,2512.29890534,2513.25530363,2514.21170192, 2515.16810021,2516.1244985,2517.08089679,2518.03729508,2518.99369337,2519.95009166,2520.90648994, 2521.86288823,2522.81928652,2523.77568481,2524.7320831,2525.68848139,2526.64487968,2527.60127797, 2528.55767626,2529.51407455,2530.47047283,2531.42687112,2532.38326941,2533.3396677,2534.29606599, 2535.25246428,2536.20886257,2537.16526086,2538.12165915,2539.07805743,2540.03445572,2540.99085401, 2541.9472523,2542.90365059,2543.86004888,2544.81644717,2545.77284546,2546.72924375,2547.68564204, 2548.64204032,2549.59843861,2550.5548369,2551.51123519,2552.46763348,2553.42403177,2554.38043006, 2555.33682835,2556.29322664] np.testing.assert_allclose(opVarOptPartLoad, opVarOptConstLoad,rtol=0.01)