Average Annualised Loss (old vers) - output being overwritten?

Hi there,
I am having an issue with the results produced by my AAL pipeline. I am hoping to get this issue fixed before switching to the new trapz function as I think the issue will persist no matter which function I use.
In the case of loss in this analysis, loss=population exposure. I am exposing the total population against 20 10m increments of sea level rise, each sea level rise csv file links multiple ARI tiffs that represent the multiple ari for that slr scenario.

My issue is that the outputs, no matter the slr, are exactly the same. I have also ran single tiff files.
The result of the single tiff runs produce a different output across SLR, however, the same output between ARI. i.e. a sea level rise of 200 w/ ari 1000 has the exact output as a slr of 10 with an ari of 1000. Yet, the slr 10+ari 1000 has a different output to slr10+ari 200 [i do have this data if this is hard to follow in writing].


SLR10 vs 80

image

  • the csv file from SLR that loops through average return interval tiffs for SLR*

Therefore, I wonder if there is an issue with the way I am looking at the tiff layers as it is the last layer (ARI1000) that is being output as representing total AAL for each SLR each event?

.
.
.

~~ Beginning of Pipeline ~~

#below is to run AAE
→ join(on: true) as exposures_join_hazards
→ select({, sample(geometry: exposure, coverage: event.coverage) as hazard_sampled})
→ select({
, map(hazard_sampled, h → h.sampled) as hazard})
→ select({}) as sampled
→ select({
, hazard: max(hazard)})
→ select({, consequence: map(hazard, hv → is_exposed(exposure, hv))})
→ select({
, exceedance_probability: 1 - exp(0-(1/float(event.ari)))}) as analysis

input(relation: ‘SLR0’) as hazard_input
→ select({
{
*,
# flood is a ‘template’ bookmark - the location is replaced, but everything else stays the same
bookmark(‘flood’, {location: location}, type: ‘coverage(floating)’) as coverage
} as event
}) as hazard_and_coverage → exposures_join_hazards.rhs

#works
analysis
→ select({*})
→ group(by: {exposure.fid as Building, event.ari as ari, event.slr as slr,
},
select: {Building,
ari,
slr,
})
->save(name: ‘CHANGE Depth-table-High-SLR0’, format: ‘csv’)

analysis
→ select({*})
→ group(by: {exposure.fid as Building, exceedance_probability, event.ari, event.slr,
exposure.land_distr as district,
},
select: {Building,
district,
exceedance_probability,
ari,
slr,
max(pp_tot) as Loss})

→ sort({exceedance_probability, Building}) as aggregate_Property #removed UProperty
→ save(name: ‘Tot_pop_build-exposure-5SLR’, format: ‘csv’)

aggregate_Property
→ select({Building,
ari,
slr,
district,
float(exceedance_probability) as exceedance_probability_float,
float(Loss) as loss}) as event_loss_table

event_loss_table
→ group(by: {Building,
district,
loss},
select: {*, min(exceedance_probability_float) as exceedance_probability_min})

→ group(by: {Building,
district},
select: {
Building:Building,
district:district,
loss_curve: fit_curve(
x-value: loss,
y-value: exceedance_probability_min, #unsure if this should be _min or _float. _min is the current exacuted approach

  fitters: {'continuous'}
)

}
)
→ join(on:max.Building=Building).rhs as max_loss_join
→ select({
Building as Building,
district,
if_then_else(is_null(max.max_loss) or max.max_loss <= 0,
0.0,
trapz(
function: loss_curve.function,
a: 1.0,
# a = 1 means annual, 50 would 50 year timeframe exposure etc.
b: if_null(max.max_loss, 0.0),
#b: max.max_exposure,
intervals: 1000)
) as aal})
->save(‘Res_Build_Demograph-AAE-High-SLR0’, format: ‘csv’)

event_loss_table
→ group(
by: Building,
select: {max: {Building, max(loss) as max_loss}}
) as max
→ save(‘Res_Build_Demograph-loss-High-SLR0’, format: ‘csv’)
max → max_loss_join.lhs

Hi Abby,

I’ve read through your pipeline and it’s not clear to me how the loss (pp_tot) is being generated as there’s no reference to it prior to its use.

It might be a good sanity check to save the intermediate steps in your pipeline while debugging problems like this. Perhaps start by outputting aggregate_Property to a CSV, i.e.

aggregate_Property
 ->
save('aggregate_property', format: 'csv')

Inspect the file and see if you’re getting different losses for different SLRs at this point in the pipeline.

Cheers
Matt

Hey Matt,

Apologies, I had snipped that bit off - the missing part of the pipeline is as follows

