|
8 | 8 | import os |
9 | 9 | import pandas as pd |
10 | 10 | from schimpy.param import * |
11 | | -from vtools import days |
| 11 | +from vtools import days,seconds |
12 | 12 |
|
13 | 13 |
|
14 | 14 |
|
| 15 | +def expected_hotstarts(run_start, dt, nday, hot_freq): |
| 16 | + """ |
| 17 | + Generate expected hotstarts based on run parameters. |
| 18 | + Parameters |
| 19 | + ---------- |
| 20 | + run_start : datetime |
| 21 | + The start time of the simulation run. |
| 22 | + dt : int |
| 23 | + The time step in seconds. |
| 24 | + nday : int |
| 25 | + The number of days for the simulation run. |
| 26 | + hot_freq : pandas.tseries.offsets.DateOffset |
| 27 | + The frequency at which hotstarts are generated. |
| 28 | + Returns |
| 29 | + ------- |
| 30 | + pandas.DataFrame |
| 31 | + A DataFrame with a DatetimeIndex representing the expected hotstart times |
| 32 | + and a column "iteration" indicating the corresponding iteration numbers. |
| 33 | + Notes |
| 34 | + ----- |
| 35 | + This function calculates the expected hotstart times and their corresponding |
| 36 | + iteration numbers based on the provided simulation parameters. It does not |
| 37 | + perform any file inventory or check for existing hotstart files. |
| 38 | + """ |
| 39 | + """Generate expected hotstarts based on run parameters.""" |
| 40 | + |
| 41 | + end = run_start + days(nday) |
| 42 | + t = run_start |
| 43 | + iters = [] |
| 44 | + times = [] |
| 45 | + dt_freq = pd.tseries.offsets.Second(dt) |
| 46 | + iters_per_hot = hot_freq / dt_freq |
| 47 | + itr = 0 |
| 48 | + print("Projected hotstarts (not inventory of files)") |
| 49 | + while t < end: |
| 50 | + times.append(t) |
| 51 | + iters.append(itr) |
| 52 | + t = t + hot_freq |
| 53 | + itr = itr + int(iters_per_hot) |
| 54 | + print(f"t={t}, itr={itr}") |
| 55 | + ndx = pd.DatetimeIndex(times) |
| 56 | + df = pd.DataFrame(index=ndx, data=iters) |
| 57 | + df.columns = ["iteration"] |
| 58 | + df.index.name = "datetime" |
| 59 | + return df |
| 60 | + |
| 61 | + |
15 | 62 | def hotstart_inventory(run_start=None, |
16 | 63 | dt=None, |
17 | 64 | nday=None, |
18 | 65 | workdir='.', |
19 | 66 | paramfile=None, |
20 | | - hot_freq=None |
21 | | - ): |
22 | | - """ Create an inventory of existing hotstarts or expected hotstarts |
| 67 | + hot_freq=None, |
| 68 | + expected=False): |
| 69 | + """ |
| 70 | + Create an inventory of existing hotstarts or expected hotstarts. |
| 71 | +
|
| 72 | + Whether the inventory is for existing or expected hotstarts depends on |
| 73 | + whether the workdir is an outputs directory or a study directory. |
23 | 74 |
|
24 | | - Existing vs expected depends on whether workdir is an outputs or study dir. |
25 | | - |
26 | 75 | Parameters |
27 | 76 | ---------- |
| 77 | + run_start : str or pandas.Timestamp, optional |
| 78 | + The start time of the simulation run in ISO-like format (e.g., '2013-12-03'). |
| 79 | + dt : int, optional |
| 80 | + The time step in seconds of the model. Default is None. |
| 81 | + nday : int, optional |
| 82 | + The number of days in the simulation run or the maximum to catalog. Default is None. |
| 83 | + workdir : str, optional |
| 84 | + The working directory, which may be a launch or outputs directory. Default is '.'. |
| 85 | + paramfile : str, optional |
| 86 | + The name of the param.nml file if it is used to infer runtime. Default is None. |
| 87 | + hot_freq : str or pandas.tseries.offsets.DateOffset, optional |
| 88 | + The hotstart frequency in pandas frequency terms (e.g., '5D'). Default is None. |
| 89 | + expected : bool, optional |
| 90 | + Flag to generate expected hotstarts instead of an inventory of existing files. Default is False. |
28 | 91 |
|
29 | | - start : Convertible to Datetime |
30 | | - Start date of run. If None inferred from paramfile. Error if |
31 | | - |
32 | | - dt : float |
33 | | - dt in seconds, for instance perhaps 90s for clinic or 120s for tropic. This |
34 | | - is needed to intepret the so-called iteration number in the hotstart labels |
35 | | - which are really time step numbers. |
36 | | -
|
37 | | - workdir : str |
38 | | - Directory to inventory. If it is an outputs directory, the inventory |
39 | | - comprise existing hotstarts. |
40 | | - |
41 | | - paramfile : str |
42 | | - Name of param.nml file, expected in workdir or workdir/.. If None, then |
43 | | - both start and dt must be supplied. If all three are None, the name "param.nml" will |
44 | | - be attempted |
45 | | -
|
46 | | - |
47 | 92 | Returns |
48 | 93 | ------- |
49 | | - Dataframe, if programatic, listing hotstarts. Should look like "Date, Iteration" pairs. CLI should print it out. |
50 | | - |
51 | | - Notes |
52 | | - ----- |
53 | | - If the listing is done in the run dir, this will be the expected hotstarts. If |
54 | | - it is in the outputs dir, it will be an inventory of existing hotstarts. |
55 | | -
|
| 94 | + pandas.DataFrame or None |
| 95 | + A DataFrame containing the inventory of hotstarts with a DatetimeIndex and a column "iteration". |
| 96 | + If no hotstarts are found and `expected` is False, returns None. |
56 | 97 | """ |
| 98 | + |
57 | 99 | run_start = pd.to_datetime(run_start) |
58 | 100 | if type(hot_freq) == str: |
59 | 101 | hot_freq = pd.tseries.frequencies.to_offset(hot_freq) |
60 | | - print(run_start,dt,paramfile,workdir,hot_freq) |
61 | | - hots = glob.glob(os.path.join(workdir,"hotstart_000000_*.nc")) |
62 | | - is_existing = (len(hots) > 0) |
63 | | - print("is_existing",is_existing) |
64 | | - param_needed = (dt is None) or (run_start is None) or (hot_freq is None and not is_existing ) |
65 | 102 |
|
| 103 | + hots = glob.glob(os.path.join(workdir, "hotstart_000000_*.nc")) |
| 104 | + is_existing = (len(hots) > 0) |
| 105 | + print(workdir) |
| 106 | + param_needed = (dt is None) or (run_start is None) or (hot_freq is None and not is_existing) or pd.isnull(run_start) |
| 107 | + print("Existing hotstarts found:", is_existing, " params read from file: " + str(param_needed)) |
66 | 108 | if param_needed: |
67 | | - if paramfile is None: |
| 109 | + if paramfile is None or paramfile == "": |
68 | 110 | paramfile = 'param.nml' |
69 | | - if is_existing or not os.path.exists(paramfile): |
70 | | - paramfile = os.path.join(workdir,'..',paramfile) |
71 | | - |
| 111 | + print("got here", paramfile, workdir) |
| 112 | + if os.path.exists(os.path.join(workdir, "..", paramfile)): |
| 113 | + paramfile = os.path.join(workdir, "..", paramfile) |
72 | 114 | params = read_params(paramfile) |
73 | 115 | dt_param = params['dt'] |
74 | 116 | run_start_param = params.run_start |
75 | 117 | run_len_param = params['rnday'] |
76 | 118 | hot_freq_param = params.hotstart_freq |
77 | | - print("run_start",run_start,run_start_param) |
78 | | - if run_start is None or pd.isnull(run_start) : |
79 | | - print("yo",run_start_param) |
| 119 | + print(f"dt={dt_param}, run_start={run_start_param}, run_len={run_len_param}, hot_freq={hot_freq_param}") |
| 120 | + if run_start is None or pd.isnull(run_start): |
80 | 121 | run_start = run_start_param |
81 | | - if dt is None: dt = dt_param |
82 | | - if nday is None or nday == 0: nday = run_len_param |
83 | | - if hot_freq is None: hot_freq=hot_freq_param |
84 | | - if not is_existing: |
85 | | - print("hello",run_start,dt,paramfile,workdir,hot_freq) |
86 | | - end = run_start + days(nday) |
87 | | - t = run_start |
88 | | - iters = [] |
89 | | - times = [] |
90 | | - dt_freq = pd.tseries.offsets.Second(dt) |
91 | | - iters_per_hot = hot_freq/dt_freq |
92 | | - itr = 0 |
93 | | - print(hot_freq,dt_freq,t,end,nday) |
94 | | - while (t<end): |
95 | | - times.append(t) |
96 | | - iters.append(itr) |
97 | | - t = t + hot_freq |
98 | | - itr = itr + int(iters_per_hot) |
99 | | - print(f"t={t},itr={itr}") |
100 | | - ndx = pd.DatetimeIndex(times) |
101 | | - df = pd.DataFrame(index=ndx,data=iters) |
102 | | - df.columns=["iteration"] |
103 | | - df.index.name="datetime" |
104 | | - print(df) |
105 | | - |
106 | | - |
107 | | -def hotstart_inventory2(start,dt=90): |
108 | | - # convert start time string input to datetime |
109 | | - if isinstance(start,str): |
110 | | - start = dtm.date.fromisoformat(start) |
111 | | - #start=list(map(int, re.split('[^\d]', start))) |
| 122 | + if dt is None: |
| 123 | + dt = dt_param |
| 124 | + if nday is None or nday == 0: |
| 125 | + nday = run_len_param |
| 126 | + if hot_freq is None: |
| 127 | + hot_freq = hot_freq_param |
| 128 | + |
| 129 | + if expected: |
| 130 | + expected_df = expected_hotstarts(run_start, dt, nday, hot_freq) |
| 131 | + print(expected_df) |
| 132 | + return expected_df |
| 133 | + |
| 134 | + if is_existing: |
| 135 | + return hotstart_inventory_exist(run_start, dt, workdir) |
| 136 | + else: |
| 137 | + return None |
| 138 | + |
| 139 | + |
| 140 | + |
| 141 | +def hotstart_inventory_exist(start,dt=90,workdir='.',do_print=True): |
| 142 | + """ |
| 143 | + Check for the existence of hotstart inventory files and generate a DataFrame |
| 144 | + mapping iterations to corresponding datetime values. |
| 145 | + Parameters |
| 146 | + ---------- |
| 147 | + start : str or pandas.Timestamp |
| 148 | + The start time as a string or pandas.Timestamp object. |
| 149 | + dt : int, optional |
| 150 | + Time step in seconds between iterations (default is 90). |
| 151 | + workdir : str, optional |
| 152 | + Directory to search for hotstart files (default is '.'). |
| 153 | + do_print : bool, optional |
| 154 | + Whether to print the iterations and corresponding times (default is True). |
| 155 | + Returns |
| 156 | + ------- |
| 157 | + pandas.DataFrame |
| 158 | + A DataFrame with datetime as the index and iteration numbers as the column. |
| 159 | + Notes |
| 160 | + ----- |
| 161 | + - The function searches for hotstart files in the specified `workdir` directory. |
| 162 | + - If no files are found in `workdir`, it searches in the current directory. |
| 163 | + - The function assumes hotstart files follow the naming pattern |
| 164 | + "hotstart_000000_<iteration>.nc". |
| 165 | + """ |
112 | 166 |
|
113 | | - hots = glob.glob("hotstart_000000_*.nc") |
| 167 | + print("Hotstart Inventory") |
| 168 | + if isinstance(start,str): |
| 169 | + start = pd.Timestamp(start) |
| 170 | + hots = glob.glob(os.path.join(workdir,"hotstart_000000_*.nc")) |
114 | 171 | if len(hots) == 0: |
115 | | - hots = glob.glob("hotstart_0000_*.nc") |
| 172 | + hots = glob.glob(os.path.join("hotstart_0000_*.nc")) |
116 | 173 | hots.sort() |
117 | 174 | iters = [int(x.split("_")[2].replace(".nc","")) for x in hots] |
118 | 175 |
|
119 | 176 | iters.sort() |
120 | | - times = [start + dtm.timedelta(seconds=x*dt) for x in iters] |
| 177 | + times = [start + seconds(x*dt) for x in iters] |
| 178 | + df = pd.DataFrame(index=times,data=iters) |
| 179 | + df.columns=["iteration"] |
| 180 | + df.index.name="datetime" |
| 181 | + |
| 182 | + if do_print: |
| 183 | + for it,t in zip(iters,times): |
| 184 | + print("{}: {}".format(it,t)) |
121 | 185 |
|
122 | | - for it,t in zip(iters,times): |
123 | | - print("{}: {}".format(it,t)) |
| 186 | + return df |
124 | 187 |
|
125 | 188 | def create_arg_parser(): |
126 | 189 | parser = argparse.ArgumentParser("Lookup station metadata by partial string match on id or name") |
127 | | - parser.add_argument('--dt',default=90,type=int,help="Time step in seconds of model") |
128 | | - parser.add_argument('--run_start',default="",help = 'Start time in iso-like format, e.g. 2013-12-03') |
129 | | - parser.add_argument('--nday',default=0,type=int,help = 'Number of days in simulation (rnday) or maximum to catalog') |
130 | | - parser.add_argument('--workdir',default='.',type=str,help="working directory, which may be a launch or outputs dir") |
131 | | - parser.add_argument('--paramfile',default="",type=str,help = 'Name of param.nml file if file is used to infer runtime') |
132 | | - parser.add_argument('--hot_freq',default=None,help = "`Hotstart frequency in pandas freq terms (e.g. '5D')") |
133 | | - return parser |
| 190 | + parser.add_argument('--dt', default=90, type=int, help="Time step in seconds of model") |
| 191 | + parser.add_argument('--run_start', default="", help='Start time in iso-like format, e.g. 2013-12-03') |
| 192 | + parser.add_argument('--nday', default=0, type=int, help='Number of days in simulation (rnday) or maximum to catalog') |
| 193 | + parser.add_argument('--workdir', default='.', type=str, help="Working directory, which is the outputs dir") |
| 194 | + parser.add_argument('--paramfile', default="", type=str, help='Name of param.nml file if file is used to infer runtime. If neither params nor paramfile provided, ./param.nmo or ../param.nml will be tried. ') |
| 195 | + parser.add_argument('--hot_freq', default=None, help="Hotstart frequency in pandas freq terms (e.g. '5D')") |
| 196 | + parser.add_argument('--expected', action='store_true', help="Flag to generate expected hotstarts instead of inventory of existing files") |
| 197 | + return parser |
134 | 198 |
|
135 | 199 |
|
136 | 200 |
|
137 | 201 | def main(): |
138 | 202 | parser = create_arg_parser() |
139 | 203 | args = parser.parse_args() |
140 | | - hotstart_inventory(args.run_start,args.dt,args.nday,args.workdir,args.paramfile,args.hot_freq) |
| 204 | + hotstart_inventory(args.run_start,args.dt,args.nday,args.workdir,args.paramfile,args.hot_freq,args.expected) |
141 | 205 |
|
142 | 206 |
|
143 | 207 | if __name__ == "__main__": |
|
0 commit comments