From e93911c6be3444a67b75c80d3ebf7213b4852b6f Mon Sep 17 00:00:00 2001 From: GabrielKS <23368820+GabrielKS@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:12:36 -0600 Subject: [PATCH 1/5] Override printing for cost aliases to maintain the illusion --- src/models/cost_functions/cost_aliases.jl | 41 ++++++++++++++++++++--- test/test_cost_functions.jl | 14 ++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/models/cost_functions/cost_aliases.jl b/src/models/cost_functions/cost_aliases.jl index 47b5382c57..7868adc23b 100644 --- a/src/models/cost_functions/cost_aliases.jl +++ b/src/models/cost_functions/cost_aliases.jl @@ -1,8 +1,9 @@ # Cost aliases: a simplified interface to the portion of the parametric # `ValueCurve{FunctionData}` design that the user is likely to interact with. Each alias -# consists of a simple name for a particular `ValueCurve{FunctionData}` type and a -# constructor and methods to interact with it without having to think about `FunctionData`. -# Everything here is properly speaking mere syntactic sugar for the underlying +# consists of a simple name for a particular `ValueCurve{FunctionData}` type, a constructor +# and methods to interact with it without having to think about `FunctionData`, and +# overridden printing behavior to complete the illusion. Everything here (aside from the +# overridden printing) is properly speaking mere syntactic sugar for the underlying # `ValueCurve{FunctionData}` design. One could imagine similar convenience constructors and # methods being defined for all the `ValueCurve{FunctionData}` types, not just the ones we # have here nicely packaged and presented to the user. @@ -23,6 +24,12 @@ InputOutputCurve{LinearFunctionData}(proportional_term::Real) = InputOutputCurve{LinearFunctionData}(proportional_term::Real, constant_term::Real) = InputOutputCurve(LinearFunctionData(proportional_term, constant_term)) +function Base.show(io::IO, data::LinearCurve) + fd = get_function_data(data) + p, c = get_proportional_term(fd), get_constant_term(fd) + print(io, "$(typeof(data))($p, $c)") +end + """ A quadratic input-output curve, may have nonzero no-load cost. @@ -38,6 +45,12 @@ InputOutputCurve{QuadraticFunctionData}(quadratic_term, proportional_term, const QuadraticFunctionData(quadratic_term, proportional_term, constant_term), ) +function Base.show(io::IO, data::QuadraticCurve) + fd = get_function_data(data) + q, p, c = get_quadratic_term(fd), get_proportional_term(fd), get_constant_term(fd) + print(io, "$(typeof(data))($q, $p, $c)") +end + """ A piecewise linear curve specified by cost values at production points. @@ -51,6 +64,10 @@ InputOutputCurve{PiecewiseLinearData}(points::Vector) = get_points(curve::PiecewisePointCurve) = get_points(get_function_data(curve)) +# Here we manually circumvent the @NamedTuple{x::Float64, y::Float64} annotation, but we keep things looking like named tuples +Base.show(io::IO, data::PiecewisePointCurve) = + print(io, "$(typeof(data))([$(join(get_points(data), ", "))])") + """ A piecewise linear curve specified by marginal rates (slopes) between production points. May have nonzero initial value. @@ -68,6 +85,14 @@ IncrementalCurve{PiecewiseStepData}(initial_input, x_coords::Vector, slopes::Vec get_slopes(curve::PiecewiseIncrementalCurve) = get_y_coords(get_function_data(curve)) +function Base.show(io::IO, data::PiecewiseIncrementalCurve) + initial_input = get_initial_input(data) + fd = get_function_data(data) + x_coords = get_x_coords(fd) + slopes = get_slopes(data) + print(io, "$(typeof(data))($initial_input, $x_coords, $slopes)") +end + """ A piecewise linear curve specified by average rates between production points. May have nonzero initial value. @@ -81,4 +106,12 @@ const PiecewiseAverageCurve = AverageRateCurve{PiecewiseStepData} AverageRateCurve{PiecewiseStepData}(initial_input, x_coords::Vector, y_coords::Vector) = AverageRateCurve(PiecewiseStepData(x_coords, y_coords), initial_input) -# TODO documentation, more getters, custom printing so it always shows the type alias (like Vector does) +function Base.show(io::IO, data::PiecewiseAverageCurve) + initial_input = get_initial_input(data) + fd = get_function_data(data) + x_coords = get_x_coords(fd) + y_coords = get_y_coords(fd) + print(io, "$(typeof(data))($initial_input, $x_coords, $y_coords)") +end + +# TODO documentation, more getters diff --git a/test/test_cost_functions.jl b/test/test_cost_functions.jl index 1596f36557..9f35a7ad9b 100644 --- a/test/test_cost_functions.jl +++ b/test/test_cost_functions.jl @@ -9,6 +9,8 @@ AverageRateCurve(LinearFunctionData(3, 2), 1.0) @test zero(io_quadratic) == InputOutputCurve(LinearFunctionData(0, 0)) @test zero(InputOutputCurve) == InputOutputCurve(LinearFunctionData(0, 0)) + @test repr(io_quadratic) == sprint(show, io_quadratic) == + "QuadraticCurve(3.0, 2.0, 1.0)" # repr is overridden due to cost alias io_linear = InputOutputCurve(LinearFunctionData(2, 1)) @test io_linear isa InputOutputCurve{LinearFunctionData} @@ -19,6 +21,8 @@ IncrementalCurve(LinearFunctionData(0, 2), 1.0) @test AverageRateCurve(io_linear) == AverageRateCurve(LinearFunctionData(0, 2), 1.0) + @test repr(io_linear) == sprint(show, io_linear) == + "LinearCurve(2.0, 1.0)" # repr is overridden due to cost alias io_piecewise = InputOutputCurve(PiecewiseLinearData([(1, 6), (3, 9), (5, 13)])) @test io_piecewise isa InputOutputCurve{PiecewiseLinearData} @@ -28,6 +32,8 @@ IncrementalCurve(PiecewiseStepData([1, 3, 5], [1.5, 2]), 6.0) @test AverageRateCurve(io_piecewise) == AverageRateCurve(PiecewiseStepData([1, 3, 5], [3, 2.6]), 6.0) + @test repr(io_piecewise) == sprint(show, io_piecewise) == + "PiecewisePointCurve([(x = 1.0, y = 6.0), (x = 3.0, y = 9.0), (x = 5.0, y = 13.0)])" # repr is overridden due to cost alias # IncrementalCurve inc_linear = IncrementalCurve(LinearFunctionData(6, 2), 1.0) @@ -42,6 +48,8 @@ AverageRateCurve(LinearFunctionData(3, 2), 1.0) @test zero(inc_linear) == IncrementalCurve(LinearFunctionData(0, 0), 0.0) @test zero(IncrementalCurve) == IncrementalCurve(LinearFunctionData(0, 0), 0.0) + @test repr(inc_linear) == sprint(show, inc_linear) == + "IncrementalCurve{LinearFunctionData}(LinearFunctionData(6.0, 2.0), 1.0)" inc_piecewise = IncrementalCurve(PiecewiseStepData([1, 3, 5], [1.5, 2]), 6.0) @test inc_piecewise isa IncrementalCurve{PiecewiseStepData} @@ -51,6 +59,8 @@ InputOutputCurve(PiecewiseLinearData([(1, 6), (3, 9), (5, 13)])) @test AverageRateCurve(inc_piecewise) == AverageRateCurve(PiecewiseStepData([1, 3, 5], [3, 2.6]), 6.0) + @test repr(inc_piecewise) == sprint(show, inc_piecewise) == + "PiecewiseIncrementalCurve(6.0, [1.0, 3.0, 5.0], [1.5, 2.0])" # repr is overridden due to cost alias # AverageRateCurve ar_linear = AverageRateCurve(LinearFunctionData(3, 2), 1.0) @@ -65,6 +75,8 @@ IncrementalCurve(LinearFunctionData(6, 2), 1.0) @test zero(ar_linear) == AverageRateCurve(LinearFunctionData(0, 0), 0.0) @test zero(AverageRateCurve) == AverageRateCurve(LinearFunctionData(0, 0), 0.0) + @test repr(ar_linear) == sprint(show, ar_linear) == + "AverageRateCurve{LinearFunctionData}(LinearFunctionData(3.0, 2.0), 1.0)" ar_piecewise = AverageRateCurve(PiecewiseStepData([1, 3, 5], [3, 2.6]), 6.0) @test get_function_data(ar_piecewise) == PiecewiseStepData([1, 3, 5], [3, 2.6]) @@ -73,6 +85,8 @@ InputOutputCurve(PiecewiseLinearData([(1, 6), (3, 9), (5, 13)])) @test IncrementalCurve(ar_piecewise) == IncrementalCurve(PiecewiseStepData([1, 3, 5], [1.5, 2]), 6.0) + @test repr(ar_piecewise) == sprint(show, ar_piecewise) == + "PiecewiseAverageCurve(6.0, [1.0, 3.0, 5.0], [3.0, 2.6])" # repr is overridden due to cost alias # Serialization round trip curves_by_type = [ # typeof() gives parameterized types From 7ec910dfb9bc0c7f33f0e8a0ddc6b436737945fb Mon Sep 17 00:00:00 2001 From: GabrielKS <23368820+GabrielKS@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:21:28 -0600 Subject: [PATCH 2/5] Implement pretty-printing for `ValueCurve`s --- src/models/cost_functions/ValueCurves.jl | 26 ++++++++++++++++++ src/models/cost_functions/cost_aliases.jl | 13 +++++++++ test/test_cost_functions.jl | 32 +++++++++++++++++++---- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/models/cost_functions/ValueCurves.jl b/src/models/cost_functions/ValueCurves.jl index 897f802f5e..7b0707ac5d 100644 --- a/src/models/cost_functions/ValueCurves.jl +++ b/src/models/cost_functions/ValueCurves.jl @@ -169,3 +169,29 @@ IncrementalCurve(data::AverageRateCurve) = IncrementalCurve(InputOutputCurve(dat is_convex(curve::InputOutputCurve) = is_convex(get_function_data(curve)) "Calculate the convexity of the underlying data" is_convex(curve::ValueCurve) = is_convex(InputOutputCurve(curve)) + +# PRINTING +# For cost aliases, return the alias name; otherwise, return the type name without the parameter +simple_type_name(curve::ValueCurve) = + string(is_cost_alias(curve) ? typeof(curve) : nameof(typeof(curve))) + +function Base.show(io::IO, ::MIME"text/plain", curve::InputOutputCurve) + print(io, simple_type_name(curve)) + is_cost_alias(curve) && print(io, " (a type of $InputOutputCurve)") + print(io, " with function: ") + show(IOContext(io, :compact => true), "text/plain", get_function_data(curve)) +end + +function Base.show(io::IO, ::MIME"text/plain", curve::IncrementalCurve) + print(io, simple_type_name(curve)) + print(io, " where initial value is $(get_initial_input(curve))") + print(io, " and derivative function f is: ") + show(IOContext(io, :compact => true), "text/plain", get_function_data(curve)) +end + +function Base.show(io::IO, ::MIME"text/plain", curve::AverageRateCurve) + print(io, simple_type_name(curve)) + print(io, " where initial value is $(get_initial_input(curve))") + print(io, " and average rate function f is: ") + show(IOContext(io, :compact => true), "text/plain", get_function_data(curve)) +end diff --git a/src/models/cost_functions/cost_aliases.jl b/src/models/cost_functions/cost_aliases.jl index 7868adc23b..66862f38f9 100644 --- a/src/models/cost_functions/cost_aliases.jl +++ b/src/models/cost_functions/cost_aliases.jl @@ -8,6 +8,9 @@ # methods being defined for all the `ValueCurve{FunctionData}` types, not just the ones we # have here nicely packaged and presented to the user. +"Whether there is a cost alias for the instance or type under consideration" +is_cost_alias(::Union{ValueCurve, Type{<:ValueCurve}}) = false + """ A linear input-output curve, representing a constant marginal rate. May have zero no-load cost (i.e., constant average rate) or not. @@ -18,6 +21,8 @@ cost (i.e., constant average rate) or not. """ const LinearCurve = InputOutputCurve{LinearFunctionData} +is_cost_alias(::Union{LinearCurve, Type{LinearCurve}}) = true + InputOutputCurve{LinearFunctionData}(proportional_term::Real) = InputOutputCurve(LinearFunctionData(proportional_term)) @@ -40,6 +45,8 @@ A quadratic input-output curve, may have nonzero no-load cost. """ const QuadraticCurve = InputOutputCurve{QuadraticFunctionData} +is_cost_alias(::Union{QuadraticCurve, Type{QuadraticCurve}}) = true + InputOutputCurve{QuadraticFunctionData}(quadratic_term, proportional_term, constant_term) = InputOutputCurve( QuadraticFunctionData(quadratic_term, proportional_term, constant_term), @@ -59,6 +66,8 @@ A piecewise linear curve specified by cost values at production points. """ const PiecewisePointCurve = InputOutputCurve{PiecewiseLinearData} +is_cost_alias(::Union{PiecewisePointCurve, Type{PiecewisePointCurve}}) = true + InputOutputCurve{PiecewiseLinearData}(points::Vector) = InputOutputCurve(PiecewiseLinearData(points)) @@ -80,6 +89,8 @@ have nonzero initial value. """ const PiecewiseIncrementalCurve = IncrementalCurve{PiecewiseStepData} +is_cost_alias(::Union{PiecewiseIncrementalCurve, Type{PiecewiseIncrementalCurve}}) = true + IncrementalCurve{PiecewiseStepData}(initial_input, x_coords::Vector, slopes::Vector) = IncrementalCurve(PiecewiseStepData(x_coords, slopes), initial_input) @@ -103,6 +114,8 @@ nonzero initial value. """ const PiecewiseAverageCurve = AverageRateCurve{PiecewiseStepData} +is_cost_alias(::Union{PiecewiseAverageCurve, Type{PiecewiseAverageCurve}}) = true + AverageRateCurve{PiecewiseStepData}(initial_input, x_coords::Vector, y_coords::Vector) = AverageRateCurve(PiecewiseStepData(x_coords, y_coords), initial_input) diff --git a/test/test_cost_functions.jl b/test/test_cost_functions.jl index 9f35a7ad9b..527272adf8 100644 --- a/test/test_cost_functions.jl +++ b/test/test_cost_functions.jl @@ -9,8 +9,11 @@ AverageRateCurve(LinearFunctionData(3, 2), 1.0) @test zero(io_quadratic) == InputOutputCurve(LinearFunctionData(0, 0)) @test zero(InputOutputCurve) == InputOutputCurve(LinearFunctionData(0, 0)) + @test PSY.is_cost_alias(io_quadratic) == PSY.is_cost_alias(typeof(io_quadratic)) == true @test repr(io_quadratic) == sprint(show, io_quadratic) == - "QuadraticCurve(3.0, 2.0, 1.0)" # repr is overridden due to cost alias + "QuadraticCurve(3.0, 2.0, 1.0)" + @test sprint(show, "text/plain", io_quadratic) == + "QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 3.0 x^2 + 2.0 x + 1.0" io_linear = InputOutputCurve(LinearFunctionData(2, 1)) @test io_linear isa InputOutputCurve{LinearFunctionData} @@ -21,8 +24,11 @@ IncrementalCurve(LinearFunctionData(0, 2), 1.0) @test AverageRateCurve(io_linear) == AverageRateCurve(LinearFunctionData(0, 2), 1.0) + @test PSY.is_cost_alias(io_linear) == PSY.is_cost_alias(typeof(io_linear)) == true @test repr(io_linear) == sprint(show, io_linear) == - "LinearCurve(2.0, 1.0)" # repr is overridden due to cost alias + "LinearCurve(2.0, 1.0)" + @test sprint(show, "text/plain", io_linear) == + "LinearCurve (a type of InputOutputCurve) with function: f(x) = 2.0 x + 1.0" io_piecewise = InputOutputCurve(PiecewiseLinearData([(1, 6), (3, 9), (5, 13)])) @test io_piecewise isa InputOutputCurve{PiecewiseLinearData} @@ -32,8 +38,11 @@ IncrementalCurve(PiecewiseStepData([1, 3, 5], [1.5, 2]), 6.0) @test AverageRateCurve(io_piecewise) == AverageRateCurve(PiecewiseStepData([1, 3, 5], [3, 2.6]), 6.0) + @test PSY.is_cost_alias(io_piecewise) == PSY.is_cost_alias(typeof(io_piecewise)) == true @test repr(io_piecewise) == sprint(show, io_piecewise) == - "PiecewisePointCurve([(x = 1.0, y = 6.0), (x = 3.0, y = 9.0), (x = 5.0, y = 13.0)])" # repr is overridden due to cost alias + "PiecewisePointCurve([(x = 1.0, y = 6.0), (x = 3.0, y = 9.0), (x = 5.0, y = 13.0)])" + @test sprint(show, "text/plain", io_piecewise) == + "PiecewisePointCurve (a type of InputOutputCurve) with function: piecewise linear y = f(x) connecting points:\n (x = 1.0, y = 6.0)\n (x = 3.0, y = 9.0)\n (x = 5.0, y = 13.0)" # IncrementalCurve inc_linear = IncrementalCurve(LinearFunctionData(6, 2), 1.0) @@ -48,8 +57,11 @@ AverageRateCurve(LinearFunctionData(3, 2), 1.0) @test zero(inc_linear) == IncrementalCurve(LinearFunctionData(0, 0), 0.0) @test zero(IncrementalCurve) == IncrementalCurve(LinearFunctionData(0, 0), 0.0) + @test PSY.is_cost_alias(inc_linear) == PSY.is_cost_alias(typeof(inc_linear)) == false @test repr(inc_linear) == sprint(show, inc_linear) == "IncrementalCurve{LinearFunctionData}(LinearFunctionData(6.0, 2.0), 1.0)" + @test sprint(show, "text/plain", inc_linear) == + "IncrementalCurve where initial value is 1.0 and derivative function f is: f(x) = 6.0 x + 2.0" inc_piecewise = IncrementalCurve(PiecewiseStepData([1, 3, 5], [1.5, 2]), 6.0) @test inc_piecewise isa IncrementalCurve{PiecewiseStepData} @@ -59,8 +71,12 @@ InputOutputCurve(PiecewiseLinearData([(1, 6), (3, 9), (5, 13)])) @test AverageRateCurve(inc_piecewise) == AverageRateCurve(PiecewiseStepData([1, 3, 5], [3, 2.6]), 6.0) + @test PSY.is_cost_alias(inc_piecewise) == PSY.is_cost_alias(typeof(inc_piecewise)) == + true @test repr(inc_piecewise) == sprint(show, inc_piecewise) == - "PiecewiseIncrementalCurve(6.0, [1.0, 3.0, 5.0], [1.5, 2.0])" # repr is overridden due to cost alias + "PiecewiseIncrementalCurve(6.0, [1.0, 3.0, 5.0], [1.5, 2.0])" + @test sprint(show, "text/plain", inc_piecewise) == + "PiecewiseIncrementalCurve where initial value is 6.0 and derivative function f is: f(x) =\n 1.5 for x in [1.0, 3.0)\n 2.0 for x in [3.0, 5.0)" # AverageRateCurve ar_linear = AverageRateCurve(LinearFunctionData(3, 2), 1.0) @@ -75,8 +91,11 @@ IncrementalCurve(LinearFunctionData(6, 2), 1.0) @test zero(ar_linear) == AverageRateCurve(LinearFunctionData(0, 0), 0.0) @test zero(AverageRateCurve) == AverageRateCurve(LinearFunctionData(0, 0), 0.0) + @test PSY.is_cost_alias(ar_linear) == PSY.is_cost_alias(typeof(ar_linear)) == false @test repr(ar_linear) == sprint(show, ar_linear) == "AverageRateCurve{LinearFunctionData}(LinearFunctionData(3.0, 2.0), 1.0)" + @test sprint(show, "text/plain", ar_linear) == + "AverageRateCurve where initial value is 1.0 and average rate function f is: f(x) = 3.0 x + 2.0" ar_piecewise = AverageRateCurve(PiecewiseStepData([1, 3, 5], [3, 2.6]), 6.0) @test get_function_data(ar_piecewise) == PiecewiseStepData([1, 3, 5], [3, 2.6]) @@ -85,8 +104,11 @@ InputOutputCurve(PiecewiseLinearData([(1, 6), (3, 9), (5, 13)])) @test IncrementalCurve(ar_piecewise) == IncrementalCurve(PiecewiseStepData([1, 3, 5], [1.5, 2]), 6.0) + @test PSY.is_cost_alias(ar_piecewise) == PSY.is_cost_alias(typeof(ar_piecewise)) == true @test repr(ar_piecewise) == sprint(show, ar_piecewise) == - "PiecewiseAverageCurve(6.0, [1.0, 3.0, 5.0], [3.0, 2.6])" # repr is overridden due to cost alias + "PiecewiseAverageCurve(6.0, [1.0, 3.0, 5.0], [3.0, 2.6])" + @test sprint(show, "text/plain", ar_piecewise) == + "PiecewiseAverageCurve where initial value is 6.0 and average rate function f is: f(x) =\n 3.0 for x in [1.0, 3.0)\n 2.6 for x in [3.0, 5.0)" # Serialization round trip curves_by_type = [ # typeof() gives parameterized types From 2e1471e979a18a8dcace7d807a07b38aeb791769 Mon Sep 17 00:00:00 2001 From: GabrielKS <23368820+GabrielKS@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:04:24 -0600 Subject: [PATCH 3/5] Implement pretty-printing for `CostCurve` and `FuelCurve` --- src/models/cost_functions/variable_cost.jl | 19 +++++++++++++++++++ test/test_cost_functions.jl | 9 +++++++++ 2 files changed, 28 insertions(+) diff --git a/src/models/cost_functions/variable_cost.jl b/src/models/cost_functions/variable_cost.jl index 3a8d032893..e0dc6e0db8 100644 --- a/src/models/cost_functions/variable_cost.jl +++ b/src/models/cost_functions/variable_cost.jl @@ -94,3 +94,22 @@ Base.zero(::Union{FuelCurve, Type{FuelCurve}}) = FuelCurve(zero(ValueCurve), 0.0 "Get the fuel cost or the name of the fuel cost time series" get_fuel_cost(cost::FuelCurve) = cost.fuel_cost + +# The strategy here is to put all the short stuff on the first line, then break and let the value_curve take more space +function Base.show(io::IO, ::MIME"text/plain", curve::CostCurve) + print( + io, + "$(nameof(typeof(curve))) with power_units $(curve.power_units), vom_cost $(LinearCurve(0.0)), and value_curve:\n ", + ) + vc_printout = sprint(show, "text/plain", curve.value_curve) # Capture the value_curve `show` so we can indent it + print(io, replace(vc_printout, "\n" => "\n ")) +end + +function Base.show(io::IO, ::MIME"text/plain", curve::FuelCurve) + print( + io, + "$(nameof(typeof(curve))) with power_units $(curve.power_units), fuel_cost $(curve.fuel_cost), vom_cost $(LinearCurve(0.0)), and value_curve:\n ", + ) + vc_printout = sprint(show, "text/plain", curve.value_curve) + print(io, replace(vc_printout, "\n" => "\n ")) +end diff --git a/test/test_cost_functions.jl b/test/test_cost_functions.jl index 527272adf8..b8ae03e1a8 100644 --- a/test/test_cost_functions.jl +++ b/test/test_cost_functions.jl @@ -162,6 +162,15 @@ end @test zero(FuelCurve) == FuelCurve(InputOutputCurve(PSY.LinearFunctionData(0.0, 0.0)), 0.0) + @test repr(cc) == sprint(show, cc) == + "CostCurve{QuadraticCurve}(QuadraticCurve(1.0, 2.0, 3.0), UnitSystem.NATURAL_UNITS = 2, 0.0)" + @test repr(fc) == sprint(show, fc) == + "FuelCurve{QuadraticCurve}(QuadraticCurve(1.0, 2.0, 3.0), UnitSystem.NATURAL_UNITS = 2, 4.0, 0.0)" + @test sprint(show, "text/plain", cc) == + "CostCurve with power_units UnitSystem.NATURAL_UNITS = 2, vom_cost LinearCurve(0.0, 0.0), and value_curve:\n QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0" + @test sprint(show, "text/plain", fc) == + "FuelCurve with power_units UnitSystem.NATURAL_UNITS = 2, fuel_cost 4.0, vom_cost LinearCurve(0.0, 0.0), and value_curve:\n QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0" + @test get_power_units(cc) == UnitSystem.NATURAL_UNITS @test get_power_units(fc) == UnitSystem.NATURAL_UNITS @test get_power_units(CostCurve(zero(InputOutputCurve), UnitSystem.SYSTEM_BASE)) == From 663219c35053cdcae4123594de77bc8537b5da78 Mon Sep 17 00:00:00 2001 From: GabrielKS <23368820+GabrielKS@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:04:54 -0600 Subject: [PATCH 4/5] Revise `CostCurve`/`FuelCurve` and `OperationalCost` pretty prints --- src/models/cost_functions/variable_cost.jl | 20 ++++++++++++++++---- src/utils/print.jl | 5 +++-- test/test_cost_functions.jl | 10 ++++++++-- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/models/cost_functions/variable_cost.jl b/src/models/cost_functions/variable_cost.jl index e0dc6e0db8..ec09bca18c 100644 --- a/src/models/cost_functions/variable_cost.jl +++ b/src/models/cost_functions/variable_cost.jl @@ -95,21 +95,33 @@ Base.zero(::Union{FuelCurve, Type{FuelCurve}}) = FuelCurve(zero(ValueCurve), 0.0 "Get the fuel cost or the name of the fuel cost time series" get_fuel_cost(cost::FuelCurve) = cost.fuel_cost +Base.show(io::IO, m::MIME"text/plain", curve::ProductionVariableCost) = + (get(io, :compact, false)::Bool ? _show_compact : _show_expanded)(io, m, curve) + # The strategy here is to put all the short stuff on the first line, then break and let the value_curve take more space -function Base.show(io::IO, ::MIME"text/plain", curve::CostCurve) +function _show_compact(io::IO, ::MIME"text/plain", curve::CostCurve) print( io, - "$(nameof(typeof(curve))) with power_units $(curve.power_units), vom_cost $(LinearCurve(0.0)), and value_curve:\n ", + "$(nameof(typeof(curve))) with power_units $(curve.power_units), vom_cost $(curve.vom_cost), and value_curve:\n ", ) vc_printout = sprint(show, "text/plain", curve.value_curve) # Capture the value_curve `show` so we can indent it print(io, replace(vc_printout, "\n" => "\n ")) end -function Base.show(io::IO, ::MIME"text/plain", curve::FuelCurve) +function _show_compact(io::IO, ::MIME"text/plain", curve::FuelCurve) print( io, - "$(nameof(typeof(curve))) with power_units $(curve.power_units), fuel_cost $(curve.fuel_cost), vom_cost $(LinearCurve(0.0)), and value_curve:\n ", + "$(nameof(typeof(curve))) with power_units $(curve.power_units), fuel_cost $(curve.fuel_cost), vom_cost $(curve.vom_cost), and value_curve:\n ", ) vc_printout = sprint(show, "text/plain", curve.value_curve) print(io, replace(vc_printout, "\n" => "\n ")) end + +function _show_expanded(io::IO, ::MIME"text/plain", curve::ProductionVariableCost) + print(io, "$(nameof(typeof(curve))):") + for field_name in fieldnames(typeof(curve)) + val = getproperty(curve, field_name) + val_printout = replace(sprint(show, "text/plain", val), "\n" => "\n ") + print(io, "\n $(field_name): $val_printout") + end +end diff --git a/src/utils/print.jl b/src/utils/print.jl index e9617f1ebe..07b6d322a0 100644 --- a/src/utils/print.jl +++ b/src/utils/print.jl @@ -124,10 +124,11 @@ function Base.summary(tech::DeviceParameter) end function Base.show(io::IO, ::MIME"text/plain", data::OperationalCost) - println(io, "$(typeof(data)): ") + print(io, "$(typeof(data)): ") for field_name in fieldnames(typeof(data)) val = getproperty(data, field_name) - print(io, " $(field_name): $val\n") + val_printout = replace(sprint(show, "text/plain", val), "\n" => "\n ") + print(io, "\n $(field_name): $val_printout") end end diff --git a/test/test_cost_functions.jl b/test/test_cost_functions.jl index b8ae03e1a8..b4ef4f9b63 100644 --- a/test/test_cost_functions.jl +++ b/test/test_cost_functions.jl @@ -167,9 +167,15 @@ end @test repr(fc) == sprint(show, fc) == "FuelCurve{QuadraticCurve}(QuadraticCurve(1.0, 2.0, 3.0), UnitSystem.NATURAL_UNITS = 2, 4.0, 0.0)" @test sprint(show, "text/plain", cc) == - "CostCurve with power_units UnitSystem.NATURAL_UNITS = 2, vom_cost LinearCurve(0.0, 0.0), and value_curve:\n QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0" + sprint(show, "text/plain", cc; context = :compact => false) == + "CostCurve:\n value_curve: QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0\n power_units: UnitSystem.NATURAL_UNITS = 2\n vom_cost: 0.0" @test sprint(show, "text/plain", fc) == - "FuelCurve with power_units UnitSystem.NATURAL_UNITS = 2, fuel_cost 4.0, vom_cost LinearCurve(0.0, 0.0), and value_curve:\n QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0" + sprint(show, "text/plain", fc; context = :compact => false) == + "FuelCurve:\n value_curve: QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0\n power_units: UnitSystem.NATURAL_UNITS = 2\n fuel_cost: 4.0\n vom_cost: 0.0" + @test sprint(show, "text/plain", cc; context = :compact => true) == + "CostCurve with power_units UnitSystem.NATURAL_UNITS = 2, vom_cost 0.0, and value_curve:\n QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0" + @test sprint(show, "text/plain", fc; context = :compact => true) == + "FuelCurve with power_units UnitSystem.NATURAL_UNITS = 2, fuel_cost 4.0, vom_cost 0.0, and value_curve:\n QuadraticCurve (a type of InputOutputCurve) with function: f(x) = 1.0 x^2 + 2.0 x + 3.0" @test get_power_units(cc) == UnitSystem.NATURAL_UNITS @test get_power_units(fc) == UnitSystem.NATURAL_UNITS From 8a82a37fa3f611198ab745d380ac7ea205bea251 Mon Sep 17 00:00:00 2001 From: GabrielKS <23368820+GabrielKS@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:07:34 -0600 Subject: [PATCH 5/5] Add custom `summary` for `OperationalCost` --- src/models/cost_functions/variable_cost.jl | 7 ++++--- src/utils/print.jl | 22 +++++++++++++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/models/cost_functions/variable_cost.jl b/src/models/cost_functions/variable_cost.jl index ec09bca18c..74195fc672 100644 --- a/src/models/cost_functions/variable_cost.jl +++ b/src/models/cost_functions/variable_cost.jl @@ -104,7 +104,7 @@ function _show_compact(io::IO, ::MIME"text/plain", curve::CostCurve) io, "$(nameof(typeof(curve))) with power_units $(curve.power_units), vom_cost $(curve.vom_cost), and value_curve:\n ", ) - vc_printout = sprint(show, "text/plain", curve.value_curve) # Capture the value_curve `show` so we can indent it + vc_printout = sprint(show, "text/plain", curve.value_curve; context = io) # Capture the value_curve `show` so we can indent it print(io, replace(vc_printout, "\n" => "\n ")) end @@ -113,7 +113,7 @@ function _show_compact(io::IO, ::MIME"text/plain", curve::FuelCurve) io, "$(nameof(typeof(curve))) with power_units $(curve.power_units), fuel_cost $(curve.fuel_cost), vom_cost $(curve.vom_cost), and value_curve:\n ", ) - vc_printout = sprint(show, "text/plain", curve.value_curve) + vc_printout = sprint(show, "text/plain", curve.value_curve; context = io) print(io, replace(vc_printout, "\n" => "\n ")) end @@ -121,7 +121,8 @@ function _show_expanded(io::IO, ::MIME"text/plain", curve::ProductionVariableCos print(io, "$(nameof(typeof(curve))):") for field_name in fieldnames(typeof(curve)) val = getproperty(curve, field_name) - val_printout = replace(sprint(show, "text/plain", val), "\n" => "\n ") + val_printout = + replace(sprint(show, "text/plain", val; context = io), "\n" => "\n ") print(io, "\n $(field_name): $val_printout") end end diff --git a/src/utils/print.jl b/src/utils/print.jl index 07b6d322a0..4e971737fd 100644 --- a/src/utils/print.jl +++ b/src/utils/print.jl @@ -119,15 +119,31 @@ function show_components_table(io::IO, sys::System; kwargs...) end end -function Base.summary(tech::DeviceParameter) - return "$(typeof(tech))" +function Base.summary(io::IO, tech::DeviceParameter) + print(io, "$(typeof(tech))") +end + +function Base.summary(io::IO, data::OperationalCost) + field_msgs = [] + for field_name in fieldnames(typeof(data)) + val = getproperty(data, field_name) + # Only the most important fields + (val isa ProductionVariableCost) && + push!(field_msgs, "$(field_name): $(typeof(val))") + (val isa TimeSeriesKey) && + push!(field_msgs, "$(field_name): time series \"$(get_name(val))\"") + end + isempty(field_msgs) && return + print(io, "$(typeof(data)) composed of ") + join(io, field_msgs, ", ") end function Base.show(io::IO, ::MIME"text/plain", data::OperationalCost) print(io, "$(typeof(data)): ") for field_name in fieldnames(typeof(data)) val = getproperty(data, field_name) - val_printout = replace(sprint(show, "text/plain", val), "\n" => "\n ") + val_printout = + replace(sprint(show, "text/plain", val; context = io), "\n" => "\n ") print(io, "\n $(field_name): $val_printout") end end