def get_network_json(self, edges, nodes):
     if not edges or not nodes:
         return {}
     edges_df = geopandas.GeoDataFrame.from_file(edges)
     nodes_df = geopandas.GeoDataFrame.from_file(nodes)
     network_json = json.loads(edges_df.to_crs(get_geographic_coordinate_system()).to_json())
     network_json['features'].extend(
         json.loads(nodes_df.to_crs(get_geographic_coordinate_system()).to_json())['features'])
     return json.dumps(network_json)
    def _plot_div_producer(self):
        """
        Since this plot doesn't use plotly to plot, we override _plot_div_producer to return a string containing
        the html div to use for this plot. The template ``map_div.html`` expects some parameters:

        Here is some example data (in a YAML-like format for documentation purposes)

        ::

            data:
              DH:
                connected_buildings: ['B1010', 'B1017', 'B1003']
                disconnected_buildings: ['B1000', 'B1009', 'B1016', ..., 'B1015']
                path_output_nodes: "{general:scenario}/inputs/networks/DH/gen_3_ind_1/nodes.shp"
                path_output_edges: "{general:scenario}/inputs/networks/DH/gen_3_ind_1/edges.shp"
              DC: {}  # data does not necessarily contain information for both types of district networks
            colors:
              dc: [63, 192, 194]
              dh: [240, 75, 91]
              disconnected: [68, 76, 83]
              district: [255, 255, 255]
            zone: str serialization of the GeoJSON of the zone.shp
            district: str serialization of the GeoJSON of the district.shp
            dc: str serialization of a GeoJSON containing both the nodes.shp + edges.shp of district cooling network
            dh: str serialization of a GeoJSON containing both the nodes.shp + edges.shp of district heating network

        :return: a str containing a full html ``<div/>`` that includes the js code to display the map.
        """
        import os
        import hashlib
        from jinja2 import Template
        template = os.path.join(os.path.dirname(__file__), "map_div.html")

        data = self.data_processing()

        zone = geopandas.GeoDataFrame.from_file(
            self.locator.get_zone_geometry()).to_crs(
                get_geographic_coordinate_system()).to_json(show_bbox=True)
        district = geopandas.GeoDataFrame.from_file(
            self.locator.get_surroundings_geometry()).to_crs(
                get_geographic_coordinate_system()).to_json(show_bbox=True)
        dc = self.get_network_json(data['DC']['path_output_edges'],
                                   data['DC']['path_output_nodes'])
        dh = self.get_network_json(data['DH']['path_output_edges'],
                                   data['DH']['path_output_nodes'])

        # Generate div id using hash of parameters
        with open(template, "r") as fp:
            div = Template(fp.read()).render(hash=hashlib.md5(
                repr(sorted(data.items())).encode("utf-8")).hexdigest(),
                                             data=json.dumps(data),
                                             colors=json.dumps(COLORS),
                                             zone=zone,
                                             district=district,
                                             dc=dc,
                                             dh=dh)
        return div
def geometry_extractor_osm(locator, config):
    """this is where the action happens if it is more than a few lines in ``main``.
    NOTE: ADD YOUR SCRIPT'S DOCUMENATION HERE (how)
    NOTE: RENAME THIS FUNCTION (SHOULD PROBABLY BE THE SAME NAME AS THE MODULE)
    """

    # local variables:
    buffer_m = config.surroundings_helper.buffer
    buildings_height = config.surroundings_helper.height_ag
    buildings_floors = config.surroundings_helper.floors_ag
    shapefile_out_path = locator.get_surroundings_geometry()
    zone = gdf.from_file(locator.get_zone_geometry())

    # trnasform zone file to geographic coordinates
    zone = zone.to_crs(get_geographic_coordinate_system())
    lon = zone.geometry[0].centroid.coords.xy[0][0]
    lat = zone.geometry[0].centroid.coords.xy[1][0]
    zone = zone.to_crs(get_projected_coordinate_system(float(lat), float(lon)))

    # get a polygon of the surrounding area, and one polygon representative of the zone area
    print("Calculating surrounding area")
    area_with_buffer = calc_surrounding_area(zone, buffer_m)

    # get footprints of all the surroundings
    print("Getting building footprints")
    area_with_buffer_polygon = area_with_buffer.to_crs(
        get_geographic_coordinate_system()).geometry.values[0]
    all_surroundings = osmnx.footprints.footprints_from_polygon(
        polygon=area_with_buffer_polygon)
    all_surroundings = all_surroundings.to_crs(
        get_projected_coordinate_system(float(lat), float(lon)))

    # erase overlapping area
    print("Removing unwanted buildings")
    surroundings = erase_no_surrounding_areas(all_surroundings, zone,
                                              area_with_buffer)

    assert surroundings.shape[
        0] > 0, 'No buildings were found within range based on buffer parameter.'

    # clean attributes of height, name and number of floors
    result = clean_attributes(surroundings,
                              buildings_height,
                              buildings_floors,
                              key="CEA")
    result = result.to_crs(
        get_projected_coordinate_system(float(lat), float(lon)))

    # save to shapefile
    result.to_file(shapefile_out_path)
    def edges_df(self):
        edges_df = geopandas.GeoDataFrame.from_file(
            self.locator.get_network_layout_edges_shapefile(self.network_type, self.network_name)).to_crs(
            get_geographic_coordinate_system())
        edges_df["_LineWidth"] = 0.1 * edges_df["Pipe_DN"]
        edges_df["length_m"] = edges_df["length_m"].round(1)

        # color the edges based on aggregated pipe heat loss
        P_loss_kPaperm_peak = (self.linear_pressure_loss_Paperm.max() / 1000).round(1) #to kPa/m
        Mass_flow_kgs_peak = self.mass_flow_kgs_pipes.max().round(1) #in kgs
        edges_df["Peak pressure loss [kPa/m]"] = P_loss_kPaperm_peak.values
        edges_df["Peak mass flow rate [kg/s]"] = Mass_flow_kgs_peak.values

        if self.velocity_mps_pipes is not None: #backward compatibility with detailed thermal network (which does not include this output)
            velocity_ms_peak = self.velocity_mps_pipes.max().round(1)  # in kgs
            edges_df["Peak velocity [m/s]"] = velocity_ms_peak.values

        # color the edges based on aggregated pipe heat loss
        if self.thermal_loss_edges_Wperm is not None: #backward compatibility with detailed thermal network (which does not include this output)
            yearly_thermal_loss = (self.thermal_loss_edges_Wperm.max()).round(2)
            edges_df["Peak Thermal losses [W/m]"] = yearly_thermal_loss.values

        # figure out colors
        p_loss_min = edges_df.Pipe_DN.min()
        p = edges_df.Pipe_DN.max()
        scale_p_loss = lambda x: remap(x, p_loss_min, p, 1.0, 1.0)
        min_rgb_mpl = [remap(c, 0.0, 255.0, 0.0, 1.0) for c in get_color_array("white")]
        max_rgb_mpl = [remap(c, 0.0, 255.0, 0.0, 1.0) for c in get_color_array("red")]

        edges_df["_FillColor"] = edges_df.Pipe_DN.apply(
            lambda p_loss: json.dumps(
                [remap(x, 0.0, 1.0, 0.0, 255.0)
                 for x in color_fader_rgb(min_rgb_mpl, max_rgb_mpl, mix=scale_p_loss(p_loss))])).values
        return edges_df
