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.")
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)
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()
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