diff --git a/data/load_profiles/cooling_electric_annual_kwh.json b/data/load_profiles/cooling_electric_annual_kwh.json new file mode 100644 index 000000000..937f74a45 --- /dev/null +++ b/data/load_profiles/cooling_electric_annual_kwh.json @@ -0,0 +1 @@ +{"Chicago":{"Hospital":1721142,"LargeOffice":533117,"MediumOffice":85839,"SecondarySchool":336986,"SmallOffice":6365,"SmallHotel":97554,"LargeHotel":469484,"FastFoodRest":6320,"MidriseApartment":25663,"RetailStore":31774,"FullServiceRest":17222,"StripMall":32544,"Supermarket":30785,"PrimarySchool":82619,"FlatLoad":238154.0,"Warehouse":4370,"Outpatient":328675},"Helena":{"Hospital":1075876,"LargeOffice":226066,"MediumOffice":44528,"SecondarySchool":132887,"SmallOffice":3442,"SmallHotel":63978,"LargeHotel":318965,"FastFoodRest":2919,"RetailStore":13952,"MidriseApartment":11101,"FullServiceRest":8420,"StripMall":13260,"Supermarket":14879,"PrimarySchool":34468,"FlatLoad":137459.0,"Warehouse":1566,"Outpatient":233034},"LasVegas":{"Hospital":1831966,"LargeOffice":792463,"MediumOffice":207085,"SecondarySchool":858081,"SmallOffice":16824,"SmallHotel":175011,"LargeHotel":798740,"FastFoodRest":22811,"RetailStore":89484,"MidriseApartment":92778,"FullServiceRest":53259,"StripMall":84138,"Supermarket":114543,"PrimarySchool":218688,"FlatLoad":368636.0,"Warehouse":28928,"Outpatient":513377},"Miami":{"Hospital":3371923,"LargeOffice":1878642,"MediumOffice":337147,"LargeHotel":1467216,"MidriseApartment":176446,"RetailStore":163290,"StripMall":180645,"PrimarySchool":434031,"Outpatient":811571,"SecondarySchool":1735906,"SmallOffice":28235,"SmallHotel":318595,"FastFoodRest":36779,"FullServiceRest":101567,"Supermarket":150368,"FlatLoad":700779.0,"Warehouse":20108},"Phoenix":{"Hospital":2288973,"LargeOffice":1124585,"MediumOffice":271151,"SecondarySchool":1204514,"SmallOffice":23720,"SmallHotel":233842,"LargeHotel":1024137,"FastFoodRest":29956,"MidriseApartment":135120,"RetailStore":123508,"FullServiceRest":69402,"StripMall":122803,"Supermarket":145706,"PrimarySchool":302372,"FlatLoad":486155.0,"Warehouse":38561,"Outpatient":640137},"LosAngeles":{"Hospital":1987427,"LargeOffice":707617,"MediumOffice":121320,"SecondarySchool":351337,"SmallOffice":8351,"SmallHotel":116966,"LargeHotel":526169,"FastFoodRest":3452,"MidriseApartment":22912,"RetailStore":22663,"FullServiceRest":11456,"StripMall":26514,"Supermarket":13630,"PrimarySchool":126130,"FlatLoad":280112.0,"Warehouse":673,"Outpatient":435175},"Boulder":{"Hospital":1223116,"LargeOffice":316540,"MediumOffice":68389,"SecondarySchool":220472,"SmallOffice":5097,"SmallHotel":84804,"LargeHotel":384065,"FastFoodRest":5270,"MidriseApartment":18535,"RetailStore":23580,"FullServiceRest":14957,"StripMall":23350,"Supermarket":24684,"PrimarySchool":57692,"FlatLoad":172858.0,"Warehouse":3574,"Outpatient":291603},"Minneapolis":{"Hospital":1516644,"LargeOffice":475102,"MediumOffice":74813,"SecondarySchool":262353,"SmallOffice":5452,"SmallHotel":91962,"LargeHotel":445049,"FastFoodRest":5429,"MidriseApartment":22491,"RetailStore":26859,"FullServiceRest":14996,"StripMall":26489,"Supermarket":25962,"PrimarySchool":62017,"FlatLoad":209265.0,"Warehouse":2923,"Outpatient":289706},"Baltimore":{"Hospital":2085465,"LargeOffice":822177,"MediumOffice":124064,"SecondarySchool":469545,"SmallOffice":8083,"SmallHotel":119859,"LargeHotel":594327,"FastFoodRest":9287,"RetailStore":44703,"MidriseApartment":36890,"FullServiceRest":25140,"StripMall":43896,"Supermarket":48913,"PrimarySchool":114110,"FlatLoad":310038.0,"Warehouse":7156,"Outpatient":406989},"SanFrancisco":{"Hospital":1427329,"LargeOffice":297494,"MediumOffice":43956,"SecondarySchool":121914,"SmallOffice":2539,"SmallHotel":71414,"LargeHotel":296230,"FastFoodRest":838,"MidriseApartment":4484,"RetailStore":4515,"FullServiceRest":3062,"StripMall":6626,"Supermarket":3252,"PrimarySchool":48323,"FlatLoad":164036.0,"Warehouse":365,"Outpatient":292238},"Seattle":{"Hospital":1432385,"LargeOffice":249231,"MediumOffice":38713,"SecondarySchool":89468,"SmallOffice":2503,"SmallHotel":60651,"LargeHotel":292028,"FastFoodRest":1245,"MidriseApartment":6380,"RetailStore":6223,"FullServiceRest":4144,"StripMall":7664,"Supermarket":4882,"PrimarySchool":28984,"FlatLoad":155682.0,"Warehouse":329,"Outpatient":266075},"Atlanta":{"Hospital":2328054,"LargeOffice":968973,"MediumOffice":155865,"SecondarySchool":608831,"SmallOffice":11259,"SmallHotel":149237,"LargeHotel":704148,"FastFoodRest":12565,"MidriseApartment":50907,"RetailStore":65044,"FullServiceRest":33832,"StripMall":62530,"Supermarket":69686,"FlatLoad":367407.0,"PrimarySchool":160138,"Warehouse":8214,"Outpatient":489234},"Duluth":{"Hospital":1149799,"LargeOffice":249416,"MediumOffice":37547,"SecondarySchool":99148,"SmallOffice":2563,"SmallHotel":61101,"LargeHotel":300364,"FastFoodRest":1709,"RetailStore":8489,"MidriseApartment":8181,"FullServiceRest":4919,"StripMall":8809,"Supermarket":9788,"PrimarySchool":25136,"FlatLoad":135374.0,"Warehouse":889,"Outpatient":198121},"Fairbanks":{"Hospital":753420,"LargeOffice":147867,"MediumOffice":24183,"SecondarySchool":53222,"SmallOffice":1877,"SmallHotel":48066,"LargeHotel":234082,"FastFoodRest":656,"MidriseApartment":5035,"RetailStore":3289,"FullServiceRest":2025,"StripMall":3592,"Supermarket":2500,"PrimarySchool":15166,"FlatLoad":89900.0,"Warehouse":97,"Outpatient":143322},"Houston":{"Hospital":2942336,"LargeOffice":1471054,"MediumOffice":239477,"SecondarySchool":1151985,"SmallOffice":19375,"SmallHotel":220470,"LargeHotel":1095441,"FastFoodRest":24525,"RetailStore":115410,"MidriseApartment":97156,"FullServiceRest":63610,"StripMall":111025,"Supermarket":125580,"PrimarySchool":282346,"FlatLoad":538015.0,"Warehouse":17665,"Outpatient":630778},"Albuquerque":{"Hospital":1382003,"LargeOffice":442687,"MediumOffice":103240,"SecondarySchool":355818,"SmallOffice":8266,"SmallHotel":109982,"LargeHotel":475348,"FastFoodRest":8466,"MidriseApartment":34088,"RetailStore":37955,"FullServiceRest":25534,"StripMall":36498,"Supermarket":40883,"PrimarySchool":99496,"FlatLoad":220232.0,"Warehouse":5831,"Outpatient":357615}} \ No newline at end of file diff --git a/data/load_profiles/domestic_hot_water_annual_mmbtu.json b/data/load_profiles/domestic_hot_water_annual_mmbtu.json new file mode 100644 index 000000000..ea6993e61 --- /dev/null +++ b/data/load_profiles/domestic_hot_water_annual_mmbtu.json @@ -0,0 +1,306 @@ +{ + "Chicago": { + "Hospital": 740.4172516, + "LargeOffice": 239.7065959, + "MediumOffice": 35.08184587, + "SecondarySchool": 456.8817409, + "SmallOffice": 11.2033023, + "SmallHotel": 406.0751832, + "LargeHotel": 7005.083356, + "FastFoodRest": 84.2645196, + "MidriseApartment": 297.4938584, + "RetailStore": 0.0, + "FullServiceRest": 260.4454844, + "StripMall": 0.0, + "Supermarket": 24.4292392, + "PrimarySchool": 179.4639347, + "FlatLoad": 611.6276445, + "Warehouse": 0.0, + "Outpatient": 45.49600079 + }, + "Helena": { + "Hospital": 800.0940058, + "LargeOffice": 262.1461576, + "MediumOffice": 37.68905029, + "SecondarySchool": 494.7393735, + "SmallOffice": 11.46564268, + "SmallHotel": 438.9398731, + "LargeHotel": 7665.023574, + "FastFoodRest": 90.44011877, + "MidriseApartment": 325.4421541, + "RetailStore": 0.0, + "FullServiceRest": 280.9757902, + "StripMall": 0.0, + "Supermarket": 25.72866824, + "PrimarySchool": 193.4573283, + "FlatLoad": 667.2021224, + "Warehouse": 0.0, + "Outpatient": 49.09222188 + }, + "Miami": { + "Hospital": 442.7295435, + "LargeOffice": 127.9412792, + "MediumOffice": 22.09603477, + "SecondarySchool": 250.1299246, + "SmallOffice": 9.891779415, + "SmallHotel": 242.232695, + "LargeHotel": 3713.248373, + "FastFoodRest": 53.47209411, + "MidriseApartment": 158.0580017, + "RetailStore": 0.0, + "FullServiceRest": 158.0518043, + "StripMall": 0.0, + "Supermarket": 17.94985187, + "PrimarySchool": 105.3179165, + "FlatLoad": 333.0450133, + "Warehouse": 0.0, + "Outpatient": 27.60091429 + }, + "LasVegas": { + "Hospital": 540.9697668, + "LargeOffice": 164.7154124, + "MediumOffice": 26.36796732, + "SecondarySchool": 327.441087, + "SmallOffice": 10.32392915, + "SmallHotel": 296.3578765, + "LargeHotel": 4800.331564, + "FastFoodRest": 63.63848459, + "MidriseApartment": 204.1120165, + "RetailStore": 0.0, + "FullServiceRest": 191.8494897, + "StripMall": 0.0, + "Supermarket": 20.08676069, + "PrimarySchool": 131.9651451, + "FlatLoad": 425.7275876, + "Warehouse": 0.0, + "Outpatient": 33.48190098 + }, + "Phoenix": { + "Hospital": 480.098265, + "LargeOffice": 141.8507451, + "MediumOffice": 23.71397275, + "SecondarySchool": 285.2339344, + "SmallOffice": 10.05557471, + "SmallHotel": 262.8487714, + "LargeHotel": 4127.191046, + "FastFoodRest": 57.34025418, + "MidriseApartment": 175.5949563, + "RetailStore": 0.0, + "FullServiceRest": 170.9086319, + "StripMall": 0.0, + "Supermarket": 18.7637822, + "PrimarySchool": 116.811664, + "FlatLoad": 368.7653325, + "Warehouse": 0.0, + "Outpatient": 29.83372212 + }, + "LosAngeles": { + "Hospital": 598.9350422, + "LargeOffice": 186.6199083, + "MediumOffice": 28.91483286, + "SecondarySchool": 352.7467563, + "SmallOffice": 10.58011717, + "SmallHotel": 328.1935523, + "LargeHotel": 5440.174033, + "FastFoodRest": 69.63212501, + "MidriseApartment": 231.215325, + "RetailStore": 0.0, + "FullServiceRest": 211.7827529, + "StripMall": 0.0, + "Supermarket": 21.35337379, + "PrimarySchool": 142.8059487, + "FlatLoad": 478.7476251, + "Warehouse": 0.0, + "Outpatient": 37.00823296 + }, + "Boulder": { + "Hospital": 737.372005, + "LargeOffice": 238.572519, + "MediumOffice": 34.9486709, + "SecondarySchool": 453.228537, + "SmallOffice": 11.18970855, + "SmallHotel": 404.4154946, + "LargeHotel": 6971.32924, + "FastFoodRest": 83.95201542, + "MidriseApartment": 296.06471, + "RetailStore": 0.0, + "FullServiceRest": 259.3997752, + "StripMall": 0.0, + "Supermarket": 24.3650532, + "PrimarySchool": 178.3378526, + "FlatLoad": 608.6556221, + "Warehouse": 0.0, + "Outpatient": 45.31437164 + }, + "Minneapolis": { + "Hospital": 790.9262388, + "LargeOffice": 258.6874644, + "MediumOffice": 37.28641454, + "SecondarySchool": 491.5554097, + "SmallOffice": 11.42620649, + "SmallHotel": 433.8738637, + "LargeHotel": 7563.607619, + "FastFoodRest": 89.48929949, + "MidriseApartment": 321.1473562, + "RetailStore": 0.0, + "FullServiceRest": 277.8184269, + "StripMall": 0.0, + "Supermarket": 25.53218144, + "PrimarySchool": 191.9480118, + "FlatLoad": 658.8635839, + "Warehouse": 0.0, + "Outpatient": 48.51884975 + }, + "Baltimore": { + "Hospital": 681.9322322, + "LargeOffice": 217.7306132, + "MediumOffice": 32.52815422, + "SecondarySchool": 417.9512972, + "SmallOffice": 10.94554028, + "SmallHotel": 373.906416, + "LargeHotel": 6358.710286, + "FastFoodRest": 78.2191761, + "MidriseApartment": 270.1195541, + "RetailStore": 0.0, + "FullServiceRest": 240.338156, + "StripMall": 0.0, + "Supermarket": 23.15795696, + "PrimarySchool": 165.3116185, + "FlatLoad": 557.0507802, + "Warehouse": 0.0, + "Outpatient": 41.96148216 + }, + "SanFrancisco": { + "Hospital": 671.40531, + "LargeOffice": 213.8445094, + "MediumOffice": 32.07909301, + "SecondarySchool": 401.395655, + "SmallOffice": 10.90004379, + "SmallHotel": 368.0979112, + "LargeHotel": 6241.842643, + "FastFoodRest": 77.13092952, + "MidriseApartment": 265.1697301, + "RetailStore": 0.0, + "FullServiceRest": 236.7180594, + "StripMall": 0.0, + "Supermarket": 22.9292287, + "PrimarySchool": 160.4507431, + "FlatLoad": 546.4574286, + "Warehouse": 0.0, + "Outpatient": 41.35500136 + }, + "Seattle": { + "Hospital": 716.6111323, + "LargeOffice": 230.8057849, + "MediumOffice": 34.04746055, + "SecondarySchool": 434.0806311, + "SmallOffice": 11.09863592, + "SmallHotel": 392.968915, + "LargeHotel": 6741.736717, + "FastFoodRest": 81.80231236, + "MidriseApartment": 286.3412104, + "RetailStore": 0.0, + "FullServiceRest": 252.2609525, + "StripMall": 0.0, + "Supermarket": 23.91178737, + "PrimarySchool": 172.0233322, + "FlatLoad": 588.8601433, + "Warehouse": 0.0, + "Outpatient": 44.07342164 + }, + "Atlanta": { + "Hospital": 615.3498557, + "LargeOffice": 192.7164525, + "MediumOffice": 29.62182675, + "SecondarySchool": 372.2083434, + "SmallOffice": 10.65138846, + "SmallHotel": 337.2688069, + "LargeHotel": 5622.340656, + "FastFoodRest": 71.33170579, + "MidriseApartment": 238.9315749, + "RetailStore": 0.0, + "FullServiceRest": 217.4332205, + "StripMall": 0.0, + "Supermarket": 21.71038069, + "PrimarySchool": 148.8362119, + "FlatLoad": 494.7735263, + "Warehouse": 0.0, + "Outpatient": 37.9759973 + }, + "Duluth": { + "Hospital": 874.2611723, + "LargeOffice": 290.0193773, + "MediumOffice": 40.92475821, + "SecondarySchool": 543.3733772, + "SmallOffice": 11.79316054, + "SmallHotel": 479.7414481, + "LargeHotel": 8484.906093, + "FastFoodRest": 98.10641517, + "MidriseApartment": 360.161261, + "RetailStore": 0.0, + "FullServiceRest": 306.4772907, + "StripMall": 0.0, + "Supermarket": 27.3451629, + "PrimarySchool": 211.2386551, + "FlatLoad": 736.3678114, + "Warehouse": 0.0, + "Outpatient": 53.53681127 + }, + "Fairbanks": { + "Hospital": 975.1062178, + "LargeOffice": 327.8820873, + "MediumOffice": 45.32138512, + "SecondarySchool": 604.6838786, + "SmallOffice": 12.23744003, + "SmallHotel": 535.2525234, + "LargeHotel": 9600.267161, + "FastFoodRest": 108.5335945, + "MidriseApartment": 407.3910855, + "RetailStore": 0.0, + "FullServiceRest": 341.1572799, + "StripMall": 0.0, + "Supermarket": 29.53958045, + "PrimarySchool": 234.2595741, + "FlatLoad": 830.07826, + "Warehouse": 0.0, + "Outpatient": 59.6203514 + }, + "Houston": { + "Hospital": 530.6352726, + "LargeOffice": 160.8917808, + "MediumOffice": 25.9266894, + "SecondarySchool": 314.7654465, + "SmallOffice": 10.27839347, + "SmallHotel": 290.6293673, + "LargeHotel": 4685.666667, + "FastFoodRest": 62.56835989, + "MidriseApartment": 199.2544784, + "RetailStore": 0.0, + "FullServiceRest": 188.292814, + "StripMall": 0.0, + "Supermarket": 19.86608717, + "PrimarySchool": 128.0705362, + "FlatLoad": 415.6076756, + "Warehouse": 0.0, + "Outpatient": 32.87691943 + }, + "Albuquerque": { + "Hospital": 669.3128607, + "LargeOffice": 212.9944774, + "MediumOffice": 31.97726287, + "SecondarySchool": 409.1649863, + "SmallOffice": 10.88949351, + "SmallHotel": 366.9712928, + "LargeHotel": 6219.08303, + "FastFoodRest": 76.9149868, + "MidriseApartment": 264.2063457, + "RetailStore": 0.0, + "FullServiceRest": 235.9992545, + "StripMall": 0.0, + "Supermarket": 22.88525618, + "PrimarySchool": 162.1556119, + "FlatLoad": 545.235078, + "Warehouse": 0.0, + "Outpatient": 41.20639013 + } +} \ No newline at end of file diff --git a/data/load_profiles/space_heating_annual_mmbtu.json b/data/load_profiles/space_heating_annual_mmbtu.json new file mode 100644 index 000000000..47001cb18 --- /dev/null +++ b/data/load_profiles/space_heating_annual_mmbtu.json @@ -0,0 +1 @@ +{"Chicago":{"Hospital":12329.57943,"LargeOffice":7706.028917000001,"MediumOffice":216.01411800000002,"SecondarySchool":8962.172873,"SmallOffice":94.19308949,"SmallHotel":479.4653436000001,"LargeHotel":5104.848129,"FastFoodRest":441.93439000000006,"MidriseApartment":1482.040156,"RetailStore":1472.8704380000001,"FullServiceRest":888.3312571,"StripMall":1497.556168,"Supermarket":3696.2112950000005,"PrimarySchool":2006.0002120000001,"FlatLoad":3258.766323,"Warehouse":2256.477231,"Outpatient":3506.5381090000005},"Helena":{"Hospital":10760.57411,"LargeOffice":7373.056709,"MediumOffice":239.8330306,"SecondarySchool":9535.484059,"SmallOffice":98.85818175,"SmallHotel":499.85992930000003,"LargeHotel":5554.910785,"FastFoodRest":468.8276835,"MidriseApartment":1531.102079,"RetailStore":1494.85988,"FullServiceRest":934.8994934,"StripMall":1604.0043970000002,"Supermarket":3948.5338049999996,"PrimarySchool":2097.777112,"FlatLoad":3252.362248,"Warehouse":2504.784991,"Outpatient":3390.42972},"Miami":{"Hospital":6248.413294,"LargeOffice":168.9731637,"MediumOffice":0.036985655,"SecondarySchool":203.5185485,"SmallOffice":0.312524873,"SmallHotel":9.098564901,"LargeHotel":198.0691407,"FastFoodRest":5.426780867,"MidriseApartment":38.70606161,"RetailStore":12.12015432,"FullServiceRest":12.03181471,"StripMall":20.73216748,"Supermarket":101.2785324,"PrimarySchool":49.78021153,"FlatLoad":605.2352137,"Warehouse":56.0796017,"Outpatient":2559.185872},"LasVegas":{"Hospital":9100.302056,"LargeOffice":2479.152321,"MediumOffice":5.220181581,"SecondarySchool":2277.7410649999997,"SmallOffice":19.16330622,"SmallHotel":138.4427074,"LargeHotel":1500.581408,"FastFoodRest":100.0877773,"MidriseApartment":487.43122850000003,"RetailStore":386.0185744,"FullServiceRest":247.21791319999997,"StripMall":389.30494280000005,"Supermarket":1479.302604,"PrimarySchool":499.6562223,"FlatLoad":1413.3882199999998,"Warehouse":579.7671637999999,"Outpatient":2924.8220460000002},"Phoenix":{"Hospital":9382.021026,"LargeOffice":1584.061452,"MediumOffice":1.922551528,"SecondarySchool":1400.638544,"SmallOffice":9.988210938,"SmallHotel":83.98084516,"LargeHotel":896.790817,"FastFoodRest":57.89972381,"MidriseApartment":290.9887152,"RetailStore":208.66330580000002,"FullServiceRest":147.2569493,"StripMall":230.16060699999997,"Supermarket":972.3008295,"PrimarySchool":305.573525,"FlatLoad":1188.188154,"Warehouse":362.42249280000004,"Outpatient":3076.340876},"LosAngeles":{"Hospital":10346.1713,"LargeOffice":1458.148818,"MediumOffice":0.12342009699999999,"SecondarySchool":1198.276619,"SmallOffice":5.898878347,"SmallHotel":72.42852638,"LargeHotel":707.848762,"FastFoodRest":40.90390152,"MidriseApartment":265.2851759,"RetailStore":175.104083,"FullServiceRest":97.94277036,"StripMall":193.18730269999998,"Supermarket":1040.273464,"PrimarySchool":318.73600980000003,"FlatLoad":1228.8385369999999,"Warehouse":323.96697819999997,"Outpatient":3417.120585},"Boulder":{"Hospital":9169.381845,"LargeOffice":5027.882454,"MediumOffice":124.26913059999998,"SecondarySchool":6268.036872,"SmallOffice":65.95714912,"SmallHotel":342.77800099999996,"LargeHotel":3975.1080020000004,"FastFoodRest":306.8980525,"MidriseApartment":1098.944993,"RetailStore":1086.9187570000001,"FullServiceRest":642.8843574,"StripMall":1093.093638,"Supermarket":2966.790122,"PrimarySchool":1356.396807,"FlatLoad":2394.8859239999997,"Warehouse":1704.8648210000001,"Outpatient":3087.969786},"Minneapolis":{"Hospital":13031.2313,"LargeOffice":10199.279129999999,"MediumOffice":394.1525556,"SecondarySchool":11963.323859999999,"SmallOffice":128.12525349999999,"SmallHotel":618.0427338999999,"LargeHotel":6359.946704,"FastFoodRest":588.8854722,"MidriseApartment":1814.148381,"RetailStore":1869.8106289999998,"FullServiceRest":1121.229499,"StripMall":1952.731917,"Supermarket":4529.776664,"PrimarySchool":2600.964302,"FlatLoad":4004.001148,"Warehouse":3231.223746,"Outpatient":3661.1462229999997},"Baltimore":{"Hospital":11253.61694,"LargeOffice":5109.311943,"MediumOffice":116.8101842,"SecondarySchool":6557.634924,"SmallOffice":63.29818348,"SmallHotel":346.3683857,"LargeHotel":3731.0254619999996,"FastFoodRest":305.2671204,"MidriseApartment":1132.964052,"RetailStore":1068.034778,"FullServiceRest":657.1337578,"StripMall":1075.39546,"Supermarket":2929.182261,"PrimarySchool":1428.239177,"FlatLoad":2539.2645399999997,"Warehouse":1568.722061,"Outpatient":3285.227941},"SanFrancisco":{"Hospital":11570.9155,"LargeOffice":2690.1191,"MediumOffice":3.8159670660000002,"SecondarySchool":3414.148347,"SmallOffice":27.53039453,"SmallHotel":189.0244446,"LargeHotel":1713.3629670000003,"FastFoodRest":127.22328700000001,"MidriseApartment":648.4472797999999,"RetailStore":569.8081034,"FullServiceRest":362.48645889999995,"StripMall":526.2320428,"Supermarket":2301.616069,"PrimarySchool":818.2159102,"FlatLoad":1808.604729,"Warehouse":675.6758453,"Outpatient":3299.0539519999998},"Seattle":{"Hospital":11935.157290000001,"LargeOffice":5266.970348,"MediumOffice":28.97979768,"SecondarySchool":6367.850187,"SmallOffice":49.34878545,"SmallHotel":310.8087307,"LargeHotel":3343.683348,"FastFoodRest":255.5992711,"MidriseApartment":1117.5465470000001,"RetailStore":952.2758742000001,"FullServiceRest":627.5634984000001,"StripMall":969.1074739000001,"Supermarket":3004.1844929999997,"PrimarySchool":1263.541878,"FlatLoad":2506.1340600000003,"Warehouse":1137.398514,"Outpatient":3468.128914},"Atlanta":{"Hospital":10467.659959999999,"LargeOffice":3624.593975,"MediumOffice":49.00635733,"SecondarySchool":3968.4936420000004,"SmallOffice":42.74797302,"SmallHotel":202.26124219999997,"LargeHotel":2427.6589879999997,"FastFoodRest":168.8402371,"MidriseApartment":718.9316697,"RetailStore":627.2489826000001,"FullServiceRest":379.5865464,"StripMall":615.2240506,"Supermarket":1880.5304489999999,"PrimarySchool":931.7212450999999,"FlatLoad":1888.856302,"Warehouse":930.9449202,"Outpatient":3186.250588},"Duluth":{"Hospital":14179.84149,"LargeOffice":12504.64187,"MediumOffice":468.2112216,"SecondarySchool":14468.64346,"SmallOffice":155.8350887,"SmallHotel":772.5386662000001,"LargeHotel":7781.9012760000005,"FastFoodRest":738.1353594999999,"MidriseApartment":2204.85149,"RetailStore":2298.8242920000002,"FullServiceRest":1400.36692,"StripMall":2411.847491,"Supermarket":5587.977185,"PrimarySchool":3160.1200719999997,"FlatLoad":4741.886326,"Warehouse":3962.122014,"Outpatient":3774.3233130000003},"Fairbanks":{"Hospital":20759.042680000002,"LargeOffice":23214.51532,"MediumOffice":949.8812392000001,"SecondarySchool":25619.149269999998,"SmallOffice":297.08593010000004,"SmallHotel":1264.41064,"LargeHotel":12298.7791,"FastFoodRest":1245.3608279999999,"MidriseApartment":3398.039504,"RetailStore":3869.670979,"FullServiceRest":2209.293209,"StripMall":3934.89178,"Supermarket":8515.422039000001,"PrimarySchool":6341.861225,"FlatLoad":7851.508208,"Warehouse":6882.6512680000005,"Outpatient":4824.076322999999},"Houston":{"Hospital":8732.10385,"LargeOffice":2229.971744,"MediumOffice":16.25994314,"SecondarySchool":2011.1678969999998,"SmallOffice":19.55157672,"SmallHotel":108.9825885,"LargeHotel":1307.035548,"FastFoodRest":85.49111065,"MidriseApartment":386.0269973,"RetailStore":289.0470815,"FullServiceRest":199.7942842,"StripMall":292.23235389999996,"Supermarket":984.7374347000001,"PrimarySchool":469.2532935,"FlatLoad":1277.307359,"Warehouse":475.9377273,"Outpatient":2829.324307},"Albuquerque":{"Hospital":8371.240776999999,"LargeOffice":3562.0023950000004,"MediumOffice":47.49307973,"SecondarySchool":4338.227865999999,"SmallOffice":43.25360481,"SmallHotel":232.2194443,"LargeHotel":2750.8382260000003,"FastFoodRest":199.73581399999998,"MidriseApartment":805.0965778,"RetailStore":755.4523907,"FullServiceRest":398.5712205,"StripMall":760.0982018,"Supermarket":2302.228741,"PrimarySchool":981.4176700999999,"FlatLoad":1854.437216,"Warehouse":1151.250885,"Outpatient":2971.868562}} \ No newline at end of file diff --git a/data/load_profiles/total_electric_annual_kwh.json b/data/load_profiles/total_electric_annual_kwh.json new file mode 100644 index 000000000..cf30884dc --- /dev/null +++ b/data/load_profiles/total_electric_annual_kwh.json @@ -0,0 +1 @@ +{"Chicago":{"midriseapartment":265528,"outpatient":1587062,"mediumoffice":972772,"warehouse":245750,"hospital":8567087,"retailstore":513106,"supermarket":2025507,"largehotel":2402021,"stripmall":506886,"secondaryschool":2568086,"fastfoodrest":189558,"smalloffice":86224,"flatload":500000,"largeoffice":6369028,"fullservicerest":333659,"primaryschool":1045477,"smallhotel":759657},"Helena":{"midriseapartment":252659,"outpatient":1568262,"mediumoffice":930630,"warehouse":252245,"hospital":8068698,"retailstore":534933,"supermarket":1969137,"largehotel":2246239,"stripmall":503504,"secondaryschool":2357548,"fastfoodrest":185877,"smalloffice":84219,"flatload":500000,"largeoffice":6003137,"fullservicerest":325263,"primaryschool":994496,"smallhotel":729797},"LasVegas":{"midriseapartment":332312,"warehouse":235888,"mediumoffice":959668,"outpatient":1782941,"hospital":9011047,"retailstore":552267,"supermarket":2001224,"largehotel":2751152,"stripmall":546209,"secondaryschool":3112938,"fastfoodrest":208062,"smalloffice":95801,"flatload":1920398,"largeoffice":6750393,"primaryschool":1196111,"fullservicerest":372350,"smallhotel":818012},"Miami":{"midriseapartment":424956,"outpatient":1929148,"mediumoffice":1021224,"warehouse":202082,"hospital":10062043,"retailstore":635086,"supermarket":2260929,"largehotel":3437188,"stripmall":675793,"secondaryschool":4074081,"fastfoodrest":224494,"smalloffice":108279,"flatload":500000,"largeoffice":8002063,"fullservicerest":448713,"primaryschool":1426635,"smallhotel":972090},"Phoenix":{"midriseapartment":378378,"outpatient":1849358,"mediumoffice":1004988,"warehouse":241585,"hospital":9265786,"retailstore":593924,"supermarket":2056195,"largehotel":2990053,"stripmall":590954,"secondaryschool":3503727,"fastfoodrest":216088,"smalloffice":104583,"flatload":500000,"largeoffice":7211666,"fullservicerest":389739,"primaryschool":1289084,"smallhotel":881843},"LosAngeles":{"midriseapartment":248028,"outpatient":1565008,"mediumoffice":846742,"warehouse":182085,"hospital":8498389,"retailstore":486188,"supermarket":1935886,"largehotel":2458786,"stripmall":491972,"secondaryschool":2584380,"fastfoodrest":188857,"smalloffice":86655,"flatload":500000,"largeoffice":6642784,"fullservicerest":352240,"primaryschool":1095263,"smallhotel":751880},"Boulder":{"midriseapartment":255428,"outpatient":1621950,"mediumoffice":884726,"warehouse":243615,"hospital":8281865,"retailstore":504256,"supermarket":1956244,"largehotel":2313151,"stripmall":495018,"secondaryschool":2441588,"fastfoodrest":189092,"smalloffice":84900,"flatload":500000,"largeoffice":6127030,"fullservicerest":334005,"primaryschool":1018424,"smallhotel":736174},"Minneapolis":{"midriseapartment":267383,"outpatient":1582701,"mediumoffice":1005875,"warehouse":249332,"hospital":8425063,"retailstore":539203,"supermarket":2034650,"largehotel":2378872,"stripmall":511567,"secondaryschool":2498647,"fastfoodrest":188368,"smalloffice":85921,"flatload":500000,"largeoffice":6306693,"fullservicerest":330920,"primaryschool":1022667,"smallhotel":774571},"Baltimore":{"midriseapartment":273225,"outpatient":1623103,"mediumoffice":945425,"warehouse":229712,"hospital":8895223,"retailstore":510257,"supermarket":2018760,"largehotel":2534272,"stripmall":504715,"secondaryschool":2698987,"fastfoodrest":192831,"smalloffice":86112,"flatload":500000,"largeoffice":6836130,"fullservicerest":341893,"primaryschool":1077312,"smallhotel":767538},"SanFrancisco":{"midriseapartment":229671,"outpatient":1394447,"mediumoffice":792199,"warehouse":185889,"hospital":7752817,"retailstore":449025,"supermarket":1841655,"largehotel":2206880,"stripmall":455802,"secondaryschool":2327074,"fastfoodrest":183953,"smalloffice":78132,"flatload":500000,"largeoffice":6085403,"fullservicerest":317124,"primaryschool":1009369,"smallhotel":698095},"Seattle":{"midriseapartment":237242,"outpatient":1434195,"mediumoffice":878390,"warehouse":210300,"hospital":7912504,"retailstore":455854,"supermarket":1868973,"largehotel":2212410,"stripmall":460449,"secondaryschool":2282972,"fastfoodrest":184142,"smalloffice":79716,"flatload":500000,"largeoffice":6019271,"fullservicerest":318741,"primaryschool":983498,"smallhotel":693921},"Atlanta":{"midriseapartment":285349,"outpatient":1672434,"mediumoffice":929349,"warehouse":223009,"hospital":9054747,"retailstore":543340,"supermarket":2092966,"largehotel":2649819,"stripmall":529719,"secondaryschool":2849901,"fastfoodrest":197467,"smalloffice":90162,"flatload":500000,"largeoffice":6995864,"fullservicerest":353750,"primaryschool":1128702,"smallhotel":795777},"Duluth":{"midriseapartment":256393,"outpatient":1534322,"mediumoffice":1032533,"warehouse":256575,"hospital":8134328,"retailstore":532503,"supermarket":1980986,"largehotel":2231678,"stripmall":500979,"secondaryschool":2333466,"fastfoodrest":183713,"smalloffice":83759,"flatload":500000,"largeoffice":6036003,"fullservicerest":318867,"primaryschool":982163,"smallhotel":752284},"Fairbanks":{"midriseapartment":271840,"outpatient":1620270,"mediumoffice":1267132,"warehouse":285064,"hospital":7899166,"retailstore":573411,"supermarket":2033295,"largehotel":2181664,"stripmall":545421,"secondaryschool":2344790,"fastfoodrest":182495,"smalloffice":86614,"flatload":500000,"largeoffice":5956232,"fullservicerest":314760,"primaryschool":986128,"smallhotel":831480},"Houston":{"midriseapartment":335063,"outpatient":1756541,"mediumoffice":972535,"warehouse":221593,"hospital":9634661,"retailstore":589419,"supermarket":2225265,"largehotel":3050370,"stripmall":577987,"secondaryschool":3421024,"fastfoodrest":210283,"smalloffice":98508,"flatload":500000,"largeoffice":7539308,"fullservicerest":383987,"primaryschool":1258146,"smallhotel":863952},"Albuquerque":{"midriseapartment":269734,"outpatient":1678720,"mediumoffice":884408,"warehouse":228939,"hospital":8468546,"retailstore":505417,"supermarket":1947654,"largehotel":2407649,"stripmall":497132,"secondaryschool":2588879,"fastfoodrest":193235,"smalloffice":87008,"flatload":500000,"largeoffice":6303595,"fullservicerest":367661,"primaryschool":1070908,"smallhotel":755373}} \ No newline at end of file diff --git a/docs/src/reopt/inputs.md b/docs/src/reopt/inputs.md index 967d544ad..f21458869 100644 --- a/docs/src/reopt/inputs.md +++ b/docs/src/reopt/inputs.md @@ -139,17 +139,17 @@ REopt.ColdThermalStorageDefaults ## DomesticHotWaterLoad ```@docs -REopt.DomesticHotWaterLoad +REopt.HotWaterLoad ``` ## SpaceHeatingLoad ```@docs -REopt.SpaceHeatingLoad +REopt.HeatingLoad ``` ## ProcessHeatLoad ```@docs -REopt.ProcessHeatLoad +REopt.HeatingLoad ``` ## FlexibleHVAC diff --git a/src/core/doe_commercial_reference_building_loads.jl b/src/core/doe_commercial_reference_building_loads.jl index e751320db..e67f4ea9f 100644 --- a/src/core/doe_commercial_reference_building_loads.jl +++ b/src/core/doe_commercial_reference_building_loads.jl @@ -124,7 +124,8 @@ function built_in_load( year::Int, annual_energy::Real, monthly_energies::AbstractArray{<:Real,1}, - boiler_efficiency_input::Union{Real,Nothing}=nothing + boiler_efficiency_input::Union{Real,Nothing}=nothing, + normalized_profile::Union{Vector{Float64}, Vector{<:Real}}=Real[], ) @assert type in ["electric", "domestic_hot_water", "space_heating", "cooling", "process_heat"] @@ -132,10 +133,15 @@ function built_in_load( lib_path = joinpath(@__DIR__, "..", "..", "data", "load_profiles", type) profile_path = joinpath(lib_path, string("crb8760_norm_" * city * "_" * buildingtype * ".dat")) - if occursin("FlatLoad", buildingtype) - normalized_profile = custom_normalized_flatload(buildingtype, year) - else - normalized_profile = vec(readdlm(profile_path, '\n', Float64, '\n')) + input_normalized = false + if isempty(normalized_profile) + if occursin("FlatLoad", buildingtype) + normalized_profile = custom_normalized_flatload(buildingtype, year) + else + normalized_profile = vec(readdlm(profile_path, '\n', Float64, '\n')) + end + else + input_normalized = true end if length(monthly_energies) == 12 @@ -143,7 +149,10 @@ function built_in_load( t0 = 1 for month in 1:12 plus_hours = daysinmonth(Date(string(year) * "-" * string(month))) * 24 - if month == 2 && isleapyear(year) + if month == 2 && isleapyear(year) && !input_normalized # for a leap year with normalized_profile, the last day is assumed to be truncated + plus_hours -= 24 + end + if month == 12 && isleapyear(year) && input_normalized plus_hours -= 24 end month_total = sum(normalized_profile[t0:t0+plus_hours-1]) @@ -194,10 +203,8 @@ end Given `blended_doe_reference_names` and `blended_doe_reference_percents` use the `constructor` function to load in DoE CRB profiles and create a single profile, where `constructor` is one of: - BuiltInElectricLoad - - BuiltInDomesticHotWaterLoad - - BuiltInSpaceHeatingLoad + - BuiltInHeatingLoad - BuiltInCoolingLoad - - BuiltInProcessHeatLoad """ function blend_and_scale_doe_profiles( @@ -211,7 +218,8 @@ function blend_and_scale_doe_profiles( annual_energy::Union{Real, Nothing} = nothing, monthly_energies::Array{<:Real,1} = Real[], addressable_load_fraction::Union{<:Real, AbstractVector{<:Real}} = 1.0, - boiler_efficiency_input::Union{Real,Nothing}=nothing + boiler_efficiency_input::Union{Real,Nothing}=nothing, + heating_load_type::String="" ) @assert sum(blended_doe_reference_percents) ≈ 1 "The sum of the blended_doe_reference_percents must equal 1" @@ -221,7 +229,7 @@ function blend_and_scale_doe_profiles( year = 2017 if isempty(city) - if constructor === BuiltInProcessHeatLoad + if heating_load_type === "process_heat" city = "Industrial" else city = find_ashrae_zone_city(latitude, longitude) @@ -229,9 +237,9 @@ function blend_and_scale_doe_profiles( end profiles = Array[] # collect the built in profiles - if constructor in [BuiltInSpaceHeatingLoad, BuiltInDomesticHotWaterLoad, BuiltInProcessHeatLoad] + if constructor == BuiltInHeatingLoad for name in blended_doe_reference_names - push!(profiles, constructor(city, name, latitude, longitude, year, addressable_load_fraction, annual_energy, monthly_energies, boiler_efficiency_input)) + push!(profiles, constructor(heating_load_type, city, name, latitude, longitude, year, addressable_load_fraction, annual_energy, monthly_energies, boiler_efficiency_input)) end else for name in blended_doe_reference_names diff --git a/src/core/electric_load.jl b/src/core/electric_load.jl index 4f6e3ba29..6e7e08e06 100644 --- a/src/core/electric_load.jl +++ b/src/core/electric_load.jl @@ -3,6 +3,7 @@ `ElectricLoad` is a required REopt input with the following keys and default values: ```julia loads_kw::Array{<:Real,1} = Real[], + normalize_and_scale_load_profile_input::Bool = false, # Takes loads_kw and normalizes and scales it to annual or monthly energy path_to_csv::String = "", # for csv containing loads_kw doe_reference_name::String = "", blended_doe_reference_names::Array{String, 1} = String[], @@ -86,6 +87,7 @@ mutable struct ElectricLoad # mutable to adjust (critical_)loads_kw based off o function ElectricLoad(; off_grid_flag::Bool = false, loads_kw::Array{<:Real,1} = Real[], + normalize_and_scale_load_profile_input::Bool = false, path_to_csv::String = "", doe_reference_name::String = "", blended_doe_reference_names::Array{String, 1} = String[], @@ -126,11 +128,23 @@ mutable struct ElectricLoad # mutable to adjust (critical_)loads_kw based off o end end - if length(loads_kw) > 0 + if length(loads_kw) > 0 && !normalize_and_scale_load_profile_input if !(length(loads_kw) / time_steps_per_hour ≈ 8760) throw(@error("Provided electric load does not match the time_steps_per_hour.")) end + + elseif length(loads_kw) > 0 && normalize_and_scale_load_profile_input + if !isempty(doe_reference_name) + @warn "loads_kw provided with normalize_and_scale_load_profile_input = true, so ignoring location and building type inputs, and only using the year and annual or monthly energy inputs with the load profile" + end + if isnothing(annual_kwh) && isempty(monthly_totals_kwh) + throw(@error("Provided loads_kw with normalize_and_scale_load_profile_input=true, but no annual_kwh or monthly_totals_kwh was provided")) + end + # Using dummy values for all unneeded location and building type arguments for normalizing and scaling load profile input + normalized_profile = loads_kw ./ sum(loads_kw) + # Need year still mainly for + loads_kw = BuiltInElectricLoad("Chicago", "LargeOffice", 41.8333, -88.0616, year, annual_kwh, monthly_totals_kwh, normalized_profile) elseif !isempty(path_to_csv) try @@ -194,314 +208,11 @@ function BuiltInElectricLoad( year::Int, annual_kwh::Union{Real, Nothing}=nothing, monthly_totals_kwh::Vector{<:Real}=Real[], + normalized_profile::Union{Vector{Float64}, Vector{<:Real}}=Real[] ) - annual_loads = Dict( - "Albuquerque" => Dict( - "fastfoodrest" => 193235, - "fullservicerest" => 367661, - "hospital" => 8468546, - "largehotel" => 2407649, - "largeoffice" => 6303595, - "mediumoffice" => 884408, - "midriseapartment" => 269734, - "outpatient" => 1678720, - "primaryschool" => 1070908, - "retailstore" => 505417, - "secondaryschool" => 2588879, - "smallhotel" => 755373, - "smalloffice" => 87008, - "stripmall" => 497132, - "supermarket" => 1947654, - "warehouse" => 228939, - "flatload" => 500000 - ), - "Atlanta" => Dict( - "fastfoodrest" => 197467, - "fullservicerest" => 353750, - "hospital" => 9054747, - "largehotel" => 2649819, - "largeoffice" => 6995864, - "mediumoffice" => 929349, - "midriseapartment" => 285349, - "outpatient" => 1672434, - "primaryschool" => 1128702, - "retailstore" => 543340, - "secondaryschool" => 2849901, - "smallhotel" => 795777, - "smalloffice" => 90162, - "stripmall" => 529719, - "supermarket" => 2092966, - "warehouse" => 223009, - "flatload" => 500000 - ), - "Baltimore" => Dict( - "fastfoodrest" => 192831, - "fullservicerest" => 341893, - "hospital" => 8895223, - "largehotel" => 2534272, - "largeoffice" => 6836130, - "mediumoffice" => 945425, - "midriseapartment" => 273225, - "outpatient" => 1623103, - "primaryschool" => 1077312, - "retailstore" => 510257, - "secondaryschool" => 2698987, - "smallhotel" => 767538, - "smalloffice" => 86112, - "stripmall" => 504715, - "supermarket" => 2018760, - "warehouse" => 229712, - "flatload" => 500000 - ), - "Boulder" => Dict( - "fastfoodrest" => 189092, - "fullservicerest" => 334005, - "hospital" => 8281865, - "largehotel" => 2313151, - "largeoffice" => 6127030, - "mediumoffice" => 884726, - "midriseapartment" => 255428, - "outpatient" => 1621950, - "primaryschool" => 1018424, - "retailstore" => 504256, - "secondaryschool" => 2441588, - "smallhotel" => 736174, - "smalloffice" => 84900, - "stripmall" => 495018, - "supermarket" => 1956244, - "warehouse" => 243615, - "flatload" => 500000 - ), - "Chicago" => Dict( - "fastfoodrest" => 189558, - "fullservicerest" => 333659, - "hospital" => 8567087, - "largehotel" => 2402021, - "largeoffice" => 6369028, - "mediumoffice" => 972772, - "midriseapartment" => 265528, - "outpatient" => 1587062, - "primaryschool" => 1045477, - "retailstore" => 513106, - "secondaryschool" => 2568086, - "smallhotel" => 759657, - "smalloffice" => 86224, - "stripmall" => 506886, - "supermarket" => 2025507, - "warehouse" => 245750, - "flatload" => 500000 - ), - "Duluth" => Dict( - "fastfoodrest" => 183713, - "fullservicerest" => 318867, - "hospital" => 8134328, - "largehotel" => 2231678, - "largeoffice" => 6036003, - "mediumoffice" => 1032533, - "midriseapartment" => 256393, - "outpatient" => 1534322, - "primaryschool" => 982163, - "retailstore" => 532503, - "secondaryschool" => 2333466, - "smallhotel" => 752284, - "smalloffice" => 83759, - "stripmall" => 500979, - "supermarket" => 1980986, - "warehouse" => 256575, - "flatload" => 500000 - ), - "Fairbanks" => Dict( - "fastfoodrest" => 182495, - "fullservicerest" => 314760, - "hospital" => 7899166, - "largehotel" => 2181664, - "largeoffice" => 5956232, - "mediumoffice" => 1267132, - "midriseapartment" => 271840, - "outpatient" => 1620270, - "primaryschool" => 986128, - "retailstore" => 573411, - "secondaryschool" => 2344790, - "smallhotel" => 831480, - "smalloffice" => 86614, - "stripmall" => 545421, - "supermarket" => 2033295, - "warehouse" => 285064, - "flatload" => 500000 - ), - "Helena" => Dict( - "fastfoodrest" => 185877, - "fullservicerest" => 325263, - "hospital" => 8068698, - "largehotel" => 2246239, - "largeoffice" => 6003137, - "mediumoffice" => 930630, - "midriseapartment" => 252659, - "outpatient" => 1568262, - "primaryschool" => 994496, - "retailstore" => 534933, - "secondaryschool" => 2357548, - "smallhotel" => 729797, - "smalloffice" => 84219, - "stripmall" => 503504, - "supermarket" => 1969137, - "warehouse" => 252245, - "flatload" => 500000 - ), - "Houston" => Dict( - "fastfoodrest" => 210283, - "fullservicerest" => 383987, - "hospital" => 9634661, - "largehotel" => 3050370, - "largeoffice" => 7539308, - "mediumoffice" => 972535, - "midriseapartment" => 335063, - "outpatient" => 1756541, - "primaryschool" => 1258146, - "retailstore" => 589419, - "secondaryschool" => 3421024, - "smallhotel" => 863952, - "smalloffice" => 98508, - "stripmall" => 577987, - "supermarket" => 2225265, - "warehouse" => 221593, - "flatload" => 500000 - ), - "LosAngeles" => Dict( - "fastfoodrest" => 188857, - "fullservicerest" => 352240, - "hospital" => 8498389, - "largehotel" => 2458786, - "largeoffice" => 6642784, - "mediumoffice" => 846742, - "midriseapartment" => 248028, - "outpatient" => 1565008, - "primaryschool" => 1095263, - "retailstore" => 486188, - "secondaryschool" => 2584380, - "smallhotel" => 751880, - "smalloffice" => 86655, - "stripmall" => 491972, - "supermarket" => 1935886, - "warehouse" => 182085, - "flatload" => 500000 - ), - "LasVegas" => Dict( - "retailstore" => 552267, - "largehotel" => 2751152, - "mediumoffice" => 959668, - "stripmall" => 546209, - "primaryschool" => 1196111, - "warehouse" => 235888, - "smalloffice" => 95801, - "supermarket" => 2001224, - "midriseapartment" => 332312, - "fullservicerest" => 372350, - "outpatient" => 1782941, - "fastfoodrest" => 208062, - "smallhotel" => 818012, - "largeoffice" => 6750393, - "secondaryschool" => 3112938, - "hospital" => 9011047, - "flatload" => 1920398 - ), - "Miami" => Dict( - "fastfoodrest" => 224494, - "fullservicerest" => 448713, - "hospital" => 10062043, - "largehotel" => 3437188, - "largeoffice" => 8002063, - "mediumoffice" => 1021224, - "midriseapartment" => 424956, - "outpatient" => 1929148, - "primaryschool" => 1426635, - "retailstore" => 635086, - "secondaryschool" => 4074081, - "smallhotel" => 972090, - "smalloffice" => 108279, - "stripmall" => 675793, - "supermarket" => 2260929, - "warehouse" => 202082, - "flatload" => 500000 - ), - "Minneapolis" => Dict( - "fastfoodrest" => 188368, - "fullservicerest" => 330920, - "hospital" => 8425063, - "largehotel" => 2378872, - "largeoffice" => 6306693, - "mediumoffice" => 1005875, - "midriseapartment" => 267383, - "outpatient" => 1582701, - "primaryschool" => 1022667, - "retailstore" => 539203, - "secondaryschool" => 2498647, - "smallhotel" => 774571, - "smalloffice" => 85921, - "stripmall" => 511567, - "supermarket" => 2034650, - "warehouse" => 249332, - "flatload" => 500000 - ), - "Phoenix" => Dict( - "fastfoodrest" => 216088, - "fullservicerest" => 389739, - "hospital" => 9265786, - "largehotel" => 2990053, - "largeoffice" => 7211666, - "mediumoffice" => 1004988, - "midriseapartment" => 378378, - "outpatient" => 1849358, - "primaryschool" => 1289084, - "retailstore" => 593924, - "secondaryschool" => 3503727, - "smallhotel" => 881843, - "smalloffice" => 104583, - "stripmall" => 590954, - "supermarket" => 2056195, - "warehouse" => 241585, - "flatload" => 500000 - ), - "SanFrancisco" => Dict( - "fastfoodrest" => 183953, - "fullservicerest" => 317124, - "hospital" => 7752817, - "largehotel" => 2206880, - "largeoffice" => 6085403, - "mediumoffice" => 792199, - "midriseapartment" => 229671, - "outpatient" => 1394447, - "primaryschool" => 1009369, - "retailstore" => 449025, - "secondaryschool" => 2327074, - "smallhotel" => 698095, - "smalloffice" => 78132, - "stripmall" => 455802, - "supermarket" => 1841655, - "warehouse" => 185889, - "flatload" => 500000 - ), - "Seattle" => Dict( - "fastfoodrest" => 184142, - "fullservicerest" => 318741, - "hospital" => 7912504, - "largehotel" => 2212410, - "largeoffice" => 6019271, - "mediumoffice" => 878390, - "midriseapartment" => 237242, - "outpatient" => 1434195, - "primaryschool" => 983498, - "retailstore" => 455854, - "secondaryschool" => 2282972, - "smallhotel" => 693921, - "smalloffice" => 79716, - "stripmall" => 460449, - "supermarket" => 1868973, - "warehouse" => 210300, - "flatload" => 500000 - ), - ) + electric_annual_kwh = JSON.parsefile(joinpath(@__DIR__, "..", "..", "data", "load_profiles", "total_electric_annual_kwh.json")) + if !(buildingtype in default_buildings) throw(@error("buildingtype $(buildingtype) not in $(default_buildings).")) end @@ -513,11 +224,11 @@ function BuiltInElectricLoad( if isnothing(annual_kwh) # Use FlatLoad annual_kwh from data for all types of FlatLoads because we don't have separate data for e.g. FlatLoad_16_7 if occursin("FlatLoad", buildingtype) - annual_kwh = annual_loads[city][lowercase("FlatLoad")] + annual_kwh = electric_annual_kwh[city][lowercase("FlatLoad")] else - annual_kwh = annual_loads[city][lowercase(buildingtype)] + annual_kwh = electric_annual_kwh[city][lowercase(buildingtype)] end end - built_in_load("electric", city, buildingtype, year, annual_kwh, monthly_totals_kwh) + built_in_load("electric", city, buildingtype, year, annual_kwh, monthly_totals_kwh, nothing, normalized_profile) end diff --git a/src/core/heating_cooling_loads.jl b/src/core/heating_cooling_loads.jl index 92b3eecb8..b629c6232 100644 --- a/src/core/heating_cooling_loads.jl +++ b/src/core/heating_cooling_loads.jl @@ -1,249 +1,250 @@ # REopt®, Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/REopt.jl/blob/master/LICENSE. """ -`DomesticHotWaterLoad` is an optional REopt input with the following keys and default values: +# `HeatingLoad` is a base function for the types of heating load inputs with the following keys and default values: ```julia - doe_reference_name::String = "", - blended_doe_reference_names::Array{String, 1} = String[], - blended_doe_reference_percents::Array{<:Real,1} = Real[], + load_type::String = "", # Valid options are space_heating for SpaceHeatingLoad, domestic_hot_water for DomesticHotWaterLoad, and process_heat for ProcessHeatLoad + doe_reference_name::String = "", # For SpaceHeatingLoad and DomesticHotWaterLoad + blended_doe_reference_names::Array{String, 1} = String[], # For SpaceHeatingLoad and DomesticHotWaterLoad + blended_doe_reference_percents::Array{<:Real,1} = Real[], # For SpaceHeatingLoad and DomesticHotWaterLoad + industrial_reference_name::String = "", # For ProcessHeatLoad + blended_industrial_reference_names::Array{String, 1} = String[], # For ProcessHeatLoad + blended_industrial_reference_percents::Array{<:Real,1} = Real[], # For ProcessHeatLoad addressable_load_fraction::Any = 1.0, # Fraction of input fuel load which is addressable by heating technologies. Can be a scalar or vector with length aligned with use of monthly_mmbtu or fuel_loads_mmbtu_per_hour. annual_mmbtu::Union{Real, Nothing} = nothing, monthly_mmbtu::Array{<:Real,1} = Real[], - fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], # Vector of hot water fuel loads [mmbtu/hour]. Length must equal 8760 * `Settings.time_steps_per_hour` + fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], # Vector of space heating fuel loads [mmbtu/hr]. Length must equal 8760 * `Settings.time_steps_per_hour` + normalize_and_scale_load_profile_input::Bool = false, # Takes fuel_loads_mmbtu_per_hour and normalizes and scales it to annual or monthly energy existing_boiler_efficiency::Real = NaN ``` -There are many ways in which a DomesticHotWaterLoad can be defined: -1. When using either `doe_reference_name` or `blended_doe_reference_names` in an `ElectricLoad` one only needs to provide the input key "DomesticHotWaterLoad" in the `Scenario` (JSON or Dict). In this case the values from DoE reference names from the `ElectricLoad` will be used to define the `DomesticHotWaterLoad`. -2. One can provide the `doe_reference_name` or `blended_doe_reference_names` directly in the `DomesticHotWaterLoad` key within the `Scenario`. These values can be combined with the `annual_mmbtu` or `monthly_mmbtu` inputs to scale the DoE reference profile(s). -3. One can provide the `fuel_loads_mmbtu_per_hour` value in the `DomesticHotWaterLoad` key within the `Scenario`. +There are different ways to define a heating load: +1. A time-series via the `fuel_loads_mmbtu_per_hour`, +2. Scaling a DOE Commercial Reference Building (CRB) or industrial reference profile or a blend of profiles to either the `annual_mmbtu` or `monthly_mmbtu` values; +3. Using the same `doe_reference_name` or `blended_doe_reference_names` from the `ElectricLoad`. +4. A time-series via the `fuel_loads_mmbtu_per_hour` along with `annual_mmbtu` or `monthly_mmbtu` with `normalize_and_scale_load_profile_input`=true -!!! note "Hot water loads" - Hot water, space heating, and process heat thermal "load" inputs are in terms of energy input required (boiler fuel), - not the actual energy demand. The fuel energy is multiplied by the existing_boiler_efficiency to get the actual energy - demand. +When using an `ElectricLoad` defined from a `doe_reference_name` or `blended_doe_reference_names` +one only needs to provide an empty Dict in the scenario JSON to add a `SpaceHeatingLoad` to a +`Scenario`, i.e.: +```json +... +"ElectricLoad": {"doe_reference_name": "MidriseApartment"}, +"SpaceHeatingLoad" : {}, +... +``` +In this case the values provided for `doe_reference_name`, or `blended_doe_reference_names` and +`blended_doe_reference_percents` are copied from the `ElectricLoad` to the the particular `HeatingLoad` type. +!!! note for all heating loads + Hot water, space heating, and process heat "load" inputs are in terms of energy input required (boiler fuel), + not the actual end use thermal energy demand. The fuel energy is multiplied by the existing_boiler_efficiency to get the actual energy + demand. """ -struct DomesticHotWaterLoad - loads_kw::Array{Real, 1} - annual_mmbtu::Real - unaddressable_annual_fuel_mmbtu::Real - - function DomesticHotWaterLoad(; - doe_reference_name::String = "", - city::String = "", - blended_doe_reference_names::Array{String, 1} = String[], - blended_doe_reference_percents::Array{<:Real,1} = Real[], - annual_mmbtu::Union{Real, Nothing} = nothing, - monthly_mmbtu::Array{<:Real,1} = Real[], - addressable_load_fraction::Any = 1.0, - fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], - time_steps_per_hour::Int = 1, # corresponding to `fuel_loads_mmbtu_per_hour` - latitude::Real = 0.0, - longitude::Real = 0.0, - existing_boiler_efficiency::Real = NaN +function HeatingLoad(; + load_type::String = "", + doe_reference_name::String = "", + blended_doe_reference_names::Array{String, 1} = String[], + blended_doe_reference_percents::Array{<:Real,1} = Real[], + industrial_reference_name::String = "", + blended_industrial_reference_names::Array{String, 1} = String[], + blended_industrial_reference_percents::Array{<:Real,1} = Real[], + city::String = "", + year::Int = doe_reference_name ≠ "" || blended_doe_reference_names ≠ String[] ? 2017 : 2022, # CRB profiles must use 2017. If providing load profile, specify year of data. + annual_mmbtu::Union{Real, Nothing} = nothing, + monthly_mmbtu::Array{<:Real,1} = Real[], + addressable_load_fraction::Any = 1.0, + fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], + normalize_and_scale_load_profile_input::Bool = false, + time_steps_per_hour::Int = 1, # corresponding to `fuel_loads_mmbtu_per_hour` + latitude::Real = 0.0, + longitude::Real = 0.0, + existing_boiler_efficiency::Real = NaN ) - if length(addressable_load_fraction) > 1 - if !isempty(fuel_loads_mmbtu_per_hour) && length(addressable_load_fraction) != length(fuel_loads_mmbtu_per_hour) - throw(@error("`addressable_load_fraction` must be a scalar or an array of length `fuel_loads_mmbtu_per_hour`")) - end - if !isempty(monthly_mmbtu) && length(addressable_load_fraction) != 12 - throw(@error("`addressable_load_fraction` must be a scalar or an array of length 12 if `monthly_mmbtu` is input")) - end - addressable_load_fraction = convert(Vector{Real}, addressable_load_fraction) - elseif typeof(addressable_load_fraction) <: Vector{} - addressable_load_fraction = convert(Real, addressable_load_fraction[1]) - else - addressable_load_fraction = convert(Real, addressable_load_fraction) + # Determine which type of heating load to build + if load_type == "space_heating" + load = :SpaceHeatingLoad + struct_type = SpaceHeatingLoad + elseif load_type == "domestic_hot_water" + load = :DomesticHotWaterLoad + struct_type = DomesticHotWaterLoad + elseif load_type == "process_heat" + load = :ProcessHeatLoad + struct_type = ProcessHeatLoad + city = "Industrial" + doe_reference_name = industrial_reference_name + blended_doe_reference_names = blended_industrial_reference_names + blended_doe_reference_percents = blended_industrial_reference_percents + else + throw(@error("load_type must be 'space_heating', 'domestic_hot_water', or 'process_heat'")) + end + + if length(addressable_load_fraction) > 1 + if !isempty(fuel_loads_mmbtu_per_hour) && length(addressable_load_fraction) != length(fuel_loads_mmbtu_per_hour) + throw(@error("`addressable_load_fraction` must be a scalar or an array of length `fuel_loads_mmbtu_per_hour`")) end - - if length(fuel_loads_mmbtu_per_hour) > 0 + if !isempty(monthly_mmbtu) && length(addressable_load_fraction) != 12 + throw(@error("`addressable_load_fraction` must be a scalar or an array of length 12 if `monthly_mmbtu` is input")) + end + addressable_load_fraction = convert(Vector{Real}, addressable_load_fraction) + elseif typeof(addressable_load_fraction) <: Vector{} + addressable_load_fraction = convert(Real, addressable_load_fraction[1]) + else + addressable_load_fraction = convert(Real, addressable_load_fraction) + end - if !(length(fuel_loads_mmbtu_per_hour) / time_steps_per_hour ≈ 8760) - throw(@error("Provided DomesticHotWaterLoad `fuel_loads_mmbtu_per_hour` does not match the time_steps_per_hour.")) - end + if length(fuel_loads_mmbtu_per_hour) > 0 && !normalize_and_scale_load_profile_input - loads_kw = fuel_loads_mmbtu_per_hour .* (KWH_PER_MMBTU * existing_boiler_efficiency) .* addressable_load_fraction - unaddressable_annual_fuel_mmbtu = sum(fuel_loads_mmbtu_per_hour .* (1 .- addressable_load_fraction)) / time_steps_per_hour + if !(length(fuel_loads_mmbtu_per_hour) / time_steps_per_hour ≈ 8760) + throw(@error("Provided $load load does not match the time_steps_per_hour.")) + end - if !isempty(doe_reference_name) || length(blended_doe_reference_names) > 0 - @warn "DomesticHotWaterLoad `fuel_loads_mmbtu_per_hour` was provided, so doe_reference_name and/or blended_doe_reference_names will be ignored." - end + loads_kw = fuel_loads_mmbtu_per_hour .* (KWH_PER_MMBTU * existing_boiler_efficiency) .* addressable_load_fraction + unaddressable_annual_fuel_mmbtu = sum(fuel_loads_mmbtu_per_hour .* (1 .- addressable_load_fraction)) / time_steps_per_hour - elseif !isempty(doe_reference_name) - loads_kw = BuiltInDomesticHotWaterLoad(city, doe_reference_name, latitude, longitude, 2017, addressable_load_fraction, annual_mmbtu, monthly_mmbtu, existing_boiler_efficiency) - if length(blended_doe_reference_names) > 0 - @warn "DomesticHotWaterLoad doe_reference_name was provided, so blended_doe_reference_names will be ignored." - end - unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) - elseif length(blended_doe_reference_names) > 0 && - length(blended_doe_reference_names) == length(blended_doe_reference_percents) - loads_kw = blend_and_scale_doe_profiles(BuiltInDomesticHotWaterLoad, latitude, longitude, 2017, - blended_doe_reference_names, blended_doe_reference_percents, city, - annual_mmbtu, monthly_mmbtu, addressable_load_fraction, - existing_boiler_efficiency) - unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) - else - throw(@error("Cannot construct DomesticHotWaterLoad. You must provide either [fuel_loads_mmbtu_per_hour], - [doe_reference_name, city], or [blended_doe_reference_names, blended_doe_reference_percents, city].")) + if !isempty(doe_reference_name) || length(blended_doe_reference_names) > 0 + @warn "$load fuel_loads_mmbtu_per_hour was provided, so doe_reference_name and/or blended_doe_reference_names will be ignored." end - if length(loads_kw) < 8760*time_steps_per_hour - loads_kw = repeat(loads_kw, inner=Int(time_steps_per_hour / (length(loads_kw)/8760))) - @warn "Repeating domestic hot water loads in each hour to match the time_steps_per_hour." + elseif length(fuel_loads_mmbtu_per_hour) > 0 && normalize_and_scale_load_profile_input + if !isempty(doe_reference_name) + @warn "fuel_loads_mmbtu_per_hour provided with normalize_and_scale_load_profile_input = true, so ignoring location and building type inputs, and only using the year and annual or monthly energy inputs with the load profile" end - - new( - loads_kw, - (sum(loads_kw)/time_steps_per_hour)/KWH_PER_MMBTU, - unaddressable_annual_fuel_mmbtu - ) + if isnothing(annual_mmbtu) && isempty(monthly_mmbtu) + throw(@error("Provided fuel_loads_mmbtu_per_hour with normalize_and_scale_load_profile_input=true, but no annual_mmbtu or monthly_mmbtu was provided")) + end + # Using dummy values for all unneeded location and building type arguments for normalizing and scaling load profile input + normalized_profile = fuel_loads_mmbtu_per_hour ./ sum(fuel_loads_mmbtu_per_hour) + loads_kw = BuiltInHeatingLoad(load_type, "Chicago", "FlatLoad", 41.8333, -88.0616, year, addressable_load_fraction, annual_mmbtu, monthly_mmbtu, existing_boiler_efficiency, normalized_profile) + unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) + elseif !isempty(doe_reference_name) + loads_kw = BuiltInHeatingLoad(load_type, city, doe_reference_name, latitude, longitude, 2017, addressable_load_fraction, annual_mmbtu, monthly_mmbtu, existing_boiler_efficiency) + if length(blended_doe_reference_names) > 0 + @warn "SpaceHeatingLoad doe_reference_name was provided, so blended_doe_reference_names will be ignored." + end + unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) + elseif length(blended_doe_reference_names) > 0 && + length(blended_doe_reference_names) == length(blended_doe_reference_percents) + loads_kw = blend_and_scale_doe_profiles(BuiltInHeatingLoad, latitude, longitude, 2017, + blended_doe_reference_names, blended_doe_reference_percents, city, + annual_mmbtu, monthly_mmbtu, addressable_load_fraction, + existing_boiler_efficiency, load_type) + unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) + else + throw(@error("Cannot construct $load. You must provide either [fuel_loads_mmbtu_per_hour], + [doe_reference_name, latitude, longitude], or [blended_doe_reference_names, blended_doe_reference_percents, latitude, longitude].")) end -end - -""" -`SpaceHeatingLoad` is an optional REopt input with the following keys and default values: -```julia - doe_reference_name::String = "", - blended_doe_reference_names::Array{String, 1} = String[], - blended_doe_reference_percents::Array{<:Real,1} = Real[], - addressable_load_fraction::Any = 1.0, # Fraction of input fuel load which is addressable by heating technologies. Can be a scalar or vector with length aligned with use of monthly_mmbtu or fuel_loads_mmbtu_per_hour. - annual_mmbtu::Union{Real, Nothing} = nothing, - monthly_mmbtu::Array{<:Real,1} = Real[], - fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], # Vector of space heating fuel loads [mmbtu/hr]. Length must equal 8760 * `Settings.time_steps_per_hour` - existing_boiler_efficiency::Real = NaN -``` + if length(loads_kw) < 8760*time_steps_per_hour + loads_kw = repeat(loads_kw, inner=Int(time_steps_per_hour / (length(loads_kw)/8760))) + @warn "Repeating $load in each hour to match the time_steps_per_hour." + end -There are many ways to define a `SpaceHeatingLoad`: -1. a time-series via the `fuel_loads_mmbtu_per_hour`, -2. scaling a DoE Commercial Reference Building (CRB) profile or a blend of CRB profiles to either the `annual_mmbtu` or `monthly_mmbtu` values; -3. or using the `doe_reference_name` or `blended_doe_reference_names` from the `ElectricLoad`. + struct_type( + loads_kw, + (sum(loads_kw)/time_steps_per_hour)/KWH_PER_MMBTU, + unaddressable_annual_fuel_mmbtu + ) +end -When using an `ElectricLoad` defined from a `doe_reference_name` or `blended_doe_reference_names` -one only needs to provide an empty Dict in the scenario JSON to add a `SpaceHeatingLoad` to a -`Scenario`, i.e.: -```json -... -"ElectricLoad": {"doe_reference_name": "MidriseApartment"}, -"SpaceHeatingLoad" : {}, -... -``` -In this case the values provided for `doe_reference_name`, or `blended_doe_reference_names` and -`blended_doe_reference_percents` are copied from the `ElectricLoad` to the `SpaceHeatingLoad`. +struct DomesticHotWaterLoad + loads_kw::Array{Real, 1} + annual_mmbtu::Real + unaddressable_annual_fuel_mmbtu::Real +end -!!! note "Space heating loads" - Hot water, space heating, and process heat thermal "load" inputs are in terms of energy input required (boiler fuel), - not the actual energy demand. The fuel energy is multiplied by the existing_boiler_efficiency to get the actual energy - emand. -""" struct SpaceHeatingLoad loads_kw::Array{Real, 1} annual_mmbtu::Real unaddressable_annual_fuel_mmbtu::Real +end - function SpaceHeatingLoad(; - doe_reference_name::String = "", - city::String = "", - blended_doe_reference_names::Array{String, 1} = String[], - blended_doe_reference_percents::Array{<:Real,1} = Real[], - annual_mmbtu::Union{Real, Nothing} = nothing, - monthly_mmbtu::Array{<:Real,1} = Real[], - addressable_load_fraction::Any = 1.0, - fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], - time_steps_per_hour::Int = 1, # corresponding to `fuel_loads_mmbtu_per_hour` - latitude::Real = 0.0, - longitude::Real = 0.0, - existing_boiler_efficiency::Real = NaN - ) - - if length(addressable_load_fraction) > 1 - if !isempty(fuel_loads_mmbtu_per_hour) && length(addressable_load_fraction) != length(fuel_loads_mmbtu_per_hour) - throw(@error("`addressable_load_fraction` must be a scalar or an array of length `fuel_loads_mmbtu_per_hour`")) - end - if !isempty(monthly_mmbtu) && length(addressable_load_fraction) != 12 - throw(@error("`addressable_load_fraction` must be a scalar or an array of length 12 if `monthly_mmbtu` is input")) - end - addressable_load_fraction = convert(Vector{Real}, addressable_load_fraction) - elseif typeof(addressable_load_fraction) <: Vector{} - addressable_load_fraction = convert(Real, addressable_load_fraction[1]) - else - addressable_load_fraction = convert(Real, addressable_load_fraction) - end - - if length(fuel_loads_mmbtu_per_hour) > 0 +struct ProcessHeatLoad + loads_kw::Array{Real, 1} + annual_mmbtu::Real + unaddressable_annual_fuel_mmbtu::Real +end - if !(length(fuel_loads_mmbtu_per_hour) / time_steps_per_hour ≈ 8760) - throw(@error("Provided space heating load does not match the time_steps_per_hour.")) - end +function BuiltInHeatingLoad( + load_type::String, + city::String, + buildingtype::String, + latitude::Real, + longitude::Real, + year::Int, + addressable_load_fraction::Union{<:Real, AbstractVector{<:Real}}, + annual_mmbtu::Union{Real, Nothing}=nothing, + monthly_mmbtu::Vector{<:Real}=Real[], + existing_boiler_efficiency::Union{Real, Nothing}=nothing, + normalized_profile::Union{Vector{Float64}, Vector{<:Real}}=Real[] + ) - loads_kw = fuel_loads_mmbtu_per_hour .* (KWH_PER_MMBTU * existing_boiler_efficiency) .* addressable_load_fraction - unaddressable_annual_fuel_mmbtu = sum(fuel_loads_mmbtu_per_hour .* (1 .- addressable_load_fraction)) / time_steps_per_hour + # Load the appropriate default annual energy data based on load_type + if load_type == "space_heating" + default_annual_mmbtu = JSON.parsefile(joinpath(@__DIR__, "..", "..", "data", "load_profiles", "space_heating_annual_mmbtu.json")) + elseif load_type == "domestic_hot_water" + default_annual_mmbtu = JSON.parsefile(joinpath(@__DIR__, "..", "..", "data", "load_profiles", "domestic_hot_water_annual_mmbtu.json")) + elseif load_type == "process_heat" + default_annual_mmbtu = Dict( + "Industrial" => Dict( + "Chemical" => 15000.0, # mid-sized chemical processes + "FlatLoad" => 10000, # continuous operations throughout the year + "Warehouse" => 7000 + ) + ) + city = "Industrial" + else + throw(@error("For BuiltInHeatingLoad, load_type must be 'space_heating', 'domestic_hot_water', or 'process_heat'")) + end - if !isempty(doe_reference_name) || length(blended_doe_reference_names) > 0 - @warn "SpaceHeatingLoad fuel_loads_mmbtu_per_hour was provided, so doe_reference_name and/or blended_doe_reference_names will be ignored." - end + if isempty(city) + city = find_ashrae_zone_city(latitude, longitude) + end + if (load_type in ["space_heating", "domestic_hot_water"]) && !(buildingtype in default_buildings) + throw(@error("buildingtype $(buildingtype) not in $(default_buildings).")) + end + if (load_type == "process_heat") && !(buildingtype in default_process_types) + throw(@error("buildingtype $(buildingtype) not in $(default_process_types).")) + end - elseif !isempty(doe_reference_name) - loads_kw = BuiltInSpaceHeatingLoad(city, doe_reference_name, latitude, longitude, 2017, addressable_load_fraction, annual_mmbtu, monthly_mmbtu, existing_boiler_efficiency) - if length(blended_doe_reference_names) > 0 - @warn "SpaceHeatingLoad doe_reference_name was provided, so blended_doe_reference_names will be ignored." - end - unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) - elseif length(blended_doe_reference_names) > 0 && - length(blended_doe_reference_names) == length(blended_doe_reference_percents) - loads_kw = blend_and_scale_doe_profiles(BuiltInSpaceHeatingLoad, latitude, longitude, 2017, - blended_doe_reference_names, blended_doe_reference_percents, city, - annual_mmbtu, monthly_mmbtu, addressable_load_fraction, - existing_boiler_efficiency) - unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) + if isnothing(annual_mmbtu) + # Use FlatLoad annual_mmbtu from data for all types of FlatLoads because we don't have separate data for e.g. FlatLoad_16_7 + if occursin("FlatLoad", buildingtype) + annual_mmbtu = default_annual_mmbtu[city]["FlatLoad"] else - throw(@error("Cannot construct BuiltInSpaceHeatingLoad. You must provide either [fuel_loads_mmbtu_per_hour], - [doe_reference_name, city], or [blended_doe_reference_names, blended_doe_reference_percents, city].")) - end - - if length(loads_kw) < 8760*time_steps_per_hour - loads_kw = repeat(loads_kw, inner=Int(time_steps_per_hour / (length(loads_kw)/8760))) - @warn "Repeating space heating loads in each hour to match the time_steps_per_hour." + annual_mmbtu = default_annual_mmbtu[city][buildingtype] end - - new( - loads_kw, - (sum(loads_kw)/time_steps_per_hour)/KWH_PER_MMBTU, - unaddressable_annual_fuel_mmbtu - ) + else + annual_mmbtu *= addressable_load_fraction end + if length(monthly_mmbtu) == 12 + monthly_mmbtu = monthly_mmbtu .* addressable_load_fraction + end + built_in_load(load_type, city, buildingtype, year, annual_mmbtu, monthly_mmbtu, + existing_boiler_efficiency, normalized_profile) end """ -function get_existing_chiller_default_cop(; existing_chiller_max_thermal_factor_on_peak_load=nothing, - max_load_kw=nothing, - max_load_kw_thermal=nothing) -This function returns the default value for ExistingChiller.cop based on: - 1. No information about load, returns average of lower and higher cop default values (`cop_unknown_thermal`) - 2. If the cooling electric `max_load_kw` is known, we first guess the thermal load profile using `cop_unknown_thermal`, - and then we use the default logic to determine the `existing_chiller_cop` based on the peak thermal load with a thermal factor multiplier. - 3. If the cooling thermal `max_load_kw_thermal` is known, same as 2. but we don't have to guess the cop to convert electric to thermal load first. + get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) + +Get unaddressable fuel load, for reporting + :addressable_load_fraction is the fraction of the input fuel load that is addressable to supply by energy technologies, like CHP + :annual_mmbtu and :monthly_mmbtu is assumed to be fuel, not thermal, in this function + :loads_kw is assumed to be thermal in this function, with units of kw_thermal, so needs to be converted to fuel mmbtu """ -function get_existing_chiller_default_cop(; existing_chiller_max_thermal_factor_on_peak_load=nothing, max_load_kw=nothing, max_load_kw_thermal=nothing) - cop_less_than_100_ton = 4.40 - cop_more_than_100_ton = 4.69 - cop_unknown_thermal = (cop_less_than_100_ton + cop_more_than_100_ton) / 2.0 - max_cooling_load_ton = nothing - if !isnothing(max_load_kw_thermal) - max_cooling_load_ton = max_load_kw_thermal / KWH_THERMAL_PER_TONHOUR - elseif !isnothing(max_load_kw) - max_cooling_load_ton = max_load_kw / KWH_THERMAL_PER_TONHOUR * cop_unknown_thermal - end - if isnothing(max_cooling_load_ton) || isnothing(existing_chiller_max_thermal_factor_on_peak_load) - return cop_unknown_thermal - elseif max_cooling_load_ton * existing_chiller_max_thermal_factor_on_peak_load < 100.0 - return cop_less_than_100_ton - else - return cop_more_than_100_ton +function get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) + # Get unaddressable fuel load, for reporting + if !isempty(monthly_mmbtu) + unaddressable_annual_fuel_mmbtu = sum(monthly_mmbtu .* (1 .- addressable_load_fraction)) + elseif !isnothing(annual_mmbtu) + unaddressable_annual_fuel_mmbtu = annual_mmbtu * (1 - addressable_load_fraction) + else # using the default CRB annual_mmbtu, so rely on loads_kw (thermal) assuming single addressable_load_fraction + unaddressable_annual_fuel_mmbtu = sum(loads_kw) / (KWH_PER_MMBTU * existing_boiler_efficiency) end + return unaddressable_annual_fuel_mmbtu end + """ `CoolingLoad` is an optional REopt input with the following keys and default values: ```julia @@ -410,689 +411,35 @@ function get_default_fraction_of_total_electric(city, doe_reference_name, latitu return default_fraction_of_total_electric_profile end - -function BuiltInDomesticHotWaterLoad( - city::String, - buildingtype::String, - latitude::Real, - longitude::Real, - year::Int, - addressable_load_fraction::Union{<:Real, AbstractVector{<:Real}}, - annual_mmbtu::Union{Real, Nothing}=nothing, - monthly_mmbtu::Vector{<:Real}=Real[], - existing_boiler_efficiency::Union{Real, Nothing}=nothing - ) - dhw_annual_mmbtu = Dict( - "Miami" => Dict( - "FastFoodRest" => 53.47209411, - "FullServiceRest" => 158.0518043, - "Hospital" => 442.7295435, - "LargeHotel" => 3713.248373, - "LargeOffice" => 127.9412792, - "MediumOffice" => 22.09603477, - "MidriseApartment" => 158.0580017, - "Outpatient" => 27.60091429, - "PrimarySchool" => 105.3179165, - "RetailStore" => 0.0, - "SecondarySchool" => 250.1299246, - "SmallHotel" => 242.232695, - "SmallOffice" => 9.891779415, - "StripMall" => 0.0, - "Supermarket" => 17.94985187, - "Warehouse" => 0.0, - "FlatLoad" => 333.0450133 - ), - "Houston" => Dict( - "FastFoodRest" => 62.56835989, - "FullServiceRest" => 188.292814, - "Hospital" => 530.6352726, - "LargeHotel" => 4685.666667, - "LargeOffice" => 160.8917808, - "MediumOffice" => 25.9266894, - "MidriseApartment" => 199.2544784, - "Outpatient" => 32.87691943, - "PrimarySchool" => 128.0705362, - "RetailStore" => 0.0, - "SecondarySchool" => 314.7654465, - "SmallHotel" => 290.6293673, - "SmallOffice" => 10.27839347, - "StripMall" => 0.0, - "Supermarket" => 19.86608717, - "Warehouse" => 0.0, - "FlatLoad" => 415.6076756 - ), - "Phoenix" => Dict( - "FastFoodRest" => 57.34025418, - "FullServiceRest" => 170.9086319, - "Hospital" => 480.098265, - "LargeHotel" => 4127.191046, - "LargeOffice" => 141.8507451, - "MediumOffice" => 23.71397275, - "MidriseApartment" => 175.5949563, - "Outpatient" => 29.83372212, - "PrimarySchool" => 116.811664, - "RetailStore" => 0.0, - "SecondarySchool" => 285.2339344, - "SmallHotel" => 262.8487714, - "SmallOffice" => 10.05557471, - "StripMall" => 0.0, - "Supermarket" => 18.7637822, - "Warehouse" => 0.0, - "FlatLoad" => 368.7653325 - ), - "Atlanta" => Dict( - "FastFoodRest" => 71.33170579, - "FullServiceRest" => 217.4332205, - "Hospital" => 615.3498557, - "LargeHotel" => 5622.340656, - "LargeOffice" => 192.7164525, - "MediumOffice" => 29.62182675, - "MidriseApartment" => 238.9315749, - "Outpatient" => 37.9759973, - "PrimarySchool" => 148.8362119, - "RetailStore" => 0.0, - "SecondarySchool" => 372.2083434, - "SmallHotel" => 337.2688069, - "SmallOffice" => 10.65138846, - "StripMall" => 0.0, - "Supermarket" => 21.71038069, - "Warehouse" => 0.0, - "FlatLoad" => 494.7735263 - ), - "LasVegas" => Dict( - "FastFoodRest" => 63.63848459, - "FullServiceRest" => 191.8494897, - "Hospital" => 540.9697668, - "LargeHotel" => 4800.331564, - "LargeOffice" => 164.7154124, - "MediumOffice" => 26.36796732, - "MidriseApartment" => 204.1120165, - "Outpatient" => 33.48190098, - "PrimarySchool" => 131.9651451, - "RetailStore" => 0.0, - "SecondarySchool" => 327.441087, - "SmallHotel" => 296.3578765, - "SmallOffice" => 10.32392915, - "StripMall" => 0.0, - "Supermarket" => 20.08676069, - "Warehouse" => 0.0, - "FlatLoad" => 425.7275876 - ), - "LosAngeles" => Dict( - "FastFoodRest" => 69.63212501, - "FullServiceRest" => 211.7827529, - "Hospital" => 598.9350422, - "LargeHotel" => 5440.174033, - "LargeOffice" => 186.6199083, - "MediumOffice" => 28.91483286, - "MidriseApartment" => 231.215325, - "Outpatient" => 37.00823296, - "PrimarySchool" => 142.8059487, - "RetailStore" => 0.0, - "SecondarySchool" => 352.7467563, - "SmallHotel" => 328.1935523, - "SmallOffice" => 10.58011717, - "StripMall" => 0.0, - "Supermarket" => 21.35337379, - "Warehouse" => 0.0, - "FlatLoad" => 478.7476251 - ), - "SanFrancisco" => Dict( - "FastFoodRest" => 77.13092952, - "FullServiceRest" => 236.7180594, - "Hospital" => 671.40531, - "LargeHotel" => 6241.842643, - "LargeOffice" => 213.8445094, - "MediumOffice" => 32.07909301, - "MidriseApartment" => 265.1697301, - "Outpatient" => 41.35500136, - "PrimarySchool" => 160.4507431, - "RetailStore" => 0.0, - "SecondarySchool" => 401.395655, - "SmallHotel" => 368.0979112, - "SmallOffice" => 10.90004379, - "StripMall" => 0.0, - "Supermarket" => 22.9292287, - "Warehouse" => 0.0, - "FlatLoad" => 546.4574286 - ), - "Baltimore" => Dict( - "FastFoodRest" => 78.2191761, - "FullServiceRest" => 240.338156, - "Hospital" => 681.9322322, - "LargeHotel" => 6358.710286, - "LargeOffice" => 217.7306132, - "MediumOffice" => 32.52815422, - "MidriseApartment" => 270.1195541, - "Outpatient" => 41.96148216, - "PrimarySchool" => 165.3116185, - "RetailStore" => 0.0, - "SecondarySchool" => 417.9512972, - "SmallHotel" => 373.906416, - "SmallOffice" => 10.94554028, - "StripMall" => 0.0, - "Supermarket" => 23.15795696, - "Warehouse" => 0.0, - "FlatLoad" => 557.0507802 - ), - "Albuquerque" => Dict( - "FastFoodRest" => 76.9149868, - "FullServiceRest" => 235.9992545, - "Hospital" => 669.3128607, - "LargeHotel" => 6219.08303, - "LargeOffice" => 212.9944774, - "MediumOffice" => 31.97726287, - "MidriseApartment" => 264.2063457, - "Outpatient" => 41.20639013, - "PrimarySchool" => 162.1556119, - "RetailStore" => 0.0, - "SecondarySchool" => 409.1649863, - "SmallHotel" => 366.9712928, - "SmallOffice" => 10.88949351, - "StripMall" => 0.0, - "Supermarket" => 22.88525618, - "Warehouse" => 0.0, - "FlatLoad" => 545.235078 - ), - "Seattle" => Dict( - "FastFoodRest" => 81.80231236, - "FullServiceRest" => 252.2609525, - "Hospital" => 716.6111323, - "LargeHotel" => 6741.736717, - "LargeOffice" => 230.8057849, - "MediumOffice" => 34.04746055, - "MidriseApartment" => 286.3412104, - "Outpatient" => 44.07342164, - "PrimarySchool" => 172.0233322, - "RetailStore" => 0.0, - "SecondarySchool" => 434.0806311, - "SmallHotel" => 392.968915, - "SmallOffice" => 11.09863592, - "StripMall" => 0.0, - "Supermarket" => 23.91178737, - "Warehouse" => 0.0, - "FlatLoad" => 588.8601433 - ), - "Chicago" => Dict( - "FastFoodRest" => 84.2645196, - "FullServiceRest" => 260.4454844, - "Hospital" => 740.4172516, - "LargeHotel" => 7005.083356, - "LargeOffice" => 239.7065959, - "MediumOffice" => 35.08184587, - "MidriseApartment" => 297.4938584, - "Outpatient" => 45.49600079, - "PrimarySchool" => 179.4639347, - "RetailStore" => 0.0, - "SecondarySchool" => 456.8817409, - "SmallHotel" => 406.0751832, - "SmallOffice" => 11.2033023, - "StripMall" => 0.0, - "Supermarket" => 24.4292392, - "Warehouse" => 0.0, - "FlatLoad" => 611.6276445 - ), - "Boulder" => Dict( - "FastFoodRest" => 83.95201542, - "FullServiceRest" => 259.3997752, - "Hospital" => 737.372005, - "LargeHotel" => 6971.32924, - "LargeOffice" => 238.572519, - "MediumOffice" => 34.9486709, - "MidriseApartment" => 296.06471, - "Outpatient" => 45.31437164, - "PrimarySchool" => 178.3378526, - "RetailStore" => 0.0, - "SecondarySchool" => 453.228537, - "SmallHotel" => 404.4154946, - "SmallOffice" => 11.18970855, - "StripMall" => 0.0, - "Supermarket" => 24.36505320, - "Warehouse" => 0.0, - "FlatLoad" => 608.6556221 - ), - "Minneapolis" => Dict( - "FastFoodRest" => 89.48929949, - "FullServiceRest" => 277.8184269, - "Hospital" => 790.9262388, - "LargeHotel" => 7563.607619, - "LargeOffice" => 258.6874644, - "MediumOffice" => 37.28641454, - "MidriseApartment" => 321.1473562, - "Outpatient" => 48.51884975, - "PrimarySchool" => 191.9480118, - "RetailStore" => 0.0, - "SecondarySchool" => 491.5554097, - "SmallHotel" => 433.8738637, - "SmallOffice" => 11.42620649, - "StripMall" => 0.0, - "Supermarket" => 25.53218144, - "Warehouse" => 0.0, - "FlatLoad" => 658.8635839 - ), - "Helena" => Dict( - "FastFoodRest" => 90.44011877, - "FullServiceRest" => 280.9757902, - "Hospital" => 800.0940058, - "LargeHotel" => 7665.023574, - "LargeOffice" => 262.1461576, - "MediumOffice" => 37.68905029, - "MidriseApartment" => 325.4421541, - "Outpatient" => 49.09222188, - "PrimarySchool" => 193.4573283, - "RetailStore" => 0.0, - "SecondarySchool" => 494.7393735, - "SmallHotel" => 438.9398731, - "SmallOffice" => 11.46564268, - "StripMall" => 0.0, - "Supermarket" => 25.72866824, - "Warehouse" => 0.0, - "FlatLoad" => 667.2021224 - ), - "Duluth" => Dict( - "FastFoodRest" => 98.10641517, - "FullServiceRest" => 306.4772907, - "Hospital" => 874.2611723, - "LargeHotel" => 8484.906093, - "LargeOffice" => 290.0193773, - "MediumOffice" => 40.92475821, - "MidriseApartment" => 360.161261, - "Outpatient" => 53.53681127, - "PrimarySchool" => 211.2386551, - "RetailStore" => 0.0, - "SecondarySchool" => 543.3733772, - "SmallHotel" => 479.7414481, - "SmallOffice" => 11.79316054, - "StripMall" => 0.0, - "Supermarket" => 27.3451629, - "Warehouse" => 0.0, - "FlatLoad" => 736.3678114 - ), - "Fairbanks" => Dict( - "FastFoodRest" => 108.5335945, - "FullServiceRest" => 341.1572799, - "Hospital" => 975.1062178, - "LargeHotel" => 9600.267161, - "LargeOffice" => 327.8820873, - "MediumOffice" => 45.32138512, - "MidriseApartment" => 407.3910855, - "Outpatient" => 59.6203514, - "PrimarySchool" => 234.2595741, - "RetailStore" => 0.0, - "SecondarySchool" => 604.6838786, - "SmallHotel" => 535.2525234, - "SmallOffice" => 12.23744003, - "StripMall" => 0.0, - "Supermarket" => 29.53958045, - "Warehouse" => 0.0, - "FlatLoad" => 830.07826 - ) - ) - if isempty(city) - city = find_ashrae_zone_city(latitude, longitude) - end - if !(buildingtype in default_buildings) - throw(@error("buildingtype $(buildingtype) not in $(default_buildings).")) - end - if isnothing(annual_mmbtu) - # Use FlatLoad annual_mmbtu from data for all types of FlatLoads because we don't have separate data for e.g. FlatLoad_16_7 - if occursin("FlatLoad", buildingtype) - annual_mmbtu = dhw_annual_mmbtu[city]["FlatLoad"] - else - annual_mmbtu = dhw_annual_mmbtu[city][buildingtype] - end - else - annual_mmbtu *= addressable_load_fraction - end - if length(monthly_mmbtu) == 12 - monthly_mmbtu = monthly_mmbtu .* addressable_load_fraction - end - built_in_load("domestic_hot_water", city, buildingtype, year, annual_mmbtu, monthly_mmbtu, - existing_boiler_efficiency) -end - - -function BuiltInSpaceHeatingLoad( - city::String, - buildingtype::String, - latitude::Real, - longitude::Real, - year::Int, - addressable_load_fraction::Union{<:Real, AbstractVector{<:Real}}, - annual_mmbtu::Union{Real, Nothing}=nothing, - monthly_mmbtu::Vector{<:Real}=Real[], - existing_boiler_efficiency::Union{Real, Nothing}=nothing - ) - spaceheating_annual_mmbtu = Dict( - "Miami" => Dict( - "FastFoodRest" => 5.426780867, - "FullServiceRest" => 12.03181471, - "Hospital" => 6248.413294, - "LargeHotel" => 198.0691407, - "LargeOffice" => 168.9731637, - "MediumOffice" => 0.036985655, - "MidriseApartment" => 38.70606161, - "Outpatient" => 2559.185872, - "PrimarySchool" => 49.78021153, - "RetailStore" => 12.12015432, - "SecondarySchool" => 203.5185485, - "SmallHotel" => 9.098564901, - "SmallOffice" => 0.312524873, - "StripMall" => 20.73216748, - "Supermarket" => 101.2785324, - "Warehouse" => 56.0796017, - "FlatLoad" => 605.2352137 - ), - "Houston" => Dict( - "FastFoodRest" => 85.49111065, - "FullServiceRest" => 199.7942842, - "Hospital" => 8732.10385, - "LargeHotel" => 1307.035548, - "LargeOffice" => 2229.971744, - "MediumOffice" => 16.25994314, - "MidriseApartment" => 386.0269973, - "Outpatient" => 2829.324307, - "PrimarySchool" => 469.2532935, - "RetailStore" => 289.0470815, - "SecondarySchool" => 2011.1678969999998, - "SmallHotel" => 108.9825885, - "SmallOffice" => 19.55157672, - "StripMall" => 292.23235389999996, - "Supermarket" => 984.7374347000001, - "Warehouse" => 475.9377273, - "FlatLoad" => 1277.307359 - ), - "Phoenix" => Dict( - "FastFoodRest" => 57.89972381, - "FullServiceRest" => 147.2569493, - "Hospital" => 9382.021026, - "LargeHotel" => 896.790817, - "LargeOffice" => 1584.061452, - "MediumOffice" => 1.922551528, - "MidriseApartment" => 290.9887152, - "Outpatient" => 3076.340876, - "PrimarySchool" => 305.573525, - "RetailStore" => 208.66330580000002, - "SecondarySchool" => 1400.638544, - "SmallHotel" => 83.98084516, - "SmallOffice" => 9.988210938, - "StripMall" => 230.16060699999997, - "Supermarket" => 972.3008295, - "Warehouse" => 362.42249280000004, - "FlatLoad" => 1188.188154 - ), - "Atlanta" => Dict( - "FastFoodRest" => 168.8402371, - "FullServiceRest" => 379.5865464, - "Hospital" => 10467.659959999999, - "LargeHotel" => 2427.6589879999997, - "LargeOffice" => 3624.593975, - "MediumOffice" => 49.00635733, - "MidriseApartment" => 718.9316697, - "Outpatient" => 3186.250588, - "PrimarySchool" => 931.7212450999999, - "RetailStore" => 627.2489826000001, - "SecondarySchool" => 3968.4936420000004, - "SmallHotel" => 202.26124219999997, - "SmallOffice" => 42.74797302, - "StripMall" => 615.2240506, - "Supermarket" => 1880.5304489999999, - "Warehouse" => 930.9449202, - "FlatLoad" => 1888.856302 - ), - "LasVegas" => Dict( - "FastFoodRest" => 100.0877773, - "FullServiceRest" => 247.21791319999997, - "Hospital" => 9100.302056, - "LargeHotel" => 1500.581408, - "LargeOffice" => 2479.152321, - "MediumOffice" => 5.220181581, - "MidriseApartment" => 487.43122850000003, - "Outpatient" => 2924.8220460000002, - "PrimarySchool" => 499.6562223, - "RetailStore" => 386.0185744, - "SecondarySchool" => 2277.7410649999997, - "SmallHotel" => 138.4427074, - "SmallOffice" => 19.16330622, - "StripMall" => 389.30494280000005, - "Supermarket" => 1479.302604, - "Warehouse" => 579.7671637999999, - "FlatLoad" => 1413.3882199999998 - ), - "LosAngeles" => Dict( - "FastFoodRest" => 40.90390152, - "FullServiceRest" => 97.94277036, - "Hospital" => 10346.1713, - "LargeHotel" => 707.848762, - "LargeOffice" => 1458.148818, - "MediumOffice" => 0.12342009699999999, - "MidriseApartment" => 265.2851759, - "Outpatient" => 3417.120585, - "PrimarySchool" => 318.73600980000003, - "RetailStore" => 175.104083, - "SecondarySchool" => 1198.276619, - "SmallHotel" => 72.42852638, - "SmallOffice" => 5.898878347, - "StripMall" => 193.18730269999998, - "Supermarket" => 1040.273464, - "Warehouse" => 323.96697819999997, - "FlatLoad" => 1228.8385369999999 - ), - "SanFrancisco" => Dict( - "FastFoodRest" => 127.22328700000001, - "FullServiceRest" => 362.48645889999995, - "Hospital" => 11570.9155, - "LargeHotel" => 1713.3629670000003, - "LargeOffice" => 2690.1191, - "MediumOffice" => 3.8159670660000002, - "MidriseApartment" => 648.4472797999999, - "Outpatient" => 3299.0539519999998, - "PrimarySchool" => 818.2159102, - "RetailStore" => 569.8081034, - "SecondarySchool" => 3414.148347, - "SmallHotel" => 189.0244446, - "SmallOffice" => 27.53039453, - "StripMall" => 526.2320428, - "Supermarket" => 2301.616069, - "Warehouse" => 675.6758453, - "FlatLoad" => 1808.604729 - ), - "Baltimore" => Dict( - "FastFoodRest" => 305.2671204, - "FullServiceRest" => 657.1337578, - "Hospital" => 11253.61694, - "LargeHotel" => 3731.0254619999996, - "LargeOffice" => 5109.311943, - "MediumOffice" => 116.8101842, - "MidriseApartment" => 1132.964052, - "Outpatient" => 3285.227941, - "PrimarySchool" => 1428.239177, - "RetailStore" => 1068.034778, - "SecondarySchool" => 6557.634924, - "SmallHotel" => 346.3683857, - "SmallOffice" => 63.29818348, - "StripMall" => 1075.39546, - "Supermarket" => 2929.182261, - "Warehouse" => 1568.722061, - "FlatLoad" => 2539.2645399999997 - ), - "Albuquerque" => Dict( - "FastFoodRest" => 199.73581399999998, - "FullServiceRest" => 398.5712205, - "Hospital" => 8371.240776999999, - "LargeHotel" => 2750.8382260000003, - "LargeOffice" => 3562.0023950000004, - "MediumOffice" => 47.49307973, - "MidriseApartment" => 805.0965778, - "Outpatient" => 2971.868562, - "PrimarySchool" => 981.4176700999999, - "RetailStore" => 755.4523907, - "SecondarySchool" => 4338.227865999999, - "SmallHotel" => 232.2194443, - "SmallOffice" => 43.25360481, - "StripMall" => 760.0982018, - "Supermarket" => 2302.228741, - "Warehouse" => 1151.250885, - "FlatLoad" => 1854.437216 - ), - "Seattle" => Dict( - "FastFoodRest" => 255.5992711, - "FullServiceRest" => 627.5634984000001, - "Hospital" => 11935.157290000001, - "LargeHotel" => 3343.683348, - "LargeOffice" => 5266.970348, - "MediumOffice" => 28.97979768, - "MidriseApartment" => 1117.5465470000001, - "Outpatient" => 3468.128914, - "PrimarySchool" => 1263.541878, - "RetailStore" => 952.2758742000001, - "SecondarySchool" => 6367.850187, - "SmallHotel" => 310.8087307, - "SmallOffice" => 49.34878545, - "StripMall" => 969.1074739000001, - "Supermarket" => 3004.1844929999997, - "Warehouse" => 1137.398514, - "FlatLoad" => 2506.1340600000003 - ), - "Chicago" => Dict( - "FastFoodRest" => 441.93439000000006, - "FullServiceRest" => 888.3312571, - "Hospital" => 12329.57943, - "LargeHotel" => 5104.848129, - "LargeOffice" => 7706.028917000001, - "MediumOffice" => 216.01411800000002, - "MidriseApartment" => 1482.040156, - "Outpatient" => 3506.5381090000005, - "PrimarySchool" => 2006.0002120000001, - "RetailStore" => 1472.8704380000001, - "SecondarySchool" => 8962.172873, - "SmallHotel" => 479.4653436000001, - "SmallOffice" => 94.19308949, - "StripMall" => 1497.556168, - "Supermarket" => 3696.2112950000005, - "Warehouse" => 2256.477231, - "FlatLoad" => 3258.766323 - ), - "Boulder" => Dict( - "FastFoodRest" => 306.8980525, - "FullServiceRest" => 642.8843574, - "Hospital" => 9169.381845, - "LargeHotel" => 3975.1080020000004, - "LargeOffice" => 5027.882454, - "MediumOffice" => 124.26913059999998, - "MidriseApartment" => 1098.944993, - "Outpatient" => 3087.969786, - "PrimarySchool" => 1356.396807, - "RetailStore" => 1086.9187570000001, - "SecondarySchool" => 6268.036872, - "SmallHotel" => 342.77800099999996, - "SmallOffice" => 65.95714912, - "StripMall" => 1093.093638, - "Supermarket" => 2966.790122, - "Warehouse" => 1704.8648210000001, - "FlatLoad" => 2394.8859239999997 - ), - "Minneapolis" => Dict( - "FastFoodRest" => 588.8854722, - "FullServiceRest" => 1121.229499, - "Hospital" => 13031.2313, - "LargeHotel" => 6359.946704, - "LargeOffice" => 10199.279129999999, - "MediumOffice" => 394.1525556, - "MidriseApartment" => 1814.148381, - "Outpatient" => 3661.1462229999997, - "PrimarySchool" => 2600.964302, - "RetailStore" => 1869.8106289999998, - "SecondarySchool" => 11963.323859999999, - "SmallHotel" => 618.0427338999999, - "SmallOffice" => 128.12525349999999, - "StripMall" => 1952.731917, - "Supermarket" => 4529.776664, - "Warehouse" => 3231.223746, - "FlatLoad" => 4004.001148 - ), - "Helena" => Dict( - "FastFoodRest" => 468.8276835, - "FullServiceRest" => 934.8994934, - "Hospital" => 10760.57411, - "LargeHotel" => 5554.910785, - "LargeOffice" => 7373.056709, - "MediumOffice" => 239.8330306, - "MidriseApartment" => 1531.102079, - "Outpatient" => 3390.42972, - "PrimarySchool" => 2097.777112, - "RetailStore" => 1494.85988, - "SecondarySchool" => 9535.484059, - "SmallHotel" => 499.85992930000003, - "SmallOffice" => 98.85818175, - "StripMall" => 1604.0043970000002, - "Supermarket" => 3948.5338049999996, - "Warehouse" => 2504.784991, - "FlatLoad" => 3252.362248 - ), - "Duluth" => Dict( - "FastFoodRest" => 738.1353594999999, - "FullServiceRest" => 1400.36692, - "Hospital" => 14179.84149, - "LargeHotel" => 7781.9012760000005, - "LargeOffice" => 12504.64187, - "MediumOffice" => 468.2112216, - "MidriseApartment" => 2204.85149, - "Outpatient" => 3774.3233130000003, - "PrimarySchool" => 3160.1200719999997, - "RetailStore" => 2298.8242920000002, - "SecondarySchool" => 14468.64346, - "SmallHotel" => 772.5386662000001, - "SmallOffice" => 155.8350887, - "StripMall" => 2411.847491, - "Supermarket" => 5587.977185, - "Warehouse" => 3962.122014, - "FlatLoad" => 4741.886326 - ), - "Fairbanks" => Dict( - "FastFoodRest" => 1245.3608279999999, - "FullServiceRest" => 2209.293209, - "Hospital" => 20759.042680000002, - "LargeHotel" => 12298.7791, - "LargeOffice" => 23214.51532, - "MediumOffice" => 949.8812392000001, - "MidriseApartment" => 3398.039504, - "Outpatient" => 4824.076322999999, - "PrimarySchool" => 6341.861225, - "RetailStore" => 3869.670979, - "SecondarySchool" => 25619.149269999998, - "SmallHotel" => 1264.41064, - "SmallOffice" => 297.08593010000004, - "StripMall" => 3934.89178, - "Supermarket" => 8515.422039000001, - "Warehouse" => 6882.6512680000005, - "FlatLoad" => 7851.508208 - ) - ) - if isempty(city) - city = find_ashrae_zone_city(latitude, longitude) - end - if !(buildingtype in default_buildings) - throw(@error("buildingtype $(buildingtype) not in $(default_buildings).")) +""" +function get_existing_chiller_default_cop(; existing_chiller_max_thermal_factor_on_peak_load=nothing, + max_load_kw=nothing, + max_load_kw_thermal=nothing) +This function returns the default value for ExistingChiller.cop based on: + 1. No information about load, returns average of lower and higher cop default values (`cop_unknown_thermal`) + 2. If the cooling electric `max_load_kw` is known, we first guess the thermal load profile using `cop_unknown_thermal`, + and then we use the default logic to determine the `existing_chiller_cop` based on the peak thermal load with a thermal factor multiplier. + 3. If the cooling thermal `max_load_kw_thermal` is known, same as 2. but we don't have to guess the cop to convert electric to thermal load first. +""" +function get_existing_chiller_default_cop(; existing_chiller_max_thermal_factor_on_peak_load=nothing, max_load_kw=nothing, max_load_kw_thermal=nothing) + cop_less_than_100_ton = 4.40 + cop_more_than_100_ton = 4.69 + cop_unknown_thermal = (cop_less_than_100_ton + cop_more_than_100_ton) / 2.0 + max_cooling_load_ton = nothing + if !isnothing(max_load_kw_thermal) + max_cooling_load_ton = max_load_kw_thermal / KWH_THERMAL_PER_TONHOUR + elseif !isnothing(max_load_kw) + max_cooling_load_ton = max_load_kw / KWH_THERMAL_PER_TONHOUR * cop_unknown_thermal end - if isnothing(annual_mmbtu) - # Use FlatLoad annual_mmbtu from data for all types of FlatLoads because we don't have separate data for e.g. FlatLoad_16_7 - if occursin("FlatLoad", buildingtype) - annual_mmbtu = spaceheating_annual_mmbtu[city]["FlatLoad"] - else - annual_mmbtu = spaceheating_annual_mmbtu[city][buildingtype] - end + if isnothing(max_cooling_load_ton) || isnothing(existing_chiller_max_thermal_factor_on_peak_load) + return cop_unknown_thermal + elseif max_cooling_load_ton * existing_chiller_max_thermal_factor_on_peak_load < 100.0 + return cop_less_than_100_ton else - annual_mmbtu *= addressable_load_fraction - end - if length(monthly_mmbtu) == 12 - monthly_mmbtu = monthly_mmbtu .* addressable_load_fraction + return cop_more_than_100_ton end - built_in_load("space_heating", city, buildingtype, year, annual_mmbtu, monthly_mmbtu, - existing_boiler_efficiency) end - function BuiltInCoolingLoad( city::String, buildingtype::String, @@ -1103,312 +450,9 @@ function BuiltInCoolingLoad( monthly_tonhour::Vector{<:Real}=Real[], existing_chiller_cop::Union{Real, Nothing}=nothing ) - cooling_annual_kwh = Dict( - "Albuquerque" => Dict( - "MidriseApartment" => 34088, - "FastFoodRest" => 8466, - "LargeOffice" => 442687, - "Outpatient" => 357615, - "PrimarySchool" => 99496, - "SmallHotel" => 109982, - "Supermarket" => 40883, - "SmallOffice" => 8266, - "StripMall" => 36498, - "MediumOffice" => 103240, - "LargeHotel" => 475348, - "Warehouse" => 5831, - "SecondarySchool" => 355818, - "Hospital" => 1382003, - "RetailStore" => 37955, - "FullServiceRest" => 25534, - "FlatLoad" => 220232.0 - ), - "Helena" => Dict( - "StripMall" => 13260, - "RetailStore" => 13952, - "Outpatient" => 233034, - "FullServiceRest" => 8420, - "SmallHotel" => 63978, - "MediumOffice" => 44528, - "Hospital" => 1075876, - "LargeHotel" => 318965, - "PrimarySchool" => 34468, - "Supermarket" => 14879, - "SmallOffice" => 3442, - "SecondarySchool" => 132887, - "FastFoodRest" => 2919, - "MidriseApartment" => 11101, - "LargeOffice" => 226066, - "Warehouse" => 1566, - "FlatLoad" => 137459.0 - ), - "LosAngeles" => Dict( - "MidriseApartment" => 22912, - "Hospital" => 1987427, - "Outpatient" => 435175, - "RetailStore" => 22663, - "SmallHotel" => 116966, - "StripMall" => 26514, - "FastFoodRest" => 3452, - "LargeHotel" => 526169, - "Supermarket" => 13630, - "SmallOffice" => 8351, - "Warehouse" => 673, - "PrimarySchool" => 126130, - "FullServiceRest" => 11456, - "SecondarySchool" => 351337, - "MediumOffice" => 121320, - "LargeOffice" => 707617, - "FlatLoad" => 280112.0 - ), - "Boulder" => Dict( - "Warehouse" => 3574, - "Hospital" => 1223116, - "PrimarySchool" => 57692, - "SmallOffice" => 5097, - "Supermarket" => 24684, - "LargeHotel" => 384065, - "LargeOffice" => 316540, - "MidriseApartment" => 18535, - "MediumOffice" => 68389, - "RetailStore" => 23580, - "FullServiceRest" => 14957, - "SecondarySchool" => 220472, - "Outpatient" => 291603, - "FastFoodRest" => 5270, - "StripMall" => 23350, - "SmallHotel" => 84804, - "FlatLoad" => 172858.0 - ), - "Chicago" => Dict( - "Hospital" => 1721142, - "SmallHotel" => 97554, - "SecondarySchool" => 336986, - "SmallOffice" => 6365, - "Supermarket" => 30785, - "StripMall" => 32544, - "FastFoodRest" => 6320, - "Outpatient" => 328675, - "LargeOffice" => 533117, - "MidriseApartment" => 25663, - "RetailStore" => 31774, - "LargeHotel" => 469484, - "MediumOffice" => 85839, - "Warehouse" => 4370, - "PrimarySchool" => 82619, - "FullServiceRest" => 17222, - "FlatLoad" => 238154.0 - ), - "Houston" => Dict( - "PrimarySchool" => 282346, - "LargeHotel" => 1095441, - "Hospital" => 2942336, - "RetailStore" => 115410, - "StripMall" => 111025, - "FastFoodRest" => 24525, - "LargeOffice" => 1471054, - "Warehouse" => 17665, - "MidriseApartment" => 97156, - "SecondarySchool" => 1151985, - "Outpatient" => 630778, - "FullServiceRest" => 63610, - "Supermarket" => 125580, - "SmallOffice" => 19375, - "SmallHotel" => 220470, - "MediumOffice" => 239477, - "FlatLoad" => 538015.0 - ), - "Phoenix" => Dict( - "SecondarySchool" => 1204514, - "StripMall" => 122803, - "PrimarySchool" => 302372, - "LargeOffice" => 1124585, - "SmallOffice" => 23720, - "Supermarket" => 145706, - "Outpatient" => 640137, - "SmallHotel" => 233842, - "MediumOffice" => 271151, - "Hospital" => 2288973, - "FullServiceRest" => 69402, - "LargeHotel" => 1024137, - "MidriseApartment" => 135120, - "RetailStore" => 123508, - "Warehouse" => 38561, - "FastFoodRest" => 29956, - "FlatLoad" => 486155.0 - ), - "Fairbanks" => Dict( - "Warehouse" => 97, - "LargeOffice" => 147867, - "Hospital" => 753420, - "MidriseApartment" => 5035, - "MediumOffice" => 24183, - "LargeHotel" => 234082, - "FullServiceRest" => 2025, - "SmallOffice" => 1877, - "Supermarket" => 2500, - "PrimarySchool" => 15166, - "RetailStore" => 3289, - "SecondarySchool" => 53222, - "Outpatient" => 143322, - "FastFoodRest" => 656, - "StripMall" => 3592, - "SmallHotel" => 48066, - "FlatLoad" => 89900.0 - ), - "Seattle" => Dict( - "StripMall" => 7664, - "SmallHotel" => 60651, - "SmallOffice" => 2503, - "Supermarket" => 4882, - "Outpatient" => 266075, - "SecondarySchool" => 89468, - "MediumOffice" => 38713, - "MidriseApartment" => 6380, - "LargeOffice" => 249231, - "FullServiceRest" => 4144, - "PrimarySchool" => 28984, - "Hospital" => 1432385, - "RetailStore" => 6223, - "LargeHotel" => 292028, - "FastFoodRest" => 1245, - "Warehouse" => 329, - "FlatLoad" => 155682.0 - ), - "Duluth" => Dict( - "Hospital" => 1149799, - "StripMall" => 8809, - "MediumOffice" => 37547, - "RetailStore" => 8489, - "LargeHotel" => 300364, - "SecondarySchool" => 99148, - "PrimarySchool" => 25136, - "LargeOffice" => 249416, - "MidriseApartment" => 8181, - "FullServiceRest" => 4919, - "Warehouse" => 889, - "SmallHotel" => 61101, - "FastFoodRest" => 1709, - "Supermarket" => 9788, - "SmallOffice" => 2563, - "Outpatient" => 198121, - "FlatLoad" => 135374.0 - ), - "Minneapolis" => Dict( - "Warehouse" => 2923, - "SmallHotel" => 91962, - "LargeOffice" => 475102, - "Outpatient" => 289706, - "Hospital" => 1516644, - "SmallOffice" => 5452, - "Supermarket" => 25962, - "MediumOffice" => 74813, - "PrimarySchool" => 62017, - "FullServiceRest" => 14996, - "LargeHotel" => 445049, - "SecondarySchool" => 262353, - "FastFoodRest" => 5429, - "MidriseApartment" => 22491, - "RetailStore" => 26859, - "StripMall" => 26489, - "FlatLoad" => 209265.0 - ), - "Baltimore" => Dict( - "SmallHotel" => 119859, - "Outpatient" => 406989, - "RetailStore" => 44703, - "FullServiceRest" => 25140, - "SecondarySchool" => 469545, - "PrimarySchool" => 114110, - "StripMall" => 43896, - "MediumOffice" => 124064, - "MidriseApartment" => 36890, - "LargeOffice" => 822177, - "Warehouse" => 7156, - "LargeHotel" => 594327, - "Hospital" => 2085465, - "Supermarket" => 48913, - "SmallOffice" => 8083, - "FastFoodRest" => 9287, - "FlatLoad" => 310038.0 - ), - "LasVegas" => Dict( - "RetailStore" => 89484, - "LargeHotel" => 798740, - "MediumOffice" => 207085, - "StripMall" => 84138, - "PrimarySchool" => 218688, - "Warehouse" => 28928, - "SmallOffice" => 16824, - "Supermarket" => 114543, - "MidriseApartment" => 92778, - "FullServiceRest" => 53259, - "Outpatient" => 513377, - "FastFoodRest" => 22811, - "SmallHotel" => 175011, - "LargeOffice" => 792463, - "SecondarySchool" => 858081, - "Hospital" => 1831966, - "FlatLoad" => 368636.0 - ), - "Atlanta" => Dict( - "LargeOffice" => 968973, - "LargeHotel" => 704148, - "Supermarket" => 69686, - "StripMall" => 62530, - "SmallOffice" => 11259, - "MediumOffice" => 155865, - "Hospital" => 2328054, - "FullServiceRest" => 33832, - "SmallHotel" => 149237, - "SecondarySchool" => 608831, - "Warehouse" => 8214, - "Outpatient" => 489234, - "FlatLoad" => 367407.0, - "FastFoodRest" => 12565, - "PrimarySchool" => 160138, - "MidriseApartment" => 50907, - "RetailStore" => 65044 - ), - "SanFrancisco" => Dict( - "SecondarySchool" => 121914, - "LargeOffice" => 297494, - "StripMall" => 6626, - "Supermarket" => 3252, - "SmallOffice" => 2539, - "Hospital" => 1427329, - "PrimarySchool" => 48323, - "LargeHotel" => 296230, - "MediumOffice" => 43956, - "MidriseApartment" => 4484, - "FullServiceRest" => 3062, - "Warehouse" => 365, - "FlatLoad" => 164036.0, - "SmallHotel" => 71414, - "RetailStore" => 4515, - "FastFoodRest" => 838, - "Outpatient" => 292238 - ), - "Miami" => Dict( - "LargeHotel" => 1467216, - "SmallOffice" => 28235, - "FastFoodRest" => 36779, - "FlatLoad" => 700779.0, - "Supermarket" => 150368, - "FullServiceRest" => 101567, - "PrimarySchool" => 434031, - "Warehouse" => 20108, - "LargeOffice" => 1878642, - "SmallHotel" => 318595, - "MidriseApartment" => 176446, - "RetailStore" => 163290, - "Outpatient" => 811571, - "Hospital" => 3371923, - "StripMall" => 180645, - "SecondarySchool" => 1735906, - "MediumOffice" => 337147 - ) - ) + + cooling_electric_annual_kwh = JSON.parsefile(joinpath(@__DIR__, "..", "..", "data", "load_profiles", "cooling_electric_annual_kwh.json")) + if isempty(city) city = find_ashrae_zone_city(latitude, longitude) end @@ -1422,9 +466,9 @@ function BuiltInCoolingLoad( if isnothing(annual_tonhour) # Use FlatLoad annual_kwh from data for all types of FlatLoads because we don't have separate data for e.g. FlatLoad_16_7 if occursin("FlatLoad", buildingtype) - annual_kwh = cooling_annual_kwh[city]["FlatLoad"] + annual_kwh = cooling_electric_annual_kwh[city]["FlatLoad"] else - annual_kwh = cooling_annual_kwh[city][buildingtype] + annual_kwh = cooling_electric_annual_kwh[city][buildingtype] end else annual_kwh = annual_tonhour * KWH_THERMAL_PER_TONHOUR / existing_chiller_cop @@ -1434,184 +478,4 @@ function BuiltInCoolingLoad( monthly_kwh = monthly_tonhour * KWH_THERMAL_PER_TONHOUR / existing_chiller_cop end built_in_load("cooling", city, buildingtype, year, annual_kwh, monthly_kwh) -end -""" -`ProcessHeatLoad` is an optional REopt input with the following keys and default values: -```julia - industry_reference_name::String = "", - sector::String = "", - blended_industry_reference_names::Array{String, 1} = String[], - blended_industry_reference_percents::Array{<:Real, 1} = Real[], - annual_mmbtu::Union{Real, Nothing} = nothing, - monthly_mmbtu::Array{<:Real,1} = Real[], - addressable_load_fraction::Any = 1.0, - fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], - time_steps_per_hour::Int = 1, # corresponding to `fuel_loads_mmbtu_per_hour` - latitude::Real = 0.0, - longitude::Real = 0.0, - existing_boiler_efficiency::Real = NaN -``` - -There are many ways in which a ProcessHeatLoad can be defined: -1. When using either `industry_reference_name` or `blended_industry_reference_names` -2. One can provide the `industry_reference_name` or `blended_industry_reference_names` directly in the `ProcessHeatLoad` key within the `Scenario`. These values can be combined with the `annual_mmbtu` or `monthly_mmbtu` inputs to scale the industry reference profile(s). -3. One can provide the `fuel_loads_mmbtu_per_hour` value in the `ProcessHeatLoad` key within the `Scenario`. - -!!! note "Process heat loads" - Process heat "load" inputs are in terms of fuel energy input required (boiler fuel), not the actual thermal demand. - The fuel energy is multiplied by the existing_boiler_efficiency to get the actual energy demand. - -""" -function BuiltInProcessHeatLoad( - sector::String, - process_type::String, - latitude::Real, - longitude::Real, - year::Int, - addressable_load_fraction::Union{<:Real, AbstractVector{<:Real}}, - annual_mmbtu::Union{Real, Nothing}=nothing, - monthly_mmbtu::Vector{<:Real}=Real[], - existing_boiler_efficiency::Union{Real, Nothing}=nothing - ) - # Override the city with 'Industrial' - sector = "Industrial" - city = sector - buildingtype = process_type - - process_heat_annual_mmbtu = Dict( - "Industrial" => Dict( - "Chemical" => 15000.0, # mid-sized chemical processes - "FlatLoad" => 10000, # continuous operations throughout the year - "Warehouse" => 7000 - ) - ) - if isempty(city) - city = "Industrial" - end - if !(process_type in default_process_types) - throw(@error("process_type $(process_type) is not recognized for process heating.")) - end - if isnothing(annual_mmbtu) - # Use FlatLoad annual_mmbtu from data for all types of FlatLoads because we don't have separate data for e.g. FlatLoad_16_7 - if occursin("FlatLoad", buildingtype) - annual_mmbtu = process_heat_annual_mmbtu[city]["FlatLoad"] - else - annual_mmbtu = process_heat_annual_mmbtu[city][buildingtype] - end - else - annual_mmbtu *= addressable_load_fraction - end - if length(monthly_mmbtu) == 12 - monthly_mmbtu = monthly_mmbtu .* addressable_load_fraction - monthly_mmbtu = Real[monthly_mmbtu...] - end - - built_in_load("process_heat", city, buildingtype, year, annual_mmbtu, monthly_mmbtu, existing_boiler_efficiency) -end - -struct ProcessHeatLoad - loads_kw::Array{Real, 1} - annual_mmbtu::Real - unaddressable_annual_fuel_mmbtu::Real - - function ProcessHeatLoad(; - industry_reference_name::String = "", - sector::String = "", - blended_industry_reference_names::Array{String, 1} = String[], - blended_industry_reference_percents::Array{<:Real, 1} = Real[], - annual_mmbtu::Union{Real, Nothing} = nothing, - monthly_mmbtu::Array{<:Real,1} = Real[], - addressable_load_fraction::Any = 1.0, - fuel_loads_mmbtu_per_hour::Array{<:Real,1} = Real[], - time_steps_per_hour::Int = 1, # corresponding to `fuel_loads_mmbtu_per_hour` - latitude::Real = 0.0, - longitude::Real = 0.0, - existing_boiler_efficiency::Real = NaN - ) - - sector = "Industrial" - doe_reference_name = industry_reference_name - city = sector - blended_doe_reference_names = blended_industry_reference_names - blended_doe_reference_percents = blended_industry_reference_percents - - - if length(addressable_load_fraction) > 1 - if !isempty(fuel_loads_mmbtu_per_hour) && length(addressable_load_fraction) != length(fuel_loads_mmbtu_per_hour) - throw(@error("`addressable_load_fraction` must be a scalar or an array of length `fuel_loads_mmbtu_per_hour`")) - end - if !isempty(monthly_mmbtu) && length(addressable_load_fraction) != 12 - throw(@error("`addressable_load_fraction` must be a scalar or an array of length 12 if `monthly_mmbtu` is input")) - end - addressable_load_fraction = convert(Vector{Real}, addressable_load_fraction) - elseif typeof(addressable_load_fraction) <: Vector{} - addressable_load_fraction = convert(Real, addressable_load_fraction[1]) - else - addressable_load_fraction = convert(Real, addressable_load_fraction) - end - - if length(fuel_loads_mmbtu_per_hour) > 0 - - if !(length(fuel_loads_mmbtu_per_hour) / time_steps_per_hour ≈ 8760) - throw(@error("Provided process heat load does not match the time_steps_per_hour.")) - end - - loads_kw = fuel_loads_mmbtu_per_hour .* (KWH_PER_MMBTU * existing_boiler_efficiency) .* addressable_load_fraction - unaddressable_annual_fuel_mmbtu = sum(fuel_loads_mmbtu_per_hour .* (1 .- addressable_load_fraction)) / time_steps_per_hour - - if !isempty(doe_reference_name) || length(blended_doe_reference_names) > 0 - @warn "ProcessHeatLoad fuel_loads_mmbtu_per_hour was provided, so doe_reference_name and/or blended_doe_reference_names will be ignored." - end - - elseif !isempty(doe_reference_name) - loads_kw = BuiltInProcessHeatLoad(city, doe_reference_name, latitude, longitude, 2017, addressable_load_fraction, annual_mmbtu, monthly_mmbtu, existing_boiler_efficiency) - if length(blended_doe_reference_names) > 0 - @warn "ProcessHeatLoad doe_reference_name was provided, so blended_doe_reference_names will be ignored." - end - unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) - elseif length(blended_doe_reference_names) > 0 && - length(blended_doe_reference_names) == length(blended_doe_reference_percents) - loads_kw = blend_and_scale_doe_profiles(BuiltInProcessHeatLoad, latitude, longitude, 2017, - blended_doe_reference_names, blended_doe_reference_percents, city, - annual_mmbtu, monthly_mmbtu, addressable_load_fraction, - existing_boiler_efficiency) - - unaddressable_annual_fuel_mmbtu = get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) - else - throw(@error("Cannot construct BuiltInProcessHeatLoad. You must provide either [fuel_loads_mmbtu_per_hour], - [industry_reference_name, city], or [blended_industry_reference_names, blended_industry_reference_percents, city].")) - end - - if length(loads_kw) < 8760*time_steps_per_hour - loads_kw = repeat(loads_kw, inner=Int(time_steps_per_hour / (length(loads_kw)/8760))) - @warn "Repeating space heating loads in each hour to match the time_steps_per_hour." - end - - new( - loads_kw, - (sum(loads_kw)/time_steps_per_hour)/KWH_PER_MMBTU, - unaddressable_annual_fuel_mmbtu - - ) - end -end - -""" - get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) - -Get unaddressable fuel load, for reporting - :addressable_load_fraction is the fraction of the input fuel load that is addressable to supply by energy technologies, like CHP - :annual_mmbtu and :monthly_mmbtu is assumed to be fuel, not thermal, in this function - :loads_kw is assumed to be thermal in this function, with units of kw_thermal, so needs to be converted to fuel mmbtu -""" -function get_unaddressable_fuel(addressable_load_fraction, annual_mmbtu, monthly_mmbtu, loads_kw, existing_boiler_efficiency) - # Get unaddressable fuel load, for reporting - if !isempty(monthly_mmbtu) - unaddressable_annual_fuel_mmbtu = sum(monthly_mmbtu .* (1 .- addressable_load_fraction)) - elseif !isnothing(annual_mmbtu) - unaddressable_annual_fuel_mmbtu = annual_mmbtu * (1 - addressable_load_fraction) - else # using the default CRB annual_mmbtu, so rely on loads_kw (thermal) assuming single addressable_load_fraction - unaddressable_annual_fuel_mmbtu = sum(loads_kw) / (KWH_PER_MMBTU * existing_boiler_efficiency) - end - return unaddressable_annual_fuel_mmbtu end \ No newline at end of file diff --git a/src/core/scenario.jl b/src/core/scenario.jl index 621781f53..762834060 100644 --- a/src/core/scenario.jl +++ b/src/core/scenario.jl @@ -221,14 +221,18 @@ function Scenario(d::Dict; flex_hvac_from_json=false) if haskey(d, "DomesticHotWaterLoad") && !haskey(d, "FlexibleHVAC") add_doe_reference_names_from_elec_to_thermal_loads(d["ElectricLoad"], d["DomesticHotWaterLoad"]) existing_boiler_efficiency = get_existing_boiler_efficiency(d) - dhw_load = DomesticHotWaterLoad(; dictkeys_tosymbols(d["DomesticHotWaterLoad"])..., + year = get(d["DomesticHotWaterLoad"], "year", electric_load.year) + dhw_load = HeatingLoad(; dictkeys_tosymbols(d["DomesticHotWaterLoad"])..., + load_type = "domestic_hot_water", latitude=site.latitude, longitude=site.longitude, time_steps_per_hour=settings.time_steps_per_hour, - existing_boiler_efficiency = existing_boiler_efficiency + existing_boiler_efficiency = existing_boiler_efficiency, + year = year ) max_heat_demand_kw = maximum(dhw_load.loads_kw) else - dhw_load = DomesticHotWaterLoad(; + dhw_load = HeatingLoad(; + load_type = "domestic_hot_water", fuel_loads_mmbtu_per_hour=zeros(8760*settings.time_steps_per_hour), time_steps_per_hour=settings.time_steps_per_hour, existing_boiler_efficiency = EXISTING_BOILER_EFFICIENCY @@ -238,14 +242,18 @@ function Scenario(d::Dict; flex_hvac_from_json=false) if haskey(d, "SpaceHeatingLoad") && !haskey(d, "FlexibleHVAC") add_doe_reference_names_from_elec_to_thermal_loads(d["ElectricLoad"], d["SpaceHeatingLoad"]) existing_boiler_efficiency = get_existing_boiler_efficiency(d) - space_heating_load = SpaceHeatingLoad(; dictkeys_tosymbols(d["SpaceHeatingLoad"])..., + year = get(d["SpaceHeatingLoad"], "year", electric_load.year) + space_heating_load = HeatingLoad(; dictkeys_tosymbols(d["SpaceHeatingLoad"])..., + load_type = "space_heating", latitude=site.latitude, longitude=site.longitude, time_steps_per_hour=settings.time_steps_per_hour, - existing_boiler_efficiency = existing_boiler_efficiency + existing_boiler_efficiency = existing_boiler_efficiency, + year = year ) max_heat_demand_kw = maximum(space_heating_load.loads_kw .+ max_heat_demand_kw) else - space_heating_load = SpaceHeatingLoad(; + space_heating_load = HeatingLoad(; + load_type = "space_heating", fuel_loads_mmbtu_per_hour=zeros(8760*settings.time_steps_per_hour), time_steps_per_hour=settings.time_steps_per_hour, existing_boiler_efficiency = EXISTING_BOILER_EFFICIENCY @@ -254,15 +262,19 @@ function Scenario(d::Dict; flex_hvac_from_json=false) if haskey(d, "ProcessHeatLoad") && !haskey(d, "FlexibleHVAC") existing_boiler_efficiency = get_existing_boiler_efficiency(d) - process_heat_load = ProcessHeatLoad(; dictkeys_tosymbols(d["ProcessHeatLoad"])..., - latitude=site.latitude, longitude=site.longitude, - time_steps_per_hour=settings.time_steps_per_hour, - existing_boiler_efficiency = existing_boiler_efficiency + year = get(d["ProcessHeatLoad"], "year", electric_load.year) + process_heat_load = HeatingLoad(; dictkeys_tosymbols(d["ProcessHeatLoad"])..., + load_type = "process_heat", + latitude = site.latitude, longitude = site.longitude, + time_steps_per_hour = settings.time_steps_per_hour, + existing_boiler_efficiency = existing_boiler_efficiency, + year = year ) max_heat_demand_kw = maximum(process_heat_load.loads_kw .+ max_heat_demand_kw) else - process_heat_load = ProcessHeatLoad(; + process_heat_load = HeatingLoad(; + load_type = "process_heat", fuel_loads_mmbtu_per_hour=zeros(8760*settings.time_steps_per_hour), time_steps_per_hour=settings.time_steps_per_hour, existing_boiler_efficiency = EXISTING_BOILER_EFFICIENCY diff --git a/src/core/simulated_load.jl b/src/core/simulated_load.jl index c9b060075..3087b584b 100644 --- a/src/core/simulated_load.jl +++ b/src/core/simulated_load.jl @@ -14,23 +14,44 @@ One particular aspect of this function specifically for the webtool/UI is the he """ function simulated_load(d::Dict) - latitude = get(d, "latitude", nothing) - longitude = get(d, "longitude", nothing) - if isnothing(latitude) || isnothing(longitude) + # Latitude and longitude are required if not normalizing and scaling load profile input + normalize_and_scale_load_profile_input = get(d, "normalize_and_scale_load_profile_input", false) + latitude = get(d, "latitude", 0.0) + longitude = get(d, "longitude", 0.0) + if (isnothing(latitude) || isnothing(longitude)) && !normalize_and_scale_load_profile_input throw(@error("latitude and longitude must be provided")) + elseif !normalize_and_scale_load_profile_input + if latitude > 90 || latitude < -90 + throw(@error("latitude $latitude is out of acceptable range (-90 <= latitude <= 90)")) + end + if longitude > 180 || longitude < -180 + throw(@error("longitude $longitude is out of acceptable range (-180 <= longitude <= 180)")) + end + end + + # Load type validation + load_type = get(d, "load_type", "electric") + if !(load_type in ["electric", "heating", "cooling", "space_heating", "domestic_hot_water", "process_heat"]) + throw(@error("load_type parameter must be one of the following: 'electric', 'heating', 'cooling', 'space_heating', 'domestic_hot_water', 'process_heat'. If load_type is not specified, 'electric' is assumed.")) end - load_type = get(d, "load_type", nothing) - # Check consistency between type/length of doe_reference_name and percent_share (for blended/hybrid buildings) + # Check for valid reference building name doe_reference_name_input = get(d, "doe_reference_name", nothing) percent_share_input = get(d, "percent_share", Real[]) - - # Determine which set of valid names to use based on the origin of the input valid_names = default_buildings if load_type == "process_heat" valid_names = default_process_types end + + # Input which then expects a custom load_profile along with annual or monthly energy values; this could be electric, heating, or cooling profiles + load_profile = get(d, "load_profile", Real[]) + if normalize_and_scale_load_profile_input + if isempty(load_profile) + throw(@error("The load_profile must be provided to normalize_and_scale_load_profile_input")) + end + end + # Validate consistency between reference name and optionally the percent_share for blended building types if !isnothing(doe_reference_name_input) && !(typeof(doe_reference_name_input) <: Vector{}) doe_reference_name = [doe_reference_name_input] elseif !isnothing(doe_reference_name_input) && !isempty(percent_share_input) @@ -80,27 +101,11 @@ function simulated_load(d::Dict) if !isnothing(doe_reference_name) for drn in doe_reference_name if !(drn in valid_names) - throw(@error("Invalid doe_reference_name - $doe_reference_name. Select from the following: $default_buildings")) + throw(@error("Invalid doe_reference_name - $drn. Select from the following: $valid_names")) end end end - if isnothing(load_type) - load_type = "electric" - end - - if latitude > 90 || latitude < -90 - throw(@error("latitude $latitude is out of acceptable range (-90 <= latitude <= 90)")) - end - - if longitude > 180 || longitude < -180 - throw(@error("longitude $longitude is out of acceptable range (-180 <= longitude <= 180)")) - end - - if !(load_type in ["electric","heating","cooling","space_heating","dhw","process_heat"]) - throw(@error("load_type parameter must be one of the following: 'electric', 'heating', or 'cooling'. If load_type is not specified, 'electric' is assumed.")) - end - # The following is possibly used in both load_type == "electric" and "cooling", so have to bring it out of those if-statements chiller_cop = get(d, "chiller_cop", nothing) @@ -116,7 +121,7 @@ function simulated_load(d::Dict) throw(@error("Invalid key $key for load_type=electric")) end end - if isnothing(doe_reference_name) + if isnothing(doe_reference_name) && !normalize_and_scale_load_profile_input throw(@error("Please supply a doe_reference_name and optionally scaling parameters (annual_kwh or monthly_totals_kwh).")) end # Annual loads (default is nothing) @@ -140,11 +145,16 @@ function simulated_load(d::Dict) # Build dependent inputs for electric load elec_load_inputs = Dict{Symbol, Any}() - if typeof(doe_reference_name) <: Vector{} && length(doe_reference_name) > 1 - elec_load_inputs[:blended_doe_reference_names] = doe_reference_name - elec_load_inputs[:blended_doe_reference_percents] = percent_share_list + if !normalize_and_scale_load_profile_input + if typeof(doe_reference_name) <: Vector{} && length(doe_reference_name) > 1 + elec_load_inputs[:blended_doe_reference_names] = doe_reference_name + elec_load_inputs[:blended_doe_reference_percents] = percent_share_list + else + elec_load_inputs[:doe_reference_name] = doe_reference_name[1] + end else - elec_load_inputs[:doe_reference_name] = doe_reference_name[1] + elec_load_inputs[:normalize_and_scale_load_profile_input] = normalize_and_scale_load_profile_input + elec_load_inputs[:loads_kw] = load_profile end electric_load = ElectricLoad(; elec_load_inputs..., @@ -221,8 +231,10 @@ function simulated_load(d::Dict) if !isempty(error_list) throw(@error("Invalid key(s) $error_list for load_type=heating")) end - if isnothing(doe_reference_name) + if isnothing(doe_reference_name) && !normalize_and_scale_load_profile_input throw(@error("Please supply a doe_reference_name and optional scaling parameters (annual_mmbtu or monthly_mmbtu).")) + elseif normalize_and_scale_load_profile_input + throw(@error("For normalizing and scaling a heating load profile, use one of load_type=['space_heating', 'domestic_hot_water', 'process_heat']")) end # Annual loads (default is nothing) annual_mmbtu = get(d, "annual_mmbtu", nothing) @@ -261,6 +273,7 @@ function simulated_load(d::Dict) throw(@error("addressable_load_fraction must be between 0.0 and 1.0")) end + # Build dependent inputs for heating load heating_load_inputs = Dict{Symbol, Any}() if length(doe_reference_name) > 1 heating_load_inputs[:blended_doe_reference_names] = doe_reference_name @@ -275,12 +288,14 @@ function simulated_load(d::Dict) # Split up the single heating fuel input for space + dhw annual_mmbtu or monthly_mmbtu into CRB profile split boiler_efficiency = get(d, "boiler_efficiency", EXISTING_BOILER_EFFICIENCY) - default_space_heating_load = SpaceHeatingLoad(; heating_load_inputs..., + default_space_heating_load = HeatingLoad(; heating_load_inputs..., + load_type="space_heating", latitude=latitude, longitude=longitude, existing_boiler_efficiency=boiler_efficiency ) - default_dhw_load = DomesticHotWaterLoad(; heating_load_inputs..., + default_dhw_load = HeatingLoad(; heating_load_inputs..., + load_type="domestic_hot_water", latitude=latitude, longitude=longitude, existing_boiler_efficiency=boiler_efficiency @@ -320,14 +335,16 @@ function simulated_load(d::Dict) dhw_annual_mmbtu = annual_mmbtu * dhw_fraction end - space_heating_load = SpaceHeatingLoad(; heating_load_inputs..., + space_heating_load = HeatingLoad(; heating_load_inputs..., + load_type="space_heating", latitude=latitude, longitude=longitude, annual_mmbtu=space_heating_annual_mmbtu, monthly_mmbtu=space_heating_monthly_mmbtu, existing_boiler_efficiency=boiler_efficiency ) - dhw_load = DomesticHotWaterLoad(; heating_load_inputs..., + dhw_load = HeatingLoad(; heating_load_inputs..., + load_type="domestic_hot_water", latitude=latitude, longitude=longitude, annual_mmbtu=dhw_annual_mmbtu, @@ -364,7 +381,7 @@ function simulated_load(d::Dict) return response end - if load_type in ["space_heating", "dhw", "process_heat"] + if load_type in ["space_heating", "domestic_hot_water", "process_heat"] error_list = [] for key in keys(d) if occursin("_kw", key) || occursin("_ton", key) @@ -372,9 +389,9 @@ function simulated_load(d::Dict) end end if !isempty(error_list) - throw(@error("Invalid key(s) $error_list for load_type=[space_heating, dhw, or process_heat")) + throw(@error("Invalid key(s) $error_list for load_type=[space_heating, domestic_hot_water, or process_heat")) end - if isnothing(doe_reference_name) + if isnothing(doe_reference_name) && !normalize_and_scale_load_profile_input throw(@error("Please supply a doe_reference_name and optional scaling parameters (annual_mmbtu or monthly_mmbtu).")) end # Annual loads (default is nothing) @@ -416,35 +433,35 @@ function simulated_load(d::Dict) boiler_efficiency = get(d, "boiler_efficiency", EXISTING_BOILER_EFFICIENCY) + # Build dependent inputs for Heating load heating_load_inputs = Dict{Symbol, Any}() - if load_type == "process_heat" - if length(doe_reference_name) > 1 - heating_load_inputs[:blended_industry_reference_names] = doe_reference_name - heating_load_inputs[:blended_industry_reference_percents] = percent_share_list + if !normalize_and_scale_load_profile_input + if load_type == "process_heat" + if length(doe_reference_name) > 1 + heating_load_inputs[:blended_industrial_reference_names] = doe_reference_name + heating_load_inputs[:blended_industrial_reference_percents] = percent_share_list + else + heating_load_inputs[:industrial_reference_name] = doe_reference_name[1] + end else - heating_load_inputs[:industry_reference_name] = doe_reference_name[1] + if length(doe_reference_name) > 1 + heating_load_inputs[:blended_doe_reference_names] = doe_reference_name + heating_load_inputs[:blended_doe_reference_percents] = percent_share_list + else + heating_load_inputs[:doe_reference_name] = doe_reference_name[1] + end end else - if length(doe_reference_name) > 1 - heating_load_inputs[:blended_doe_reference_names] = doe_reference_name - heating_load_inputs[:blended_doe_reference_percents] = percent_share_list - else - heating_load_inputs[:doe_reference_name] = doe_reference_name[1] - end + heating_load_inputs[:normalize_and_scale_load_profile_input] = normalize_and_scale_load_profile_input + heating_load_inputs[:fuel_loads_mmbtu_per_hour] = load_profile end + if addressable_load_fraction != 1.0 heating_load_inputs[:addressable_load_fraction] = addressable_load_fraction end - - if load_type == "space_heating" - constructor = SpaceHeatingLoad - elseif load_type == "dhw" - constructor = DomesticHotWaterLoad - elseif load_type == "process_heat" - constructor = ProcessHeatLoad - end - heating_load = constructor(; heating_load_inputs..., + heating_load = HeatingLoad(; heating_load_inputs..., + load_type = load_type, latitude=latitude, longitude=longitude, annual_mmbtu=annual_mmbtu, @@ -456,6 +473,7 @@ function simulated_load(d::Dict) heating_monthly_energy = get_monthly_energy(load_series) response = Dict([ + ("load_type", load_type), ("loads_mmbtu_per_hour", round.(load_series, digits=3)), ("annual_mmbtu", round(sum(load_series), digits=3)), ("monthly_mmbtu", round.(heating_monthly_energy, digits=3)), diff --git a/src/core/utils.jl b/src/core/utils.jl index 8f92c9f6f..9b6caabff 100644 --- a/src/core/utils.jl +++ b/src/core/utils.jl @@ -156,7 +156,7 @@ function dictkeys_tosymbols(d::Dict) "production_factor_series", "monthly_energy_rates", "monthly_demand_rates", "blended_doe_reference_percents", - "blended_industry_reference_percents", + "blended_industrial_reference_percents", "coincident_peak_load_charge_per_kw", "grid_draw_limit_kw_by_time_step", "export_limit_kw_by_time_step", "outage_probabilities", @@ -183,7 +183,7 @@ function dictkeys_tosymbols(d::Dict) end if k in [ "blended_doe_reference_names", - "blended_industry_reference_names" + "blended_industrial_reference_names" ] try v = convert(Array{String, 1}, v) diff --git a/test/runtests.jl b/test/runtests.jl index a998c75b2..ac4c854b3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -346,8 +346,8 @@ else # run HiGHS tests ("annual_mmbtu", sim_load_response_heating["dhw_annual_mmbtu"]) ]) - input_data["ProcessHeatLoad"] = Dict([("blended_industry_reference_names", doe_reference_name_heating), - ("blended_industry_reference_percents", percent_share_heating), + input_data["ProcessHeatLoad"] = Dict([("blended_industrial_reference_names", doe_reference_name_heating), + ("blended_industrial_reference_percents", percent_share_heating), ("annual_mmbtu", annual_mmbtu_process) ]) @@ -2383,9 +2383,9 @@ else # run HiGHS tests input_data["DomesticHotWaterLoad"]["doe_reference_name"] = building elec_load = REopt.ElectricLoad(latitude=latitude, longitude=longitude, doe_reference_name=building) input_data["ElectricLoad"]["annual_kwh"] = elec_load_multiplier * sum(elec_load.loads_kw) - space_load = REopt.SpaceHeatingLoad(latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) + space_load = REopt.HeatingLoad(load_type="space_heating", latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) input_data["SpaceHeatingLoad"]["annual_mmbtu"] = heat_load_multiplier * space_load.annual_mmbtu / input_data["ExistingBoiler"]["efficiency"] - dhw_load = REopt.DomesticHotWaterLoad(latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) + dhw_load = REopt.HeatingLoad(load_type="domestic_hot_water", latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) input_data["DomesticHotWaterLoad"]["annual_mmbtu"] = heat_load_multiplier * dhw_load.annual_mmbtu / input_data["ExistingBoiler"]["efficiency"] s = Scenario(input_data) inputs = REoptInputs(s) @@ -2910,5 +2910,95 @@ else # run HiGHS tests @test length(r["Messages"]["errors"]) > 0 @test length(r["Messages"]["warnings"]) > 0 end + + @testset "Normalize and scale load profile input to annual and monthly energy" begin + # Normalize and scale input load profile based on annual or monthly energy uses + # The purpose of this is to be able to build a load profile shape, and then scale to the typical monthly energy data that users have + + input_data = JSON.parsefile("./scenarios/norm_scale_load.json") + + # Start with normalizing and scaling electric load only + input_data["ElectricLoad"]["loads_kw"] = fill(10.0, 8760) + input_data["ElectricLoad"]["loads_kw"][5:28] .= 20.0 + input_data["ElectricLoad"]["year"] = 2017 + # input_data["ElectricLoad"]["annual_kwh"] = 87600.0 + + input_data["ElectricLoad"]["monthly_totals_kwh"] = fill(87600.0/12, 12) + input_data["ElectricLoad"]["monthly_totals_kwh"][2] *= 2 + input_data["ElectricLoad"]["normalize_and_scale_load_profile_input"] = true + + s = Scenario(input_data) + inputs = REoptInputs(s) + + # Check that monthly energy input is preserved when normalizing and scaling the hourly profile + @test abs(sum(s.electric_load.loads_kw) - sum(input_data["ElectricLoad"]["monthly_totals_kwh"])) < 0.01 + + # This get_monthly_energy function is only equivalent for non-leap years with loads_kw normalization and scaling because it removes the leap day from the processing of monthly hours/energy + monthly_totals_kwh = REopt.get_monthly_energy(s.electric_load.loads_kw; year=2017) + # Check that each month matches + @test sum(monthly_totals_kwh .- input_data["ElectricLoad"]["monthly_totals_kwh"]) < 0.1 + + # Check that the load ratio within a month is proportional to the loads_kw ratio + @test abs(s.electric_load.loads_kw[6] / s.electric_load.loads_kw[4] - input_data["ElectricLoad"]["loads_kw"][6] / input_data["ElectricLoad"]["loads_kw"][4]) < 0.001 + + # Check consistency with simulated_load function + d_sim_load = Dict([ + ("load_type", "electric"), + ("normalize_and_scale_load_profile_input", true), + ("load_profile", input_data["ElectricLoad"]["loads_kw"]), + ("monthly_totals_kwh", input_data["ElectricLoad"]["monthly_totals_kwh"]) + ]) + + sim_load_response = simulated_load(d_sim_load) + + @test abs(sim_load_response["annual_kwh"] - sum(input_data["ElectricLoad"]["monthly_totals_kwh"])) < 1.0 + @test sum(s.electric_load.loads_kw .- sim_load_response["loads_kw"]) < 10.0 + + # Check space heating load normization and scaling + input_data = JSON.parsefile("./scenarios/norm_scale_load.json") + input_data["ElectricLoad"]["doe_reference_name"] = "LargeOffice" + # Focus on SpaceHeating for heating norm and scale + input_data["SpaceHeatingLoad"] = Dict() + input_data["SpaceHeatingLoad"]["fuel_loads_mmbtu_per_hour"] = fill(10.0, 8760) + input_data["SpaceHeatingLoad"]["fuel_loads_mmbtu_per_hour"][5:28] .= 20.0 + input_data["SpaceHeatingLoad"]["year"] = 2020 # Test leap year which for norm_and_scale expects the last day to be cut off instead of the leap day + # input_data["SpaceHeatingLoad"]["annual_mmbtu"] = 87600.0 + + input_data["SpaceHeatingLoad"]["monthly_mmbtu"] = fill(87600.0/12, 12) + input_data["SpaceHeatingLoad"]["monthly_mmbtu"][2] *= 2 + input_data["SpaceHeatingLoad"]["normalize_and_scale_load_profile_input"] = true + + input_data["SpaceHeatingLoad"]["addressable_load_fraction"] = 0.9 + address_frac = input_data["SpaceHeatingLoad"]["addressable_load_fraction"] + + s = Scenario(input_data) + inputs = REoptInputs(s) + + # Check that monthly energy input is preserved when normalizing and scaling the hourly profile + @test abs(sum(s.space_heating_load.loads_kw / s.existing_boiler.efficiency / REopt.KWH_PER_MMBTU) - sum(input_data["SpaceHeatingLoad"]["monthly_mmbtu"]) * address_frac) < 1.0 + + # This get_monthly_energy function is only equivalent for non-leap years with loads_kw normalization and scaling because it removes the leap day from the processing of monthly hours/energy + monthly_kwht = REopt.get_monthly_energy(s.space_heating_load.loads_kw; year=2017) + monthly_mmbtu = monthly_kwht/ s.existing_boiler.efficiency / REopt.KWH_PER_MMBTU + # Check that each month matches + @test sum(monthly_mmbtu .- input_data["SpaceHeatingLoad"]["monthly_mmbtu"] * address_frac) < 1.0 + + # Check that the load ratio within a month is proportional to the loads_kw ratio + @test abs(s.space_heating_load.loads_kw[6] / s.space_heating_load.loads_kw[4] - input_data["SpaceHeatingLoad"]["fuel_loads_mmbtu_per_hour"][6] / input_data["SpaceHeatingLoad"]["fuel_loads_mmbtu_per_hour"][4]) < 0.001 + + # Check consistency with simulated_load function + d_sim_load = Dict([ + ("load_type", "space_heating"), + ("normalize_and_scale_load_profile_input", true), + ("load_profile", input_data["SpaceHeatingLoad"]["fuel_loads_mmbtu_per_hour"]), + ("monthly_mmbtu", input_data["SpaceHeatingLoad"]["monthly_mmbtu"]), + ("addressable_load_fraction", address_frac) + ]) + + sim_load_response = simulated_load(d_sim_load) + + @test abs(sim_load_response["annual_mmbtu"] - sum(input_data["SpaceHeatingLoad"]["monthly_mmbtu"]) * address_frac) < 1.0 + @test sum(s.space_heating_load.loads_kw / s.existing_boiler.efficiency / REopt.KWH_PER_MMBTU .- sim_load_response["loads_mmbtu_per_hour"]) < 10.0 + end end end \ No newline at end of file diff --git a/test/scenarios/electric_heater.json b/test/scenarios/electric_heater.json index f63650053..c84387c07 100644 --- a/test/scenarios/electric_heater.json +++ b/test/scenarios/electric_heater.json @@ -42,7 +42,7 @@ "annual_kwh": 87600.0 }, "ProcessHeatLoad": { - "industry_reference_name": "FlatLoad" + "industrial_reference_name": "FlatLoad" }, "SpaceHeatingLoad": { "doe_reference_name": "FlatLoad" diff --git a/test/scenarios/norm_scale_load.json b/test/scenarios/norm_scale_load.json new file mode 100644 index 000000000..9691b7416 --- /dev/null +++ b/test/scenarios/norm_scale_load.json @@ -0,0 +1,14 @@ +{ + "Site": { + "latitude": 37.78, + "longitude": -122.45 + }, + "ElectricLoad": {}, + "ExistingBoiler": { + "fuel_cost_per_mmbtu": 10 + }, + "ElectricTariff": { + "blended_annual_energy_rate": 0.1, + "blended_annual_demand_rate": 10 + } + } \ No newline at end of file diff --git a/test/scenarios/process_heat.json b/test/scenarios/process_heat.json index 9aff11e8c..4f0539ada 100644 --- a/test/scenarios/process_heat.json +++ b/test/scenarios/process_heat.json @@ -31,7 +31,7 @@ }, "ProcessHeatLoad": { "annual_mmbtu": 87600.0, - "industry_reference_name": "FlatLoad" + "industrial_reference_name": "FlatLoad" }, "Boiler": { "min_mmbtu_per_hour": 0.0, diff --git a/test/scenarios/thermal_load.json b/test/scenarios/thermal_load.json index 9b8d47290..930707a0a 100644 --- a/test/scenarios/thermal_load.json +++ b/test/scenarios/thermal_load.json @@ -24,7 +24,7 @@ "doe_reference_name": "LargeOffice" }, "ProcessHeatLoad": { - "industry_reference_name": "FlatLoad" + "industrial_reference_name": "FlatLoad" }, "DomesticHotWaterLoad": { "doe_reference_name": "LargeOffice" diff --git a/test/test_with_xpress.jl b/test/test_with_xpress.jl index c368d88b4..df981dd1e 100644 --- a/test/test_with_xpress.jl +++ b/test/test_with_xpress.jl @@ -1549,9 +1549,9 @@ end input_data["DomesticHotWaterLoad"]["doe_reference_name"] = building elec_load = REopt.ElectricLoad(latitude=latitude, longitude=longitude, doe_reference_name=building) input_data["ElectricLoad"]["annual_kwh"] = elec_load_multiplier * sum(elec_load.loads_kw) - space_load = REopt.SpaceHeatingLoad(latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) + space_load = REopt.HeatingLoad(load_type="space_heating", latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) input_data["SpaceHeatingLoad"]["annual_mmbtu"] = heat_load_multiplier * space_load.annual_mmbtu / input_data["ExistingBoiler"]["efficiency"] - dhw_load = REopt.DomesticHotWaterLoad(latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) + dhw_load = REopt.HeatingLoad(load_type="domestic_hot_water", latitude=latitude, longitude=longitude, doe_reference_name=building, existing_boiler_efficiency=input_data["ExistingBoiler"]["efficiency"]) input_data["DomesticHotWaterLoad"]["annual_mmbtu"] = heat_load_multiplier * dhw_load.annual_mmbtu / input_data["ExistingBoiler"]["efficiency"] s = Scenario(input_data) inputs = REoptInputs(s)