def get_longitude(scenario_path):
    import cea.inputlocator
    data = gdf.from_file(
        cea.inputlocator.InputLocator(scenario_path).get_zone_geometry())
    data = data.to_crs(get_geographic_coordinate_system())
    longitude = data.geometry[0].centroid.coords.xy[0][0]
    return longitude
def polygon_to_zone(buildings_floors, buildings_floors_below_ground,
                    buildings_height, buildings_height_below_ground, poly,
                    shapefile_out_path):
    poly = poly.to_crs(get_geographic_coordinate_system())
    lon = poly.geometry[0].centroid.coords.xy[0][0]
    lat = poly.geometry[0].centroid.coords.xy[1][0]
    # get footprints of all the district
    poly = osmnx.footprints.footprints_from_polygon(
        polygon=poly['geometry'].values[0])

    # clean geometries
    poly = clean_geometries(poly)

    # clean attributes of height, name and number of floors
    result, result_allfields = clean_attributes(poly,
                                                buildings_height,
                                                buildings_floors,
                                                buildings_height_below_ground,
                                                buildings_floors_below_ground,
                                                key="B")
    result = result.to_crs(
        get_projected_coordinate_system(float(lat), float(lon)))

    # save to shapefile
    result.to_file(shapefile_out_path)

    return result_allfields
Esempio n. 7
0
def route_project_overview():
    cea_config = current_app.cea_config
    project_path = cea_config.project
    project_name = os.path.basename(project_path)

    # Get the list of scenarios
    scenarios = get_scenarios(project_path)

    # Get scenario descriptions
    descriptions = {}
    for scenario in scenarios:
        descriptions[scenario] = {}
        locator = cea.inputlocator.InputLocator(os.path.join(project_path, scenario))
        zone = locator.get_zone_geometry()
        if os.path.isfile(zone):
            try:
                zone_df = geopandas.read_file(zone).to_crs(get_geographic_coordinate_system())
                descriptions[scenario]['Coordinates'] = (float("%.5f" % ((zone_df.total_bounds[1] + zone_df.total_bounds[3])/2)),
                                                     float("%.5f" % ((zone_df.total_bounds[0] + zone_df.total_bounds[2])/2)))
            except RuntimeError as e:
                descriptions[scenario]['Warning'] = 'Could not read the Zone file. ' \
                                                    'Check if your geometries have a coordinate system.'

        else:
            descriptions[scenario]['Warning'] = 'Zone file does not exist.'

    # Clean .cache images
    for filepath in glob.glob(os.path.join(os.path.join(project_path, '.cache', '*.png'))):
        print(filepath)
        image = os.path.basename(filepath).split('.')[0]
        if image not in scenarios:
            os.remove(filepath)


    return render_template('project_overview.html', project_name=project_name, scenarios=scenarios, descriptions=descriptions)
Esempio n. 8
0
def create_polygon(coordinate_tuple_list, output_path, filename):
    poly = Polygon(coordinate_tuple_list)
    gdf = gpd.GeoDataFrame([{'geometry': poly}])
    gdf.crs = get_geographic_coordinate_system()
    # Make sure directory exists
    os.makedirs(output_path, exist_ok=True)
    gdf.to_file(os.path.join(output_path, '{filename}.shp'.format(filename=filename)))
    print('Polygon `{filename}` created in {output_path}'.format(filename=filename, output_path=output_path))
Esempio n. 9
0
def calc_bounding_box(shapefile_district, shapefile_zone):
    #connect both files and avoid repetition
    data_zone = Gdf.from_file(shapefile_zone)
    data_dis = Gdf.from_file(shapefile_district)
    data_dis = data_dis.loc[~data_dis["Name"].isin(data_zone["Name"])]
    data = data_dis.append(data_zone, ignore_index=True, sort=True)
    data = data.to_crs(get_geographic_coordinate_system())
    result = data.total_bounds  # in float
    return result
Esempio n. 10
0
    def _plot_div_producer(self):
        """
        Since this plot doesn't use plotly to plot, we override _plot_div_producer to return a string containing
        the html div to use for this plot. The template ``network_plot.html`` expects some parameters:

        - hash: this is used to make the html id's in the plot unique
        - edges: a GeoJson serialization of the networks edges and data
        - nodes: a GeoJson serialization of the networks nodes and data,
        - colors: a JSON dictionary of [R, G, B] arrays for the colors to use
        - zone: a GeoJson serialization of the zone's buildings
        - district: a GeoJson serialization of the distrct's buildings

        :return: a str containing a full html ``<div/>`` that includes the js code to display the map.
        """

        import os
        import hashlib
        import random
        from jinja2 import Template

        zone_df = geopandas.GeoDataFrame.from_file(
            self.locator.get_zone_geometry()).to_crs(
                get_geographic_coordinate_system())
        zone_df["_FillColor"] = json.dumps(self.colors["zone"])
        zone = zone_df.to_json(show_bbox=True)

        district_df = geopandas.GeoDataFrame.from_file(
            self.locator.get_surroundings_geometry()).to_crs(
                get_geographic_coordinate_system())
        district_df["_FillColor"] = json.dumps(self.colors["district"])
        district = district_df.to_json(show_bbox=True)

        edges = self.edges_df.to_json(show_bbox=True)
        nodes = self.nodes_df.to_json(show_bbox=True)

        hash = hashlib.md5((str(random.random()) + edges +
                            nodes).encode("utf-8")).hexdigest()
        template = os.path.join(os.path.dirname(__file__), "network_plot.html")
        div = Template(open(template).read()).render(hash=hash,
                                                     edges=edges,
                                                     nodes=nodes,
                                                     zone=zone,
                                                     district=district)
        return div
Esempio n. 11
0
def df_to_json(file_location):
    try:
        table_df = geopandas.GeoDataFrame.from_file(file_location)
        from cea.utilities.standardize_coordinates import get_geographic_coordinate_system
        table_df = table_df.to_crs(get_geographic_coordinate_system(
        ))  # make sure that the geojson is coded in latitude / longitude
        return json.loads(table_df.to_json())
    except IOError as e:
        print(e)
        abort(404, 'Input file not found: %s' % file_location)
