def get_cen_latlon(curr_fdate, find_nearest_fdate=False): """ Using the TC vitals path for the storm, determine the center lat and lon If find_nearest_fdate is True and the `curr_fdate' is not in the vitals, find the nearest date :returns: 2-tuple consisting of center lat and lon """ args = dict(fdate=curr_fdate, stormId=storm_id) path = tc_vitals_path.format(**args) trk = trkutils.get_track_data(path) # map forecast dates to pycane.postproc.tracker.objects.TrackerEntry objects trk_fdates = trk.fcst_date_dict if curr_fdate in trk_fdates: nearest = curr_fdate elif find_nearest_fdate: nearest = min(trk_fdates.keys(), key=lambda d: abs(d - curr_fdate)) log.info("Current forecast date {0} is not in tc vitals. Using " " nearest date: {1}".format(curr_fdate, nearest)) else: raise Exception( "Current forecast date {0} is not in tc vitals".format(curr_fdate)) cenlat = trk_fdates[nearest].lat cenlon = trk_fdates[nearest].lon return (cenlat, cenlon)
interval = tdelta(hours=1) # Set the "initialization" dates, which will be used to calculate the # absolute dates. # get_geos5trk_track_data() will automatically set start_date to the first # date in the 'atcf' #paths[0].start_date = ... #paths[1].start_date = dtime(year=2006, month=9, day=4, hour=0) # set for gfdltrk too # how frequently to mark the line showing the track TIME_MARKER_INTERVAL = 6 log.basicConfig(level=log.DEBUG) for i, label in enumerate(names): log.info("processing %s @ %s" % (names[i], paths[i])) forecast_track = trkutils.get_track_data(paths[i]) times = [] datedict = forecast_track.fcst_date_dict trkdata_filtered = [] currdate = copy.copy(start_date) while currdate < end_date: trkdata = datedict[currdate] trkdata_filtered.append(trkdata) times.append(mpl_dates.date2num(currdate)) currdate += interval forecast_track.tracker_entries = trkdata_filtered #day_idc = [ idx for idx,val in enumerate(fhrs) if val%TIME_MARKER_INTERVAL == 0 ] plt.figure("tracks") #(lats,lons) = [(trkentry.lat,trkentry.lon) for trkentry in forecast_track.tracker_entries] lats = [trkentry.lat for trkentry in forecast_track.tracker_entries] lons = [trkentry.lon for trkentry in forecast_track.tracker_entries]
#for ctr,fmin in enumerate(range(FIRST_FHR, duration_minutes + 1, interval_mins)): ctr = first_fhr for fmin in range(first_fhr * 60, duration_minutes + 1, interval_mins): #fil.write("{0:04d} {1:05d}\n".format(ctr+1, fmin)) fil.write("{0:04d} {1:05d}\n".format(ctr, fmin)) # without enumerate ctr += int(input_frequency.total_seconds() / 3600) def run_tracker(): open("fort.14", "w").close() # TODO : need this for cyclogenesis if __name__ == "__main__": # Build ForecastTrack object and create fort.12 (tcvitals first guess) file args = dict(fdate=start_date, stormId=storm_id) path = tc_vitals_path.format(**args) trk = trkutils.get_track_data(path) trk.originating_center = 'AOML' trk.storm_number = storm_number trk.basin = storm_basin trk.dump_gfdltrk_fort12( outfile="fort.12" ) # TODO : GENERALIZE this function @ pycane - it's just atcf i think # TODO ? pass in fhr offset? (first_fhr) # Create NL # TODO - just use premade one for now create_links_and_index_files() create_fort15() run_tracker()
def read_config(self, config_file): ''' Read the given `config_file' and set member variables accordingly ''' BASIC_CONFIG_SECTION = 'basic_settings' DATA_CONFIG_SECTION = 'data_settings' PLOT_CONFIG_SECTION = 'plot_settings' MAP_CONFIG_SECTION = 'map_settings' STORM_CONFIG_SECTION = 'storm_settings' # read config file - if you get a TypeError you need a newer # version of Pyhon or a third-party ordered dictionary. The # OrderedDict is needed since the items() must be kept in order config = ConfigParser.ConfigParser(dict_type=OrderedDict) if not os.path.exists(config_file): logging.fatal("Specified/Default config file %s does not exist" %config_file) raise Exception("Specified/Default config file %s does not exist" %config_file) config.readfp(open(config_file)) # Set dataset-specific information datasets = [ v for (k,v) in config.items('dataset_names') ] data_paths = [ v for (k,v) in config.items('data_paths') ] plot_colors = [ v.replace("'","").replace('"','') for (k,v) in config.items('plot_colors') ] line_styles = [ v for (k,v) in config.items('line_styles') ] line_widths = [ float(v) for (k,v) in config.items('line_widths') ] assert len(datasets) > 0 assert len(datasets) == len(data_paths) assert len(plot_colors) == len(datasets) assert len(line_styles) == len(datasets) assert len(line_widths) == len(datasets) for path in data_paths: if not os.path.exists(path): self.log.error("Specified experiment path does not exist: {}" .format(path)) sys.exit(1) # Set basic configuration settings self.log_level = config.get(BASIC_CONFIG_SECTION, 'log_level') self.value_source = config.get(BASIC_CONFIG_SECTION, 'value_source') startDate = config.get(BASIC_CONFIG_SECTION, 'start_date') try: startDate = startDate.replace("'", "").replace('"', '') os.environ['TZ'] = 'UTC' tzset() self.start_date = mktime(strptime(startDate, '%m-%d-%Y %H:%M')) except ValueError: print 'Given start date', startDate, 'does not match expected format MM-DD-YYYY hh:mm' sys.exit(1) endDate = config.get(BASIC_CONFIG_SECTION, 'end_date') try: endDate = endDate.replace("'", "").replace('"', '') os.environ['TZ'] = 'UTC' tzset() self.end_date = mktime( strptime(endDate, '%m-%d-%Y %H:%M') ) except: # ValueError print 'Given end date', endDate, 'does not match expected format MM-DD-YYYY hh:mm' sys.exit(1) self.cycle_frequency = config.getfloat(BASIC_CONFIG_SECTION, 'cycle_frequency') * 3600.0 self.forecast_frequency = config.getfloat(BASIC_CONFIG_SECTION, 'forecast_frequency') * 3600.0 self.forecast_duration = config.getfloat(BASIC_CONFIG_SECTION, 'forecast_duration') * 3600.0 self.history_interval = config.getfloat(BASIC_CONFIG_SECTION, 'history_interval') * 3600.0 self.tracker = config.get(BASIC_CONFIG_SECTION, 'tracker') # storm settings self.storm_id = config.get(STORM_CONFIG_SECTION, 'storm_id') try: self.best_track_db_path = config.get(STORM_CONFIG_SECTION, "best_track_db_path") self.log.warn("Best_track was set. Will use this for truth_track. " "Hence the 'truth_tracker_data_file' and 'nature_run_tracker'" " options will be ignored".format()) # UPDATE : For NHC b-deck best tracks # TODO : Still want to support different kinds. I'm just hardcoding for B-deck here startYear = conversions.epoch_to_yyyymmddHHMM(self.start_date)[0:4] self.best_track_db_path = self.best_track_db_path.replace("{aY}", startYear) self.truth_track = trkutils.get_track_data(self.best_track_db_path, self.storm_id, self.start_date) """ # TODO : this cannot be instantiated here since it depends on the cycle date # and storm name ymdh = conversions.epoch_to_yyyymmddHHMM(self.start_date)[:-2] self.best_track_db_path = self.best_track_db_path.replace("{aYMDH}", ymdh) globs = glob.glob(self.best_track_db_path) print self.best_track_db_path assert len(globs) == 1 self.best_track_db_path = globs[0] self.truth_track = trkutils.get_track_data(self.best_track_db_path) """ except ConfigParser.NoOptionError: self.best_track_db_path = None try: # TODO : This actually isn't being used, it will always try to guess it # i.e. call trkutils.get_track_data() self.best_track_db_format = config.get(STORM_CONFIG_SECTION, 'best_track_db_format') except ConfigParser.NoOptionError: self.best_track_db_format = '_guess_it' # data settings self.average_type = config.get(DATA_CONFIG_SECTION, "average_type") if not self.average_type in ('mean', 'rmse'): raise Exception("Average type should be 'mean' or 'rmse'") self.difference_type = config.get(DATA_CONFIG_SECTION, "difference_type") if not self.difference_type in ("absolute", "relative"): raise Exception("Difference type should be 'absolute' or 'relative'") self.plot_flagged_tracker_entries = config.getboolean(DATA_CONFIG_SECTION, 'plot_flagged_tracker_entries') self.annotate_unflagged_entries = config.getboolean(DATA_CONFIG_SECTION, 'annotate_unflagged_entries') self.ignore_land_points = config.getboolean(DATA_CONFIG_SECTION, "ignore_land_points") # TODO : Unify the best track and truth track stuff. Leave this one as a # deprecated option if self.best_track_db_path is None: truthTrackFile = config.get(DATA_CONFIG_SECTION, 'truth_tracker_data_file') try: self.nature_run_tracker = config.get(DATA_CONFIG_SECTION, 'nature_run_tracker') except ConfigParser.NoOptionError: self.nature_run_tracker = '_guess_it' #import pdb ; pdb.set_trace() if self.nature_run_tracker == 'diapost': self.truth_track = trkutils.get_diapost_track_data(truthTrackFile) elif self.nature_run_tracker == 'nolan': self.truth_track = trkutils.get_nolan_track_data(truthTrackFile) elif self.nature_run_tracker == 'gfdl': self.truth_track = trkutils.get_gfdltrk_track_data(truthTrackFile) else: try: self.truth_track = trkutils.get_track_data(truthTrackFile) except: sys.stderr.writeln( ("Unable to determine ATCF type for best track/truth. Try" " to manually pass in via `nature_run_tracker'. Possible" " values are 'nolan', 'gfdl', and 'diapost'.")) sys.exit(1) # plot settings self.time_axis_parameter = config.get(PLOT_CONFIG_SECTION, 'time_axis_parameter') self.legend_position = config.get(PLOT_CONFIG_SECTION, 'legend_position') self.legend_alpha = config.getfloat(PLOT_CONFIG_SECTION, 'legend_alpha') self.plot_nature_values = config.getboolean(PLOT_CONFIG_SECTION, 'plot_nature_values') # since hex codes use hash symbol, they need to be quoted in config file self.nature_line_color = config.get(PLOT_CONFIG_SECTION, 'nature_line_color').replace("'", "") self.nature_line_style = config.get(PLOT_CONFIG_SECTION, 'nature_line_style').replace("'", "") self.hline_at_zero = config.getboolean(PLOT_CONFIG_SECTION, 'add_hline_at_zero') # TODO : make this optional, since it will be set in stylesheets anyway self.line_width = config.getfloat(PLOT_CONFIG_SECTION, 'line_width') # Set Styles. Specifically, set self.style_paths which will be a list # containing the paths to the styles to use. For now, this consists # of the style specified in the file <stylesheets_path>/general/<view_target>.mplstyle # and any extra style specified by parameter <stylesheets>. The latter having # higher priority. Eventually, method-specific styles will be supported, maybe. self.view_target = self._getopt(config, PLOT_CONFIG_SECTION, 'view_target', 'desktop') self.stylesheets_path = self._getopt(config, PLOT_CONFIG_SECTION, 'stylesheets_path', './conf/styles') generalStyle = os.path.join(self.stylesheets_path, 'general', self.view_target) # we're going to pass in an exact path, so the extension is required generalStyle = generalStyle + '.mplstyle' userStyles = self._getopt(config, PLOT_CONFIG_SECTION, 'stylesheets', None) if userStyles is None: self.style_paths = [generalStyle] else: userStyles = re.split(', | |,', userStyles) self.style_paths = [generalStyle].extend(userStyles) for i,path in enumerate(self.style_paths): if not os.path.exists(path): self.log.warn("Style sheet path {} does not exist!".format(path)) self.style_paths.pop(i) #sys.exit(133) #self.static_y_limit_track = config.getboolean(PLOT_CONFIG_SECTION, 'static_y_limit_track') self.static_y_limit_mslp_value = config.getboolean(PLOT_CONFIG_SECTION, 'static_y_limit_mslp') self.static_y_limit_maxwind_value = config.getboolean(PLOT_CONFIG_SECTION, 'static_y_limit_maxwind') self.static_y_limit_track_error = config.getboolean(PLOT_CONFIG_SECTION, 'static_y_limit_track_error') self.static_y_limit_mslp_error = config.getboolean(PLOT_CONFIG_SECTION, 'static_y_limit_mslp_error') self.static_y_limit_maxwind_error = config.getboolean(PLOT_CONFIG_SECTION, 'static_y_limit_maxwind_error') self.y_limits_track = self.get_list(config.get(PLOT_CONFIG_SECTION, 'y_limits_track'), minValues=2, maxValues=2) self.y_limits_mslp = self.get_list(config.get(PLOT_CONFIG_SECTION, 'y_limits_mslp'), minValues=2, maxValues=2) self.y_limits_maxwind = self.get_list(config.get(PLOT_CONFIG_SECTION, 'y_limits_maxwind'), minValues=2, maxValues=2) self.y_limits_track_error = self.get_list(config.get(PLOT_CONFIG_SECTION, 'y_limits_track_error'), minValues=2, maxValues=2) self.y_limits_mslp_error = self.get_list(config.get(PLOT_CONFIG_SECTION, 'y_limits_mslp_error'), minValues=2, maxValues=2) self.y_limits_maxwind_error = self.get_list(config.get(PLOT_CONFIG_SECTION, 'y_limits_maxwind_error'), minValues=2, maxValues=2) # # Process Map-related options # self.map_options = {} # settings that are parsed as lists self.map_options['padding'] = self.get_list(config.get(MAP_CONFIG_SECTION, 'padding'), cast=float, minValues=4, maxValues=4) # settings with string values for param in ('projection', 'resolution', 'latitude_label_mask', 'longitude_label_mask', 'ocean_color', 'lake_color', 'continents_fill_color', 'map_extents'): self.map_options[param] = config.get(MAP_CONFIG_SECTION, param) # populate all the boolean settings for param in ('draw_coastlines', 'draw_countries', 'get_extents_from_grib'): self.map_options[param] = config.getboolean(MAP_CONFIG_SECTION, param) #settings with integer values for param in ('latitude_line_freq', 'longitude_line_freq', 'track_plot_time_indicator_freq'): self.map_options[param] = int(config.get(MAP_CONFIG_SECTION, param)) # TODO : Don't need #draw_map_boundary : Use the 'water_color'/'map_boundary_color' ; #lake_color and continent_color can be used instead of fill_continents # # convert input # #label masks for param in ('latitude_label_mask', 'longitude_label_mask'): # convert label masks to list, as expected by drawparallels/meridians self.map_options[param] = self.get_list(self.map_options[param], cast=int, minValues=4, maxValues=4) # map extents self.map_options['map_extents'] = self.map_options['map_extents']\ .replace("'", "").replace('"', '') toks = self.map_options['map_extents'].strip().split() self.map_options['southern_latitude'] = float(toks[0]) self.map_options['western_longitude'] = float(toks[1]) self.map_options['northern_latitude'] = float(toks[2]) self.map_options['eastern_longitude'] = float(toks[3]) # padding #self.map_options['padding'] = \ #[x for x in self.map_options['padding'].strip().split(' ')] # validate input if not self.map_options['resolution'] in ('l', 'c', 'i', 'h', 'f'): raise Exception("Resolution in config file should be c/crude, "\ "l/low, i/intermediate, h/high, f/full") # populate list of DaffyExperimentDataset objects corresponding to the # datasets being plotted self.datasets = [] for i in range(len(datasets)): plot_options = {} plot_options['tracker'] = self.tracker plot_options['plot_flagged_tracker_entries'] = self.plot_flagged_tracker_entries plot_options['line_color'] = plot_colors[i] plot_options['line_style'] = line_styles[i] plot_options['line_width'] = line_widths[i] plot_options['annotate_unflagged_entries'] = self.annotate_unflagged_entries plot_options['hline_at_zero'] = self.hline_at_zero plot_options['ignore_land_points'] = self.ignore_land_points # Determine what system was used to run the experiment # and instantiate either DaffyExperimentDataset or PyHwrfExperimentDataset # For now, simply look for the gfdltrk product, since that should # probably exist for all experiments. exptTypeFound = False try: #import pdb ; pdb.set_trace() ds = DaffyExperimentDataset( name=datasets[i], path=data_paths[i], start_date=self.start_date, end_date=self.end_date, cycle_frequency=self.cycle_frequency, forecast_frequency=self.forecast_frequency, forecast_duration=self.forecast_duration, history_interval=self.history_interval, plot_options=plot_options, truth_track=self.truth_track) p = ds.products['gfdltrk_track'].get_path(cycle=self.end_date) exptTypeFound = True self.log.info("Guessing this is a DAFFY experiment based on "\ "existance of %s" %p) except (MissingProductException, AmbiguousProductException) as e: self.log.info("Assuming it's not a DAFFY experiment due to exc." "Original exception: {0}".format(e)) pass if not exptTypeFound: try: ds = PyHwrfExperimentDataset( name=datasets[i], path=data_paths[i], start_date=self.start_date, end_date=self.end_date, cycle_frequency=self.cycle_frequency, forecast_frequency=self.forecast_frequency, forecast_duration=self.forecast_duration, history_interval=self.history_interval, plot_options=plot_options, stormId=self.storm_id, best_track_path=self.best_track_db_path, truth_track=self.truth_track) p = ds.products['gfdltrk_track'].\ get_path(cycle=self.end_date) self.log.info("Guessing this is a PyHWRF experiment based "\ "on existance of %s" %p) exptTypeFound = True except (MissingProductException, AmbiguousProductException): pass if not exptTypeFound: try: ds = NmmbAutorunnerExperimentDataset( name=datasets[i], path=data_paths[i], start_date=self.start_date, end_date=self.end_date, cycle_frequency=self.cycle_frequency, history_interval=self.history_interval, forecast_frequency=self.forecast_frequency, forecast_duration=self.forecast_duration, plot_options=plot_options, stormId=self.storm_id, truth_track=self.truth_track, ) p = ds.products['diapost_track_domSpecific'].\ get_path(cycle=self.end_date, domain=2) exptTypeFound = True self.log.info("Guessing this is an NMM-B autorunner"\ " experiment based on existance of %s" %p) # TODO: unhack this. self.log.warn("Forcing 'tracker' for this Dataset to diapost, since that is all the NMMB autorunner supports") plot_options['tracker'] = 'diapost' except (MissingProductException, AmbiguousProductException): raise Exception("{} : Unable to determine experiment type " "from the last cycle's tracker output" "check that path to experiments and that " " settings in conf/<experiment_type>.cfg " " are correct". format(datasets[i])) self.datasets.append(ds)