diff --git a/MANIFEST.in b/MANIFEST.in index 965b2dd..1f2c0de 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,9 +3,11 @@ include CONTRIBUTING.rst include HISTORY.rst include LICENSE include README.rst +include privatekey.json recursive-include tests * recursive-exclude * __pycache__ recursive-exclude * *.py[co] recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif +recursive-include hydroengine_service *.json diff --git a/hydroengine_service/liwo_blueprints.py b/hydroengine_service/liwo_blueprints.py index d96516f..14b3ae2 100644 --- a/hydroengine_service/liwo_blueprints.py +++ b/hydroengine_service/liwo_blueprints.py @@ -8,8 +8,8 @@ from hydroengine_service import liwo_functions v1 = Blueprint("liwo-v1", __name__) -v2 = Blueprint('liwo-v2', __name__) - +v2 = Blueprint("liwo-v2", __name__) +v3 = Blueprint("liwo-v3", __name__) DEFAULT_COLLECTION = 'projects/deltares-rws/liwo/2021_0_3' @@ -49,6 +49,67 @@ def scenario_info(im): mimetype='application/json' ) +@v3.route('/get_liwo_scenarios', methods=['GET', 'POST']) +@flask_cors.cross_origin() +def get_liwo_scenarios(): + r = request.get_json() + + # name of breach location as string + liwo_ids = r['liwo_ids'] + # band name as string + band = r['band'] + + collection = r.get('collection', DEFAULT_COLLECTION) + + id_key = 'Scenario_ID' + bands = { + 'waterdepth': 'waterdiepte', + 'velocity': 'stroomsnelheid', + 'riserate': 'stijgsnelheid', + 'damage': 'schade', + 'fatalities': 'slachtoffers', + 'affected': 'getroffenen', + 'arrivaltime': 'aankomsttijd' + } + reducers = { + "waterdepth": "max", + "velocity": "max", + "riserate": "max", + "damage": "max", + "fatalities": "max", + "affected": "max", + "arrivaltime": "min" + } + + assert band in bands + band_name = bands[band] + reducer = reducers[band] + + image = liwo_functions.filter_liwo_collection_v3(collection, id_key, liwo_ids, band_name, reducer) + + params = liwo_functions.get_liwo_styling(band) + info = liwo_functions.generate_image_info(image, params) + info['liwo_ids'] = liwo_ids + info['band'] = band + + # Following needed for export: + # Specify region over which to compute + region = image.geometry() + + if r.get('export'): + # default to 5m + info['scale'] = r.get('scale', 5) + # always + info['crs'] = r.get('crs', 'EPSG:4326') + extra_info = liwo_functions.export_image_response(image, region, info) + info.update(extra_info) + + return Response( + json.dumps(info), + status=200, + mimetype='application/json' + ) + @v2.route('/get_liwo_scenarios', methods=['GET', 'POST']) @flask_cors.cross_origin() diff --git a/hydroengine_service/liwo_functions.py b/hydroengine_service/liwo_functions.py index 66c0021..c85bcb8 100644 --- a/hydroengine_service/liwo_functions.py +++ b/hydroengine_service/liwo_functions.py @@ -149,6 +149,56 @@ def filter_liwo_collection_v2(collection_path, id_key, scenario_ids, band, reduc image = image.clip(bounds) return image +def filter_liwo_collection_v3(collection_path, id_key, scenario_ids, band, reducer): + """ + Create combined max image from collection. Version 2 based on named image bands + :param collection_path: Path to Earth Engine Image Collection + :param id_key: Metadata key name for unique ids + :param scenario_ids: List of scenario ids to combine + :param band: band of image to select + :param reducer: reducer operation by which to combine images + :return: combined image + """ + # Filter based on scenario id, band + scenarios = ee.ImageCollection(collection_path) + + if type(scenarios.first().get("Scenario_ID").getInfo()) == int: + scenarios = scenarios.filter(ee.Filter.inList(id_key, scenario_ids)) + elif type(scenarios.first().get("Scenario_ID").getInfo()) == str: + scenario_ids = [str(x) for x in scenario_ids] + scenarios = scenarios.filter(ee.Filter.inList(id_key, scenario_ids)) + + scenarios = scenarios.select(band) + n_selected = scenarios.size().getInfo() + + if n_selected == 0: + msg = 'No images available for breach locations: %s' % (scenario_ids,) + logger.debug(msg) + raise error_handler.InvalidUsage(msg) + # raise ValueError("No images with band {} in scenario_ids {}".format(band, scenario_ids)) + + if len(scenario_ids) != n_selected: + logging.info( + "collection {}, missing {} scenarios for band {}".format(collection_path, len(scenario_ids) - n_selected, band) + ) + + bounds = scenarios.geometry().bounds() + + # reduce image + reduce_func = getattr(ee.Reducer, reducer)() + if reducer == 'min': + # Aankomstijden <= 0 should not be included in the aggregated minimum + scenarios = scenarios.map(lambda i: i.mask(i.gt(0))) + + image = ee.Image(scenarios.reduce(reduce_func)) + if reducer == 'max': + # Do not display any values <= 0 (Some no data values assigned as 0 and not -9999). + image = image.mask(image.gt(0)) + + # reclip by bounds + image = image.clip(bounds) + return image + def generate_image_info(im, params): """generate url and tokens for image""" diff --git a/hydroengine_service/main.py b/hydroengine_service/main.py index 105aa4a..519fae2 100755 --- a/hydroengine_service/main.py +++ b/hydroengine_service/main.py @@ -44,8 +44,6 @@ v1 = Blueprint("version1", "version1") v2 = Blueprint('version2', "version2") - - # if 'privatekey.json' is defined in environmental variable - write it to file if 'key' in os.environ: print('Writing privatekey.json from environmental variable ...') @@ -1247,6 +1245,7 @@ def server_error(e): app.register_blueprint(liwo_blueprints.v1, url_prefix="/v1") app.register_blueprint(liwo_blueprints.v2, url_prefix="/v2") +app.register_blueprint(liwo_blueprints.v3, url_prefix="/v3") app.register_blueprint(dgds_blueprints.v1, url_prefix="/v1") app.register_blueprint(dgds_blueprints.v2, url_prefix="/v2")