Skip to content

Risk Trajectory Split 4 : Non-interpolated (Static) trajectories#1200

Open
spjuhel wants to merge 47 commits intodevelopfrom
feature/static-risk-traj
Open

Risk Trajectory Split 4 : Non-interpolated (Static) trajectories#1200
spjuhel wants to merge 47 commits intodevelopfrom
feature/static-risk-traj

Conversation

@spjuhel
Copy link
Collaborator

@spjuhel spjuhel commented Dec 18, 2025

As the Risk trajectory PR is too substantial, this is a fourth split.

This PR builds on PRs #1197 and #1199, introduces RiskTrajectory, the abstract basis for trajectory objects, and the concrete class StaticRiskTrajectory which aims at facilitating the computation of risk metrics over multiple Snapshot objects.

The code is split between a high level interface StaticRiskTrajectory and a low level computing class CalcRiskMetricsPoint.

RiskTrajectory

The rationale behind this class is to hold the common code for any type of risk trajectory:

  • a collection of Snapshot
  • an optional risk discount rate, and associated methods to compute NPV.
  • (abstract) access to risk metrics

CalcRiskMetricPoint

The rationale behind this class is to handle the computation and "data formatting" of different risk metrics over a collection of Snapshot, following an ImpactComputationStrategy (see PR #1199). In this case, without any interpolation, thus it is essentially a wrapper for multiple calls to ImpactCalc or equivalent in ImpactComputationStrategy.

The class contains:

  • @lazy_property properties, dictating how the foundational elements for risk metric should be computed (see below)
  • calc_<risk_metric> methods (which are the ones called by the StaticRiskTrajectory object): these make use of the above and put them in nice and tidy dataframes.

@lazy_property explained

We want to avoid recomputing when unnecessary, thus we have computed metrics and "impact data" as @lazy_property, which cache the results of the computation. For instance, calling static_traj.per_date_aai the first time computes the different required Impact objects, stores them, and then the .aai_agg for each Impact and also store them.

A subsequent call to .per_date_aai return the previously stored value.
In addition, a subsequent call to .per_date_eai will reuse computed Impact objects.

The @lazy_property decorator implements this memoization flow: it returns the cached _metric attribute if available. If not, it computes the value, stores it in _metric, and returns the result.

Attributes that would change metric results (such as the computation strategy or the return periods to compute) make use of @property to reset the cached data when their value is changed by calling _reset_impact_data.

StaticRiskTrajectory

This class is the interface with the user. It receives the list of snapshot to compute metrics for, and gives access to computed risk metrics and plots. It also handles the computation of net present values if a risk discount rate is provided.
It also uses a memoization flow for the "final" results.

PR Author Checklist

PR Reviewer Checklist

Comment on lines +125 to +132
def reusable_intensity_mat(max_intensity=HAZARD_MAX_INTENSITY):
# Choosen such that:
# - 1st event has 0 intensity
# - 2nd event has max intensity in first exposure point (defaulting to 0 value)
# - 3rd event has 1/2* of max intensity in second centroid
# - 4th event has 1/4* of max intensity everywhere
# *: So that you can double intensity of the hazard and expect double impacts
return csr_matrix(
Copy link
Member

@chahank chahank Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen with negative intensities? Probably easy to test using a negative intensity factor. Although then the reusable impact function set would need adjustments.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is beyond the scope of this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm when could this be done? Because negative intensities are valid in CLIMADA, and it would be quite problematic to break this without good reason.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have a look.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, sorry I got confused actually, my initial comment on "this is beyond this PR" applies.

This PR has absolutely no impact on how negative intensities are handled by CLIMADA, it will work the same as before, we did not modify anything related to impact computation here, everything is just a wrapper.

I do have to check if interpolation cause problems with negative value (but that's split 5 not this one).

What also might change something is the option appraisal refactoring (next big project in line) which does change the measure module, and hopefully fixes the problem mentioned by Chris in #1257.

@spjuhel
Copy link
Collaborator Author

spjuhel commented Mar 12, 2026

@chahank
I am pretty sure I addressed all comments, see the one on negative intensities and resolve if you are OK.

The failing tests are related to #1263 #1264 (and #1081) and are being addressed, and not related to this PR.

I'll merge once you greenlight me :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants