Resolve applicable per-energy prices for a URPX rate plan at a given instant.
Given a coerced rate plan (urpx.coerce/coerce-rate-plan) and a
ZonedDateTime, resolve-prices returns the season, the matched TOU period
(if any), and one entry per active per-energy ledger (commodity, distribution,
public benefits, etc.). Each ledger entry carries a :tiers vector — for
block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is
surfaced so the caller can pick the active one based on cumulative usage;
for non-tiered ledgers the vector has a single entry.
Skipped:
:urpx/hasCalculationMethod is set
(recurring fixed charges like a monthly customer charge — these are
subscription-style and don't apply to instantaneous lookup).Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays, urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays booleans (both default to true when omitted). Holiday detection sources, in priority order:
:holiday? predicate in opts (highest precedence — overrides).urpx.holidays/derive-predicate.Plans without a HolidayCalendar and called without :holiday? retain the
pre-existing 'every date is a non-holiday' fallback — so brackets that
opt out of non-holidays (urpx:includeNonHolidays = false) will never match.
Resolve applicable per-energy prices for a URPX rate plan at a given instant.
Given a coerced rate plan (`urpx.coerce/coerce-rate-plan`) and a
ZonedDateTime, `resolve-prices` returns the season, the matched TOU period
(if any), and one entry per active per-energy ledger (commodity, distribution,
public benefits, etc.). Each ledger entry carries a `:tiers` vector — for
block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is
surfaced so the caller can pick the active one based on cumulative usage;
for non-tiered ledgers the vector has a single entry.
Skipped:
- PriceDefinitions whose own `:urpx/hasCalculationMethod` is set
(recurring fixed charges like a monthly customer charge — these are
subscription-style and don't apply to instantaneous lookup).
Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays,
urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the
TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays
booleans (both default to true when omitted). Holiday detection sources,
in priority order:
1. Explicit `:holiday?` predicate in opts (highest precedence — overrides).
2. The plan's embedded urpx:HolidayCalendar, derived via
`urpx.holidays/derive-predicate`.
3. Fallback: every date treated as a non-holiday.
Plans without a HolidayCalendar and called without `:holiday?` retain the
pre-existing 'every date is a non-holiday' fallback — so brackets that
opt out of non-holidays (urpx:includeNonHolidays = false) will never match.(has-energy-ledger? resolved)True if resolved carries any ledger measured in urpx:energy, which is the
precondition for marginal-unit-rate returning a number.
Ask this before calling it when sweeping a corpus. Plenty of real schedules price nothing per kWh (street lighting, fixed service charges), and for those a marginal per-kWh rate is not a small number, it is a question that does not apply.
True if `resolved` carries any ledger measured in urpx:energy, which is the precondition for `marginal-unit-rate` returning a number. Ask this before calling it when sweeping a corpus. Plenty of real schedules price nothing per kWh (street lighting, fixed service charges), and for those a marginal per-kWh rate is not a small number, it is a question that does not apply.
(marginal-unit-rate resolved)(marginal-unit-rate resolved opts)Sum the unit prices across all energy ledgers, picking the LOWEST tier in each block-tiered ledger as the marginal $/kWh at the start of a billing period.
A ledger is treated as energy iff its referenced MetricInput's urpx:measurementKind is urpx:energy. Per-meter, per-customer, per-day, or per-month service charges (urpx:profileMetricInput, or non-energy measurementKinds) are excluded — they have a different shape and don't belong in a $/kWh sum.
Useful for price signaling: when you don't know a customer's usage but want a single $/kWh number, this is the marginal rate at zero baseline usage.
REFUSES, rather than returning a number, in two cases:
a marginal tier could not be valued a nil unit price reads to a consumer as free, and for a discount that is the worst available answer an energy ledger carries mutually- these are alternatives, not exclusive price alternatives with no tiers: exactly one applies to a caller selection customer, and which one is the caller's to say
The second is why composing a PG&E plan with its vintage-PCIA modifier
needs :profile-alternatives. Taking the first of eighteen mutually
exclusive prices added an arbitrary 0.02973 to the rate; the eighteen span
0.06391/kWh, so there is no default worth inventing.
EVENT-DRIVEN PRICES ARE EXCLUDED BY DEFAULT. A Price carrying
urpx:hasDynamicPricing applies only while its event is called: a critical
peak charge is real but exceptional, capped around 50 hours a summer against
roughly 2,200 summer hours. Summing it unconditionally answered what would this cost during an event', which read as the ordinary rate. The default is now the non-event baseline, which is what a price signal means bythe next
kWh'. Unlike the alternatives above there IS a defensible default here,
because no-event-today is the ordinary state rather than an arbitrary pick.
Pass {:include-dynamic-pricing? true} for the during-event upper bound.
Either way :urpx.resolved/dynamic-pricing on the tier says which prices
are event-driven, so a caller can compute both.
Sum the unit prices across all **energy** ledgers, picking the LOWEST tier
in each block-tiered ledger as the marginal $/kWh at the start of a billing
period.
A ledger is treated as energy iff its referenced MetricInput's
urpx:measurementKind is urpx:energy. Per-meter, per-customer, per-day, or
per-month service charges (urpx:profileMetricInput, or non-energy
measurementKinds) are excluded — they have a different shape and don't
belong in a $/kWh sum.
Useful for price signaling: when you don't know a customer's usage but want
a single $/kWh number, this is the marginal rate at zero baseline usage.
REFUSES, rather than returning a number, in two cases:
a marginal tier could not be valued a nil unit price reads to a
consumer as free, and for a
discount that is the worst
available answer
an energy ledger carries mutually- these are alternatives, not
exclusive price alternatives with no tiers: exactly one applies to a
caller selection customer, and which one is the
caller's to say
The second is why composing a PG&E plan with its vintage-PCIA modifier
needs `:profile-alternatives`. Taking the first of eighteen mutually
exclusive prices added an arbitrary 0.02973 to the rate; the eighteen span
0.06391/kWh, so there is no default worth inventing.
EVENT-DRIVEN PRICES ARE EXCLUDED BY DEFAULT. A Price carrying
urpx:hasDynamicPricing applies only while its event is called: a critical
peak charge is real but exceptional, capped around 50 hours a summer against
roughly 2,200 summer hours. Summing it unconditionally answered `what would
this cost during an event', which read as the ordinary rate. The default is
now the non-event baseline, which is what a price signal means by `the next
kWh'. Unlike the alternatives above there IS a defensible default here,
because no-event-today is the ordinary state rather than an arbitrary pick.
Pass `{:include-dynamic-pricing? true}` for the during-event upper bound.
Either way `:urpx.resolved/dynamic-pricing` on the tier says which prices
are event-driven, so a caller can compute both.(measurement-kinds resolved)The set of urpx:measurementKind @ids present across resolved's ledgers.
What a caller usually wants to know, having found that a plan prices nothing per kWh, is what it DOES price in, so this answers with the kinds rather than a bare yes or no and lets a sweeping consumer route instead of merely skip.
May be empty. CPAU E-14 is the case: a street lighting schedule whose charges are all per-lamp-per-month and per-fixture-per-month, filed as recurring charges with their own CalculationMethod, which price resolution excludes. Nothing resolves, so nothing is reported, and an empty set says exactly that.
The set of urpx:measurementKind @ids present across `resolved`'s ledgers. What a caller usually wants to know, having found that a plan prices nothing per kWh, is what it DOES price in, so this answers with the kinds rather than a bare yes or no and lets a sweeping consumer route instead of merely skip. May be empty. CPAU E-14 is the case: a street lighting schedule whose charges are all per-lamp-per-month and per-fixture-per-month, filed as recurring charges with their own CalculationMethod, which price resolution excludes. Nothing resolves, so nothing is reported, and an empty set says exactly that.
(resolve-modifier-prices modifier zdt)Resolve every per-energy unit price that modifier (a coerced
urpx:RatePlanModifier) contributes at zdt.
Returns the same shape as resolve-prices minus the season/TOU keys
(modifier ledgers are flat add-ons): {:urpx.resolved/ledgers [...]}.
When the modifier carries its own urpx:hasTOUSchedule, PDs with :urpx/touPeriodNumber are gated against the modifier's resolved period. Without an own TOUSchedule and no base context, every applicable Price is surfaced — matrix-style modifiers (e.g. CPAU E-HRA — 4x4 reserve level x generation tier driven by external state) rely on this so the caller can select the active value, since the URPX condition vocabulary (operator + label conditionValue) is not yet specified in a way that's programmatically interpretable. Filter the returned :tiers vector on :urpx.resolved/price-id when needed.
Resolve every per-energy unit price that `modifier` (a coerced
urpx:RatePlanModifier) contributes at `zdt`.
Returns the same shape as `resolve-prices` minus the season/TOU keys
(modifier ledgers are flat add-ons): {:urpx.resolved/ledgers [...]}.
When the modifier carries its own urpx:hasTOUSchedule, PDs with
:urpx/touPeriodNumber are gated against the modifier's resolved period.
Without an own TOUSchedule and no base context, every applicable Price
is surfaced — matrix-style modifiers (e.g. CPAU E-HRA — 4x4 reserve
level x generation tier driven by external state) rely on this so the
caller can select the active value, since the URPX condition
vocabulary (operator + label conditionValue) is not yet specified in a
way that's programmatically interpretable. Filter the returned :tiers
vector on :urpx.resolved/price-id when needed.(resolve-prices rate-plan zdt)(resolve-prices rate-plan zdt opts)Resolve all per-energy unit prices that apply to rate-plan at zdt
(a java.time.ZonedDateTime in the rate plan's local timezone).
Optional opts map:
:holiday? predicate (LocalDate -> bool) used to evaluate a bracket's
urpx:includeHolidays / urpx:includeNonHolidays gates. A plain
set of LocalDates works (sets are functions). When omitted,
a predicate is derived from the plan's embedded
urpx:HolidayCalendar via urpx.holidays/derive-predicate;
if neither is available, every date is treated as a
non-holiday — so brackets that opt out of non-holidays
(urpx:includeNonHolidays = false, e.g. holiday-only off-peak
overrides) will never match.
:profile-alternatives a {<ProfileAlternatives @id> <ProfileAlternative @id>} map driving customer-profile-driven price selection. When the rate plan declares Prices.hasPriceSetAlternatives (URPX v0.2.0 ProfileAlternatives idiom — income-tier CARE/FERA/Standard, vintage-PCIA default tier, voltage configuration, …) each PriceSetAlternatives surfaces the prices of the explicitly- chosen alternative. Unmapped alternatives are silently skipped — programmatic ConditionExpression evaluation against a customer profile is a future enhancement.
Examples of :holiday?:
;; Most rate plans embed urpx:HolidayCalendar — no opts needed: (resolve-prices plan zdt)
;; Static set — overrides any embedded calendar: (def us-federal-2026 #{(LocalDate/of 2026 1 1) ; New Year's Day (LocalDate/of 2026 1 19) ; Martin Luther King Jr. Day (LocalDate/of 2026 2 16) ; Presidents Day (LocalDate/of 2026 5 25) ; Memorial Day (LocalDate/of 2026 6 19) ; Juneteenth (LocalDate/of 2026 7 3) ; Independence Day (observed) (LocalDate/of 2026 9 7) ; Labor Day (LocalDate/of 2026 11 11) ; Veterans Day (LocalDate/of 2026 11 26) ; Thanksgiving (LocalDate/of 2026 12 25)}) ; Christmas (resolve-prices plan zdt {:holiday? us-federal-2026})
;; Composed predicate — if you maintain a calendar elsewhere: (resolve-prices plan zdt {:holiday? (fn [d] (calendar/observed? :us-federal d))})
Returns: {:urpx.resolved/season-name String or nil :urpx.resolved/tou-period-name String or nil :urpx.resolved/tou-period-number int or nil :urpx.resolved/ledgers [LedgerResult]}
where each LedgerResult is: {:urpx.resolved/ledger-id String :urpx.resolved/ledger-name String :urpx.resolved/ledger-type Ref :urpx.resolved/metric-input-id String (when the ledger references one) :urpx.resolved/metric-input-type Ref (e.g. urpx:measuredMetricInput) :urpx.resolved/measurement-kind Ref (e.g. urpx:energy — present when the MetricInput carries one; marginal-unit-rate filters on this) :urpx.resolved/unit-of-measure Ref (e.g. urpx:kWh) :urpx.resolved/tiers [TierResult]}
and each TierResult is: {:urpx.resolved/price-definition-id String :urpx.resolved/price-id String :urpx.resolved/price-name String :urpx.resolved/unit-price BigDecimal :urpx.resolved/tier-number int (only on block-tiered ledgers) :urpx.resolved/tier-name String :urpx.resolved/tier-lower-bound BigDecimal :urpx.resolved/tier-upper-bound BigDecimal :urpx.resolved/tier-lower-bound-operator Ref :urpx.resolved/tier-upper-bound-operator Ref :urpx.resolved/dynamic-pricing Map (present iff the source Price carries urpx:hasDynamicPricing — a CPP Event Charge, RTP price, or other event-driven component; consumers that need a non-event marginal rate filter on the absence of this key)}
For non-tiered ledgers, :tiers has a single entry with no tier-* keys. For block-tiered ledgers (e.g. CPAU E-1), :tiers carries every tier sorted by tier-number — the caller chooses based on cumulative billing-period usage.
Resolve all per-energy unit prices that apply to `rate-plan` at `zdt`
(a java.time.ZonedDateTime in the rate plan's local timezone).
Optional `opts` map:
:holiday? predicate `(LocalDate -> bool)` used to evaluate a bracket's
urpx:includeHolidays / urpx:includeNonHolidays gates. A plain
set of LocalDates works (sets are functions). When omitted,
a predicate is derived from the plan's embedded
urpx:HolidayCalendar via `urpx.holidays/derive-predicate`;
if neither is available, every date is treated as a
non-holiday — so brackets that opt out of non-holidays
(urpx:includeNonHolidays = false, e.g. holiday-only off-peak
overrides) will never match.
:profile-alternatives a {<ProfileAlternatives @id> <ProfileAlternative @id>}
map driving customer-profile-driven price selection. When the
rate plan declares Prices.hasPriceSetAlternatives (URPX v0.2.0
ProfileAlternatives idiom — income-tier CARE/FERA/Standard,
vintage-PCIA default tier, voltage configuration, …) each
PriceSetAlternatives surfaces the prices of the explicitly-
chosen alternative. Unmapped alternatives are silently skipped
— programmatic ConditionExpression evaluation against a
customer profile is a future enhancement.
Examples of `:holiday?`:
;; Most rate plans embed urpx:HolidayCalendar — no opts needed:
(resolve-prices plan zdt)
;; Static set — overrides any embedded calendar:
(def us-federal-2026
#{(LocalDate/of 2026 1 1) ; New Year's Day
(LocalDate/of 2026 1 19) ; Martin Luther King Jr. Day
(LocalDate/of 2026 2 16) ; Presidents Day
(LocalDate/of 2026 5 25) ; Memorial Day
(LocalDate/of 2026 6 19) ; Juneteenth
(LocalDate/of 2026 7 3) ; Independence Day (observed)
(LocalDate/of 2026 9 7) ; Labor Day
(LocalDate/of 2026 11 11) ; Veterans Day
(LocalDate/of 2026 11 26) ; Thanksgiving
(LocalDate/of 2026 12 25)}) ; Christmas
(resolve-prices plan zdt {:holiday? us-federal-2026})
;; Composed predicate — if you maintain a calendar elsewhere:
(resolve-prices plan zdt {:holiday? (fn [d] (calendar/observed? :us-federal d))})
Returns:
{:urpx.resolved/season-name String or nil
:urpx.resolved/tou-period-name String or nil
:urpx.resolved/tou-period-number int or nil
:urpx.resolved/ledgers [LedgerResult]}
where each LedgerResult is:
{:urpx.resolved/ledger-id String
:urpx.resolved/ledger-name String
:urpx.resolved/ledger-type Ref
:urpx.resolved/metric-input-id String (when the ledger references one)
:urpx.resolved/metric-input-type Ref (e.g. urpx:measuredMetricInput)
:urpx.resolved/measurement-kind Ref (e.g. urpx:energy — present when
the MetricInput carries one;
marginal-unit-rate filters on this)
:urpx.resolved/unit-of-measure Ref (e.g. urpx:kWh)
:urpx.resolved/tiers [TierResult]}
and each TierResult is:
{:urpx.resolved/price-definition-id String
:urpx.resolved/price-id String
:urpx.resolved/price-name String
:urpx.resolved/unit-price BigDecimal
:urpx.resolved/tier-number int (only on block-tiered ledgers)
:urpx.resolved/tier-name String
:urpx.resolved/tier-lower-bound BigDecimal
:urpx.resolved/tier-upper-bound BigDecimal
:urpx.resolved/tier-lower-bound-operator Ref
:urpx.resolved/tier-upper-bound-operator Ref
:urpx.resolved/dynamic-pricing Map (present iff the source Price
carries urpx:hasDynamicPricing
— a CPP Event Charge, RTP
price, or other event-driven
component; consumers that
need a non-event marginal
rate filter on the absence
of this key)}
For non-tiered ledgers, :tiers has a single entry with no tier-* keys.
For block-tiered ledgers (e.g. CPAU E-1), :tiers carries every tier sorted
by tier-number — the caller chooses based on cumulative billing-period usage.(resolve-prices-with-modifiers rate-plan modifiers zdt)(resolve-prices-with-modifiers rate-plan modifiers zdt opts)Resolve prices for rate-plan at zdt and append ledger results for
each modifier in modifiers whose :urpx/applicableToRatePlan list
includes the base plan's @id. Modifiers whose target lists don't include
the plan are silently skipped.
Returns the resolve-prices shape with :urpx.resolved/ledgers extended
by the modifier ledgers.
Resolve prices for `rate-plan` at `zdt` and append ledger results for each modifier in `modifiers` whose :urpx/applicableToRatePlan list includes the base plan's @id. Modifiers whose target lists don't include the plan are silently skipped. Returns the `resolve-prices` shape with :urpx.resolved/ledgers extended by the modifier ledgers.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |