Пример #1
0
    def __init__(self, *args):
        self.logger = logging.getLogger("logfile")
        try:
            # LF instantiates with args[0] = True
            # avoids circular relation and only locally import cDef
            import cDefinitions as cDef  # contains reach and feature definitions
            self.feat_id = args[0]
            self.features = cDef.FeatureDefinitions()
            self.feature_reader = cDef.FeatureReader()
        except:
            self.logger.info("ERROR: Invalid feature ID.")
            self.feat_id = ""
            self.features = ""
        self.all_row = {}
        self.thresh_row_dict = self.feature_reader.get_rows()
        # self.thresh_row_dict = {"d2w_low": 8, "d2w_up": 9, "det_low": 10, "det_up": 11, "u": 13, "h": 12, "Fr": 14,
        #                         "D": 15, "freq": 16, "mu_bad": 17, "mu_good": 18, "mu_method": 19, "sf": 20,
        #                         "inverse_tcd": 22, "fill": 23, "scour": 24, "S0": 21, "taux": 7, "lf": 25, "ds": 26,
        #                         "name": 4}
        self.unit_conv_candidates = [
            "d2w_low", "d2w_up", "det_low", "det_up", "u", "h", "D", "fill",
            "scour"
        ]
        self.thresh_xlsx = config.xlsx_thresholds

        try:
            self.wb = oxl.load_workbook(filename=self.thresh_xlsx,
                                        read_only=True,
                                        data_only=True)
            wb_open = True
        except:
            wb_open = False
            self.logger.info("ERROR: Could not open threshold_values.xlsx.")
        try:
            if wb_open:
                self.ws = self.wb['thresholds']
            else:
                self.ws = ""
        except:
            self.logger.info(
                "ERROR: Could not find sheet \'thresholds\' in threshold_values.xlsx."
            )

        # identify unit system
        try:
            unit_cell = self.ws.cell(row=self.thresh_row_dict['unit'],
                                     column=5).value
            if str(unit_cell).lower() == "u.s. customary":
                self.ft2m = 0.3047992
            else:
                self.ft2m = 1.0
        except:
            self.ft2m = 0.3047992
            self.logger.info(
                "WARNING: Could not identify unit system settings (use default = U.S. customary)."
            )
 def __init__(self, condition, feature_type, lf_dir):
     acceptable_types = [
         "terraforming", "plantings", "bioengineering", "connectivity"
     ]
     if feature_type in acceptable_types:
         Director.__init__(self, condition, lf_dir)
         self.logger.info("*** feature_type: " + str(feature_type))
         self.features = cDef.FeatureDefinitions()
         self.names = self.features.feat_class_name_dict[feature_type]
         self.shortnames = self.features.feat_class_id_dict[feature_type]
         self.ds_rasters = self.append_ds_rasters(self.shortnames)
         self.lf_rasters = self.append_lf_rasters(self.shortnames)
     else:
         self.logger.info("ERROR: Invalid keyword for feature type.")
Пример #3
0
    def __init__(self, feature_name, *sub_feature):
        # sub_feature = BOOL (optional)
        self.feats = cDef.FeatureDefinitions(False)
        self.sub = False
        self.name = feature_name
        self.id = self.feats.name_dict[feature_name]
        self.feat_lyr_type = self.set_feat_layer_type()

        if not sub_feature:
            if self.feats.col_name_dict[feature_name] in [
                    24, 25, 11, 12, 13, 14
            ]:
                self.sub = True
            else:
                self.feature = Feature(self.id)
        else:
            # sub_feature containing features (called in second iteration in feature_analysis.py)
            self.feature = Feature(self.id)
Пример #4
0
    def __init__(self, master=None):
        self.condition_list = fGl.get_subdir_names(config.dir2ra +
                                                   "01_Conditions\\")
        self.condition = ""
        self.errors = False
        self.features = cDef.FeatureDefinitions()
        self.feature_id_list = []
        self.feature_name_list = []
        self.logger = logging.getLogger("logfile")
        self.reaches = cDef.ReachDefinitions()
        self.reach_ids_applied = [
        ]  # self.reaches.id_xlsx ## initial: all reaches (IDs)
        self.reach_lookup_needed = False
        self.reach_names_applied = [
        ]  # self.reaches.names_xlsx ## initial: all reaches (full names)
        self.reach_template_dir = config.dir2mt + ".templates\\"
        self.reader = cRM.Read()
        self.unit = "us"
        self.q_unit = "cfs"
        self.h_unit = "ft"
        self.u_unit = "ft/s"
        self.verified = False
        self.ww = int()  # window width
        self.wh = int()  # window height
        self.wx = int()
        self.wy = int()
        self.xd = 5  # distance holder in x-direction (pixel)
        self.yd = 5  # distance holder in y-direction (pixel)

        # Construct the Frame object.
        tk.Frame.__init__(self, master)
        # if imported from master GUI, redefine master as highest level (ttk.Notebook tab container)
        if __name__ != '__main__':
            self.master = self.winfo_toplevel()
        self.pack(expand=True, fill=tk.BOTH)

        # tkinter standard object
        self.l_reaches = tk.Label(self)

        self.make_standard_menus()
def main(maxlf_dir=str(), min_lf=float(), prj_name=str(), unit=str(), version=str()):
    """ delineate optimum plantings
    required input variables:
    min_lf = minimum plant lifespan where plantings are considered
    prj_name = "TBR"  #  (corresponding to folder name)
    prj_name = "BartonsBar" (for example)
    unit = "us" or "si"
    version = "v10"  # type() =  3-char str: vII
    """
    logger = logging.getLogger("logfile")

    logger.info("PLACE OPTIMUM PLANT SPECIES ----- ----- ----- -----")
    features = cDef.FeatureDefinitions(False)  # read feature IDs (required to identify plants)

    if unit == "us":
        area_units = "SQUARE_FEET_US"
        ft2_to_acres = config.ft2ac
    else:
        area_units = "SQUARE_METERS"
        ft2_to_acres = 1.0
    arcpy.CheckOutExtension('Spatial')
    arcpy.gp.overwriteOutput = True

    path2pp = config.dir2pm + prj_name + "_" + version + "\\"

    # folder settings 
    ras_dir = path2pp + "Geodata\\Rasters\\"
    shp_dir = path2pp + "Geodata\\Shapefiles\\"
    quant_dir = path2pp + "Quantities\\"
    fGl.del_ovr_files(path2pp)  # Delete temporary raster calculator files

    # file settings
    xlsx_target = path2pp + prj_name + "_assessment_" + version + ".xlsx"

    action_ras = {}
    try:
        logger.info("Looking up MaxLifespan Rasters ...")
        arcpy.env.workspace = maxlf_dir
        action_ras_all = arcpy.ListRasters()
        logger.info(" >> Source directory: " + maxlf_dir)
        arcpy.env.workspace = path2pp + "Geodata\\"
        for aras in action_ras_all:
            for plant in features.id_list_plants:
                if plant in str(aras):
                    logger.info("   -- found: " + maxlf_dir + str(aras))
                    action_ras.update({aras: arcpy.Raster(maxlf_dir + aras)})
            if ("max" in str(aras)) and ("plant" in str(aras)):
                max_lf_plants = arcpy.Raster(maxlf_dir + aras)
        logger.info(" -- OK (read Rasters)\n")
    except:
        logger.info("ERROR: Could not find action Rasters.")
        return -1

    # CONVERT PROJECT SHAPEFILE TO RASTER
    try:
        logger.info("Converting Project Shapefile to Raster ...")
        arcpy.env.workspace = shp_dir
        arcpy.PolygonToRaster_conversion("ProjectArea.shp", "AreaCode", ras_dir + "ProjectArea.tif",
                                         cell_assignment="CELL_CENTER", priority_field="NONE", cellsize=1)
        logger.info(" -- OK. Loading project raster ...")
        arcpy.env.workspace = path2pp + "Geodata\\"
        prj_area = arcpy.Raster(ras_dir + "ProjectArea.tif")
        logger.info(" -- OK (Shapefile2Raster conversion)\n")
    except arcpy.ExecuteError:
        logger.info("ExecuteERROR: (arcpy).")
        logger.info(arcpy.GetMessages(2))
        arcpy.AddError(arcpy.GetMessages(2))
        return -1
    except Exception as e:
        logger.info("ExceptionERROR: (arcpy).")
        logger.info(e.args[0])
        arcpy.AddError(e.args[0])
        return -1
    except:
        logger.info("ExceptionERROR: (arcpy) Conversion failed.")
        return -1

    # CONVERT EXISTING PLANTS SHAPEFILE TO RASTER
    try:
        logger.info("Converting PlantExisting.shp Shapefile to Raster ...")
        arcpy.env.workspace = shp_dir
        arcpy.PolygonToRaster_conversion(shp_dir + "PlantExisting.shp", "gridcode", ras_dir + "PlantExisting.tif",
                                         cell_assignment="CELL_CENTER", priority_field="NONE", cellsize=1)
        arcpy.env.workspace = path2pp + "Geodata\\"
        logger.info(" -- OK (Shapefile2Raster conversion)\n")
    except arcpy.ExecuteError:
        logger.info("ExecuteERROR: (arcpy).")
        logger.info(arcpy.GetMessages(2))
        arcpy.AddError(arcpy.GetMessages(2))
        arcpy.CreateRasterDataset_management(ras_dir, "PlantExisting.tif", "1", "8_BIT_UNSIGNED", "World_Mercator.prj",
                                             "3", "", "PYRAMIDS -1 NEAREST JPEG",
                                             "128 128", "NONE", "")
    except Exception as e:
        logger.info("ExceptionERROR: (arcpy).")
        logger.info(e.args[0])
        arcpy.AddError(e.args[0])
    except:
        logger.info("WARNING: PlantExisting.shp is corrupted or non-existent.")
    logger.info(" >> Loading existing plant raster ...")
    existing_plants = arcpy.Raster(ras_dir + "PlantExisting.tif")

    # RETAIN RELEVANT PLANTINGS ONLY
    shp_4_stats = {}
    try:
        logger.info("Analyzing optimum plant types in project area ...")
        logger.info(" >> Cropping maximum lifespan Raster ... ")
        arcpy.env.extent = prj_area.extent
        max_lf_crop = Con((~IsNull(prj_area) & ~IsNull(max_lf_plants)), Con(IsNull(existing_plants), Float(max_lf_plants)))
        logger.info(" >> Saving crop ... ")
        max_lf_crop.save(ras_dir + "max_lf_pl_c.tif")
        logger.info(" -- OK ")
        occupied_px_ras = ""
        for aras in action_ras.keys():
            plant_ras = action_ras[aras]
            if not('.tif' in str(aras)):
                aras_tif = str(aras) + '.tif'
                aras_no_end = aras
            else:
                aras_tif = aras
                aras_no_end = aras.split('.tif')[0]
            logger.info(" >> Applying MaxLifespan Raster({}) where lifespan > {} years.".format(str(plant_ras), str(min_lf)))
            __temp_ras__ = Con((~IsNull(prj_area) & ~IsNull(plant_ras)), Con((Float(max_lf_plants) >= min_lf), (max_lf_plants * plant_ras)))
            if arcpy.Exists(occupied_px_ras):
                logger.info(" >> Reducing to relevant pixels only ... ")
                __temp_ras__ = Con((IsNull(occupied_px_ras) & IsNull(existing_plants)), __temp_ras__)
                occupied_px_ras = Con(~IsNull(occupied_px_ras), occupied_px_ras,  __temp_ras__)
            else:
                occupied_px_ras = __temp_ras__
                __temp_ras__ = Con(IsNull(existing_plants), __temp_ras__)
            logger.info(" >> Saving raster ... ")
            __temp_ras__.save(ras_dir + aras_tif)
            logger.info(" >> Converting to shapefile (polygon for area statistics) ... ")
            try:
                shp_ras = Con(~IsNull(__temp_ras__), 1, 0)
                arcpy.RasterToPolygon_conversion(shp_ras, shp_dir + aras_no_end + ".shp", "NO_SIMPLIFY")
            except:
                logger.info("     !! " + aras_tif + " is not suitable for this project.")
            arcpy.env.workspace = maxlf_dir
            logger.info(" >> Calculating area statistics ... ")
            try:
                arcpy.AddField_management(shp_dir + aras_no_end + ".shp", "F_AREA", "FLOAT", 9)
            except:
                logger.info("    * field F_AREA already exists ")
            try:
                arcpy.CalculateGeometryAttributes_management(shp_dir + aras_no_end + ".shp",
                                                             geometry_property=[["F_AREA", "AREA"]],
                                                             area_unit=area_units)
                shp_4_stats.update({aras: shp_dir + aras_no_end + ".shp"})
            except:
                shp_4_stats.update({aras: config.dir2pm + ".templates\\area_dummy.shp"})
                logger.info("     !! Omitting (not applicable) ...")
            arcpy.env.workspace = path2pp + "Geodata\\"
        logger.info(" -- OK (Shapefile and raster analyses)\n")
        logger.info("Calculating area statistics of plants to be cleared for construction ...")
        try:
            arcpy.AddField_management(shp_dir + "PlantClearing.shp", "F_AREA", "FLOAT", 9)
        except:
            logger.info("    * cannot add field F_AREA to %s (already exists?)" % str(shp_dir + "PlantClearing.shp"))
        try:
            arcpy.CalculateGeometryAttributes_management(shp_dir + "PlantClearing.shp",
                                                         geometry_property=[["F_AREA", "AREA"]],
                                                         area_unit=area_units)
            shp_4_stats.update({"clearing": shp_dir + "PlantClearing.shp"})
        except:
            shp_4_stats.update({"clearing": config.dir2pm + ".templates\\area_dummy.shp"})
            logger.info("    * no clearing applicable ")
        logger.info(" -- OK (Statistic calculation)\n")
    except arcpy.ExecuteError:
        logger.info("ExecuteERROR: (arcpy).")
        logger.info(arcpy.GetMessages(2))
        arcpy.AddError(arcpy.GetMessages(2))
        return -1
    except Exception as e:
        logger.info("ExceptionERROR: (arcpy).")
        logger.info(e.args[0])
        arcpy.AddError(e.args[0])
        return -1
    except:
        logger.info("ExceptionERROR: (arcpy) Conversion failed.")
        return -1

    # CLEAN UP useless shapefiles
    logger.info("Cleaning up redundant shapefiles ...")
    arcpy.env.workspace = shp_dir
    all_shps = arcpy.ListFeatureClasses()
    for shp in all_shps:
        if "_del" in str(shp):
            try:
                arcpy.Delete_management(shp)
            except:
                logger.info(str(shp) + " is locked. Remove manually to avoid confusion.")
    arcpy.env.workspace = path2pp + "Geodata\\"
    logger.info(" -- OK (Clean up)\n")

    # EXPORT STATISTIC TABLES
    logger.info("Exporting table statistics ...")
    stat_files = {}
    for ts in shp_4_stats.keys():
        try:
            logger.info(" >> Exporting " + str(shp_4_stats[ts]) + " area ...")
            arcpy.TableToTable_conversion(shp_4_stats[ts], quant_dir, "plant_" + ts + ".txt")
            stat_files.update({ts: quant_dir + "plant_" + ts + ".txt"})
        except:
            logger.info("    !! EXPORT FAILED (empty %s ?)" % str(ts))
    logger.info(" -- OK (Table export)\n")

    arcpy.CheckInExtension('Spatial')

    # PREPARE AREA DATA (QUANTITIES)
    logger.info("Processing table statistics ...")
    write_dict = {}
    for sf in stat_files.keys():
        stat_data = fGl.read_txt(stat_files[sf])
        logger.info("     --> Extracting relevant area ...")
        polygon_count = 0
        total_area_ft2 = 0.0
        for row in stat_data:
            if row[0] == 1:
                total_area_ft2 += row[1]
                polygon_count += 1
        write_dict.update({sf: total_area_ft2 * float(ft2_to_acres)})
        logger.info("     --> OK")
    logger.info(" -- OK (Area extraction finished).")

    # WRITE AREA DATA TO EXCEL FILE
    logger.info("Writing results ...")
    fGl.write_dict2xlsx(write_dict, xlsx_target, "B", "C", 4)

    logger.info(" -- OK (PLANT PLACEMENT FINISHED)\n")
    return ras_dir
    def __init__(self, from_master):
        sg.RaModuleGui.__init__(self, from_master)
        self.ww = 700  # window width
        self.wh = 490  # window height
        self.title = "Lifespan Design"
        self.set_geometry(self.ww, self.wh, self.title)

        self.condition_list = fGl.get_subdir_names(config.dir2conditions)
        self.condition_selected = False

        self.feature_list = []
        self.features = cDef.FeatureDefinitions(False)
        self.habitat = False
        self.manning_n = 0.0473934
        self.mapping = False
        self.out_lyt_dir = []
        self.out_ras_dir = []

        self.wild = False

        # GUI OBJECT VARIABLES
        self.gui_condition = tk.StringVar()
        self.gui_interpreter = tk.StringVar()
        self.extent_type = tk.StringVar()

        # LABELS
        self.l_s_feat = tk.Label(self, text="Selected features: ")
        self.l_s_feat.grid(sticky=tk.W,
                           row=0,
                           column=0,
                           padx=self.xd,
                           pady=self.yd)
        self.l_features = tk.Label(
            self,
            fg="red",
            text=
            "Choose from \'Add Features\' Menu (required for Raster Maker only)"
        )
        self.l_features.grid(sticky=tk.W,
                             row=0,
                             column=1,
                             columnspan=6,
                             padx=self.xd,
                             pady=self.yd)
        self.l_reach_label = tk.Label(self, text="Reaches:")
        self.l_reach_label.grid(sticky=tk.W,
                                row=1,
                                column=0,
                                columnspan=1,
                                padx=self.xd,
                                pady=self.yd * 2)
        self.l_reaches = tk.Label(
            self,
            fg="red",
            text="Select from Reaches menu (required for Raster Maker only)")
        self.l_reaches.grid(sticky=tk.W,
                            row=1,
                            column=1,
                            columnspan=6,
                            padx=self.xd,
                            pady=self.yd * 2)
        self.l_condition = tk.Label(self, text="Condition: \n")
        self.l_condition.grid(sticky=tk.W,
                              row=3,
                              column=0,
                              columnspan=3,
                              padx=self.xd,
                              pady=self.yd)
        self.b_v_condition = tk.Button(self,
                                       fg="red",
                                       text="Select",
                                       command=lambda: self.select_condition())
        self.b_v_condition.grid(sticky=tk.W,
                                row=3,
                                column=3,
                                padx=self.xd,
                                pady=self.yd)

        self.l_n = tk.Label(self,
                            text="Roughness (Manning\'s n): %.3f " %
                            self.manning_n)
        self.l_n.grid(sticky=tk.W,
                      row=10,
                      column=0,
                      columnspan=3,
                      padx=self.xd,
                      pady=self.yd)

        # DROP DOWN ENTRIES (SCROLL BARS)
        self.sb_condition = tk.Scrollbar(self, orient=tk.VERTICAL)
        self.sb_condition.grid(sticky=tk.W,
                               row=3,
                               column=2,
                               padx=0,
                               pady=self.yd)
        self.lb_condition = tk.Listbox(self,
                                       height=3,
                                       width=14,
                                       yscrollcommand=self.sb_condition.set)
        for e in self.condition_list:
            self.lb_condition.insert(tk.END, e)
        self.lb_condition.grid(sticky=tk.W,
                               row=3,
                               column=1,
                               padx=self.xd,
                               pady=self.yd)
        self.sb_condition.config(command=self.lb_condition.yview)
        self.b_ref_condition = tk.Button(
            self,
            text="Refresh list",
            command=lambda: self.refresh_conditions(
                self.lb_condition, self.sb_condition, config.dir2conditions))
        self.b_ref_condition.grid(sticky=tk.W,
                                  row=3,
                                  column=4,
                                  padx=self.xd,
                                  pady=self.yd)

        # BUTTONS
        self.b_mod_r = tk.Button(
            self,
            width=25,
            bg="white",
            text="Revise input file",
            command=lambda: self.open_inp_file("input_definitions.inp"))
        self.b_mod_r.grid(sticky=tk.EW,
                          row=5,
                          column=0,
                          columnspan=2,
                          padx=self.xd,
                          pady=self.yd)
        self.b_mod_r["state"] = "disabled"
        self.b_mod_m = tk.Button(
            self,
            width=25,
            bg="white",
            text="Modify map parameters",
            command=lambda: self.open_inp_file("mapping.inp"))
        self.b_mod_m.grid(sticky=tk.EW,
                          row=5,
                          column=2,
                          columnspan=2,
                          padx=self.xd,
                          pady=self.yd)
        self.b_mod_th = tk.Button(
            self,
            width=25,
            bg="white",
            text="Modify survival threshold values",
            command=lambda: self.open_inp_file("threshold_values"))
        self.b_mod_th.grid(sticky=tk.EW,
                           row=6,
                           column=0,
                           columnspan=2,
                           padx=self.xd,
                           pady=self.yd)
        self.b_mod_rea = tk.Button(self,
                                   width=25,
                                   bg="white",
                                   text="Modify river/reach extents",
                                   command=lambda: self.open_inp_file(
                                       "computation_extents.xlsx", "MT"))
        self.b_mod_rea.grid(sticky=tk.EW,
                            row=6,
                            column=2,
                            columnspan=2,
                            padx=self.xd,
                            pady=self.yd)
        self.b_n = tk.Button(self,
                             width=25,
                             bg="white",
                             text="Change / Info",
                             command=lambda: self.set_n())
        self.b_n.grid(sticky=tk.W,
                      row=10,
                      column=2,
                      columnspan=5,
                      padx=self.xd,
                      pady=self.yd)

        self.complete_menus()

        # CHECK BOXES(CHECKBUTTONS)
        self.cb_lyt = tk.Checkbutton(
            self,
            text="Include mapping after raster preparation",
            command=lambda: self.mod_mapping())
        self.cb_lyt.grid(sticky=tk.W,
                         row=7,
                         column=0,
                         columnspan=4,
                         padx=self.xd,
                         pady=self.yd)
        self.cb_wild = tk.Checkbutton(
            self,
            text="Apply wildcard raster to spatially confine analysis",
            command=lambda: self.mod_wild())
        self.cb_wild.grid(sticky=tk.W,
                          row=8,
                          column=0,
                          columnspan=5,
                          padx=self.xd,
                          pady=self.yd)

        self.cb_habitat = tk.Checkbutton(self,
                                         text="Apply habitat matching",
                                         command=lambda: self.mod_habitat())
        self.cb_habitat.grid(sticky=tk.W,
                             row=9,
                             column=0,
                             columnspan=5,
                             padx=self.xd,
                             pady=self.yd)
        self.cb_extent = tk.Checkbutton(
            self,
            text="Limit computation extent to boundary (boundary.tif) raster",
            variable=self.extent_type,
            onvalue="raster",
            offvalue="standard")
        self.cb_extent.grid(sticky=tk.W,
                            row=11,
                            column=0,
                            columnspan=5,
                            padx=self.xd,
                            pady=self.yd)
        self.cb_extent.deselect()
