Esempio n. 1
0
File: core.py Progetto: AIFDR/riab
def get_bounding_boxes(haz_metadata, exp_metadata, req_bbox):
    """Check and get appropriate bounding boxes for input layers

    Input
        haz_metadata: Metadata for hazard layer
        exp_metadata: Metadata for exposure layer
        req_bbox: Bounding box (string) as requested by HTML POST.

    Output
        haz_bbox: Bounding box to be used for hazard layer.
        exp_bbox: Bounding box to be used for exposure layer
        imp_bbox: Bounding box to be used for resulting impact layer

    Note exp_bbox and imp_bbox are the same and calculated as the
         intersection among hazard, exposure and viewport bounds.
         haz_bbox may be grown by one pixel size in case exposure data
         is vector data to make sure points always can be interpolated
    """

    # Input checks
    msg = ('Invalid bounding box %s (%s). '
           'It must be a string' % (str(req_bbox), type(req_bbox)))
    assert isinstance(req_bbox, basestring), msg
    check_bbox_string(req_bbox)

    # Get bounding boxes for layers and viewport
    haz_bbox = haz_metadata['bounding_box']
    exp_bbox = exp_metadata['bounding_box']
    vpt_bbox = bboxstring2list(req_bbox)

    # New bounding box for data common to hazard, exposure and viewport
    # Download only data within this intersection
    intersection_bbox = bbox_intersection(vpt_bbox, haz_bbox, exp_bbox)
    if intersection_bbox is None:
        # Bounding boxes did not overlap
        msg = ('Bounding boxes of hazard data [%s], exposure data [%s] '
               'and viewport [%s] did not overlap, so no computation was '
               'done. Please make sure you pan to where the data is and '
               'that hazard and exposure data overlaps.'
               % (bboxlist2string(haz_bbox, decimals=3),
                  bboxlist2string(exp_bbox, decimals=3),
                  bboxlist2string(vpt_bbox, decimals=3)))
        logger.info(msg)
        raise Exception(msg)

    # Grow hazard bbox to buffer this common bbox in case where
    # hazard is raster and exposure is vector
    if (haz_metadata['layer_type'] == 'raster' and
        exp_metadata['layer_type'] == 'vector'):

        haz_res = haz_metadata['resolution']
        haz_bbox = buffered_bounding_box(intersection_bbox, haz_res)
    else:
        haz_bbox = intersection_bbox

    # Usually the intersection bbox is used for both exposure layer and result
    exp_bbox = imp_bbox = intersection_bbox

    return haz_bbox, exp_bbox, imp_bbox
Esempio n. 2
0
def get_bounding_boxes(haz_metadata, exp_metadata, req_bbox):
    """Check and get appropriate bounding boxes for input layers

    Input
        haz_metadata: Metadata for hazard layer
        exp_metadata: Metadata for exposure layer
        req_bbox: Bounding box (string) as requested by HTML POST.

    Output
        haz_bbox: Bounding box to be used for hazard layer.
        exp_bbox: Bounding box to be used for exposure layer
        imp_bbox: Bounding box to be used for resulting impact layer

    Note exp_bbox and imp_bbox are the same and calculated as the
         intersection among hazard, exposure and viewport bounds.
         haz_bbox may be grown by one pixel size in case exposure data
         is vector data to make sure points always can be interpolated
    """

    # Input checks
    msg = ('Invalid bounding box %s (%s). '
           'It must be a string' % (str(req_bbox), type(req_bbox)))
    assert isinstance(req_bbox, basestring), msg
    check_bbox_string(req_bbox)

    # Get bounding boxes for layers and viewport
    haz_bbox = haz_metadata['bounding_box']
    exp_bbox = exp_metadata['bounding_box']
    vpt_bbox = bboxstring2list(req_bbox)

    # New bounding box for data common to hazard, exposure and viewport
    # Download only data within this intersection
    intersection_bbox = bbox_intersection(vpt_bbox, haz_bbox, exp_bbox)
    if intersection_bbox is None:
        # Bounding boxes did not overlap
        msg = ('Bounding boxes of hazard data [%s], exposure data [%s] '
               'and viewport [%s] did not overlap, so no computation was '
               'done. Please make sure you pan to where the data is and '
               'that hazard and exposure data overlaps.' %
               (bboxlist2string(haz_bbox, decimals=3),
                bboxlist2string(exp_bbox, decimals=3),
                bboxlist2string(vpt_bbox, decimals=3)))
        logger.info(msg)
        raise Exception(msg)

    # Grow hazard bbox to buffer this common bbox in case where
    # hazard is raster and exposure is vector
    if (haz_metadata['layer_type'] == 'raster'
            and exp_metadata['layer_type'] == 'vector'):

        haz_res = haz_metadata['resolution']
        haz_bbox = buffered_bounding_box(intersection_bbox, haz_res)
    else:
        haz_bbox = intersection_bbox

    # Usually the intersection bbox is used for both exposure layer and result
    exp_bbox = imp_bbox = intersection_bbox

    return haz_bbox, exp_bbox, imp_bbox
Esempio n. 3
0
    def test_bounding_box_conversions(self):
        """Bounding boxes can be converted between list and string
        """

        # Good ones
        for x in [[105, -7, 108, -5],
                  [106.5, -6.5, 107, -6],
                  [94.972335, -11.009721, 141.014, 6.073612333333],
                  [105.3, -8.5, 110.0, -5.5],
                  [105.6, -7.8, 110.5, -5.1]]:
            bbox_string = bboxlist2string(x)
            bbox_list = bboxstring2list(bbox_string)

            assert numpy.allclose(x, bbox_list, rtol=1.0e-6, atol=1.0e-6)

        for x in ['105,-7,108,-5',
                  '106.5, -6.5, 107,-6',
                  '94.972335,-11.009721,141.014,6.073612333333']:
            bbox_list = bboxstring2list(x)

            # Check that numbers are numerically consistent
            assert numpy.allclose([float(z) for z in x.split(',')],
                                  bbox_list, rtol=1.0e-6, atol=1.0e-6)

        # Bad ones
        for bbox in [[105, -7, 'x', -5],
                     [106.5, -6.5, -6],
                     [94.972335, 0, -11.009721, 141.014, 6]]:
            try:
                bbox_string = bboxlist2string(bbox)
            except:
                pass
            else:
                msg = 'Should have raised exception'
                raise Exception(msg)

        for x in ['106.5,-6.5,-6',
                  '106.5,-6.5,-6,4,10',
                  '94.972335,x,141.014,6.07']:
            try:
                bbox_list = bboxstring2list(x)
            except:
                pass
            else:
                msg = 'Should have raised exception: %s' % x
                raise Exception(msg)
Esempio n. 4
0
def calculate(request, save_output=save_to_geonode):
    start = datetime.datetime.now()

    if request.method == 'GET':
        # FIXME: Add a basic form here to be able to generate the POST request.
        return HttpResponse('This should be accessed by robots, not humans.'
                            'In other words using HTTP POST instead of GET.')
    elif request.method == 'POST':
        data = request.POST
        impact_function_name = data['impact_function']
        hazard_server = data['hazard_server']
        hazard_layer = data['hazard']
        exposure_server = data['exposure_server']
        exposure_layer = data['exposure']
        bbox = data['bbox']
        keywords = data['keywords']

    if request.user.is_anonymous():
        theuser = get_valid_user()
    else:
        theuser = request.user

    # Create entry in database
    calculation = Calculation(user=theuser,
                              run_date=start,
                              hazard_server=hazard_server,
                              hazard_layer=hazard_layer,
                              exposure_server=exposure_server,
                              exposure_layer=exposure_layer,
                              impact_function=impact_function_name,
                              success=False)

    try:

        # Input checks
        msg = 'This cannot happen :-)'
        assert isinstance(bbox, basestring), msg

        check_bbox_string(bbox)

        # Find the intersection of bounding boxes for viewport,
        # hazard and exposure.
        vpt_bbox = bboxstring2list(bbox)
        haz_bbox = get_metadata(hazard_server,
                                hazard_layer)['bounding_box']
        exp_bbox = get_metadata(exposure_server,
                                exposure_layer)['bounding_box']

        # Impose minimum bounding box size (as per issue #101).
        # FIXME (Ole): This will need to be revisited in conjunction with
        # raster resolutions at some point.
        min_res = 0.00833334
        eps = 1.0e-1
        vpt_bbox = minimal_bounding_box(vpt_bbox, min_res, eps=eps)
        haz_bbox = minimal_bounding_box(haz_bbox, min_res, eps=eps)
        exp_bbox = minimal_bounding_box(exp_bbox, min_res, eps=eps)

        # New bounding box for data common to hazard, exposure and viewport
        # Download only data within this intersection
        intersection = bbox_intersection(vpt_bbox, haz_bbox, exp_bbox)
        if intersection is None:
            # Bounding boxes did not overlap
            msg = ('Bounding boxes of hazard data, exposure data and '
                   'viewport did not overlap, so no computation was '
                   'done. Please try again.')
            logger.info(msg)
            raise Exception(msg)

        bbox = bboxlist2string(intersection)

        plugin_list = get_plugins(impact_function_name)
        _, impact_function = plugin_list[0].items()[0]
        impact_function_source = inspect.getsource(impact_function)

        calculation.impact_function_source = impact_function_source
        calculation.bbox = bbox

        calculation.save()

        msg = 'Performing requested calculation'
        logger.info(msg)

        # Download selected layer objects
        msg = ('- Downloading hazard layer %s from %s' % (hazard_layer,
                                                      hazard_server))
        logger.info(msg)

        H = download(hazard_server, hazard_layer, bbox)

        msg = ('- Downloading exposure layer %s from %s' % (exposure_layer,
                                                        exposure_server))
        logger.info(msg)
        E = download(exposure_server, exposure_layer, bbox)

        # Calculate result using specified impact function
        msg = ('- Calculating impact using %s' % impact_function)
        logger.info(msg)

        impact_filename = calculate_impact(layers=[H, E],
                                           impact_fcn=impact_function)

        # Upload result to internal GeoServer
        msg = ('- Uploading impact layer %s' % impact_filename)
        logger.info(msg)
        result = save_output(impact_filename,
                         title='output_%s' % start.isoformat(),
                         user=theuser)
    except Exception, e:
        #FIXME: Reimplement error saving for calculation
        logger.error(e)
        errors = e.__str__()
        trace = exception_format(e)
        calculation.errors = errors
        calculation.stacktrace = trace
        calculation.save()
        jsondata = json.dumps({'errors': errors, 'stacktrace': trace})
        return HttpResponse(jsondata, mimetype='application/json')
