def test_insert_map_datum(self): """An `uiapi.hazard_map_data` record is inserted correctly.""" self.output = self.setup_output() session = Session.get() hmw = HazardMapDBWriter( session, self.output.path, self.output.oq_job.id) hmw.output = self.output # This output has no map data before calling the function under test. self.assertEqual(0, len(self.output.hazardmapdata_set)) self.assertEqual(0, len(self.output.lossmapdata_set)) # Call the function under test. data = HAZARD_MAP_DATA[-1] hmw.insert_map_datum(*data) # After calling the function under test we see the expected map data. self.assertEqual(1, len(self.output.hazardmapdata_set)) self.assertEqual(0, len(self.output.lossmapdata_set)) # Make sure the inserted map data is correct. [hmd] = self.output.hazardmapdata_set point = data[0].point self.assertEqual([point.x, point.y], hmd.location.coords(session)) self.assertEqual(round_float(data[1].get("IML")), round_float(hmd.value))
def _point_to_ds_name(point): """Generate a dataset name from a :class:`django.contrib.gis.geos.point.Point`. This dataset name is meant to be used in UHS HDF5 result files. :param point: :class:`django.contrib.gis.geos.point.Point` object. :returns: A dataset name generated from the point's lat/lon values. Example:: "lon:-179.45-lat:-20.75" A simple example: >>> from django.contrib.gis.geos.point import Point >>> pt = Point(-179.45, -20.75) >>> _point_to_ds_name(pt) 'lon:-179.45-lat:-20.75' This function uses :function:`openquake.utils.round_float` to round coordinate values. Thus, any coordinate value with more than 7 digits after the decimal will be rounded to 7 digits: >>> pt = Point(-179.12345675, 79.12345674) >>> _point_to_ds_name(pt) 'lon:-179.1234568-lat:79.1234567' """ return _DS_NAME_FMT % (round_float(point.x), round_float(point.y))
def test_insert_map_datum(self): """An `uiapi.hazard_map_data` record is inserted correctly.""" self.output = self.setup_output() session = Session.get() hmw = HazardMapDBWriter(session, self.output.path, self.output.oq_job.id) hmw.output = self.output # This output has no map data before calling the function under test. self.assertEqual(0, len(self.output.hazardmapdata_set)) self.assertEqual(0, len(self.output.lossmapdata_set)) # Call the function under test. data = HAZARD_MAP_DATA[-1] hmw.insert_map_datum(*data) # After calling the function under test we see the expected map data. self.assertEqual(1, len(self.output.hazardmapdata_set)) self.assertEqual(0, len(self.output.lossmapdata_set)) # Make sure the inserted map data is correct. [hmd] = self.output.hazardmapdata_set point = data[0].point self.assertEqual([point.x, point.y], hmd.location.coords(session)) self.assertEqual(round_float(data[1].get("IML")), round_float(hmd.value))
def __init__(self, longitude, latitude, depth=0.0): nhlib_geo.Point.__init__(self, round_float(longitude), round_float(latitude), depth=depth) self.point = geometry.Point(self.longitude, self.latitude)
def serialize(self, iterable): self.insert_output(self.get_output_type()) # get the value for HazardMap from the first value header = iterable[0][1] fargs = dict(output=self.output, poe=header["poE"], statistic_type=header["statistics"]) if header["statistics"] == "quantile": fargs.update(dict(quantile=header["quantileValue"])) one_or_none = models.HazardMap.objects.filter(**fargs) if len(one_or_none) == 1: self.hazard_map = one_or_none[0] else: self.hazard_map = models.HazardMap(**fargs) self.hazard_map.save() # Update the output record with the minimum/maximum values. self.output.min_value = round_float(min( data[1].get("IML") for data in iterable)) self.output.max_value = round_float(max( data[1].get("IML") for data in iterable)) self.output.save() super(HazardMapDBWriter, self).serialize(iterable)
def serialize(self, iterable): self.insert_output(self.get_output_type()) # get the value for HazardMap from the first value header = iterable[0][1] fargs = dict(output=self.output, poe=header["poE"], statistic_type=header["statistics"]) if header["statistics"] == "quantile": fargs.update(dict(quantile=header["quantileValue"])) one_or_none = models.HazardMap.objects.filter(**fargs) if len(one_or_none) == 1: self.hazard_map = one_or_none[0] else: self.hazard_map = models.HazardMap(**fargs) self.hazard_map.save() # Update the output record with the minimum/maximum values. self.output.min_value = round_float( min(data[1].get("IML") for data in iterable)) self.output.max_value = round_float( max(data[1].get("IML") for data in iterable)) self.output.save() super(HazardMapDBWriter, self).serialize(iterable)
def test_serialize_sets_min_max_values(self): """ serialize() sets the minimum and maximum values on the output record. """ # Call the function under test. self.writer.serialize(HAZARD_MAP_MEAN_DATA()) minimum = min(data[1].get("IML") for data in HAZARD_MAP_MEAN_DATA()) maximum = max(data[1].get("IML") for data in HAZARD_MAP_MEAN_DATA()) # After calling the function under test we see the expected map data. output = self.job.output_set.get() self.assertEqual(round_float(minimum), round_float(output.min_value)) self.assertEqual(round_float(maximum), round_float(output.max_value))
def from_coordinates(cls, coordinates, cell_size=DEFAULT_REGION_CELL_SIZE): """ Build a region from a list of polygon coordinates. :param coordinates: List of 2-tuples (lon, lat). Example:: [(-118.25, 34.07), (-118.22, 34.07), (-118.22, 34.04), (-118.25, 34.04)] :returns: :py:class:`openquake.shapes.Region` instance """ # Constrain the precision for the coordinates: coordinates = [(round_float(pt[0]), round_float(pt[1])) for pt in coordinates] return cls(geometry.Polygon(coordinates), cell_size=cell_size)
def polygon_ewkt_from_coords(coords): ''' Convert a string list of coordinates to SRS 4326 POLYGON EWKT. For more information about EWKT, see: http://en.wikipedia.org/wiki/Well-known_text NOTE: Input coordinates are expected in the order (lat, lon). The ordering for SRS 4326 is (lon, lat). NOTE 2: All coordinate values will be rounded using :py:function:`openquake.utils.round_float` >>> polygon_ewkt_from_coords( ... "38.113, -122.0, 38.113, -122.114, 38.111, -122.57") 'SRID=4326;POLYGON((-122.0 38.113, -122.114 38.113, -122.57 38.111, \ -122.0 38.113))' ''' coord_list = [round_float(x) for x in coords.split(",")] vertices = ['%s %s' % (coord_list[i + 1], coord_list[i]) for i in xrange(0, len(coord_list), 2)] ewkt = 'SRID=4326;POLYGON((%s, %s))' # The polygon needs to form a closed loop, so the first & last coord must # be the same: ewkt %= (', '.join(vertices), vertices[0]) return ewkt
def verify_hazmap_nrml(tc, nrml_path, exp_results_file): """ Given a NRML path and a path to an expected results file, load the expected hazard map results from the latter and compare them with the data contained in the NRML file. :param tc: :class:`unittest.TestCase` object (for test assertions). :param string nrml_path: path to the nrml file to check :param string exp_results_file: path to the expected results file """ root = etree.parse(nrml_path) hmns = root.xpath("//ns:HMNode", namespaces={"ns": "http://openquake.org/xmlns/nrml/0.3"}) # Example "-122.7 47.8": 0.15097656969 nrml_data = dict([(hmn[0][0][0].text, float(hmn[1].text)) for hmn in hmns]) map_data = [line.strip() for line in open(exp_results_file, 'r').readlines()] # Example line: "-122.7 47.8 0.15097656969" map_data = dict(line.rsplit(" ", 1) for line in map_data) tc.assertEqual(len(map_data), len(nrml_data)) for site, iml in map_data.iteritems(): iml = round_float(float(iml)) numpy.testing.assert_approx_equal(iml, nrml_data[site])
def multipoint_ewkt_from_coords(coords): ''' Convert a string list of coordinates to SRS 4326 MULTIPOINT EWKT. For more information about EWKT, see: http://en.wikipedia.org/wiki/Well-known_text NOTE: Input coordinates are expected in the order (lat, lon). The ordering for SRS 4326 is (lon, lat). NOTE 2: All coordinate values will be rounded using :py:function:`openquake.utils.round_float` >>> multipoint_ewkt_from_coords("38.113, -122.0, 38.113, -122.114") 'SRID=4326;MULTIPOINT((-122.0 38.113), (-122.114 38.113))' ''' coord_list = [round_float(x) for x in coords.split(",")] points = [ '(%s %s)' % (coord_list[i + 1], coord_list[i]) for i in xrange(0, len(coord_list), 2) ] ewkt = 'SRID=4326;MULTIPOINT(%s)' ewkt %= ', '.join(points) return ewkt
def insert_map_datum(self, point, value): """Inserts a single hazard map datum. Please note that `point.x` and `point.y` store the longitude and the latitude respectively. :param point: The hazard map point/location. :type point: :py:class:`shapes.GridPoint` or :py:class:`shapes.Site` :param float value: the value for the given location """ logger.info("> insert_map_datum") if isinstance(point, shapes.GridPoint): point = point.site.point if isinstance(point, shapes.Site): point = point.point value = value.get("IML") if value is None: logger.warn("No IML value for position: [%s, %s]" % (point.x, point.y)) else: datum = HazardMapData(location="POINT(%s %s)" % (point.x, point.y), output=self.output, value=round_float(value)) self.session.add(datum) self.session.commit() logger.info("datum = [%s, %s], %s" % (point.x, point.y, datum)) logger.info("< insert_map_datum")
def insert_map_datum(self, point, value): """Inserts a single hazard map datum. Please note that `point.x` and `point.y` store the longitude and the latitude respectively. :param point: The hazard map point/location. :type point: :py:class:`shapes.GridPoint` or :py:class:`shapes.Site` :param float value: the value for the given location """ logger.info("> insert_map_datum") if isinstance(point, shapes.GridPoint): point = point.site.point if isinstance(point, shapes.Site): point = point.point value = value.get("IML") if value is None: logger.warn( "No IML value for position: [%s, %s]" % (point.x, point.y)) else: datum = HazardMapData(location="POINT(%s %s)" % (point.x, point.y), output=self.output, value=round_float(value)) self.session.add(datum) self.session.commit() logger.info("datum = [%s, %s], %s" % (point.x, point.y, datum)) logger.info("< insert_map_datum")
def verify_hazmap_nrml(tc, nrml_path, exp_results_file): """ Given a NRML path and a path to an expected results file, load the expected hazard map results from the latter and compare them with the data contained in the NRML file. :param tc: :class:`unittest.TestCase` object (for test assertions). :param string nrml_path: path to the nrml file to check :param string exp_results_file: path to the expected results file """ root = etree.parse(nrml_path) hmns = root.xpath("//ns:HMNode", namespaces={"ns": "http://openquake.org/xmlns/nrml/0.3"}) # Example "-122.7 47.8": 0.15097656969 nrml_data = dict([(hmn[0][0][0].text, float(hmn[1].text)) for hmn in hmns]) map_data = [ line.strip() for line in open(exp_results_file, 'r').readlines() ] # Example line: "-122.7 47.8 0.15097656969" map_data = dict(line.rsplit(" ", 1) for line in map_data) tc.assertEqual(len(map_data), len(nrml_data)) for site, iml in map_data.iteritems(): iml = round_float(float(iml)) numpy.testing.assert_approx_equal(iml, nrml_data[site])
def _cell_to_polygon(lowerleft, cell_size): """Return the cell with the given mid point and size. :param lowerleft: the lower left corner of the risk cell :type lowerleft: a :py:class:`openquake.shapes.Site` instance :param float cell_size: the configured risk cell size :return: the risk cell as a :py:class:`django.contrib.gis.geos.Polygon` """ lon, lat = lowerleft.coords coos = [(lon, lat), # lower left (lon, lat + cell_size), # upper left (lon + cell_size, lat + cell_size), # upper right (lon + cell_size, lat), # lower right (lon, lat)] coos = [(round_float(x), round_float(y)) for x, y in coos] return geos.Polygon(coos)
def test_serialize_sets_min_max_values(self): """ serialize() sets the minimum and maximum values on the output record. """ self.job = self.setup_classic_job() session = Session.get() output_path = self.generate_output_path(self.job) hmw = HazardMapDBWriter(session, output_path, self.job.id) # Call the function under test. hmw.serialize(HAZARD_MAP_DATA) minimum = min(data[1].get("IML") for data in HAZARD_MAP_DATA) maximum = max(data[1].get("IML") for data in HAZARD_MAP_DATA) # After calling the function under test we see the expected map data. [output] = self.job.output_set self.assertEqual(round_float(minimum), round_float(output.min_value)) self.assertEqual(round_float(maximum), round_float(output.max_value))
def serialize(self, iterable): self.insert_output(self.get_output_type()) # get the value for HazardMap from the first value header = iterable[0][1] self.hazard_map = models.HazardMap(output=self.output, poe=header["poE"], statistic_type=header["statistics"]) if header["statistics"] == "quantile": self.hazard_map.quantile = header["quantileValue"] self.hazard_map.save() # Update the output record with the minimum/maximum values. self.output.min_value = round_float(min(data[1].get("IML") for data in iterable)) self.output.max_value = round_float(max(data[1].get("IML") for data in iterable)) self.output.save() super(HazardMapDBWriter, self).serialize(iterable)
def normalize(self, values): result = [] for site, attrs in values: new = attrs.copy() new['IML'] = round_float(attrs['IML']) new['investigationTimeSpan'] = float(new['investigationTimeSpan']) result.append((site, new)) return result
def _cell_to_polygon(center, cell_size): """Return the cell with the given mid point and size. :param center: the center of the risk cell :type center: a :py:class:`openquake.shapes.Site` instance :param float cell_size: the configured risk cell size :return: the risk cell as a :py:class:`django.contrib.gis.geos.Polygon` """ clon, clat = center.coords half_csize = cell_size / 2.0 lon, lat = (clon - half_csize, clat - half_csize) coos = [(lon, lat), # lower left (lon, lat + cell_size), # upper left (lon + cell_size, lat + cell_size), # upper right (lon + cell_size, lat), # lower right (lon, lat)] coos = [(round_float(x), round_float(y)) for x, y in coos] return geos.Polygon(coos)
def serialize(self, iterable): """Writes hazard map data to the database. :param iterable: will look something like this: [(Site(-121.7, 37.6), {'IML': 1.9266716959669603, 'IMT': 'PGA', 'investigationTimeSpan': '50.0', 'poE': 0.01, 'statistics': 'mean', 'vs30': 760.0}), . . . {'IML': 1.925653989154411, 'IMT': 'PGA', 'investigationTimeSpan': '50.0', 'poE': 0.01, 'statistics': 'mean', 'vs30': 760.0})] We first insert a `uiapi.output` record for the hazard map and then an `uiapi.hazard_map_data` record for each datum in the `iterable`. """ logger.info("> serialize") logger.info("serializing %s points" % len(iterable)) self.insert_output() for key, value in iterable: self.insert_map_datum(key, value) # Update the output record with the minimum/maximum values. self.output.min_value = round_float(min( data[1].get("IML") for data in iterable)) self.output.max_value = round_float(max( data[1].get("IML") for data in iterable)) self.session.add(self.output) self.session.commit() logger.info("serialized %s points" % len(iterable)) logger.info("< serialize")
def serialize(self, iterable): """Writes hazard map data to the database. :param iterable: will look something like this: [(Site(-121.7, 37.6), {'IML': 1.9266716959669603, 'IMT': 'PGA', 'investigationTimeSpan': '50.0', 'poE': 0.01, 'statistics': 'mean', 'vs30': 760.0}), . . . {'IML': 1.925653989154411, 'IMT': 'PGA', 'investigationTimeSpan': '50.0', 'poE': 0.01, 'statistics': 'mean', 'vs30': 760.0})] We first insert a `uiapi.output` record for the hazard map and then an `uiapi.hazard_map_data` record for each datum in the `iterable`. """ logger.info("> serialize") logger.info("serializing %s points" % len(iterable)) self.insert_output() for key, value in iterable: self.insert_map_datum(key, value) # Update the output record with the minimum/maximum values. self.output.min_value = round_float( min(data[1].get("IML") for data in iterable)) self.output.max_value = round_float( max(data[1].get("IML") for data in iterable)) self.session.add(self.output) self.session.commit() logger.info("serialized %s points" % len(iterable)) logger.info("< serialize")
def _cell_to_polygon(center, cell_size): """Return the cell with the given mid point and size. :param center: the center of the risk cell :type center: a :py:class:`openquake.shapes.Site` instance :param float cell_size: the configured risk cell size :return: the risk cell as a :py:class:`django.contrib.gis.geos.Polygon` """ clon, clat = center.coords half_csize = cell_size / 2.0 lon, lat = (clon - half_csize, clat - half_csize) coos = [ (lon, lat), # lower left (lon, lat + cell_size), # upper left (lon + cell_size, lat + cell_size), # upper right (lon + cell_size, lat), # lower right (lon, lat) ] coos = [(round_float(x), round_float(y)) for x, y in coos] return geos.Polygon(coos)
def serialize(self, iterable): self.insert_output(self.get_output_type()) # get the value for HazardMap from the first value header = iterable[0][1] self.hazard_map = models.HazardMap( output=self.output, poe=header['poE'], statistic_type=header['statistics']) if header['statistics'] == 'quantile': self.hazard_map.quantile = header['quantileValue'] self.hazard_map.save() # Update the output record with the minimum/maximum values. self.output.min_value = round_float(min( data[1].get("IML") for data in iterable)) self.output.max_value = round_float(max( data[1].get("IML") for data in iterable)) self.output.save() super(HazardMapDBWriter, self).serialize(iterable)
def _build_polygon(self): """ Create the polygon underlying this grid. """ # since we are always considering the center of the # cells, we must include half of the cell size # to the borders half_cell_size = self.cell_size / 2.0 min_lon = self.llc.longitude - half_cell_size max_lon = (self.llc.longitude + (self.columns * self.cell_size) + half_cell_size) min_lat = self.llc.latitude - half_cell_size max_lat = (self.llc.latitude + (self.rows * self.cell_size) + half_cell_size) coords = [(min_lon, max_lat), (max_lon, max_lat), (max_lon, min_lat), (min_lon, min_lat)] return geometry.Polygon([(round_float(pt[0]), round_float(pt[1])) for pt in coords])
def test_round_float_rounding(self): """ By default, the :py:module:`decimal` module uses the 'round-half-even' algorithm for rounding numbers. Since the rounding method can be set in a global context for the :py:module:`decimal` module, we want to make sure the :py:function:`openquake.utils.round_float` is unaffected context changes. """ decimal.getcontext().rounding = decimal.ROUND_FLOOR # changing the decimal context rounding should not affect the behavior # of round_float self.assertEqual(-121.0000001, round_float(-121.00000009)) # reset the global context so we don't potentially screw up other tests decimal.getcontext().rounding = decimal.ROUND_HALF_EVEN
def test_round_float(self): """ This test exercises the :py:function:`openquake.utils.round_float` function. Basically, the function should take any float number and round it to a fixed number of decimal places (for example, 7 places). The rounding method used is the default for the :py:module:`decimal` module, which is ROUND_HALF_EVEN. For more information on 'half-even' rounding, there is a good explanation here: http://www.diycalculator.com/popup-m-round.shtml#A5 """ in_values = (29.000000000000004, -121.00000009, -121.00000001, 121.00000005, 121.00000006) out_values = (29.0, -121.0000001, -121.0, 121.0, 121.0000001) for i, val in enumerate(in_values): self.assertEqual(out_values[i], round_float(in_values[i]))
def test_round_float(self): """ This test exercises the :py:function:`openquake.utils.round_float` function. Basically, the function should take any float number and round it to a fixed number of decimal places (for example, 7 places). The rounding method used is the default for the :py:module:`decimal` module, which is ROUND_HALF_EVEN. For more information on 'half-even' rounding, there is a good explanation here: http://www.diycalculator.com/popup-m-round.shtml#A5 """ in_values = ( 29.000000000000004, -121.00000009, -121.00000001, 121.00000005, 121.00000006) out_values = (29.0, -121.0000001, -121.0, 121.0, 121.0000001) for i, _ in enumerate(in_values): self.assertEqual(out_values[i], round_float(in_values[i]))
def insert_datum(self, point, value): """Inserts a single hazard map datum. Please note that `point.x` and `point.y` store the longitude and the latitude respectively. :param point: The hazard map point/location. :type point: :py:class:`shapes.GridPoint` or :py:class:`shapes.Site` :param float value: the value for the given location """ if isinstance(point, shapes.GridPoint): point = point.site.point if isinstance(point, shapes.Site): point = point.point value = value.get("IML") if value is None: LOGGER.warn("No IML value for position: [%s, %s]" % (point.x, point.y)) else: self.bulk_inserter.add_entry( hazard_map_id=self.hazard_map.id, value=round_float(value), location="POINT(%s %s)" % (point.x, point.y) )
def multipoint_ewkt_from_coords(coords): """ Convert a string list of coordinates to SRS 4326 MULTIPOINT EWKT. For more information about EWKT, see: http://en.wikipedia.org/wiki/Well-known_text NOTE: Input coordinates are expected in the order (lat, lon). The ordering for SRS 4326 is (lon, lat). NOTE 2: All coordinate values will be rounded using :py:function:`openquake.utils.round_float` >>> multipoint_ewkt_from_coords("38.113, -122.0, 38.113, -122.114") 'SRID=4326;MULTIPOINT((-122.0 38.113), (-122.114 38.113))' """ coord_list = [round_float(x) for x in coords.split(",")] points = ["(%s %s)" % (coord_list[i + 1], coord_list[i]) for i in xrange(0, len(coord_list), 2)] ewkt = "SRID=4326;MULTIPOINT(%s)" ewkt %= ", ".join(points) return ewkt
def insert_datum(self, point, value): """Inserts a single hazard map datum. Please note that `point.x` and `point.y` store the longitude and the latitude respectively. :param point: The hazard map point/location. :type point: :py:class:`shapes.GridPoint` or :py:class:`shapes.Site` :param float value: the value for the given location """ if isinstance(point, shapes.GridPoint): point = point.site.point if isinstance(point, shapes.Site): point = point.point value = value.get("IML") if value is None: LOGGER.warn("No IML value for position: [%s, %s]" % (point.x, point.y)) else: self.bulk_inserter.add_entry(hazard_map_id=self.hazard_map.id, value=round_float(value), location="POINT(%s %s)" % (point.x, point.y))
def __init__(self, longitude, latitude): longitude = round_float(longitude) latitude = round_float(latitude) self.point = geometry.Point(longitude, latitude)
def check_gridpoint(self, gridpoint): """Confirm that the point is contained by the region""" point = Point(round_float(self._column_to_longitude(gridpoint.column)), round_float(self._row_to_latitude(gridpoint.row))) return self.check_point(point)
def __init__(self, longitude, latitude, depth=0.0): nhlib_geo.Point.__init__( self, round_float(longitude), round_float(latitude), depth=depth) self.point = geometry.Point(self.longitude, self.latitude)