Esempio n. 1
0
    def action_checklist(self):
        """Action checklist for the itb earthquake fatality report.

        :returns: The action checklist
        :rtype: list
        """
        total_fatalities = self.total_fatalities
        total_displaced = self.total_evacuated
        rounded_displaced = format_int(population_rounding(total_displaced))
        message = m.Message(style_class='container')
        message.add(m.Heading(tr('Action checklist'), **styles.INFO_STYLE))
        checklist = m.BulletedList()
        if total_fatalities:
            checklist.add(tr(
                'Are there enough victim identification units available '
                'for %s people?') % (
                    format_int(population_rounding(total_fatalities))))
        if total_displaced:
            checklist.add(tr(
                'Are there enough shelters and relief items available for '
                '%s people?') % rounded_displaced)
        if rounded_displaced:
            checklist.add(tr(
                'If yes, where are they located and how will we '
                'distribute them?'))
        if total_displaced:
            checklist.add(tr(
                'If no, where can we obtain additional relief items '
                'from and how will we transport them?'))
        message.add(checklist)
        return message
Esempio n. 2
0
    def action_checklist(self):
        """Action checklist for the itb earthquake fatality report.

        :returns: The action checklist
        :rtype: list
        """
        total_fatalities = self.total_fatalities
        total_displaced = self.total_evacuated
        rounded_displaced = format_int(population_rounding(total_displaced))

        fields = super(ITBFatalityFunction, self).action_checklist()
        if total_fatalities:
            fields.append(tr(
                'Are there enough victim identification units available '
                'for %s people?') % (
                    format_int(population_rounding(total_fatalities))))
        if total_displaced:
            fields.append(tr(
                'Are there enough shelters and relief items available for '
                '%s people?') % rounded_displaced)
        if rounded_displaced:
            fields.append(tr(
                'If yes, where are they located and how will we '
                'distribute them?'))
        if total_displaced:
            fields.append(tr(
                'If no, where can we obtain additional relief items '
                'from and how will we transport them?'))

        return fields
Esempio n. 3
0
    def action_checklist(self):
        """Action checklist for the itb earthquake fatality report.

        :returns: The action checklist
        :rtype: list
        """
        total_fatalities = self.total_fatalities
        total_displaced = self.total_evacuated
        rounded_displaced = format_int(population_rounding(total_displaced))

        fields = super(ITBFatalityFunction, self).action_checklist()
        if total_fatalities:
            fields.append(
                tr('Are there enough victim identification units available '
                   'for %s people?') %
                (format_int(population_rounding(total_fatalities))))
        if rounded_displaced:
            fields.append(
                tr('Are there enough covered floor areas available for '
                   '%s people?') % rounded_displaced)
            fields.append(
                tr('Are there enough shelters and relief items available for '
                   '%s people?') % rounded_displaced)
            fields.append(
                tr('If yes, where are they located and how will we '
                   'distribute them?'))
            fields.append(
                tr('If no, where can we obtain additional relief items '
                   'from and how will we transport them?'))
            fields.append(
                tr('Are there enough water supply, sanitation, hygiene, food, '
                   'shelter, medicines and relief items available for %s '
                   'displaced people?') % rounded_displaced)

        return fields
Esempio n. 4
0
    def action_checklist(self):
        """Action checklist for the itb earthquake fatality report.

        :returns: The action checklist
        :rtype: list
        """
        total_fatalities = self.total_fatalities
        total_displaced = self.total_evacuated
        rounded_displaced = format_int(population_rounding(total_displaced))

        fields = super(ITBFatalityFunction, self).action_checklist()
        if total_fatalities:
            fields.append(
                tr("Are there enough victim identification units available " "for %s people?")
                % (format_int(population_rounding(total_fatalities)))
            )
        if rounded_displaced:
            fields.append(tr("Are there enough covered floor areas available for " "%s people?") % rounded_displaced)
            fields.append(
                tr("Are there enough shelters and relief items available for " "%s people?") % rounded_displaced
            )
            fields.append(tr("If yes, where are they located and how will we " "distribute them?"))
            fields.append(
                tr("If no, where can we obtain additional relief items " "from and how will we transport them?")
            )
            fields.append(
                tr(
                    "Are there enough water supply, sanitation, hygiene, food, "
                    "shelter, medicines and relief items available for %s "
                    "displaced people?"
                )
                % rounded_displaced
            )

        return fields
Esempio n. 5
0
    def action_checklist(self):
        """Action checklist for the itb earthquake fatality report.

        :returns: The action checklist
        :rtype: list
        """
        total_fatalities = self.total_fatalities
        total_displaced = self.total_evacuated
        rounded_displaced = format_int(population_rounding(total_displaced))
        message = m.Message(style_class='container')
        message.add(m.Heading(tr('Action checklist'), **styles.INFO_STYLE))
        checklist = m.BulletedList()
        if total_fatalities:
            checklist.add(tr(
                'Are there enough victim identification units available '
                'for %s people?') % (
                    format_int(population_rounding(total_fatalities))))
        if total_displaced:
            checklist.add(tr(
                'Are there enough shelters and relief items available for '
                '%s people?') % rounded_displaced)
        if rounded_displaced:
            checklist.add(tr(
                'If yes, where are they located and how will we '
                'distribute them?'))
        if total_displaced:
            checklist.add(tr(
                'If no, where can we obtain additional relief items '
                'from and how will we transport them?'))
        message.add(checklist)
        return message
    def hazard_table(self, hazard_table):
        """ Return updated hazard table.

        :param hazard_table: hazard table.
        :type hazard_table: Table

        :returns hazard_table: Updated Hazard Table
        :rtype area_name: Table
        """
        hazard_table.caption = None

        for key, value in self.hazard_levels.iteritems():

            name = self.hazard_class_mapping[key][0]
            # This skips reporting people not affected in No zone
            if key == 'wet':
                row = m.Row()
                row.add(m.Cell(tr(
                    'People within hazard field ("%s") of value "%s"')
                               % (self.hazard_class_field, name),
                               header=True))
                value = format_int(population_rounding(value))
                row.add(m.Cell(value, align='right'))
            elif key == 'dry':
                continue
            else:
                row = m.Row()
                row.add(m.Cell(name, header=True))
                value = format_int(population_rounding(value))
                row.add(m.Cell(value, align='right'))
            hazard_table.add(row)

        # Total affected population
        row = m.Row()
        row.add(m.Cell(
            tr('Total affected people'),
            header=True))
        affected = format_int(
            population_rounding(self.total_affected_population))
        row.add(m.Cell(affected, align='right'))
        hazard_table.add(row)

        # Non affected population
        row = m.Row()
        unaffected = format_int(
            population_rounding(self.unaffected_population))
        row.add(m.Cell(tr('Unaffected people'), header=True))
        row.add(m.Cell(unaffected, align='right'))
        hazard_table.add(row)

        # Total Population
        row = m.Row()
        total_population = format_int(
            population_rounding(self.total_population))
        row.add(m.Cell(tr('Total people'), header=True))
        row.add(m.Cell(total_population, align='right'))
        hazard_table.add(row)

        return hazard_table
    def hazard_table(self, hazard_table):
        """ Return updated hazard table.

        :param hazard_table: hazard table.
        :type hazard_table: Table

        :returns hazard_table: Updated Hazard Table
        :rtype area_name: Table
        """
        hazard_table.caption = None

        for key, value in self.hazard_levels.iteritems():

            name = self.hazard_class_mapping[key][0]
            # This skips reporting people not affected in No zone
            if key == 'wet':
                row = m.Row()
                row.add(
                    m.Cell(
                        tr('People within hazard field ("%s") of value "%s"') %
                        (self.hazard_class_field, name),
                        header=True))
                value = format_int(population_rounding(value))
                row.add(m.Cell(value, align='right'))
            elif key == 'dry':
                continue
            else:
                row = m.Row()
                row.add(m.Cell(name, header=True))
                value = format_int(population_rounding(value))
                row.add(m.Cell(value, align='right'))
            hazard_table.add(row)

        # Total affected population
        row = m.Row()
        row.add(m.Cell(tr('Total affected people'), header=True))
        affected = format_int(
            population_rounding(self.total_affected_population))
        row.add(m.Cell(affected, align='right'))
        hazard_table.add(row)

        # Non affected population
        row = m.Row()
        unaffected = format_int(population_rounding(
            self.unaffected_population))
        row.add(m.Cell(tr('Unaffected people'), header=True))
        row.add(m.Cell(unaffected, align='right'))
        hazard_table.add(row)

        # Total Population
        row = m.Row()
        total_population = format_int(
            population_rounding(self.total_population))
        row.add(m.Cell(tr('Total people'), header=True))
        row.add(m.Cell(total_population, align='right'))
        hazard_table.add(row)

        return hazard_table
Esempio n. 8
0
    def test_itb_earthquake_fatality_estimation(self):
        """Fatalities from ground shaking can be computed correctly using the
            ITB fatality model (Test data from Hadi Ghasemi)."""
        # Name file names for hazard level, exposure and expected fatalities
        hazard_filename = '%s/itb_test_mmi.asc' % TESTDATA
        exposure_filename = '%s/itb_test_pop.asc' % TESTDATA

        # Calculate impact using API
        hazard_layer = read_layer(hazard_filename)
        exposure_layer = read_layer(exposure_filename)

        plugin_name = 'ITB Fatality Function'
        impact_function = get_plugin(plugin_name)

        # Call calculation engine
        impact_layer = calculate_impact(layers=[hazard_layer, exposure_layer],
                                        impact_fcn=impact_function)
        impact_filename = impact_layer.get_filename()

        impact_layer = read_layer(impact_filename)
        # calculated_result = I.get_data()
        # print calculated_result.shape
        keywords = impact_layer.get_keywords()
        # print "keywords", keywords
        population = float(keywords['total_population'])
        fatalities = float(keywords['total_fatalities'])

        # Check aggregated values
        expected_population = population_rounding(85424650.0)
        msg = ('Expected population was %f, I got %f' %
               (expected_population, population))
        assert population == expected_population, msg

        expected_fatalities = population_rounding(40871.3028)
        msg = ('Expected fatalities was %f, I got %f' %
               (expected_fatalities, fatalities))

        assert numpy.allclose(fatalities, expected_fatalities,
                              rtol=1.0e-5), msg

        # Check that aggregated number of fatilites is as expected
        all_numbers = int(
            numpy.sum([
                31.8937368131, 2539.26369372, 1688.72362573, 17174.9261705,
                19436.834531
            ]))
        msg = ('Aggregated number of fatalities not as expected: %i' %
               all_numbers)
        assert all_numbers == 40871, msg

        x = population_rounding(all_numbers)
        msg = ('Did not find expected fatality value %i in summary %s' %
               (x, keywords['impact_summary']))
        assert format_int(x) in keywords['impact_summary'], msg
    def test_itb_earthquake_fatality_estimation(self):
        """Fatalities from ground shaking can be computed correctly using the
            ITB fatality model (Test data from Hadi Ghasemi)."""
        # Name file names for hazard level, exposure and expected fatalities
        hazard_filename = '%s/itb_test_mmi.asc' % TESTDATA
        exposure_filename = '%s/itb_test_pop.asc' % TESTDATA

        # Calculate impact using API
        hazard_layer = read_layer(hazard_filename)
        exposure_layer = read_layer(exposure_filename)

        plugin_name = 'ITB Fatality Function'
        impact_function = get_plugin(plugin_name)

        # Call calculation engine
        impact_layer = calculate_impact(
            layers=[hazard_layer, exposure_layer], impact_fcn=impact_function)
        impact_filename = impact_layer.get_filename()

        impact_layer = read_layer(impact_filename)
        # calculated_result = I.get_data()
        # print calculated_result.shape
        keywords = impact_layer.get_keywords()
        # print "keywords", keywords
        population = float(keywords['total_population'])
        fatalities = float(keywords['total_fatalities'])

        # Check aggregated values
        expected_population = population_rounding(85424650.0)
        msg = ('Expected population was %f, I got %f'
               % (expected_population, population))
        assert population == expected_population, msg

        expected_fatalities = population_rounding(40871.3028)
        msg = ('Expected fatalities was %f, I got %f'
               % (expected_fatalities, fatalities))

        assert numpy.allclose(fatalities, expected_fatalities,
                              rtol=1.0e-5), msg

        # Check that aggregated number of fatilites is as expected
        all_numbers = int(numpy.sum([31.8937368131,
                                     2539.26369372,
                                     1688.72362573,
                                     17174.9261705,
                                     19436.834531]))
        msg = ('Aggregated number of fatalities not as expected: %i'
               % all_numbers)
        assert all_numbers == 40871, msg

        x = population_rounding(all_numbers)
        msg = ('Did not find expected fatality value %i in summary %s'
               % (x, keywords['impact_summary']))
        assert format_int(x) in keywords['impact_summary'], msg
    def impact_summary(self):
        """Create impact summary as data.

        :returns: Impact Summary in dictionary format.
        :rtype: dict
        """
        attributes = ['category', 'value']
        fields = []

        # Breakdown by hazard level (if available)
        if len(self.impact_category_ordering):
            for category in self.impact_category_ordering:
                population_in_category = self.lookup_category(category)
                population_in_category = format_int(population_rounding(
                    population_in_category
                ))
                row = [tr(category), population_in_category]
                fields.append(row)

        # Total affected population
        row = [
            tr('Total affected population'),
            format_int(population_rounding(self.total_affected_population))
        ]
        fields.append(row)

        # Non affected population
        row = [
            tr('Unaffected population'),
            format_int(population_rounding(self.unaffected_population))
        ]
        fields.append(row)

        # Total Population
        row = [
            tr('Total population'),
            format_int(population_rounding(self.total_population))
        ]
        fields.append(row)

        # Population needing evacuation
        row = [
            tr('Population needing evacuation <sup>1</sup>'),
            format_int(population_rounding(self.total_evacuated))
        ]
        fields.append(row)

        return {
            'attributes': attributes,
            'fields': fields
        }
Esempio n. 11
0
    def generate_analysis_result_html(self):
        """Return a HTML table of the analysis result

        :return: A file path to the html file saved to disk.
        """
        message = m.Message(style_class='report')
        # Table for affected population
        table = m.Table(style_class='table table-condensed table-striped')
        row = m.Row()
        total_people = self.tr('%s') % format_int(population_rounding(
            self.impact_data.total_affected_population))
        estimates_idp = self.tr('%s') % format_int(population_rounding(
            self.impact_data.estimates_idp))
        row.add(m.Cell(
            self.tr('Total affected population (people)'), header=True))
        row.add(m.Cell(total_people, style_class="text-right"))
        table.add(row)
        row = m.Row()
        row.add(m.Cell(self.tr('Estimates of IDP (people)'), header=True))
        row.add(m.Cell(estimates_idp, style_class="text-right"))
        table.add(row)
        message.add(table)
        # Table for minimum needs
        for k, v in self.impact_data.minimum_needs.iteritems():
            section = self.tr('Relief items to be provided %s :') % k
            # text = m.Text(section)
            row = m.Row(style_class='alert-info')
            row.add(m.Cell(section, header=True, attributes='colspan=2'))
            # message.add(text)
            table = m.Table(
                header=row,
                style_class='table table-condensed table-striped')
            for e in v:
                row = m.Row()
                need_name = self.tr(e['name'])
                need_number = format_int(
                    population_rounding(e['amount']))
                need_unit = self.tr(e['unit']['abbreviation'])
                if need_unit:
                    need_string = '%s (%s)' % (need_name, need_unit)
                else:
                    need_string = need_name
                row.add(m.Cell(need_string, header=True))
                row.add(m.Cell(need_number, style_class="text-right"))
                table.add(row)
            message.add(table)

        path = self.write_html_table('impact_analysis_report.html', message)
        return path
Esempio n. 12
0
    def notes(self):
        """Notes and caveats for the IF report.

        :returns: Dicts containing notes.
        :rtype: dict
        """
        title = tr('Notes and assumptions')
        fields = [
            tr('Total population in the analysis area: %s') %
            format_int(population_rounding(self.total_population)),
            tr('<sup>1</sup>People are displaced if they experience and '
               'survive a shake level of more than 5 on the MMI scale.'),
            tr('The fatality calculation assumes that no fatalities occur for '
               'shake levels below 4 and fatality counts of less than 50 are '
               'disregarded.')
        ]
        if self.__class__ != ITBFatalityFunction:
            fields.append(tr(
                'Fatality model is from Institut Teknologi Bandung 2012.'))
            fields.append(tr(
                'Fatality model is from the Population Vulnerability '
                'Pager Model.'))
        fields.extend([
            tr('Map shows the estimation of displaced population.'),
            tr('All values are rounded up to the nearest integer in order to '
               'avoid representing human lives as fractions.'),
            tr('Population rounding is applied to all population values, '
               'which may cause discrepancies when adding values.')
        ])

        return {
            'title': title,
            'fields': fields
        }
Esempio n. 13
0
    def notes(self):
        """Notes and caveats for the IF report.

        :returns: List containing notes.
        :rtype: list
        """
        fields = [
            tr("Total population in the analysis area: %s") % format_int(population_rounding(self.total_population)),
            tr(
                "<sup>1</sup>People are displaced if they experience and "
                "survive a shake level of more than 5 on the MMI scale."
            ),
            tr(
                "The fatality calculation assumes that no fatalities occur for "
                "shake levels below 4 and fatality counts of less than 50 are "
                "disregarded."
            ),
            tr("Fatality model is from Institut Teknologi Bandung 2012."),
            tr("Map shows the estimation of displaced population."),
        ]
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 14
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        population = format_int(population_rounding(self.total_population))
        thresholds = self.parameters['thresholds'].value

        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        fields = [
            tr('Total population in the analysis area: %s') % population,
            tr('<sup>1</sup>People need evacuation if flood levels exceed '
               '%(eps).1f m.') % {'eps': thresholds[-1]},
            needs_provenance,
        ]

        if self.no_data_warning:
            fields = fields + no_data_warning
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
    def format_int(number):
        """Get the correct integer format.

        :param number: The number to format
        :type number: float or integer
        """
        return format_int(population_rounding(number))
Esempio n. 16
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        population = format_int(population_rounding(self.total_population))
        threshold = format_int(self.parameters['evacuation_percentage'].value)

        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        fields = [
            tr('Total population in the analysis area: %s') % population,
            tr('<sup>1</sup>The evacuation threshold used to determine '
               'population needing evacuation is %s%%.') % threshold,
            needs_provenance,
        ]

        if self.no_data_warning:
            fields = fields + no_data_warning
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 17
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        population = format_int(population_rounding(self.total_population))
        threshold = format_int(self.parameters['evacuation_percentage'].value)

        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        fields = [
            tr('Total population in the analysis area: %s') % population,
            tr('<sup>1</sup>The evacuation threshold used to determine '
               'population needing evacuation is %s%%.') % threshold,
            needs_provenance,
        ]

        if self.no_data_warning:
            fields = fields + no_data_warning
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
    def action_checklist(self):
        """Return the action check list section of the report.

        :return: The action check list as dict.
        :rtype: dict
        """
        title = tr('Action checklist')
        evacuated_people = format_int(
            population_rounding(self.total_affected_population))
        fields = [
            tr('Which group or population is most affected?'),
            tr('Who are the vulnerable people in the population and why?'),
            tr('How will warnings be disseminated?'),
            tr('What are people\'s likely movements?'),
            tr('What are the security factors for the affected population?'),
            tr('What are the security factors for relief responders?'),
            tr('How will we reach evacuated people?'),
            tr('What kind of food does the population normally consume?'),
            tr('What are the critical non-food items required by the affected '
               'population?'),
            tr('Are there enough water supply, sanitation, hygiene, food, '
               'shelter, medicines and relief items available for %s people?'
                % evacuated_people),
            tr('If yes, where are they located and how will we distribute '
               'them?'),
            tr('If no, where can we obtain additional relief items and how '
               'will we distribute them?'),
            tr('What are the related health risks?'),
            tr('Who are the key people responsible for coordination?')
        ]

        return {
            'title': title,
            'fields': fields
        }
Esempio n. 19
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class="container")
        message.add(m.Heading(tr("Notes and assumptions"), **styles.INFO_STYLE))
        checklist = m.BulletedList()
        population = format_int(population_rounding(self.total_population))
        checklist.add(tr("Total population in the analysis area: %s") % population)
        checklist.add(tr("<sup>1</sup>People need evacuation if they are in a " "hazard zone."))
        checklist.add(tr("Map shows population count in high, medium, and low " "hazard areas."))
        checklist.add(
            tr(
                "All values are rounded up to the nearest integer in "
                "order to avoid representing human lives as fractions."
            )
        )
        checklist.add(
            tr(
                "Population rounding is applied to all population "
                "values, which may cause discrepancies when adding values."
            )
        )
        message.add(checklist)
        return message
    def test_volcano_population_evacuation_impact(self):
        """Population impact from volcanic hazard is computed correctly."""
        # Name file names for hazard level, exposure and expected fatalities
        hazard_filename = '%s/donut.shp' % TESTDATA
        exposure_filename = ('%s/pop_merapi_clip.tif' % TESTDATA)

        # Calculate impact using API
        hazard_layer = read_layer(hazard_filename)
        exposure_layer = read_layer(exposure_filename)

        plugin_name = 'Volcano Polygon Hazard Population'
        impact_function = get_plugin(plugin_name)

        impact_layer = calculate_impact(
            layers=[hazard_layer, exposure_layer], impact_fcn=impact_function)
        impact_filename = impact_layer.get_filename()

        impact_layer = read_layer(impact_filename)

        keywords = impact_layer.get_keywords()

        # Check for expected results:
        for value in ['Merapi', 192055, 56514, 68568, 66971]:
            if isinstance(value, int):
                x = format_int(population_rounding(value))
            else:
                x = value
            summary = keywords['impact_summary']
            msg = ('Did not find expected value %s in summary %s'
                   % (x, summary))
            assert x in summary, msg