input(‘census1’, name: ‘region1’)
→ join_total_area1.rhs

input(‘buildings’, name: ‘exposure’)

→ join(on: exposure.SA12018_V1 = region1.SA12018_V1) as join_total_area1
→ select({*, float(exposure.AREA)*float(exposure.B_Level) as house_area})

*total area = float(exposure.AREA)*float(exposure.B_Level) aggregated per census block. The aggregation of house area per census block is is done within a previous pipeline and has already been joined to the exposure layer. Not within this current pipeline.

→ select({ *,house_area/exposure.total_area as division_factor}) as population_division
→ select({ *,
if_then_else(float(region1.C18_Sex_To) >0, (float(division_factor) * float(region1.C18_Sex_To)),
float(division_factor) * int(0) ) as pp_tot}) as pp_m2

The result is a total population value per meters2 of a building. Looking at the shapefile output from this everything looks to be as I’d expect.

Hi Abby,

Thanks for clearing that up.

It seems like you’re using pp_tot across all of your buildings which may be why you’re seeing the same AAL regardless of SLR. You’ll likely want to apply pp_tot to only the buildings which are exposed. You could add something like is_exposed(exposure, hv) * pp_tot to omit the loss contribution from buildings which are unaffected.

If you’re still seeing issues after this change, would you mind showing your project.ini file and the command you’re using to run the model?

Cheers
Matt

Hi Matt,

Unfortunately, I am still having the same issue.

My project.ini is pretty basic, and I am running via Riskscape pipeline eval Pipeline_File_Name.txt
image

Thanks for your help,
Abby

Hi Abby,

Could you attach your updated pipeline after you made the is_exposed(exposure, hv) * pp_tot change?

Thanks,
Tim

Hi Tim,

The pipeline is as follows:

input(‘census1’, name: ‘region1’)
→ join_total_area1.rhs

input(‘buildings’, name: ‘exposure’)

→ join(on: exposure.SA12018_V1 = region1.SA12018_V1) as join_total_area1

→ select({*, float(exposure.AREA)*float(exposure.B_Level) as house_area})

→ select({ *,house_area/exposure.total_area as division_factor}) as population_division
→ select({ *,
#demographic and ethnicity
if_then_else(float(region1.C18_Sex_To) >0, (float(division_factor) * float(region1.C18_Sex_To)),
float(division_factor) * int(0) ) as pp_tot}) as pp_m2

#below is to run AAE
→ join(on: true) as exposures_join_hazards
→ select({, sample(geometry: exposure, coverage: event.coverage) as hazard_sampled})
→ select({
, map(hazard_sampled, h → h.sampled) as hazard})
→ select({}) as sampled
→ select({
, hazard: max(hazard)})
→ select({*, consequence: map(hazard, hv → is_exposed(exposure, hv) * pp_tot)})
→ select({*, exceedance_probability: 1 - exp(0-(1/float(event.ari)))}) as analysis

input(relation: ‘SLR200’) as hazard_input
→ select({
{
*,
# flood is a ‘template’ bookmark - the location is replaced, but everything else stays the same
bookmark(‘flood’, {location: location}, type: ‘coverage(floating)’) as coverage
} as event
}) as hazard_and_coverage → exposures_join_hazards.rhs

#works
analysis
→ select({*})
→ group(by: {exposure.fid as Building, event.ari as ari, event.slr as slr,
#exposure.land_distr as district,
#exposure.X_Coord as X_Coord,
#exposure.Y_Coord as Y_Coord,
},
select: {Building,
ari,
slr,
#district,
#exposure.X_Coord,
#exposure.Y_Coord,
})
->save(name: ‘CHANGE Depth-table-High-SLRXX’, format: ‘csv’)

analysis
→ select({*})
→ group(by: {exposure.fid as Building, exceedance_probability, event.ari, event.slr,
exposure.land_distr as district,
#exposure.X_Coord,
#exposure.Y_Coord as Y_Coord,
},
select: {Building,
district,
exceedance_probability,
ari,
slr,
#X_Coord,
#Y_Coord,
min(pp_tot) as Loss})

→ sort({exceedance_probability, Building}) as aggregate_Property #removed UProperty
→ save(name: ‘Tot_pop_build-exposure-XXSLR’, format: ‘csv’)

aggregate_Property
→ select({Building,
ari,
slr,
district,
float(exceedance_probability) as exceedance_probability_float,
float(Loss) as loss}) as event_loss_table

→ save(name: ‘aggregared_excceedence_test’, format: ‘csv’)

event_loss_table
→ group(by: {Building,
district,
loss,
slr},
select: {*, min(exceedance_probability_float) as exceedance_probability_min})