Esempio n. 12
0
    def get(self, scenario):
        project = request.args.get('project')
        if project is None:
            config = current_app.cea_config
        else:
            if not os.path.exists(project):
                abort(400, 'Project path: "{project}" does not exist'.format(project=project))
            config = cea.config.Configuration()
            config.project = project

        choices = list_scenario_names_for_project(config)
        if scenario in choices:
            locator = cea.inputlocator.InputLocator(os.path.join(config.project, scenario))
            zone_path = locator.get_zone_geometry()
            if os.path.isfile(zone_path):
                cache_path = os.path.join(config.project, '.cache')
                image_path = os.path.join(cache_path, scenario + '.png')

                zone_modified = os.path.getmtime(zone_path)
                if not os.path.isfile(image_path):
                    image_modified = 0
                else:
                    image_modified = os.path.getmtime(image_path)

                if zone_modified > image_modified:
                    # Make sure .cache folder exists
                    if not os.path.exists(cache_path):
                        os.makedirs(cache_path)

                    try:
                        zone_df = geopandas.read_file(zone_path)
                        zone_df = zone_df.to_crs(get_geographic_coordinate_system())
                        polygons = zone_df['geometry']

                        polygons = [list(polygons.geometry.exterior[row_id].coords) for row_id in range(polygons.shape[0])]

                        m = StaticMap(256, 160)
                        for polygon in polygons:
                            out = Polygon(polygon, 'blue', 'black', False)
                            m.add_polygon(out)

                        image = m.render()
                        image.save(image_path)
                    except Exception as e:
                        abort(400, str(e))

                import base64
                with open(image_path, 'rb') as imgFile:
                    image = base64.b64encode(imgFile.read())

                return {'image': image.decode("utf-8")}
            abort(400, 'Zone file not found')
        else:
            abort(400, 'Scenario does not exist', choices=choices)
Esempio n. 13
0
def calc_building_centroids(input_buildings_shp,
                            temp_path_building_centroids_shp,
                            list_district_scale_buildings,
                            plant_buildings,
                            consider_only_buildings_with_demand=False,
                            type_network="DH",
                            total_demand=False):
    # # get coordinate system and project to WSG 84
    zone_df = gdf.from_file(input_buildings_shp)
    zone_df = zone_df.loc[zone_df['Name'].isin(list_district_scale_buildings +
                                               plant_buildings)]
    zone_df = zone_df.reset_index(drop=True)

    # get only buildings with a demand, send out a message if there are less than 2 buildings.
    if consider_only_buildings_with_demand:
        total_demand = pd.read_csv(total_demand)
        if type_network == "DH":
            field = "QH_sys_MWhyr"
        elif type_network == "DC":
            field = "QC_sys_MWhyr"
        buildings_with_load = total_demand[
            total_demand[field] > 0.0].Name.tolist()
        selected_buildings = list(
            set(buildings_with_load).union(set(plant_buildings)))
        if len(selected_buildings) >= 2:
            zone_df = zone_df.loc[zone_df['Name'].isin(selected_buildings)]
            zone_df = zone_df.reset_index(drop=True)
        else:
            raise Exception(
                "We could not find two or more buildings with thermal energy demand the network layout "
                "will not work unless the consider_only_buildings_with_demand parameter is set to False"
            )

    zone_df = zone_df.to_crs(get_geographic_coordinate_system())
    lon = zone_df.geometry[0].centroid.coords.xy[0][0]
    lat = zone_df.geometry[0].centroid.coords.xy[1][0]

    # get coordinate system and re project to UTM
    zone_df = zone_df.to_crs(get_projected_coordinate_system(lat, lon))

    # create points with centroid
    points = zone_df.copy()
    points.geometry = zone_df['geometry'].centroid

    # # decrease the number of units of the points
    building_centroids_df = simplify_points_accurracy(points,
                                                      SHAPEFILE_TOLERANCE,
                                                      points.crs)

    # saving result
    building_centroids_df.to_file(temp_path_building_centroids_shp,
                                  driver='ESRI Shapefile')

    return building_centroids_df
Esempio n. 14
0
def route_save_building_properties():
    data = request.get_json()
    changes = data['changes']
    tables = data['tables']
    geojson = data['geojson']
    crs = data['crs']

    out = {'tables': {}, 'geojsons': {}}

    # TODO: Maybe save the files to temp location in case something fails
    locator = cea.inputlocator.InputLocator(current_app.cea_config.scenario)
    for db in INPUTS:
        db_info = INPUTS[db]
        location = getattr(locator, db_info['location'])()

        if len(tables[db]) != 0:
            if db_info['type'] == 'shp':
                from cea.utilities.standardize_coordinates import get_geographic_coordinate_system
                table_df = geopandas.GeoDataFrame.from_features(
                    geojson[db]['features'],
                    crs=get_geographic_coordinate_system())
                out['geojsons'][db] = json.loads(
                    table_df.to_json(show_bbox=True))
                table_df = table_df.to_crs(crs[db])
                table_df.to_file(location,
                                 driver='ESRI Shapefile',
                                 encoding='ISO-8859-1')

                table_df = pandas.DataFrame(table_df.drop(columns='geometry'))
                out['tables'][db] = json.loads(
                    table_df.set_index('Name').to_json(orient='index'))
            elif db_info['type'] == 'dbf':
                table_df = pandas.read_json(json.dumps(tables[db]))
                cea.utilities.dbf.dataframe_to_dbf(table_df, location)

                out['tables'][db] = json.loads(
                    table_df.set_index('Name').to_json(orient='index'))
        else:  # delete file if empty
            out['tables'][db] = {}
            if os.path.isfile(location):
                if db_info['type'] == 'shp':
                    import glob
                    for filepath in glob.glob(
                            os.path.join(
                                locator.get_building_geometry_folder(),
                                '%s.*' % db)):
                        os.remove(filepath)
                elif db_info['type'] == 'dbf':
                    os.remove(location)
            if db_info['type'] == 'shp':
                out['geojsons'][db] = {}

    return jsonify(out)