Esempio n. 21
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        if self.volcano_names:
            sorted_volcano_names = ', '.join(sorted(self.volcano_names))
        else:
            sorted_volcano_names = tr('Not specified in data')

        fields = [
            tr('Total population in the analysis area: %s') %
            format_int(population_rounding(self.total_population)),
            tr('<sup>1</sup>People need evacuation if they are within the '
               'volcanic hazard zones.'),
            tr('Volcanoes considered: %s.') % sorted_volcano_names
        ]

        if needs_provenance:
            fields.append(needs_provenance)

        if self.no_data_warning:
            fields = fields + no_data_warning

        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 22
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class='container')
        message.add(m.Heading(tr('Notes and assumptions'),
                              **styles.INFO_STYLE))
        checklist = m.BulletedList()
        population = format_int(population_rounding(self.total_population))
        checklist.add(
            tr('Total population in the analysis area: %s') % population)
        checklist.add(
            tr('<sup>1</sup>People need evacuation if they are in a '
               'hazard zone.'))
        checklist.add(
            tr('Map shows population count in high, medium, and low '
               'hazard areas.'))
        checklist.add(
            tr('All values are rounded up to the nearest integer in '
               'order to avoid representing human lives as fractions.'))
        checklist.add(
            tr('Population rounding is applied to all population '
               'values, which may cause discrepancies when adding values.'))
        message.add(checklist)
        return message
Esempio n. 23
0
    def test_volcano_population_evacuation_impact(self):
        """Population impact from volcanic hazard is computed correctly."""
        # Name file names for hazard level, exposure and expected fatalities
        hazard_filename = '%s/donut.shp' % TESTDATA
        exposure_filename = ('%s/pop_merapi_clip.tif' % TESTDATA)

        # Calculate impact using API
        hazard_layer = read_layer(hazard_filename)
        exposure_layer = read_layer(exposure_filename)

        plugin_name = 'Volcano Polygon Hazard Population'
        impact_function = get_plugin(plugin_name)

        impact_layer = calculate_impact(layers=[hazard_layer, exposure_layer],
                                        impact_fcn=impact_function)
        impact_filename = impact_layer.get_filename()

        impact_layer = read_layer(impact_filename)

        keywords = impact_layer.get_keywords()

        # Check for expected results:
        for value in ['Merapi', 192055, 56514, 68568, 66971]:
            if isinstance(value, int):
                x = format_int(population_rounding(value))
            else:
                x = value
            summary = keywords['impact_summary']
            msg = ('Did not find expected value %s in summary %s' %
                   (x, summary))
            assert x in summary, msg
Esempio n. 24
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class='container')

        message.add(
            m.Heading(tr('Notes and assumptions'), **styles.INFO_STYLE))
        checklist = m.BulletedList()
        checklist.add(tr(
            'Total population in the analysis area: %s'
            ) % population_rounding(self.total_population))
        checklist.add(tr(
            '<sup>1</sup>People need evacuation if they are in a '
            'hazard zone.'))

        if self.no_data_warning:
            checklist.add(tr(
                'The layers contained "no data" values. This missing data '
                'was carried through to the impact layer.'))
            checklist.add(tr(
                '"No data" values in the impact layer were treated as 0 '
                'when counting the affected or total population.'))
        checklist.add(tr(
            'All values are rounded up to the nearest integer in '
            'order to avoid representing human lives as fractions.'))
        checklist.add(tr(
            'Population rounding is applied to all population '
            'values, which may cause discrepancies when adding value.'))

        message.add(checklist)
        return message
Esempio n. 25
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: dict
        """
        title = tr('Notes and assumptions')
        fields = [
            tr('Total population in the analysis area: %s') %
            population_rounding(self.total_population),
            tr('<sup>1</sup>People need evacuation if they are in a hazard '
               'zone.'),
            tr('Map shows the numbers of people in high, medium, and low '
               'hazard class areas.')
        ]

        if self.no_data_warning:
            fields.append(tr(
                'The layers contained "no data" values. This missing data '
                'was carried through to the impact layer.'))
            fields.append(tr(
                '"No data" values in the impact layer were treated as 0 '
                'when counting the affected or total population.'))

        fields.extend([
            tr('All values are rounded up to the nearest integer in order to '
               'avoid representing human lives as fractions.'),
            tr('Population rounding is applied to all population values, '
               'which may cause discrepancies when adding value.')
        ])

        return {
            'title': title,
            'fields': fields
        }
Esempio n. 26
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        notes = [
            {'content': tr('Notes'), 'header': True},
            {
                'content': tr('Total population: %s') % format_int(
                    population_rounding(self.total_population))
            },
            {
                'content': tr(
                    '<sup>1</sup>People need evacuation if they are in a '
                    'hazard zone.')
            },
            {
                'content': tr(
                    'Map shows population count in high, medium, and low '
                    'hazard area.')
            },
            {
                'content': tr(
                    'All values are rounded up to the nearest integer in '
                    'order to avoid representing human lives as fractions.'),
            },
            {
                'content': tr(
                    'Population rounding is applied to all population '
                    'values, which may cause discrepancies when adding '
                    'values.')
            }
        ]
        return notes
Esempio n. 27
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class='container')

        message.add(m.Heading(tr('Notes and assumptions'),
                              **styles.INFO_STYLE))
        checklist = m.BulletedList()
        checklist.add(
            tr('Total population in the analysis area: %s') %
            population_rounding(self.total_population))
        checklist.add(
            tr('<sup>1</sup>People need evacuation if they are in a '
               'hazard zone.'))

        if self.no_data_warning:
            checklist.add(
                tr('The layers contained "no data" values. This missing data '
                   'was carried through to the impact layer.'))
            checklist.add(
                tr('"No data" values in the impact layer were treated as 0 '
                   'when counting the affected or total population.'))
        checklist.add(
            tr('All values are rounded up to the nearest integer in '
               'order to avoid representing human lives as fractions.'))
        checklist.add(
            tr('Population rounding is applied to all population '
               'values, which may cause discrepancies when adding value.'))

        message.add(checklist)
        return message
Esempio n. 28
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))
        fields = [
            tr('Map shows buildings affected in each of the volcano buffered '
               'zones.'),
            tr('Total population in the analysis area: %s') %
            population_rounding(self.total_population),
            tr('<sup>1</sup>People need evacuation if they are within the '
               'volcanic hazard zones.'),
            tr('Volcanoes considered: %s.') % self.volcano_names,
            needs_provenance
        ]

        if self.no_data_warning:
            fields = fields + no_data_warning
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 29
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        if self.volcano_names:
            sorted_volcano_names = ', '.join(sorted(self.volcano_names))
        else:
            sorted_volcano_names = tr('Not specified in data')

        fields = [
            tr('Map shows buildings affected in each of the volcano buffered '
               'zones.'),
            tr('Total population in the analysis area: %s') %
            format_int(population_rounding(self.total_population)),
            tr('<sup>1</sup>People need evacuation if they are within the '
               'volcanic hazard zones.'),
            tr('Volcanoes considered: %s.') % sorted_volcano_names,
        ]
        if needs_provenance:
            fields.append(needs_provenance)

        if self.no_data_warning:
            fields = fields + no_data_warning
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 30
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        population = format_int(population_rounding(self.total_population))
        thresholds = self.parameters['thresholds'].value

        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        fields = [
            tr('Total population in the analysis area: %s') % population,
            tr('<sup>1</sup>People need evacuation if flood levels exceed '
               '%(eps).1f m.') % {
                   'eps': thresholds[-1]
               },
            needs_provenance,
        ]

        if self.no_data_warning:
            fields = fields + no_data_warning
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 31
0
    def notes(self):
        """Notes and caveats for the IF report.

        :returns: Dicts containing notes.
        :rtype: list
        """
        fields = [
            tr('Total population in the analysis area: %s') %
            format_int(population_rounding(self.total_population)),
            tr('<sup>1</sup>People are displaced if they experience and '
               'survive a shake level of more than 5 on the MMI scale.'),
            tr('The fatality calculation assumes that no fatalities occur for '
               'shake levels below 4 and fatality counts of less than 50 are '
               'disregarded.')
        ]
        if self.__class__ != ITBFatalityFunction:
            fields.append(tr(
                'Fatality model is from Institut Teknologi Bandung 2012.'))
            fields.append(tr(
                'Fatality model is from the Population Vulnerability '
                'Pager Model.'))
        fields.extend([
            tr('Map shows the estimation of displaced population.'),
        ])
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
    def impact_summary(self):
        """The impact summary as per category

        :returns: The impact summary.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class='container')
        table = m.Table(style_class='table table-condensed table-striped')
        table.caption = None
        row = m.Row()
        row.add(m.Cell(
            tr('Population needing evacuation <sup>1</sup>'),
            header=True))
        evacuated = format_int(population_rounding(self.total_evacuated))
        row.add(m.Cell(evacuated, align='right'))
        table.add(row)
        if len(self.impact_category_ordering):
            table.add(m.Row())  # add a blank line
            row = m.Row()
            row.add(m.Cell(
                tr('Total affected population'),
                header=True))
            affected = format_int(
                population_rounding(self.total_affected_population))
            row.add(m.Cell(affected, align='right'))
            table.add(row)

            for category in self.impact_category_ordering:
                population_in_category = self.lookup_category(category)
                population_in_category = format_int(population_rounding(
                    population_in_category
                ))
                row = m.Row()
                row.add(m.Cell(tr(category), header=True))
                row.add(m.Cell(population_in_category, align='right'))
                table.add(row)

        table.add(m.Row())  # add a blank line

        row = m.Row()
        unaffected = format_int(
            population_rounding(self.unaffected_population))
        row.add(m.Cell(tr('Unaffected population'), header=True))
        row.add(m.Cell(unaffected, align='right'))
        table.add(row)
        message.add(table)
        return message
Esempio n. 33
0
    def generate_analysis_result_html(self):
        """Return a HTML table of the analysis result

        :return: A file path to the html file saved to disk.
        """
        message = m.Message(style_class='report')
        # Table for affected population
        table = m.Table(style_class='table table-condensed table-striped')
        row = m.Row()
        total_people = self.tr('%s') % format_int(
            population_rounding(self.impact_data.total_affected_population))
        estimates_idp = self.tr('%s') % format_int(
            population_rounding(self.impact_data.estimates_idp))
        row.add(
            m.Cell(self.tr('Total affected population (people)'), header=True))
        row.add(m.Cell(total_people, style_class="text-right"))
        table.add(row)
        row = m.Row()
        row.add(m.Cell(self.tr('Estimates of IDP (people)'), header=True))
        row.add(m.Cell(estimates_idp, style_class="text-right"))
        table.add(row)
        message.add(table)
        # Table for minimum needs
        for k, v in self.impact_data.minimum_needs.iteritems():
            section = self.tr('Relief items to be provided %s :') % k
            # text = m.Text(section)
            row = m.Row(style_class='alert-info')
            row.add(m.Cell(section, header=True, attributes='colspan=2'))
            # message.add(text)
            table = m.Table(header=row,
                            style_class='table table-condensed table-striped')
            for e in v:
                row = m.Row()
                need_name = self.tr(e['name'])
                need_number = format_int(population_rounding(e['amount']))
                need_unit = self.tr(e['unit']['abbreviation'])
                if need_unit:
                    need_string = '%s (%s)' % (need_name, need_unit)
                else:
                    need_string = need_name
                row.add(m.Cell(need_string, header=True))
                row.add(m.Cell(need_number, style_class="text-right"))
                table.add(row)
            message.add(table)

        path = self.write_html_table('impact_analysis_report.html', message)
        return path