Пример #7
0
def make_output_dir(condition, reach_ids, habitat_analysis,
                    relevant_feat_names):
    # sets / creates a raster/shp/mxd/pdf output dir as a function of provided condition + feature layer type
    # condition = STR or number (will be converted to str)
    # reach_id = LIST from MT/.templates/computation_extents.xlsx
    # habitat_analysis = BOOL
    # relevant_feat_names = LIST with entries from LD/.templates/threshold_values.xlsx
    features = cDef.FeatureDefinitions()
    feat_id_list = []
    [
        feat_id_list.append(features.name_dict[item])
        for item in relevant_feat_names
    ]
    feat_col_list = []
    [
        feat_col_list.append(features.col_name_dict[item])
        for item in relevant_feat_names
    ]

    if reach_ids.__len__() == 1:
        if not str(reach_ids[0]) == "none":
            reach_name = "_" + str(reach_ids[0])
        else:
            reach_name = ""
    else:
        reach_name = "_all"

    type_int_list = []
    for tt in feat_col_list:
        if tt in features.threshold_cols_framework:
            type_int_list.append(1)
        if tt in features.threshold_cols_plants:
            type_int_list.append(2)
        if tt in features.threshold_cols_toolbox:
            type_int_list.append(2)
        if tt in features.threshold_cols_complement:
            type_int_list.append(3)
    try:
        feat_lyr_type = int(sum(type_int_list) / type_int_list.__len__())
    except:
        feat_lyr_type = 0

    if not habitat_analysis:
        # define output directory as a function of layer type
        if feat_lyr_type > 0:
            for i in range(0, 9):
                test_folder = str(condition) + reach_name + "_lyr" + str(
                    feat_lyr_type) + str(i)
                test_dir = config.dir2lf + "Output\\Rasters\\" + test_folder + "\\"
                if not os.path.exists(test_dir):
                    os.makedirs(test_dir)
                    output_dir = test_dir
                    break
                else:
                    files_exist = True  # basic assumption: a raster for the analyzed feature already exists
                    file_count = len([
                        name for name in os.listdir(test_dir)
                        if os.path.isfile(os.path.join(test_dir, name))
                    ])
                    if file_count < 9:
                        output_dir = test_dir
                        break
                    else:
                        file_names = []
                        [
                            file_names.append(fn)
                            for fn in os.listdir(test_dir)
                            if os.path.isfile(os.path.join(test_dir, fn))
                        ]
                        for f_id in feat_id_list:
                            for f_n in file_names:
                                if not (f_id in f_n):
                                    files_exist = False  # if any analyzed feature is not yet present, this folder is OK
                                    output_dir = test_dir
                                    break

                        if not files_exist:
                            break
                        if not (i < 9):
                            print(
                                "Maximum folder size for this layer reached -- restarting at lyrX0."
                            )
                            print(
                                "Consider better file structure; this time, old files are deleted."
                            )
                            test_folder = str(condition) + "_lyr" + str(
                                feat_lyr_type) + str(0)
                            output_dir = config.dir2lf + "Output\\Rasters\\" + test_folder + "\\"
                            break
        else:
            output_dir = config.dir2lf + "Output\\Rasters\\" + str(
                condition) + reach_name + "lyr00\\"
    else:
        output_dir = config.dir2lf + "Output\\Rasters\\" + str(
            condition) + reach_name + "_hab\\"

    if not ("output_dir" in locals()):
        print("No reach or feature layer or habitat_analysis information.")
        print("--> Output folder name corresponds to input condition.")
        output_dir = config.dir2lf + "Output\\Rasters\\" + str(
            condition) + "\\"

    chk_dir(output_dir)

    return output_dir
