Impact assessment

Impact assessment extracts the impact of a particular sensor detecting a particular scenario. Impact can be measured using a variety of metrics such as time to detection, population impacted, or volume of contaminant released before detection. Additionally, these impact metrics can be used to define when a sensor covers a particular scenario for use in coverage-based optimization formulations.

The chama.impact module converts information about the signal and sensors, described in the Simulation and Sensor technology sections, into the input needed for the sensor placement optimization formulations described in the Optimization section. Impact assessment starts by extracting the times when each sensor detects a scenario. After that, detection times can be converted into other impact metrics used in the Impact Formulation or coverage-based formats used in the Coverage Formulation.

Extract detection times

The ability for a sensor to detect a scenario depends on several factors, including the scenario environmental conditions, sensor location, and sensor operating parameters. While some scenarios might be detected multiple times by a single sensor, other scenarios can go undetected by all sensors. The following example demonstrates how to extract detection times using a predefined signal, and a set of predefined sensors.

Obtain a signal DataFrame and group sensors (defined in the Sensor technology section) in a dictionary:

>>> print(signal.head())
   S1  S2    S3   T  X  Y  Z
0   0   0     0   0  1  1  1
1  10  10     0  10  1  1  1
2  20  20   200  20  1  1  1
3  30  30   600  30  1  1  1
4  40  40  1200  40  1  1  1

>>> sensors = dict()
>>> sensors['A'] = stationary_pt_sensor
>>> sensors['B'] = mobile_pt_sensor
>>> sensors['C'] = stationary_camera_sensor
>>> sensors['D'] = mobile_camera_sensor

Extract detection times:

>>> det_times = chama.impact.extract_detection_times(signal, sensors)
>>> print(det_times)
  Scenario Sensor   Detection Times
0       S1      A              [30]
1       S1      B              [30]
2       S1      C  [10, 20, 30, 40]
3       S2      A      [10, 20, 30]
4       S2      B          [20, 30]
5       S2      C  [10, 20, 30, 40]
6       S3      A          [20, 30]
7       S3      B          [20, 30]
8       S3      C      [20, 30, 40]

The example shows that Scenario S1 was detected by Sensor A at time 30 (units of time depend on the simulation). Scenario S1 was also detected by Sensor B and time 30 and Sensor C at times 10, 20, 30 and 40. Scenario S2 was detected by Sensors A, B, and C. Scenario S3 was detected by Sensors A, B, and C. Sensor D did not detect any scenarios.

The detection times DataFrame can be converted into the required input format for the Impact Formulation or Coverage Formulation as described below.

Convert detection times to input for the Impact Formulation

The Impact Formulation requires as input a DataFrame with three columns: ‘Scenario’, ‘Sensor’, and ‘Impact’, where the ‘Impact’ is a single numerical value for each row. This means that the list of detection times in the DataFrame produced above must be reduced to a single numerical value representing the impact to be minimized.

Minimum detection time

The example below shows how to build an input DataFrame for the Impact Formulation to optimize a sensor layout that minimizes detection time.

Extract detection time statistics:

>>> det_time_stats = chama.impact.detection_time_stats(det_times)
>>> print(det_time_stats)
  Scenario Sensor  Min  Mean  Median  Max  Count
0       S1      A   30  30.0    30.0   30      1
1       S1      B   30  30.0    30.0   30      1
2       S1      C   10  25.0    25.0   40      4
3       S2      A   10  20.0    20.0   30      3
4       S2      B   20  25.0    25.0   30      2
5       S2      C   10  25.0    25.0   40      4
6       S3      A   20  25.0    25.0   30      2
7       S3      B   20  25.0    25.0   30      2
8       S3      C   20  30.0    30.0   40      3

Extract the minimum detection time from the statistics computed above:

>>> min_det_time = det_time_stats[['Scenario','Sensor','Min']]
>>> min_det_time = min_det_time.rename(columns={'Min':'Impact'})
>>> print(min_det_time)
  Scenario Sensor  Impact
0       S1      A      30
1       S1      B      30
2       S1      C      10
3       S2      A      10
4       S2      B      20
5       S2      C      10
6       S3      A      20
7       S3      B      20
8       S3      C      20

Other impact metrics

Depending on the information available from the simulation, detection time can be converted to other measures of impact, such as damage cost, extent of contamination, or ability to protect critical assets and populations. For example, if the cost of detecting scenario S1 at time 30 is $80,000, then the impact metric for that scenario can be translated from a detection time of 30 to a cost of $80,000. The data associated with the new impact metric is stored in a Pandas DataFrame with one column for time, ‘T’, and one column for each scenario (name specified by the user).

Example impact costs associated with each scenario and time:

>>> print(impact_cost)
    T      S1     S2      S3
0   0       0      0       0
1  10   10000   5000   15000
2  20   40000  20000   50000
3  30   80000  75000   95000
4  40  100000  90000  150000

Rename the time column in min_det_time to ‘T’:

>>> det_time = min_det_time.rename(columns={'Impact':'T'}, inplace=False)
>>> print(det_time)
  Scenario Sensor   T
0       S1      A  30
1       S1      B  30
2       S1      C  10
3       S2      A  10
4       S2      B  20
5       S2      C  10
6       S3      A  20
7       S3      B  20
8       S3      C  20

Convert minimum detection time to damage cost:

>>> impact_metric = chama.impact.detection_time_to_impact(det_time, impact_cost)
>>> print(impact_metric)
  Scenario Sensor  Impact