Esempio n. 15
0
def route_get_building_properties():
    import cea.glossary

    div = request.args.get('div', default=False)

    # FIXME: Find a better way to ensure order of tabs
    tabs = ['zone', 'age', 'occupancy', 'architecture', 'internal-loads', 'indoor-comfort', 'air-conditioning-systems',
            'supply-systems', 'emission-intensity', 'surroundings']

    locator = cea.inputlocator.InputLocator(current_app.cea_config.scenario)
    store = {'tables': {}, 'geojsons': {}, 'columns': {}, 'column_types': {}, 'crs': {}, 'glossary': {}}
    glossary = cea.glossary.read_glossary_df()
    for db in INPUTS:
        db_info = INPUTS[db]
        location = getattr(locator, db_info['location'])()
        try:
            if db_info['type'] == 'shp':

                from cea.utilities.standardize_coordinates import shapefile_to_WSG_and_UTM, \
                    get_geographic_coordinate_system
                table_df, lat, lon = shapefile_to_WSG_and_UTM(location)

                # save projected coordinate system
                store['crs'][db] = get_projected_coordinate_system(lat, lon)

                store['geojsons'][db] = json.loads(
                    table_df.to_crs(get_geographic_coordinate_system()).to_json(show_bbox=True))

                table_df = pandas.DataFrame(table_df.drop(columns='geometry'))
                if 'REFERENCE' in db_info['fieldnames'] and 'REFERENCE' not in table_df.columns:
                    table_df['REFERENCE'] = None
                store['tables'][db] = json.loads(table_df.set_index('Name').to_json(orient='index'))
            else:
                assert db_info['type'] == 'dbf', 'Unexpected database type: %s' % db_info['type']
                table_df = cea.utilities.dbf.dbf_to_dataframe(location)
                if 'REFERENCE' in db_info['fieldnames'] and 'REFERENCE' not in table_df.columns:
                    table_df['REFERENCE'] = None
                store['tables'][db] = json.loads(table_df.set_index('Name').to_json(orient='index'))

            store['columns'][db] = db_info['fieldnames']
            store['column_types'][db] = {k: v.__name__ for k, v in db_info['fieldtypes'].items()}

            filenames = glossary['FILE_NAME'].str.split(pat='/').str[-1]
            store['glossary'].update(json.loads(glossary[filenames == '%s.%s' % (db.replace('-', '_'), db_info['type'])]
                                                [['VARIABLE', 'UNIT', 'DESCRIPTION']].set_index('VARIABLE').to_json(
                orient='index')))

        except IOError as e:
            print(e)
            store['tables'][db] = {}
    return render_template('table.html' if not div else 'input_editor_electron.html',
                           store=store, tabs=tabs, last_updated=dir_last_updated())
    def _plot_div_producer(self):
        import os
        import hashlib
        from jinja2 import Template
        template = os.path.join(os.path.dirname(__file__), "map_div.html")

        data = self.data_processing()

        zone = geopandas.GeoDataFrame.from_file(self.locator.get_zone_geometry())\
            .to_crs(get_geographic_coordinate_system()).to_json(show_bbox=True)
        district = geopandas.GeoDataFrame.from_file(self.locator.get_district_geometry()) \
            .to_crs(get_geographic_coordinate_system()).to_json(show_bbox=True)
        dc = self.get_newtork_json(data['path_output_edges_DC'],
                                   data['path_output_nodes_DC'])
        dh = self.get_newtork_json(data['path_output_edges_DH'],
                                   data['path_output_nodes_DH'])

        # Generate div id using hash of parameters
        div = Template(open(template).read())\
            .render(hash=hashlib.md5(repr(sorted(data.items()))).hexdigest(), data=json.dumps(data), colors=COLORS,
                    zone=zone, district=district, dc=dc, dh=dh)
        return div
Esempio n. 17
0
def calc_connectivity_network(path_streets_shp, building_centroids_df, temp_path_potential_network_shp):
    """
    This script outputs a potential network connecting a series of building points to the closest street network
    the street network is assumed to be a good path to the district heating or cooling network

    :param path_streets_shp: path to street shapefile
    :param building_centroids_df: path to substations in buildings (or close by)
    :param path_potential_network: output path shapefile
    :return:
    """
    # first get the street network
    street_network = gdf.from_file(path_streets_shp)

    # check coordinate system
    street_network = street_network.to_crs(get_geographic_coordinate_system())
    lon = street_network.geometry[0].centroid.coords.xy[0][0]
    lat = street_network.geometry[0].centroid.coords.xy[1][0]
    street_network = street_network.to_crs(get_projected_coordinate_system(lat, lon))
    crs = street_network.crs

    street_network = simplify_liness_accurracy(street_network.geometry.values, SHAPEFILE_TOLERANCE, crs)

    # create terminals/branches form street to buildings
    prototype_network = create_terminals(building_centroids_df, crs, street_network)
    config = cea.config.Configuration()
    locator = cea.inputlocator.InputLocator(scenario=config.scenario)

    # first split in intersections
    prototype_network = one_linestring_per_intersection(prototype_network.geometry.values,
                                                        crs)
    # snap endings of all vectors to ending of all other vectors
    prototype_network = snappy_endings(prototype_network.geometry.values, SNAP_TOLERANCE, crs)

    # calculate intersections
    gdf_points_snapped = calculate_end_points_intersections(prototype_network, crs)

    # snap these points to the lines and transform lines
    gdf_points_snapped, prototype_network = snap_points(gdf_points_snapped, prototype_network, SNAP_TOLERANCE, crs)

    # save for verification purposes
    prototype_network.to_file(locator.get_temporary_file("prototype_network.shp"), driver='ESRI Shapefile')
    # get segments
    potential_network_df = split_line_by_nearest_points(prototype_network, gdf_points_snapped, 1.0, crs)

    # calculate Shape_len field
    potential_network_df["Shape_Leng"] = potential_network_df["geometry"].apply(lambda x: x.length)

    potential_network_df.to_file(temp_path_potential_network_shp, driver='ESRI Shapefile')

    return crs
Esempio n. 18
0
def calc_bounding_box_projected_coordinates(shapefile_zone, shapefile_surroundings):

    # connect both files and avoid repetition
    data_zone = Gdf.from_file(shapefile_zone)
    data_dis = Gdf.from_file(shapefile_surroundings)
    data_dis = data_dis.loc[~data_dis["Name"].isin(data_zone["Name"])]
    data = data_dis.append(data_zone, ignore_index = True, sort=True)
    data = data.to_crs(get_geographic_coordinate_system())
    lon = data.geometry[0].centroid.coords.xy[0][0]
    lat = data.geometry[0].centroid.coords.xy[1][0]
    crs = get_projected_coordinate_system(float(lat), float(lon))
    data = data.to_crs(get_projected_coordinate_system(float(lat), float(lon)))
    result = data.total_bounds
    result = [np.float32(x) for x in result]  # in float32 so the raster works
    return result, crs, lon, lat
def calc_substation_location(input_buildings_shp,
                             output_substations_shp,
                             connected_buildings,
                             consider_only_buildings_with_demand=False,
                             type_network="DH",
                             total_demand=False):
    # # get coordinate system and project to WSG 84
    poly = gdf.from_file(input_buildings_shp)
    if connected_buildings != []:
        # get only buildings described
        poly = poly.loc[poly['Name'].isin(connected_buildings)]
        poly = poly.reset_index(drop=True)

    # get only buildings with a demand, send out a message if there are less than 2 buildings.
    if consider_only_buildings_with_demand:
        total_demand = pd.read_csv(total_demand)
        if type_network == "DH":
            field = "QH_sys_MWhyr"
        elif type_network == "DC":
            field = "QC_sys_MWhyr"
        buildings_with_load_df = total_demand[total_demand[field] > 0.0]
        if buildings_with_load_df.shape[0] >= 2:
            buildings_with_load = buildings_with_load_df['Name'].tolist()
            poly = poly.loc[poly['Name'].isin(buildings_with_load)]
            poly = poly.reset_index(drop=True)
        else:
            raise Exception(
                "We could not find two or more buildings with thermal energy demand the network layout "
                "will not work unless the consider_only_buildings_with_demand parameter is set to False"
            )

    poly = poly.to_crs(get_geographic_coordinate_system())
    lon = poly.geometry[0].centroid.coords.xy[0][0]
    lat = poly.geometry[0].centroid.coords.xy[1][0]

    # get coordinate system and re project to UTM
    poly = poly.to_crs(get_projected_coordinate_system(lat, lon))

    # create points
    points = poly.copy()
    points.geometry = poly['geometry'].centroid

    # saving result
    points.to_file(output_substations_shp, driver='ESRI Shapefile')

    return points, poly
