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.