diff --git a/CHANGELOG.md b/CHANGELOG.md index a5fbbb78d..8f7f0fadd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,17 @@ Classify the change according to the following categories: ##### Removed ### Patches +## heuristic-dispatch-option +### Minor udpates +#### Added +- Add **ElectricStorage** inputs field **dispatch_options** with heuristic options + +## fixed-soc +### Minor udpates +#### Added +- Add **ElectricStorage** inputs field **fixed_soc_series_fraction** and **fixed_soc_series_fraction_tolerance** to allow users to fix the SOC timeseries within a chosen absolute tolerance +### Changed +- **ElectricStorage** result key **state_of_health** to **state_of_health_series_fraction** ## v3.20.0 ### Minor Updates @@ -40,7 +51,7 @@ Classify the change according to the following categories: ## v3.19.0 ### Minor updates -##### Added +#### Added - New `CHP` fields **serve_absorption_chiller_only**, **months_serving_absorption_chiller_only**, **follow_electrical_load**, and **include_cooling_in_chp_size** - New output `thermal_to_absorption_chiller_series_mmbtu_per_hour` added to heating technologies `CHPOutputs`, `ElectricHeaterOutputs`, `CSTOutputs`, `BoilerOutputs`, `SteamTurbineOutputs`, and `ExistingBoilerOutputs`, and new output `storage_to_absorption_chiller_series_mmbtu_per_hour` for `HotThermalStorageOutputs` and `HighTempThermalStorageOutputs`. ##### Changed diff --git a/julia_src/Manifest.toml b/julia_src/Manifest.toml index dc825f89c..cae773a91 100644 --- a/julia_src/Manifest.toml +++ b/julia_src/Manifest.toml @@ -948,9 +948,11 @@ version = "1.11.0" [[deps.REopt]] deps = ["ArchGDAL", "CSV", "CoolProp", "DataFrames", "Dates", "DelimitedFiles", "HTTP", "JLD", "JSON", "JuMP", "LinDistFlow", "LinearAlgebra", "Logging", "MathOptInterface", "Requires", "Roots", "Statistics", "TestEnv"] -git-tree-sha1 = "e807b62ab249fca7b59ac6ab7bb71725f504cc5f" +git-tree-sha1 = "a2b247b6e4b74093a89a5464e62e3953eb521d6c" +repo-rev = "chp-expand-dispatch" +repo-url = "https://github.com/NREL/REopt.jl.git" uuid = "d36ad4e8-d74a-4f7a-ace1-eaea049febf6" -version = "0.59.2" +version = "0.59.3" [[deps.Random]] deps = ["SHA"] diff --git a/julia_src/heuristic_dispatch_sizing.jl b/julia_src/heuristic_dispatch_sizing.jl new file mode 100644 index 000000000..a4f0ba8c1 --- /dev/null +++ b/julia_src/heuristic_dispatch_sizing.jl @@ -0,0 +1,197 @@ +# REopt®, Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NatLabRockies/REopt_API/blob/master/LICENSE. +# ============================================================================ +# Heuristic battery dispatch sizing pre-solve +# ---------------------------------------------------------------------------- +# Validates acceptable technologies and calls REopt to size PV and ElectricStorage +# when the user does not provide fixed sizes for heuristic battery dispatch strategies: +# * daily_foresight_optimized (MPC) +# * peak_shaving_look_ahead, peak_shaving_look_behind, self_consumption (SAM dispatches) +# These strategies require fixed, non-zero technology sizes. +# ============================================================================ + +""" + build_dispatch_response(status; skip_heuristic_dispatch=false, messages=Dict(), result_dict=Dict()) + +Build a consistent heuristic-dispatch response envelope with status, version info, and messages. +Ensures all response paths (success, error, skip) have uniform structure. +""" +function build_dispatch_response(status::String; skip_heuristic_dispatch=false, messages=Dict(), result_dict=Dict()) + response = Dict( + "status" => status, + "reopt_version" => string(pkgversion(reoptjl)), + "Messages" => messages, + "skip_heuristic_dispatch" => skip_heuristic_dispatch, + ) + # Merge result data if provided (for success case) + return merge(response, result_dict) +end + +""" + get_technology_sizes!(d::Dict, model_inputs::reoptjl.REoptInputs, solver_settings::Dict) + +Determine PV and ElectricStorage sizes. If min_kw != max_kw and/or min_kwh != max_kwh, +call REopt to size technologies. User input battery sizes must also be greater than zero. + d is mutated in-place to update PV and ElectricStorage sizes. + model_inputs has already been processed to remove inputs not used in REopt.jl +""" +function get_technology_sizes!(d::Dict, model_inputs::reoptjl.REoptInputs, solver_settings::Dict) + # pv and batt are updated in-place from the dictionary `d` and used in the final REopt run + pv = get!(d, "PV", Dict()) + batt = get!(d, "ElectricStorage", Dict()) + + function is_fixed(dct, lo_key, hi_key) + lo = get(dct, lo_key, nothing) + hi = get(dct, hi_key, nothing) + return lo !== nothing && hi !== nothing && Float64(lo) == Float64(hi) + end + + # Check if both PV and BESS sizes fixed + pv_fixed = is_fixed(pv, "min_kw", "max_kw") + batt_fixed = is_fixed(batt, "min_kw", "max_kw") && + is_fixed(batt, "min_kwh", "max_kwh") + + if pv_fixed && batt_fixed + pv_kw = Float64(pv["min_kw"]) + batt_kw = Float64(batt["min_kw"]) + batt_kwh = Float64(batt["min_kwh"]) + return (pv_kw = pv_kw, batt_kw = batt_kw, batt_kwh = batt_kwh, skip_heuristic_dispatch = false, pv_production_factor_series = nothing) + end + + @info "PV and/or ElectricStorage sizes are not specified — running REopt sizing first." + # TODO: Should we "remove tiers" here for sizing or allow for optimizing with tiers? + + m = get_solver_model(get_solver_model_type(solver_settings["solver_name"]), solver_settings["solver_attributes"]) + + sizing_results = reoptjl.run_reopt(m, model_inputs) + + if get(sizing_results, "status", "") != "optimal" + status = get(sizing_results, "status", "unknown") + msgs = get(sizing_results, "Messages", Dict()) + errs = get(msgs, "errors", []) + warns = get(msgs, "warnings", []) + error("REopt sizing pre-step did not solve (status = $(status)). " * + "REopt errors: $(errs). REopt warnings: $(warns).") + end + + pv_kw = Float64(get(get(sizing_results, "PV", Dict()), "size_kw", 0.0)) + batt_kw = Float64(get(get(sizing_results, "ElectricStorage", Dict()), "size_kw", 0.0)) + batt_kwh = Float64(get(get(sizing_results, "ElectricStorage", Dict()), "size_kwh", 0.0)) + pv_production_factor_series = get(get(sizing_results, "PV", Dict()), "production_factor_series", nothing) + + # Skip the MPC loop if no battery is sized + if batt_kw <= 0.0 || batt_kwh <= 0.0 + return (pv_kw = pv_kw, batt_kw = 0.0, batt_kwh = 0.0, skip_heuristic_dispatch = true, pv_production_factor_series = pv_production_factor_series) + end + + # Fix inputs for final REopt run in http.jl + pv["min_kw"] = pv_kw + pv["max_kw"] = pv_kw + batt["min_kw"] = batt_kw + batt["max_kw"] = batt_kw + batt["min_kwh"] = batt_kwh + batt["max_kwh"] = batt_kwh + + @info "REopt sizing solved with PV = $(pv_kw) kW and battery = $(batt_kw) kW / $(batt_kwh) kWh." + return (; pv_kw, batt_kw, batt_kwh, skip_heuristic_dispatch = false, pv_production_factor_series) +end + +""" + validate_and_size_pv_storage!(d::Dict; solver_name, strategy_label) + +Validates accepted technologies for heuristic battery dispatch strategies (daily_foresight_optimized, +peak_shaving_look_ahead, peak_shaving_look_behind, self_consumption). Then calls get_technology_sizes +to size PV and ElectricStorage if fixed sizes are not defined by the user. +""" +function validate_and_size_pv_storage!(d::Dict; solver_name::String="HiGHS", strategy_label::String="a heuristic battery dispatch strategy") + fail(error_dict) = (; error = error_dict, technology_sizes = nothing, model_inputs = nothing, + solver_settings = Dict(), time_steps_per_hour = 1) + + ## Validation on allowable inputs for predetermined heuristic battery dispatch strategies + # Error if any techs other than PV and ElectricStorage are provided + allowed_keys = Set(["PV", "ElectricStorage", "ElectricLoad", "ElectricTariff", "ElectricUtility", "Site", "Settings", "Financial"]) + unsupported_keys = setdiff(keys(d), allowed_keys) + # Ignore disallowed technologies that are explicitly disabled with max_kw = 0 + for key in copy(unsupported_keys) + val = get(d, key, nothing) + if val isa AbstractDict && haskey(val, "max_kw") && val["max_kw"] == 0 + setdiff!(unsupported_keys, [key]) + end + end + if !isempty(unsupported_keys) + return fail(build_dispatch_response( + "error", + messages = Dict("errors" => ["When using $(strategy_label), only PV and ElectricStorage are supported technologies. " * + "Unsupported inputs found: $(join(unsupported_keys, ", "))."]) + )) + end + + # Heuristic dispatch through the API only supports a single PV, so error on multiple PVs and normalize a one-element array down to a Dict so downstream code can treat d["PV"] as a Dict. + # TODO: Handle multiple PVs + if haskey(d, "PV") && isa(d["PV"], AbstractArray) + if length(d["PV"]) > 1 + return fail(build_dispatch_response( + "error", + messages = Dict("errors" => ["$(strategy_label): Multiple PV systems are not supported at this time."]) + )) + elseif length(d["PV"]) == 1 + d["PV"] = d["PV"][1] + else + delete!(d, "PV") # empty PV array -> treat as no PV + end + end + + # Check max storage sizing is greater than zero + batt = get(d, "ElectricStorage", Dict()) + if Float64(get(batt, "max_kw", 1.0)) <= 0.0 || Float64(get(batt, "max_kwh", 1.0)) <= 0.0 + return fail(build_dispatch_response( + "error", + messages = Dict("errors" => ["When using $(strategy_label), ElectricStorage max_kw and max_kwh must both be greater than zero."]) + )) + end + + settings = get!(d, "Settings", Dict()) + time_steps_per_hour = Int(get(settings, "time_steps_per_hour", 1)) + + # Update sizing_post to remove solver settings and dispatch inputs, to be able to validate inputs using REoptInputs + sizing_post = deepcopy(d) + sizing_settings = get(sizing_post, "Settings", Dict()) + solver_settings = Dict() + delete!(sizing_settings, "run_bau") # Remove run_bau from sizing run + solver_settings["timeout_seconds"] = pop!(sizing_settings, "timeout_seconds", 600) # Only gets used in sizing run + solver_settings["optimality_tolerance"] = pop!(sizing_settings, "optimality_tolerance", 0.001) # Update to a higher value if solve time becomes an issue + solver_settings["solver_attributes"] = SolverAttributes(solver_settings["timeout_seconds"], solver_settings["optimality_tolerance"]) + solver_settings["solver_name"] = solver_name + # Delete inputs specific to the heuristic battery dispatch run + if haskey(sizing_post, "ElectricStorage") + delete!(sizing_post["ElectricStorage"], "dispatch_strategy") + delete!(sizing_post["ElectricStorage"], "fixed_soc_series_fraction") + end + + # Process and validate inputs using REoptInputs + model_inputs = nothing + try + model_inputs = reoptjl.REoptInputs(sizing_post) + + # REoptInputs returns an error Dict (rather than throwing) when input validation fails. + # Surface those messages instead of falling through to get_technology_sizes!, which expects a REoptInputs and would otherwise raise a confusing MethodError. + if isa(model_inputs, Dict) + @error "REopt input validation failed during sizing pre-solve." messages=get(model_inputs, "Messages", Dict()) + return fail(build_dispatch_response( + "error", + messages = get(model_inputs, "Messages", Dict("errors" => ["REopt input validation failed."])) + )) + end + @info "Successfully processed REopt inputs." + catch e + @error "Something went wrong during REopt inputs processing!" exception=(e, catch_backtrace()) + return fail(build_dispatch_response( + "error", + messages = Dict("errors" => [sprint(showerror, e)]) + )) + end + + # If fixed PV and battery sizes are not provided, call REopt first in a sizing run + technology_sizes = get_technology_sizes!(d, model_inputs, solver_settings) + + return (; error = nothing, technology_sizes, model_inputs, solver_settings, time_steps_per_hour) +end diff --git a/julia_src/http.jl b/julia_src/http.jl index 9eab6396d..e52baf7b5 100644 --- a/julia_src/http.jl +++ b/julia_src/http.jl @@ -1,4 +1,4 @@ -using HTTP, JSON, JuMP +using HTTP, JSON, JuMP using HiGHS, Cbc, SCIP using GhpGhx import REopt as reoptjl # For REopt.jl, needed because we still have local REopt.jl module for V1/V2 @@ -8,6 +8,8 @@ DotEnv.load!() const test_nrel_developer_api_key = ENV["NREL_DEVELOPER_API_KEY"] ENV["NREL_DEVELOPER_EMAIL"] = "reopt@nlr.gov" +include("heuristic_dispatch_sizing.jl") +include("mpc.jl") include("os_solvers.jl") @@ -64,6 +66,7 @@ function reopt(req::HTTP.Request) ENV["NREL_DEVELOPER_API_KEY"] = test_nrel_developer_api_key delete!(d, "api_key") end + settings = d["Settings"] solver_name = get(settings, "solver_name", "HiGHS") if solver_name == "Xpress" && !(xpress_installed=="True") @@ -71,6 +74,64 @@ function reopt(req::HTTP.Request) @warn "Changing solver_name from Xpress to $solver_name because Xpress is not installed. Next time Specify Settings.solver_name = 'HiGHS' or 'Cbc' or 'SCIP'" end + + # When ElectricStorage.dispatch_strategy == "daily_foresight_optimized", "peak_shaving_look_ahead", "peak_shaving_look_behind", or + # "self_consumption", if needed, first run REopt to get optimal sizing of PV and battery. Fix PV and battery sizing before running + # the main REopt optimization (skipping heuristic dispatch if optimal battery size is 0). + # For ElectricStorage.dispatch_strategy == daily_foresight_optimized and non-zero battery sizing, run the MPC rolling-horizon loop + # first to get an SOC profile and set ElectricStorage.fixed_soc_series_fraction = MPC SOC. + electric_storage = get(d, "ElectricStorage", Dict()) + dispatch_strategy = get(electric_storage, "dispatch_strategy", nothing) + sam_dispatch_strategies = ("peak_shaving_look_ahead", "peak_shaving_look_behind", "self_consumption") + + if dispatch_strategy == "daily_foresight_optimized" + try + @info "Running MPC to obtain daily foresight optimized battery dispatch profile." + mpc_results = get_mpc_results!(d; solver_name=solver_name) + if get(mpc_results, "status", "") == "error" + @error "MPC pre-solve failed input validation" messages=get(mpc_results, "Messages", Dict()) + return HTTP.Response(400, JSON.json(mpc_results)) + elseif get(mpc_results, "skip_heuristic_dispatch", false) == true + @info "Cannot execute daily_foresight_optimized battery dispatch because optimal battery size is 0. Setting dispatch strategy to 'optimized'." + d["ElectricStorage"]["dispatch_strategy"] = "optimized" + else + soc = mpc_results["ElectricStorage"]["soc_series_fraction"] + d["ElectricStorage"]["fixed_soc_series_fraction"] = soc + d["ElectricStorage"]["dispatch_strategy"] = "custom_soc" + end + catch e + @error "MPC pre-solve failed" exception=(e, catch_backtrace()) + return HTTP.Response(500, JSON.json(Dict( + "error" => "MPC pre-solve failed: " * sprint(showerror, e), + "reopt_version" => string(pkgversion(reoptjl)), + ))) + end + elseif dispatch_strategy in sam_dispatch_strategies + try + @info "Running REopt sizing to fix PV/ElectricStorage sizes for the '$(dispatch_strategy)' dispatch strategy." + sized = validate_and_size_pv_storage!(d; solver_name=solver_name, + strategy_label="the '$(dispatch_strategy)' dispatch strategy") + if sized.error !== nothing + @error "Sizing pre-solve failed input validation" messages=get(sized.error, "Messages", Dict()) + return HTTP.Response(400, JSON.json(sized.error)) + elseif sized.technology_sizes.skip_heuristic_dispatch + @info "Optimal battery size is 0 for the '$(dispatch_strategy)' dispatch strategy. Setting dispatch strategy to 'optimized'." + d["ElectricStorage"]["dispatch_strategy"] = "optimized" + elseif dispatch_strategy == "self_consumption" && + Float64(get(get(d, "PV", Dict()), "existing_kw", 0.0)) + sized.technology_sizes.pv_kw <= 0.0 + @info "The self_consumption dispatch strategy requires PV, but total PV size is 0. Setting dispatch strategy to 'optimized'." + d["ElectricStorage"]["dispatch_strategy"] = "optimized" + end + # else: PV/ElectricStorage sizes are fixed in d; keep dispatch_strategy for the main run + catch e + @error "Sizing pre-solve failed" exception=(e, catch_backtrace()) + return HTTP.Response(500, JSON.json(Dict( + "error" => "Sizing pre-solve failed: " * sprint(showerror, e), + "reopt_version" => string(pkgversion(reoptjl)), + ))) + end + end + timeout_seconds = pop!(settings, "timeout_seconds") optimality_tolerance = pop!(settings, "optimality_tolerance") solver_attributes = SolverAttributes(timeout_seconds, optimality_tolerance) @@ -120,13 +181,18 @@ function reopt(req::HTTP.Request) ] if haskey(d, "CHP") inputs_with_defaults_from_julia_chp = [ + :name, :installed_cost_per_kw, :tech_sizes_for_cost_curve, :om_cost_per_kwh, :electric_efficiency_full_load, :thermal_efficiency_full_load, :min_allowable_kw, :cooling_thermal_factor, :min_turn_down_fraction, :unavailability_periods, :max_kw, :size_class, :electric_efficiency_half_load, :thermal_efficiency_half_load, :macrs_option_years, :macrs_bonus_fraction, :federal_itc_fraction ] - chp_dict = Dict(key=>getfield(model_inputs.s.chp, key) for key in inputs_with_defaults_from_julia_chp) + if length(model_inputs.s.chps) == 1 + chp_dict = Dict(key=>getfield(model_inputs.s.chps[1], key) for key in inputs_with_defaults_from_julia_chp) + else + chp_dict = [Dict(key=>getfield(chp, key) for key in inputs_with_defaults_from_julia_chp) for chp in model_inputs.s.chps] + end else chp_dict = Dict() end @@ -192,9 +258,13 @@ function reopt(req::HTTP.Request) end if haskey(d, "PV") inputs_with_defaults_from_julia_pv = [ - :size_class, :installed_cost_per_kw, :om_cost_per_kw, :macrs_option_years, :macrs_bonus_fraction, :federal_itc_fraction + :name, :size_class, :installed_cost_per_kw, :om_cost_per_kw, :macrs_option_years, :macrs_bonus_fraction, :federal_itc_fraction ] - pv_dict = Dict(key=>getfield(model_inputs.s.pvs[1], key) for key in inputs_with_defaults_from_julia_pv) + if length(model_inputs.s.pvs) == 1 + pv_dict = Dict(key=>getfield(model_inputs.s.pvs[1], key) for key in inputs_with_defaults_from_julia_pv) + else + pv_dict = [Dict(key=>getfield(pv, key) for key in inputs_with_defaults_from_julia_pv) for pv in model_inputs.s.pvs] + end else pv_dict = Dict() end @@ -208,7 +278,7 @@ function reopt(req::HTTP.Request) end if haskey(d, "ElectricStorage") inputs_with_defaults_from_julia_electric_storage = [ - :macrs_option_years, :macrs_bonus_fraction, :total_itc_fraction + :macrs_option_years, :macrs_bonus_fraction, :total_itc_fraction, :internal_efficiency_fraction ] electric_storage_dict = Dict(key=>getfield(model_inputs.s.storage.attr["ElectricStorage"], key) for key in inputs_with_defaults_from_julia_electric_storage) else @@ -810,6 +880,66 @@ function job_no_xpress(req::HTTP.Request) return HTTP.Response(500, JSON.json(error_response)) end +""" + mpc(req::HTTP.Request) + +HTTP endpoint for rolling-horizon Model Predictive Control (MPC) dispatch optimization. + +This endpoint performs a full-year rolling-horizon MPC dispatch for PV + ElectricStorage systems, +optimizing daily dispatch using a 24-hour look-ahead window. Runs the MPC dispatch loop via +`get_mpc_results!` and returns dispatch results and cost metrics as JSON. + +Arguments: + req::HTTP.Request: REopt inputs dictionary + +Returns JSON dictionary containing: + - MPC: Metadata (time_steps_per_hour, horizon_time_steps) + - PV: Size and dispatch series (to load, storage, grid, curtailed) + - ElectricStorage: Sizes and state-of-charge series + - ElectricUtility: Grid dispatch series and emissions + - ElectricLoad: Load profile used + - ElectricTariff: Energy and demand costs, peak demands by month/ratchet + - status: "optimal" + - reopt_version: Version of REopt.jl used + +""" +function mpc(req::HTTP.Request) + d = JSON.parse(String(req.body)) + error_response = Dict() + results = Dict() + try + if !isempty(get(d, "api_key", "")) + ENV["NREL_DEVELOPER_API_KEY"] = pop!(d, "api_key") + else + ENV["NREL_DEVELOPER_API_KEY"] = test_nrel_developer_api_key + delete!(d, "api_key") + end + + solver_name = get(get(d, "Settings", Dict()), "solver_name", "HiGHS") + if solver_name == "Xpress" && !(xpress_installed=="True") + solver_name = "HiGHS" + @warn "Changing solver_name from Xpress to $solver_name because Xpress is not installed. Next time + Specify Settings.solver_name = 'HiGHS' or 'Cbc' or 'SCIP'" + end + + results = get_mpc_results!(d; solver_name=solver_name) + catch e + @error "MPC failed" exception=(e, catch_backtrace()) + error_response["error"] = sprint(showerror, e) + error_response["reopt_version"] = string(pkgversion(reoptjl)) + end + GC.gc() + if !isempty(error_response) + return HTTP.Response(500, JSON.json(error_response)) + elseif get(results, "status", "") == "error" + @error "MPC failed input validation" messages=get(results, "Messages", Dict()) + return HTTP.Response(400, JSON.json(results)) + else + @info "MPC ran successfully." + return HTTP.Response(200, JSON.json(results)) + end +end + # define REST endpoints to dispatch to "service" functions const ROUTER = HTTP.Router() @@ -820,6 +950,7 @@ else end HTTP.register!(ROUTER, "POST", "/reopt", reopt) HTTP.register!(ROUTER, "POST", "/erp", erp) +HTTP.register!(ROUTER, "POST", "/mpc", mpc) HTTP.register!(ROUTER, "POST", "/ghpghx", ghpghx) HTTP.register!(ROUTER, "GET", "/chp_defaults", chp_defaults) HTTP.register!(ROUTER, "GET", "/avert_emissions_profile", avert_emissions_profile) diff --git a/julia_src/mpc.jl b/julia_src/mpc.jl new file mode 100644 index 000000000..d718e76ad --- /dev/null +++ b/julia_src/mpc.jl @@ -0,0 +1,465 @@ +# REopt®, Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NatLabRockies/REopt_API/blob/master/LICENSE. +# ============================================================================ +# MPC (Model Predictive Control) endpoint +# ---------------------------------------------------------------------------- +# Rolling-horizon dispatch with one day look-ahead using REopt.run_mpc. Assumes: +# * PV and ElectricStorage are the only available technologies +# * Only perfect forecast scenarios are modeled (no forecast errors) +# * Sizing: Perform a sizing run first if PV or ElectricStorage sizes are not provided (storage sizes must be > 0) +# * PV: Use PVWatts if `PV.production_factor_series` is not provided +# * ElectricLoad: Use commercial reference profiles if `ElectricLoad.loads_kw` is not provided +# * Code wraps with Jan 1 data to determine Dec 31 dispatch (leap-year inputs are not supported) +# * MPC settings are currently hard coded (e.g., forecast horizon, control horizon, optimization horizon) +# ============================================================================ + +""" + get_month_transition_timesteps(time_steps_per_hour) + +Return an array of length 12 specifying the index marking the start of each month in a non-leap year +""" +function get_month_transition_timesteps(time_steps_per_hour::Int) + # hours in each month for a non-leap year + hours_per_month = [744, 672, 744, 720, 744, 720, 744, 744, 720, 744, 720, 744] + starts = Vector{Int}(undef, 12) + starts[1] = 1 + for m in 2:12 + starts[m] = starts[m-1] + hours_per_month[m-1] * time_steps_per_hour + end + return starts +end + +""" + slice_data(arr, idx, end_idx) + +Returns arr[idx:end_idx] but wrap around to the start of arr if end_idx > length(arr). +""" +function slice_data(arr::AbstractVector, idx::Int, end_idx::Int) + n = length(arr) + if end_idx <= n + return arr[idx:end_idx] + else + wrap_len = end_idx - n + return vcat(arr[idx:n], arr[1:wrap_len]) + end +end + + +""" + generate_pv_production_factors(d, time_steps_per_hour) + +Generate a PV production factor series using PVWatts by calling REopt.get_production_factor. +This is called by get_mpc_results! only when the user does not provide a custom production_factor_series and REopt is not called for sizing. +""" +function generate_pv_production_factors(d::Dict, time_steps_per_hour::Int) + site = get(d, "Site", Dict()) + lat = Float64(site["latitude"]) + lon = Float64(site["longitude"]) + + @info "MPC: PV.production_factor_series not provided; generating using PVWatts through REopt.jl (lat=$(lat), lon=$(lon))." + + pv = get(d, "PV", Dict()) + pv_pf_kwargs = (:array_type, :tilt, :module_type, :losses, :azimuth, :gcr, + :radius, :name, :location, :dc_ac_ratio, :inv_eff) + kwargs = Dict{Symbol,Any}(Symbol(k) => v for (k, v) in pv if Symbol(k) in pv_pf_kwargs) + pv_struct = reoptjl.PV(; latitude = lat, kwargs...) + pv_production_factor_series = reoptjl.get_production_factor(pv_struct, lat, lon; + time_steps_per_hour = time_steps_per_hour) + return Vector{Float64}(pv_production_factor_series) +end + +function get_mpc_results!(d::Dict; solver_name::String="HiGHS")::Dict + """ + Run a full-year rolling-horizon MPC dispatch for PV + ElectricStorage by + calling `REopt.run_mpc` once per timestep with a 24-hour look-ahead. + + Inputs: + d::Dict, REopt inputs dictionary (will be modified in-place to store computed fixed sizes and PV production factors.) + + Returns JSON dictionary containing: + - status: "optimal", "error", or "skipped" + - reopt_version: Version of REopt.jl used + - Messages: Dict with optional errors, warnings, or info + - skip_heuristic_dispatch: Boolean indicating if MPC was skipped + + For "optimal" status, also includes: + - MPC: Metadata (time_steps_per_hour, horizon_time_steps) + - PV: Size and dispatch series (to load, storage, grid, curtailed) + - ElectricStorage: Sizes and state-of-charge series + - ElectricUtility: Grid dispatch series and emissions + - ElectricLoad: Load profile used + - ElectricTariff: Separate cost components (total_energy_cost, total_export_benefit, + total_tou_demand_cost, total_non_tou_monthly_demand_cost), a combined total_electricity_bill, + per-timestep energy/export series, and peak demands by month/ratchet + + """ + + # The checks below are removed because when MPC is called through REopt, the last REopt run will error if these goals are not met. + # If MPC is called directly, specifying these inputs IS an issue (because they're not consdired in MPC dispatch). If the MPC endpoint becomes public, we should re-enable these checks. + # # Error if unsupported CO2/renewable-fraction constraints are set + # _site_input = get(d, "Site", Dict()) + # if !isnothing(get(_site_input, "CO2_emissions_reduction_min_fraction", nothing)) + # error("MPC: Site.CO2_emissions_reduction_min_fraction is not supported in MPC runs.") + # end + # if get(_site_input, "include_grid_renewable_fraction_in_RE_constraints", false) == true + # error("MPC: Site.include_grid_renewable_fraction_in_RE_constraints is not supported in MPC runs.") + # end + # if get(_site_input, "include_exported_elec_emissions_in_total", true) == false + # error("MPC: Site.include_exported_elec_emissions_in_total = false is not supported in MPC runs.") + # end + # if get(_site_input, "include_exported_renewable_electricity_in_total", true) == false + # error("MPC: Site.include_exported_renewable_electricity_in_total = false is not supported in MPC runs.") + # end + + # Error for off-grid runs + if haskey(d, "Settings") && get(d["Settings"], "off_grid_flag", false) == true + return build_dispatch_response( + "error", + messages = Dict("errors" => ["MPC: Off-grid runs are not currently supported in MPC."]) + ) + end + + # Error if rate tariff contains lookbacks or coincident peak charges. (These are not currently supported in MPC.) + if (haskey(d["ElectricTariff"], "demand_lookback_months") && length(d["ElectricTariff"]["demand_lookback_months"]) > 0 ) || + (haskey(d["ElectricTariff"], "demand_lookback_percent") && d["ElectricTariff"]["demand_lookback_percent"] > 0) || + (haskey(d["ElectricTariff"], "demand_lookback_range") && d["ElectricTariff"]["demand_lookback_range"] > 0) + return build_dispatch_response( + "error", + messages = Dict("errors" => ["MPC: ElectricTariff with demand lookbacks is not currently supported in MPC runs."]) + ) + end + if haskey(d["ElectricTariff"], "coincident_peak_load_active_time_steps") && d["ElectricTariff"]["coincident_peak_load_active_time_steps"] != [Int64[]] + return build_dispatch_response( + "error", + messages = Dict("errors" => ["MPC: ElectricTariff with coincident peak charges is not currently supported in MPC runs."]) + ) + end + + # TODO: show this warning only if tiered rates are detected in the tariff. + @warn "Using MPC to determine dispatch. MPC does not model: tiered electricity rates; rates will be flattened to the first tier." + + # Restrict inputs to PV + ElectricStorage and run a REopt "optimized" sizing pass if sizes are + # not user-fixed. This mutates `d` to fix the resulting PV/ElectricStorage sizes. + sized = validate_and_size_pv_storage!(d; solver_name=solver_name, + strategy_label="MPC (daily_foresight_optimized dispatch)") + if sized.error !== nothing + return sized.error + end + technology_sizes = sized.technology_sizes + model_inputs = sized.model_inputs + solver_settings = sized.solver_settings + time_steps_per_hour = sized.time_steps_per_hour + + ## Set up MPC inputs + # TODO: MPC horizons and timeout are currently hard coded + per_iter_timeout_s = 30.0 + length_of_data = 8760 * time_steps_per_hour + horizon = 24 * time_steps_per_hour + + s = model_inputs.s # Access the processed Scenario struct + + # Skip MPC if no battery is optimally sized + if technology_sizes.skip_heuristic_dispatch + return build_dispatch_response( + "skipped", + skip_heuristic_dispatch = true, + messages = Dict("info" => ["No battery was optimally sized in REopt pre-step; MPC dispatch not needed."]) + ) + end + + # Sizes from user or initial REopt run + pv_kw = technology_sizes.pv_kw + batt_kw = technology_sizes.batt_kw + batt_kwh = technology_sizes.batt_kwh + + # Note: REoptInputs does not provide PV production factors if user doesn't specify custom values + # PV production is NOT levelized in MPC but IS levelized in REopt. This will result in a slight mis-match. + if !isempty(s.pvs) # Get prod factors if PV considered. + if !isnothing(s.pvs[1].production_factor_series) + pv_prod_factor = Float64.(s.pvs[1].production_factor_series) + elseif technology_sizes.pv_production_factor_series !== nothing + pv_prod_factor = Float64.(technology_sizes.pv_production_factor_series) + else + pv_prod_factor = generate_pv_production_factors(d, time_steps_per_hour) + end + # Avoid another PVWatts call in the final REopt run. + d["PV"]["production_factor_series"] = pv_prod_factor + else + pv_prod_factor = zeros(Float64, length_of_data) + end + + loads_kw = Float64.(s.electric_load.loads_kw) + + # Extract tariff inputs relevant to MPC (use first tier only if tiered rates) + # TODO: Implement lookbacks (demand_lookback_months, demand_lookback_percent, demand_lookback_range), coincident peak charges, and handling of tiered rates here and in REopt.jl. + energy_rates = Float64.(s.electric_tariff.energy_rates[:, 1]) + monthly_demand_rates = isempty(s.electric_tariff.monthly_demand_rates) ? + zeros(Float64, 12) : Float64.(s.electric_tariff.monthly_demand_rates[:, 1]) + tou_demand_rates = isempty(s.electric_tariff.tou_demand_rates) ? Float64[] : Float64.(s.electric_tariff.tou_demand_rates[:, 1]) + tou_demand_ratchet_time_steps = [Int.(v) for v in s.electric_tariff.tou_demand_ratchet_time_steps] + n_tou_ratchets = length(tou_demand_rates) # Number of TOU ratchets + tou_previous_peak_demands = zeros(Float64, n_tou_ratchets) # Tracks past TOU peak demand per ratchet + monthly_previous_peak_demands = zeros(Float64, 12) # Tracks past monthly peak demand + + # Extract storage efficiency and SOC defaults from processed inputs + rect_eff = Float64(s.storage.attr["ElectricStorage"].rectifier_efficiency_fraction) + inv_eff = Float64(s.storage.attr["ElectricStorage"].inverter_efficiency_fraction) + int_eff = Float64(s.storage.attr["ElectricStorage"].internal_efficiency_fraction) + charge_eff = rect_eff * sqrt(int_eff) + discharge_eff = inv_eff * sqrt(int_eff) + soc_0 = Float64(s.storage.attr["ElectricStorage"].soc_init_fraction) + soc_min = Float64(s.storage.attr["ElectricStorage"].soc_min_fraction) + + # Extract emissions defaults (or use user input if provided) + co2_grid_emissions_series = Float64.(s.electric_utility.emissions_factor_series_lb_CO2_per_kwh) + + # --- Export / net metering setup (mirror the sizing-run scenario) --- + # NEM is enabled in MPC when ElectricUtility.net_metering_limit_kw > 0. + nm_limit_kw = Float64(s.electric_utility.net_metering_limit_kw) + + # WHL (net billing) rate: export_rates[:WHL] in the processed scenario is a negative "cost"; + # MPCElectricTariff expects a positive wholesale_rate (it negates internally). + whl_rate_full = (:WHL in s.electric_tariff.export_bins) ? + -1.0 .* Float64.(s.electric_tariff.export_rates[:WHL]) : nothing + + # PV export capability comes from the processed PV struct. + pv_can_net_meter = !isempty(s.pvs) ? Bool(s.pvs[1].can_net_meter) : false + pv_can_wholesale = !isempty(s.pvs) ? Bool(s.pvs[1].can_wholesale) : false + + # Battery export capability comes from the processed ElectricStorage struct + _batt_attr = s.storage.attr["ElectricStorage"] + batt_can_net_meter = Bool(_batt_attr.can_net_meter) + batt_can_wholesale = Bool(_batt_attr.can_wholesale) + + # NEM export is credited (approximately) at the retail energy rate; used for cost reporting below. + nem_active = nm_limit_kw > 0 && (pv_can_net_meter || batt_can_net_meter) + + month_starts = get_month_transition_timesteps(time_steps_per_hour) + + # ts_to_month = 8760 array specifying which month each timestep falls in (1-12) + ts_to_month = Vector{Int}(undef, length_of_data) + for m in 1:12 + s_idx = month_starts[m] + e = m < 12 ? month_starts[m+1] - 1 : length_of_data + ts_to_month[s_idx:e] .= m + end + + # ts_to_ratchet = 8760 array specifying which ratchet each timestep falls in + ts_to_ratchet = zeros(Int, length_of_data) + for (t, ratchet_ts) in enumerate(tou_demand_ratchet_time_steps), g in ratchet_ts + if 1 <= g <= length_of_data + ts_to_ratchet[g] = t + end + end + + # Saved dispatch series (first timestep of each MPC loop) + dispatch_series = Dict( + "PV" => Dict( + "electric_to_load_series_kw" => Float64[], + "electric_to_storage_series_kw" => Float64[], + "electric_to_grid_series_kw" => Float64[], + "electric_curtailed_series_kw" => Float64[], + ), + "ElectricStorage" => Dict( + "storage_to_load_series_kw" => Float64[], + "storage_to_grid_series_kw" => Float64[], + "soc_series_fraction" => Float64[], + ), + "ElectricUtility" => Dict( + "electric_to_load_series_kw" => Float64[], + "electric_to_storage_series_kw" => Float64[], + "emissions_series_lb_CO2" => Float64[], + ), + "ElectricLoad" => Dict( + "load_series_kw" => Float64[], + ), + ) + energy_cost_series = Float64[] # grid purchase (energy) charges per timestep + export_benefit_series = Float64[] # NEM/WHL export credits per timestep (positive = revenue) + total_energy_cost = 0.0 + total_export_benefit = 0.0 + soc_init_frac = soc_0 + + # Build MPC post + # Update this fn if mpc capabilities are updated (e.g., to support outages, multiple PVs, or more tariff inputs) + function build_mpc_post(current_horizon_pv, current_horizon_load, current_horizon_energy_rates, + current_horizon_emissions, current_horizon_tou_ts, current_horizon_monthly_ts, + tou_previous_peak_demands, monthly_previous_peak_demands, soc_init_frac, + current_horizon_whl_rate) + tariff = Dict( + "energy_rates" => current_horizon_energy_rates, + "tou_demand_rates" => tou_demand_rates, + "tou_demand_time_steps" => current_horizon_tou_ts, + "tou_previous_peak_demands" => tou_previous_peak_demands, + "monthly_demand_rates" => monthly_demand_rates, + "time_steps_monthly" => current_horizon_monthly_ts, + "monthly_previous_peak_demands" => monthly_previous_peak_demands, + ) + # WHL (net billing) export: MPCElectricTariff reads a positive `wholesale_rate` and + # builds the :WHL export bin when it is provided. + if current_horizon_whl_rate !== nothing + tariff["wholesale_rate"] = current_horizon_whl_rate + end + return Dict( + "PV" => Dict( + "size_kw" => pv_kw, + "production_factor_series" => current_horizon_pv, + "can_net_meter" => pv_can_net_meter, + "can_wholesale" => pv_can_wholesale, + ), + "ElectricStorage" => Dict( + "size_kw" => batt_kw, + "size_kwh" => batt_kwh, + "charge_efficiency" => charge_eff, + "discharge_efficiency" => discharge_eff, + "soc_init_fraction" => soc_init_frac, + "soc_min_fraction" => soc_min, + "can_net_meter" => batt_can_net_meter, + "can_wholesale" => batt_can_wholesale, + ), + "ElectricLoad" => Dict( + "loads_kw" => current_horizon_load, + ), + "ElectricTariff" => tariff, + # net_metering_limit_kw drives the NEM export bin in MPCElectricTariff (NEM on if > 0) + "ElectricUtility" => Dict( + "net_metering_limit_kw" => nm_limit_kw, + "emissions_factor_series_lb_CO2_per_kwh" => current_horizon_emissions, + ), + ) + end + + @info "MPC: starting rolling-horizon optimization ($(length_of_data) iterations, horizon = $(horizon) timesteps)" + for idx in 1:length_of_data + end_ts = idx + horizon - 1 + + current_horizon_pv = slice_data(pv_prod_factor, idx, end_ts) + current_horizon_load = slice_data(loads_kw, idx, end_ts) + current_horizon_energy_rates = slice_data(energy_rates, idx, end_ts) + current_horizon_emissions = slice_data(co2_grid_emissions_series, idx, end_ts) + current_horizon_whl_rate = whl_rate_full === nothing ? nothing : slice_data(whl_rate_full, idx, end_ts) + + # List of length n_tou_ratchets, specifies which ts of the current horizon are in each TOU ratchet + # by placing values 1 to horizon into the corresponding element of the array based on ratchet number + current_horizon_tou_ts = [Int[] for _ in 1:n_tou_ratchets] + + # 12 element list, each element for one month of the year. Specifies which timesteps of the current horizon are + # in each month by placing values 1 - horizon into the corresponding element of the array based on month number + current_horizon_monthly_ts = [Int[] for _ in 1:12] + for k in 1:horizon + g = idx + k - 1 + if g > length_of_data + g -= length_of_data + end + push!(current_horizon_monthly_ts[ts_to_month[g]], k) + ratchet = ts_to_ratchet[g] + if ratchet > 0 + push!(current_horizon_tou_ts[ratchet], k) + end + end + + post = build_mpc_post(current_horizon_pv, current_horizon_load, current_horizon_energy_rates, + current_horizon_emissions, current_horizon_tou_ts, current_horizon_monthly_ts, + tou_previous_peak_demands, monthly_previous_peak_demands, soc_init_frac, + current_horizon_whl_rate + ) + + model = get_solver_model(get_solver_model_type(solver_name), + SolverAttributes(per_iter_timeout_s, solver_settings["optimality_tolerance"])) + result = reoptjl.run_mpc(model, post) + + # Assume perfect forecast; save first timestep of results as the executed state + pv_res = result["PV"] + batt_res = result["ElectricStorage"] + util_res = result["ElectricUtility"] + + pv_to_load = pv_res["electric_to_load_series_kw"][1] + pv_to_batt = pv_res["electric_to_storage_series_kw"][1] + pv_to_grid = haskey(pv_res, "electric_to_grid_series_kw") ? pv_res["electric_to_grid_series_kw"][1] : 0.0 + pv_curtailed = haskey(pv_res, "electric_curtailed_series_kw") ? pv_res["electric_curtailed_series_kw"][1] : 0.0 + batt_to_load = batt_res["storage_to_load_series_kw"][1] + batt_to_grid = haskey(batt_res, "storage_to_grid_series_kw") ? batt_res["storage_to_grid_series_kw"][1] : 0.0 + batt_soc = batt_res["soc_series_fraction"][1] + util_to_load = util_res["electric_to_load_series_kw"][1] + util_to_batt = util_res["electric_to_storage_series_kw"][1] + grid_power = max(util_to_load + util_to_batt, 0.0) + + push!(dispatch_series["PV"]["electric_to_load_series_kw"], pv_to_load) + push!(dispatch_series["PV"]["electric_to_storage_series_kw"], pv_to_batt) + push!(dispatch_series["PV"]["electric_to_grid_series_kw"], pv_to_grid) + push!(dispatch_series["PV"]["electric_curtailed_series_kw"], pv_curtailed) + push!(dispatch_series["ElectricStorage"]["storage_to_load_series_kw"], batt_to_load) + push!(dispatch_series["ElectricStorage"]["storage_to_grid_series_kw"], batt_to_grid) + push!(dispatch_series["ElectricStorage"]["soc_series_fraction"], batt_soc) + push!(dispatch_series["ElectricUtility"]["electric_to_load_series_kw"], util_to_load) + push!(dispatch_series["ElectricUtility"]["electric_to_storage_series_kw"], util_to_batt) + push!(dispatch_series["ElectricUtility"]["emissions_series_lb_CO2"], + co2_grid_emissions_series[idx] * grid_power / time_steps_per_hour) + push!(dispatch_series["ElectricLoad"]["load_series_kw"], loads_kw[idx]) + + # Running electricity costs (reported as separate components; see results below) + # Energy (grid purchase) charge for this timestep + step_energy_charge = grid_power * energy_rates[idx] / time_steps_per_hour + + # Export credit for this timestep. NEM credits at the retail energy rate; otherwise WHL credits + # at the wholesale rate. NOTE: when both NEM and WHL are available the model chooses per horizon + # and the executed-timestep bin split is not returned, so this can misprice such timesteps. + step_export_kw = pv_to_grid + batt_to_grid + export_rate_idx = nem_active ? energy_rates[idx] : + (whl_rate_full !== nothing ? whl_rate_full[idx] : 0.0) + step_export_benefit = step_export_kw * export_rate_idx / time_steps_per_hour + + push!(energy_cost_series, step_energy_charge) + push!(export_benefit_series, step_export_benefit) + total_energy_cost += step_energy_charge + total_export_benefit += step_export_benefit + + soc_init_frac = batt_soc + + # Update monthly and TOU peak demand as max(current ts grid_power, previous max) + current_month = ts_to_month[idx] + monthly_previous_peak_demands[current_month] = max(grid_power, monthly_previous_peak_demands[current_month]) + + if n_tou_ratchets > 0 + current_ratchet = ts_to_ratchet[idx] + if current_ratchet > 0 + tou_previous_peak_demands[current_ratchet] = max(grid_power, tou_previous_peak_demands[current_ratchet]) + end + end + + end + + @info "MPC looping completed." + + # Calculate final demand costs + monthly_demand_cost_total = sum(monthly_previous_peak_demands .* monthly_demand_rates) + tou_demand_cost_total = n_tou_ratchets > 0 ? + sum(tou_previous_peak_demands .* tou_demand_rates) : 0.0 + + return build_dispatch_response( + "optimal", + result_dict = Dict( + "MPC" => Dict( + "time_steps_per_hour" => time_steps_per_hour, + "horizon_time_steps" => horizon, + ), + "PV" => merge(Dict("size_kw" => pv_kw), dispatch_series["PV"]), + "ElectricStorage" => merge(Dict("size_kw" => batt_kw, "size_kwh" => batt_kwh), dispatch_series["ElectricStorage"]), + "ElectricUtility" => dispatch_series["ElectricUtility"], + "ElectricLoad" => dispatch_series["ElectricLoad"], + "ElectricTariff" => Dict( + # --- Cost components (before tax); combine for the total bill below --- + "total_energy_cost" => total_energy_cost, # grid purchases (energy) only + "total_export_benefit" => total_export_benefit, # NEM/WHL credits (positive = revenue) + "total_tou_demand_cost" => tou_demand_cost_total, + "total_non_tou_monthly_demand_cost" => monthly_demand_cost_total, + # --- Total electricity bill = energy charge - export benefit + demand charges --- + "total_electricity_bill" => total_energy_cost - total_export_benefit + + tou_demand_cost_total + monthly_demand_cost_total, + "energy_cost_series_per_timestep" => energy_cost_series, + "export_benefit_series_per_timestep" => export_benefit_series, + "tou_peaks_by_ratchet_kw" => tou_previous_peak_demands, + "monthly_peaks_kw" => monthly_previous_peak_demands, # Optimal peaks (whereas REopt's ElectricLoad.monthly_peaks_kw is BAU peaks) + ), + ) + ) +end diff --git a/reo/exceptions.py b/reo/exceptions.py index 1fca1087a..be8ad5751 100644 --- a/reo/exceptions.py +++ b/reo/exceptions.py @@ -1,4 +1,4 @@ -# REopt®, Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/REopt_API/blob/master/LICENSE. +# REopt®, Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NatLabRockies/REopt_API/blob/master/LICENSE. from reo.models import ErrorModel import logging log = logging.getLogger(__name__) @@ -22,7 +22,7 @@ def __init__(self, task='', name='', run_uuid='', message='', traceback='', user :param traceback: sys.exc_info()[2] """ if message == "Wind Dataset Timed Out": - msg_with_email = (" Please try again later or email reopt@nrel.gov for support or un-check the wind option " + msg_with_email = (" Please try again later or email reopt@nlr.gov for support or un-check the wind option " "to take wind out of the analysis") elif message.startswith("PV Watts could not locate a dataset station"): msg_with_email = (" Please increase your PV search radius parameter, or choose an alternate " @@ -30,14 +30,14 @@ def __init__(self, task='', name='', run_uuid='', message='', traceback='', user "You can also use a search radius of 0 to return PV Watts results regardless of distance " "to the nearest station.") elif run_uuid: - msg_with_email = (" Please visit https://github.com/NREL/REopt-API-Analysis/discussions for support with " - "common API usage issues. You can also email reopt@nrel.gov with your run_uuid ({}) for support.".format(run_uuid)) + msg_with_email = (" Please visit https://github.com/NatLabRockies/REopt-Analysis-Scripts/discussions for support with " + "common API usage issues. You can also email reopt@nlr.gov with your run_uuid ({}) for support.".format(run_uuid)) elif user_uuid: - msg_with_email = (" Please visit https://github.com/NREL/REopt-API-Analysis/discussions for support with " - "common API usage issues. You can also email reopt@nrel.gov with your user_uuid ({}) for support.".format(user_uuid)) + msg_with_email = (" Please visit https://github.com/NatLabRockies/REopt-Analysis-Scripts/discussions for support with " + "common API usage issues. You can also email reopt@nlr.gov with your user_uuid ({}) for support.".format(user_uuid)) else: - msg_with_email = (" Please visit https://github.com/NREL/REopt-API-Analysis/discussions for support with " - "common API usage issues. You can also email reopt@nrel.gov for support.") + msg_with_email = (" Please visit https://github.com/NatLabRockies/REopt-Analysis-Scripts/discussions for support with " + "common API usage issues. You can also email reopt@nlr.gov for support.") if 'infeasible' not in traceback: self.message = message + msg_with_email # msg_with_email included in messages: error response, but not in error table diff --git a/reoptjl/custom_table_config.py b/reoptjl/custom_table_config.py index 4cd3ec479..4d52f13cc 100644 --- a/reoptjl/custom_table_config.py +++ b/reoptjl/custom_table_config.py @@ -804,6 +804,12 @@ "bau_value" : lambda df: safe_get(df, "outputs.ElectricStorage.storage_to_load_series_kw_bau"), "scenario_value": lambda df: safe_get(df, "outputs.ElectricStorage.storage_to_load_series_kw") }, + { + "label" : "Battery Exported to Grid (kWh/yr)", + "key" : "battery_exported_to_grid", + "bau_value" : lambda df: safe_get(df, "outputs.ElectricStorage.storage_to_grid_series_kw_bau"), + "scenario_value": lambda df: safe_get(df, "outputs.ElectricStorage.storage_to_grid_series_kw") + }, { "label" : "Generator Serving Load (kWh/yr)", "key" : "generator_serving_load", diff --git a/reoptjl/migrations/0114_chpoutputs_electric_curtailed_series_kw.py b/reoptjl/migrations/0114_chpoutputs_electric_curtailed_series_kw.py new file mode 100644 index 000000000..3269fcd6e --- /dev/null +++ b/reoptjl/migrations/0114_chpoutputs_electric_curtailed_series_kw.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.26 on 2026-02-03 16:40 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0113_merge_20251209_2338'), + ] + + operations = [ + migrations.AddField( + model_name='chpoutputs', + name='electric_curtailed_series_kw', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, null=True), blank=True, default=list, help_text='Electric power curtailed time-series array [kW]', size=None), + ), + ] diff --git a/reoptjl/migrations/0116_rename_state_of_health_electricstorageoutputs_state_of_health_series_fraction_and_more.py b/reoptjl/migrations/0116_rename_state_of_health_electricstorageoutputs_state_of_health_series_fraction_and_more.py new file mode 100644 index 000000000..4945d667e --- /dev/null +++ b/reoptjl/migrations/0116_rename_state_of_health_electricstorageoutputs_state_of_health_series_fraction_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.26 on 2026-05-15 22:25 + +import django.contrib.postgres.fields +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0115_alter_coldthermalstorageinputs_installed_cost_per_gal_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='electricstorageoutputs', + old_name='state_of_health', + new_name='state_of_health_series_fraction', + ), + migrations.AddField( + model_name='electricstorageinputs', + name='fixed_soc_series_fraction', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), blank=True, default=list, help_text='If provided, SOC (as fraction of total energy capacity) will not be optimized and will instead be fixed to the values providedhere +- the absolute fixed_soc_series_fraction_tolerance. Must be an array of values 0-1 with length equal to 8760*time_steps_per_hour.', size=None), + ), + migrations.AddField( + model_name='electricstorageinputs', + name='fixed_soc_series_fraction_tolerance', + field=models.FloatField(blank=True, help_text='Absolute tolerance on fixed_soc_series_fraction to avoid infeasible solutions when fixed_soc_series_fraction is provided.', null=True, validators=[django.core.validators.MinValueValidator(-1), django.core.validators.MaxValueValidator(1)]), + ), + ] diff --git a/reoptjl/migrations/0117_merge_20260530_1640.py b/reoptjl/migrations/0117_merge_20260530_1640.py new file mode 100644 index 000000000..0302ff8e6 --- /dev/null +++ b/reoptjl/migrations/0117_merge_20260530_1640.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.26 on 2026-05-30 16:40 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0116_alter_apimeta_api_key_alter_apimeta_job_type'), + ('reoptjl', '0116_rename_state_of_health_electricstorageoutputs_state_of_health_series_fraction_and_more'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0117_merge_20260601_2056.py b/reoptjl/migrations/0117_merge_20260601_2056.py new file mode 100644 index 000000000..6040e706e --- /dev/null +++ b/reoptjl/migrations/0117_merge_20260601_2056.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.26 on 2026-06-01 20:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0116_alter_apimeta_api_key_alter_apimeta_job_type'), + ('reoptjl', '0116_rename_state_of_health_electricstorageoutputs_state_of_health_series_fraction_and_more'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0117_merge_20260803_1544.py b/reoptjl/migrations/0117_merge_20260803_1544.py new file mode 100644 index 000000000..e50521d7c --- /dev/null +++ b/reoptjl/migrations/0117_merge_20260803_1544.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.26 on 2026-08-03 15:44 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0114_chpoutputs_electric_curtailed_series_kw'), + ('reoptjl', '0116_alter_apimeta_api_key_alter_apimeta_job_type'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0118_merge_20260629_2347.py b/reoptjl/migrations/0118_merge_20260629_2347.py new file mode 100644 index 000000000..e55228f28 --- /dev/null +++ b/reoptjl/migrations/0118_merge_20260629_2347.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.26 on 2026-06-29 23:47 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0117_merge_20260530_1640'), + ('reoptjl', '0117_merge_20260601_2056'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0119_alter_electricstorageinputs_fixed_soc_series_fraction_tolerance.py b/reoptjl/migrations/0119_alter_electricstorageinputs_fixed_soc_series_fraction_tolerance.py new file mode 100644 index 000000000..2378b63f3 --- /dev/null +++ b/reoptjl/migrations/0119_alter_electricstorageinputs_fixed_soc_series_fraction_tolerance.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.26 on 2026-07-09 18:09 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0118_merge_20260629_2347'), + ] + + operations = [ + migrations.AlterField( + model_name='electricstorageinputs', + name='fixed_soc_series_fraction_tolerance', + field=models.FloatField(blank=True, help_text='Absolute tolerance on fixed_soc_series_fraction to avoid infeasible solutions when fixed_soc_series_fraction is provided.', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1)]), + ), + ] diff --git a/reoptjl/migrations/0120_electricstorageinputs_dispatch_strategy_and_more.py b/reoptjl/migrations/0120_electricstorageinputs_dispatch_strategy_and_more.py new file mode 100644 index 000000000..486adb62d --- /dev/null +++ b/reoptjl/migrations/0120_electricstorageinputs_dispatch_strategy_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.26 on 2026-07-09 20:32 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0119_alter_electricstorageinputs_fixed_soc_series_fraction_tolerance'), + ] + + operations = [ + migrations.AddField( + model_name='electricstorageinputs', + name='dispatch_strategy', + field=models.TextField(blank=True, choices=[('optimized', 'Optimized'), ('peak_shaving_look_ahead', 'Peak Shaving Look Ahead'), ('peak_shaving_look_behind', 'Peak Shaving Look Behind'), ('self_consumption', 'Self Consumption'), ('backup', 'Backup'), ('custom_soc', 'Custom Soc'), ('daily_foresight_optimized', 'Daily Foresight Optimized')], default='optimized', help_text='Electric storage dispatch strategy can be one of: optimized, peak_shaving_look_ahead, peak_shaving_look_behind, self_consumption, backup, custom_soc, daily_foresight_optimized', null=True), + ), + migrations.AlterField( + model_name='electricstorageinputs', + name='soc_min_fraction', + field=models.FloatField(blank=True, 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)]), + ), + ] diff --git a/reoptjl/migrations/0121_electricstorageinputs_can_export_beyond_nem_limit_and_more.py b/reoptjl/migrations/0121_electricstorageinputs_can_export_beyond_nem_limit_and_more.py new file mode 100644 index 000000000..d1c39e257 --- /dev/null +++ b/reoptjl/migrations/0121_electricstorageinputs_can_export_beyond_nem_limit_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 4.2.26 on 2026-07-15 19:47 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0120_electricstorageinputs_dispatch_strategy_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='electricstorageinputs', + name='can_export_beyond_nem_limit', + field=models.BooleanField(blank=True, default=False, help_text='True/False for if technology can export energy beyond the annual site load (and be compensated for that energy at the export_rate_beyond_net_metering_limit).'), + ), + migrations.AddField( + model_name='electricstorageinputs', + name='can_net_meter', + field=models.BooleanField(blank=True, default=False, help_text='True/False for if technology has option to participate in net metering agreement with utility. Note that a technology can only participate in either net metering or wholesale rates (not both).'), + ), + migrations.AddField( + model_name='electricstorageinputs', + name='can_wholesale', + field=models.BooleanField(blank=True, default=False, help_text='True/False for if technology has option to export energy that is compensated at the wholesale_rate. Note that a technology can only participate in either net metering or wholesale rates (not both).'), + ), + migrations.AddField( + model_name='electricstorageoutputs', + name='storage_to_grid_series_kw', + 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/0122_merge_20260804_1339.py b/reoptjl/migrations/0122_merge_20260804_1339.py new file mode 100644 index 000000000..2eb4a5a90 --- /dev/null +++ b/reoptjl/migrations/0122_merge_20260804_1339.py @@ -0,0 +1,14 @@ +# Generated by Django 4.2.26 on 2026-08-04 13:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0117_merge_20260803_1544'), + ('reoptjl', '0121_electricstorageinputs_can_export_beyond_nem_limit_and_more'), + ] + + operations = [ + ] diff --git a/reoptjl/migrations/0123_chpinputs_existing_kw_and_more.py b/reoptjl/migrations/0123_chpinputs_existing_kw_and_more.py new file mode 100644 index 000000000..6b6a8dff8 --- /dev/null +++ b/reoptjl/migrations/0123_chpinputs_existing_kw_and_more.py @@ -0,0 +1,121 @@ +# Generated by Django 4.2.26 on 2026-08-04 22:24 + +import django.contrib.postgres.fields +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0122_merge_20260804_1339'), + ] + + operations = [ + migrations.AddField( + model_name='chpinputs', + name='existing_kw', + field=models.FloatField(blank=True, default=0, help_text='Existing CHP electric capacity (based on rated electric power)', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100000.0)]), + ), + migrations.AddField( + model_name='chpinputs', + name='fuel_cost_escalation_rate_fraction', + field=models.FloatField(blank=True, help_text='Annual nominal chp fuel cost escalation rate, as a decimal.', null=True, validators=[django.core.validators.MinValueValidator(-1.0), django.core.validators.MaxValueValidator(1.0)]), + ), + migrations.AddField( + model_name='chpinputs', + name='name', + field=models.TextField(blank=True, default='CHP', help_text='CHP description for distinguishing between multiple CHP models'), + ), + migrations.AddField( + model_name='chpinputs', + name='operating_reserve_required_fraction', + field=models.FloatField(blank=True, help_text='Only applicable when off_grid_flag=True. Required operating reserves applied to each timestep as a fraction of CHP generation serving load in that timestep.', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(1.0)]), + ), + migrations.AddField( + model_name='chpinputs', + name='production_factor_series', + field=django.contrib.postgres.fields.ArrayField(base_field=models.FloatField(blank=True), blank=True, default=list, help_text='Optional user-defined production factors. Must be normalized to units of kW-AC/kW-AC nameplate, representing the AC power (kW) output per 1 kW-AC of CHP capacity in each time step. The series must be one year (January through December) of hourly, 30-minute, or 15-minute data.', size=None), + ), + migrations.AddField( + model_name='chpinputs', + name='ramp_rate_fraction_per_hour', + field=models.FloatField(blank=True, default=1.0, help_text='Maximum rate of change in electric production per hour as a fraction of size_kw [kW/size_kw/hour].', validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(1000.0)]), + ), + migrations.AddField( + model_name='chpoutputs', + name='annual_electric_production_kwh_bau', + field=models.FloatField(blank=True, help_text='Electric energy produced in a year by the existing CHP system in BAU [kWh]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='annual_fuel_consumption_mmbtu_bau', + field=models.FloatField(blank=True, help_text='Fuel consumed in a year by the existing CHP system in BAU [MMBtu]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='annual_thermal_production_mmbtu_bau', + field=models.FloatField(blank=True, help_text='Thermal energy produced in a year by the existing CHP system in BAU [MMBtu]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='lifecycle_fuel_cost_after_tax_bau', + field=models.FloatField(blank=True, help_text='Present value of cost of fuel consumed by the existing CHP system in BAU, after tax [$]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='lifecycle_standby_cost_after_tax_bau', + field=models.FloatField(blank=True, help_text='Present value of all CHP standby charges for the existing CHP system in BAU, after tax.', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='name', + field=models.TextField(blank=True, default='CHP', help_text='CHP description for distinguishing between multiple CHP models'), + ), + migrations.AddField( + model_name='chpoutputs', + name='size_kw_bau', + field=models.FloatField(blank=True, help_text='Power capacity size of the existing CHP system in BAU [kW]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='year_one_fuel_cost_after_tax_bau', + field=models.FloatField(blank=True, help_text='Cost of fuel consumed by the existing CHP system in year one in BAU, after tax [$]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='year_one_fuel_cost_before_tax_bau', + field=models.FloatField(blank=True, help_text='Cost of fuel consumed by the existing CHP system in year one in BAU [$]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='year_one_standby_cost_after_tax_bau', + field=models.FloatField(blank=True, help_text='CHP standby charges in year one for the existing CHP system in BAU, after tax [$]', null=True), + ), + migrations.AddField( + model_name='chpoutputs', + name='year_one_standby_cost_before_tax_bau', + field=models.FloatField(blank=True, help_text='CHP standby charges in year one for the existing CHP system in BAU [$]', null=True), + ), + migrations.AlterField( + model_name='chpinputs', + name='max_kw', + field=models.FloatField(blank=True, help_text='Maximum new CHP size (in kWe) constraint for optimization (upper bound on additional capacity beyond existing_kw). Set to zero to disable CHP', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(100000000.0)]), + ), + migrations.AlterField( + model_name='chpinputs', + name='meta', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='CHPInputs', to='reoptjl.apimeta'), + ), + migrations.AlterField( + model_name='chpinputs', + name='min_kw', + field=models.FloatField(blank=True, default=0, help_text='Minimum new CHP size constraint for optimization (lower bound on additional capacity beyond existing_kw).', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000000000.0)]), + ), + migrations.AlterField( + model_name='chpoutputs', + name='meta', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='CHPOutputs', to='reoptjl.apimeta'), + ), + ] diff --git a/reoptjl/migrations/0124_chpinputs_follow_heating_load.py b/reoptjl/migrations/0124_chpinputs_follow_heating_load.py new file mode 100644 index 000000000..03756771d --- /dev/null +++ b/reoptjl/migrations/0124_chpinputs_follow_heating_load.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.26 on 2026-08-05 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reoptjl', '0123_chpinputs_existing_kw_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='chpinputs', + name='follow_heating_load', + field=models.BooleanField(blank=True, default=False, help_text='Boolean indicator if CHP follows the heating load by running at capacity or meeting the load only', null=True), + ), + ] diff --git a/reoptjl/models.py b/reoptjl/models.py index d7df3b936..d3a79d540 100644 --- a/reoptjl/models.py +++ b/reoptjl/models.py @@ -3668,6 +3668,16 @@ class ElectricStorageInputs(BaseModel, models.Model): primary_key=True ) + ELECTRICSTORAGE_DISPATCH_STRATEGY = models.TextChoices('ELECTRICSTORAGE_DISPATCH_STRATEGY', ( + "optimized", + "peak_shaving_look_ahead", + "peak_shaving_look_behind", + "self_consumption", + "backup", + "custom_soc", + "daily_foresight_optimized" + )) + min_kw = models.FloatField( default=0, validators=[ @@ -3731,8 +3741,14 @@ class ElectricStorageInputs(BaseModel, models.Model): blank=True, help_text="Battery rectifier efficiency" ) + dispatch_strategy = models.TextField( + default=ELECTRICSTORAGE_DISPATCH_STRATEGY.optimized, + choices=ELECTRICSTORAGE_DISPATCH_STRATEGY.choices, + null=True, + blank=True, + help_text="Electric storage dispatch strategy can be one of: optimized, peak_shaving_look_ahead, peak_shaving_look_behind, self_consumption, backup, custom_soc, daily_foresight_optimized" + ) soc_min_fraction = models.FloatField( - default=0.2, validators=[ MinValueValidator(0), MaxValueValidator(1.0) @@ -3753,10 +3769,48 @@ class ElectricStorageInputs(BaseModel, models.Model): blank=True, help_text="Battery state of charge at first hour of optimization as fraction of energy capacity." ) + fixed_soc_series_fraction = ArrayField( + models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1) + ], + blank=True + ), + default=list, blank=True, + help_text=("If provided, SOC (as fraction of total energy capacity) will not be optimized and will instead be fixed to the values provided" + "here +- the absolute fixed_soc_series_fraction_tolerance. Must be an array of values 0-1 with length equal to 8760*time_steps_per_hour.") + ) + fixed_soc_series_fraction_tolerance = models.FloatField( + validators=[ + MinValueValidator(0), + MaxValueValidator(1) + ], + null=True, blank=True, + help_text="Absolute tolerance on fixed_soc_series_fraction to avoid infeasible solutions when fixed_soc_series_fraction is provided." + ) can_grid_charge = models.BooleanField( blank=True, help_text="Flag to set whether the battery can be charged from the grid, or just onsite generation." ) + can_net_meter = models.BooleanField( + default=False, + blank=True, + help_text=("True/False for if technology has option to participate in net metering agreement with utility. " + "Note that a technology can only participate in either net metering or wholesale rates (not both).") + ) + can_wholesale = models.BooleanField( + default=False, + blank=True, + help_text=("True/False for if technology has option to export energy that is compensated at the wholesale_rate. " + "Note that a technology can only participate in either net metering or wholesale rates (not both).") + ) + can_export_beyond_nem_limit = models.BooleanField( + default=False, + blank=True, + help_text=("True/False for if technology can export energy beyond the annual site load (and be compensated for " + "that energy at the export_rate_beyond_net_metering_limit).") + ) installed_cost_per_kw = models.FloatField( default=968.0, validators=[ @@ -3942,9 +3996,13 @@ class ElectricStorageOutputs(BaseModel, models.Model): models.FloatField(null=True, blank=True), blank=True, default=list ) + storage_to_grid_series_kw = ArrayField( + models.FloatField(null=True, blank=True), + blank=True, default=list + ) initial_capital_cost = models.FloatField(null=True, blank=True) maintenance_cost = models.FloatField(null=True, blank=True) - state_of_health = ArrayField( + state_of_health_series_fraction = ArrayField( models.FloatField(null=True, blank=True), blank=True, default=list ) @@ -4361,11 +4419,16 @@ class GeneratorOutputs(BaseModel, models.Model): class CHPInputs(BaseModel, models.Model): key = "CHP" - meta = models.OneToOneField( + meta = models.ForeignKey( to=APIMeta, on_delete=models.CASCADE, related_name="CHPInputs", - unique=True + unique=False + ) + name = models.TextField( + blank=True, + default="CHP", + help_text="CHP description for distinguishing between multiple CHP models" ) # Prime mover @@ -4491,7 +4554,7 @@ class CHPInputs(BaseModel, models.Model): ], null=True, blank=True, - help_text="Maximum CHP size (in kWe) constraint for optimization. Set to zero to disable CHP" + help_text="Maximum new CHP size (in kWe) constraint for optimization (upper bound on additional capacity beyond existing_kw). Set to zero to disable CHP" ) cooling_thermal_factor = models.FloatField( validators=[ @@ -4526,6 +4589,15 @@ class CHPInputs(BaseModel, models.Model): blank=True, help_text="CHP size class. Must be an integer value between 0 and 7" ) + existing_kw = models.FloatField( + default=0, + validators=[ + MinValueValidator(0), + MaxValueValidator(1.0e5) + ], + blank=True, + help_text="Existing CHP electric capacity (based on rated electric power)" + ) min_kw = models.FloatField( default=0, validators=[ @@ -4533,7 +4605,7 @@ class CHPInputs(BaseModel, models.Model): MaxValueValidator(1.0e9) ], blank=True, - help_text="Minimum CHP size constraint for optimization" + help_text="Minimum new CHP size constraint for optimization (lower bound on additional capacity beyond existing_kw)." ) fuel_type = models.TextField( null=False, @@ -4561,6 +4633,15 @@ class CHPInputs(BaseModel, models.Model): blank=True, help_text="CHP system per-operating-hour (variable) operations and maintenance costs in $/hr-kW" ) + ramp_rate_fraction_per_hour = models.FloatField( + default=1.0, + validators=[ + MinValueValidator(0.0), + MaxValueValidator(1.0e3) + ], + blank=True, + help_text="Maximum rate of change in electric production per hour as a fraction of size_kw [kW/size_kw/hour]." + ) supplementary_firing_capital_cost_per_kw = models.FloatField( default=150, validators=[ @@ -4645,6 +4726,12 @@ class CHPInputs(BaseModel, models.Model): blank=True, help_text="Boolean indicator if CHP follows the electrical load by running at capacity or meeting the load only" ) + follow_heating_load = models.BooleanField( + default=False, + null=True, + blank=True, + help_text="Boolean indicator if CHP follows the heating load by running at capacity or meeting the load only" + ) can_serve_dhw = models.BooleanField( default=True, null=True, @@ -4663,6 +4750,26 @@ class CHPInputs(BaseModel, models.Model): blank=True, help_text="Boolean indicator if CHP can serve process heat load" ) + operating_reserve_required_fraction = models.FloatField( + validators=[ + MinValueValidator(0.0), + MaxValueValidator(1.0) + ], + blank=True, + null=True, + help_text=("Only applicable when off_grid_flag=True. Required operating reserves applied to each timestep " + "as a fraction of CHP generation serving load in that timestep.") + ) + production_factor_series = ArrayField( + models.FloatField( + blank=True + ), + default=list, + blank=True, + help_text=("Optional user-defined production factors. Must be normalized to units of kW-AC/kW-AC nameplate, " + "representing the AC power (kW) output per 1 kW-AC of CHP capacity in each time step. " + "The series must be one year (January through December) of hourly, 30-minute, or 15-minute data.") + ) #Financial and emissions @@ -4884,6 +4991,15 @@ class CHPInputs(BaseModel, models.Model): null=True, help_text="Pounds of CO2 emitted per MMBTU of CHP fuel burned." ) + fuel_cost_escalation_rate_fraction = models.FloatField( + validators=[ + MinValueValidator(-1.0), + MaxValueValidator(1.0) + ], + null=True, + blank=True, + help_text="Annual nominal chp fuel cost escalation rate, as a decimal." + ) def clean(self): error_messages = {} @@ -4913,17 +5029,26 @@ def clean(self): class CHPOutputs(BaseModel, models.Model): key = "CHPOutputs" - meta = models.OneToOneField( + meta = models.ForeignKey( to=APIMeta, on_delete=models.CASCADE, related_name="CHPOutputs", - unique=True + unique=False + ) + name = models.TextField( + blank=True, + default="CHP", + help_text="CHP description for distinguishing between multiple CHP models" ) size_kw = models.FloatField( null=True, blank=True, help_text="Power capacity size of the CHP system [kW]" ) + size_kw_bau = models.FloatField( + null=True, blank=True, + help_text="Power capacity size of the existing CHP system in BAU [kW]" + ) size_supplemental_firing_kw = models.FloatField( null=True, blank=True, help_text="Power capacity of CHP supplementary firing system [kW]" @@ -4932,14 +5057,26 @@ class CHPOutputs(BaseModel, models.Model): null=True, blank=True, help_text="Fuel consumed in a year [MMBtu]" ) + annual_fuel_consumption_mmbtu_bau = models.FloatField( + null=True, blank=True, + help_text="Fuel consumed in a year by the existing CHP system in BAU [MMBtu]" + ) annual_electric_production_kwh = models.FloatField( null=True, blank=True, help_text="Electric energy produced in a year [kWh]" ) + annual_electric_production_kwh_bau = models.FloatField( + null=True, blank=True, + help_text="Electric energy produced in a year by the existing CHP system in BAU [kWh]" + ) annual_thermal_production_mmbtu = models.FloatField( null=True, blank=True, help_text="Thermal energy produced in a year [MMBtu]" ) + annual_thermal_production_mmbtu_bau = models.FloatField( + null=True, blank=True, + help_text="Thermal energy produced in a year by the existing CHP system in BAU [MMBtu]" + ) electric_production_series_kw = ArrayField( models.FloatField( null=True, blank=True @@ -4968,6 +5105,13 @@ class CHPOutputs(BaseModel, models.Model): default=list, blank=True, help_text="Electric power serving the electric load time-series array [kW]" ) + electric_curtailed_series_kw = ArrayField( + models.FloatField( + null=True, blank=True + ), + default=list, blank=True, + help_text="Electric power curtailed time-series array [kW]" + ) thermal_to_storage_series_mmbtu_per_hour = ArrayField( models.FloatField( null=True, blank=True @@ -5007,26 +5151,50 @@ class CHPOutputs(BaseModel, models.Model): null=True, blank=True, help_text="Cost of fuel consumed by the CHP system in year one [$]" ) + year_one_fuel_cost_before_tax_bau = models.FloatField( + null=True, blank=True, + help_text="Cost of fuel consumed by the existing CHP system in year one in BAU [$]" + ) year_one_fuel_cost_after_tax = models.FloatField( null=True, blank=True, help_text="Cost of fuel consumed by the CHP system in year one, after tax [$]" - ) + ) + year_one_fuel_cost_after_tax_bau = models.FloatField( + null=True, blank=True, + help_text="Cost of fuel consumed by the existing CHP system in year one in BAU, after tax [$]" + ) lifecycle_fuel_cost_after_tax = models.FloatField( null=True, blank=True, help_text="Present value of cost of fuel consumed by the CHP system, after tax [$]" ) + lifecycle_fuel_cost_after_tax_bau = models.FloatField( + null=True, blank=True, + help_text="Present value of cost of fuel consumed by the existing CHP system in BAU, after tax [$]" + ) year_one_standby_cost_before_tax = models.FloatField( null=True, blank=True, help_text="CHP standby charges in year one [$]" ) + year_one_standby_cost_before_tax_bau = models.FloatField( + null=True, blank=True, + help_text="CHP standby charges in year one for the existing CHP system in BAU [$]" + ) year_one_standby_cost_after_tax = models.FloatField( null=True, blank=True, help_text="CHP standby charges in year one, after tax [$]" - ) + ) + year_one_standby_cost_after_tax_bau = models.FloatField( + null=True, blank=True, + help_text="CHP standby charges in year one for the existing CHP system in BAU, after tax [$]" + ) lifecycle_standby_cost_after_tax = models.FloatField( null=True, blank=True, help_text="Present value of all CHP standby charges, after tax." ) + lifecycle_standby_cost_after_tax_bau = models.FloatField( + null=True, blank=True, + help_text="Present value of all CHP standby charges for the existing CHP system in BAU, after tax." + ) thermal_production_series_mmbtu_per_hour = ArrayField( models.FloatField(null=True, blank=True), default = list, @@ -9422,8 +9590,16 @@ def filter_none_and_empty_array(d:dict): try: d["ColdThermalStorage"] = filter_none_and_empty_array(meta.ColdThermalStorageInputs.dict) except: pass - try: d["CHP"] = filter_none_and_empty_array(meta.CHPInputs.dict) - except: pass + try: + chps = meta.CHPInputs.all() + if len(chps) == 1: + d["CHP"] = filter_none_and_empty_array(chps[0].dict) + elif len(chps) > 1: + d["CHP"] = [] + for chp in chps: + d["CHP"].append(filter_none_and_empty_array(chp.dict)) + except: + pass try: d["SteamTurbine"] = filter_none_and_empty_array(meta.SteamTurbineInputs.dict) except: pass diff --git a/reoptjl/src/process_results.py b/reoptjl/src/process_results.py index 38036f6fc..cef2c71b4 100644 --- a/reoptjl/src/process_results.py +++ b/reoptjl/src/process_results.py @@ -64,7 +64,11 @@ def process_results(results: dict, run_uuid: str) -> None: if "CoolingLoad" in results.keys(): CoolingLoadOutputs.create(meta=meta, **results["CoolingLoad"]).save() if "CHP" in results.keys(): - CHPOutputs.create(meta=meta, **results["CHP"]).save() + if isinstance(results["CHP"], dict): + CHPOutputs.create(meta=meta, **results["CHP"]).save() + elif isinstance(results["CHP"], list): + for chpdict in results["CHP"]: + CHPOutputs.create(meta=meta, **chpdict).save() if "AbsorptionChiller" in results.keys(): AbsorptionChillerOutputs.create(meta=meta, **results["AbsorptionChiller"]).save() if "Outages" in results.keys(): @@ -134,10 +138,21 @@ def update_inputs_in_database(inputs_to_update: dict, run_uuid: str) -> None: if inputs_to_update["Site"]: SiteInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["Site"]) - if inputs_to_update["CHP"]: # Will be an empty dictionary if CHP is not considered - if inputs_to_update["CHP"].get("installed_cost_per_kw") and type(inputs_to_update["CHP"].get("installed_cost_per_kw")) == float: - inputs_to_update["CHP"]["installed_cost_per_kw"] = [inputs_to_update["CHP"]["installed_cost_per_kw"]] - CHPInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["CHP"]) + if inputs_to_update["CHP"]: # Will be an empty dictionary/list if CHP is not considered + if isinstance(inputs_to_update["CHP"], dict): + if inputs_to_update["CHP"].get("installed_cost_per_kw") and type(inputs_to_update["CHP"].get("installed_cost_per_kw")) == float: + inputs_to_update["CHP"]["installed_cost_per_kw"] = [inputs_to_update["CHP"]["installed_cost_per_kw"]] + prune_update_fields(CHPInputs, inputs_to_update["CHP"]) + CHPInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["CHP"]) + elif isinstance(inputs_to_update["CHP"], list): + for chp_input in inputs_to_update["CHP"]: + if chp_input.get("installed_cost_per_kw") and type(chp_input.get("installed_cost_per_kw")) == float: + chp_input["installed_cost_per_kw"] = [chp_input["installed_cost_per_kw"]] + prune_update_fields(CHPInputs, chp_input) + name = chp_input.get("name") + if not name: + raise ValueError(f"CHP list item missing required 'name' field for update. Cannot update all CHP rows without identifying specific CHP.") + CHPInputs.objects.filter(meta__run_uuid=run_uuid, name=name).update(**chp_input) 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"]: @@ -156,7 +171,15 @@ 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"]) + if isinstance(inputs_to_update["PV"], dict): + PVInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["PV"]) + elif isinstance(inputs_to_update["PV"], list): + for pv_input in inputs_to_update["PV"]: + prune_update_fields(PVInputs, pv_input) + name = pv_input.get("name") + if not name: + raise ValueError(f"PV list item missing required 'name' field for update. Cannot update all PV rows without identifying specific PV.") + PVInputs.objects.filter(meta__run_uuid=run_uuid, name=name).update(**pv_input) if inputs_to_update["Wind"]: prune_update_fields(WindInputs, inputs_to_update["Wind"]) WindInputs.objects.filter(meta__run_uuid=run_uuid).update(**inputs_to_update["Wind"]) diff --git a/reoptjl/src/run_jump_model.py b/reoptjl/src/run_jump_model.py index 7a4733160..7e0f3980b 100644 --- a/reoptjl/src/run_jump_model.py +++ b/reoptjl/src/run_jump_model.py @@ -35,7 +35,11 @@ def on_failure(self, exc, task_id, args, kwargs, einfo): exc.save_to_db() msg = exc.message meta = APIMeta.objects.get(run_uuid=exc.run_uuid) - meta.status = "An error occurred. See messages for more." + # Server-side failures map to 500 at /results; other failures (e.g. infeasible, timeout) map to 400. + if isinstance(exc, (UnexpectedError, REoptFailedToStartError)): + meta.status = "Internal Server Error. See messages for more." + else: + meta.status = "error" meta.save(update_fields=["status"]) Message.create(meta=meta, message_type="error", message=msg).save() @@ -68,10 +72,21 @@ def run_jump_model(run_uuid): response_json = response.json() if response.status_code == 500: raise REoptFailedToStartError(task=name, message=response_json["error"], run_uuid=run_uuid, user_uuid=user_uuid) - results = response_json["results"] - reopt_version = response_json["reopt_version"] - if results["status"].strip().lower() != "error": - inputs_with_defaults_set_in_julia = response_json["inputs_with_defaults_set_in_julia"] + if response.status_code == 400: + # REopt.jl returned an input-validation error; store it as an error result so /results returns 400 with the messages. + if "results" in response_json: + # Regular reopt error: Messages (incl. has_stacktrace) are nested under "results". + results = response_json["results"] + else: + # MPC-style error envelope has Messages at the top level. + results = {"status": "error", + "Messages": response_json.get("Messages", {"errors": ["Invalid inputs. Please check your inputs and try again."]})} + reopt_version = response_json.get("reopt_version", "") + else: + results = response_json["results"] + reopt_version = response_json["reopt_version"] + if results["status"].strip().lower() != "error": + inputs_with_defaults_set_in_julia = response_json["inputs_with_defaults_set_in_julia"] time_dict["pyjulia_run_reopt_seconds"] = time.time() - t_start results.update(time_dict) diff --git a/reoptjl/test/posts/all_inputs_test.json b/reoptjl/test/posts/all_inputs_test.json index 36926c78e..3cc26956b 100644 --- a/reoptjl/test/posts/all_inputs_test.json +++ b/reoptjl/test/posts/all_inputs_test.json @@ -167,6 +167,7 @@ "internal_efficiency_fraction": 0.975, "inverter_efficiency_fraction": 0.96, "rectifier_efficiency_fraction": 0.96, + "dispatch_strategy": "optimized", "soc_min_fraction": 0.2, "soc_min_applies_during_outages": true, "soc_init_fraction": 0.5, @@ -187,7 +188,9 @@ "total_itc_fraction": 0.0, "total_rebate_per_kw": 0.0, "total_rebate_per_kwh": 0.0, - "optimize_soc_init_fraction": false + "optimize_soc_init_fraction": false, + "fixed_soc_series_fraction": [], + "fixed_soc_series_fraction_tolerance": 0.05 }, "Generator": { "existing_kw": 0.0, diff --git a/reoptjl/test/posts/mpc.json b/reoptjl/test/posts/mpc.json new file mode 100644 index 000000000..ac2a4ca07 --- /dev/null +++ b/reoptjl/test/posts/mpc.json @@ -0,0 +1,8798 @@ +{ + "Settings": { + "solver_name": "HiGHS", + "time_steps_per_hour": 1, + "timeout_seconds": 420, + "optimality_tolerance": 0.02, + "run_bau": false + }, + "Site": { + "latitude": 37.7749, + "longitude": -122.4194 + }, + "PV": { + "min_kw": 100.0, + "max_kw": 100.0, + "can_net_meter": true, + "production_factor_series": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.207695, + 0.422279, + 0.560222, + 0.636338, + 0.651241, + 0.59589, + 0.485124, + 0.31164800000000004, + 0.06971, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.110515, + 0.24489, + 0.434685, + 0.478031, + 0.29884, + 0.22947700000000001, + 0.37041199999999996, + 0.294755, + 0.067825, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.022489000000000002, + 0.057006999999999995, + 0.034283, + 0.08069, + 0.069618, + 0.000787, + 0.017152, + 0.008091, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010897, + 0.030341999999999997, + 0.024048, + 0.103774, + 0.002987, + 0.098589, + 0.055890999999999996, + 0.031303, + 0.0039689999999999994, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.22544, + 0.436521, + 0.567823, + 0.640915, + 0.651996, + 0.608505, + 0.508782, + 0.34101, + 0.10376200000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.226905, + 0.431828, + 0.496223, + 0.63124, + 0.5209969999999999, + 0.539629, + 0.401755, + 0.248243, + 0.068388, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.062381, + 0.152695, + 0.033644, + 0.189455, + 0.11001000000000001, + 0.335787, + 0.07615300000000001, + 0.043837, + 0.007545, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005589, + 0.019161, + 0.011602, + 0.043304, + 0.044791, + 0.030343, + 0.053302999999999996, + 0.029886, + 0.004236, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.046078, + 0.122215, + 0.30306900000000003, + 0.364937, + 0.36310899999999996, + 0.100177, + 0.11197, + 0.063728, + 0.012695999999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.073214, + 0.014662000000000001, + 0.062383, + 0.0043040000000000005, + 0.002898, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.206088, + 0.413534, + 0.5486040000000001, + 0.535755, + 0.35776100000000005, + 0.40656200000000003, + 0.255694, + 0.163653, + 0.052244, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.031121, + 0.079763, + 0.216532, + 0.200732, + 0.644237, + 0.280151, + 0.006021, + 0.002331, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.23405600000000001, + 0.443721, + 0.574236, + 0.64771, + 0.6605599999999999, + 0.614382, + 0.513732, + 0.360351, + 0.135912, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.223237, + 0.427037, + 0.556472, + 0.621769, + 0.634969, + 0.596948, + 0.5063960000000001, + 0.352406, + 0.13306, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.218728, + 0.42540100000000003, + 0.568219, + 0.637793, + 0.653227, + 0.6152799999999999, + 0.523317, + 0.36587400000000003, + 0.141215, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.23777199999999998, + 0.44528199999999996, + 0.5741689999999999, + 0.487531, + 0.661188, + 0.616721, + 0.523869, + 0.36788600000000005, + 0.145238, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.15826400000000002, + 0.313322, + 0.442387, + 0.5035609999999999, + 0.646653, + 0.497986, + 0.32740600000000003, + 0.217306, + 0.077209, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 7.7e-05, + 0.005954, + 0.017921, + 0.020105, + 0.03295, + 0.0022029999999999997, + 0.0008219999999999999, + 0.00228, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.146098, + 0.266418, + 0.5167820000000001, + 0.610033, + 0.44228300000000004, + 0.049975, + 0.514537, + 0.360977, + 0.140149, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.120022, + 0.25899900000000003, + 0.5457609999999999, + 0.34677600000000003, + 0.052723, + 0.438317, + 0.08987099999999999, + 0.002341, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.156128, + 0.372561, + 0.401088, + 0.352929, + 0.285026, + 0.20338499999999998, + 0.11293, + 0.058656, + 0.016661000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.19702699999999998, + 0.406659, + 0.109709, + 0.07210899999999999, + 0.522181, + 0.16973, + 0.018692, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00015900000000000002, + 0.07371, + 0.46699599999999997, + 0.497896, + 0.50987, + 0.472797, + 0.30132299999999995, + 0.11578000000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.102631, + 0.221361, + 0.447398, + 0.5571900000000001, + 0.673879, + 0.634937, + 0.5453709999999999, + 0.396301, + 0.17660800000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0025099999999999996, + 0.22553700000000002, + 0.423811, + 0.368827, + 0.46375900000000003, + 0.650763, + 0.620319, + 0.53724, + 0.39084500000000005, + 0.174275, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.002576, + 0.23149799999999998, + 0.435505, + 0.577054, + 0.6498339999999999, + 0.671845, + 0.637499, + 0.549935, + 0.400792, + 0.182867, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00758, + 0.25863099999999994, + 0.46878699999999995, + 0.603314, + 0.679697, + 0.6936380000000001, + 0.644942, + 0.549987, + 0.401648, + 0.183955, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003556, + 0.225736, + 0.425526, + 0.471517, + 0.679453, + 0.695043, + 0.651433, + 0.559501, + 0.408837, + 0.191579, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0030659999999999997, + 0.17253800000000002, + 0.319397, + 0.447594, + 0.5588869999999999, + 0.536493, + 0.558367, + 0.434576, + 0.273629, + 0.123788, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.006468, + 0.26311700000000005, + 0.40993999999999997, + 0.30082299999999995, + 0.684885, + 0.7004199999999999, + 0.658906, + 0.440605, + 0.416477, + 0.200399, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009722, + 0.25576499999999996, + 0.46326799999999996, + 0.544865, + 0.575312, + 0.5256609999999999, + 0.33669600000000005, + 0.34551600000000005, + 0.248773, + 0.079561, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.006511, + 0.247534, + 0.445187, + 0.554033, + 0.628343, + 0.654242, + 0.6316269999999999, + 0.5464990000000001, + 0.405115, + 0.196443, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.01492, + 0.25507, + 0.133643, + 0.26287900000000003, + 0.37820299999999996, + 0.674183, + 0.639516, + 0.558255, + 0.413467, + 0.19937, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015502, + 0.086509, + 0.139454, + 0.5923930000000001, + 0.6651549999999999, + 0.679215, + 0.642657, + 0.559689, + 0.41865800000000003, + 0.208602, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.020964, + 0.28124099999999996, + 0.49231400000000003, + 0.620063, + 0.691965, + 0.703221, + 0.661597, + 0.572276, + 0.43388499999999997, + 0.21993100000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.021228, + 0.14013, + 0.234809, + 0.46230099999999996, + 0.250766, + 0.36852300000000004, + 0.649845, + 0.566859, + 0.42470600000000003, + 0.21536000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.021122, + 0.025151, + 0.057479999999999996, + 0.08925799999999999, + 0.103733, + 0.263445, + 0.242077, + 0.23626, + 0.165649, + 0.064395, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.066496, + 0.10229, + 0.118071, + 0.25259200000000004, + 0.18767599999999998, + 0.174407, + 0.067248, + 0.090411, + 0.030815000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.028866, + 0.284723, + 0.356714, + 0.523703, + 0.6942820000000001, + 0.713585, + 0.67173, + 0.5817859999999999, + 0.440543, + 0.22945400000000002, + 0.0079, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.032, + 0.29314100000000004, + 0.498997, + 0.629564, + 0.7036760000000001, + 0.7216950000000001, + 0.685867, + 0.594664, + 0.44993700000000003, + 0.234653, + 0.009337999999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.033338, + 0.287651, + 0.48927800000000005, + 0.616632, + 0.680474, + 0.693491, + 0.654555, + 0.564772, + 0.433353, + 0.213252, + 0.003781, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.020056, + 0.08881399999999999, + 0.338297, + 0.543219, + 0.596919, + 0.69924, + 0.542607, + 0.413375, + 0.330295, + 0.22752, + 0.004777999999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.040970999999999994, + 0.283454, + 0.475534, + 0.5974550000000001, + 0.669778, + 0.552811, + 0.446658, + 0.527128, + 0.377336, + 0.12930699999999998, + 0.00239, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013573, + 0.025055, + 0.067513, + 0.11536400000000001, + 0.174123, + 0.104833, + 0.09042700000000001, + 0.054126, + 0.020904, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.04468, + 0.25911900000000004, + 0.439435, + 0.563762, + 0.632254, + 0.6521290000000001, + 0.328483, + 0.540633, + 0.25031200000000003, + 0.083521, + 0.010247, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.051542000000000004, + 0.026562000000000002, + 0.30834500000000004, + 0.6004160000000001, + 0.6815910000000001, + 0.39878199999999997, + 0.16822800000000002, + 0.386711, + 0.321494, + 0.23660499999999998, + 0.016772, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.060192, + 0.291545, + 0.361254, + 0.331589, + 0.385625, + 0.335976, + 0.233911, + 0.135821, + 0.014922000000000001, + 0.031966999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.044932, + 0.285211, + 0.493955, + 0.6397229999999999, + 0.718935, + 0.527409, + 0.707648, + 0.616122, + 0.351425, + 0.249001, + 0.020041, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00994, + 0.07306399999999999, + 0.041134, + 0.317872, + 0.347862, + 0.418657, + 0.35969799999999996, + 0.339814, + 0.17905600000000002, + 0.040002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.034241, + 0.15840100000000001, + 0.296391, + 0.08306699999999999, + 0.090551, + 0.047091, + 0.042392000000000006, + 0.12198, + 0.080349, + 0.002233, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.026936, + 0.220476, + 0.490147, + 0.32875099999999996, + 0.357146, + 0.42798200000000003, + 0.664018, + 0.572755, + 0.435245, + 0.236703, + 0.021262, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010258, + 0.096562, + 0.203518, + 0.600028, + 0.591035, + 0.581933, + 0.546376, + 0.5808329999999999, + 0.447123, + 0.252392, + 0.027173, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.021838999999999997, + 0.11009300000000001, + 0.418191, + 0.555395, + 0.591322, + 0.570702, + 0.557001, + 0.49666699999999997, + 0.324747, + 0.090819, + 0.002615, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.091813, + 0.325463, + 0.15421, + 0.6510520000000001, + 0.26193900000000003, + 0.427861, + 0.7114360000000001, + 0.252874, + 0.288834, + 0.260892, + 0.035828000000000006, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.09758599999999999, + 0.33346699999999996, + 0.519919, + 0.6407160000000001, + 0.713893, + 0.734447, + 0.700998, + 0.616637, + 0.479126, + 0.275596, + 0.043648000000000006, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.102257, + 0.342515, + 0.531277, + 0.649798, + 0.7194769999999999, + 0.735367, + 0.697784, + 0.6113540000000001, + 0.47650099999999995, + 0.276463, + 0.04868, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.104298, + 0.341447, + 0.530255, + 0.648726, + 0.714005, + 0.615319, + 0.570394, + 0.435757, + 0.319392, + 0.169755, + 0.02958, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017295, + 0.323784, + 0.467444, + 0.54375, + 0.716537, + 0.735182, + 0.5598289999999999, + 0.5356559999999999, + 0.388509, + 0.141916, + 0.016282, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.116723, + 0.353379, + 0.532111, + 0.6548120000000001, + 0.72369, + 0.7399990000000001, + 0.7082809999999999, + 0.621674, + 0.48418900000000004, + 0.29177, + 0.057391, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.111654, + 0.339012, + 0.34675900000000004, + 0.460963, + 0.582859, + 0.42449400000000004, + 0.373393, + 0.24651900000000002, + 0.05025, + 0.033569, + 0.011414, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.029684000000000002, + 0.015553, + 0.150826, + 0.096607, + 0.790417, + 0.746839, + 0.650021, + 0.49600099999999997, + 0.287842, + 0.059677999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.097219, + 0.029974, + 0.245173, + 0.509524, + 0.362653, + 0.421228, + 0.267154, + 0.25759899999999997, + 0.049686999999999995, + 0.035323, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.026494, + 0.025445, + 0.101385, + 0.063761, + 0.158956, + 0.164179, + 0.115258, + 0.055415, + 0.036472000000000004, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.039520000000000007, + 0.32023599999999997, + 0.21712700000000001, + 0.483665, + 0.427042, + 0.398914, + 0.40226, + 0.417226, + 0.25019, + 0.074965, + 0.023945, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00437, + 0.100305, + 0.274823, + 0.403126, + 0.604246, + 0.588712, + 0.551582, + 0.605985, + 0.463137, + 0.26813, + 0.060101, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.024516, + 0.345265, + 0.516995, + 0.639512, + 0.473585, + 0.725527, + 0.482527, + 0.609947, + 0.471918, + 0.276389, + 0.063228, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.008816000000000001, + 0.06780800000000001, + 0.198193, + 0.446741, + 0.400309, + 0.541388, + 0.715101, + 0.626445, + 0.48399000000000003, + 0.282674, + 0.06483499999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.042539, + 0.164435, + 0.553807, + 0.5011530000000001, + 0.758212, + 0.77442, + 0.737505, + 0.639857, + 0.49224599999999996, + 0.29106, + 0.070381, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.15869, + 0.40103500000000003, + 0.577339, + 0.700155, + 0.767641, + 0.784826, + 0.745556, + 0.652605, + 0.508755, + 0.305269, + 0.076014, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.054398, + 0.081043, + 0.42425599999999997, + 0.503707, + 0.737906, + 0.754303, + 0.717615, + 0.6364099999999999, + 0.495182, + 0.301902, + 0.07805, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.15837, + 0.39331099999999997, + 0.567373, + 0.681314, + 0.736961, + 0.737013, + 0.687886, + 0.60803, + 0.48419999999999996, + 0.29970600000000003, + 0.079087, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.052518999999999996, + 0.159327, + 0.328732, + 0.669928, + 0.731684, + 0.746134, + 0.717596, + 0.5362720000000001, + 0.493911, + 0.296259, + 0.076678, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.051247999999999995, + 0.187869, + 0.5580499999999999, + 0.6821889999999999, + 0.7531570000000001, + 0.769657, + 0.73427, + 0.650882, + 0.507289, + 0.307917, + 0.082402, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.09169799999999999, + 0.279419, + 0.29978699999999997, + 0.47239299999999995, + 0.40810700000000005, + 0.20960900000000002, + 0.16908099999999998, + 0.428692, + 0.498267, + 0.297099, + 0.078316, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0017800000000000001, + 0.168075, + 0.397638, + 0.565641, + 0.682569, + 0.7479389999999999, + 0.767616, + 0.735413, + 0.647673, + 0.507462, + 0.237204, + 0.007864, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003414, + 0.10562600000000001, + 0.376731, + 0.5580940000000001, + 0.666061, + 0.725865, + 0.740677, + 0.702678, + 0.6132430000000001, + 0.473989, + 0.283315, + 0.077291, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0036720000000000004, + 0.052357999999999995, + 0.139844, + 0.553953, + 0.665559, + 0.732144, + 0.7444339999999999, + 0.7156509999999999, + 0.631231, + 0.49967399999999995, + 0.310479, + 0.089037, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004647, + 0.18046, + 0.39882100000000004, + 0.414856, + 0.6189199999999999, + 0.6545829999999999, + 0.6138060000000001, + 0.673336, + 0.5296879999999999, + 0.426967, + 0.269061, + 0.065591, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004355, + 0.150454, + 0.33557400000000004, + 0.528914, + 0.637541, + 0.578269, + 0.716262, + 0.680254, + 0.6026710000000001, + 0.476746, + 0.294038, + 0.056965, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.002179, + 0.00437, + 0.053927, + 0.109019, + 0.237154, + 0.227977, + 0.27866399999999997, + 0.42091199999999995, + 0.317135, + 0.24538300000000002, + 0.16309, + 0.064928, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.007954, + 0.036506, + 0.079628, + 0.21349700000000002, + 0.322758, + 0.446036, + 0.758214, + 0.7218450000000001, + 0.6352300000000001, + 0.499241, + 0.305756, + 0.08911799999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0029620000000000002, + 0.093987, + 0.13712, + 0.194631, + 0.378106, + 0.45871, + 0.5164880000000001, + 0.460509, + 0.37861700000000004, + 0.251616, + 0.087476, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011045, + 0.040895, + 0.412297, + 0.579653, + 0.196054, + 0.7642089999999999, + 0.40402499999999997, + 0.41291100000000003, + 0.380364, + 0.357733, + 0.214743, + 0.037257, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.014909, + 0.20342, + 0.425916, + 0.5928709999999999, + 0.711846, + 0.777106, + 0.790258, + 0.756649, + 0.668144, + 0.20056000000000002, + 0.103436, + 0.030566, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.019303999999999998, + 0.220282, + 0.45027100000000003, + 0.6142430000000001, + 0.72369, + 0.7888189999999999, + 0.7988139999999999, + 0.75714, + 0.595485, + 0.517654, + 0.324861, + 0.09987399999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.021793, + 0.212108, + 0.428913, + 0.5901409999999999, + 0.703235, + 0.7663730000000001, + 0.7731849999999999, + 0.735835, + 0.521258, + 0.429628, + 0.24329499999999998, + 0.056109, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.022963, + 0.043286, + 0.124235, + 0.232799, + 0.320848, + 0.7670119999999999, + 0.785678, + 0.751068, + 0.657134, + 0.5162559999999999, + 0.322629, + 0.101645, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.026743, + 0.224262, + 0.444289, + 0.606557, + 0.711096, + 0.773561, + 0.789644, + 0.749735, + 0.659048, + 0.523871, + 0.332743, + 0.106444, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.028473, + 0.22575499999999998, + 0.442178, + 0.597698, + 0.704451, + 0.76274, + 0.773423, + 0.734248, + 0.6476649999999999, + 0.514004, + 0.325755, + 0.104397, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.030614000000000002, + 0.220653, + 0.432615, + 0.5874729999999999, + 0.696327, + 0.753764, + 0.76858, + 0.734579, + 0.6509579999999999, + 0.517126, + 0.246369, + 0.09568600000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004672, + 0.162977, + 0.443077, + 0.507745, + 0.706308, + 0.74123, + 0.789443, + 0.601442, + 0.557023, + 0.44275400000000004, + 0.283506, + 0.106104, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.027623, + 0.17741800000000002, + 0.357074, + 0.585418, + 0.685648, + 0.736874, + 0.7510979999999999, + 0.722754, + 0.550971, + 0.509244, + 0.308328, + 0.101213, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015663, + 0.16794499999999998, + 0.43129, + 0.579802, + 0.6936599999999999, + 0.759934, + 0.774892, + 0.7403529999999999, + 0.657941, + 0.52416, + 0.331498, + 0.109362, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.029842, + 0.13053800000000002, + 0.309222, + 0.51897, + 0.636846, + 0.646696, + 0.676881, + 0.631426, + 0.524899, + 0.339399, + 0.202929, + 0.08028199999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.125947, + 0.31171899999999997, + 0.482402, + 0.5644199999999999, + 0.597461, + 0.6387630000000001, + 0.530771, + 0.51403, + 0.482815, + 0.293091, + 0.099892, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.042969, + 0.056249, + 0.107878, + 0.18890700000000002, + 0.305965, + 0.315038, + 0.7746770000000001, + 0.5291119999999999, + 0.445243, + 0.397129, + 0.244786, + 0.086456, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.044275, + 0.027727, + 0.09003499999999999, + 0.155842, + 0.37283, + 0.551149, + 0.38921300000000003, + 0.6464930000000001, + 0.557837, + 0.465028, + 0.28536, + 0.086013, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.048019, + 0.196745, + 0.44526, + 0.601424, + 0.717346, + 0.7732559999999999, + 0.728509, + 0.6810170000000001, + 0.6363479999999999, + 0.5214439999999999, + 0.332935, + 0.113818, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.052713, + 0.252454, + 0.46536500000000003, + 0.625539, + 0.7366119999999999, + 0.797933, + 0.805922, + 0.775174, + 0.686875, + 0.540394, + 0.342638, + 0.116468, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.025056000000000002, + 0.254183, + 0.463, + 0.616322, + 0.721293, + 0.775361, + 0.790967, + 0.7548429999999999, + 0.666332, + 0.446007, + 0.305602, + 0.06133400000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.12155200000000001, + 0.46793, + 0.470894, + 0.755336, + 0.820584, + 0.724289, + 0.673685, + 0.536342, + 0.467707, + 0.338795, + 0.11994400000000001, + 0.001472, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.061122, + 0.278408, + 0.49714600000000003, + 0.6572709999999999, + 0.767188, + 0.825215, + 0.832831, + 0.79164, + 0.693194, + 0.546177, + 0.350979, + 0.123056, + 0.001472, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.062035, + 0.264189, + 0.45987700000000004, + 0.598544, + 0.6976330000000001, + 0.757966, + 0.7777430000000001, + 0.750242, + 0.636547, + 0.487867, + 0.32704300000000003, + 0.11739100000000001, + 0.002422, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.020648, + 0.01117, + 0.113569, + 0.11582899999999999, + 0.246007, + 0.618874, + 0.5315019999999999, + 0.595178, + 0.492678, + 0.5332169999999999, + 0.339469, + 0.121077, + 0.002424, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.067418, + 0.279493, + 0.49157799999999996, + 0.615208, + 0.7614740000000001, + 0.822515, + 0.826419, + 0.780931, + 0.6849729999999999, + 0.539667, + 0.344538, + 0.12405100000000001, + 0.001916, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.070637, + 0.283006, + 0.49051100000000003, + 0.639332, + 0.741068, + 0.795591, + 0.797122, + 0.750928, + 0.6599919999999999, + 0.5190560000000001, + 0.33437700000000004, + 0.12055800000000001, + 0.001459, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.074152, + 0.28825599999999996, + 0.500058, + 0.659172, + 0.76954, + 0.833333, + 0.833333, + 0.797959, + 0.704894, + 0.5533790000000001, + 0.355991, + 0.129968, + 0.003236, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.074889, + 0.293091, + 0.5042719999999999, + 0.658667, + 0.766779, + 0.822448, + 0.8234600000000001, + 0.785347, + 0.694955, + 0.551687, + 0.356843, + 0.130835, + 0.003095, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.037212, + 0.14308600000000002, + 0.311227, + 0.30757, + 0.490679, + 0.345737, + 0.12741, + 0.377938, + 0.123617, + 0.29588600000000004, + 0.17526599999999998, + 0.07737000000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.067246, + 0.282511, + 0.483958, + 0.6292279999999999, + 0.719526, + 0.7577229999999999, + 0.314807, + 0.7376269999999999, + 0.661076, + 0.525931, + 0.341142, + 0.127801, + 0.003975, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.028002, + 0.10915699999999999, + 0.289136, + 0.425682, + 0.44997000000000004, + 0.398326, + 0.33848, + 0.14156200000000002, + 0.314291, + 0.133382, + 0.060633, + 0.025675999999999997, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.081814, + 0.29616699999999996, + 0.498654, + 0.647913, + 0.6306090000000001, + 0.808295, + 0.816507, + 0.775126, + 0.680986, + 0.54342, + 0.35283499999999995, + 0.132697, + 0.0041849999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.085343, + 0.294456, + 0.485252, + 0.6235109999999999, + 0.714194, + 0.7650739999999999, + 0.781359, + 0.7536219999999999, + 0.6716340000000001, + 0.538512, + 0.35338200000000003, + 0.133828, + 0.004897, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.087977, + 0.267079, + 0.421356, + 0.630357, + 0.7295969999999999, + 0.783338, + 0.792134, + 0.7579589999999999, + 0.672363, + 0.541036, + 0.356166, + 0.135745, + 0.004637, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.07389100000000001, + 0.23507, + 0.34896699999999997, + 0.524833, + 0.664827, + 0.6858970000000001, + 0.725471, + 0.565309, + 0.37285, + 0.480601, + 0.341559, + 0.13161, + 0.007202, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.088703, + 0.291028, + 0.482028, + 0.627556, + 0.727248, + 0.77962, + 0.783077, + 0.74173, + 0.657898, + 0.521532, + 0.34216399999999997, + 0.116736, + 0.007184, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.08848099999999999, + 0.285978, + 0.468597, + 0.598646, + 0.673618, + 0.708876, + 0.713664, + 0.668434, + 0.6019690000000001, + 0.483587, + 0.28160199999999996, + 0.12948300000000001, + 0.008009, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.6e-05, + 0.080895, + 0.24996000000000002, + 0.41862099999999997, + 0.55862, + 0.688866, + 0.710542, + 0.749359, + 0.6859829999999999, + 0.633802, + 0.5047740000000001, + 0.294478, + 0.13263999999999998, + 0.010395, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.040119999999999996, + 0.084547, + 0.251187, + 0.49125, + 0.7337229999999999, + 0.696178, + 0.753887, + 0.506325, + 0.429825, + 0.332226, + 0.196345, + 0.107807, + 0.012041, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.001974, + 0.09655, + 0.298657, + 0.487712, + 0.629165, + 0.7306, + 0.7835449999999999, + 0.789498, + 0.754728, + 0.664607, + 0.505505, + 0.351837, + 0.139472, + 0.010841, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.001431, + 0.097452, + 0.311599, + 0.502648, + 0.647389, + 0.743358, + 0.7921269999999999, + 0.795764, + 0.741722, + 0.653215, + 0.520768, + 0.346831, + 0.137167, + 0.010234, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004936, + 0.095904, + 0.300991, + 0.487262, + 0.629145, + 0.723993, + 0.7717849999999999, + 0.77195, + 0.7256739999999999, + 0.638793, + 0.512115, + 0.342082, + 0.136677, + 0.011221, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0020440000000000002, + 0.095974, + 0.297072, + 0.474027, + 0.605012, + 0.695874, + 0.742736, + 0.7494310000000001, + 0.7158909999999999, + 0.639689, + 0.516091, + 0.346294, + 0.139463, + 0.010402, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0025710000000000004, + 0.099634, + 0.125545, + 0.214989, + 0.27689800000000003, + 0.384141, + 0.447624, + 0.5753039999999999, + 0.588515, + 0.502235, + 0.348949, + 0.22737000000000002, + 0.12404699999999999, + 0.0154, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004016, + 0.086669, + 0.311898, + 0.503537, + 0.651307, + 0.7556240000000001, + 0.8129149999999999, + 0.82048, + 0.779639, + 0.691472, + 0.547764, + 0.359165, + 0.14536000000000002, + 0.01998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005642, + 0.110009, + 0.219572, + 0.498907, + 0.47551, + 0.7317140000000001, + 0.782514, + 0.7900900000000001, + 0.749857, + 0.661058, + 0.522559, + 0.34376, + 0.144143, + 0.019156, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004595, + 0.108375, + 0.310535, + 0.49135700000000004, + 0.626531, + 0.717198, + 0.7497119999999999, + 0.740721, + 0.704237, + 0.6344160000000001, + 0.513544, + 0.34401, + 0.142683, + 0.017547999999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005557, + 0.109097, + 0.303772, + 0.476466, + 0.6048020000000001, + 0.6937519999999999, + 0.749798, + 0.7649900000000001, + 0.734274, + 0.6551359999999999, + 0.522389, + 0.347792, + 0.147037, + 0.017007, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005613000000000001, + 0.102176, + 0.274083, + 0.48810000000000003, + 0.6244959999999999, + 0.714416, + 0.759349, + 0.764383, + 0.730348, + 0.6545639999999999, + 0.5248379999999999, + 0.353545, + 0.14971500000000001, + 0.018359, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.007352, + 0.10667700000000001, + 0.222787, + 0.323993, + 0.440432, + 0.5293239999999999, + 0.707286, + 0.803968, + 0.7639729999999999, + 0.670115, + 0.451214, + 0.32716, + 0.149251, + 0.019969, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.007338, + 0.112447, + 0.19577799999999998, + 0.49967399999999995, + 0.638171, + 0.7393869999999999, + 0.791788, + 0.79999, + 0.7529239999999999, + 0.562156, + 0.23397300000000001, + 0.104749, + 0.077098, + 0.018154, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.008945, + 0.117691, + 0.33212400000000003, + 0.527736, + 0.6748379999999999, + 0.779161, + 0.8330960000000001, + 0.833333, + 0.793226, + 0.698527, + 0.56063, + 0.377036, + 0.158525, + 0.019178999999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009997, + 0.119729, + 0.336048, + 0.524143, + 0.662519, + 0.759269, + 0.81637, + 0.824706, + 0.783884, + 0.692042, + 0.556822, + 0.37542899999999996, + 0.158562, + 0.019191, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010369999999999999, + 0.118947, + 0.327337, + 0.511619, + 0.646485, + 0.736004, + 0.7887609999999999, + 0.7963060000000001, + 0.757433, + 0.676044, + 0.5433830000000001, + 0.366131, + 0.157183, + 0.020559, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012357, + 0.12007999999999999, + 0.323774, + 0.5068980000000001, + 0.647683, + 0.7438980000000001, + 0.798995, + 0.810144, + 0.771925, + 0.686506, + 0.5524260000000001, + 0.375444, + 0.160727, + 0.020858, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011989000000000001, + 0.11749599999999999, + 0.25419200000000003, + 0.398294, + 0.400877, + 0.5124869999999999, + 0.557611, + 0.579722, + 0.5902050000000001, + 0.414634, + 0.382172, + 0.20396, + 0.068842, + 0.015655, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013439, + 0.122954, + 0.32947000000000004, + 0.511314, + 0.64667, + 0.744016, + 0.796692, + 0.8050470000000001, + 0.7647419999999999, + 0.679663, + 0.550348, + 0.376439, + 0.161832, + 0.020120000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011496000000000001, + 0.12006499999999999, + 0.326423, + 0.5072099999999999, + 0.6429389999999999, + 0.738278, + 0.787753, + 0.7917580000000001, + 0.748549, + 0.665971, + 0.539534, + 0.368103, + 0.160248, + 0.019939, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012114000000000002, + 0.119616, + 0.323852, + 0.499141, + 0.6247820000000001, + 0.706117, + 0.746535, + 0.744782, + 0.715635, + 0.645179, + 0.5263920000000001, + 0.364307, + 0.159252, + 0.019081, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012166, + 0.12052, + 0.320012, + 0.365527, + 0.603876, + 0.682699, + 0.7220019999999999, + 0.7347229999999999, + 0.7115199999999999, + 0.639481, + 0.521957, + 0.35888600000000004, + 0.157971, + 0.01912, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012134, + 0.122408, + 0.32899, + 0.356559, + 0.617382, + 0.679177, + 0.726013, + 0.7407, + 0.45909500000000003, + 0.452621, + 0.365512, + 0.365162, + 0.126024, + 0.027617, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013826, + 0.12295099999999999, + 0.13161099999999998, + 0.213845, + 0.629129, + 0.423654, + 0.553487, + 0.522511, + 0.431276, + 0.429702, + 0.343071, + 0.183126, + 0.09931100000000001, + 0.024231000000000003, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015090999999999999, + 0.122309, + 0.086023, + 0.12706900000000002, + 0.30466000000000004, + 0.714503, + 0.601279, + 0.5160119999999999, + 0.37555099999999997, + 0.406671, + 0.291643, + 0.17912, + 0.097994, + 0.025934000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.002282, + 0.18245699999999998, + 0.295768, + 0.31481, + 0.49377499999999996, + 0.595351, + 0.60853, + 0.453839, + 0.39474200000000004, + 0.283304, + 0.21739, + 0.092012, + 0.026334, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.021034, + 0.079773, + 0.13078399999999998, + 0.141793, + 0.14632, + 0.585864, + 0.26032299999999997, + 0.630306, + 0.755147, + 0.666841, + 0.538431, + 0.367719, + 0.168125, + 0.031530999999999997, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.019996, + 0.026963, + 0.201859, + 0.238998, + 0.27355900000000005, + 0.34639600000000004, + 0.31611, + 0.372289, + 0.33307299999999995, + 0.510328, + 0.389312, + 0.249021, + 0.16745, + 0.027084, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015973, + 0.050921999999999995, + 0.106054, + 0.236125, + 0.28130099999999997, + 0.435716, + 0.773492, + 0.7800779999999999, + 0.743549, + 0.6586219999999999, + 0.531336, + 0.365966, + 0.167825, + 0.028523, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017864, + 0.027129, + 0.08003199999999999, + 0.13152, + 0.182107, + 0.264315, + 0.356851, + 0.620477, + 0.745107, + 0.65998, + 0.532121, + 0.366289, + 0.16822900000000002, + 0.029331, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017897, + 0.020992, + 0.078553, + 0.25082, + 0.390909, + 0.46969299999999997, + 0.6200370000000001, + 0.49851, + 0.66011, + 0.6680320000000001, + 0.541029, + 0.373334, + 0.17175, + 0.028512, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.018651, + 0.112599, + 0.282601, + 0.42089, + 0.49280599999999997, + 0.625745, + 0.586268, + 0.48599000000000003, + 0.342324, + 0.419175, + 0.469794, + 0.29239, + 0.151174, + 0.032146, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017297, + 0.121114, + 0.314191, + 0.48754899999999995, + 0.619668, + 0.7095309999999999, + 0.7584529999999999, + 0.76481, + 0.510628, + 0.457718, + 0.39039100000000004, + 0.375546, + 0.17272300000000002, + 0.027833, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.014946, + 0.124693, + 0.329579, + 0.500985, + 0.6280979999999999, + 0.7166710000000001, + 0.765813, + 0.770787, + 0.733469, + 0.62961, + 0.42783699999999997, + 0.323835, + 0.128507, + 0.029062, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015742000000000003, + 0.124466, + 0.325493, + 0.496758, + 0.626302, + 0.721232, + 0.7711420000000001, + 0.781747, + 0.744568, + 0.663201, + 0.540038, + 0.374375, + 0.174834, + 0.03215, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.019091, + 0.125897, + 0.318746, + 0.49278, + 0.625355, + 0.718834, + 0.770458, + 0.7843730000000001, + 0.748819, + 0.666632, + 0.539734, + 0.37614299999999995, + 0.173984, + 0.028513999999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017242999999999998, + 0.124158, + 0.06264600000000001, + 0.178791, + 0.276097, + 0.428327, + 0.7704160000000001, + 0.777531, + 0.738263, + 0.478214, + 0.358983, + 0.367617, + 0.17359200000000002, + 0.031254000000000004, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.01849, + 0.125577, + 0.07566800000000001, + 0.125324, + 0.230327, + 0.7232029999999999, + 0.7762859999999999, + 0.785982, + 0.74378, + 0.661566, + 0.538037, + 0.373517, + 0.09324299999999999, + 0.030423, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017256, + 0.12506799999999998, + 0.110572, + 0.24290199999999998, + 0.6252559999999999, + 0.720554, + 0.7714610000000001, + 0.77665, + 0.731527, + 0.651872, + 0.52824, + 0.367402, + 0.08143500000000001, + 0.021567, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017864, + 0.12331, + 0.138566, + 0.476777, + 0.60011, + 0.687781, + 0.744903, + 0.757595, + 0.719746, + 0.6449, + 0.52823, + 0.370871, + 0.175671, + 0.029462, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017667000000000002, + 0.12262300000000001, + 0.314322, + 0.478148, + 0.601547, + 0.692001, + 0.745992, + 0.759512, + 0.727566, + 0.649312, + 0.5300320000000001, + 0.372968, + 0.176089, + 0.029172, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017689, + 0.119718, + 0.082723, + 0.188954, + 0.6159260000000001, + 0.70438, + 0.75805, + 0.543986, + 0.356286, + 0.307839, + 0.163659, + 0.101762, + 0.176803, + 0.034805, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.001501, + 0.033394, + 0.208316, + 0.275793, + 0.534165, + 0.6711670000000001, + 0.759541, + 0.7219779999999999, + 0.6432190000000001, + 0.522374, + 0.365564, + 0.177534, + 0.036857999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.019123, + 0.123994, + 0.17273500000000003, + 0.281583, + 0.420527, + 0.7169030000000001, + 0.768156, + 0.778011, + 0.739894, + 0.589782, + 0.417119, + 0.276129, + 0.17735499999999998, + 0.029594000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.019771, + 0.1276, + 0.329236, + 0.510213, + 0.64652, + 0.745016, + 0.801312, + 0.8141889999999999, + 0.780685, + 0.6998690000000001, + 0.569515, + 0.402697, + 0.193085, + 0.033735999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.018617, + 0.12625, + 0.328121, + 0.5059359999999999, + 0.638141, + 0.73481, + 0.788671, + 0.8012469999999999, + 0.764558, + 0.683237, + 0.5587880000000001, + 0.39440800000000004, + 0.188965, + 0.032936, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.016128, + 0.123399, + 0.32430200000000003, + 0.497112, + 0.6244700000000001, + 0.712294, + 0.760725, + 0.774938, + 0.744657, + 0.6708529999999999, + 0.5507989999999999, + 0.391155, + 0.188228, + 0.031150999999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017238, + 0.037786, + 0.082593, + 0.155993, + 0.266724, + 0.31041599999999997, + 0.52718, + 0.794987, + 0.48786900000000005, + 0.417819, + 0.334315, + 0.230732, + 0.113611, + 0.038749000000000006, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015051, + 0.121002, + 0.324491, + 0.502126, + 0.6363869999999999, + 0.733967, + 0.789828, + 0.796649, + 0.755122, + 0.675611, + 0.552755, + 0.392126, + 0.18762, + 0.030208, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.014263999999999999, + 0.12002299999999999, + 0.32279199999999997, + 0.50312, + 0.640899, + 0.7380249999999999, + 0.7907240000000001, + 0.800277, + 0.76375, + 0.683246, + 0.5559769999999999, + 0.39469600000000005, + 0.191445, + 0.029419, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013573, + 0.12124, + 0.32852, + 0.51175, + 0.652975, + 0.756659, + 0.8125800000000001, + 0.82533, + 0.779586, + 0.699496, + 0.5706910000000001, + 0.405403, + 0.195549, + 0.029963, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.016452, + 0.120715, + 0.325237, + 0.501415, + 0.636452, + 0.731885, + 0.786635, + 0.798526, + 0.7681570000000001, + 0.6892780000000001, + 0.562674, + 0.39933300000000005, + 0.193166, + 0.032457, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.016456, + 0.118185, + 0.316253, + 0.489392, + 0.621872, + 0.726076, + 0.7841480000000001, + 0.799498, + 0.767494, + 0.687311, + 0.563801, + 0.401065, + 0.195015, + 0.030074, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013586, + 0.117809, + 0.319064, + 0.49144299999999996, + 0.623199, + 0.721373, + 0.778143, + 0.7918440000000001, + 0.762365, + 0.6810320000000001, + 0.561431, + 0.40121100000000004, + 0.195976, + 0.032311, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013515000000000001, + 0.116745, + 0.31525, + 0.485568, + 0.610792, + 0.7035739999999999, + 0.761147, + 0.776, + 0.741736, + 0.6657540000000001, + 0.54587, + 0.388789, + 0.188826, + 0.029390999999999997, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013968999999999999, + 0.034817, + 0.022286999999999998, + 0.26031299999999996, + 0.19918100000000002, + 0.15325899999999998, + 0.137296, + 0.134786, + 0.218141, + 0.399507, + 0.196552, + 0.14671299999999998, + 0.038700000000000005, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.032327, + 0.06714700000000001, + 0.052448, + 0.114373, + 0.142308, + 0.162687, + 0.14993399999999998, + 0.12407599999999999, + 0.127264, + 0.082131, + 0.13867, + 0.00783, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012013999999999999, + 0.004995, + 0.01875, + 0.064679, + 0.087142, + 0.08417, + 0.097608, + 0.211388, + 0.246262, + 0.451718, + 0.276364, + 0.37488900000000003, + 0.07338299999999999, + 0.028211, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010019, + 0.10659199999999999, + 0.302065, + 0.47190899999999997, + 0.603576, + 0.696914, + 0.748737, + 0.75799, + 0.725409, + 0.651159, + 0.53738, + 0.385779, + 0.187872, + 0.026566, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.01062, + 0.10738299999999999, + 0.306761, + 0.47857299999999997, + 0.607958, + 0.7013189999999999, + 0.753356, + 0.763183, + 0.7293740000000001, + 0.6544059999999999, + 0.538975, + 0.387293, + 0.189708, + 0.028763, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011284, + 0.109024, + 0.303321, + 0.470437, + 0.593844, + 0.686339, + 0.7411599999999999, + 0.757658, + 0.72926, + 0.656399, + 0.5423490000000001, + 0.38921100000000003, + 0.19109700000000002, + 0.029571, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011295999999999999, + 0.110669, + 0.309966, + 0.48045499999999997, + 0.6034660000000001, + 0.6939270000000001, + 0.748915, + 0.764276, + 0.733005, + 0.663678, + 0.546762, + 0.39276799999999995, + 0.195298, + 0.031758, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013355, + 0.108283, + 0.305229, + 0.47979, + 0.608902, + 0.701546, + 0.754189, + 0.754992, + 0.7229909999999999, + 0.6466369999999999, + 0.529201, + 0.39785899999999996, + 0.197648, + 0.033838, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015186999999999999, + 0.004396, + 0.212429, + 0.170851, + 0.393761, + 0.706807, + 0.761787, + 0.771726, + 0.734264, + 0.6604690000000001, + 0.541841, + 0.387553, + 0.19239599999999998, + 0.035893999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012277, + 0.105961, + 0.136349, + 0.163071, + 0.333057, + 0.707661, + 0.762103, + 0.7740119999999999, + 0.741294, + 0.668716, + 0.549509, + 0.396413, + 0.19567099999999998, + 0.030087, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010157, + 0.104338, + 0.300464, + 0.477176, + 0.612568, + 0.707696, + 0.761226, + 0.7703479999999999, + 0.738544, + 0.66174, + 0.545092, + 0.390384, + 0.192938, + 0.032158, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.22877799999999998, + 0.24671, + 0.61099, + 0.518475, + 0.757718, + 0.7679450000000001, + 0.736183, + 0.6628, + 0.546933, + 0.396155, + 0.194349, + 0.033595, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012846, + 0.104833, + 0.1574, + 0.349649, + 0.5929909999999999, + 0.6817920000000001, + 0.737738, + 0.751026, + 0.734365, + 0.658663, + 0.543479, + 0.391357, + 0.193249, + 0.03269, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012921, + 0.10499599999999999, + 0.236078, + 0.450474, + 0.573652, + 0.654376, + 0.710185, + 0.72766, + 0.697688, + 0.627068, + 0.5133690000000001, + 0.367672, + 0.186548, + 0.040939, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011651, + 0.10309399999999999, + 0.274181, + 0.431048, + 0.550468, + 0.602677, + 0.658768, + 0.6761, + 0.6570969999999999, + 0.589818, + 0.479751, + 0.33807600000000004, + 0.174224, + 0.042985999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011941, + 0.10133400000000001, + 0.26412599999999997, + 0.41965199999999997, + 0.532482, + 0.591616, + 0.652441, + 0.676687, + 0.647587, + 0.580236, + 0.470041, + 0.324135, + 0.16828700000000002, + 0.043366999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012697, + 0.102635, + 0.255157, + 0.411253, + 0.535554, + 0.6492169999999999, + 0.704309, + 0.715807, + 0.657593, + 0.588662, + 0.47988, + 0.339948, + 0.176194, + 0.048122, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012064, + 0.104624, + 0.26977300000000004, + 0.43310899999999997, + 0.568138, + 0.634916, + 0.708646, + 0.743589, + 0.715839, + 0.646525, + 0.5362089999999999, + 0.391578, + 0.198019, + 0.044446, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.011448999999999999, + 0.103948, + 0.26410500000000003, + 0.42638, + 0.5592820000000001, + 0.615514, + 0.6728200000000001, + 0.6855460000000001, + 0.625622, + 0.550622, + 0.44047699999999995, + 0.301221, + 0.152387, + 0.033542999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003758, + 0.09410500000000001, + 0.13639099999999998, + 0.23612200000000003, + 0.328591, + 0.580373, + 0.648182, + 0.674729, + 0.6532190000000001, + 0.590871, + 0.486405, + 0.346995, + 0.179572, + 0.044267, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010534, + 0.097538, + 0.154745, + 0.32769, + 0.56738, + 0.660772, + 0.719405, + 0.734521, + 0.700231, + 0.626323, + 0.5134249999999999, + 0.364247, + 0.180813, + 0.040645, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009798999999999999, + 0.09900400000000001, + 0.09458, + 0.182376, + 0.26516, + 0.36677699999999996, + 0.5940979999999999, + 0.460793, + 0.72274, + 0.429085, + 0.527577, + 0.37349400000000005, + 0.184832, + 0.039966999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009944000000000001, + 0.097467, + 0.029405, + 0.06197999999999999, + 0.125157, + 0.371761, + 0.5609160000000001, + 0.754015, + 0.72562, + 0.654449, + 0.537044, + 0.38439, + 0.19250399999999998, + 0.037823, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.008166, + 0.099285, + 0.063757, + 0.146037, + 0.249859, + 0.5238250000000001, + 0.724213, + 0.739248, + 0.7250979999999999, + 0.650181, + 0.5356069999999999, + 0.384454, + 0.192366, + 0.034639, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.007744, + 0.09795999999999999, + 0.099763, + 0.23904, + 0.350635, + 0.733731, + 0.7915639999999999, + 0.803003, + 0.773721, + 0.693151, + 0.571206, + 0.410582, + 0.202003, + 0.032241, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.006982, + 0.030633, + 0.089609, + 0.18224500000000002, + 0.29823700000000003, + 0.539766, + 0.767008, + 0.782852, + 0.7498579999999999, + 0.678584, + 0.561551, + 0.403002, + 0.198469, + 0.032985, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.006292, + 0.097045, + 0.094936, + 0.160084, + 0.252238, + 0.330622, + 0.646216, + 0.6573669999999999, + 0.549135, + 0.6783669999999999, + 0.5543640000000001, + 0.392495, + 0.194032, + 0.039469000000000004, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005793, + 0.017884, + 0.054570999999999995, + 0.074378, + 0.111643, + 0.19058, + 0.424976, + 0.377923, + 0.590525, + 0.44951100000000005, + 0.25779, + 0.252684, + 0.080567, + 0.0013939999999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.017122, + 0.292223, + 0.131564, + 0.129653, + 0.11605, + 0.429508, + 0.45538799999999996, + 0.593252, + 0.696373, + 0.42951999999999996, + 0.313035, + 0.138058, + 0.032211, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004949, + 0.015502, + 0.066892, + 0.464961, + 0.32999, + 0.670271, + 0.724501, + 0.740326, + 0.695189, + 0.618593, + 0.498122, + 0.346719, + 0.171014, + 0.036234999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003669, + 0.092007, + 0.28005, + 0.458039, + 0.595346, + 0.685022, + 0.7494679999999999, + 0.770077, + 0.753625, + 0.678376, + 0.562316, + 0.40467899999999996, + 0.19651400000000002, + 0.030562000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004136999999999999, + 0.09312300000000001, + 0.292676, + 0.478173, + 0.6147079999999999, + 0.710612, + 0.7686609999999999, + 0.7813410000000001, + 0.7506649999999999, + 0.678271, + 0.556412, + 0.385995, + 0.188857, + 0.035771000000000004, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003749, + 0.091194, + 0.282068, + 0.46097899999999997, + 0.595208, + 0.6924239999999999, + 0.751557, + 0.76842, + 0.7278060000000001, + 0.656251, + 0.542549, + 0.38782, + 0.187976, + 0.028846, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0025670000000000003, + 0.08610599999999999, + 0.282717, + 0.463063, + 0.598043, + 0.701151, + 0.763845, + 0.783995, + 0.751491, + 0.679756, + 0.559903, + 0.403275, + 0.19164099999999998, + 0.02395, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.008025000000000001, + 0.085283, + 0.09686499999999999, + 0.14163499999999998, + 0.17796199999999998, + 0.24358000000000002, + 0.311884, + 0.5878150000000001, + 0.575168, + 0.322108, + 0.439795, + 0.20380500000000001, + 0.131167, + 0.026132000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0022400000000000002, + 0.083544, + 0.09713899999999999, + 0.109293, + 0.16634200000000002, + 0.25605399999999995, + 0.33430200000000004, + 0.468298, + 0.5515249999999999, + 0.49306099999999997, + 0.431448, + 0.391867, + 0.184454, + 0.026316, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003029, + 0.081888, + 0.091944, + 0.33751, + 0.278038, + 0.7260209999999999, + 0.788763, + 0.804582, + 0.770023, + 0.690458, + 0.562119, + 0.40074, + 0.188723, + 0.023535, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00139, + 0.078624, + 0.144262, + 0.45333999999999997, + 0.591727, + 0.6882569999999999, + 0.7530030000000001, + 0.772559, + 0.746761, + 0.669008, + 0.5479189999999999, + 0.393201, + 0.18550999999999998, + 0.021201, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0014650000000000002, + 0.08122499999999999, + 0.143595, + 0.47109500000000004, + 0.43645100000000003, + 0.717369, + 0.780265, + 0.7940349999999999, + 0.759884, + 0.684477, + 0.563179, + 0.368029, + 0.17403, + 0.028694, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.001768, + 0.034997, + 0.228962, + 0.413642, + 0.540157, + 0.496544, + 0.632058, + 0.358714, + 0.511038, + 0.5498350000000001, + 0.484404, + 0.352137, + 0.16747700000000001, + 0.028271, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.002297, + 0.081055, + 0.26716, + 0.446297, + 0.588515, + 0.6805979999999999, + 0.7361409999999999, + 0.74602, + 0.704822, + 0.6265729999999999, + 0.5055470000000001, + 0.348312, + 0.164793, + 0.030579000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.001829, + 0.078529, + 0.153773, + 0.182204, + 0.58836, + 0.684542, + 0.743713, + 0.7519410000000001, + 0.720915, + 0.32249, + 0.288676, + 0.21, + 0.111453, + 0.024106000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.001389, + 0.076974, + 0.10411799999999999, + 0.231026, + 0.27592, + 0.312024, + 0.442178, + 0.388232, + 0.34825, + 0.653569, + 0.326533, + 0.373606, + 0.17034, + 0.021162, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.001417, + 0.076737, + 0.066887, + 0.130271, + 0.206044, + 0.275166, + 0.598327, + 0.787374, + 0.756013, + 0.437475, + 0.382978, + 0.388443, + 0.176458, + 0.018925, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.000924, + 0.074822, + 0.046741, + 0.09890900000000001, + 0.146153, + 0.21000899999999997, + 0.282202, + 0.297567, + 0.317298, + 0.678545, + 0.553433, + 0.278227, + 0.173966, + 0.016632, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.000482, + 0.07431499999999999, + 0.038613999999999996, + 0.139427, + 0.6136, + 0.351498, + 0.324897, + 0.30159600000000003, + 0.307107, + 0.273677, + 0.171186, + 0.108861, + 0.173599, + 0.017242999999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00045900000000000004, + 0.074509, + 0.038, + 0.10371, + 0.10421599999999999, + 0.14637999999999998, + 0.438581, + 0.473175, + 0.47200400000000003, + 0.439111, + 0.5521029999999999, + 0.190199, + 0.10216, + 0.017463, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.075034, + 0.082718, + 0.24115199999999998, + 0.606649, + 0.71049, + 0.771027, + 0.786333, + 0.753093, + 0.6750470000000001, + 0.550732, + 0.379487, + 0.1684, + 0.020065000000000003, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.07245, + 0.179595, + 0.143514, + 0.318639, + 0.7108239999999999, + 0.770436, + 0.782548, + 0.748754, + 0.6686259999999999, + 0.545319, + 0.373399, + 0.164659, + 0.018155, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.072958, + 0.27398500000000003, + 0.45807600000000004, + 0.5881130000000001, + 0.684447, + 0.746874, + 0.767076, + 0.738247, + 0.6622100000000001, + 0.5410560000000001, + 0.377513, + 0.16531800000000002, + 0.01358, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.07315600000000001, + 0.168526, + 0.37621699999999997, + 0.6189880000000001, + 0.718658, + 0.7771290000000001, + 0.796036, + 0.763882, + 0.6840700000000001, + 0.556948, + 0.381424, + 0.165737, + 0.016182, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.07219400000000001, + 0.28031, + 0.47402, + 0.613753, + 0.7113780000000001, + 0.7690650000000001, + 0.783811, + 0.754809, + 0.673239, + 0.548581, + 0.380083, + 0.163602, + 0.013112, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.071427, + 0.282519, + 0.476737, + 0.6179600000000001, + 0.721441, + 0.7812910000000001, + 0.802622, + 0.768201, + 0.687123, + 0.558901, + 0.384158, + 0.164227, + 0.012882999999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.07142, + 0.28150200000000003, + 0.47492399999999996, + 0.613799, + 0.710958, + 0.769211, + 0.7819109999999999, + 0.751104, + 0.67379, + 0.5487110000000001, + 0.377618, + 0.161153, + 0.012528000000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.070471, + 0.279532, + 0.471774, + 0.609475, + 0.706569, + 0.7678339999999999, + 0.785687, + 0.751826, + 0.674085, + 0.546129, + 0.37551, + 0.156636, + 0.011427, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.07111100000000001, + 0.275492, + 0.47280700000000003, + 0.618214, + 0.7202799999999999, + 0.781066, + 0.797456, + 0.7635, + 0.68243, + 0.551745, + 0.373727, + 0.15471000000000001, + 0.010248, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.06931699999999999, + 0.27876999999999996, + 0.48077, + 0.628019, + 0.7322329999999999, + 0.792431, + 0.8069700000000001, + 0.7713880000000001, + 0.686742, + 0.554183, + 0.370765, + 0.151665, + 0.009032, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.066729, + 0.060238999999999994, + 0.12030400000000001, + 0.20492, + 0.727187, + 0.789087, + 0.803326, + 0.7692559999999999, + 0.683883, + 0.55015, + 0.367124, + 0.14898599999999998, + 0.007723, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.066943, + 0.26824000000000003, + 0.46156, + 0.59554, + 0.6898289999999999, + 0.749663, + 0.767619, + 0.7413569999999999, + 0.661937, + 0.53327, + 0.35802999999999996, + 0.14319300000000001, + 0.005699, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.064701, + 0.26375299999999996, + 0.449702, + 0.5847469999999999, + 0.686847, + 0.750565, + 0.766986, + 0.7343010000000001, + 0.653555, + 0.526183, + 0.223696, + 0.095664, + 0.00471, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.063134, + 0.056537, + 0.146715, + 0.260139, + 0.708307, + 0.766364, + 0.7750049999999999, + 0.735241, + 0.651503, + 0.523926, + 0.349391, + 0.13699799999999998, + 0.004189, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.06303199999999999, + 0.087004, + 0.16555, + 0.13255, + 0.26376499999999997, + 0.44682, + 0.78854, + 0.75075, + 0.6649149999999999, + 0.531584, + 0.354223, + 0.136024, + 0.00387, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.062834, + 0.061764, + 0.21978899999999998, + 0.604011, + 0.706488, + 0.768179, + 0.780649, + 0.744112, + 0.661617, + 0.531258, + 0.352725, + 0.13499, + 0.0034, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.061985, + 0.110968, + 0.262685, + 0.593878, + 0.696, + 0.755641, + 0.7724289999999999, + 0.740506, + 0.655255, + 0.524693, + 0.339793, + 0.12795600000000001, + 0.0028399999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.060903, + 0.044276, + 0.091652, + 0.16186, + 0.32560500000000003, + 0.437329, + 0.36658999999999997, + 0.331049, + 0.37931099999999995, + 0.37037200000000003, + 0.116191, + 0.030126999999999998, + 0.004861, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.018888000000000002, + 0.0043040000000000005, + 0.133963, + 0.592598, + 0.45269299999999996, + 0.42350099999999996, + 0.759057, + 0.721438, + 0.497493, + 0.507491, + 0.242527, + 0.12127500000000001, + 0.004615, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.049387, + 0.12957400000000002, + 0.447529, + 0.594086, + 0.696349, + 0.753147, + 0.761147, + 0.722887, + 0.6397619999999999, + 0.343109, + 0.16083699999999998, + 0.118828, + 0.002298, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.046494, + 0.16522900000000001, + 0.222255, + 0.097719, + 0.099006, + 0.181837, + 0.12926300000000002, + 0.147102, + 0.132619, + 0.10119700000000001, + 0.042618, + 0.046629, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0027519999999999997, + 0.115165, + 0.093289, + 0.046822, + 0.176256, + 0.380156, + 0.207031, + 0.2296, + 0.295696, + 0.178033, + 0.26714, + 0.05001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.046945999999999995, + 0.103502, + 0.22362, + 0.564345, + 0.349068, + 0.7256509999999999, + 0.287511, + 0.271318, + 0.189382, + 0.069565, + 0.105419, + 0.051781, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005525, + 0.019878, + 0.052762, + 0.016998000000000003, + 0.044707000000000004, + 0.059487000000000005, + 0.094413, + 0.252527, + 0.178067, + 0.18603999999999998, + 0.10785800000000001, + 0.027280000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.029485, + 0.068054, + 0.2364, + 0.27556400000000003, + 0.503134, + 0.743007, + 0.75637, + 0.724163, + 0.639276, + 0.5033960000000001, + 0.302086, + 0.099577, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.053216, + 0.251101, + 0.454838, + 0.6062580000000001, + 0.719015, + 0.775149, + 0.78623, + 0.74907, + 0.660022, + 0.5203390000000001, + 0.31559699999999996, + 0.101404, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.053634, + 0.252173, + 0.45603899999999997, + 0.608504, + 0.717505, + 0.774586, + 0.7811480000000001, + 0.739577, + 0.6502490000000001, + 0.511695, + 0.309996, + 0.098569, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.052307, + 0.25113800000000003, + 0.45194999999999996, + 0.603209, + 0.70387, + 0.761327, + 0.769518, + 0.733683, + 0.64275, + 0.506339, + 0.312166, + 0.096439, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.051603, + 0.258728, + 0.46372399999999997, + 0.607355, + 0.702324, + 0.748641, + 0.744611, + 0.697677, + 0.612783, + 0.48474599999999995, + 0.304379, + 0.093498, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.051321, + 0.257668, + 0.45863, + 0.594221, + 0.676433, + 0.7114389999999999, + 0.7138089999999999, + 0.6969160000000001, + 0.6223289999999999, + 0.49459699999999995, + 0.308034, + 0.091195, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.050485999999999996, + 0.164012, + 0.458529, + 0.604928, + 0.710269, + 0.764668, + 0.7716839999999999, + 0.730172, + 0.637846, + 0.497673, + 0.304908, + 0.08705800000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.048874, + 0.103821, + 0.21676499999999999, + 0.319427, + 0.683195, + 0.741734, + 0.755362, + 0.7183010000000001, + 0.626524, + 0.490141, + 0.29953399999999997, + 0.084652, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.048909, + 0.252048, + 0.452807, + 0.597665, + 0.6968730000000001, + 0.7520990000000001, + 0.7560520000000001, + 0.710031, + 0.619445, + 0.483213, + 0.29206299999999996, + 0.080476, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.008218999999999999, + 0.062746, + 0.343072, + 0.587448, + 0.679215, + 0.73119, + 0.7393909999999999, + 0.703063, + 0.615703, + 0.481752, + 0.131167, + 0.078533, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.046773, + 0.25224, + 0.450604, + 0.581271, + 0.66724, + 0.621202, + 0.559766, + 0.290469, + 0.295916, + 0.063854, + 0.039456000000000005, + 0.035485, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.007078, + 0.11536, + 0.154068, + 0.239208, + 0.432833, + 0.452584, + 0.500207, + 0.542018, + 0.46946499999999997, + 0.340873, + 0.096689, + 0.025527, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.042451, + 0.021914000000000003, + 0.434939, + 0.585476, + 0.37264600000000003, + 0.535252, + 0.464078, + 0.7079880000000001, + 0.617049, + 0.475537, + 0.272673, + 0.066726, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.041644, + 0.103419, + 0.186767, + 0.5937319999999999, + 0.38583, + 0.347459, + 0.758167, + 0.715911, + 0.619743, + 0.476314, + 0.269769, + 0.06359000000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.041915, + 0.052778, + 0.11571, + 0.221702, + 0.6660119999999999, + 0.707726, + 0.7145750000000001, + 0.6720349999999999, + 0.5862329999999999, + 0.301093, + 0.26199900000000004, + 0.05977300000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.040936, + 0.245555, + 0.451152, + 0.594269, + 0.685691, + 0.725351, + 0.7218239999999999, + 0.674923, + 0.586419, + 0.453869, + 0.26692, + 0.059666, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.03964, + 0.239674, + 0.441878, + 0.579503, + 0.665412, + 0.70053, + 0.683704, + 0.6424249999999999, + 0.572988, + 0.446689, + 0.259878, + 0.055873, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.037937, + 0.23413499999999998, + 0.42833499999999997, + 0.559914, + 0.650413, + 0.70513, + 0.715101, + 0.676275, + 0.586256, + 0.447036, + 0.253321, + 0.051641, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.036616, + 0.23306100000000002, + 0.42856700000000003, + 0.566746, + 0.658908, + 0.712979, + 0.273412, + 0.20024, + 0.210772, + 0.12337300000000001, + 0.048593000000000004, + 0.049364, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.036052, + 0.23161400000000001, + 0.43627699999999997, + 0.430145, + 0.692299, + 0.43016899999999997, + 0.744698, + 0.694641, + 0.600911, + 0.45447000000000004, + 0.251268, + 0.047200000000000006, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.016725999999999998, + 0.11996, + 0.190281, + 0.18260300000000002, + 0.251654, + 0.416777, + 0.311896, + 0.342411, + 0.601939, + 0.45538799999999996, + 0.25166499999999997, + 0.04499, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.034146, + 0.234789, + 0.434764, + 0.5783780000000001, + 0.677605, + 0.729558, + 0.736546, + 0.689751, + 0.595518, + 0.451852, + 0.248224, + 0.042103, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.032858, + 0.234234, + 0.435102, + 0.570606, + 0.662284, + 0.7171230000000001, + 0.725706, + 0.6809850000000001, + 0.589055, + 0.44195999999999996, + 0.236514, + 0.037571, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.030258, + 0.228497, + 0.42511200000000005, + 0.561797, + 0.659902, + 0.718371, + 0.7262569999999999, + 0.682596, + 0.587812, + 0.440435, + 0.237548, + 0.035122999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.028769, + 0.040116, + 0.149019, + 0.5778260000000001, + 0.676714, + 0.725862, + 0.727406, + 0.677336, + 0.580351, + 0.435901, + 0.232681, + 0.03165, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005873000000000001, + 0.05745, + 0.070354, + 0.145361, + 0.276031, + 0.318728, + 0.714883, + 0.6678200000000001, + 0.439892, + 0.24615199999999998, + 0.055658, + 0.026646, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010898, + 0.053048000000000005, + 0.073686, + 0.08358700000000001, + 0.125563, + 0.163946, + 0.154197, + 0.16926, + 0.255404, + 0.222258, + 0.022745, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.021639, + 0.219482, + 0.42365600000000003, + 0.573014, + 0.6631710000000001, + 0.714418, + 0.713721, + 0.662055, + 0.565356, + 0.417231, + 0.21596, + 0.018524000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.020017, + 0.221425, + 0.426117, + 0.5691710000000001, + 0.6593680000000001, + 0.701554, + 0.69929, + 0.646841, + 0.552672, + 0.410928, + 0.203491, + 0.013211, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015887000000000002, + 0.210938, + 0.408814, + 0.545889, + 0.628721, + 0.654883, + 0.660805, + 0.626325, + 0.542539, + 0.400688, + 0.15998500000000002, + 0.012243, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.015208000000000001, + 0.21765, + 0.41752999999999996, + 0.549406, + 0.632591, + 0.673997, + 0.677658, + 0.642331, + 0.548235, + 0.401411, + 0.145277, + 0.011348, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013535, + 0.210733, + 0.406833, + 0.547661, + 0.6461399999999999, + 0.698605, + 0.70241, + 0.6026079999999999, + 0.455407, + 0.20909899999999998, + 0.196403, + 0.008032, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.047063, + 0.07460599999999999, + 0.29309500000000005, + 0.50876, + 0.727662, + 0.728486, + 0.527083, + 0.57286, + 0.41376100000000005, + 0.201266, + 0.008241, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.013196, + 0.218811, + 0.431058, + 0.581635, + 0.355814, + 0.393898, + 0.727796, + 0.672336, + 0.444598, + 0.15283000000000002, + 0.089271, + 0.007621, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012566, + 0.21428999999999998, + 0.422602, + 0.566615, + 0.664284, + 0.713619, + 0.718136, + 0.6693600000000001, + 0.5692480000000001, + 0.419314, + 0.201549, + 0.006019, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.012557, + 0.22023900000000002, + 0.434192, + 0.582461, + 0.678133, + 0.7249629999999999, + 0.7252569999999999, + 0.670073, + 0.56751, + 0.413868, + 0.195304, + 0.004944, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010303000000000001, + 0.208334, + 0.420602, + 0.572177, + 0.674265, + 0.723615, + 0.723899, + 0.665089, + 0.558895, + 0.40475099999999997, + 0.18867699999999998, + 0.003299, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.009943, + 0.210407, + 0.416373, + 0.461478, + 0.6478200000000001, + 0.699751, + 0.6996290000000001, + 0.636987, + 0.533709, + 0.380959, + 0.101137, + 0.001592, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.007014, + 0.17302099999999998, + 0.100578, + 0.5501900000000001, + 0.648019, + 0.6374690000000001, + 0.6909120000000001, + 0.639799, + 0.5364, + 0.381908, + 0.16755199999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004782, + 0.006548, + 0.034409999999999996, + 0.032368, + 0.149793, + 0.101551, + 0.017712, + 0.032756999999999994, + 0.01075, + 0.005068, + 0.016055, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003782, + 0.011712, + 0.03513, + 0.054396, + 0.191519, + 0.254391, + 0.174083, + 0.181369, + 0.114663, + 0.067932, + 0.027174, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00456, + 0.19268000000000002, + 0.39708699999999997, + 0.544356, + 0.6422920000000001, + 0.689196, + 0.6861670000000001, + 0.633378, + 0.532332, + 0.379832, + 0.161846, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.003271, + 0.197648, + 0.072952, + 0.359967, + 0.6032029999999999, + 0.674269, + 0.672571, + 0.6217039999999999, + 0.526077, + 0.372739, + 0.117737, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.037519, + 0.118131, + 0.271037, + 0.447394, + 0.565115, + 0.6666470000000001, + 0.6211749999999999, + 0.5185, + 0.368333, + 0.154619, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.002837, + 0.18903399999999998, + 0.395341, + 0.539532, + 0.635814, + 0.684397, + 0.682763, + 0.6285069999999999, + 0.526528, + 0.367362, + 0.152617, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.20630400000000002, + 0.422473, + 0.573425, + 0.6698419999999999, + 0.712172, + 0.70272, + 0.63859, + 0.529393, + 0.373365, + 0.154067, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.193789, + 0.408322, + 0.5538289999999999, + 0.6358830000000001, + 0.672077, + 0.67788, + 0.632753, + 0.528596, + 0.363955, + 0.144868, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.17715799999999998, + 0.037519, + 0.085596, + 0.22354, + 0.150351, + 0.14341399999999999, + 0.190971, + 0.342519, + 0.13118100000000002, + 0.140293, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.019774, + 0.072339, + 0.11859099999999999, + 0.231626, + 0.537931, + 0.693981, + 0.639796, + 0.535243, + 0.368725, + 0.14376499999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.054695999999999995, + 0.150714, + 0.36448, + 0.217615, + 0.546058, + 0.452536, + 0.5567219999999999, + 0.46962, + 0.359802, + 0.134535, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.014599, + 0.397248, + 0.560635, + 0.658057, + 0.720816, + 0.715422, + 0.653673, + 0.325007, + 0.36343200000000003, + 0.133243, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.075804, + 0.23005199999999998, + 0.279673, + 0.61168, + 0.6977490000000001, + 0.491079, + 0.63648, + 0.5232910000000001, + 0.351323, + 0.12747, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.169025, + 0.39040199999999997, + 0.25982, + 0.49509800000000004, + 0.694016, + 0.689037, + 0.6303920000000001, + 0.519901, + 0.348014, + 0.015561, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.163648, + 0.377446, + 0.5316839999999999, + 0.147767, + 0.347079, + 0.667241, + 0.613993, + 0.506486, + 0.34086900000000003, + 0.120567, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.170267, + 0.38594799999999996, + 0.5339740000000001, + 0.626856, + 0.6693669999999999, + 0.6614690000000001, + 0.601403, + 0.49387400000000004, + 0.329827, + 0.114333, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.15903, + 0.365031, + 0.510793, + 0.606676, + 0.6488740000000001, + 0.640845, + 0.586047, + 0.482803, + 0.326324, + 0.112199, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.157155, + 0.367833, + 0.5149320000000001, + 0.6066889999999999, + 0.645025, + 0.635437, + 0.580117, + 0.48292599999999997, + 0.32219200000000003, + 0.108298, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.167697, + 0.045020000000000004, + 0.108587, + 0.19986, + 0.380894, + 0.6550739999999999, + 0.600916, + 0.5009239999999999, + 0.33419600000000005, + 0.110689, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.160291, + 0.054792, + 0.148983, + 0.19856000000000001, + 0.554485, + 0.654157, + 0.595567, + 0.491637, + 0.16375, + 0.106486, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.036153, + 0.13190700000000002, + 0.144793, + 0.155528, + 0.19497, + 0.10528499999999999, + 0.117372, + 0.106992, + 0.067453, + 0.086387, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.145009, + 0.36654899999999996, + 0.525515, + 0.628753, + 0.672117, + 0.66337, + 0.609757, + 0.502155, + 0.33248, + 0.10377800000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.099326, + 0.237247, + 0.217076, + 0.417549, + 0.374998, + 0.400719, + 0.403937, + 0.17356100000000002, + 0.259808, + 0.04269, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.15512399999999998, + 0.38606999999999997, + 0.5509109999999999, + 0.647608, + 0.6922200000000001, + 0.680134, + 0.618429, + 0.503468, + 0.325989, + 0.097506, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.14688800000000002, + 0.367476, + 0.5165230000000001, + 0.6042240000000001, + 0.649552, + 0.652689, + 0.601259, + 0.49030399999999996, + 0.315618, + 0.089229, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.00282, + 0.065374, + 0.06556999999999999, + 0.09196, + 0.081842, + 0.055698, + 0.101548, + 0.08664, + 0.153448, + 0.012676, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.072771, + 0.155337, + 0.30438299999999996, + 0.30615, + 0.301221, + 0.404387, + 0.25063599999999997, + 0.153184, + 0.13897900000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.12151999999999999, + 0.15256299999999998, + 0.204154, + 0.294755, + 0.088546, + 0.125015, + 0.111239, + 0.16584200000000002, + 0.277208, + 0.067205, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.021837, + 0.172847, + 0.333735, + 0.37463, + 0.118137, + 0.166679, + 0.045265, + 0.121636, + 0.0043029999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.102994, + 0.31802199999999997, + 0.48637, + 0.249355, + 0.21543500000000002, + 0.639988, + 0.5702910000000001, + 0.455561, + 0.279702, + 0.064611, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.11159999999999999, + 0.330081, + 0.492464, + 0.5938479999999999, + 0.639313, + 0.636021, + 0.57711, + 0.465206, + 0.293691, + 0.069892, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.124408, + 0.345734, + 0.510216, + 0.606967, + 0.649924, + 0.639601, + 0.577689, + 0.467798, + 0.292263, + 0.06800199999999999, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.114897, + 0.339818, + 0.502745, + 0.604611, + 0.642788, + 0.628312, + 0.564039, + 0.44971, + 0.282666, + 0.060213, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.100816, + 0.149375, + 0.080733, + 0.143083, + 0.029922, + 0.077057, + 0.327374, + 0.250195, + 0.089389, + 0.046901000000000005, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.105865, + 0.140363, + 0.065292, + 0.12192700000000001, + 0.021096, + 0.03713, + 0.08520799999999999, + 0.095861, + 0.153179, + 0.002419, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.006724, + 0.002274, + 0.218692, + 0.46231900000000004, + 0.63751, + 0.386472, + 0.351781, + 0.248465, + 0.253622, + 0.037558999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.09554399999999999, + 0.092549, + 0.470888, + 0.568247, + 0.618829, + 0.418186, + 0.292743, + 0.126427, + 0.054466, + 0.005438, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.089524, + 0.31415699999999996, + 0.48466000000000004, + 0.5851369999999999, + 0.632293, + 0.621621, + 0.560523, + 0.44731299999999996, + 0.27578800000000003, + 0.035813000000000005, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.09669199999999999, + 0.329865, + 0.49500299999999997, + 0.589234, + 0.6313, + 0.618016, + 0.555369, + 0.447514, + 0.277829, + 0.042247, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.040038, + 0.100956, + 0.29577499999999995, + 0.440085, + 0.475562, + 0.60354, + 0.549668, + 0.442303, + 0.266445, + 0.031738, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.037166, + 0.359454, + 0.32966, + 0.532563, + 0.629447, + 0.579843, + 0.468908, + 0.19475800000000001, + 0.037732999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.085157, + 0.33581099999999997, + 0.513514, + 0.6185729999999999, + 0.66907, + 0.663337, + 0.601445, + 0.478952, + 0.28866, + 0.039542, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.08052200000000001, + 0.33885899999999997, + 0.514571, + 0.625602, + 0.676106, + 0.668609, + 0.60321, + 0.483903, + 0.294549, + 0.041943, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.072522, + 0.33386, + 0.5135510000000001, + 0.6163529999999999, + 0.6650320000000001, + 0.657848, + 0.5895370000000001, + 0.467971, + 0.2831, + 0.029879000000000003, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.030361, + 0.16774, + 0.27061799999999997, + 0.430272, + 0.585603, + 0.459374, + 0.45499700000000004, + 0.276931, + 0.197446, + 0.032334, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.051043, + 0.30494499999999997, + 0.48424700000000004, + 0.5955750000000001, + 0.650799, + 0.641634, + 0.580016, + 0.459, + 0.27347000000000005, + 0.030786, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.047353, + 0.301939, + 0.478007, + 0.586032, + 0.634158, + 0.6282709999999999, + 0.568155, + 0.45525299999999996, + 0.27690800000000004, + 0.035792000000000004, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.020583999999999998, + 0.14386500000000002, + 0.269198, + 0.500752, + 0.36566899999999997, + 0.457079, + 0.395386, + 0.161571, + 0.192339, + 0.006709, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0036379999999999997, + 0.040121000000000004, + 0.057902999999999996, + 0.057275, + 0.123192, + 0.085161, + 0.112676, + 0.22146000000000002, + 0.031337, + 0.0059050000000000005, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.042859, + 0.038104, + 0.129663, + 0.079961, + 0.20484200000000002, + 0.062014, + 0.11486, + 0.081828, + 0.000804, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.004687, + 0.127452, + 0.036534, + 0.13252699999999998, + 0.05534, + 0.048898000000000004, + 0.010955999999999999, + 0.030615, + 0.0, + 0.031921, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.027622, + 0.280421, + 0.45673, + 0.571893, + 0.620841, + 0.6171760000000001, + 0.558654, + 0.450077, + 0.273764, + 0.035171, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.029021, + 0.29875599999999997, + 0.488084, + 0.5953890000000001, + 0.649371, + 0.642302, + 0.579766, + 0.459941, + 0.278207, + 0.034389, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.024632, + 0.28309300000000004, + 0.469962, + 0.5844429999999999, + 0.635895, + 0.629531, + 0.568164, + 0.450895, + 0.27214, + 0.03344, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.023339, + 0.280745, + 0.465478, + 0.5748070000000001, + 0.6232190000000001, + 0.620653, + 0.562562, + 0.451157, + 0.275655, + 0.034586, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.022476, + 0.285697, + 0.471498, + 0.5787340000000001, + 0.632184, + 0.627077, + 0.5680599999999999, + 0.456219, + 0.278186, + 0.035561, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.019162, + 0.27452699999999997, + 0.461979, + 0.576836, + 0.625655, + 0.6215900000000001, + 0.563875, + 0.449472, + 0.272434, + 0.033602, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.014070000000000001, + 0.27456200000000003, + 0.465611, + 0.582663, + 0.6310520000000001, + 0.624709, + 0.568688, + 0.453159, + 0.27370999999999995, + 0.033262, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.000549, + 0.06019, + 0.019434999999999997, + 0.27879899999999996, + 0.366548, + 0.119098, + 0.037265, + 0.012471999999999999, + 0.040909999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.005386999999999999, + 0.09322799999999999, + 0.411584, + 0.3983, + 0.290843, + 0.10846800000000001, + 0.117991, + 0.042327, + 0.024497, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.035429, + 0.020318000000000003, + 0.275372, + 0.449861, + 0.129708, + 0.40101600000000004, + 0.10377, + 0.18141, + 0.005507, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010394, + 0.017341000000000002, + 0.367632, + 0.134552, + 0.07384, + 0.257359, + 0.176508, + 0.045712, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.03066, + 0.021280999999999998, + 0.102838, + 0.092095, + 0.088723, + 0.030473, + 0.108304, + 0.020708999999999998, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 2.4e-05, + 0.014702999999999999, + 0.07937999999999999, + 0.086605, + 0.072087, + 0.08878100000000001, + 0.014531, + 0.014476000000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.047119999999999995, + 0.10545600000000001, + 0.08333499999999999, + 0.134996, + 0.193302, + 0.11107500000000001, + 0.177164, + 0.016797999999999997, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.051546999999999996, + 0.41633499999999996, + 0.535533, + 0.565662, + 0.447768, + 0.32101, + 0.256375, + 0.104744, + 0.003762, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.126812, + 0.367576, + 0.459642, + 0.36076400000000003, + 0.168426, + 0.203407, + 0.088589, + 0.00328, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0013109999999999999, + 0.11211700000000001, + 0.411627, + 0.5515869999999999, + 0.617072, + 0.617684, + 0.57199, + 0.463167, + 0.28522699999999995, + 0.039644, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.270694, + 0.472675, + 0.59624, + 0.657344, + 0.659728, + 0.602637, + 0.49268900000000004, + 0.30993200000000004, + 0.047591, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.25683999999999996, + 0.45623, + 0.573627, + 0.6295259999999999, + 0.628937, + 0.576683, + 0.463113, + 0.284615, + 0.037795999999999996, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.19900299999999999, + 0.26733100000000004, + 0.53418, + 0.434674, + 0.32583100000000004, + 0.55662, + 0.444478, + 0.184032, + 0.016429, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.016259, + 0.0030099999999999997, + 0.017943999999999998, + 0.043079, + 0.050006, + 0.01554, + 0.01411, + 0.053131, + 0.001287, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.116388, + 0.44166000000000005, + 0.568314, + 0.628334, + 0.630308, + 0.581491, + 0.469296, + 0.29585500000000003, + 0.047240000000000004, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.050122, + 0.399708, + 0.3785, + 0.363068, + 0.5497569999999999, + 0.527504, + 0.39016199999999995, + 0.136928, + 0.037068, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.15160900000000002, + 0.263996, + 0.27651299999999995, + 0.26359899999999997, + 0.283422, + 0.142758, + 0.028759, + 0.219005, + 0.008166, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.10223399999999999, + 0.17571199999999998, + 0.320901, + 0.264941, + 0.318867, + 0.336154, + 0.243585, + 0.026018999999999997, + 0.001746, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.010048, + 0.20984, + 0.23355199999999998, + 0.093792, + 0.06717400000000001, + 0.06515800000000001, + 0.010235, + 0.024574000000000002, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.188452, + 0.39397699999999997, + 0.53483, + 0.61465, + 0.633432, + 0.583827, + 0.47733499999999995, + 0.30777699999999997, + 0.055341999999999995, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.247196, + 0.45849, + 0.589357, + 0.6594869999999999, + 0.664524, + 0.610888, + 0.497631, + 0.322501, + 0.06749200000000001, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.115419, + 0.283392, + 0.497602, + 0.487976, + 0.513755, + 0.482264, + 0.334339, + 0.160522, + 0.069884, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.059505, + 0.41926100000000005, + 0.536193, + 0.598533, + 0.601776, + 0.39882999999999996, + 0.346023, + 0.283566, + 0.021283999999999997, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.083165, + 0.23922, + 0.061994, + 0.13736500000000001, + 0.094553, + 0.134045, + 0.055619, + 0.030178, + 0.069961, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "ElectricStorage": { + "min_kw": 20.0, + "max_kw": 20.0, + "min_kwh": 40.0, + "max_kwh": 40.0, + "soc_init_fraction": 0.5, + "soc_min_fraction": 0.2, + "dispatch_strategy": "daily_foresight_optimized" + }, + "ElectricLoad": { + "year": 2025 + }, + "ElectricTariff": { + "monthly_demand_rates": [200.0, 20.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0] + }, + "ElectricUtility": { + "net_metering_limit_kw": 0.0 + } +} \ No newline at end of file diff --git a/reoptjl/test/test_job_endpoint.py b/reoptjl/test/test_job_endpoint.py index 501fb1e55..82e3f671e 100644 --- a/reoptjl/test/test_job_endpoint.py +++ b/reoptjl/test/test_job_endpoint.py @@ -113,6 +113,45 @@ def test_process_reopt_error(self): assert(r['messages']['has_stacktrace']==True) assert(resp.status_code==400) + def test_mpc(self): + """ + Purpose of this test is to ensure that the MPC endpoint works as expected + """ + + post_file = os.path.join('reoptjl', 'test', 'posts', 'mpc.json') + post = json.load(open(post_file, 'r')) + + # Checking that MPC correctly identifies peak load of Jan and Feb and fully dispatches BESS for both peaks. + loads_kw = [10] * 8760 + loads_kw[743] = 50 # 1/31/25 23:00 + loads_kw[745] = 100 # 2/1/25 01:00 + post["ElectricLoad"]["loads_kw"] = loads_kw + post["ElectricTariff"]["monthly_energy_rates"] = [0.10] * 12 + + # expected_jan_demand_cost = post["ElectricTariff"]["monthly_demand_rates"][0] * (50 - post["ElectricStorage"]["min_kw"]) + # expected_feb_demand_cost = post["ElectricTariff"]["monthly_demand_rates"][1] * (100 - post["ElectricStorage"]["min_kw"]) + + # resp = self.api_client.post('/v3/job/', format='json', data=post) + # self.assertHttpCreated(resp) + # r = json.loads(resp.content) + # run_uuid = r.get('run_uuid') + + # resp = self.api_client.get(f'/v3/job/{run_uuid}/results') + # r = json.loads(resp.content) + # results = r["outputs"] + # assert(resp.status_code==200) + # self.assertAlmostEqual(results["ElectricTariff"]["monthly_demand_cost_series_before_tax"][0], expected_jan_demand_cost, delta=0.01) + # self.assertAlmostEqual(results["ElectricTariff"]["monthly_demand_cost_series_before_tax"][1], expected_feb_demand_cost, delta=0.01) + + # Should error if off-grid + post["Settings"]["off_grid_flag"] = True + resp = self.api_client.post('/v3/job/', format='json', data=post) + self.assertHttpCreated(resp) + r = json.loads(resp.content) + run_uuid = r.get('run_uuid') + resp = self.api_client.get(f'/v3/job/{run_uuid}/results') + assert(resp.status_code==400) + def test_thermal_in_results(self): """ Purpose of this test is to check that the expected thermal loads, techs, and storage are included in the results diff --git a/reoptjl/validators.py b/reoptjl/validators.py index 21f65cc76..671d383fd 100644 --- a/reoptjl/validators.py +++ b/reoptjl/validators.py @@ -89,6 +89,7 @@ def __init__(self, raw_inputs: dict, ghpghx_inputs_validation_errors=None): CSTInputs ) self.pvnames = [] + self.chpnames = [] on_grid_required_object_names = [ "Site", "ElectricLoad", "ElectricTariff" ] @@ -105,12 +106,27 @@ def __init__(self, raw_inputs: dict, ghpghx_inputs_validation_errors=None): for obj in self.objects: if obj == APIMeta: continue # already created and saved if obj.key in raw_inputs.keys(): - if isinstance(raw_inputs[obj.key], list) and obj.key == "PV": # only handle array of PV - for (i, user_pv) in enumerate(raw_inputs["PV"]): - name = user_pv.get("name", "") - self.pvnames.append(name if not name == "" else "PV" + str(i)) - filtered_user_post[self.pvnames[-1]] = scrub_fields(obj, user_pv) - self.models[self.pvnames[-1]] = obj.create(meta=meta, **filtered_user_post[self.pvnames[-1]]) + if isinstance(raw_inputs[obj.key], list) and obj.key in ["PV", "CHP"]: + # only PV and CHP can be arrays of technology objects + seen_names = set() + for (i, user_tech) in enumerate(raw_inputs[obj.key]): + name = user_tech.get("name", "") + tech_name = name if not name == "" else obj.key + str(i) + + # Check for duplicate names within the list + if tech_name in seen_names: + self.validation_errors[obj.key] = f"Duplicate {obj.key} name: '{tech_name}'. All {obj.key} names must be unique." + continue + seen_names.add(tech_name) + + if obj.key == "PV": + self.pvnames.append(tech_name) + else: + self.chpnames.append(tech_name) + if name == "": + user_tech["name"] = tech_name + filtered_user_post[tech_name] = scrub_fields(obj, user_tech) + self.models[tech_name] = obj.create(meta=meta, **filtered_user_post[tech_name]) else: filtered_user_post[obj.key] = scrub_fields(obj, raw_inputs[obj.key]) self.models[obj.key] = obj.create(meta=meta, **filtered_user_post[obj.key]) @@ -151,7 +167,7 @@ def messages(self): if "ElectricUtility" in self.models.keys(): msg_dict["ignored inputs"] = ("ElectricUtility inputs are not applicable when off_grid_flag is true, and will be ignored. " "Provided ElectricUtility can be removed from inputs") - msg_dict["info"] = ("When off_grid_flag is true, only PV, Wind, ElectricStorage, Generator technologies can be modeled.") + msg_dict["info"] = ("When off_grid_flag is true, only PV, Wind, ElectricStorage, Generator, CHP technologies can be modeled.") return msg_dict @property @@ -164,11 +180,11 @@ def validated_input_dict(self): """ d = dict() for model in self.models.values(): - if model.key == "PV" and self.pvnames: - if "PV" not in d.keys(): - d["PV"] = [{k: v for (k, v) in model.dict.items() if v not in [None, []]}] + if model.key in ["PV", "CHP"] and (self.pvnames if model.key == "PV" else self.chpnames): + if model.key not in d.keys(): + d[model.key] = [{k: v for (k, v) in model.dict.items() if v not in [None, []]}] else: - d["PV"].append({k: v for (k, v) in model.dict.items() if v not in [None, []]}) + d[model.key].append({k: v for (k, v) in model.dict.items() if v not in [None, []]}) else: d[model.key] = {k: v for (k, v) in model.dict.items() if v not in [None, []]} # cleaning out model attribute @@ -272,6 +288,27 @@ def update_pv_defaults_offgrid(self, pvmodel): cross_clean_pv(self.models[pvname]) update_pv_defaults_offgrid(self, self.models[pvname]) + """ + CHP validation + """ + def cross_clean_chp(chpmodel_key): + if len(self.models[chpmodel_key].production_factor_series) > 0: + self.clean_time_series(chpmodel_key, "production_factor_series") + + if self.models["Settings"].off_grid_flag: + if self.models[chpmodel_key].operating_reserve_required_fraction is None: + self.models[chpmodel_key].operating_reserve_required_fraction = 0.0 + else: + # operating reserve requirement for CHP only applies to off-grid + self.models[chpmodel_key].operating_reserve_required_fraction = 0.0 + + if "CHP" in self.models.keys(): # single CHP + cross_clean_chp("CHP") + + if len(self.chpnames) > 0: # multiple CHP + for chpname in self.chpnames: + cross_clean_chp(chpname) + """ Time series values are up or down sampled to align with Settings.time_steps_per_hour """ @@ -363,11 +400,20 @@ def update_pv_defaults_offgrid(self, pvmodel): else: self.models["ElectricStorage"].soc_init_fraction = 1.0 + if self.models["ElectricStorage"].__getattribute__("soc_min_fraction") == None: + if self.models["ElectricStorage"].dispatch_strategy=="backup": + self.models["ElectricStorage"].soc_min_fraction = 0.8 + else: + self.models["ElectricStorage"].soc_min_fraction = 0.2 + if self.models["ElectricStorage"].__getattribute__("can_grid_charge") == None: if self.models["Settings"].off_grid_flag==False: self.models["ElectricStorage"].can_grid_charge = True else: self.models["ElectricStorage"].can_grid_charge = False + + if len(self.models["ElectricStorage"].__getattribute__("fixed_soc_series_fraction")) > 1: + self.clean_time_series("ElectricStorage", "fixed_soc_series_fraction") """ @@ -540,9 +586,17 @@ def assign_ref_buildings_from_electric_load(self, load_to_assign): def validate_offgrid_keys(self): # From https://github.com/NatLabRockies/REopt.jl/blob/4b0fb7f6556b2b6e9a9a7e8fa65398096fb6610f/src/core/scenario.jl#L88 - valid_input_keys_offgrid = ["PV", "Wind", "ElectricStorage", "Generator", "Settings", "Site", "Financial", "ElectricLoad", "ElectricTariff", "ElectricUtility", "Meta"] + valid_input_keys_offgrid = ["PV", "Wind", "ElectricStorage", "Generator", "CHP", "Settings", "Site", "Financial", "ElectricLoad", "ElectricTariff", "ElectricUtility", "Meta"] + + normalized_model_keys = set(self.models.keys()) + if len(self.pvnames) > 0: + normalized_model_keys -= set(self.pvnames) + normalized_model_keys.add("PV") + if len(self.chpnames) > 0: + normalized_model_keys -= set(self.chpnames) + normalized_model_keys.add("CHP") - invalid_input_keys_offgrid = list(set(list(self.models.keys()))-set(valid_input_keys_offgrid)) + invalid_input_keys_offgrid = list(normalized_model_keys - set(valid_input_keys_offgrid)) if 'APIMeta' in invalid_input_keys_offgrid: invalid_input_keys_offgrid.remove('APIMeta') diff --git a/reoptjl/views.py b/reoptjl/views.py index 08b1e21e8..c3af61e3e 100644 --- a/reoptjl/views.py +++ b/reoptjl/views.py @@ -254,8 +254,16 @@ def results(request, run_uuid): try: r["inputs"]["ProcessHeatLoad"] = meta.ProcessHeatLoadInputs.dict except: pass - try: r["inputs"]["CHP"] = meta.CHPInputs.dict - except: pass + try: + chps = meta.CHPInputs.all() + if len(chps) == 1: + r["inputs"]["CHP"] = chps[0].dict + elif len(chps) > 1: + r["inputs"]["CHP"] = [] + for chp in chps: + r["inputs"]["CHP"].append(chp.dict) + except: + pass try: r["inputs"]["AbsorptionChiller"] = meta.AbsorptionChillerInputs.dict except: pass @@ -340,8 +348,16 @@ def results(request, run_uuid): except: pass try: r["outputs"]["ColdThermalStorage"] = meta.ColdThermalStorageOutputs.dict except: pass - try: r["outputs"]["CHP"] = meta.CHPOutputs.dict - except: pass + try: + chps = meta.CHPOutputs.all() + if len(chps) == 1: + r["outputs"]["CHP"] = chps[0].dict + elif len(chps) > 1: + r["outputs"]["CHP"] = [] + for chp in chps: + r["outputs"]["CHP"].append(chp.dict) + except: + pass try: r["outputs"]["AbsorptionChiller"] = meta.AbsorptionChillerOutputs.dict except: pass try: r["outputs"]["HeatingLoad"] = meta.HeatingLoadOutputs.dict @@ -381,6 +397,8 @@ def results(request, run_uuid): if meta.status == "error": return JsonResponse(r, status=400) + if meta.status == "Internal Server Error. See messages for more.": + return JsonResponse(r, status=500) return JsonResponse(r) @@ -1366,23 +1384,26 @@ def queryset_for_summary(api_metas,summary_dict:dict): # assumes run_uuids exist in both CHPInputs and CHPOutputs chpInputs = CHPInputs.objects.filter(meta__run_uuid__in=run_uuids).only( 'meta__run_uuid', + 'name', 'thermal_efficiency_full_load' ) thermal_efficiency_full_load = dict() if len(chpInputs) > 0: for m in chpInputs: - thermal_efficiency_full_load[str(m.meta.run_uuid)] = m.thermal_efficiency_full_load + thermal_efficiency_full_load[(str(m.meta.run_uuid), m.name)] = m.thermal_efficiency_full_load chpOutputs = CHPOutputs.objects.filter(meta__run_uuid__in=run_uuids).only( 'meta__run_uuid', + 'name', 'size_kw' ) if len(chpOutputs) > 0: for m in chpOutputs: - if thermal_efficiency_full_load[str(m.meta.run_uuid)] == 0: - summary_dict[str(m.meta.run_uuid)]['prime_gen_kw'] = m.size_kw + rte = thermal_efficiency_full_load.get((str(m.meta.run_uuid), m.name)) + if rte == 0: + summary_dict[str(m.meta.run_uuid)]['prime_gen_kw'] = (summary_dict[str(m.meta.run_uuid)].get('prime_gen_kw') or 0) + (m.size_kw or 0) else: - summary_dict[str(m.meta.run_uuid)]['chp_kw'] = m.size_kw + summary_dict[str(m.meta.run_uuid)]['chp_kw'] = (summary_dict[str(m.meta.run_uuid)].get('chp_kw') or 0) + (m.size_kw or 0) ghpOutputs = GHPOutputs.objects.filter(meta__run_uuid__in=run_uuids).only( 'meta__run_uuid',