Esempio n. 34
0
    def action_checklist(self):
        """Action checklist for the itb earthquake fatality report.

        :returns: The action checklist
        :rtype: list
        """
        total_fatalities = self.total_fatalities
        total_displaced = self.total_evacuated
        checklist = [
            {
                'content': tr('Action checklist'),
                'header': True
            },
            {
                'content': tr(
                    'Are there enough victim identification units available '
                    'for %s people?') % (
                        population_rounding(total_fatalities)),
                'condition': total_fatalities
            },
            {
                'content': tr(
                    'Are there enough shelters and relief items available for '
                    '%s people?') % (population_rounding(total_displaced)),
                'condition': total_displaced

            },
            {
                'content': tr(
                    'If yes, where are they located and how will we '
                    'distribute them?'),
                'condition': total_displaced

            },
            {
                'content': tr(
                    'If no, where can we obtain additional relief items '
                    'from and how will we transport them?'),
                'condition': total_displaced

            },

        ]
        return checklist
    def impact_summary(self):
        """The impact summary as per category

        :returns: The impact summary.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class='container')
        table = m.Table(style_class='table table-condensed table-striped')
        table.caption = None
        row = m.Row()
        row.add(
            m.Cell(tr('Population needing evacuation <sup>1</sup>'),
                   header=True))
        evacuated = format_int(population_rounding(self.total_evacuated))
        row.add(m.Cell(evacuated, align='right'))
        table.add(row)
        if len(self.impact_category_ordering):
            table.add(m.Row())  # add a blank line
            row = m.Row()
            row.add(m.Cell(tr('Total affected population'), header=True))
            affected = format_int(
                population_rounding(self.total_affected_population))
            row.add(m.Cell(affected, align='right'))
            table.add(row)

            for category in self.impact_category_ordering:
                population_in_category = self.lookup_category(category)
                population_in_category = format_int(
                    population_rounding(population_in_category))
                row = m.Row()
                row.add(m.Cell(tr(category), header=True))
                row.add(m.Cell(population_in_category, align='right'))
                table.add(row)

        table.add(m.Row())  # add a blank line

        row = m.Row()
        unaffected = format_int(population_rounding(
            self.unaffected_population))
        row.add(m.Cell(tr('Unaffected population'), header=True))
        row.add(m.Cell(unaffected, align='right'))
        table.add(row)
        message.add(table)
        return message
Esempio n. 36
0
 def notes(self):
     notes = [
         {
             'content': tr('Notes'),
             'header': True
         },
         {
             'content': tr('Total population: %s') % format_int(
                 population_rounding(self.total_population))
         },
         {
             'content': tr(
                 '<sup>1</sup>People are considered to be displaced if '
                 'they experience and survive a shake level'
                 'of more than 5 on the MMI scale.')
         },
         {
             'content': tr(
                 'The fatality calculation assumes that '
                 'no fatalities occur for shake levels below 4 '
                 'and fatality counts of less than 50 are '
                 'disregarded.')
         },
         {
             'content': tr(
                 'Fatality model is from Institut Teknologi Bandung 2012.'),
             'condition': self.__class__ == ITBFatalityFunction
         },
         {
             'content': tr(
                 'Fatality model is from the '
                 'Population Vulnerability Pager Model.'),
             'condition': self.__class__ != ITBFatalityFunction
         },
         {
             'content': tr(
                 'Map shows the estimation of displaced population.')
         },
         {
             'content': tr(get_needs_provenance_value(self.parameters))
         },
         {
             'content': tr(
                 'All values are rounded up to the nearest integer in '
                 'order to avoid representing human lives as fractions.'),
         },
         {
             'content': tr(
                 'Population rounding is applied to all population '
                 'values, which may cause discrepancies when adding '
                 'values.')
         }
     ]
     return notes
Esempio n. 37
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        notes = [
            {'content': tr('Notes'), 'header': True},
            {
                'content': tr('Total population: %s') % format_int(
                    population_rounding(self.total_population))
            },
            {
                'content': tr(
                    '<sup>1</sup>The evacuation threshold used to determine '
                    'population needing evacuation is %s%%.'),
                'arguments': format_int(
                    self.parameters['evacuation_percentage'].value)
            },
            {
                'content': tr(
                    ''
                    'are within any polygons.'),
                'condition': not self.use_affected_field
            },
            {
                'content': tr(
                    'The layers contained `no data`. This missing data was '
                    'carried through to the impact layer.'),
                'condition': self.no_data_warning
            },
            {
                'content': tr(
                    '`No data` values in the impact layer were treated as 0 '
                    'when counting the affected or total population.'),
                'condition': self.no_data_warning
            },
            {
                'content': get_needs_provenance_value(self.parameters)
            },
            {
                'content': tr(
                    'All values are rounded up to the nearest integer in '
                    'order to avoid representing human lives as fractions.'),
            },
            {
                'content': tr(
                    'Population rounding is applied to all population '
                    'values, which may cause discrepancies when adding '
                    'values.'
                )
            }
        ]
        return notes
Esempio n. 38
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        notes = [
            {
                'content': tr('Notes'),
                'header': True
            },
            {
                'content': tr('Total population: %s') % format_int(
                    population_rounding(self.total_population))
            },
            {
                'content': tr('Volcanoes considered: %s'),
                'header': True,
                'arguments': self.volcano_names
            },
            {
                'content': tr(
                    '<sup>1</sup>People need evacuation if they are within '
                    'the volcanic hazard zones.'),
            },
            {
                'content': tr(get_needs_provenance_value(self.parameters)),
            },
            {
                'content': tr(
                    'The layers contained `no data`. This missing data was '
                    'carried through to the impact layer.'),
                'condition': self.no_data_warning
            },
            {
                'content': tr(
                    '`No data` values in the impact layer were treated as 0 '
                    'when counting the affected or total population.'),
                'condition': self.no_data_warning
            },
            {
                'content': tr(
                    'All values are rounded up to the nearest integer in '
                    'order to avoid representing human lives as fractions.'),
            },
            {
                'content': tr(
                    'Population rounding is applied to all population '
                    'values, which may cause discrepancies when adding '
                    'values.')
            }
        ]
        return notes
    def impact_summary(self):
        """The impact summary as per category

        :returns: The impact summary.
        :rtype: list
        """
        impact_summary_report = [(
            {
                'content': [
                    tr('Population needing evacuation <sup>1</sup>'),
                    '%s' % population_rounding(self.total_evacuated)],
                'header': True
            })]
        if len(self.impact_category_ordering):
            impact_summary_report.append(self.blank_line)
            impact_summary_report.append({
                'content': [
                    tr('Total affected population'),
                    format_int(population_rounding(
                        self.total_affected_population))],
                'header': True
            })
            for category in self.impact_category_ordering:
                population_in_category = self.lookup_category(category)
                population_in_category = format_int(population_rounding(
                    population_in_category
                ))
                impact_summary_report.append(
                    {'content': [tr(category), population_in_category]})
        impact_summary_report.append(self.blank_line)
        impact_summary_report.append({
            'content': [
                tr('Unaffected population'),
                format_int(population_rounding(self.unaffected_population))],
            'header': True
        })
        return impact_summary_report
Esempio n. 40
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        thresholds = self.parameters['thresholds'].value
        notes = [
            {
                'content': tr('Notes'),
                'header': True
            },
            {
                'content': tr('Total population: %s') % population_rounding(
                    self.total_population)
            },
            {
                'content': tr(
                    '<sup>1</sup>People need evacuation if flood levels '
                    'exceed %(eps).1f m.') % {'eps': thresholds[-1]},
            },
            {
                'content': tr(get_needs_provenance_value(self.parameters)),
            },
            {
                'content': tr(
                    'The layers contained `no data`. This missing data was '
                    'carried through to the impact layer.'),
                'condition': self.no_data_warning
            },
            {
                'content': tr(
                    '`No data` values in the impact layer were treated as 0 '
                    'when counting the affected or total population.'),
                'condition': self.no_data_warning
            },
            {
                'content': tr(
                    'All values are rounded up to the nearest integer in '
                    'order to avoid representing human lives as fractions.'),
            },
            {
                'content': tr(
                    'Population rounding is applied to all population '
                    'values, which may cause discrepancies when adding '
                    'values.')
            }
        ]
        return notes
Esempio n. 41
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        notes = [

            {'content': tr('Notes'), 'header': True},
            {
                'content': tr('Total population: %s') % format_int(
                    population_rounding(self.total_population))
            },
            {
                'content': tr(
                    '<sup>1</sup>People need evacuation if they are in a '
                    'hazard zone.')
            },
            {
                'content': tr(
                    'Map shows the numbers of people in high, medium, '
                    'and low hazard class areas.')
            },
            {
                'content': tr(
                    'The layers contained `no data`. This missing data was '
                    'carried through to the impact layer.'),
                'condition': self.no_data_warning
            },
            {
                'content': tr(
                    '`No data` values in the impact layer were treated as 0 '
                    'when counting the affected or total population.'),
                'condition': self.no_data_warning
            },
            {
                'content': tr(
                    'All values are rounded up to the nearest integer in '
                    'order to avoid representing human lives as fractions.'),
            },
            {
                'content': tr(
                    'Population rounding is applied to all population '
                    'values, which may cause discrepancies when adding '
                    'values.'
                )
            }
        ]
        return notes
Esempio n. 42
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        population = format_int(population_rounding(self.total_population))
        fields = [
            tr('The total people in the area is %s') % population,
            tr('Null values will be considered as zero.')
        ]
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 43
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        population = format_int(population_rounding(self.total_population))
        fields = [
            tr('The total people in the area is %s') % population,
            tr('Null values will be considered as zero.')
        ]
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 44
0
    def notes(self):
        """Notes and caveats for the IF report.

        :returns: List of dicts containing notes.
        :rtype: list
        """
        message = m.Message(style_class='container')
        message.add(
            m.Heading(tr('Notes and assumptions'), **styles.INFO_STYLE))

        checklist = m.BulletedList()

        checklist.add(tr(
            'Total population in the analysis area: %s'
            ) % format_int(population_rounding(self.total_population)))

        checklist.add(tr(
            '<sup>1</sup>People are displaced if '
            'they experience and survive a shake level'
            'of more than 5 on the MMI scale.'))

        checklist.add(tr(
            'The fatality calculation assumes that '
            'no fatalities occur for shake levels below 4 '
            'and fatality counts of less than 50 are '
            'disregarded.'))

        if self.__class__ != ITBFatalityFunction:
            checklist.add(tr(
                'Fatality model is from Institut Teknologi Bandung 2012.'))
            checklist.add(tr(
                'Fatality model is from the Population Vulnerability '
                'Pager Model.'))

        checklist.add(tr('Map shows the estimation of displaced population.'))

        checklist.add(tr(get_needs_provenance_value(self.parameters)))
        checklist.add(tr(
            'All values are rounded up to the nearest integer in '
            'order to avoid representing human lives as fractions.'))
        checklist.add(tr(
            'Population rounding is applied to all population '
            'values, which may cause discrepancies when adding values.'))

        message.add(checklist)
        return message
    def extra_actions(self):
        """Return population specific actions for the report.

        .. note:: Only calculated actions are implemented here, the rest
            are defined in definitions.py.

        .. versionadded:: 3.5

        :return: The action check list as list.
        :rtype: list
        """
        evacuated_people = format_int(
            population_rounding(self.total_affected_population))
        fields = [
            tr('Are there enough water supply, sanitation, hygiene, food, '
               'shelter, medicines and relief items available for %s '
               'people?' % evacuated_people)]
        return fields
Esempio n. 46
0
    def render_population_table(self):
        with open(self.working_dir_path('population_impact.json')) as f:
            population_impact_data = json.loads(f.read())

        impact_summary = population_impact_data['impact summary']['fields']

        key_mapping = {
            'Population in very low hazard zone': 'very_low',
            'Population in medium hazard zone': 'medium',
            'Population in high hazard zone': 'high',
            'Population in very high hazard zone': 'very_high',
            'Population in low hazard zone': 'low'
        }

        population_dict = {}
        for val in impact_summary:
            if val[0] in key_mapping:
                population_dict[key_mapping[val[0]]] = val[1]

        for key, val in key_mapping.iteritems():
            if val not in population_dict:
                population_dict[val] = 0
            else:
                # divide per 1000 people (unit used in the report)
                population_dict[val] /= 1000
                population_dict[val] = format_int(
                    population_rounding(population_dict[val]))

        # format:
        # {
        #     'very_low': 1,
        #     'low': 2,
        #     'medium': 3,
        #     'high': 4,
        #     'very_high': 5
        # }
        population_template = self.ash_fixtures_dir(
            'population-table.template.html')
        with open(population_template) as f:
            template = Template(f.read())
            html_string = template.render(**population_dict)

        with open(self.population_html_path, 'w') as f:
            f.write(html_string)
Esempio n. 47
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        population = format_int(population_rounding(self.total_population))
        fields = [
            tr('Total population in the analysis area: %s') % population,
            tr('<sup>1</sup>People need evacuation if they are in a hazard '
               'zone.'),
            tr('Map shows the number of people in high, medium, and low '
               'hazard zones.')
        ]
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
    def action_checklist(self):
        """Polygon Population action.

        :returns: The population breakdown report.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class='container')
        message.add(m.Heading(tr('Action checklist'), **styles.INFO_STYLE))
        population = population_rounding(sum(
            self.affected_population.values()))
        checklist = m.BulletedList()
        checklist.add(tr('Which group or people is most affected?'))
        checklist.add(
            tr('Who are the vulnerable people in the population and why?'))
        checklist.add(tr('How will warnings be disseminated?'))
        checklist.add(tr('What are people\'s likely movements?'))
        checklist.add(
            tr('What are the security factors for the affected people?'))
        checklist.add(
            tr('What are the security factors for relief responders?'))
        checklist.add(tr('How will we reach evacuated people?'))
        checklist.add(
            tr('What kind of food does the people normally consume?'))
        checklist.add(
            tr('What are the critical non-food items required by the affected '
               'people?'))
        checklist.add(
            tr('Are there enough water supply, sanitation, hygiene, food, '
               'shelter, medicines and relief items available for %s people?' %
               format_int(population)))

        checklist.add(
            tr('If yes, where are they located and how will we distribute them?'
               ))
        checklist.add(
            tr('If no, where can we obtain additional relief items and how will '
               'we distribute them?'))
        checklist.add(tr('What are the related health risks?'))
        checklist.add(
            tr('Who are the key people responsible for coordination?'))
        message.add(checklist)

        return message