0       S1      A   80000
1       S1      B   80000
2       S1      C   10000
3       S2      A    5000
4       S2      B   20000
5       S2      C    5000
6       S3      A   50000
7       S3      B   50000
8       S3      C   50000

Note that the detection_time_to_impact function interpolates based on time, if needed.

Convert detection times to input for the Coverage Formulation

The Coverage Formulation requires as input a DataFrame with two columns: ‘Sensor’, and ‘Coverage’, where the ‘Coverage’ is a list of entities covered by each sensor. The formulation optimizes a sensor layout that maximizes the coverage of the entities contained in this DataFrame. An entity to be covered might include scenarios, scenario-time pairs, or geographic locations.

Scenario coverage

The following example converts detection times to scenario coverage. With scenario coverage, a scenario is the entity to be covered. A scenario is considered covered by a sensor if that sensor detects that scenario at any time.

Recall the detection times DataFrame from above:

>>> print(det_times)
  Scenario Sensor   Detection Times
0       S1      A              [30]
1       S1      B              [30]
2       S1      C  [10, 20, 30, 40]
3       S2      A      [10, 20, 30]
4       S2      B          [20, 30]
5       S2      C  [10, 20, 30, 40]
6       S3      A          [20, 30]
7       S3      B          [20, 30]
8       S3      C      [20, 30, 40]

Convert detection times to scenario coverage:

>>> scenario_cov = chama.impact.detection_times_to_coverage(det_times, coverage_type='scenario')
>>> print(scenario_cov)
  Sensor      Coverage
0      A  [S1, S2, S3]
1      B  [S1, S2, S3]
2      C  [S1, S2, S3]

This example shows that sensor A covers the scenarios S1, S2, and S3. Sensors B and C also cover all three scenarios.

Scenario-time coverage

The next example converts detection times to scenario-time coverage. With scenario-time coverage, the entities to be covered are all combinations of the scenarios and the detection times. This type of coverage gives more weight to sensors that detect scenarios for longer periods of time. The same detection_times_to_coverage function can be used to convert detection times to scenario-time coverage with one major difference to the previous case. With scenario coverage the scenarios themselves become the entities to be covered. This means that if there is additional data available for the scenarios such as weights/probabilities or undetected impact, these values can be used directly in the coverage solver. With scenario-time coverage, we are essentially defining new entities/scenarios. So any data corresponding to the original scenarios must be translated to the new entities before they can be passed to the coverage solver. The detection_times_to_coverage function does this by accepting an optional ‘scenario’ keyword argument containing a DataFrame with scenario probabilities and undetected impact. These values are then propagated to the new scenario-time entities and a new DataFrame is returned with this information.

Convert detection times to scenario-time coverage and propagate scenario information to new scenario-time pairs:

>>> print(scenario)
   Probability Scenario  Undetected Impact
0         0.25       S1                100
1         0.50       S2                100
2         0.75       S3                100

>>> scen_time_cov, new_scenario = chama.impact.detection_times_to_coverage(
...                                          det_times,
...                                          coverage_type='scenario-time',
...                                          scenario=scenario)

>>> print(scen_time_cov)
  Sensor                                           Coverage
0      A  [S1-30.0, S2-10.0, S2-20.0, S2-30.0, S3-20.0, ...
1      B      [S1-30.0, S2-20.0, S2-30.0, S3-20.0, S3-30.0]
2      C  [S1-10.0, S1-20.0, S1-30.0, S1-40.0, S2-10.0, ...

>>> print(new_scenario)
   Scenario  Probability  Undetected Impact
0   S1-30.0         0.25                100
2   S1-10.0         0.25                100
3   S1-20.0         0.25                100
5   S1-40.0         0.25                100
6   S2-10.0         0.50                100
7   S2-20.0         0.50                100
8   S2-30.0         0.50                100
14  S2-40.0         0.50                100
15  S3-20.0         0.75                100
16  S3-30.0         0.75                100
21  S3-40.0         0.75                100

This example shows that sensor A covers the scenario-time pairs S1-30.0, S2-10.0, and S2-20.0 among others. In addition, notice that the probability and undetected impact for scenario S1 is propagated to all scenario-time pairs containing S1 in the new_scenario DataFrame.

Convert input for the Impact Formulation to the Coverage Formulation

Users can also convert the input DataFrame for the Impact Formulation to the input DataFrame for the Coverage Formulation. This is especially convenient in cases where the user is solving optimization problems using both solver classes and the DataFrame for the impact solver was generated outside of the standard Chama workflow (i.e. the signal, sensors, or detection_times DataFrames are unavailable). In the following example, an impact DataFrame is converted to a scenario coverage DataFrame.

Recall the impact DataFrame containing minimum detection time from above:

>>> print(min_det_time)
  Scenario Sensor  Impact
0       S1      A      30
1       S1      B      30
2       S1      C      10
3       S2      A      10
4       S2      B      20
5       S2      C      10
6       S3      A      20
7       S3      B      20
8       S3      C      20

Convert the impact DataFrame to a coverage DataFrame:

>>> scenario_cov = chama.impact.impact_to_coverage(min_det_time)
>>> print(scenario_cov)
  Sensor      Coverage
0      A  [S1, S2, S3]
1      B  [S1, S2, S3]
2      C  [S1, S2, S3]

Notice that we end up with the same scenario coverage DataFrame as before but using different input.