→ group(by: {Building,
district,
slr},
select: {
Building:Building,
district:district,
#slr:slr,
loss_curve: fit_curve(
x-value: loss,
y-value: exceedance_probability_min, #unsure if this should be _min or _float. _min is the current exacuted approach

  # a continuous fit doesn't do any fitting per-se, but returns a continuous function
  # using the points produced by our event loss data - this is good enough for our example
  fitters: {'continuous'}
)

}
)
→ join(on:max.Building=Building).rhs as max_loss_join
→ select({
Building as Building,
district,
if_then_else(is_null(max.max_loss) or max.max_loss <= 0,
0.0,
trapz(
function: loss_curve.function,
a: 1.0,
# a = 1 means annual, 50 would 50 year timeframe exposure etc.
b: if_null(max.max_loss, 0.0),
#b: max.max_exposure,
intervals: 1000)
) as aal})
->save(‘AAE-doubleup-TEST-ARIall-SL200’,format: ‘csv’)

event_loss_table
→ group(
by: Building,
select: {max: {Building, max(loss) as max_loss}}
) as max
→ save(‘Res_Build_Demograph-loss-High-SLRXX’, format: ‘csv’)
max → max_loss_join.lhs

Thanks again to you both for taking the time to have a look at this.

Abby

Hi Abby,

No worries at all.

Your consequence calculation should be good now, but needs to be referenced when computing the loss thereafter, i.e. min(pp_tot) as Loss should be min(consequence) as Loss.

Cheers
Matt

Hi Matt,

It makes complete sense to have the consequence there rather than pp_tot - sticks out as an issue now you’ve mentioned it.

I wonder if there may be further issues as the outputs make less sense than before. The odd number out to the side is AAL summed - just there so that i can check if there are any differences in the data, or not, at a glance.

Left = SLR 10 Right = SLr 200

Thanks again, its great to have multiple sets of eyes after a few weeks of confusion!

Cheers,
Abby

Hi Abby,

The best way to debug this sort of thing would be to see the ‘event loss table’, i.e. the loss for each individual event that’s going into the AAL. As Matt mentioned earlier, you can do this by saving outputting aggregate_Property to a CSV. You could then look at the individual losses for buildings that are producing strange results (and you could potentially cross-check the AAL manually by using numpy.trapz).

In this case, you’re not really dealing with monotonically increasing losses per-building. You’re dealing with a constant population per building (if exposed) or zero (if not exposed). So you’re going to end up with each building’s loss value always being one of only two possible values. What the AAL is doing is calculating the area under the loss/EP curve. The problem is when we plot x=loss, y=EP and the loss values are all the same, there is no area under the curve (there’s only a single ‘x’ point, so it’s just a vertical line), so the AAL ends up being zero.

So what you could do here is flip the x,y values being plotted, so it ends up being x=EP, y=loss. (We’ve actually got changes coming in the next release to do this by default, and make this whole process a bit simpler)

So where you’ve currently got steps in your pipeline like this:

-> group(by: {Building, district, loss},
        select: {*, min(exceedance_probability_float) as exceedance_probability_min})
-> group(by: {Building, district},
        select: {
            Building:Building,
            district:district,
            loss_curve: fit_curve(
                x-value: loss,
                y-value: exceedance_probability_min,
              fitters: {'continuous'})
        })
-> select({
            *,
            trapz(
                function: loss_curve.function,
                a: 1.0,
                b: if_null(max.max_loss, 0.0),
                intervals: 1000) as aal
          })

you could try replacing them with just a single step:

-> group(by: {Building, district},
        select: {
            Building:Building,
            district:district,
            aal: trapz(
                       fit_curve(
                            x-value: exceedance_probability_float,
                            y-value: loss,
                            fitters: {'continuous'}
                       ).function,
                       a: 0.0,
                       b: max(exceedance_probability_float),
                       intervals: 1000)
        })

Hope that helps.

Tim

1 Like

Hey Tim and Matt,

The numbers produced by the pipeline are not looking as I would expect [ attached below a small subset]

I am trying the new aal_trapz function to rule out any issues there. I am getting a List:Nulling[Anything] error - I wonder if there is something that I am missing which may be causing this (to_list?) or if there are steps within the pipeline that I no longer need as the new trapz function no longer requires them?

I have tried to use the ‘to_list’ function for both the consequence and loss but they are deemed a non comparable type.

The pipeline is the same as before with the difference in trap function as below:

#below is to run AAE
→ join(on: true) as exposures_join_hazards
→ select({, sample(geometry: exposure, coverage: event.coverage) as hazard_sampled})
→ select({
, map(hazard_sampled, h → h.sampled) as hazard})
→ select({}) as sampled
→ select({
, hazard: max(hazard)})
→ select({, consequence: map(hazard, hv → is_exposed(exposure, hv) (pp_tot))})
→ select({*, exceedance_probability: 1 - exp(0-(1/float(event.ari)))}) as analysis

input(relation: ‘SLR150’) as hazard_input
#and load the tiff that’s in the location column
→ select({ {*,
#flood is a ‘template’ bookmark - the location is replaced, but everything else stays the same
bookmark(‘flood’, {location: location}, type: ‘coverage(floating)’) as coverage
} as event
}) as hazard_and_coverage → exposures_join_hazards.rhs

#works
analysis
→ select({*})
→ group(by: {exposure.fid as Building, event.ari as ari, event.slr as slr,},
select: {Building, ari, slr,})
->save(name: ‘CHANGE Depth-table-High-SLRXX’, format: ‘csv’)

analysis
→ select({*})
→ group(by: {exposure.fid as Building, exceedance_probability, event.ari, event.slr,
exposure.land_distr as district, },
select: {Building,
district, exceedance_probability, ari, slr,
#to_list(consequences) as loss_test
min(consequence) as Loss})
→ sort({exceedance_probability, Building}) as aggregate_Property #removed UProperty
→ save(name: ‘Tot_pop_build-exposure-XXSLR’, format: ‘csv’)

aggregate_Property
→ select({Building, ari, slr,district,
exceedance_probability as exceedance_probability_float,
#float(Loss) as loss,
Loss as loss}) as event_loss_table
→ save(name: ‘aggregated_excceedence_test’, format: ‘csv’)

event_loss_table
→ join(on:max.Building=Building).rhs as max_loss_join
→ select({
Building as Building, district, exceedance_probability_float,

#muted for time being to see if can move past nulling era.
#if_then_else(float(max.max_loss) <=0,
#or max.max_loss
#0.0,

aal_trapz(
loss: max.max_loss,
ep: exceedance_probability_float) as aal })
->save(‘AAE_newtrapz_SLR_150’, format: ‘csv’)

event_loss_table
→ group(
by: Building,
select: {max: {Building, max(loss) as max_loss}}
) as max

→ save(‘Res_Build_Demograph-loss-High-SLRXX’, format: ‘csv’)
max → max_loss_join.lhs

Im sure its just something simple over looked.
Again, I appreciate the help so far

Hi Abby,

Sorry, the error message is a bit confusing in this case. Basically the problem is you’re using aal_trapz in a select pipeline step instead of a group step. Your pipeline step should probably look more like this:

group(by: { Building, district },
      select: {
        *,
        aal_trapz(
            loss: consequence,
            ep: exceedance_probability_float) as aal
      })

Note that there’s a few other things in your pipeline that don’t look quite right. E.g. the whole max_loss_join part of the pipeline is no longer necessary now that you’re using aal_trapz. Your pipeline should perhaps look more like this:

#below is to run AAE
→ join(on: true) as exposures_join_hazards
→ select({, sample(geometry: exposure, coverage: event.coverage) as hazard_sampled})
→ select({, map(hazard_sampled, h → h.sampled) as hazard})
→ select({}) as sampled
→ select({, hazard: max(hazard)})
→ select({, consequence: map(hazard, hv → is_exposed(exposure, hv) * pp_tot)})
→ select({*, exceedance_probability: 1 - exp(0-(1/float(event.ari)))}) as analysis

input(relation: ‘SLR150’) as hazard_input
#and load the tiff that’s in the location column
→ select({ {*,
#flood is a ‘template’ bookmark - the location is replaced, but everything else stays the same
bookmark(‘flood’, {location: location}, type: ‘coverage(floating)’) as coverage
} as event
}) as hazard_and_coverage → exposures_join_hazards.rhs

analysis
# TODO: is it just one hazard file per ARI/SLR? If so, this step might be redundant?
→ group(by: {exposure.fid as Building, exceedance_probability, event.ari, event.slr,
exposure.land_distr as district, },
       select: {
            *,
            # TODO: maybe you want the max() here?
            min(consequence) as Loss
    }) as event_loss_table
→ sort({exceedance_probability, Building}) as aggregate_Property #removed UProperty
→ save(name: ‘Tot_pop_build-exposure-XXSLR’, format: ‘csv’)

event_loss_table
->
group(by: { Building, district },
      select: {
        *,
        aal_trapz(
            loss: Loss,
            ep: exceedance_probability) as aal
      })   
->
save(‘AAE_newtrapz_SLR_150’, format: ‘csv’)

Cheers,
Tim