Esempio n. 20
0
def df_to_json(file_location, bbox=False):
    from cea.utilities.standardize_coordinates import get_lat_lon_projected_shapefile, get_projected_coordinate_system

    try:
        table_df = geopandas.GeoDataFrame.from_file(file_location)
        # Save coordinate system
        lat, lon = get_lat_lon_projected_shapefile(table_df)
        crs = get_projected_coordinate_system(lat, lon)
        # make sure that the geojson is coded in latitude / longitude
        out = table_df.to_crs(get_geographic_coordinate_system())
        out = json.loads(out.to_json(show_bbox=bbox))
        return out, crs
    except (IOError, DriverError) as e:
        print(e)
        return None, None
    except Exception as e:
        traceback.print_exc()
        return None, None
Esempio n. 21
0
def route_get_images(scenario):
    cea_config = current_app.cea_config
    project_path = cea_config.project
    locator = cea.inputlocator.InputLocator(
        os.path.join(project_path, scenario))
    zone_path = locator.get_zone_geometry()
    if not os.path.isfile(zone_path):
        abort(404, 'Zone file not found')
    cache_path = os.path.join(project_path, '.cache')
    image_path = os.path.join(cache_path, scenario + '.png')

    zone_modified = os.path.getmtime(zone_path)
    if not os.path.isfile(image_path):
        image_modified = 0
    else:
        image_modified = os.path.getmtime(image_path)

    if zone_modified > image_modified:
        # Make sure .cache folder exists
        if not os.path.exists(cache_path):
            os.makedirs(cache_path)

        zone_df = geopandas.read_file(zone_path)
        zone_df = zone_df.to_crs(get_geographic_coordinate_system())
        polygons = zone_df['geometry']

        polygons = [
            list(polygons.geometry.exterior[row_id].coords)
            for row_id in range(polygons.shape[0])
        ]

        m = StaticMap(256, 160)
        for polygon in polygons:
            out = Polygon(polygon, 'blue', 'black', False)
            m.add_polygon(out)

        image = m.render()
        image.save(image_path)

    import base64
    with open(image_path, 'rb') as imgFile:
        image = base64.b64encode(imgFile.read())
    return image
Esempio n. 22
0
def df_to_json(file_location, bbox=False, trigger_abort=True):
    from cea.utilities.standardize_coordinates import get_lat_lon_projected_shapefile, get_projected_coordinate_system
    try:
        table_df = geopandas.GeoDataFrame.from_file(file_location)
        # Save coordinate system
        lat, lon = get_lat_lon_projected_shapefile(table_df)
        crs = get_projected_coordinate_system(lat, lon)
        # make sure that the geojson is coded in latitude / longitude
        out = table_df.to_crs(get_geographic_coordinate_system())
        out = json.loads(out.to_json(show_bbox=bbox))
        return out, crs
    except IOError as e:
        print(e)
        if trigger_abort:
            abort(400, 'Input file not found: %s' % file_location)
    except RuntimeError as e:
        print(e)
        if trigger_abort:
            abort(400, e.message)
def calc_substation_location(input_buildings_shp, output_substations_shp, connected_buildings):

    # # get coordinate system and project to WSG 84
    poly = gdf.from_file(input_buildings_shp)
    if connected_buildings != []:
        #get only buildings
        poly = poly.loc[poly['Name'].isin(connected_buildings)]
        poly = poly.reset_index(drop=True)

    poly = poly.to_crs(get_geographic_coordinate_system())
    lon = poly.geometry[0].centroid.coords.xy[0][0]
    lat = poly.geometry[0].centroid.coords.xy[1][0]

    # get coordinate system and re project to UTM
    poly = poly.to_crs(get_projected_coordinate_system(lat, lon))

    # create points
    points = poly.copy()
    points.geometry = poly['geometry'].centroid

    # saving result
    points.to_file(output_substations_shp, driver='ESRI Shapefile')
Esempio n. 24
0
def calc_connectivity_network(path_streets_shp, path_connection_point_buildings_shp, path_potential_network):
    """
    This script outputs a potential network connecting a series of building points to the closest street network
    the street network is assumed to be a good path to the district heating or cooling network

    :param path_streets_shp: path to street shapefile
    :param path_connection_point_buildings_shp: path to substations in buildings (or close by)
    :param path_potential_network: output path shapefile
    :return:
    """
    # first get the building centroids and the street network
    buiding_centroids = gdf.from_file(path_connection_point_buildings_shp)
    street_network = gdf.from_file(path_streets_shp)

    # check coordinate system
    street_network = street_network.to_crs(get_geographic_coordinate_system())
    lon = street_network.geometry[0].centroid.coords.xy[0][0]
    lat = street_network.geometry[0].centroid.coords.xy[1][0]
    street_network = street_network.to_crs(get_projected_coordinate_system(lat, lon))
    crs = street_network.crs

    # # decrease the number of units of the points
    tolerance = 6
    buiding_centroids = simplify_points_accurracy(buiding_centroids, tolerance, crs)
    street_network = simplify_liness_accurracy(street_network.geometry.values, tolerance, crs)

    # create terminals/branches form street to buildings
    prototype_network = create_terminals(buiding_centroids, crs, street_network)
    config = cea.config.Configuration()
    locator=cea.inputlocator.InputLocator(scenario=config.scenario)
    prototype_network.to_file(locator.get_temporary_file("prototype_network.shp"), driver='ESRI Shapefile')


    # first split in intersections
    prototype_network = one_linestring_per_intersection(prototype_network.geometry.values,
                                                        crs)

    # snap endings of all vectors to ending of all other vectors
    prototype_network = snappy_endings(prototype_network.geometry.values, 0.5, crs)

    # calculate intersections
    gdf_points_snapped = calculate_end_points_intersections(prototype_network, crs)

    # snap these points to the lines and transform lines
    gdf_points_snapped, prototype_network = snap_points(gdf_points_snapped, prototype_network,
                                                        crs)
    # get segments
    gdf_segments = split_line_by_nearest_points(prototype_network, gdf_points_snapped, 1.0, crs)

    # calculate Shape_len field
    gdf_segments["Shape_Leng"] = gdf_segments["geometry"].apply(lambda x: x.length)

    # add length to segments
    # gdf_segments.plot()
    # import matplotlib.pyplot as plt
    # gdf_points.plot()
    # gdf_points_snapped.plot()
    # plt.show()
    # x=1
    gdf_segments.to_file(path_potential_network, driver='ESRI Shapefile')

    return crs
