diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cee93ce4..b076f84d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,36 @@ Classify the change according to the following categories: ##### Removed ### Patches +## v3.14.0 +### Minor Updates +#### Added +- `CST` (concentrating solar thermal) Intputs and Outputs models; see /help endpoint for model fields +- `HighTempThermalStorage` Inputs and Outputs models; see /help endpoint for model fields + +#### Changed +Update the following inputs from the previous --> new values: +- `Financial.offtaker_discount_rate_fraction`: 0.0638 --> 0.0624 +- `Financial.owner_discount_rate_fraction`: 0.0638 --> 0.0624 +- `Financial.elec_cost_escalation_rate_fraction`: 0.017 --> 0.0166 +- `Financial.existing_boiler_fuel_cost_escalation_rate_fraction `: 0.015 --> 0.0348 +- `Financial.boiler_fuel_cost_escalation_rate_fraction `: 0.015 --> 0.0348 +- `Financial.chp_fuel_cost_escalation_rate_fraction `: 0.015 --> 0.0348 +- `Financial.generator_fuel_cost_escalation_rate_fraction `: 0.012 --> 0.0197 +- `Generator.fuel_cost_per_gallon`: 3.61 --> 2.25 +- `ColdThermalStorage`, `HotThermalStorage`, `ElectricStorage` `macrs_option_years`: 7 --> 5 +- `CHP`, `ColdThermalStorage`, `HotThermalStorage`, `ElectricStorage`, `PV`, `Wind` `macrs_bonus_fraction` 0.6 --> 1.0 +- `GHP.macrs_bonus_fraction`: 0.4 --> 0.0 +- `GHP.macrs_option_years`: 5 --> 0 +- `SteamTurbine.macrs_bonus_fraction`: 0 --> 1.0 +- `SteamTurbine.macrs_option_years`: 0 --> 5 (in order for 100% bonus depr to apply) +- `CHP.federal_itc_fraction`: 0.3 --> 0.0 +- `Wind.om_cost_per_kw`: 36.0 --> 42.0 +- `Wind.size_class_to_installed_cost` = Dict( + "residential"=> 6339.0, --> 7692.0 + "commercial"=> 4760.0, --> 5776.0 + "medium"=> 3137.0, --> 3807.0 + "large"=> 2386.0 --> 2896.0) + ## v3.13.0 ### Minor Updates #### Added diff --git a/julia_src/.env b/julia_src/.env index 53ef8e1c8..db3264dcd 100644 --- a/julia_src/.env +++ b/julia_src/.env @@ -1 +1,2 @@ -NREL_DEVELOPER_API_KEY="gAfosXcQ9Ldfw3qXqvKVb7PxMEkYigozmC9R3mXQ" \ No newline at end of file +NREL_DEVELOPER_API_KEY="gAfosXcQ9Ldfw3qXqvKVb7PxMEkYigozmC9R3mXQ" +NREL_DEVELOPER_EMAIL="reopt@nrel.gov" \ No newline at end of file diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index 499e0c00a..d70a383ef 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -71,10 +71,10 @@ version = "0.4.7" uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" [[deps.BenchmarkTools]] -deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] -git-tree-sha1 = "f1dff6729bc61f4d49e140da1af55dcd1ac97b2f" +deps = ["Compat", "JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "e38fbc49a620f5d0b660d7f543db1009fe0f8336" uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -version = "1.5.0" +version = "1.6.0" [[deps.BitFlags]] git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d" @@ -89,15 +89,15 @@ version = "0.7.3" [[deps.Blosc_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Lz4_jll", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "ef12cdd1c7fb7e1dfd6fa8fd60d4db6bc61d2f23" +git-tree-sha1 = "535c80f1c0847a4c967ea945fca21becc9de1522" uuid = "0b7ba130-8d10-5ba8-a3d6-c5182647fed9" -version = "1.21.6+2" +version = "1.21.7+0" [[deps.Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "35abeca13bc0425cff9e59e229d971f5231323bf" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1b96ea4a01afe0ea4090c5c8039690672dd13f2e" uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.8+3" +version = "1.0.9+0" [[deps.CEnum]] git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" @@ -142,9 +142,9 @@ version = "0.8.5" [[deps.CodecZlib]] deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759" +git-tree-sha1 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.6" +version = "0.7.8" [[deps.CoinUtils_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Pkg"] @@ -207,9 +207,9 @@ weakdeps = ["InverseFunctions"] [[deps.ConcurrentUtilities]] deps = ["Serialization", "Sockets"] -git-tree-sha1 = "f36e5e8fdffcb5646ea5da81495a5a7566005127" +git-tree-sha1 = "d9d26935a0bcffc87d2613ce14c527c99fc543fd" uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" -version = "2.4.3" +version = "2.5.0" [[deps.ConstructionBase]] git-tree-sha1 = "76219f1ed5771adbb096743bff43fb5fdd4c1157" @@ -256,9 +256,9 @@ version = "1.7.0" [[deps.DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" +git-tree-sha1 = "4e1fe97fdaed23e9dc21d4d664bea76b65fc50a0" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.20" +version = "0.18.22" [[deps.DataValueInterfaces]] git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" @@ -294,10 +294,9 @@ uuid = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3" version = "0.3.23" [[deps.DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" +git-tree-sha1 = "e7b7e6f178525d17c720ab9c081e4ef04429f860" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.9.3" +version = "0.9.4" [[deps.DotEnv]] deps = ["PrecompileTools"] @@ -329,9 +328,9 @@ version = "0.1.5" [[deps.FileIO]] deps = ["Pkg", "Requires", "UUIDs"] -git-tree-sha1 = "2dd20384bf8c6d411b5c7370865b1e9b26cb2ea3" +git-tree-sha1 = "b66970a70db13f45b7e57fbda1736e1cf72174ea" uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" -version = "1.16.6" +version = "1.17.0" weakdeps = ["HTTP"] [deps.FileIO.extensions] @@ -339,9 +338,9 @@ weakdeps = ["HTTP"] [[deps.FilePathsBase]] deps = ["Compat", "Dates"] -git-tree-sha1 = "2ec417fc319faa2d768621085cc1feebbdee686b" +git-tree-sha1 = "3bab2c5aa25e7840a4b065805c0cdfc01f3068d2" uuid = "48062228-2e41-5def-b9a4-89aafe57970f" -version = "0.9.23" +version = "0.9.24" weakdeps = ["Mmap", "Test"] [deps.FilePathsBase.extensions] @@ -414,7 +413,7 @@ uuid = "0329782f-3d07-4b52-b9f6-d3137cf03c7a" version = "1.0.2" [[deps.GhpGhx]] -git-tree-sha1 = "bddcbcddc9a4ae7ae4f1ea7d4d8ccf38507d4071" +git-tree-sha1 = "c2f3becdf925f287778fa088da6da01e307f6ce8" repo-rev = "main" repo-url = "https://github.com/NREL/GhpGhx.jl.git" uuid = "7ce85f02-24a8-4d69-a3f0-14b5daa7d30c" @@ -446,33 +445,33 @@ version = "0.17.2" [[deps.HDF5_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "LibCURL_jll", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "OpenSSL_jll", "TOML", "Zlib_jll", "libaec_jll"] -git-tree-sha1 = "87bd95f99219dc3b86d4ee11a9a7bfa6075000a9" +git-tree-sha1 = "e94f84da9af7ce9c6be049e9067e511e17ff89ec" uuid = "0234f1f7-429e-5d53-9886-15a909be8d59" -version = "1.14.5+0" +version = "1.14.6+0" [[deps.HTTP]] -deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] -git-tree-sha1 = "abbbb9ec3afd783a7cbd82ef01dcd088ea051398" +deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "PrecompileTools", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] +git-tree-sha1 = "c67b33b085f6e2faf8bf79a61962e7339a81129c" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "1.10.1" +version = "1.10.15" [[deps.HiGHS]] deps = ["HiGHS_jll", "MathOptInterface", "PrecompileTools", "SparseArrays"] -git-tree-sha1 = "fce13308f09771b160232903cad57be39a8a0ebb" +git-tree-sha1 = "219becee955e18b349be83d74bdd2e5ad4804d0f" uuid = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" -version = "1.7.5" +version = "1.15.0" [[deps.HiGHS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "f596ee3668df8587158bcaef1ae47bf75bc0fe39" +git-tree-sha1 = "72bceb63d4ae3683f091f812b6958a199c494a1b" uuid = "8fd58aa0-07eb-5a78-9b36-339c94fd15ea" -version = "1.6.0+1" +version = "1.10.0+0" [[deps.Hwloc_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "290232556f4ffb60ac3e476acf28e1a46e764742" +git-tree-sha1 = "f93a9ce66cd89c9ba7a4695a47fd93b4c6bc59fa" uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8" -version = "2.11.2+2" +version = "2.12.0+0" [[deps.ImageCore]] deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"] @@ -525,14 +524,14 @@ version = "1.3.1" [[deps.Ipopt_jll]] deps = ["ASL_jll", "Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "MUMPS_seq_jll", "SPRAL_jll", "libblastrampoline_jll"] -git-tree-sha1 = "4f55ad688c698a4f77d892a1cb673f7e8a30f178" +git-tree-sha1 = "546c40fd3718c65d48296dd6cec98af9904e3ca4" uuid = "9cc047cb-c261-5740-88fc-0cf96f7bdcc7" -version = "300.1400.1700+0" +version = "300.1400.1400+0" [[deps.IrrationalConstants]] -git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" +git-tree-sha1 = "e2222959fbc6c19554dc15174c81bf7bf3aa691c" uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.2.2" +version = "0.2.4" [[deps.IterTools]] git-tree-sha1 = "42d5f897009e7ff2cf88db414a389e5ed1bdd023" @@ -562,17 +561,29 @@ git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" version = "0.21.4" +[[deps.JSON3]] +deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"] +git-tree-sha1 = "196b41e5a854b387d99e5ede2de3fcb4d0422aae" +uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +version = "1.14.2" + + [deps.JSON3.extensions] + JSON3ArrowExt = ["ArrowTypes"] + + [deps.JSON3.weakdeps] + ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" + [[deps.JpegTurbo_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "3447a92280ecaad1bd93d3fce3d408b6cfff8913" +git-tree-sha1 = "eac1206917768cb54957c65a615460d87b455fc1" uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "3.1.0+1" +version = "3.1.1+0" [[deps.JuMP]] -deps = ["LinearAlgebra", "MacroTools", "MathOptInterface", "MutableArithmetics", "OrderedCollections", "Printf", "SnoopPrecompile", "SparseArrays"] -git-tree-sha1 = "cd161958e8b47f9696a6b03f563afb4e5fe8f703" +deps = ["LinearAlgebra", "MacroTools", "MathOptInterface", "MutableArithmetics", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays"] +git-tree-sha1 = "c9ace86360c1dc0635de5f9e2ce5143b86c53311" uuid = "4076af6c-e467-56ae-b986-b466b2749572" -version = "1.17.0" +version = "1.25.0" [deps.JuMP.extensions] JuMPDimensionalDataExt = "DimensionalData" @@ -587,9 +598,9 @@ uuid = "88015f11-f218-50d7-93a8-a6af411a945d" version = "3.0.0+1" [[deps.LRUCache]] -git-tree-sha1 = "b3cc6698599b10e652832c2f23db3cab99d51b59" +git-tree-sha1 = "5519b95a490ff5fe629c4a7aa3b3dfc9160498b3" uuid = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637" -version = "1.6.1" +version = "1.6.2" weakdeps = ["Serialization"] [deps.LRUCache.extensions] @@ -685,16 +696,16 @@ uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" version = "1.10.1+0" [[deps.METIS_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "1c20a46719c0dc4ec4e7021ca38f53e1ec9268d9" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "2eefa8baa858871ae7770c98c3c2a7e46daba5b4" uuid = "d00139f3-1899-568f-a2f0-47f597d42d70" -version = "5.1.2+1" +version = "5.1.3+0" [[deps.MPICH_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"] -git-tree-sha1 = "7715e65c47ba3941c502bffb7f266a41a7f54423" +git-tree-sha1 = "3aa3210044138a1749dbd350a9ba8680869eb503" uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" -version = "4.2.3+0" +version = "4.3.0+1" [[deps.MPIPreferences]] deps = ["Libdl", "Preferences"] @@ -704,21 +715,20 @@ version = "0.1.11" [[deps.MPItrampoline_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"] -git-tree-sha1 = "97aac4a518b6f01851f8821272780e1ba56fe90d" +git-tree-sha1 = "ff91ca13c7c472cef700f301c8d752bc2aaff1a8" uuid = "f1f71cc9-e9ae-5b93-9b94-4fe0e1ad3748" -version = "5.5.2+0" +version = "5.5.3+0" [[deps.MUMPS_seq_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "METIS_jll", "libblastrampoline_jll"] -git-tree-sha1 = "0eab12f94948ca67908aec14b9f2ebefd17463fe" +git-tree-sha1 = "840b83c65b27e308095c139a457373850b2f5977" uuid = "d7ed1dd3-d0ae-5e8e-bfb4-87a502085b8d" -version = "500.700.301+0" +version = "500.600.201+0" [[deps.MacroTools]] -deps = ["Markdown", "Random"] -git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" +git-tree-sha1 = "72aebe0b5051e5143a079a4685a46da330a40472" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.13" +version = "0.5.15" [[deps.MappedArrays]] git-tree-sha1 = "2dab0221fe2b0f2cb6754eaa743cc266339f527e" @@ -730,10 +740,10 @@ deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" [[deps.MathOptInterface]] -deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] -git-tree-sha1 = "362ae34a5291a79e16b8eb87b5738532c5e799ff" +deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON3", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test"] +git-tree-sha1 = "6723502b2135aa492a65be9633e694482a340ee7" uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" -version = "1.23.0" +version = "1.38.0" [[deps.MbedTLS]] deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] @@ -773,30 +783,30 @@ version = "2023.1.10" [[deps.MutableArithmetics]] deps = ["LinearAlgebra", "SparseArrays", "Test"] -git-tree-sha1 = "806eea990fb41f9b36f1253e5697aa645bf6a9f8" +git-tree-sha1 = "491bdcdc943fcbc4c005900d7463c9f216aabf4c" uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" -version = "1.4.0" +version = "1.6.4" [[deps.NaNMath]] deps = ["OpenLibm_jll"] -git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" +git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "1.0.2" +version = "1.1.3" [[deps.Ncurses_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "3690e6c58c16ba676bcc9b5654762fe8a05db1c7" +git-tree-sha1 = "b5e7e7ad16adfe5f68530f9f641955b5b0f12bbb" uuid = "68e3532b-a499-55ff-9963-d1c0c0748b3a" -version = "6.5.0+1" +version = "6.5.1+0" [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" [[deps.OffsetArrays]] -git-tree-sha1 = "5e1897147d1ff8d98883cda2be2187dcf57d8f0c" +git-tree-sha1 = "a414039192a155fb38c4599a60110f0018c6ec82" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.15.0" +version = "1.16.0" [deps.OffsetArrays.extensions] OffsetArraysAdaptExt = "Adapt" @@ -828,9 +838,9 @@ version = "0.8.1+2" [[deps.OpenMPI_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML", "Zlib_jll"] -git-tree-sha1 = "2dace87e14256edb1dd0724ab7ba831c779b96bd" +git-tree-sha1 = "047b66eb62f3cae59ed260ebb9075a32a04350f1" uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" -version = "5.0.6+0" +version = "5.0.7+2" [[deps.OpenSSL]] deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] @@ -840,20 +850,20 @@ version = "1.4.3" [[deps.OpenSSL_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "f58782a883ecbf9fb48dcd363f9ccd65f36c23a8" +git-tree-sha1 = "a9697f1d06cc3eb3fb3ad49cc67f2cfabaac31ea" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.0.15+2" +version = "3.0.16+0" [[deps.OpenSpecFun_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "418e63d434f5ca12b188bbb287dfbe10a5af1da4" +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1346c9208249809840c91b26703912dff463d335" uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.5+1" +version = "0.5.6+0" [[deps.OrderedCollections]] -git-tree-sha1 = "12f1439c4f986bb868acda6ea33ebc78e19b95ad" +git-tree-sha1 = "cc4054e898b852042d7b503313f7ad03de99c3dd" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.7.0" +version = "1.8.0" [[deps.Osi_jll]] deps = ["Artifacts", "CoinUtils_jll", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Pkg"] @@ -922,9 +932,9 @@ uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "4db74039055f6084d8bd45304de9de856462d917" +git-tree-sha1 = "f9fd5a8419a3a1c057403fb34fd4f47c15afe28e" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.53.2" +version = "0.54.0" [[deps.Random]] deps = ["SHA"] @@ -937,9 +947,9 @@ version = "0.3.2" [[deps.Readline_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Ncurses_jll"] -git-tree-sha1 = "69684dc9c2c69f7c515097841991362cca0739ea" +git-tree-sha1 = "6044f482a91c7aa2b82ab614aedd726be633ad05" uuid = "05236dd9-4125-5232-aa7c-9ec0c9b2c25a" -version = "8.2.1+1" +version = "8.2.13+0" [[deps.RecipesBase]] deps = ["PrecompileTools"] @@ -954,15 +964,15 @@ version = "1.2.2" [[deps.Requires]] deps = ["UUIDs"] -git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64" uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.3.0" +version = "1.3.1" [[deps.Roots]] deps = ["Accessors", "CommonSolve", "Printf"] -git-tree-sha1 = "e52cf0872526c7a0b3e1af9c58a69b90e19b022e" +git-tree-sha1 = "3ac13765751ffc81e3531223782d9512f6023f71" uuid = "f2b01f46-fcfa-551c-844a-d8ac1e96c665" -version = "2.2.5" +version = "2.2.7" [deps.Roots.extensions] RootsChainRulesCoreExt = "ChainRulesCore" @@ -979,22 +989,22 @@ version = "2.2.5" SymPyPythonCall = "bc8888f7-b21e-4b7c-a06a-5d9c9496438c" [[deps.SCIP]] -deps = ["Ipopt_jll", "Libdl", "LinearAlgebra", "MathOptInterface", "SCIP_PaPILO_jll", "SCIP_jll"] -git-tree-sha1 = "ac0512c46cd91744f62463514f2c581025ea5b93" +deps = ["Libdl", "LinearAlgebra", "MathOptInterface", "OpenBLAS32_jll", "SCIP_PaPILO_jll", "SCIP_jll"] +git-tree-sha1 = "34fc53e96b77a9abb54d1303d1b0b8999e5c4514" uuid = "82193955-e24f-5292-bf16-6f2c5261a85f" -version = "0.11.6" +version = "0.12.3" [[deps.SCIP_PaPILO_jll]] -deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "GMP_jll", "Ipopt_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Pkg", "Readline_jll", "Zlib_jll", "bliss_jll", "boost_jll", "oneTBB_jll"] -git-tree-sha1 = "7705b5779724f35d78351548f24c7f7656e61bc2" +deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "GMP_jll", "Ipopt_jll", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "Readline_jll", "Zlib_jll", "bliss_jll", "boost_jll", "oneTBB_jll"] +git-tree-sha1 = "6fc56a56f9bccaa809d96250dba5eab909a60f6f" uuid = "fc9abe76-a5e6-5fed-b0b7-a12f309cf031" -version = "0.1.0+3" +version = "900.200.100+0" [[deps.SCIP_jll]] -deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "GMP_jll", "Ipopt_jll", "JLLWrappers", "Libdl", "Pkg", "Readline_jll", "Zlib_jll", "bliss_jll", "boost_jll"] -git-tree-sha1 = "4a23f926d711535640963aea90a3f5d931ae52c7" +deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "GMP_jll", "Ipopt_jll", "JLLWrappers", "Libdl", "Readline_jll", "Zlib_jll", "boost_jll"] +git-tree-sha1 = "f87b83dd8bd166c0904d64441fc424073c65539d" uuid = "e5ac4fe4-a920-5659-9bf8-f9f73e9e79ce" -version = "0.2.1+0" +version = "900.200.100+0" [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" @@ -1002,15 +1012,15 @@ version = "0.7.0" [[deps.SPRAL_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "Libdl", "METIS_jll", "libblastrampoline_jll"] -git-tree-sha1 = "11f3da4b25efacd1cec8e263421f2a9003a5e8e0" +git-tree-sha1 = "34b9dacd687cace8aa4d550e3e9bb8615f1a61e9" uuid = "319450e9-13b8-58e8-aa9f-8fd1420848ab" -version = "2024.5.8+0" +version = "2024.1.18+0" [[deps.SQLite_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "7b5b0b963000117848dfe9199bbe4f528e37c5fd" +git-tree-sha1 = "9a325057cdb9b066f1f96dc77218df60fe3007cb" uuid = "76ed43ae-9a5d-5a62-8c75-30186b810ce8" -version = "3.47.2+1" +version = "3.48.0+0" [[deps.SentinelArrays]] deps = ["Dates", "Random"] @@ -1026,12 +1036,6 @@ git-tree-sha1 = "f305871d2f381d21527c770d4788c06c097c9bc1" uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" version = "1.2.0" -[[deps.SnoopPrecompile]] -deps = ["Preferences"] -git-tree-sha1 = "e760a70afdcd461cf01a575947738d359234665c" -uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" -version = "1.0.3" - [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" @@ -1080,6 +1084,12 @@ git-tree-sha1 = "725421ae8e530ec29bcbdddbe91ff8053421d023" uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" version = "0.4.1" +[[deps.StructTypes]] +deps = ["Dates", "UUIDs"] +git-tree-sha1 = "159331b30e94d7b11379037feeb9b690950cace8" +uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" +version = "1.11.0" + [[deps.SuiteSparse_jll]] deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" @@ -1129,9 +1139,9 @@ uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" version = "0.11.3" [[deps.URIs]] -git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" +git-tree-sha1 = "cbbebadbcc76c5ca1cc4b4f3b0614b3e603b5000" uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.5.1" +version = "1.5.2" [[deps.UUIDs]] deps = ["Random", "SHA"] @@ -1163,10 +1173,10 @@ uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60" version = "1.6.1" [[deps.Xpress]] -deps = ["Libdl", "LinearAlgebra", "MathOptInterface", "SparseArrays"] -git-tree-sha1 = "29c47b54b6938852a598fc6761ed927aad61f10e" +deps = ["Libdl", "MathOptInterface"] +git-tree-sha1 = "f48ea69baa747f63b0d08c89ce7bc38d8ef62bd4" uuid = "9e70acf3-d6c9-5be6-b5bd-4e2c73e3e054" -version = "0.16.2" +version = "0.17.1" [[deps.Zlib_jll]] deps = ["Libdl"] @@ -1175,9 +1185,9 @@ version = "1.2.13+1" [[deps.Zstd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "7dc5adc3f9bfb9b091b7952f4f6048b7e37acafc" +git-tree-sha1 = "446b23e73536f84e8037f5dce465e92275f6a308" uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" -version = "1.5.6+2" +version = "1.5.7+1" [[deps.bliss_jll]] deps = ["Artifacts", "GMP_jll", "JLLWrappers", "Libdl", "Pkg"] @@ -1187,9 +1197,9 @@ version = "0.77.0+1" [[deps.boost_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "7a89efe0137720ca82f99e8daa526d23120d0d37" +git-tree-sha1 = "d9484c66c733c1c84f1d4cfef538d3c7b9d32199" uuid = "28df3c45-c428-5900-9ff8-a3135698ca75" -version = "1.76.0+1" +version = "1.79.0+3" [[deps.libaec_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -1210,9 +1220,9 @@ version = "100.700.100+0" [[deps.libpng_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "055a96774f383318750a1a5e10fd4151f04c29c5" +git-tree-sha1 = "068dfe202b0a05b8332f1e8e6b4080684b9c7700" uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.46+0" +version = "1.6.47+0" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] @@ -1221,9 +1231,9 @@ version = "1.52.0+1" [[deps.oneTBB_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "7d0ea0f4895ef2f5cb83645fa689e52cb55cf493" +git-tree-sha1 = "d5a767a3bb77135a99e433afe0eb14cd7f6914c3" uuid = "1317d2d5-d96f-522e-a858-c73665f53c3e" -version = "2021.12.0+0" +version = "2022.0.0+0" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] diff --git a/julia_src/http.jl b/julia_src/http.jl index cd12baa0e..8e4b0a4fc 100644 --- a/julia_src/http.jl +++ b/julia_src/http.jl @@ -7,6 +7,8 @@ DotEnv.load!() const test_nrel_developer_api_key = ENV["NREL_DEVELOPER_API_KEY"] +ENV["NREL_DEVELOPER_EMAIL"] = "reopt@nrel.gov" + include("os_solvers.jl") # Load Xpress only if it is installed, as indicated by ENV["XPRESS_INSTALLED"]="True" diff --git a/reoptjl/custom_table_config.py b/reoptjl/custom_table_config.py index f12854ceb..e99dc0ea8 100644 --- a/reoptjl/custom_table_config.py +++ b/reoptjl/custom_table_config.py @@ -234,6 +234,18 @@ "bau_value" : lambda df: safe_get(df, "outputs.GHP.ghpghx_chosen_outputs.length_boreholes_ft_bau")*safe_get(df, "outputs.GHP.ghpghx_chosen_outputs.number_of_boreholes_bau"), "scenario_value": lambda df: safe_get(df, "outputs.GHP.ghpghx_chosen_outputs.length_boreholes_ft")*safe_get(df, "outputs.GHP.ghpghx_chosen_outputs.number_of_boreholes") }, + { + "label" : "Concentrating Solar Thermal Capacity (kW)", + "key" : "cst_capacity", + "bau_value" : lambda df: safe_get(df, "outputs.CST.size_kw_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.CST.size_kw") + }, + { + "label" : "High Temperature Thermal Storage Capacity (kWh)", + "key" : "high_temp_tes_capacity", + "bau_value" : lambda df: safe_get(df, "outputs.HighTempThermalStorage.size_kwh_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.HighTempThermalStorage.size_kwh") + }, # New ASHP entries { "label" : "ASHP Space Heating and Cooling Capacity (ton)", @@ -915,6 +927,12 @@ "bau_value" : lambda df: safe_get(df, "outputs.SteamTurbine.thermal_to_load_series_mmbtu_per_hour_bau"), "scenario_value": lambda df: safe_get(df, "outputs.SteamTurbine.thermal_to_load_series_mmbtu_per_hour") }, + { + "label" : "Steam Turbine Charging High Temp Thermal Storage (MMBtu/yr)", + "key" : "steam_turbine_charging_high_temp_thermal_storage", + "bau_value" : lambda df: safe_get(df, "outputs.SteamTurbine.thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.SteamTurbine.thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour") + }, { "label" : "Steam Turbine Charging Hot Water Storage (MMBtu/yr)", "key" : "steam_turbine_charging_hot_water_storage", @@ -963,6 +981,42 @@ "bau_value" : lambda df: safe_get(df, "outputs.ASHPWaterHeater.thermal_to_storage_series_mmbtu_per_hour_bau"), "scenario_value": lambda df: safe_get(df, "outputs.ASHPWaterHeater.thermal_to_storage_series_mmbtu_per_hour") }, + { + "label" : "CST Charging High Temp Thermal Storage (MMBtu/yr)", + "key" : "cst_charging_high_temp_thermal_storage", + "bau_value" : lambda df: safe_get(df, "outputs.CST.thermal_to_high_temp_thermal_series_mmbtu_per_hour_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.CST.thermal_to_high_temp_thermal_series_mmbtu_per_hour") + }, + { + "label" : "CST Charging Hot Water Storage (MMBtu/yr)", + "key" : "cst_charging_hot_water_storage", + "bau_value" : lambda df: safe_get(df, "outputs.CST.thermal_to_storage_series_mmbtu_per_hour_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.CST.thermal_to_storage_series_mmbtu_per_hour") + }, + { + "label" : "CST Thermal to Steam Turbine (MMBtu/yr)", + "key" : "cst_thermal_to_steam_turbine", + "bau_value" : lambda df: safe_get(df, "outputs.CST.thermal_to_steamturbine_series_mmbtu_per_hour_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.CST.thermal_to_steamturbine_series_mmbtu_per_hour") + }, + { + "label" : "CST Thermal Vented (MMBtu/yr)", + "key" : "cst_thermal_vented", + "bau_value" : lambda df: safe_get(df, "outputs.CST.thermal_curtailed_series_mmbtu_per_hour_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.CST.thermal_curtailed_series_mmbtu_per_hour") + }, + { + "label" : "CST Total Thermal Produced (MMBtu/yr)", + "key" : "cst_total_thermal_produced", + "bau_value" : lambda df: safe_get(df, "outputs.CST.annual_thermal_production_mmbtu_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.CST.annual_thermal_production_mmbtu") + }, + { + "label" : "High Temp Thermal Storage Serving Thermal Load (MMBtu/yr)", + "key" : "high_temp_thermal_storage_serving_thermal_load", + "bau_value" : lambda df: safe_get(df, "outputs.HighTempThermalStorage.storage_to_load_series_mmbtu_per_hour_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.HighTempThermalStorage.storage_to_load_series_mmbtu_per_hour") + }, { "label" : "Hot Water Storage Serving Thermal Load (MMBtu/yr)", "key" : "hot_water_storage_serving_thermal_load", diff --git a/reoptjl/migrations/0081_cstoutputs_cstinputs.py b/reoptjl/migrations/0081_cstoutputs_cstinputs.py new file mode 100644 index 000000000..9c71d9685 --- /dev/null +++ b/reoptjl/migrations/0081_cstoutputs_cstinputs.py @@ -0,0 +1,63 @@ +# Generated by Django 4.0.7 on 2025-04-23 16:47 + +import django.contrib.postgres.fields +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import reoptjl.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0080_electricloadoutputs_annual_electric_load_with_thermal_conversions_kwh_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='CSTOutputs', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('size_kw', models.FloatField(blank=True, null=True)), + ('annual_electric_consumption_kwh', models.FloatField(blank=True, null=True)), + ('annual_thermal_production_mmbtu', models.FloatField(blank=True, null=True)), + ('thermal_production_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None)), + ('electric_consumption_series_kw', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None)), + ('thermal_to_storage_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None)), + ('thermal_to_hot_sensible_tes_storage_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None)), + ('thermal_to_steamturbine_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None)), + ('thermal_curtailed_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None)), + ('thermal_to_load_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None)), + ('meta', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='CSTOutputs', to='reoptjl.apimeta')), + ], + bases=(reoptjl.models.BaseModel, models.Model), + ), + migrations.CreateModel( + name='CSTInputs', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tech_type', models.TextField(blank=True, default='ptc', help_text='Type of CST you want to implement into your system')), + ('min_kw', models.FloatField(blank=True, default=0, help_text='Minimum CST size constraint for optimization.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('max_kw', models.FloatField(blank=True, default=1000000000.0, help_text='Maximum CST size constraint for optimization (upper bound on additional capacity beyond existing_kw). Set to zero to disable PV', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('acres_per_kw', models.FloatField(blank=True, default=0.006, help_text='Power density for CST', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)])), + ('installed_cost_per_kw', models.FloatField(blank=True, default=1200, help_text='Installed CST cost in $/kW', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000.0)])), + ('om_cost_per_kw', models.FloatField(blank=True, default=18, help_text='Annual CST operations and maintenance costs in $/kW', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)])), + ('om_cost_per_kwh', models.FloatField(blank=True, default=18, help_text='Annual CST operations and maintenance costs in $/kWh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)])), + ('macrs_option_years', models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable')), + ('macrs_bonus_fraction', models.FloatField(blank=True, default=0.6, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])), + ('capacity_factor_series', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, help_text='Optional user-defined capacity factors for CST.', size=None)), + ('elec_consumption_factor_series', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, help_text='Optional user-defined electricity consumption factors for CST.', size=None)), + ('can_supply_steam_turbine', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if CST can supply steam to the steam turbine for electric production', null=True)), + ('can_serve_dhw', models.BooleanField(blank=True, default=True, help_text='Boolean indicator if CST can serve hot water load', null=True)), + ('can_serve_space_heating', models.BooleanField(blank=True, default=True, help_text='Boolean indicator if CST can serve space heating load', null=True)), + ('can_serve_process_heat', models.BooleanField(blank=True, default=True, help_text='Boolean indicator if CST can serve process heat load', null=True)), + ('charge_storage_only', models.BooleanField(blank=True, default=True, help_text='Boolean indicator if CST can only supply hot TES', null=True)), + ('emissions_factor_lb_CO2_per_mmbtu', models.FloatField(blank=True, help_text='Pounds of CO2 emitted per MMBTU of fuel burned.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('emissions_factor_lb_NOx_per_mmbtu', models.FloatField(blank=True, help_text='Pounds of CO2 emitted per MMBTU of fuel burned.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('emissions_factor_lb_SO2_per_mmbtu', models.FloatField(blank=True, help_text='Pounds of CO2 emitted per MMBTU of fuel burned.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('emissions_factor_lb_PM25_per_mmbtu', models.FloatField(blank=True, help_text='Pounds of CO2 emitted per MMBTU of fuel burned.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('meta', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='CSTInputs', to='reoptjl.apimeta')), + ], + bases=(reoptjl.models.BaseModel, models.Model), + ), + ] diff --git a/reoptjl/migrations/0085_merge_20250507_0118.py b/reoptjl/migrations/0085_merge_20250507_0118.py new file mode 100644 index 000000000..f192ab17b --- /dev/null +++ b/reoptjl/migrations/0085_merge_20250507_0118.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-05-07 01:18 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0081_cstoutputs_cstinputs'), + ('reoptjl', '0084_merge_20250424_1814'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0086_alter_cstinputs_meta.py b/reoptjl/migrations/0086_alter_cstinputs_meta.py new file mode 100644 index 000000000..6ab8e8741 --- /dev/null +++ b/reoptjl/migrations/0086_alter_cstinputs_meta.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.7 on 2025-05-07 03:39 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0085_merge_20250507_0118'), + ] + + operations = [ + migrations.AlterField( + model_name='cstinputs', + name='meta', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='CSTInputs', to='reoptjl.apimeta'), + ), + ] diff --git a/reoptjl/migrations/0087_cstinputs_inlet_temp_degf_cstinputs_outlet_temp_degf.py b/reoptjl/migrations/0087_cstinputs_inlet_temp_degf_cstinputs_outlet_temp_degf.py new file mode 100644 index 000000000..f2ac2ed53 --- /dev/null +++ b/reoptjl/migrations/0087_cstinputs_inlet_temp_degf_cstinputs_outlet_temp_degf.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.7 on 2025-05-07 18:54 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0086_alter_cstinputs_meta'), + ] + + operations = [ + migrations.AddField( + model_name='cstinputs', + name='inlet_temp_degF', + field=models.FloatField(blank=True, default=500, help_text="This is the temperature at which your process needs the heat transfer fluid specified above to be at when entering your facility. In other words, this is your 'hot' temperature.", validators=[django.core.validators.MinValueValidator(300), django.core.validators.MaxValueValidator(750)]), + ), + migrations.AddField( + model_name='cstinputs', + name='outlet_temp_degF', + field=models.FloatField(blank=True, default=400, help_text="This is the temperature at which your the heat transfer fluid specified above returns from your process after heat has been extracted. In other words, this is your cold' temperature. If you have an open system, the inlet temperature will be assumed to be ambient temperature (20 C / 68 F).", validators=[django.core.validators.MinValueValidator(300), django.core.validators.MaxValueValidator(750)]), + ), + ] diff --git a/reoptjl/migrations/0088_alter_cstinputs_acres_per_kw_and_more.py b/reoptjl/migrations/0088_alter_cstinputs_acres_per_kw_and_more.py new file mode 100644 index 000000000..62cff09b5 --- /dev/null +++ b/reoptjl/migrations/0088_alter_cstinputs_acres_per_kw_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 4.0.7 on 2025-05-08 16:45 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0087_cstinputs_inlet_temp_degf_cstinputs_outlet_temp_degf'), + ] + + operations = [ + migrations.AlterField( + model_name='cstinputs', + name='acres_per_kw', + field=models.FloatField(blank=True, default=0.000939, help_text='Power density for CST', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)]), + ), + migrations.AlterField( + model_name='cstinputs', + name='charge_storage_only', + field=models.BooleanField(blank=True, default=False, help_text='Boolean indicator if CST can only supply hot TES', null=True), + ), + migrations.AlterField( + model_name='cstinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=0.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='cstinputs', + name='om_cost_per_kw', + field=models.FloatField(blank=True, default=0.0, help_text='Annual CST operations and maintenance costs in $/kW', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)]), + ), + migrations.AlterField( + model_name='cstinputs', + name='om_cost_per_kwh', + field=models.FloatField(blank=True, default=0.0, help_text='Annual CST operations and maintenance costs in $/kWh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)]), + ), + ] diff --git a/reoptjl/migrations/0089_electricheateroutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py b/reoptjl/migrations/0089_electricheateroutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py new file mode 100644 index 000000000..768c14681 --- /dev/null +++ b/reoptjl/migrations/0089_electricheateroutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.7 on 2025-05-08 16:56 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0088_alter_cstinputs_acres_per_kw_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='electricheateroutputs', + name='thermal_to_hot_sensible_tes_series_mmbtu_per_hour', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None), + ), + ] diff --git a/reoptjl/migrations/0090_cstoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py b/reoptjl/migrations/0090_cstoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py new file mode 100644 index 000000000..09ab4516d --- /dev/null +++ b/reoptjl/migrations/0090_cstoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.7 on 2025-05-08 17:08 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0089_electricheateroutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour'), + ] + + operations = [ + migrations.AddField( + model_name='cstoutputs', + name='thermal_to_hot_sensible_tes_series_mmbtu_per_hour', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None), + ), + ] diff --git a/reoptjl/migrations/0091_cstoutputs_thermal_to_dhw_load_series_mmbtu_per_hour_and_more.py b/reoptjl/migrations/0091_cstoutputs_thermal_to_dhw_load_series_mmbtu_per_hour_and_more.py new file mode 100644 index 000000000..403067fff --- /dev/null +++ b/reoptjl/migrations/0091_cstoutputs_thermal_to_dhw_load_series_mmbtu_per_hour_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.0.7 on 2025-05-08 17:23 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0090_cstoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour'), + ] + + operations = [ + migrations.AddField( + model_name='cstoutputs', + name='thermal_to_dhw_load_series_mmbtu_per_hour', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None), + ), + migrations.AddField( + model_name='cstoutputs', + name='thermal_to_process_heat_load_series_mmbtu_per_hour', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None), + ), + migrations.AddField( + model_name='cstoutputs', + name='thermal_to_space_heating_load_series_mmbtu_per_hour', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None), + ), + ] diff --git a/reoptjl/migrations/0092_alter_cstoutputs_meta.py b/reoptjl/migrations/0092_alter_cstoutputs_meta.py new file mode 100644 index 000000000..d846fccb6 --- /dev/null +++ b/reoptjl/migrations/0092_alter_cstoutputs_meta.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.7 on 2025-05-08 18:28 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0091_cstoutputs_thermal_to_dhw_load_series_mmbtu_per_hour_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='cstoutputs', + name='meta', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='CSTOutputs', to='reoptjl.apimeta'), + ), + ] diff --git a/reoptjl/migrations/0093_alter_chpinputs_federal_itc_fraction_and_more.py b/reoptjl/migrations/0093_alter_chpinputs_federal_itc_fraction_and_more.py new file mode 100644 index 000000000..354937af6 --- /dev/null +++ b/reoptjl/migrations/0093_alter_chpinputs_federal_itc_fraction_and_more.py @@ -0,0 +1,124 @@ +# Generated by Django 4.0.7 on 2025-09-03 16:20 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0092_merge_20250613_0525'), + ] + + operations = [ + migrations.AlterField( + model_name='chpinputs', + name='federal_itc_fraction', + field=models.FloatField(blank=True, default=0.0, help_text='Percentage of capital costs that are credited towards federal taxes', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='chpinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=0.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='chpinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=0, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + migrations.AlterField( + model_name='coldthermalstorageinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='coldthermalstorageinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + migrations.AlterField( + model_name='financialinputs', + name='boiler_fuel_cost_escalation_rate_fraction', + field=models.FloatField(blank=True, default=0.0348, help_text='Annual nominal boiler fuel cost escalation rate', validators=[django.core.validators.MinValueValidator(-1), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='financialinputs', + name='chp_fuel_cost_escalation_rate_fraction', + field=models.FloatField(blank=True, default=0.0348, help_text='Annual nominal chp fuel cost escalation rate', validators=[django.core.validators.MinValueValidator(-1), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='financialinputs', + name='elec_cost_escalation_rate_fraction', + field=models.FloatField(blank=True, default=0.0166, help_text='Annual nominal utility electricity cost escalation rate.', validators=[django.core.validators.MinValueValidator(-1), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='financialinputs', + name='existing_boiler_fuel_cost_escalation_rate_fraction', + field=models.FloatField(blank=True, default=0.0348, help_text='Annual nominal existing boiler fuel cost escalation rate', validators=[django.core.validators.MinValueValidator(-1), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='financialinputs', + name='generator_fuel_cost_escalation_rate_fraction', + field=models.FloatField(blank=True, default=0.0197, help_text='Annual nominal boiler fuel cost escalation rate', validators=[django.core.validators.MinValueValidator(-1), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='financialinputs', + name='offtaker_discount_rate_fraction', + field=models.FloatField(blank=True, default=0.0624, help_text='Nominal energy offtaker discount rate. In single ownership model the offtaker is also the generation owner.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='financialinputs', + name='owner_discount_rate_fraction', + field=models.FloatField(blank=True, default=0.0624, help_text='Nominal generation owner discount rate. Used for two party financing model. In two party ownership model the offtaker does not own the generator(s).', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='generatorinputs', + name='fuel_cost_per_gallon', + field=models.FloatField(blank=True, default=2.25, help_text='Diesel cost in $/gallon', validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(100.0)]), + ), + migrations.AlterField( + model_name='ghpinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=0.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='ghpinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=0, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + migrations.AlterField( + model_name='hotthermalstorageinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='hotthermalstorageinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + migrations.AlterField( + model_name='pvinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='windinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='windinputs', + name='om_cost_per_kw', + field=models.FloatField(blank=True, default=42, help_text='Annual operations and maintenance costs in $/kW', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)]), + ), + ] diff --git a/reoptjl/migrations/0093_hotsensibletesinputs_hotsensibletesoutputs_and_more.py b/reoptjl/migrations/0093_hotsensibletesinputs_hotsensibletesoutputs_and_more.py new file mode 100644 index 000000000..04fcf6c17 --- /dev/null +++ b/reoptjl/migrations/0093_hotsensibletesinputs_hotsensibletesoutputs_and_more.py @@ -0,0 +1,68 @@ +# Generated by Django 4.0.7 on 2025-05-09 17:25 + +import django.contrib.postgres.fields +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import reoptjl.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0092_alter_cstoutputs_meta'), + ] + + operations = [ + migrations.CreateModel( + name='HotSensibleTESInputs', + fields=[ + ('meta', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='HotSensibleTESInputs', serialize=False, to='reoptjl.apimeta')), + ('min_kwh', models.FloatField(blank=True, default=0.0, help_text='Minimum TES volume (energy) size constraint for optimization', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('max_kwh', models.FloatField(blank=True, default=0.0, help_text='Maximum TES volume (energy) size constraint for optimization. Set to zero to disable storage', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('hot_temp_degF', models.FloatField(blank=True, default=1065.0, help_text='Hot-side supply water temperature from HotTES (top of tank) to the heating load', validators=[django.core.validators.MinValueValidator(200.0), django.core.validators.MaxValueValidator(2000.0)])), + ('cool_temp_degF', models.FloatField(blank=True, default=554.0, help_text='Cold-side return water temperature from the heating load to the HotTES (bottom of tank)', validators=[django.core.validators.MinValueValidator(200.0), django.core.validators.MaxValueValidator(2000.0)])), + ('internal_efficiency_fraction', models.FloatField(blank=True, default=0.999999, help_text='Thermal losses due to mixing from thermal power entering or leaving tank', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('soc_min_fraction', models.FloatField(blank=True, default=0.1, help_text='Minimum allowable battery state of charge as fraction of energy capacity.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('soc_init_fraction', models.FloatField(blank=True, default=0.5, help_text='Battery state of charge at first hour of optimization as fraction of energy capacity.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('installed_cost_per_kwh', models.FloatField(blank=True, default=1.5, help_text='Installed hot TES cost in $/kwh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('om_cost_per_kwh', models.FloatField(blank=True, default=0.0, help_text='Annual hot TES operations and maintenance costs in $/kwh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)])), + ('thermal_decay_rate_fraction', models.FloatField(blank=True, default=0.0004, help_text='Thermal energy-based cost of TES (e.g. volume of the tank)', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('macrs_option_years', models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=7, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable')), + ('macrs_bonus_fraction', models.FloatField(blank=True, default=0.6, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])), + ('macrs_itc_reduction', models.FloatField(blank=True, default=0.0, help_text='Percent of the ITC value by which depreciable basis is reduced', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])), + ('total_itc_fraction', models.FloatField(blank=True, default=0.3, help_text='Total investment tax credit in percent applied toward capital costs', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])), + ('total_rebate_per_kwh', models.FloatField(blank=True, default=0.0, help_text='Rebate per unit installed energy capacity', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('can_serve_dhw', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can serve space heating load', null=True)), + ('can_serve_space_heating', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can serve space heating load', null=True)), + ('can_serve_process_heat', models.BooleanField(blank=True, default=True, help_text='Boolean indicator if hot thermal storage can serve process heat load', null=True)), + ('supply_turbine_only', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can serve only steam turbine', null=True)), + ('one_direction_flow', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can only', null=True)), + ('num_charge_hours', models.FloatField(blank=True, default=4.0, help_text='Number of charge hours', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('num_discharge_hours', models.FloatField(blank=True, default=10.0, help_text='Number of charge hours', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ], + bases=(reoptjl.models.BaseModel, models.Model), + ), + migrations.CreateModel( + name='HotSensibleTESOutputs', + fields=[ + ('meta', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='HotSensibleTESOutputs', serialize=False, to='reoptjl.apimeta')), + ('size_gal', models.FloatField(blank=True, null=True)), + ('size_kwh', models.FloatField(blank=True, null=True)), + ('soc_series_fraction', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None)), + ('storage_to_load_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None)), + ('storage_to_turbine_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None)), + ], + bases=(reoptjl.models.BaseModel, models.Model), + ), + migrations.AddField( + model_name='hotthermalstorageoutputs', + name='size_kwh', + field=models.FloatField(blank=True, null=True), + ), + migrations.AddField( + model_name='hotthermalstorageoutputs', + name='storage_to_turbine_series_mmbtu_per_hour', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None), + ), + ] diff --git a/reoptjl/migrations/0094_alter_chpinputs_macrs_bonus_fraction_and_more.py b/reoptjl/migrations/0094_alter_chpinputs_macrs_bonus_fraction_and_more.py new file mode 100644 index 000000000..2af077603 --- /dev/null +++ b/reoptjl/migrations/0094_alter_chpinputs_macrs_bonus_fraction_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 4.0.7 on 2025-09-05 17:55 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0093_alter_chpinputs_federal_itc_fraction_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='chpinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='chpinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + migrations.AlterField( + model_name='steamturbineinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='steamturbineinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable', null=True), + ), + ] diff --git a/reoptjl/migrations/0094_alter_hotsensibletesinputs_meta_and_more.py b/reoptjl/migrations/0094_alter_hotsensibletesinputs_meta_and_more.py new file mode 100644 index 000000000..f44992aff --- /dev/null +++ b/reoptjl/migrations/0094_alter_hotsensibletesinputs_meta_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.7 on 2025-05-09 17:44 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0093_hotsensibletesinputs_hotsensibletesoutputs_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='hotsensibletesinputs', + name='meta', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='HotSensibleTesInputs', serialize=False, to='reoptjl.apimeta'), + ), + migrations.AlterField( + model_name='hotsensibletesoutputs', + name='meta', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='HotSensibleTesOutputs', serialize=False, to='reoptjl.apimeta'), + ), + ] diff --git a/reoptjl/migrations/0095_merge_20250729_1616.py b/reoptjl/migrations/0095_merge_20250729_1616.py new file mode 100644 index 000000000..fe7b9dcc7 --- /dev/null +++ b/reoptjl/migrations/0095_merge_20250729_1616.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-07-29 16:16 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0092_merge_20250613_0525'), + ('reoptjl', '0094_alter_hotsensibletesinputs_meta_and_more'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0095_merge_20250808_1803.py b/reoptjl/migrations/0095_merge_20250808_1803.py new file mode 100644 index 000000000..f89400f09 --- /dev/null +++ b/reoptjl/migrations/0095_merge_20250808_1803.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-08-08 18:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0092_merge_20250613_0525'), + ('reoptjl', '0094_alter_hotsensibletesinputs_meta_and_more'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0096_alter_cstinputs_inlet_temp_degf_and_more.py b/reoptjl/migrations/0096_alter_cstinputs_inlet_temp_degf_and_more.py new file mode 100644 index 000000000..0597152a5 --- /dev/null +++ b/reoptjl/migrations/0096_alter_cstinputs_inlet_temp_degf_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.7 on 2025-08-08 19:25 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0095_merge_20250729_1616'), + ] + + operations = [ + migrations.AlterField( + model_name='cstinputs', + name='inlet_temp_degF', + field=models.FloatField(blank=True, default=400, help_text="This is the temperature at which your process needs the heat transfer fluid specified above to be at when entering your facility. In other words, this is your 'hot' temperature.", validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(750)]), + ), + migrations.AlterField( + model_name='cstinputs', + name='outlet_temp_degF', + field=models.FloatField(blank=True, default=70, help_text="This is the temperature at which your the heat transfer fluid specified above returns from your process after heat has been extracted. In other words, this is your cold' temperature. If you have an open system, the inlet temperature will be assumed to be ambient temperature (20 C / 68 F).", validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(750)]), + ), + ] diff --git a/reoptjl/migrations/0097_merge_20250811_1817.py b/reoptjl/migrations/0097_merge_20250811_1817.py new file mode 100644 index 000000000..bae465fc1 --- /dev/null +++ b/reoptjl/migrations/0097_merge_20250811_1817.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-08-11 18:17 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0095_merge_20250808_1803'), + ('reoptjl', '0096_alter_cstinputs_inlet_temp_degf_and_more'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0098_alter_cstinputs_can_serve_dhw_and_more.py b/reoptjl/migrations/0098_alter_cstinputs_can_serve_dhw_and_more.py new file mode 100644 index 000000000..bd5fb5952 --- /dev/null +++ b/reoptjl/migrations/0098_alter_cstinputs_can_serve_dhw_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.0.7 on 2025-08-20 22:36 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0097_merge_20250811_1817'), + ] + + operations = [ + migrations.AlterField( + model_name='cstinputs', + name='can_serve_dhw', + field=models.BooleanField(blank=True, default=False, help_text='Boolean indicator if CST can serve hot water load', null=True), + ), + migrations.AlterField( + model_name='cstinputs', + name='can_serve_space_heating', + field=models.BooleanField(blank=True, default=False, help_text='Boolean indicator if CST can serve space heating load', null=True), + ), + migrations.AlterField( + model_name='cstinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=0.6, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + ] diff --git a/reoptjl/migrations/0098_steamturbineoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py b/reoptjl/migrations/0098_steamturbineoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py new file mode 100644 index 000000000..f98e7fc37 --- /dev/null +++ b/reoptjl/migrations/0098_steamturbineoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour.py @@ -0,0 +1,19 @@ +# Generated by Django 4.0.7 on 2025-08-18 17:57 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0097_merge_20250811_1817'), + ] + + operations = [ + migrations.AddField( + model_name='steamturbineoutputs', + name='thermal_to_hot_sensible_tes_series_mmbtu_per_hour', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, size=None), + ), + ] diff --git a/reoptjl/migrations/0099_merge_20250821_1548.py b/reoptjl/migrations/0099_merge_20250821_1548.py new file mode 100644 index 000000000..c485f61e1 --- /dev/null +++ b/reoptjl/migrations/0099_merge_20250821_1548.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-08-21 15:48 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0098_alter_cstinputs_can_serve_dhw_and_more'), + ('reoptjl', '0098_steamturbineoutputs_thermal_to_hot_sensible_tes_series_mmbtu_per_hour'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0100_hightempthermalstorageinputs_and_more.py b/reoptjl/migrations/0100_hightempthermalstorageinputs_and_more.py new file mode 100644 index 000000000..979aa50d1 --- /dev/null +++ b/reoptjl/migrations/0100_hightempthermalstorageinputs_and_more.py @@ -0,0 +1,101 @@ +# Generated by Django 4.0.7 on 2025-09-02 18:10 + +import django.contrib.postgres.fields +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import reoptjl.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0099_merge_20250821_1548'), + ] + + operations = [ + migrations.CreateModel( + name='HighTempThermalStorageInputs', + fields=[ + ('meta', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='HighTempThermalStorageInputs', serialize=False, to='reoptjl.apimeta')), + ('fluid', models.TextField(blank=True, default='INCOMP::NaK', help_text='Type of fluid for your High Temp Thermal Storage system')), + ('min_kwh', models.FloatField(blank=True, default=0.0, help_text='Minimum TES volume (energy) size constraint for optimization', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('max_kwh', models.FloatField(blank=True, default=0.0, help_text='Maximum TES volume (energy) size constraint for optimization. Set to zero to disable storage', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('hot_temp_degF', models.FloatField(blank=True, default=1065.0, help_text='Hot-side supply water temperature from HotTES (top of tank) to the heating load', validators=[django.core.validators.MinValueValidator(200.0), django.core.validators.MaxValueValidator(2000.0)])), + ('cool_temp_degF', models.FloatField(blank=True, default=554.0, help_text='Cold-side return water temperature from the heating load to the HotTES (bottom of tank)', validators=[django.core.validators.MinValueValidator(200.0), django.core.validators.MaxValueValidator(2000.0)])), + ('internal_efficiency_fraction', models.FloatField(blank=True, default=0.999999, help_text='Thermal losses due to mixing from thermal power entering or leaving tank', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('soc_min_fraction', models.FloatField(blank=True, default=0.1, help_text='Minimum allowable battery state of charge as fraction of energy capacity.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('soc_init_fraction', models.FloatField(blank=True, default=0.5, help_text='Battery state of charge at first hour of optimization as fraction of energy capacity.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('installed_cost_per_kwh', models.FloatField(blank=True, default=1.5, help_text='Installed hot TES cost in $/kwh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('om_cost_per_kwh', models.FloatField(blank=True, default=0.0, help_text='Annual hot TES operations and maintenance costs in $/kwh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)])), + ('thermal_decay_rate_fraction', models.FloatField(blank=True, default=0.0004, help_text='Thermal energy-based cost of TES (e.g. volume of the tank)', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1.0)])), + ('macrs_option_years', models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=7, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable')), + ('macrs_bonus_fraction', models.FloatField(blank=True, default=0.6, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])), + ('macrs_itc_reduction', models.FloatField(blank=True, default=0.0, help_text='Percent of the ITC value by which depreciable basis is reduced', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])), + ('total_itc_fraction', models.FloatField(blank=True, default=0.3, help_text='Total investment tax credit in percent applied toward capital costs', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)])), + ('total_rebate_per_kwh', models.FloatField(blank=True, default=0.0, help_text='Rebate per unit installed energy capacity', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)])), + ('can_serve_dhw', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can serve space heating load', null=True)), + ('can_serve_space_heating', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can serve space heating load', null=True)), + ('can_serve_process_heat', models.BooleanField(blank=True, default=True, help_text='Boolean indicator if hot thermal storage can serve process heat load', null=True)), + ('supply_turbine_only', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can serve only steam turbine', null=True)), + ('one_direction_flow', models.BooleanField(blank=True, default=False, help_text='Boolean indicator if hot thermal storage can only', null=True)), + ('num_charge_hours', models.FloatField(blank=True, default=4.0, help_text='Number of charge hours', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ('num_discharge_hours', models.FloatField(blank=True, default=10.0, help_text='Number of charge hours', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)])), + ], + bases=(reoptjl.models.BaseModel, models.Model), + ), + migrations.CreateModel( + name='HighTempThermalStorageOutputs', + fields=[ + ('meta', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='HighTempThermalStorageOutputs', serialize=False, to='reoptjl.apimeta')), + ('size_kwh', models.FloatField(blank=True, null=True)), + ('soc_series_fraction', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None)), + ('storage_to_load_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None)), + ('storage_to_turbine_series_mmbtu_per_hour', django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), default=list, size=None)), + ], + bases=(reoptjl.models.BaseModel, models.Model), + ), + migrations.RemoveField( + model_name='hotsensibletesoutputs', + name='meta', + ), + migrations.RenameField( + model_name='cstoutputs', + old_name='thermal_to_hot_sensible_tes_series_mmbtu_per_hour', + new_name='thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour', + ), + migrations.RenameField( + model_name='electricheateroutputs', + old_name='thermal_to_hot_sensible_tes_series_mmbtu_per_hour', + new_name='thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour', + ), + migrations.RenameField( + model_name='steamturbineoutputs', + old_name='thermal_to_hot_sensible_tes_series_mmbtu_per_hour', + new_name='thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour', + ), + migrations.RemoveField( + model_name='cstinputs', + name='capacity_factor_series', + ), + migrations.RemoveField( + model_name='cstoutputs', + name='thermal_to_hot_sensible_tes_storage_series_mmbtu_per_hour', + ), + migrations.AddField( + model_name='cstinputs', + name='production_factor', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, help_text='Optional user-defined production factors for CST.', size=None), + ), + migrations.AddField( + model_name='cstoutputs', + name='size_mmbtu_per_hour', + field=models.FloatField(blank=True, null=True), + ), + migrations.DeleteModel( + name='HotSensibleTESInputs', + ), + migrations.DeleteModel( + name='HotSensibleTESOutputs', + ), + ] diff --git a/reoptjl/migrations/0101_alter_hightempthermalstorageinputs_installed_cost_per_kwh_and_more.py b/reoptjl/migrations/0101_alter_hightempthermalstorageinputs_installed_cost_per_kwh_and_more.py new file mode 100644 index 000000000..4fca3fbb7 --- /dev/null +++ b/reoptjl/migrations/0101_alter_hightempthermalstorageinputs_installed_cost_per_kwh_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.0.7 on 2025-09-05 21:17 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0100_hightempthermalstorageinputs_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='hightempthermalstorageinputs', + name='installed_cost_per_kwh', + field=models.FloatField(blank=True, default=62, help_text='Installed hot TES cost in $/kwh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + migrations.AlterField( + model_name='hightempthermalstorageinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=1.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='hightempthermalstorageinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=5, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + ] diff --git a/reoptjl/migrations/0102_alter_cstinputs_installed_cost_per_kw_and_more.py b/reoptjl/migrations/0102_alter_cstinputs_installed_cost_per_kw_and_more.py new file mode 100644 index 000000000..bcf048a0b --- /dev/null +++ b/reoptjl/migrations/0102_alter_cstinputs_installed_cost_per_kw_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 4.0.7 on 2025-09-07 05:41 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0101_alter_hightempthermalstorageinputs_installed_cost_per_kwh_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='cstinputs', + name='installed_cost_per_kw', + field=models.FloatField(blank=True, default=2200.0, help_text='Installed CST cost in $/kW', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000.0)]), + ), + migrations.AlterField( + model_name='cstinputs', + name='macrs_bonus_fraction', + field=models.FloatField(blank=True, default=0.0, help_text='Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + migrations.AlterField( + model_name='cstinputs', + name='macrs_option_years', + field=models.IntegerField(blank=True, choices=[(0, 'Zero'), (5, 'Five'), (7, 'Seven')], default=0, help_text='Duration over which accelerated depreciation will occur. Set to zero to disable'), + ), + migrations.AlterField( + model_name='cstinputs', + name='om_cost_per_kw', + field=models.FloatField(blank=True, default=33.0, help_text='Annual CST operations and maintenance costs in $/kW', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000.0)]), + ), + migrations.AlterField( + model_name='hightempthermalstorageinputs', + name='installed_cost_per_kwh', + field=models.FloatField(blank=True, default=86.0, help_text='Installed hot TES cost in $/kwh', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10000.0)]), + ), + ] diff --git a/reoptjl/migrations/0103_merge_20250917_2157.py b/reoptjl/migrations/0103_merge_20250917_2157.py new file mode 100644 index 000000000..4b7773921 --- /dev/null +++ b/reoptjl/migrations/0103_merge_20250917_2157.py @@ -0,0 +1,14 @@ +# Generated by Django 4.0.7 on 2025-09-17 21:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0094_alter_chpinputs_macrs_bonus_fraction_and_more'), + ('reoptjl', '0102_alter_cstinputs_installed_cost_per_kw_and_more'), + ] + + operations = [ + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index 2d48782ea..8472bd177 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -76,10 +76,10 @@ class MACRS_YEARS_CHOICES(models.IntegerChoices): } WIND_COST_DEFAULTS = { # size_class_to_installed_cost - "residential" : 6339.0, - "commercial" : 4760.0, - "medium" : 3137.0, - "large" : 2386.0 + "residential" : 7692.0, + "commercial" : 5776.0, + "medium" : 3807.0, + "large" : 2896.0 } def at_least_one_set(model, possible_sets): @@ -677,7 +677,7 @@ class FinancialInputs(BaseModel, models.Model): help_text="Analysis period in years. Must be integer." ) elec_cost_escalation_rate_fraction = models.FloatField( - default=0.017, + default=0.0166, validators=[ MinValueValidator(-1), MaxValueValidator(1) @@ -686,7 +686,7 @@ class FinancialInputs(BaseModel, models.Model): help_text="Annual nominal utility electricity cost escalation rate." ) offtaker_discount_rate_fraction = models.FloatField( - default=0.0638, + default=0.0624, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -714,7 +714,7 @@ class FinancialInputs(BaseModel, models.Model): help_text="Annual nominal O&M cost escalation rate" ) owner_discount_rate_fraction = models.FloatField( - default=0.0638, + default=0.0624, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -906,7 +906,7 @@ class FinancialInputs(BaseModel, models.Model): help_text=("Annual nominal escalation rate of the public health cost of 1 tonne of PM2.5 emissions (as a decimal). The default value is calculated from the EASIUR model for a height of 150m.") ) generator_fuel_cost_escalation_rate_fraction = models.FloatField( - default=0.012, + default=0.0197, validators=[ MinValueValidator(-1), MaxValueValidator(1) @@ -915,7 +915,7 @@ class FinancialInputs(BaseModel, models.Model): help_text=("Annual nominal boiler fuel cost escalation rate") ) existing_boiler_fuel_cost_escalation_rate_fraction = models.FloatField( - default=0.015, + default=0.0348, validators=[ MinValueValidator(-1), MaxValueValidator(1) @@ -924,7 +924,7 @@ class FinancialInputs(BaseModel, models.Model): help_text=("Annual nominal existing boiler fuel cost escalation rate") ) boiler_fuel_cost_escalation_rate_fraction = models.FloatField( - default=0.015, + default=0.0348, validators=[ MinValueValidator(-1), MaxValueValidator(1) @@ -933,7 +933,7 @@ class FinancialInputs(BaseModel, models.Model): help_text=("Annual nominal boiler fuel cost escalation rate") ) chp_fuel_cost_escalation_rate_fraction = models.FloatField( - default=0.015, + default=0.0348, validators=[ MinValueValidator(-1), MaxValueValidator(1) @@ -2785,7 +2785,7 @@ class PV_LOCATION_CHOICES(models.TextChoices): help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" ) macrs_bonus_fraction = models.FloatField( - default=0.6, + default=1.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -3214,7 +3214,7 @@ class WIND_SIZE_CLASS_CHOICES(models.TextChoices): help_text="Installed cost in $/kW. Default cost is determined based on size_class." ) om_cost_per_kw = models.FloatField( - default=36, + default=42, validators=[ MinValueValidator(0), MaxValueValidator(1.0e3) @@ -3229,7 +3229,7 @@ class WIND_SIZE_CLASS_CHOICES(models.TextChoices): help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" ) macrs_bonus_fraction = models.FloatField( - default=0.6, + default=1.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -3642,13 +3642,13 @@ class ElectricStorageInputs(BaseModel, models.Model): help_text="Annual O&M cost as a fraction of installed cost." ) macrs_option_years = models.IntegerField( - default=MACRS_YEARS_CHOICES.SEVEN, + default=MACRS_YEARS_CHOICES.FIVE, choices=MACRS_YEARS_CHOICES.choices, blank=True, help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" ) macrs_bonus_fraction = models.FloatField( - default=0.6, + default=1.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -3809,7 +3809,7 @@ class GeneratorInputs(BaseModel, models.Model): help_text="Diesel generator per unit production (variable) operations and maintenance costs in $/kWh" ) fuel_cost_per_gallon = models.FloatField( - default=3.0, + default=2.25, validators=[ MinValueValidator(0.0), MaxValueValidator(1.0e2) @@ -4438,7 +4438,7 @@ class CHPInputs(BaseModel, models.Model): help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" ) macrs_bonus_fraction = models.FloatField( - default=0.6, + default=1.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -4456,7 +4456,7 @@ class CHPInputs(BaseModel, models.Model): help_text="Percent of the ITC value by which depreciable basis is reduced" ) federal_itc_fraction = models.FloatField( - default=0.3, + default=0.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -5617,6 +5617,11 @@ class ElectricHeaterOutputs(BaseModel, models.Model): default = list ) + thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default = list + ) + class ASHPSpaceHeaterInputs(BaseModel, models.Model): key = "ASHPSpaceHeater" meta = models.OneToOneField( @@ -6693,7 +6698,7 @@ class SIZE_CLASS_LIST(models.IntegerChoices): ) macrs_option_years = models.IntegerField( - default=MACRS_YEARS_CHOICES.ZERO, + default=MACRS_YEARS_CHOICES.FIVE, choices=MACRS_YEARS_CHOICES.choices, null=True, blank=True, @@ -6701,7 +6706,7 @@ class SIZE_CLASS_LIST(models.IntegerChoices): ) macrs_bonus_fraction = models.FloatField( - default=0.0, + default=1.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -6792,6 +6797,11 @@ class SteamTurbineOutputs(BaseModel, models.Model): default = list ) + thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + blank=True, default=list + ) + class HotThermalStorageInputs(BaseModel, models.Model): key = "HotThermalStorage" @@ -6894,13 +6904,13 @@ class HotThermalStorageInputs(BaseModel, models.Model): help_text="Thermal energy-based cost of TES (e.g. volume of the tank)" ) macrs_option_years = models.IntegerField( - default=MACRS_YEARS_CHOICES.SEVEN, + default=MACRS_YEARS_CHOICES.FIVE, choices=MACRS_YEARS_CHOICES.choices, blank=True, help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" ) macrs_bonus_fraction = models.FloatField( - default=0.6, + default=1.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -6969,6 +6979,7 @@ class HotThermalStorageOutputs(BaseModel, models.Model): primary_key=True ) size_gal = models.FloatField(null=True, blank=True) + size_kwh = models.FloatField(null=True, blank=True) soc_series_fraction = ArrayField( models.FloatField(null=True, blank=True), default = list, @@ -6991,11 +7002,236 @@ class HotThermalStorageOutputs(BaseModel, models.Model): models.FloatField(null=True, blank=True), default = list ) + storage_to_turbine_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default = list + ) def clean(self): # perform custom validation here. pass +class HighTempThermalStorageInputs(BaseModel, models.Model): + key = "HighTempThermalStorage" + + meta = models.OneToOneField( + APIMeta, + on_delete=models.CASCADE, + related_name="HighTempThermalStorageInputs", + primary_key=True + ) + fluid = models.TextField( + blank=True, + default="INCOMP::NaK", + help_text="Type of fluid for your High Temp Thermal Storage system" + ) + + min_kwh = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e9) + ], + null=True, + blank=True, + default=0.0, + help_text="Minimum TES volume (energy) size constraint for optimization" + ) + max_kwh = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e9) + ], + blank=True, + default=0.0, + help_text="Maximum TES volume (energy) size constraint for optimization. Set to zero to disable storage" + ) + hot_temp_degF = models.FloatField( + validators=[ + MinValueValidator(200.0), + MaxValueValidator(2000.0) + ], + blank=True, + default=1065.0, + help_text="Hot-side supply water temperature from HotTES (top of tank) to the heating load" + ) + cool_temp_degF = models.FloatField( + validators=[ + MinValueValidator(200.0), + MaxValueValidator(2000.0) + ], + blank=True, + default=554.0, + help_text="Cold-side return water temperature from the heating load to the HotTES (bottom of tank)" + ) + internal_efficiency_fraction = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0) + ], + blank=True, + default=0.999999, + help_text="Thermal losses due to mixing from thermal power entering or leaving tank" + ) + soc_min_fraction = models.FloatField( + default=0.1, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0) + ], + blank=True, + help_text="Minimum allowable battery state of charge as fraction of energy capacity." + ) + soc_init_fraction = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0) + ], + default=0.5, + blank=True, + help_text="Battery state of charge at first hour of optimization as fraction of energy capacity." + ) + installed_cost_per_kwh = models.FloatField( + default=86.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e4) + ], + blank=True, + help_text="Installed hot TES cost in $/kwh" + ) + om_cost_per_kwh = models.FloatField( + default=0.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e3) + ], + blank=True, + help_text="Annual hot TES operations and maintenance costs in $/kwh" + ) + thermal_decay_rate_fraction = models.FloatField( + default=0.0004, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0) + ], + blank=True, + help_text="Thermal energy-based cost of TES (e.g. volume of the tank)" + ) + macrs_option_years = models.IntegerField( + default=MACRS_YEARS_CHOICES.FIVE, + choices=MACRS_YEARS_CHOICES.choices, + blank=True, + help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" + ) + macrs_bonus_fraction = models.FloatField( + default=1.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1) + ], + blank=True, + help_text="Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation" + ) + macrs_itc_reduction = models.FloatField( + default=0.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1) + ], + blank=True, + help_text="Percent of the ITC value by which depreciable basis is reduced" + ) + total_itc_fraction = models.FloatField( + default=0.3, + validators=[ + MinValueValidator(0), + MaxValueValidator(1) + ], + blank=True, + help_text="Total investment tax credit in percent applied toward capital costs" + ) + total_rebate_per_kwh = models.FloatField( + default=0.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e9) + ], + blank=True, + help_text="Rebate per unit installed energy capacity" + ) + can_serve_dhw = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if hot thermal storage can serve space heating load" + ) + can_serve_space_heating = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if hot thermal storage can serve space heating load" + ) + can_serve_process_heat = models.BooleanField( + default=True, + null=True, + blank=True, + help_text="Boolean indicator if hot thermal storage can serve process heat load" + ) + supply_turbine_only = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if hot thermal storage can serve only steam turbine" + ) + one_direction_flow = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if hot thermal storage can only" + ) + num_charge_hours = models.FloatField( + default=4.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1e4) + ], + blank=True, + help_text="Number of charge hours" + ) + num_discharge_hours = models.FloatField( + default=10.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1e4) + ], + blank=True, + help_text="Number of charge hours" + ) + +class HighTempThermalStorageOutputs(BaseModel, models.Model): + key = "HighTempThermalStorageOutputs" + + meta = models.OneToOneField( + APIMeta, + on_delete=models.CASCADE, + related_name="HighTempThermalStorageOutputs", + primary_key=True + ) + size_kwh = models.FloatField(null=True, blank=True) + soc_series_fraction = ArrayField( + models.FloatField(null=True, blank=True), + default = list, + ) + storage_to_load_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default = list, + ) + storage_to_turbine_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default = list + ) + + class ColdThermalStorageInputs(BaseModel, models.Model): key = "ColdThermalStorage" @@ -7098,13 +7334,13 @@ class ColdThermalStorageInputs(BaseModel, models.Model): help_text="Thermal energy-based cost of TES (e.g. volume of the tank)" ) macrs_option_years = models.IntegerField( - default=MACRS_YEARS_CHOICES.SEVEN, + default=MACRS_YEARS_CHOICES.FIVE, choices=MACRS_YEARS_CHOICES.choices, blank=True, help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" ) macrs_bonus_fraction = models.FloatField( - default=0.6, + default=1.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -8399,13 +8635,13 @@ class GHPInputs(BaseModel, models.Model): ) macrs_option_years = models.IntegerField( - default=MACRS_YEARS_CHOICES.FIVE, + default=MACRS_YEARS_CHOICES.ZERO, choices=MACRS_YEARS_CHOICES.choices, blank=True, help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" ) macrs_bonus_fraction = models.FloatField( - default=0.6, + default=0.0, validators=[ MinValueValidator(0), MaxValueValidator(1) @@ -8584,6 +8820,243 @@ class GHPOutputs(BaseModel, models.Model): annual_thermal_production_mmbtu = models.FloatField(null=True, blank=True) annual_thermal_production_tonhour = models.FloatField(null=True, blank=True) + +class CSTInputs(BaseModel, models.Model): + key = "CST" + meta = models.OneToOneField( + to=APIMeta, + on_delete=models.CASCADE, + related_name="CSTInputs", + unique=False + ) + + tech_type = models.TextField( + blank=True, + default="ptc", + help_text="Type of CST you want to implement into your system" + ) + min_kw = models.FloatField( + default=0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e9) + ], + blank=True, + help_text="Minimum CST size constraint for optimization." + ) + max_kw = models.FloatField( + default=1.0e9, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e9) + ], + blank=True, + help_text="Maximum CST size constraint for optimization (upper bound on additional capacity beyond existing_kw). Set to zero to disable PV" + ) + inlet_temp_degF = models.FloatField( + default=400, + validators=[ + MinValueValidator(0), + MaxValueValidator(750) + ], + blank=True, + help_text="This is the temperature at which your process needs the heat transfer fluid specified above to be at when entering your facility. In other words, this is your 'hot' temperature." + ) + outlet_temp_degF = models.FloatField( + default=70, + validators=[ + MinValueValidator(0), + MaxValueValidator(750) + ], + blank=True, + help_text="This is the temperature at which your the heat transfer fluid specified above returns from your process after heat has been extracted. In other words, this is your cold' temperature. If you have an open system, the inlet temperature will be assumed to be ambient temperature (20 C / 68 F)." + ) + acres_per_kw = models.FloatField( + default=0.000939, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e3) + ], + blank=True, + help_text="Power density for CST" + ) + installed_cost_per_kw = models.FloatField( + default=2200.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e5) + ], + blank=True, + help_text="Installed CST cost in $/kW" + ) + om_cost_per_kw = models.FloatField( + default=33.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e3) + ], + blank=True, + help_text="Annual CST operations and maintenance costs in $/kW" + ) + om_cost_per_kwh = models.FloatField( + default=0.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e3) + ], + blank=True, + help_text="Annual CST operations and maintenance costs in $/kWh" + ) + macrs_option_years = models.IntegerField( + default=MACRS_YEARS_CHOICES.ZERO, + choices=MACRS_YEARS_CHOICES.choices, + blank=True, + help_text="Duration over which accelerated depreciation will occur. Set to zero to disable" + ) + macrs_bonus_fraction = models.FloatField( + default=0.0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1) + ], + blank=True, + help_text="Percent of upfront project costs to depreciate in year one in addition to scheduled depreciation" + ) + production_factor = ArrayField( + models.FloatField( + blank=True + ), + default=list, blank=True, + help_text=("Optional user-defined production factors for CST.") + ) + elec_consumption_factor_series = ArrayField( + models.FloatField( + blank=True + ), + default=list, blank=True, + help_text=("Optional user-defined electricity consumption factors for CST.") + ) + can_supply_steam_turbine = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if CST can supply steam to the steam turbine for electric production" + ) + can_serve_dhw = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if CST can serve hot water load" + ) + can_serve_space_heating = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if CST can serve space heating load" + ) + can_serve_process_heat = models.BooleanField( + default=True, + null=True, + blank=True, + help_text="Boolean indicator if CST can serve process heat load" + ) + charge_storage_only = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if CST can only supply hot TES" + ) + emissions_factor_lb_CO2_per_mmbtu = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1e4) + ], + blank=True, + null=True, + help_text="Pounds of CO2 emitted per MMBTU of fuel burned." + ) + emissions_factor_lb_NOx_per_mmbtu = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1e4) + ], + blank=True, + null=True, + help_text="Pounds of CO2 emitted per MMBTU of fuel burned." + ) + emissions_factor_lb_SO2_per_mmbtu = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1e4) + ], + blank=True, + null=True, + help_text="Pounds of CO2 emitted per MMBTU of fuel burned." + ) + emissions_factor_lb_PM25_per_mmbtu = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1e4) + ], + blank=True, + null=True, + help_text="Pounds of CO2 emitted per MMBTU of fuel burned." + ) + +class CSTOutputs(BaseModel, models.Model): + key = "CSTOutputs" + meta = models.OneToOneField( + to=APIMeta, + on_delete=models.CASCADE, + related_name="CSTOutputs", + unique=False + ) + size_kw = models.FloatField(null=True, blank=True) + size_mmbtu_per_hour = models.FloatField(null=True, blank=True) + annual_electric_consumption_kwh = models.FloatField(null=True, blank=True) + annual_thermal_production_mmbtu = models.FloatField(null=True, blank=True) + thermal_production_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default=list, blank=True + ) + electric_consumption_series_kw = ArrayField( + models.FloatField(null=True, blank=True), + default=list, blank=True + ) + thermal_to_storage_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + blank=True, default=list + ) + thermal_to_high_temp_thermal_storage_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + blank=True, default=list + ) + thermal_to_steamturbine_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + blank=True, default=list + ) + thermal_curtailed_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + blank=True, default=list + ) + thermal_to_load_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default=list, blank=True + ) + thermal_to_dhw_load_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default=list, blank=True + ) + thermal_to_space_heating_load_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default = list + ) + thermal_to_process_heat_load_series_mmbtu_per_hour = ArrayField( + models.FloatField(null=True, blank=True), + default = list + ) + + def get_input_dict_from_run_uuid(run_uuid:str): """ Construct the input dict for REopt.run_reopt @@ -8658,6 +9131,9 @@ def filter_none_and_empty_array(d:dict): try: d["HotThermalStorage"] = filter_none_and_empty_array(meta.HotThermalStorageInputs.dict) except: pass + try: d["HighTempThermalStorage"] = filter_none_and_empty_array(meta.HighTempThermalStorageInputs.dict) + except: pass + try: d["ColdThermalStorage"] = filter_none_and_empty_array(meta.ColdThermalStorageInputs.dict) except: pass @@ -8682,6 +9158,10 @@ def filter_none_and_empty_array(d:dict): try: d["ASHPWaterHeater"] = filter_none_and_empty_array(meta.ASHPWaterHeaterInputs.dict) except: pass + try: d["CST"] = filter_none_and_empty_array(meta.CSTInputs.dict) + except: pass + + return d ''' diff --git a/reoptjl/src/process_results.py b/reoptjl/src/process_results.py index eee8c1942..c1faad9e7 100644 --- a/reoptjl/src/process_results.py +++ b/reoptjl/src/process_results.py @@ -8,7 +8,8 @@ REoptjlMessageOutputs, AbsorptionChillerOutputs, BoilerOutputs, SteamTurbineInputs, \ SteamTurbineOutputs, GHPInputs, GHPOutputs, ExistingChillerInputs, \ ElectricHeaterOutputs, ASHPSpaceHeaterOutputs, ASHPWaterHeaterOutputs, \ - SiteInputs, ASHPSpaceHeaterInputs, ASHPWaterHeaterInputs, PVInputs + SiteInputs, ASHPSpaceHeaterInputs, ASHPWaterHeaterInputs, CSTInputs, CSTOutputs, PVInputs, \ + HighTempThermalStorageInputs, HighTempThermalStorageOutputs import numpy as np import sys import traceback as tb @@ -90,6 +91,10 @@ def process_results(results: dict, run_uuid: str) -> None: ASHPSpaceHeaterOutputs.create(meta=meta, **results["ASHPSpaceHeater"]).save() if "ASHPWaterHeater" in results.keys(): ASHPWaterHeaterOutputs.create(meta=meta, **results["ASHPWaterHeater"]).save() + if "CST" in results.keys(): + CSTOutputs.create(meta=meta, **results["CST"]).save() + if "HighTempThermalStorage" in results.keys(): + HighTempThermalStorageOutputs.create(meta=meta, **results["HighTempThermalStorage"]).save() # TODO process rest of results except Exception as e: exc_type, exc_value, exc_traceback = sys.exc_info() @@ -131,7 +136,6 @@ def update_inputs_in_database(inputs_to_update: dict, run_uuid: str) -> None: CHPInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["CHP"]) if inputs_to_update["SteamTurbine"]: # Will be an empty dictionary if SteamTurbine is not considered SteamTurbineInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["SteamTurbine"]) - if inputs_to_update["GHP"]: GHPInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["GHP"]) if inputs_to_update["ExistingChiller"]: @@ -148,7 +152,14 @@ def update_inputs_in_database(inputs_to_update: dict, run_uuid: str) -> None: ASHPWaterHeaterInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["ASHPWaterHeater"]) if inputs_to_update["PV"]: prune_update_fields(PVInputs, inputs_to_update["PV"]) - PVInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["PV"]) + PVInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["PV"]) + # TODO CST is not added to this inputs_with_defaults_set_in_julia dictionary in http.jl, IF we need to update any CST inputs + if inputs_to_update.get("CST") is not None: + prune_update_fields(CSTInputs, inputs_to_update["CST"]) + CSTInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["CST"]) + if inputs_to_update.get("HighTempThermalStorage") is not None: + prune_update_fields(HighTempThermalStorageInputs, inputs_to_update["HighTempThermalStorage"]) + HighTempThermalStorageInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["HighTempThermalStorage"]) except Exception as e: exc_type, exc_value, exc_traceback = sys.exc_info() debug_msg = "exc_type: {}; exc_value: {}; exc_traceback: {}".format( diff --git a/reoptjl/test/posts/outage.json b/reoptjl/test/posts/outage.json index 5658437c5..b7a501c47 100644 --- a/reoptjl/test/posts/outage.json +++ b/reoptjl/test/posts/outage.json @@ -34,7 +34,8 @@ "min_kw": 150.0, "max_kw": 150.0, "macrs_bonus_fraction": 0.8, - "macrs_option_years": 0 + "macrs_option_years": 0, + "federal_itc_fraction": 0.3 }, "PV": { "min_kw": 282.3629, diff --git a/reoptjl/test/test_http_endpoints.py b/reoptjl/test/test_http_endpoints.py index 8104a6197..14771a2c3 100644 --- a/reoptjl/test/test_http_endpoints.py +++ b/reoptjl/test/test_http_endpoints.py @@ -35,7 +35,7 @@ def test_chp_defaults(self): self.assertEqual(http_response["prime_mover"], "combustion_turbine") self.assertEqual(http_response["size_class"], 2) self.assertGreater(http_response["chp_elec_size_heuristic_kw"], 3500.0) - self.assertEqual(http_response["default_inputs"]["federal_itc_fraction"], 0.3) + self.assertEqual(http_response["default_inputs"]["federal_itc_fraction"], 0.0) inputs = { "prime_mover": "micro_turbine", @@ -50,7 +50,7 @@ def test_chp_defaults(self): http_response = response.json() # Check the endpoint logic with the expected selection - self.assertEqual(http_response["default_inputs"]["federal_itc_fraction"], 0.3) + self.assertEqual(http_response["default_inputs"]["federal_itc_fraction"], 0.0) inputs = { "prime_mover": "combustion_turbine", diff --git a/reoptjl/test/test_validator.py b/reoptjl/test/test_validator.py index 8e0c1c6d3..2e9d5c24b 100644 --- a/reoptjl/test/test_validator.py +++ b/reoptjl/test/test_validator.py @@ -102,7 +102,7 @@ def test_off_grid_defaults_overrides(self): self.assertAlmostEqual(validator.models["Wind"].operating_reserve_required_fraction, 0.5) self.assertAlmostEqual(validator.models["PV"].operating_reserve_required_fraction, 0.25) - self.assertEqual(validator.models["Wind"].installed_cost_per_kw, 4760.0) # set based on size_class + self.assertEqual(validator.models["Wind"].installed_cost_per_kw, 5776.0) # set based on size_class (commercial) self.assertAlmostEqual(validator.models["ElectricLoad"].operating_reserve_required_fraction, 0.1) self.assertAlmostEqual(validator.models["ElectricLoad"].critical_load_fraction, 1.0) diff --git a/reoptjl/validators.py b/reoptjl/validators.py index a65a60b02..306814dd8 100644 --- a/reoptjl/validators.py +++ b/reoptjl/validators.py @@ -2,10 +2,10 @@ import logging import pandas as pd from reoptjl.models import MAX_BIG_NUMBER, APIMeta, ExistingBoilerInputs, UserProvidedMeta, SiteInputs, Settings, ElectricLoadInputs, ElectricTariffInputs, \ - FinancialInputs, BaseModel, Message, ElectricUtilityInputs, PVInputs, ElectricStorageInputs, GeneratorInputs, WindInputs, SpaceHeatingLoadInputs, \ + FinancialInputs, BaseModel, Message, ElectricUtilityInputs, PVInputs, CSTInputs, ElectricStorageInputs, GeneratorInputs, WindInputs, SpaceHeatingLoadInputs, \ DomesticHotWaterLoadInputs, CHPInputs, CoolingLoadInputs, ExistingChillerInputs, HotThermalStorageInputs, ColdThermalStorageInputs, \ AbsorptionChillerInputs, BoilerInputs, SteamTurbineInputs, GHPInputs, ProcessHeatLoadInputs, ElectricHeaterInputs, ASHPSpaceHeaterInputs, \ - ASHPWaterHeaterInputs + ASHPWaterHeaterInputs, HighTempThermalStorageInputs from django.core.exceptions import ValidationError from pyproj import Proj from typing import Tuple @@ -77,6 +77,7 @@ def __init__(self, raw_inputs: dict, ghpghx_inputs_validation_errors=None): CHPInputs, BoilerInputs, HotThermalStorageInputs, + HighTempThermalStorageInputs, ColdThermalStorageInputs, AbsorptionChillerInputs, SteamTurbineInputs, @@ -84,7 +85,8 @@ def __init__(self, raw_inputs: dict, ghpghx_inputs_validation_errors=None): ProcessHeatLoadInputs, ElectricHeaterInputs, ASHPSpaceHeaterInputs, - ASHPWaterHeaterInputs + ASHPWaterHeaterInputs, + CSTInputs ) self.pvnames = [] on_grid_required_object_names = [ diff --git a/reoptjl/views.py b/reoptjl/views.py index 28b4cab9b..e00a77660 100644 --- a/reoptjl/views.py +++ b/reoptjl/views.py @@ -17,7 +17,8 @@ ColdThermalStorageInputs, ColdThermalStorageOutputs, AbsorptionChillerInputs, AbsorptionChillerOutputs,\ FinancialInputs, FinancialOutputs, UserUnlinkedRuns, BoilerInputs, BoilerOutputs, SteamTurbineInputs, \ SteamTurbineOutputs, GHPInputs, GHPOutputs, ProcessHeatLoadInputs, ElectricHeaterInputs, ElectricHeaterOutputs, \ - ASHPSpaceHeaterInputs, ASHPSpaceHeaterOutputs, ASHPWaterHeaterInputs, ASHPWaterHeaterOutputs, PortfolioUnlinkedRuns + ASHPSpaceHeaterInputs, ASHPSpaceHeaterOutputs, ASHPWaterHeaterInputs, ASHPWaterHeaterOutputs, PortfolioUnlinkedRuns, \ + CSTInputs, CSTOutputs, HighTempThermalStorageInputs, HighTempThermalStorageOutputs import os import requests @@ -70,6 +71,7 @@ def help(request): d["ExistingBoiler"] = ExistingBoilerInputs.info_dict(ExistingBoilerInputs) d["Boiler"] = BoilerInputs.info_dict(BoilerInputs) d["HotThermalStorage"] = HotThermalStorageInputs.info_dict(HotThermalStorageInputs) + d["HighTempThermalStorage"] = HighTempThermalStorageInputs.info_dict(HighTempThermalStorageInputs) d["ColdThermalStorage"] = ColdThermalStorageInputs.info_dict(ColdThermalStorageInputs) d["SpaceHeatingLoad"] = SpaceHeatingLoadInputs.info_dict(SpaceHeatingLoadInputs) d["DomesticHotWaterLoad"] = DomesticHotWaterLoadInputs.info_dict(DomesticHotWaterLoadInputs) @@ -82,6 +84,7 @@ def help(request): d["ElectricHeater"] = ElectricHeaterInputs.info_dict(ElectricHeaterInputs) d["ASHPSpaceHeater"] = ASHPSpaceHeaterInputs.info_dict(ASHPSpaceHeaterInputs) d["ASHPWaterHeater"] = ASHPWaterHeaterInputs.info_dict(ASHPWaterHeaterInputs) + d["CST"] = CSTInputs.info_dict(CSTInputs) return JsonResponse(d) @@ -121,6 +124,7 @@ def outputs(request): d["ExistingBoiler"] = ExistingBoilerOutputs.info_dict(ExistingBoilerOutputs) d["Boiler"] = BoilerOutputs.info_dict(BoilerOutputs) d["HotThermalStorage"] = HotThermalStorageOutputs.info_dict(HotThermalStorageOutputs) + d["HighTempThermalStorage"] = HighTempThermalStorageOutputs.info_dict(HighTempThermalStorageOutputs) d["ColdThermalStorage"] = ColdThermalStorageOutputs.info_dict(ColdThermalStorageOutputs) d["Site"] = SiteOutputs.info_dict(SiteOutputs) d["HeatingLoad"] = HeatingLoadOutputs.info_dict(HeatingLoadOutputs) @@ -133,6 +137,8 @@ def outputs(request): d["ASHPWaterHeater"] = ASHPWaterHeaterOutputs.info_dict(ASHPWaterHeaterOutputs) d["Messages"] = REoptjlMessageOutputs.info_dict(REoptjlMessageOutputs) d["SteamTurbine"] = SteamTurbineOutputs.info_dict(SteamTurbineOutputs) + d["CST"] = CSTOutputs.info_dict(CSTOutputs) + return JsonResponse(d) except Exception as e: @@ -222,7 +228,7 @@ def results(request, run_uuid): try: r["inputs"]["ExistingChiller"] = meta.ExistingChillerInputs.dict except: pass - + try: r["inputs"]["ExistingBoiler"] = meta.ExistingBoilerInputs.dict except: pass @@ -232,6 +238,9 @@ def results(request, run_uuid): try: r["inputs"]["HotThermalStorage"] = meta.HotThermalStorageInputs.dict except: pass + try: r["inputs"]["HighTempThermalStorage"] = meta.HighTempThermalStorageInputs.dict + except: pass + try: r["inputs"]["ColdThermalStorage"] = meta.ColdThermalStorageInputs.dict except: pass @@ -265,6 +274,9 @@ def results(request, run_uuid): try: r["inputs"]["ASHPWaterHeater"] = meta.ASHPWaterHeaterInputs.dict except: pass + try: r["inputs"]["CST"] = meta.CSTInputs.dict + except: pass + try: r["outputs"] = dict() r["messages"] = dict() @@ -323,6 +335,8 @@ def results(request, run_uuid): try: r["outputs"]["HotThermalStorage"] = meta.HotThermalStorageOutputs.dict except: pass + try: r["outputs"]["HighTempThermalStorage"] = meta.HighTempThermalStorageOutputs.dict + except: pass try: r["outputs"]["ColdThermalStorage"] = meta.ColdThermalStorageOutputs.dict except: pass try: r["outputs"]["CHP"] = meta.CHPOutputs.dict @@ -343,6 +357,8 @@ def results(request, run_uuid): except: pass try: r["outputs"]["ASHPWaterHeater"] = meta.ASHPWaterHeaterOutputs.dict except: pass + try: r["outputs"]["CST"] = meta.CSTOutputs.dict + except: pass for d in r["outputs"].values(): if isinstance(d, dict): @@ -943,7 +959,9 @@ def summary(request, user_uuid): "wind_kw", # Wind Size (kW) "gen_kw", # Generator Size (kW) "batt_kw", # Battery Power (kW) - "batt_kwh" # Battery Capacity (kWh) + "batt_kwh", # Battery Capacity (kWh) + "cst_kw", # CST Size (kW) + "hightemptes_kwh" # High Temp TES Capacity (kWh) "" }] } @@ -1087,7 +1105,7 @@ def summary_by_chunk(request, user_uuid, chunk): def create_summary_dict(user_uuid:str,summary_dict:dict): # if these keys are missing from a `scenario` we add 0s for them, all Floats. - optional_keys = ["npv_us_dollars", "net_capital_costs", "year_one_savings_us_dollars", "pv_kw", "wind_kw", "gen_kw", "batt_kw", "batt_kwh"] + optional_keys = ["npv_us_dollars", "net_capital_costs", "year_one_savings_us_dollars", "pv_kw", "wind_kw", "gen_kw", "batt_kw", "batt_kwh", "cst_kw", "hightemptes_kwh"] # Create eventual response dictionary return_dict = dict() @@ -1308,6 +1326,22 @@ def queryset_for_summary(api_metas,summary_dict:dict): for m in gen: summary_dict[str(m.meta.run_uuid)]['gen_kw'] = m.size_kw + cst = CSTOutputs.objects.filter(meta__run_uuid__in=run_uuids).only( + 'meta__run_uuid', + 'size_kw' + ) + if len(cst) > 0: + for m in cst: + summary_dict[str(m.meta.run_uuid)]['cst_kw'] = m.size_kw + + hightemptes = HighTempThermalStorageOutputs.objects.filter(meta__run_uuid__in=run_uuids).only( + 'meta__run_uuid', + 'size_kwh' + ) + if len(hightemptes) > 0: + for m in hightemptes: + summary_dict[str(m.meta.run_uuid)]['hightemptes_kwh'] = m.size_kwh + # assumes run_uuids exist in both CHPInputs and CHPOutputs chpInputs = CHPInputs.objects.filter(meta__run_uuid__in=run_uuids).only( 'meta__run_uuid',