Esempio n. 49
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: safe.messaging.Message
        """
        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        message = m.Message(style_class='container')
        message.add(m.Heading(tr('Notes and assumptions'),
                              **styles.INFO_STYLE))
        checklist = m.BulletedList()
        checklist.add(
            tr('Map shows buildings affected in each of the volcano buffered '
               'zones.'))
        checklist.add(
            tr('Total population in the analysis area: %s') %
            population_rounding(self.total_population))
        checklist.add(
            tr('<sup>1</sup>People need evacuation if they are within '
               'the volcanic hazard zones.'))
        names = tr('Volcanoes considered: %s.') % self.volcano_names
        checklist.add(names)
        checklist.add(needs_provenance)
        if self.no_data_warning:
            checklist.add(
                tr('The layers contained "no data" values. This missing data '
                   'was carried through to the impact layer.'))
            checklist.add(
                tr('"No data" values in the impact layer were treated as 0 '
                   'when counting the affected or total population.'))
        checklist.add(
            tr('All values are rounded up to the nearest integer in '
               'order to avoid representing human lives as fractions.'))
        checklist.add(
            tr('Population rounding is applied to all population '
               'values, which may cause discrepancies when adding value.'))
        message.add(checklist)
        return message
    def extra_actions(self):
        """Return the action specific to polygon people exposure.

        .. note:: Only calculated actions are implemented here, the rest
            are defined in definitions.py.

        .. versionadded:: 3.5

        :return: The action check list as dict.
        :rtype: dict
        """
        population = population_rounding(sum(
            self.affected_population.values()))

        fields = [
            tr('Are there enough water supply, sanitation, hygiene, food, '
               'shelter, medicines and relief items available for %s people?' %
               format_int(population)),
        ]
        return fields
Esempio n. 51
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: list
        """
        fields = [
            tr('Total population in the analysis area: %s') %
            format_int(population_rounding(self.total_population)),
            tr('<sup>1</sup>People need evacuation if they are in a hazard '
               'zone.')
        ]

        if self.no_data_warning:
            fields = fields + no_data_warning
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 52
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: safe.messaging.Message
        """
        if get_needs_provenance_value(self.parameters) is None:
            needs_provenance = ''
        else:
            needs_provenance = tr(get_needs_provenance_value(self.parameters))

        message = m.Message(style_class='container')

        message.add(
            m.Heading(tr('Notes and assumptions'), **styles.INFO_STYLE))
        checklist = m.BulletedList()
        population = format_int(population_rounding(self.total_population))
        checklist.add(tr(
            'Total population in the analysis area: %s') % population)
        threshold = format_int(self.parameters['evacuation_percentage'].value)
        checklist.add(tr(
            '<sup>1</sup>The evacuation threshold used to determine '
            'population needing evacuation is %s%%.') % threshold)

        checklist.add(needs_provenance)
        if self.no_data_warning:
            checklist.add(tr(
                'The layers contained "no data" values. This missing data '
                'was carried through to the impact layer.'))
            checklist.add(tr(
                '"No data" values in the impact layer were treated as 0 '
                'when counting the affected or total population.'))
        checklist.add(tr(
            'All values are rounded up to the nearest integer in '
            'order to avoid representing human lives as fractions.'))
        checklist.add(tr(
            'Population rounding is applied to all population '
            'values, which may cause discrepancies when adding values.'))

        message.add(checklist)
        return message
Esempio n. 53
0
    def test_population_rounding(self):
        """Test for population_rounding_full function."""
        # rounding up
        for _ in range(100):
            # After choosing some random numbers the sum of the randomly
            # selected and one greater than that should be less than the
            # population rounded versions of these.
            n = random.randint(1, 1000000)
            n_pop, dummy = population_rounding_full(n)
            n1 = n + 1
            n1_pop, dummy = population_rounding_full(n1)
            self.assertGreater(n_pop + n1_pop, n + n1)

        self.assertEqual(population_rounding_full(989)[0], 990)
        self.assertEqual(population_rounding_full(991)[0], 1000)
        self.assertEqual(population_rounding_full(8888)[0], 8900)
        self.assertEqual(population_rounding_full(9888888)[0], 9889000)

        for _ in range(100):
            n = random.randint(1, 1000000)
            self.assertEqual(population_rounding(n),
                             population_rounding_full(n)[0])
Esempio n. 54
0
    def notes(self):
        """Notes and caveats for the IF report.

        :returns: List containing notes.
        :rtype: list
        """
        fields = [
            tr('Total population in the analysis area: %s') %
            format_int(population_rounding(self.total_population)),
            tr('<sup>1</sup>People are displaced if they experience and '
               'survive a shake level of more than 5 on the MMI scale.'),
            tr('The fatality calculation assumes that no fatalities occur for '
               'shake levels below 4 and fatality counts of less than 50 are '
               'disregarded.'),
            tr('Fatality model is from Institut Teknologi Bandung 2012.'),
            tr('Map shows the estimation of displaced population.')
        ]
        # include any generic exposure specific notes from definitions.py
        fields = fields + self.exposure_notes()
        # include any generic hazard specific notes from definitions.py
        fields = fields + self.hazard_notes()
        return fields
Esempio n. 55
0
    def notes(self):
        """Return the notes section of the report.

        :return: The notes that should be attached to this impact report.
        :rtype: safe.messaging.Message
        """
        message = m.Message(style_class='container')

        message.add(
            m.Heading(tr('Notes and assumptions'), **styles.INFO_STYLE))
        checklist = m.BulletedList()
        population = format_int(population_rounding(self.total_population))
        checklist.add(tr(
            'The total people in the area is %s') % population)
        checklist.add(tr(
            'All values are rounded up to the nearest integer in order to '
            'avoid representing human lives as fractions.'))
        checklist.add(tr(
            'People rounding is applied to all population values, which '
            'may cause discrepancies when adding values.'))
        checklist.add(tr('Null value will be considered as zero.'))

        message.add(checklist)
        return message
Esempio n. 56
0
    def run(self, layers=None):
        """Plugin for impact of population as derived by classified hazard.

        Input
        :param layers: List of layers expected to contain

              * hazard_layer: Raster layer of classified hazard
              * exposure_layer: Raster layer of population data

        Counts number of people exposed to each class of the hazard

        Return
          Map of population exposed to high class
          Table with number of people in each class
        """
        self.validate()
        self.prepare(layers)

        # The 3 classes
        # TODO (3.2): shouldnt these be defined in keywords rather? TS
        low_class = self.parameters['low_hazard_class']
        medium_class = self.parameters['medium_hazard_class']
        high_class = self.parameters['high_hazard_class']

        # The classes must be different to each other
        unique_classes_flag = all(x != y for x, y in list(
            itertools.combinations([low_class, medium_class, high_class], 2)))
        if not unique_classes_flag:
            raise FunctionParametersError(
                'There is hazard class that has the same value with other '
                'class. Please check the parameters.')

        # Identify hazard and exposure layers
        hazard_layer = self.hazard  # Classified Hazard
        exposure_layer = self.exposure  # Population Raster

        # Extract data as numeric arrays
        hazard_data = hazard_layer.get_data(nan=True)  # Class
        no_data_warning = False
        if has_no_data(hazard_data):
            no_data_warning = True

        # Calculate impact as population exposed to each class
        population = exposure_layer.get_data(scaling=True)

        # Get all population data that falls in each hazard class
        high_hazard_population = numpy.where(hazard_data == high_class,
                                             population, 0)
        medium_hazard_population = numpy.where(hazard_data == medium_class,
                                               population, 0)
        low_hazard_population = numpy.where(hazard_data == low_class,
                                            population, 0)
        affected_population = (high_hazard_population +
                               medium_hazard_population +
                               low_hazard_population)

        # Carry the no data values forward to the impact layer.
        affected_population = numpy.where(numpy.isnan(population), numpy.nan,
                                          affected_population)
        affected_population = numpy.where(numpy.isnan(hazard_data), numpy.nan,
                                          affected_population)

        # Count totals
        total_population = int(numpy.nansum(population))
        total_high_population = int(numpy.nansum(high_hazard_population))
        total_medium_population = int(numpy.nansum(medium_hazard_population))
        total_low_population = int(numpy.nansum(low_hazard_population))
        total_affected = int(numpy.nansum(affected_population))
        total_not_affected = total_population - total_affected

        # check for zero impact
        if total_affected == 0:
            table_body = [
                self.question,
                TableRow(
                    [tr('People affected'),
                     '%s' % format_int(total_affected)],
                    header=True)
            ]
            message = Table(table_body).toNewlineFreeString()
            raise ZeroImpactException(message)

        minimum_needs = [
            parameter.serialize()
            for parameter in self.parameters['minimum needs']
        ]

        table_body, total_needs = self._tabulate(
            population_rounding(total_high_population),
            population_rounding(total_low_population),
            population_rounding(total_medium_population), minimum_needs,
            population_rounding(total_not_affected), self.question,
            population_rounding(total_affected))

        impact_table = Table(table_body).toNewlineFreeString()

        table_body = self._tabulate_action_checklist(
            table_body, population_rounding(total_population), no_data_warning)
        impact_summary = Table(table_body).toNewlineFreeString()

        # Create style
        colours = [
            '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600',
            '#FF0000', '#7A0000'
        ]
        classes = create_classes(affected_population.flat[:], len(colours))
        interval_classes = humanize_class(classes)
        style_classes = []

        for i in xrange(len(colours)):
            style_class = dict()
            if i == 1:
                label = create_label(
                    interval_classes[i],
                    tr('Low Population [%i people/cell]' % classes[i]))
            elif i == 4:
                label = create_label(
                    interval_classes[i],
                    tr('Medium Population [%i people/cell]' % classes[i]))
            elif i == 7:
                label = create_label(
                    interval_classes[i],
                    tr('High Population [%i people/cell]' % classes[i]))
            else:
                label = create_label(interval_classes[i])
            style_class['label'] = label
            style_class['quantity'] = classes[i]
            if i == 0:
                transparency = 100
            else:
                transparency = 0
            style_class['transparency'] = transparency
            style_class['colour'] = colours[i]
            style_classes.append(style_class)

        style_info = dict(target_field=None,
                          style_classes=style_classes,
                          style_type='rasterStyle')

        # For printing map purpose
        map_title = tr('Population affected by each class')
        legend_notes = tr('Thousand separator is represented by %s' %
                          get_thousand_separator())
        legend_units = tr('(people per cell)')
        legend_title = tr('Number of People')

        # Create raster object and return
        raster_layer = Raster(
            data=affected_population,
            projection=exposure_layer.get_projection(),
            geotransform=exposure_layer.get_geotransform(),
            name=tr('Population which %s') %
            (self.impact_function_manager.get_function_title(self).lower()),
            keywords={
                'impact_summary': impact_summary,
                'impact_table': impact_table,
                'map_title': map_title,
                'legend_notes': legend_notes,
                'legend_units': legend_units,
                'legend_title': legend_title,
                'total_needs': total_needs
            },
            style_info=style_info)
        self._impact = raster_layer
        return raster_layer
    def run(self, layers):
        """Risk plugin for flood population evacuation.

        :param layers: List of layers expected to contain

            * hazard_layer : Vector polygon layer of flood depth
            * exposure_layer : Raster layer of population data on the same grid
                as hazard_layer

        Counts number of people exposed to areas identified as flood prone

        :returns: Map of population exposed to flooding Table with number of
            people evacuated and supplies required.
        :rtype: tuple
        """
        # Identify hazard and exposure layers
        hazard_layer = get_hazard_layer(layers)  # Flood inundation
        exposure_layer = get_exposure_layer(layers)

        question = get_question(hazard_layer.get_name(),
                                exposure_layer.get_name(), self)

        # Check that hazard is polygon type
        if not hazard_layer.is_vector:
            message = ('Input hazard %s  was not a vector layer as expected ' %
                       hazard_layer.get_name())
            raise Exception(message)

        message = (
            'Input hazard must be a polygon layer. I got %s with layer type '
            '%s' % (hazard_layer.get_name(), hazard_layer.get_geometry_name()))
        if not hazard_layer.is_polygon_data:
            raise Exception(message)

        # Run interpolation function for polygon2raster
        P = assign_hazard_values_to_exposure_data(hazard_layer,
                                                  exposure_layer,
                                                  attribute_name='population')

        # Initialise attributes of output dataset with all attributes
        # from input polygon and a population count of zero
        new_attributes = hazard_layer.get_data()
        category_title = 'affected'  # FIXME: Should come from keywords
        deprecated_category_title = 'FLOODPRONE'
        categories = {}
        for attr in new_attributes:
            attr[self.target_field] = 0
            try:
                cat = attr[category_title]
            except KeyError:
                try:
                    cat = attr['FLOODPRONE']
                    categories[cat] = 0
                except KeyError:
                    pass

        # Count affected population per polygon, per category and total
        affected_population = 0
        for attr in P.get_data():

            affected = False
            if 'affected' in attr:
                res = attr['affected']
                if res is None:
                    x = False
                else:
                    x = bool(res)
                affected = x
            elif 'FLOODPRONE' in attr:
                # If there isn't an 'affected' attribute,
                res = attr['FLOODPRONE']
                if res is not None:
                    affected = res.lower() == 'yes'
            elif 'Affected' in attr:
                # Check the default attribute assigned for points
                # covered by a polygon
                res = attr['Affected']
                if res is None:
                    x = False
                else:
                    x = res
                affected = x
            else:
                # assume that every polygon is affected (see #816)
                affected = True
                # there is no flood related attribute
                # message = ('No flood related attribute found in %s. '
                #       'I was looking for either "Flooded", "FLOODPRONE" '
                #       'or "Affected". The latter should have been '
                #       'automatically set by call to '
                #       'assign_hazard_values_to_exposure_data(). '
                #       'Sorry I can\'t help more.')
                # raise Exception(message)

            if affected:
                # Get population at this location
                pop = float(attr['population'])

                # Update population count for associated polygon
                poly_id = attr['polygon_id']
                new_attributes[poly_id][self.target_field] += pop

                # Update population count for each category
                if len(categories) > 0:
                    try:
                        cat = new_attributes[poly_id][category_title]
                    except KeyError:
                        cat = new_attributes[poly_id][
                            deprecated_category_title]
                    categories[cat] += pop

                # Update total
                affected_population += pop

        # Estimate number of people in need of evacuation
        evacuated = (affected_population *
                     self.parameters['evacuation_percentage'] / 100.0)

        affected_population, rounding = population_rounding_full(
            affected_population)

        total = int(numpy.sum(exposure_layer.get_data(nan=0, scaling=False)))

        # Don't show digits less than a 1000
        total = population_rounding(total)
        evacuated, rounding_evacuated = population_rounding_full(evacuated)

        minimum_needs = [
            parameter.serialize()
            for parameter in self.parameters['minimum needs']
        ]

        # Generate impact report for the pdf map
        table_body = [
            question,
            TableRow([
                tr('People affected'),
                '%s*' % (format_int(int(affected_population)))
            ],
                     header=True),
            TableRow([
                TableCell(tr('* Number is rounded up to the nearest %s') %
                          (rounding),
                          col_span=2)
            ]),
            TableRow([
                tr('People needing evacuation'),
                '%s*' % (format_int(int(evacuated)))
            ],
                     header=True),
            TableRow([
                TableCell(tr('* Number is rounded up to the nearest %s') %
                          (rounding_evacuated),
                          col_span=2)
            ]),
            TableRow([
                tr('Evacuation threshold'),
                '%s%%' % format_int(self.parameters['evacuation_percentage'])
            ],
                     header=True),
            TableRow(
                tr('Map shows the number of people affected in each flood prone '
                   'area')),
            TableRow(
                tr('Table below shows the weekly minimum needs for all '
                   'evacuated people'))
        ]
        total_needs = evacuated_population_needs(evacuated, minimum_needs)
        for frequency, needs in total_needs.items():
            table_body.append(
                TableRow([
                    tr('Needs should be provided %s' % frequency),
                    tr('Total')
                ],
                         header=True))
            for resource in needs:
                table_body.append(
                    TableRow([
                        tr(resource['table name']),
                        format_int(resource['amount'])
                    ]))

        impact_table = Table(table_body).toNewlineFreeString()

        table_body.append(TableRow(tr('Action Checklist:'), header=True))
        table_body.append(TableRow(tr('How will warnings be disseminated?')))
        table_body.append(TableRow(tr('How will we reach stranded people?')))
        table_body.append(TableRow(tr('Do we have enough relief items?')))
        table_body.append(
            TableRow(
                tr('If yes, where are they located and how will we distribute '
                   'them?')))
        table_body.append(
            TableRow(
                tr('If no, where can we obtain additional relief items from and '
                   'how will we transport them to here?')))

        # Extend impact report for on-screen display
        table_body.extend([
            TableRow(tr('Notes'), header=True),
            tr('Total population: %s') % format_int(total),
            tr('People need evacuation if in the area identified as '
               '"Flood Prone"'),
            tr('Minimum needs are defined in BNPB regulation 7/2008')
        ])
        impact_summary = Table(table_body).toNewlineFreeString()

        # Create style
        # Define classes for legend for flooded population counts
        colours = [
            '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600',
            '#FF0000', '#7A0000'
        ]

        population_counts = [x['population'] for x in new_attributes]
        classes = create_classes(population_counts, len(colours))
        interval_classes = humanize_class(classes)

        # Define style info for output polygons showing population counts
        style_classes = []
        for i in xrange(len(colours)):
            style_class = dict()
            style_class['label'] = create_label(interval_classes[i])
            if i == 0:
                transparency = 0
                style_class['min'] = 0
            else:
                transparency = 0
                style_class['min'] = classes[i - 1]
            style_class['transparency'] = transparency
            style_class['colour'] = colours[i]
            style_class['max'] = classes[i]
            style_classes.append(style_class)

        # Override style info with new classes and name
        style_info = dict(target_field=self.target_field,
                          style_classes=style_classes,
                          style_type='graduatedSymbol')

        # For printing map purpose
        map_title = tr('People affected by flood prone areas')
        legend_notes = tr('Thousand separator is represented by \'.\'')
        legend_units = tr('(people per polygon)')
        legend_title = tr('Population Count')

        # Create vector layer and return
        vector_layer = Vector(data=new_attributes,
                              projection=hazard_layer.get_projection(),
                              geometry=hazard_layer.get_geometry(),
                              name=tr('People affected by flood prone areas'),
                              keywords={
                                  'impact_summary': impact_summary,
                                  'impact_table': impact_table,
                                  'target_field': self.target_field,
                                  'map_title': map_title,
                                  'legend_notes': legend_notes,
                                  'legend_units': legend_units,
                                  'legend_title': legend_title,
                                  'affected_population': affected_population,
                                  'total_population': total,
                                  'total_needs': total_needs
                              },
                              style_info=style_info)
        return vector_layer
Esempio n. 58
0
    def run(self, layers):
        """Plugin for impact of population as derived by categorised hazard.

        :param layers: List of layers expected to contain

            * hazard_layer: Raster layer of categorised hazard
            * exposure_layer: Raster layer of population data

        Counts number of people exposed to each category of the hazard

        :returns:
          Map of population exposed to high category
          Table with number of people in each category
        """

        # The 3 category
        high_t = self.parameters['Categorical thresholds'][2]
        medium_t = self.parameters['Categorical thresholds'][1]
        low_t = self.parameters['Categorical thresholds'][0]

        # Identify hazard and exposure layers
        hazard_layer = get_hazard_layer(layers)  # Categorised Hazard
        exposure_layer = get_exposure_layer(layers)  # Population Raster

        question = get_question(hazard_layer.get_name(),
                                exposure_layer.get_name(), self)

        # Extract data as numeric arrays
        C = hazard_layer.get_data(nan=0.0)  # Category

        # Calculate impact as population exposed to each category
        P = exposure_layer.get_data(nan=0.0, scaling=True)
        H = numpy.where(C <= high_t, P, 0)
        M = numpy.where(C < medium_t, P, 0)
        L = numpy.where(C < low_t, P, 0)

        # Count totals
        total = int(numpy.sum(P))
        high = int(numpy.sum(H)) - int(numpy.sum(M))
        medium = int(numpy.sum(M)) - int(numpy.sum(L))
        low = int(numpy.sum(L))
        total_impact = high + medium + low

        # Don't show digits less than a 1000
        total = population_rounding(total)
        total_impact = population_rounding(total_impact)
        high = population_rounding(high)
        medium = population_rounding(medium)
        low = population_rounding(low)

        minimum_needs = [
            parameter.serialize()
            for parameter in self.parameters['minimum needs']
        ]

        # Generate impact report for the pdf map
        table_body = [
            question,
            TableRow([tr('People impacted '),
                      '%s' % format_int(total_impact)],
                     header=True),
            TableRow(
                [tr('People in high hazard area '),
                 '%s' % format_int(high)],
                header=True),
            TableRow([
                tr('People in medium hazard area '),
                '%s' % format_int(medium)
            ],
                     header=True),
            TableRow([tr('People in low hazard area'),
                      '%s' % format_int(low)],
                     header=True)
        ]

        impact_table = Table(table_body).toNewlineFreeString()

        # Extend impact report for on-screen display
        table_body.extend([
            TableRow(tr('Notes'), header=True),
            tr('Map shows population count in high or medium hazard area'),
            tr('Total population: %s') % format_int(total),
            TableRow(
                tr('Table below shows the minimum needs for all '
                   'affected people'))
        ])

        total_needs = evacuated_population_needs(total_impact, minimum_needs)
        for frequency, needs in total_needs.items():
            table_body.append(
                TableRow([
                    tr('Needs should be provided %s' % frequency),
                    tr('Total')
                ],
                         header=True))
            for resource in needs:
                table_body.append(
                    TableRow([
                        tr(resource['table name']),
                        format_int(resource['amount'])
                    ]))

        impact_summary = Table(table_body).toNewlineFreeString()
        map_title = tr('People in high hazard areas')

        # Generate 8 equidistant classes across the range of flooded population
        # 8 is the number of classes in the predefined flood population style
        # as imported
        # noinspection PyTypeChecker
        classes = numpy.linspace(numpy.nanmin(M.flat[:]),
                                 numpy.nanmax(M.flat[:]), 8)

        # Modify labels in existing flood style to show quantities
        style_classes = style_info['style_classes']

        style_classes[1]['label'] = tr('Low [%i people/cell]') % classes[1]
        style_classes[4]['label'] = tr('Medium [%i people/cell]') % classes[4]
        style_classes[7]['label'] = tr('High [%i people/cell]') % classes[7]

        style_info['legend_title'] = tr('Population Count')

        # Create raster object and return
        raster_layer = Raster(M,
                              projection=hazard_layer.get_projection(),
                              geotransform=hazard_layer.get_geotransform(),
                              name=tr('Population which %s') %
                              (get_function_title(self).lower()),
                              keywords={
                                  'impact_summary': impact_summary,
                                  'impact_table': impact_table,
                                  'map_title': map_title,
                                  'total_needs': total_needs
                              },
                              style_info=style_info)
        return raster_layer
Esempio n. 59
0
    def run(self):
        """Run volcano point population evacuation Impact Function.

        Counts number of people exposed to volcano event.

        :returns: Map of population exposed to the volcano hazard zone.
            The returned dict will include a table with number of people
            evacuated and supplies required.
        :rtype: dict

        :raises:
            * Exception - When hazard layer is not vector layer
            * RadiiException - When radii are not valid (they need to be
                monotonically increasing)
        """
        self.validate()
        self.prepare()

        self.provenance.append_step(
            'Calculating Step', 'Impact function is calculating the impact.')

        # Parameters
        radii = self.parameters['distances'].value

        # Get parameters from layer's keywords
        volcano_name_attribute = self.hazard.keyword('volcano_name_field')

        # Input checks
        if not self.hazard.layer.is_point_data:
            msg = (
                'Input hazard must be a polygon or point layer. I got %s with '
                'layer type %s' %
                (self.hazard.name, self.hazard.layer.get_geometry_name()))
            raise Exception(msg)

        data_table = self.hazard.layer.get_data()

        # Use concentric circles
        category_title = 'Radius'

        centers = self.hazard.layer.get_geometry()
        hazard_layer = buffer_points(centers,
                                     radii,
                                     category_title,
                                     data_table=data_table)

        # Get names of volcanoes considered
        if volcano_name_attribute in hazard_layer.get_attribute_names():
            volcano_name_list = []
            # Run through all polygons and get unique names
            for row in data_table:
                volcano_name_list.append(row[volcano_name_attribute])

            volcano_names = ''
            for radius in volcano_name_list:
                volcano_names += '%s, ' % radius
            self.volcano_names = volcano_names[:-2]  # Strip trailing ', '

        # Run interpolation function for polygon2raster
        interpolated_layer, covered_exposure_layer = \
            assign_hazard_values_to_exposure_data(
                hazard_layer,
                self.exposure.layer,
                attribute_name=self.target_field
            )

        # Initialise affected population per categories
        for radius in radii:
            category = 'Radius %s km ' % format_int(radius)
            self.affected_population[category] = 0

        if has_no_data(self.exposure.layer.get_data(nan=True)):
            self.no_data_warning = True
        # Count affected population per polygon and total
        for row in interpolated_layer.get_data():
            # Get population at this location
            population = row[self.target_field]
            if not numpy.isnan(population):
                population = float(population)
                # Update population count for this category
                category = 'Radius %s km ' % format_int(row[category_title])
                self.affected_population[category] += population

        # Count totals
        self.total_population = population_rounding(
            int(numpy.nansum(self.exposure.layer.get_data())))

        self.minimum_needs = [
            parameter.serialize() for parameter in filter_needs_parameters(
                self.parameters['minimum needs'])
        ]

        impact_table = impact_summary = self.html_report()

        # Create style
        colours = [
            '#FFFFFF', '#38A800', '#79C900', '#CEED00', '#FFCC00', '#FF6600',
            '#FF0000', '#7A0000'
        ]
        classes = create_classes(covered_exposure_layer.get_data().flat[:],
                                 len(colours))
        interval_classes = humanize_class(classes)
        # Define style info for output polygons showing population counts
        style_classes = []
        for i in xrange(len(colours)):
            style_class = dict()
            style_class['label'] = create_label(interval_classes[i])
            if i == 1:
                label = create_label(
                    interval_classes[i],
                    tr('Low Population [%i people/cell]' % classes[i]))
            elif i == 4:
                label = create_label(
                    interval_classes[i],
                    tr('Medium Population [%i people/cell]' % classes[i]))
            elif i == 7:
                label = create_label(
                    interval_classes[i],
                    tr('High Population [%i people/cell]' % classes[i]))
            else:
                label = create_label(interval_classes[i])

            style_class['label'] = label
            style_class['quantity'] = classes[i]
            style_class['colour'] = colours[i]
            style_class['transparency'] = 0
            style_classes.append(style_class)

        # Override style info with new classes and name
        style_info = dict(target_field=None,
                          style_classes=style_classes,
                          style_type='rasterStyle')

        # For printing map purpose
        map_title = tr('People affected by the buffered point volcano')
        legend_title = tr('Population')
        legend_units = tr('(people per cell)')
        legend_notes = tr('Thousand separator is represented by  %s' %
                          get_thousand_separator())

        # Create vector layer and return
        extra_keywords = {
            'impact_summary': impact_summary,
            'impact_table': impact_table,
            'target_field': self.target_field,
            'map_title': map_title,
            'legend_notes': legend_notes,
            'legend_units': legend_units,
            'legend_title': legend_title,
            'total_needs': self.total_needs
        }

        self.set_if_provenance()

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        impact_layer = Raster(
            data=covered_exposure_layer.get_data(),
            projection=covered_exposure_layer.get_projection(),
            geotransform=covered_exposure_layer.get_geotransform(),
            name=tr('People affected by the buffered point volcano'),
            keywords=impact_layer_keywords,
            style_info=style_info)

        self._impact = impact_layer
        return impact_layer
Esempio n. 60
0
class ITBFatalityFunction(ImpactFunction):
    # noinspection PyUnresolvedReferences
    """Indonesian Earthquake Fatality Model.

    This model was developed by Institut Teknologi Bandung (ITB) and
    implemented by Dr. Hadi Ghasemi, Geoscience Australia.


    Reference:

    Indonesian Earthquake Building-Damage and Fatality Models and
    Post Disaster Survey Guidelines Development,
    Bali, 27-28 February 2012, 54pp.


    Algorithm:

    In this study, the same functional form as Allen (2009) is adopted
    to express fatality rate as a function of intensity (see Eq. 10 in the
    report). The Matlab built-in function (fminsearch) for  Nelder-Mead
    algorithm was used to estimate the model parameters. The objective
    function (L2G norm) that is minimised during the optimisation is the
    same as the one used by Jaiswal et al. (2010).

    The coefficients used in the indonesian model are
    x=0.62275231, y=8.03314466, zeta=2.15

    Allen, T. I., Wald, D. J., Earle, P. S., Marano, K. D., Hotovec, A. J.,
    Lin, K., and Hearne, M., 2009. An Atlas of ShakeMaps and population
    exposure catalog for earthquake loss modeling, Bull. Earthq. Eng. 7,
    701-718.

    Jaiswal, K., and Wald, D., 2010. An empirical model for global earthquake
    fatality estimation, Earthq. Spectra 26, 1017-1037.


    Caveats and limitations:

    The current model is the result of the above mentioned workshop and
    reflects the best available information. However, the current model
    has a number of issues listed below and is expected to evolve further
    over time.

    1 - The model is based on limited number of observed fatality
        rates during 4 past fatal events.
    2 - The model clearly over-predicts the fatality rates at
        intensities higher than VIII.
    3 - The model only estimates the expected fatality rate for a given
        intensity level; however the associated uncertainty for the proposed
        model is not addressed.
    4 - There are few known mistakes in developing the current model:
        - rounding MMI values to the nearest 0.5,
        - Implementing Finite-Fault models of candidate events, and
        - consistency between selected GMPEs with those in use by BMKG.
          These issues will be addressed by ITB team in the final report.

    Note: Because of these caveats, decisions should not be made solely on
    the information presented here and should always be verified by ground
    truthing and other reliable information sources.
    """

    _metadata = ITBFatalityMetadata()

    def __init__(self):
        super(ITBFatalityFunction, self).__init__()

        # AG: Use the proper minimum needs, update the parameters
        self.parameters = add_needs_parameters(self.parameters)
        self.hardcoded_parameters = OrderedDict([
            ('x', 0.62275231), ('y', 8.03314466),  # Model coefficients
            # Rates of people displaced for each MMI level
            ('displacement_rate', {
                1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 1.0,
                7: 1.0, 8: 1.0, 9: 1.0, 10: 1.0
            }),
            ('mmi_range', range(2, 10)),
            ('step', 0.5),
            # Threshold below which layer should be transparent
            ('tolerance', 0.01),
            ('calculate_displaced_people', True)
        ])

    def fatality_rate(self, mmi):
        """ITB method to compute fatality rate.

        :param mmi:
        """
        # As per email discussion with Ole, Trevor, Hadi, mmi < 4 will have
        # a fatality rate of 0 - Tim
        if mmi < 4:
            return 0

        x = self.hardcoded_parameters['x']
        y = self.hardcoded_parameters['y']
        # noinspection PyUnresolvedReferences
        return numpy.power(10.0, x * mmi - y)

    def run(self, layers=None):
        """Indonesian Earthquake Fatality Model.

        Input:

        :param layers: List of layers expected to contain,

                hazard: Raster layer of MMI ground shaking

                exposure: Raster layer of population count
        """
        self.validate()
        self.prepare(layers)

        displacement_rate = self.hardcoded_parameters['displacement_rate']

        # Tolerance for transparency
        tolerance = self.hardcoded_parameters['tolerance']

        # Extract input layers
        intensity = self.hazard
        population = self.exposure

        # Extract data grids
        hazard = intensity.get_data()   # Ground Shaking
        exposure = population.get_data(scaling=True)  # Population Density

        # Calculate people affected by each MMI level
        # FIXME (Ole): this range is 2-9. Should 10 be included?
        mmi_range = self.hardcoded_parameters['mmi_range']
        number_of_exposed = {}
        number_of_displaced = {}
        number_of_fatalities = {}

        # Calculate fatality rates for observed Intensity values (hazard
        # based on ITB power model
        mask = numpy.zeros(hazard.shape)
        for mmi in mmi_range:
            # Identify cells where MMI is in class i and
            # count people affected by this shake level
            mmi_matches = numpy.where(
                (hazard > mmi - self.hardcoded_parameters['step']) * (
                    hazard <= mmi + self.hardcoded_parameters['step']),
                exposure, 0)

            # Calculate expected number of fatalities per level
            fatality_rate = self.fatality_rate(mmi)

            fatalities = fatality_rate * mmi_matches

            # Calculate expected number of displaced people per level
            try:
                displacements = displacement_rate[mmi] * mmi_matches
            except KeyError, e:
                msg = 'mmi = %i, mmi_matches = %s, Error msg: %s' % (
                    mmi, str(mmi_matches), str(e))
                # noinspection PyExceptionInherit
                raise InaSAFEError(msg)

            # Adjust displaced people to disregard fatalities.
            # Set to zero if there are more fatalities than displaced.
            displacements = numpy.where(
                displacements > fatalities, displacements - fatalities, 0)

            # Sum up numbers for map
            mask += displacements   # Displaced

            # Generate text with result for this study
            # This is what is used in the real time system exposure table
            number_of_exposed[mmi] = numpy.nansum(mmi_matches.flat)
            number_of_displaced[mmi] = numpy.nansum(displacements.flat)
            # noinspection PyUnresolvedReferences
            number_of_fatalities[mmi] = numpy.nansum(fatalities.flat)

        # Set resulting layer to NaN when less than a threshold. This is to
        # achieve transparency (see issue #126).
        mask[mask < tolerance] = numpy.nan

        # Total statistics
        total, rounding = population_rounding_full(numpy.nansum(exposure.flat))

        # Compute number of fatalities
        fatalities = population_rounding(numpy.nansum(
            number_of_fatalities.values()))
        # As per email discussion with Ole, Trevor, Hadi, total fatalities < 50
        # will be rounded down to 0 - Tim
        if fatalities < 50:
            fatalities = 0

        # Compute number of people displaced due to building collapse
        displaced = population_rounding(numpy.nansum(
            number_of_displaced.values()))

        # Generate impact report
        table_body = [self.question]

        # Add total fatality estimate
        s = format_int(fatalities)
        table_body.append(TableRow([tr('Number of fatalities'), s],
                                   header=True))

        if self.hardcoded_parameters['calculate_displaced_people']:
            # Add total estimate of people displaced
            s = format_int(displaced)
            table_body.append(TableRow([tr('Number of people displaced'), s],
                                       header=True))
        else:
            displaced = 0

        # Add estimate of total population in area
        s = format_int(int(total))
        table_body.append(TableRow([tr('Total number of people'), s],
                                   header=True))

        minimum_needs = [
            parameter.serialize() for parameter in
            self.parameters['minimum needs']
        ]

        # Generate impact report for the pdf map
        table_body = [
            self.question, TableRow(
                [tr('Fatalities'), '%s' % format_int(fatalities)],
                header=True),
            TableRow(
                [tr('People displaced'), '%s' % format_int(displaced)],
                header=True),
            TableRow(tr('Map shows the estimation of displaced population'))]

        total_needs = evacuated_population_needs(
            displaced, minimum_needs)
        for frequency, needs in total_needs.items():
            table_body.append(TableRow(
                [
                    tr('Needs should be provided %s' % frequency),
                    tr('Total')
                ],
                header=True))
            for resource in needs:
                table_body.append(TableRow([
                    tr(resource['table name']),
                    format_int(resource['amount'])]))
        table_body.append(TableRow(tr('Provenance'), header=True))
        table_body.append(TableRow(self.parameters['provenance']))

        table_body.append(TableRow(tr('Action Checklist:'), header=True))

        if fatalities > 0:
            table_body.append(tr('Are there enough victim identification '
                                 'units available for %s people?') %
                              format_int(fatalities))
        if displaced > 0:
            table_body.append(tr('Are there enough shelters and relief items '
                                 'available for %s people?')
                              % format_int(displaced))
            table_body.append(TableRow(tr('If yes, where are they located and '
                                          'how will we distribute them?')))
            table_body.append(TableRow(tr('If no, where can we obtain '
                                          'additional relief items from and '
                                          'how will we transport them?')))

        # Extend impact report for on-screen display
        table_body.extend([TableRow(tr('Notes'), header=True),
                           tr('Total population: %s') % format_int(total),
                           tr('People are considered to be displaced if '
                              'they experience and survive a shake level'
                              'of more than 5 on the MMI scale '),
                           tr('Minimum needs are defined in BNPB '
                              'regulation 7/2008'),
                           tr('The fatality calculation assumes that '
                              'no fatalities occur for shake levels below 4 '
                              'and fatality counts of less than 50 are '
                              'disregarded.'),
                           tr('All values are rounded up to the nearest '
                              'integer in order to avoid representing human '
                              'lives as fractions.')])

        table_body.append(TableRow(tr('Notes'), header=True))
        table_body.append(tr('Fatality model is from '
                             'Institute of Teknologi Bandung 2012.'))
        table_body.append(
            tr('Population numbers rounded up to the nearest %s.') % rounding)

        # Result
        impact_summary = Table(table_body).toNewlineFreeString()
        impact_table = impact_summary

        # check for zero impact
        if numpy.nanmax(mask) == 0 == numpy.nanmin(mask):
            table_body = [
                self.question,
                TableRow([tr('Fatalities'), '%s' % format_int(fatalities)],
                         header=True)]
            my_message = Table(table_body).toNewlineFreeString()
            raise ZeroImpactException(my_message)

        # Create style
        colours = ['#EEFFEE', '#FFFF7F', '#E15500', '#E4001B', '#730000']
        classes = create_classes(mask.flat[:], len(colours))
        interval_classes = humanize_class(classes)
        style_classes = []
        for i in xrange(len(colours)):
            style_class = dict()
            style_class['label'] = create_label(interval_classes[i])
            style_class['quantity'] = classes[i]
            if i == 0:
                transparency = 100
            else:
                transparency = 30
            style_class['transparency'] = transparency
            style_class['colour'] = colours[i]
            style_classes.append(style_class)

        style_info = dict(target_field=None,
                          style_classes=style_classes,
                          style_type='rasterStyle')

        # For printing map purpose
        map_title = tr('Earthquake impact to population')
        legend_notes = tr('Thousand separator is represented by %s' %
                          get_thousand_separator())
        legend_units = tr('(people per cell)')
        legend_title = tr('Population Count')

        # Create raster object and return
        raster = Raster(
            mask,
            projection=population.get_projection(),
            geotransform=population.get_geotransform(),
            keywords={
                'impact_summary': impact_summary,
                'total_population': total,
                'total_fatalities': fatalities,
                'fatalities_per_mmi': number_of_fatalities,
                'exposed_per_mmi': number_of_exposed,
                'displaced_per_mmi': number_of_displaced,
                'impact_table': impact_table,
                'map_title': map_title,
                'legend_notes': legend_notes,
                'legend_units': legend_units,
                'legend_title': legend_title,
                'total_needs': total_needs},
            name=tr('Estimated displaced population per cell'),
            style_info=style_info)
        self._impact = raster
        return raster