Esempio n. 25
0
def route_create_scenario_save():

    cea_config = current_app.cea_config

    # Make sure that the scenario folder exists
    try:
        os.makedirs(
            os.path.join(cea_config.project,
                         request.form.get('scenario-name')))
    except OSError as e:
        print(e.message)

    cea_config.scenario_name = request.form.get('scenario-name')
    cea_config.save()

    scenario_path = cea_config.scenario

    locator = cea.inputlocator.InputLocator(scenario_path)

    if request.form.get('input-files') == 'import':
        zone = request.form.get('zone')
        surroundings = request.form.get('surroundings')
        terrain = request.form.get('terrain')
        streets = request.form.get('streets')
        typology = request.form.get('typology')

        # since we're creating a new scenario, go ahead and and make sure we have
        # the folders _before_ we try copying to them
        locator.ensure_parent_folder_exists(locator.get_zone_geometry())
        locator.ensure_parent_folder_exists(locator.get_terrain())
        locator.ensure_parent_folder_exists(locator.get_building_typology())
        locator.ensure_parent_folder_exists(locator.get_street_network())

        if zone:
            for filename in glob_shapefile_auxilaries(zone):
                shutil.copy(filename, locator.get_building_geometry_folder())
        if surroundings:
            for filename in glob_shapefile_auxilaries(surroundings):
                shutil.copy(filename, locator.get_building_geometry_folder())
        if terrain:
            shutil.copyfile(terrain, locator.get_terrain())
        if streets:
            shutil.copyfile(streets, locator.get_street_network())

        if typology:
            shutil.copyfile(typology, locator.get_building_typology())
        elif zone:
            zone_df = geopandas.read_file(zone)
            if 'category' not in zone_df.columns:
                # set 'MULTI_RES' as default
                calculate_typology_file(zone_df, None, 'MULTI_RES',
                                        locator.get_building_typology())
            else:
                calculate_typology_file(zone_df, None,
                                        'Get it from open street maps',
                                        locator.get_building_typology())

    elif request.form.get('input-files') == 'copy':
        source_scenario = os.path.join(cea_config.project,
                                       request.form.get('scenario'))
        shutil.copytree(
            cea.inputlocator.InputLocator(source_scenario).get_input_folder(),
            locator.get_input_folder())

    elif request.form.get('input-files') == 'generate':
        tools = request.form.getlist('tools')
        if tools is not None:
            for tool in tools:
                if tool == 'zone-helper':
                    # FIXME: Setup a proper endpoint for site creation
                    data = json.loads(request.form.get('poly-string'))
                    site = geopandas.GeoDataFrame(
                        crs=get_geographic_coordinate_system(),
                        geometry=[shape(data['geometry'])])
                    site_path = locator.get_site_polygon()
                    locator.ensure_parent_folder_exists(site_path)
                    site.to_file(site_path)
                    print('site.shp file created at %s' % site_path)
                    cea.api.zone_helper(cea_config)
                elif tool == 'surroundings-helper':
                    cea.api.surroundings_helper(cea_config)
                elif tool == 'streets-helper':
                    cea.api.streets_helper(cea_config)
                elif tool == 'terrain-helper':
                    cea.api.terrain_helper(cea_config)
                elif tool == 'weather-helper':
                    cea.api.weather_helper(cea_config)

    return redirect(url_for('inputs_blueprint.route_get_building_properties'))
Esempio n. 26
0
    def post(self):
        """Create new scenario"""
        config = current_app.cea_config
        payload = api.payload
        new_scenario_path = os.path.join(config.project, payload['name'])

        # Make sure that the scenario folder exists
        try:
            os.makedirs(new_scenario_path)
        except OSError as e:
            print(e.message)

        locator = cea.inputlocator.InputLocator(new_scenario_path)

        # Run database_initializer to copy databases to input
        if 'databases-path' in payload:
            try:
                cea.api.data_initializer(
                    config,
                    scenario=new_scenario_path,
                    databases_path=payload['databases-path'])
            except Exception as e:
                trace = traceback.format_exc()
                return {
                    'message': 'data_initializer: {}'.format(e.message),
                    'trace': trace
                }, 500

        if payload['input-data'] == 'import':
            files = payload['files']

            if files is not None:
                try:
                    # since we're creating a new scenario, go ahead and and make sure we have
                    # the folders _before_ we try copying to them
                    locator.ensure_parent_folder_exists(
                        locator.get_zone_geometry())
                    locator.ensure_parent_folder_exists(locator.get_terrain())
                    locator.ensure_parent_folder_exists(
                        locator.get_building_typology())
                    locator.ensure_parent_folder_exists(
                        locator.get_street_network())

                    if 'zone' in files:
                        for filename in glob_shapefile_auxilaries(
                                files['zone']):
                            shutil.copy(filename,
                                        locator.get_building_geometry_folder())
                    if 'surroundings' in files:
                        for filename in glob_shapefile_auxilaries(
                                files['surroundings']):
                            shutil.copy(filename,
                                        locator.get_building_geometry_folder())
                    if 'terrain' in files:
                        shutil.copyfile(files['terrain'],
                                        locator.get_terrain())
                    if 'streets' in files:
                        shutil.copyfile(files['streets'],
                                        locator.get_street_network())

                    from cea.datamanagement.zone_helper import calculate_age, calculate_typology_file
                    if 'typology' in files and files['typology'] != '':
                        shutil.copyfile(files['typology'],
                                        locator.get_building_typology())
                    elif 'zone' in files:
                        zone_df = geopandas.read_file(files['zone'])
                        if 'category' not in zone_df.columns:
                            # set 'MULTI_RES' as default
                            calculate_typology_file(
                                locator, zone_df, None, 'MULTI_RES',
                                locator.get_building_typology())
                        else:
                            calculate_typology_file(
                                locator, zone_df, None,
                                'Get it from open street maps',
                                locator.get_building_typology())
                except Exception as e:
                    trace = traceback.format_exc()
                    return {'message': e.message, 'trace': trace}, 500

        elif payload['input-data'] == 'copy':
            try:
                source_scenario = os.path.join(config.project,
                                               payload['copy-scenario'])
                shutil.copytree(
                    cea.inputlocator.InputLocator(
                        source_scenario).get_input_folder(),
                    locator.get_input_folder())
            except OSError as e:
                trace = traceback.format_exc()
                return {'message': e.message, 'trace': trace}, 500

        elif payload['input-data'] == 'generate':
            tools = payload['tools']
            if tools is not None:
                for tool in tools:
                    try:
                        if tool == 'zone':
                            # FIXME: Setup a proper endpoint for site creation
                            site = geopandas.GeoDataFrame(
                                crs=get_geographic_coordinate_system(),
                                geometry=[
                                    shape(payload['geojson']['features'][0]
                                          ['geometry'])
                                ])
                            site_path = locator.get_site_polygon()
                            locator.ensure_parent_folder_exists(site_path)
                            site.to_file(site_path)
                            print('site.shp file created at %s' % site_path)
                            cea.api.zone_helper(config,
                                                scenario=new_scenario_path)
                        elif tool == 'surroundings':
                            cea.api.surroundings_helper(
                                config, scenario=new_scenario_path)
                        elif tool == 'streets':
                            cea.api.streets_helper(config,
                                                   scenario=new_scenario_path)
                        elif tool == 'terrain':
                            cea.api.terrain_helper(config,
                                                   scenario=new_scenario_path)
                        elif tool == 'weather':
                            cea.api.weather_helper(config,
                                                   scenario=new_scenario_path)
                    except Exception as e:
                        trace = traceback.format_exc()
                        return {
                            'message': '{}_helper: {}'.format(tool, e.message),
                            'trace': trace
                        }, 500

        return {'scenarios': list_scenario_names_for_project(config)}