Esempio n. 5
0
def calculate(request, save_output=save_to_geonode):
    start = datetime.datetime.now()

    if request.method == 'GET':
        # FIXME: Add a basic form here to be able to generate the POST request.
        return HttpResponse('This should be accessed by robots, not humans.'
                            'In other words using HTTP POST instead of GET.')
    elif request.method == 'POST':
        data = request.POST
        impact_function_name = data['impact_function']
        hazard_server = data['hazard_server']
        hazard_layer = data['hazard']
        exposure_server = data['exposure_server']
        exposure_layer = data['exposure']
        requested_bbox = data['bbox']
        keywords = data['keywords']

    if request.user.is_anonymous():
        theuser = get_valid_user()
    else:
        theuser = request.user

    # Create entry in database
    calculation = Calculation(user=theuser,
                              run_date=start,
                              hazard_server=hazard_server,
                              hazard_layer=hazard_layer,
                              exposure_server=exposure_server,
                              exposure_layer=exposure_layer,
                              impact_function=impact_function_name,
                              success=False)

    # Wrap main computation loop in try except to catch and present
    # messages and stack traces in the application
    try:
        # Get metadata
        haz_metadata = get_metadata(hazard_server, hazard_layer)
        exp_metadata = get_metadata(exposure_server, exposure_layer)

        # Determine common resolution in case of raster layers
        raster_resolution = get_common_resolution(haz_metadata, exp_metadata)

        # Get reconciled bounding boxes
        haz_bbox, exp_bbox, imp_bbox = get_bounding_boxes(haz_metadata,
                                                          exp_metadata,
                                                          requested_bbox)

        # Record layers to download
        download_layers = [(hazard_server, hazard_layer, haz_bbox),
                           (exposure_server, exposure_layer, exp_bbox)]

        # Add linked layers if any FIXME: STILL TODO!

        # Get selected impact function
        impact_function = get_plugin(impact_function_name)
        impact_function_source = inspect.getsource(impact_function)

        # Record information calculation object and save it
        calculation.impact_function_source = impact_function_source
        calculation.bbox = bboxlist2string(imp_bbox)
        calculation.save()

        # Start computation
        msg = 'Performing requested calculation'
        logger.info(msg)

        # Download selected layer objects
        layers = []
        for server, layer_name, bbox in download_layers:
            msg = ('- Downloading layer %s from %s'
                   % (layer_name, server))
            logger.info(msg)
            L = download(server, layer_name, bbox, raster_resolution)
            layers.append(L)

        # Calculate result using specified impact function
        msg = ('- Calculating impact using %s' % impact_function)
        logger.info(msg)
        impact_filename = calculate_impact(layers=layers,
                                           impact_fcn=impact_function)

        # Upload result to internal GeoServer
        msg = ('- Uploading impact layer %s' % impact_filename)
        logger.info(msg)
        result = save_output(impact_filename,
                             title='output_%s' % start.isoformat(),
                             user=theuser)
    except Exception, e:
        # FIXME: Reimplement error saving for calculation.
        # FIXME (Ole): Why should we reimplement?
        # This is dangerous. Try to raise an exception
        # e.g. in get_metadata_from_layer. Things will silently fail.
        # See issue #170

        logger.error(e)
        errors = e.__str__()
        trace = exception_format(e)
        calculation.errors = errors
        calculation.stacktrace = trace
        calculation.save()
        jsondata = json.dumps({'errors': errors, 'stacktrace': trace})
        return HttpResponse(jsondata, mimetype='application/json')