def getRiskMXD(i, is_actuals, run_output, fire, extent, perim, score): """! Save risk map for given inputs @param i Index of simulation date to use @param is_actuals Whether or not simulation was run for actual weather @param run_output Folder simulation output was saved to @param fire Fire simulation was for @param extent Extent to use for map @param perim Perimeter to display on map @param score Score for given day @return Path used for saving output with given inputs @return MapDocument with opened output @return extent Extent that was applied to the map """ logging.debug("Running getRiskMXD() for {}".format(i)) prefix = 'actuals_' if is_actuals else 'wxshield_' map_output = getMapOutput(run_output) copyMXD = getRiskMXDName(i, is_actuals, run_output, fire, extent, perim) shutil.copyfile(os.path.join(Settings.HOME_DIR, "mxds", "rampart.mxd"), copyMXD) theMXD = arcpy.mapping.MapDocument(copyMXD) extent, prob = setDayCommon(i, is_actuals, theMXD, run_output, fire, perim, extent) prob_input = os.path.join(run_output, prob) total_path = os.path.join( map_output, prob_input.replace(prefix, 'RA_').replace('.asc', '.tif')) setDataSource(theMXD, "*Relative Risk*", total_path) setText(theMXD, "txtScore", score) arcpy.RefreshActiveView() theMXD.save() return copyMXD, theMXD, extent
def getFuelMXDName(fire_prefix, run_output, fire, extent, perim): """! Get path to save fuel map for given inputs to @param fire_prefix prefix to use for file name @param run_output Folder simulation output was saved to @param fire Fire simulation was for @param extent Extent to use for map @param perim Perimeter to display on map @return Path to use for saving output with given inputs """ map_output = getMapOutput(run_output) return os.path.join(map_output, fire_prefix + "_fuels.mxd")
def setDayCommon(i, is_actuals, theMXD, run_output, fire, perim, extent): """! Set common attributes on maps that are for a specific day @param i Index of date that map is for @param is_actuals Whether or not this is for actual weather @param theMXD mxd to apply settings to @param run_output Folder that simulation outputs are in @param fire Fire that simulation was for @param perim Perimeter to show on map @param extent Extent to apply to map @return Extent after applying to map @return Probability contour that was used """ prefix = 'actuals_' if is_actuals else 'wxshield_' fire_prefix = fire + "_" + ('actual_' if is_actuals else '') probs = [ x for x in os.listdir(os.path.join(Settings.HOME_DIR, run_output)) if x.startswith(prefix) and x[-3:] == "asc" ] day0 = find_day(probs[0]) - 1 jds = map(find_day, probs) dates = map(find_date, probs) days = map(lambda x: x - day0, jds) sim_output = readSimOutput(run_output) txtSize, txtAssumptions = getSizeAndAssumptions(i, sim_output, days, dates) map_output = getMapOutput(run_output) f = os.path.join( run_output, probs[i].replace(prefix, 'sizes_').replace('.asc', '.csv')) size_graph = makeSizeGraphName(f) setSourceImage(theMXD, "graph_stats", size_graph) prob_source = os.path.join( map_output, probs[i].replace(".asc", "_class_poly.shp").replace("-", "_")) low_prob = setDataSource(theMXD, "Low Probability", prob_source) gtr10 = setDataSource(theMXD, "> 10%", prob_source) df = arcpy.mapping.ListDataFrames(theMXD, "Layers")[0] df.spatialReference = arcpy.Describe(prob_source).spatialReference if not extent: # only set extent based on final map so that they all cover the same area #~ extent = gtr10.getSelectedExtent() extent = low_prob.getSelectedExtent() # HACK: do this here so the same extent gets applied to subsequent maps applyExtent(extent, theMXD, df.spatialReference) extent = df.extent setCommon(theMXD, fire + "\n" + dates[i] + ' - Day ' + str(days[i]), txtAssumptions, txtSize, run_output, fire, perim, extent, prob_source) return df.extent, probs[i]
def getProjectionMXDName(i, is_actuals, run_output, fire, extent, perim): """! Generate name of mxd to output to when using given parameters @param i index of date to use @param is_actuals Whether or not this is for actual observations @param run_output Folder that output is in @param fire Name of fire @param extent Extent to set on map @param perim Perimeter to use draw on map @return Name of mxd that would be output with given parameters """ prefix = 'actuals_' if is_actuals else 'wxshield_' fire_prefix = fire + "_" + ('actual_' if is_actuals else '') probs = [x for x in os.listdir(os.path.join(Settings.HOME_DIR, run_output)) if x.startswith(prefix) and x[-3:] == "asc"] map_output = getMapOutput(run_output) dates = map(find_date, probs) return os.path.join(map_output, fire_prefix + dates[i] + ".mxd")
def getRiskMXDName(i, is_actuals, run_output, fire, extent, perim): """! Get path to save risk map for given inputs to @param i Index of simulation date to use @param is_actuals Whether or not simulation was run for actual weather @param run_output Folder simulation output was saved to @param fire Fire simulation was for @param extent Extent to use for map @param perim Perimeter to display on map @return Path to use for saving output with given inputs """ prefix = 'actuals_' if is_actuals else 'wxshield_' fire_prefix = fire + "_" + ('actual_' if is_actuals else '') probs = [ x for x in os.listdir(os.path.join(Settings.HOME_DIR, run_output)) if x.startswith(prefix) and x[-3:] == "asc" ] map_output = getMapOutput(run_output) dates = map(find_date, probs) return os.path.join(map_output, fire_prefix + dates[i] + "_risk.mxd")
def getImpactMXD(fire_prefix, run_output, fire, extent, perim): """! Save impact map for given inputs @param fire_prefix prefix to use for file name @param run_output Folder simulation output was saved to @param fire Fire simulation was for @param extent Extent to use for map @param perim Perimeter to display on map @return Path used for saving output with given inputs @return MapDocument with opened output @return extent Extent that was applied to the map """ logging.debug("Called getImpactMXD()") sim_output = readSimOutput(run_output) map_output = getMapOutput(run_output) copyMXD = getImpactMXDName(fire_prefix, run_output, fire, extent, perim) shutil.copyfile(os.path.join(Settings.HOME_DIR, "mxds", "impact.mxd"), copyMXD) theMXD = arcpy.mapping.MapDocument(copyMXD) impact = Settings.RAMPART_MASK.format( 'high', findSuffix(findFuelRaster(sim_output))) setDataSource(theMXD, "*Potential Impact*", impact) txtAssumptions = ( "Potential Impact is based on staff assessment of impact on a 1 - 10 scale,\n" "representing the loss from the damage or disruption from various types of RA data\n" "burned with a 4000+ kW/m head fire intensity. Each cell is coloured based on the\n" "amount and type of RA within it. Potential Impact is the 'worst case'\n" "and the risk calculation on subsequent maps is a downscaling of this (e.g., burned\n" "with lower fire intensity and/or lower probability). Warning: use with caution and\n" "awareness of the assumptions and simplifications. Impact does not include indirect\n" "(e.g. smoke) or long-term effects. A hectare must burn in the model to show any risk;\n" "limitations of FireSTARR apply. RA may be missing from the GIS database, affecting\n" "results.") setCommon(theMXD, fire, txtAssumptions, " ", run_output, fire, perim, extent, impact) arcpy.RefreshActiveView() theMXD.save() return copyMXD, theMXD
def makeMaps(scenario, run_output, force_maps, hide): """! @param scenario Scenario to use settings from @param run_output Folder where simulation output resides @param force_maps Whether or not to force making maps if they already exist @param hide Whether or not to show perimeter closest to date on map @return Path to final output pdf """ import pdf from pdf import makePDF perimeters = PerimeterList(scenario.year, scenario.fire) sim_output = readSimOutput(run_output) startup = find_lines(sim_output, 'Startup indices ') startup = startup[0] if ( len(startup) > 0) else "Startup indices are not valid" prefix = 'actuals_' if scenario.actuals_only else 'wxshield_' fire_prefix = scenario.fire + "_" + ('actual_' if scenario.actuals_only else '') probs = [ x for x in os.listdir(os.path.join(Settings.HOME_DIR, run_output)) if x.startswith(prefix) and x[-3:] == "asc" ] day0 = find_day(probs[0]) - 1 jds = map(find_day, probs) dates = map(find_date, probs) days = map(lambda x: x - day0, jds) extent = None perim = None ensure_dir(scenario.outbase) out_dir = os.path.join(scenario.outbase, scenario.fire[:3]) ensure_dir(out_dir) for_time = os.path.basename(scenario.run_output) pdf_output = os.path.abspath( os.path.join(out_dir, fire_prefix + for_time + ".pdf")) copied = os.path.join(scenario.outbase, os.path.basename(pdf_output)) # HACK: if any one map is required then make them all if not (force_maps or not os.path.exists(pdf_output)): logging.info("Maps already exist for " + scenario.fire) return copied for_time = os.path.basename(scenario.run_output) mapflag = os.path.join(out_dir, scenario.fire + "_" + for_time + "_mapsinprogress") if os.path.exists(mapflag): logging.info("Maps already being made for " + scenario.fire) return copied write_file(os.path.dirname(mapflag), os.path.basename(mapflag), " ") map_output = getMapOutput(run_output) logging.info("Making maps for " + scenario.fire) # HACK: run in parallel but assume this works for now wxshield = getWxSHIELDFile(dates[0], scenario.fire, map_output) processes = [] run_what = r'python.exe firestarr\getWxshield.py {} {} {} {} {} "{}"'.format( scenario.lat, scenario.lon, dates[0], days[-1], scenario.fire, map_output) if 'overridden' in startup: startup_values = map(lambda x: x.strip(), startup[startup.find('(') + 1:-1].split(',')) logging.debug(startup_values) # HACK: just use known positions for now #~ (0.0mm, FFMC 92.0, DMC 59.0, DC 318.0) #~ print(startup_values[0][:-2], startup_values[1][5:].strip(), startup_values[2][4:].strip(), startup_values[0][3:].strip()) apcp = float(startup_values[0][:-2]) ffmc = float(startup_values[1][5:].strip()) dmc = float(startup_values[2][4:].strip()) dc = float(startup_values[3][3:].strip()) run_what += ' --apcp_0800 {} --ffmc {} --dmc {} --dc {}'.format( apcp, ffmc, dmc, dc) logging.debug(run_what) processes.append( start_process(run_what, Settings.PROCESS_FLAGS, Settings.HOME_DIR)) arcpy.env.overwriteOutput = True ensure_dir(os.path.dirname(out_dir)) ensure_dir(out_dir) # keep these until the end so they lock the file names mxd_paths = [] mxd_names = [] risk_paths = [] risk_names = [] scores = [] txtFuelRaster = find_line(sim_output, 'Fuel raster is ', 'Fuel raster is ') suffix = findSuffix(txtFuelRaster) env_push() png_processes = [] arcpy.env.scratchWorkspace = ensure_dir( arcpy.CreateScratchName(scenario.fire + os.path.basename(run_output), "", "Workspace", arcpy.GetSystemEnvironment('TEMP'))) for i in reversed(xrange(len(days))): f = os.path.join( run_output, probs[i].replace(prefix, 'sizes_').replace('.asc', '.csv')) run_what = r'python.exe firestarr\plotsize.py "{}" "{}"'.format( f, days[i]) png_processes = [ start_process(run_what, Settings.PROCESS_FLAGS, Settings.HOME_DIR) ] + png_processes for i in reversed(xrange(len(days))): finish_process(png_processes[i]) arcpy.env.addOutputsToMap = False prob_input = os.path.join(run_output, probs[i]) c_prob = arcpy.sa.Int(arcpy.sa.Raster(prob_input) * 10) shp_class = os.path.join( map_output, probs[i].replace(".asc", "_class_poly.shp").replace("-", "_")) # keep getting 'WARNING: Error of opening hash table for code page.' when we save to file plan poly = "in_memory\poly" logging.debug("Converting to polygon") arcpy.RasterToPolygon_conversion(c_prob, poly, "SIMPLIFY") del c_prob #~ print(shp_class) arcpy.CopyFeatures_management(poly, shp_class) del poly perim = None if hide else perimeters.find_perim( scenario.fire, dates[i]) copyMXD = None if len(days) - 1 == i: # we need to get the extent from the last map copyMXD, theMXD, extent = getProjectionMXD(i, scenario.actuals_only, scenario.run_output, scenario.fire, extent, perim) run_what = r'python.exe firestarr\saveboth.py "{}" "{}"'.format( copyMXD, fire_prefix + dates[i] + ".png") processes.append( start_process(run_what, Settings.PROCESS_FLAGS, Settings.HOME_DIR)) del theMXD run_what = r'python.exe firestarr\assets.py {} "{}" {} "{}" {}'.format( i, scenario.run_output, scenario.fire, extent, prefix) else: copyMXD = getProjectionMXDName(i, scenario.actuals_only, scenario.run_output, scenario.fire, extent, perim) run_what = r'python.exe firestarr\getProjectionMXD.py {} "{}" {} "{}"'.format( i, scenario.run_output, scenario.fire, extent) if scenario.actuals_only: run_what += ' --actuals' if perim: run_what += ' --perim "{}"'.format(perim) processes.append( start_process(run_what, Settings.PROCESS_FLAGS, Settings.HOME_DIR)) mxd_paths = [copyMXD] + mxd_paths mxd_names = [fire_prefix + dates[i] + ".png"] + mxd_names start_raster = os.path.join(run_output, scenario.fire + '.tif') fire_raster = None if os.path.exists(start_raster): fire_raster = arcpy.sa.Raster(start_raster) # need to make sure the extent is the same for all rasters or they don't add properly env_push() setSnapAndExtent(prob_input) def by_intensity(intensity): letter = intensity.upper()[0] prob_i = os.path.join( run_output, prob_input.replace(prefix, 'intensity_{}_'.format(letter))) ra = Settings.RAMPART_MASK.format(intensity, suffix) logging.debug(prob_i) raster = arcpy.sa.Int( arcpy.sa.Raster(prob_i) * arcpy.sa.Raster(ra)) if fire_raster is not None: # don't count anything in the starting perimeter # HACK: will not consider fires that start from just a size raster = arcpy.sa.Con(arcpy.sa.IsNull(fire_raster), raster, 0) raster = arcpy.sa.Con(arcpy.sa.IsNull(raster), 0, raster) return raster low_raster = by_intensity('low') moderate_raster = by_intensity('moderate') high_raster = by_intensity('high') total_raster = low_raster + moderate_raster + high_raster total_raster = arcpy.sa.SetNull(0 == total_raster, total_raster) total_path = os.path.join( map_output, prob_input.replace(prefix, 'RA_').replace('.asc', '.tif')) total_raster.save(total_path) del low_raster del moderate_raster del high_raster score = arcpy.RasterToNumPyArray(total_raster, nodata_to_value=0).sum() # .58 so that 10 for social & economic gives a 10 total score score = fixK(score / 1000000.0 / 0.58) env_pop() run_what = r'python.exe firestarr\getRiskMXD.py {} "{}" {} "{}" "{}"'.format( i, scenario.run_output, scenario.fire, extent, score) if scenario.actuals_only: run_what += ' --actuals' if perim: run_what += ' --perim "{}"'.format(perim) processes.append( start_process(run_what, Settings.PROCESS_FLAGS, Settings.HOME_DIR)) copyMXD = getRiskMXDName(i, scenario.actuals_only, scenario.run_output, scenario.fire, extent, perim) risk_paths = [copyMXD] + risk_paths risk_names = [ os.path.join(os.path.dirname(copyMXD), fire_prefix + dates[i] + "_risk.png") ] + risk_names scores = [score] + scores env_pop() copyMXD = getFuelMXDName(fire_prefix, scenario.run_output, scenario.fire, extent, perim) run_what = r'python.exe firestarr\getFuelMXD.py {} "{}" {} "{}"'.format( fire_prefix, scenario.run_output, scenario.fire, extent) if perim: run_what += ' --perim "{}"'.format(perim) processes.append( start_process(run_what, Settings.PROCESS_FLAGS, Settings.HOME_DIR)) mxd_paths = [copyMXD] + mxd_paths mxd_names = [fire_prefix + "_fuels.png"] + mxd_names mxd_names = map(lambda x: os.path.abspath(os.path.join(map_output, x)), mxd_names) copyMXD = getImpactMXDName(fire_prefix, scenario.run_output, scenario.fire, extent, perim) run_what = r'python.exe firestarr\getImpactMXD.py {} "{}" {} "{}"'.format( fire_prefix, scenario.run_output, scenario.fire, extent) if perim: run_what += ' --perim "{}"'.format(perim) processes.append( start_process(run_what, Settings.PROCESS_FLAGS, Settings.HOME_DIR)) risk_paths = [copyMXD] + risk_paths risk_names = [ os.path.join(os.path.dirname(copyMXD), fire_prefix + "_impact.png") ] + risk_names for process in processes: finish_process(process) # HACK: put in not generated images for any missing maps if len(mxd_names) < 6: mxd_names = ( mxd_names + [os.path.join(Settings.HOME_DIR, 'not_generated.png')] * 6)[:6] if len(risk_names) < 6: risk_names = ( risk_names + [os.path.join(Settings.HOME_DIR, 'not_generated.png')] * 6)[:6] logging.debug(mxd_names + [wxshield] + risk_names) makePDF(scenario.fire, days, dates, mxd_names, wxshield, risk_names, sim_output, pdf_output, scores) try_copy(pdf_output, copied) # HACK: use known file name for assets csv_orig = os.path.abspath( os.path.join(run_output, fire_prefix + for_time + "_assets.csv")) csv_output = os.path.abspath( os.path.join(out_dir, os.path.basename(csv_orig))) csv_copied = os.path.join(scenario.outbase, os.path.basename(csv_orig)) try_copy(csv_orig, csv_output) try_copy(csv_orig, csv_copied) fixtime(scenario.fire, parse(for_time.replace('_', ' ')), [pdf_output, copied, csv_orig, csv_copied]) try: tryForceRemove(mapflag) except: pass # shouldn't need any of these intermediary outputs shutil.rmtree(map_output, True) return copied