Esempio n. 27
0
    def nodes_df(self):
        nodes_df = geopandas.GeoDataFrame.from_file(
            self.locator.get_network_layout_nodes_shapefile(
                self.network_type,
                self.network_name)).to_crs(get_geographic_coordinate_system())

        P_loss_kPa_peak = (self.pressure_at_nodes_Pa.max() / 1000).round(
            1)  #to kPa
        nodes_df["Peak pressure [kPa]"] = P_loss_kPa_peak.values

        #temperature at all nodes
        temperature_supply = self.temperature_supply_nodes_C.round(1)
        temperature_return = self.temperature_return_nodes_C.round(1)
        index_max = self.buildings_hourly.idxmax(axis=0)
        delta_T = (temperature_supply - temperature_return).round(1)

        #temperature at the plant
        index_max_T_plant = self.buildings_hourly.sum(axis=1).idxmax(axis=0)
        temperature_supply_plant = self.temperature_supply_return_plant_C[
            'temperature_supply_K'] - 273
        temperature_return_plant = self.temperature_supply_return_plant_C[
            'temperature_return_K'] - 273
        T_supply_peak = round(temperature_supply_plant[index_max_T_plant], 1)
        delta_T_peak = round((temperature_supply_plant -
                              temperature_return_plant)[index_max_T_plant], 1)

        #energy generation at the plant
        annual_loads = self.hourly_loads.values
        Q_loss_kWh = self.total_thermal_losses_kWh.values
        Peak_load_MWh = round((annual_loads + Q_loss_kWh).max() / 1000, 1)

        if self.mass_flow_kgs_nodes is not None:  #backward compatibility with detailed thermal network (which does not include this output)
            Mass_flow_kgs_peak = self.mass_flow_kgs_nodes.max().round(1)
            nodes_df["Peak mass flow rate [kg/s]"] = Mass_flow_kgs_peak.values

        peak_demands = self.buildings_hourly.apply(pd.Series.max)
        pumping_peak = self.plant_pumping_requirement_kWh.max().round(1)

        def get_peak_building_demand(row):
            if row["Type"] == "CONSUMER":
                return peak_demands[row["Building"]]
            else:
                return None

        def get_pumping_node(row):
            if row["Type"] == "PLANT":
                return pumping_peak[0]
            else:
                return None

        def get_T_plant_node(row):
            if row["Type"] == "PLANT":
                return T_supply_peak
            else:
                return None

        def get_Peak_plant_node(row):
            if row["Type"] == "PLANT":
                return Peak_load_MWh
            else:
                return None

        def get_DT_plant_node(row):
            if row["Type"] == "PLANT":
                return delta_T_peak
            else:
                return None

        def get_peak_supply_temp(row):
            if row["Building"] in index_max.index.values:
                return temperature_supply[row['Name']][index_max[
                    row["Building"]]]
            else:
                return None

        def get_peak_delta_temp(row):
            if row["Building"] in index_max.index.values:
                return delta_T[row['Name']][index_max[row["Building"]]]
            else:
                return None

        nodes_df["Peak Supply Temperature [C]"] = nodes_df.apply(
            get_peak_supply_temp, axis=1)
        nodes_df["Peak delta Temperature [C]"] = nodes_df.apply(
            get_peak_delta_temp, axis=1)
        nodes_df["Peak Thermal Demand [kW]"] = nodes_df.apply(
            get_peak_building_demand, axis=1)
        nodes_df["Pumping Power [kW]"] = nodes_df.apply(get_pumping_node,
                                                        axis=1)
        nodes_df["Supply Temperature [C]"] = nodes_df.apply(get_T_plant_node,
                                                            axis=1)
        nodes_df["Delta Temperature [C]"] = nodes_df.apply(get_DT_plant_node,
                                                           axis=1)
        nodes_df["Peak Thermal Generation [MW]"] = nodes_df.apply(
            get_Peak_plant_node, axis=1)

        nodes_df["_Radius"] = self.get_radius(nodes_df)

        # Figure out the colors (based on the average supply temperatures)
        P_loss_min = nodes_df["Peak Thermal Demand [kW]"].min()
        P_loss_max = nodes_df["Peak Thermal Demand [kW]"].max()
        scale_p_loss = lambda x: remap(x, P_loss_min, P_loss_max, 0.0, 1.0)

        # matplotlib works on RGB in ranges [0.0, 1.0] - scale the input colors to that, transform and then scale back
        # to web versions ([0, 255])
        min_rgb_mpl = [
            remap(c, 0.0, 255.0, 0.0, 1.0) for c in get_color_array("white")
        ]
        max_rgb_mpl = [
            remap(c, 0.0, 255.0, 0.0, 1.0) for c in get_color_array("red")
        ]

        nodes_df["Peak Thermal Demand [kW]"] = nodes_df[
            "Peak Thermal Demand [kW]"].fillna(0.0)
        nodes_df["_FillColor"] = json.dumps(get_color_array("black"))
        nodes_df["_FillColor"] = nodes_df["Peak Thermal Demand [kW]"].apply(
            lambda p_loss: json.dumps([
                remap(x, 0.0, 1.0, 0.0, 255.0) for x in color_fader_rgb(
                    min_rgb_mpl, max_rgb_mpl, mix=scale_p_loss(p_loss))
            ])).values

        return nodes_df
Esempio n. 28
0
    def put(self):
        form = api.payload
        config = current_app.cea_config
        locator = cea.inputlocator.InputLocator(config.scenario)

        tables = form['tables']
        geojsons = form['geojsons']
        crs = form['crs']
        schedules = form['schedules']

        out = {'tables': {}, 'geojsons': {}}

        # TODO: Maybe save the files to temp location in case something fails
        for db in INPUTS:
            db_info = INPUTS[db]
            location = getattr(locator, db_info['location'])()
            file_type = db_info['file_type']

            if len(tables[db]) != 0:
                if file_type == 'shp':
                    from cea.utilities.standardize_coordinates import get_geographic_coordinate_system
                    table_df = geopandas.GeoDataFrame.from_features(
                        geojsons[db]['features'],
                        crs=get_geographic_coordinate_system())
                    out['geojsons'][db] = json.loads(
                        table_df.to_json(show_bbox=True))
                    table_df = table_df.to_crs(crs[db])
                    table_df.to_file(location,
                                     driver='ESRI Shapefile',
                                     encoding='ISO-8859-1')

                    table_df = pandas.DataFrame(
                        table_df.drop(columns='geometry'))
                    out['tables'][db] = json.loads(
                        table_df.set_index('Name').to_json(orient='index'))
                elif file_type == 'dbf':
                    table_df = pandas.read_json(json.dumps(tables[db]),
                                                orient='index')

                    # Make sure index name is 'Name;
                    table_df.index.name = 'Name'
                    table_df = table_df.reset_index()

                    cea.utilities.dbf.dataframe_to_dbf(table_df, location)
                    out['tables'][db] = json.loads(
                        table_df.set_index('Name').to_json(orient='index'))

            else:  # delete file if empty
                out['tables'][db] = {}
                if os.path.isfile(location):
                    if file_type == 'shp':
                        import glob
                        for filepath in glob.glob(
                                os.path.join(
                                    locator.get_building_geometry_folder(),
                                    '%s.*' % db)):
                            os.remove(filepath)
                    elif file_type == 'dbf':
                        os.remove(location)
                if file_type == 'shp':
                    out['geojsons'][db] = {}

        if schedules:
            for building in schedules:
                schedule_dict = schedules[building]
                schedule_path = locator.get_building_weekly_schedules(building)
                schedule_data = schedule_dict['SCHEDULES']
                schedule_complementary_data = {
                    'MONTHLY_MULTIPLIER': schedule_dict['MONTHLY_MULTIPLIER'],
                    'METADATA': schedule_dict['METADATA']
                }
                data = pandas.DataFrame()
                for day in ['WEEKDAY', 'SATURDAY', 'SUNDAY']:
                    df = pandas.DataFrame({
                        'HOUR': range(1, 25),
                        'DAY': [day] * 24
                    })
                    for schedule_type, schedule in schedule_data.items():
                        df[schedule_type] = schedule[day]
                    data = data.append(df, ignore_index=True)
                save_cea_schedule(data.to_dict('list'),
                                  schedule_complementary_data, schedule_path)
                print('Schedule file written to {}'.format(schedule_path))
        return out