def raster_maker(condition, reach_ids, *args):
    # args[0] = feature_list (list from threshold_values.xlsx)
    # args[1] = mapping (True/False)
    # args[2] = habitat analysis (True/False)
    # args[3] = unit system ("us" or "si")
    # args[4] = wildcard raster application
    # args[5] = FLOAT manning n in s/m^(1/3)
    # args[6] = STR extent_type either "standard" (reaches) or "raster" (background raster)
    features = cDef.FeatureDefinitions(False)
    logger = logging.getLogger("logfile")
    if not args:
        # use general feature list and default settings if no arguments are provided
        feature_list = features.feature_name_list
        mapping = False
        habitat_analysis = False
        unit_system = "us"
        wildcard = False
    else:
        try:
            if args[0].__len__() > 0:
                feature_list = args[0]
            else:
                feature_list = features.feature_name_list
        except:
            # use simplified feature list
            feature_list = features.feature_name_list
        try:
            mapping = args[1]
            logger.info("Integrated mapping (layout creation) activated.")
        except:
            mapping = False
            logger.info("Integrated mapping deactivated.")
        try:
            habitat_analysis = args[2]
        except:
            habitat_analysis = False
            logger.info("Physical feature stability analysis only.")
        try:
            unit_system = args[3]
        except:
            unit_system = "us"
        try:
            wildcard = args[4]
        except:
            wildcard = False
        try:
            manning_n = float(args[5])
        except:
            manning_n = 0.0473934
        try:
            extent_type = str(args[6])
        except:
            extent_type = "standard"

    logger.info("lifespan_design.raster_maker initiated with feature list = " +
                str(feature_list) + "\nUnit system: " + str(unit_system))

    reach_reader = cRM.Read()
    reaches = cDef.ReachDefinitions()

    outputs = []

    for r in reach_ids:
        if reach_ids.__len__() < 8:
            reach_extents = reach_reader.get_reach_coordinates(
                reaches.dict_id_int_id[r])
        else:
            reach_extents = "MAXOF"
        output_dir = fGl.make_output_dir(condition, [r], habitat_analysis,
                                         feature_list)
        outputs.append(output_dir)
        # fGl.clean_dir(output_dir)
        for f in feature_list:
            logger.info(
                "----- ----- ----- ----- ----- ----- ----- ----- -----")
            if reach_extents == "MAXOF":
                logger.info("FEATURE: " + str(f))
            else:
                logger.info("FEATURE (REACH: " + reaches.dict_id_names[r] +
                            "): " + str(f))
            logger.info(
                "----- ----- ----- ----- ----- ----- ----- ----- -----")
            feature = cFe.FeatureContainer(
                f
            )  # instantiate object containing all restoration feature attributes

            if not feature.sub:
                analysis(feature.feature, condition, reach_extents,
                         habitat_analysis, output_dir, unit_system, wildcard,
                         manning_n, extent_type)
            else:
                sub_feature = cFe.FeatureContainer(f, feature.sub)
                analysis(sub_feature.feature, condition, reach_extents,
                         habitat_analysis, output_dir, unit_system, wildcard,
                         manning_n, extent_type)
        if reach_extents == "MAXOF":
            break

    logger.info("RASTERS FINISHED.")

    if mapping:
        outputs = map_maker(outputs)

    return outputs