Esempio n. 29
0
    def get(self, scenario):
        building_limit = 500

        project = request.args.get('project')
        if project is None:
            config = current_app.cea_config
        else:
            if not os.path.exists(project):
                abort(
                    400, 'Project path: "{project}" does not exist'.format(
                        project=project))
            config = cea.config.Configuration()
            config.project = project

        choices = list_scenario_names_for_project(config)
        if scenario in choices:
            locator = cea.inputlocator.InputLocator(
                os.path.join(config.project, scenario))
            zone_path = locator.get_zone_geometry()
            if os.path.isfile(zone_path):
                cache_path = os.path.join(config.project, '.cache')
                image_path = os.path.join(cache_path, scenario + '.png')

                zone_modified = os.path.getmtime(zone_path)
                if not os.path.isfile(image_path):
                    image_modified = 0
                else:
                    image_modified = os.path.getmtime(image_path)

                if zone_modified > image_modified:
                    print(f'Generating preview image for scenario: {scenario}')
                    # Make sure .cache folder exists
                    os.makedirs(cache_path, exist_ok=True)

                    try:
                        zone_df = geopandas.read_file(zone_path)
                        zone_df = zone_df.to_crs(
                            get_geographic_coordinate_system())
                        polygons = zone_df['geometry']

                        m = StaticMap(256, 160)
                        if len(polygons) <= building_limit:
                            polygons = [
                                list(polygons.geometry.exterior[row_id].coords)
                                for row_id in range(polygons.shape[0])
                            ]
                            for polygon in polygons:
                                out = Polygon(polygon, 'blue', 'black', False)
                                m.add_polygon(out)
                        else:
                            print(
                                f'Number of buildings({len(polygons)}) exceed building limit({building_limit}): '
                                f'Generating simplified image')
                            # Generate only the shape outline of the zone area
                            convex_hull = polygons.unary_union.convex_hull
                            polygon = convex_hull.exterior.coords
                            out = Polygon(polygon, None, 'blue', False)
                            m.add_polygon(out)

                        image = m.render()
                        image.save(image_path)
                    except Exception as e:
                        abort(400, str(e))

                import base64
                with open(image_path, 'rb') as imgFile:
                    image = base64.b64encode(imgFile.read())

                return {'image': image.decode("utf-8")}
            abort(400, 'Zone file not found')
        else:
            abort(400, 'Scenario does not exist', choices=choices)
Esempio n. 30
0
    def post(self):
        """Create new scenario"""
        config = cea.config.Configuration()
        project = api.payload.get('project')
        if project is not None:
            config.project = project

        scenario_name = api.payload.get('scenario_name')
        if scenario_name is not None:
            new_scenario_path = os.path.join(config.project, str(scenario_name).strip())
            # Make sure that the scenario folder exists
            try:
                os.makedirs(new_scenario_path)
            except OSError as e:
                trace = traceback.format_exc()
                return {'message': e.message, 'trace': trace}, 500
        else:
            return {'message': 'scenario_name parameter cannot be empty'}, 500

        locator = cea.inputlocator.InputLocator(new_scenario_path)

        # Run database_initializer to copy databases to input
        databases_path = api.payload.get('databases_path')
        if databases_path is not None:
            try:
                cea.api.data_initializer(config, scenario=new_scenario_path, databases_path=databases_path)
            except Exception as e:
                trace = traceback.format_exc()
                return {'message': 'data_initializer: {}'.format(e.message), 'trace': trace}, 500

        input_data = api.payload.get('input_data')
        if input_data == 'import':
            files = api.payload.get('files')
            if files is not None:
                try:
                    cea.api.create_new_scenario(config,
                                                scenario=new_scenario_path,
                                                zone=files.get('zone'),
                                                surroundings=files.get('surroundings'),
                                                streets=files.get('streets'),
                                                terrain=files.get('terrain'),
                                                typology=files.get('typology'))
                except Exception as e:
                    trace = traceback.format_exc()
                    return {'message': 'create_new_scenario: {}'.format(e.message), 'trace': trace}, 500

        elif input_data == 'copy':
            source_scenario_name = api.payload.get('copy_scenario')
            try:
                source_scenario = os.path.join(config.project, source_scenario_name)
                shutil.copytree(cea.inputlocator.InputLocator(source_scenario).get_input_folder(),
                                locator.get_input_folder())
            except OSError as e:
                trace = traceback.format_exc()
                return {'message': e.message, 'trace': trace}, 500

        elif input_data == 'generate':
            tools = api.payload.get('tools')
            if tools is not None:
                for tool in tools:
                    try:
                        if tool == 'zone':
                            # FIXME: Setup a proper endpoint for site creation
                            site_geojson = api.payload.get('geojson')
                            if site_geojson is None:
                                raise ValueError('Could not find GeoJson for site polygon')
                            site = geopandas.GeoDataFrame(crs=get_geographic_coordinate_system(),
                                                          geometry=[shape(site_geojson['features'][0]['geometry'])])
                            site_path = locator.get_site_polygon()
                            locator.ensure_parent_folder_exists(site_path)
                            site.to_file(site_path)
                            print('site.shp file created at %s' % site_path)
                            cea.api.zone_helper(config, scenario=new_scenario_path)
                        elif tool == 'surroundings':
                            cea.api.surroundings_helper(config, scenario=new_scenario_path)
                        elif tool == 'streets':
                            cea.api.streets_helper(config, scenario=new_scenario_path)
                        elif tool == 'terrain':
                            cea.api.terrain_helper(config, scenario=new_scenario_path)
                        elif tool == 'weather':
                            cea.api.weather_helper(config, scenario=new_scenario_path)
                    except Exception as e:
                        trace = traceback.format_exc()
                        return {'message': '{}_helper: {}'.format(tool, e.message), 'trace': trace}, 500

        config.restricted_to = None
        return {'scenarios_list': list_scenario_names_for_project(config)}