source: TOOLS/ConsoGENCMIP6/bin/plot_jobs.py @ 2450

Last change on this file since 2450 was 2450, checked in by labetoulle, 7 years ago

plot_jobs : default is now to plot the last three weeks instead of everything

  • Property svn:executable set to *
File size: 12.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# this must come first
5from __future__ import print_function, unicode_literals, division
6
7# standard library imports
8from argparse import ArgumentParser
9import os
10import os.path
11import datetime as dt
12import numpy as np
13
14# Application library imports
15from gencmip6 import *
16from gencmip6_path import *
17
18
19########################################
20class DataDict(dict):
21  #---------------------------------------
22  def __init__(self):
23    self = {}
24
25  #---------------------------------------
26  def init_range(self, date_beg, date_end, inc=1):
27    """
28    """
29    # delta = date_end - date_beg
30    # delta = delta + dt.timedelta(days=1)
31    delta = date_end - date_beg + dt.timedelta(days=1)
32
33    (deb, fin) = (0, int(delta.total_seconds() / 3600))
34
35    dates = (date_beg + dt.timedelta(hours=i)
36             for i in xrange(deb, fin, inc))
37
38    for date in dates:
39      self.add_item(date)
40
41  #---------------------------------------
42  def fill_data(self, file_list):
43    """
44    """
45    for filein in sorted(file_list):
46      try:
47        data = np.genfromtxt(
48          filein,
49          skip_header=1,
50          converters={
51            0: string_to_datetime,
52            1: int,
53            2: int,
54          },
55          missing_values="nan",
56        )
57      except Exception as rc:
58        print("Problem with file {} :\n{}".format(filein, rc))
59        exit(1)
60
61      if len(data) == 24:
62        run_mean = np.nanmean(
63            np.array([run for _, run, _ in data])
64        )
65        pen_mean = np.nanmean(
66            np.array([pen for _, _, pen in data])
67        )
68        run_std = np.nanstd(
69            np.array([run for _, run, _ in data])
70        )
71        pen_std = np.nanstd(
72            np.array([pen for _, _, pen in data])
73        )
74      else:
75        run_mean = np.nan
76        pen_mean = np.nan
77        run_std  = np.nan
78        pen_std  = np.nan
79
80      for date, run, pen in data:
81        if date.hour == 0:
82          self.add_item(
83            date,
84            run,
85            pen,
86            run_mean,
87            pen_mean,
88            run_std,
89            pen_std
90          )
91        else:
92          self.add_item(date, run, pen)
93        self[date].fill()
94
95  #---------------------------------------
96  def add_item(self, date, run=np.nan, pen=np.nan,
97               run_mean=np.nan, pen_mean=np.nan,
98               run_std=np.nan, pen_std=np.nan):
99    """
100    """
101    self[date] = Conso(
102      date,
103      run,
104      pen,
105      run_mean,
106      pen_mean,
107      run_std,
108      pen_std
109    )
110
111  #---------------------------------------
112  def get_items_in_range(self, date_beg, date_end, inc=1):
113    """
114    """
115    items = (item for item in self.itervalues()
116                   if item.date >= date_beg and
117                      item.date <= date_end)
118    items = sorted(items, key=lambda item: item.date)
119
120    return items[::inc]
121
122  #---------------------------------------
123  def get_items_in_full_range(self, inc=1):
124    """
125    """
126    items = (item for item in self.itervalues()
127                   if item.date.hour == 0)
128    items = sorted(items, key=lambda item: item.date)
129
130    return items[::inc]
131
132  #---------------------------------------
133  def get_items(self, inc=1):
134    """
135    """
136    items = (item for item in self.itervalues()
137                   if item.isfilled())
138    items = sorted(items, key=lambda item: item.date)
139
140    return items[::inc]
141
142
143class Conso(object):
144  #---------------------------------------
145  def __init__(self, date, run=np.nan, pen=np.nan,
146               run_mean=np.nan, pen_mean=np.nan,
147               run_std=np.nan, pen_std=np.nan):
148
149    self.date     = date
150    self.run      = run
151    self.pen      = pen
152    self.run_mean = run_mean
153    self.pen_mean = pen_mean
154    self.run_std  = run_std
155    self.pen_std  = pen_std
156    self.filled   = False
157
158  #---------------------------------------
159  def __repr__(self):
160    return "R{:.0f} ({:.0f}/{:.0f}) P{:.0f} ({:.0f}/{:.0f})".format(
161      self.run,
162      self.run_mean,
163      self.run_std,
164      self.pen,
165      self.pen_mean,
166      self.pen_std,
167    )
168
169  #---------------------------------------
170  def isfilled(self):
171    return self.filled
172
173  #---------------------------------------
174  def fill(self):
175    self.filled = True
176
177
178########################################
179def plot_init():
180  paper_size  = np.array([29.7, 21.0])
181  fig, ax = plt.subplots(figsize=(paper_size/2.54))
182
183  return fig, ax
184
185
186########################################
187def plot_data(ax, xcoord, dates, run_jobs, pen_jobs, run_std, pen_std):
188  """
189  """
190  line_width = 0.
191  width = 1.05
192
193  ax.bar(xcoord, run_jobs, width=width, yerr=run_std/2.,
194         linewidth=line_width, align="center",
195         color="lightgreen", ecolor="green", antialiased=True,
196         label="jobs running")
197  ax.bar(xcoord, pen_jobs, bottom=run_jobs, width=width,
198         linewidth=line_width, align="center",
199         color="firebrick", antialiased=True,
200         label="jobs pending")
201  # ax.step(xcoord, run_jobs, where="mid", linewidth=1, color="black", label="jobs running")
202  # ax.step(xcoord, pen_jobs+run_jobs, where="mid", linewidth=1, color="black", label="jobs running")
203
204
205########################################
206def plot_config(fig, ax, xcoord, dates, title, conso_per_day):
207  """
208  """
209  # ... Config axes ...
210  # -------------------
211  # 1) Range
212  xmin, xmax = xcoord[0]-1, xcoord[-1]+1
213  ax.set_xlim(xmin, xmax)
214
215  # 2) Ticks labels
216  (date_beg, date_end) = (dates[0], dates[-1])
217
218  if date_end - date_beg > dt.timedelta(weeks=9):
219    date_fmt = "{:%d-%m}"
220    maj_xticks = [x for x, d in zip(xcoord, dates)
221                     if d.weekday() == 0 and d.hour == 0]
222    maj_xlabs  = [date_fmt.format(d) for d in dates
223                     if d.weekday() == 0 and d.hour == 0]
224  else:
225    date_fmt = "{:%d-%m %Hh}"
226    maj_xticks = [x for x, d in zip(xcoord, dates)
227                     if d.hour == 0 or d.hour == 12]
228    maj_xlabs  = [date_fmt.format(d) for d in dates
229                     if d.hour == 0 or d.hour == 12]
230
231  ax.set_xticks(xcoord, minor=True)
232  ax.set_xticks(maj_xticks, minor=False)
233  ax.set_xticklabels(maj_xlabs, rotation="vertical", size="x-small")
234
235  yticks = list(ax.get_yticks())
236  yticks.append(conso_per_day)
237  ax.set_yticks(yticks)
238
239  ax.axhline(y=conso_per_day, color="blue", alpha=0.5,
240             label="conso journaliÚre idéale")
241
242  for x, d in zip(xcoord, dates):
243    if d.weekday() == 0 and d.hour == 0:
244      ax.axvline(x=x, color="black", linewidth=1., linestyle=":")
245
246  # 3) Define axes title
247  ax.set_ylabel("cœurs", fontweight="bold")
248  ax.tick_params(axis="y", labelsize="small")
249
250  # 4) Define plot size
251  fig.subplots_adjust(
252    left=0.08,
253    bottom=0.09,
254    right=0.93,
255    top=0.93,
256  )
257
258  # ... Main title and legend ...
259  # -----------------------------
260  fig.suptitle(title, fontweight="bold", size="large")
261  ax.legend(loc="upper right", fontsize="x-small", frameon=False)
262
263
264########################################
265def get_arguments():
266  parser = ArgumentParser()
267  parser.add_argument("-v", "--verbose", action="store_true",
268                      help="verbose mode")
269  parser.add_argument("-f", "--full", action="store_true",
270                      help="plot the whole period")
271  parser.add_argument("-i", "--increment", action="store",
272                      type=int, default=1, dest="inc",
273                      help="sampling increment")
274  parser.add_argument("-r", "--range", action="store", nargs=2,
275                      type=string_to_date,
276                      help="date range: ssaa-mm-jj ssaa-mm-jj")
277  parser.add_argument("-s", "--show", action="store_true",
278                      help="interactive mode")
279  parser.add_argument("-d", "--dods", action="store_true",
280                      help="copy output on dods")
281
282  return parser.parse_args()
283
284
285########################################
286if __name__ == '__main__':
287
288  # .. Initialization ..
289  # ====================
290  # ... Command line arguments ...
291  # ------------------------------
292  args = get_arguments()
293
294  # ... Constants ...
295  # -----------------
296  WEEK_NB = 3
297
298  # ... Turn interactive mode off ...
299  # ---------------------------------
300  if not args.show:
301    import matplotlib
302    matplotlib.use('Agg')
303
304  import matplotlib.pyplot as plt
305  # from matplotlib.backends.backend_pdf import PdfPages
306
307  if not args.show:
308    plt.ioff()
309
310  # ... Files and directories ...
311  # -----------------------------
312  (file_param, file_utheo) = \
313      get_input_files(DIR["SAVEDATA"], [OUT["PARAM"], OUT["UTHEO"]])
314
315  file_list = glob.glob(os.path.join(DIR["SAVEDATA"],
316                                     "OUT_JOBS_PENDING_*"))
317
318  img_name = "jobs"
319
320  today   = dt.datetime.today()
321  weeknum = today.isocalendar()[1]
322
323  if args.verbose:
324    fmt_str = "{:10s} : {}"
325    print(fmt_str.format("args", args))
326    print(fmt_str.format("today", today))
327    print(fmt_str.format("file_param", file_param))
328    print(fmt_str.format("file_utheo", file_utheo))
329    print(fmt_str.format("file_list", file_list))
330    print(fmt_str.format("img_name", img_name))
331
332  # .. Get project info ..
333  # ======================
334  gencmip6 = Project()
335  gencmip6.fill_data(file_param)
336  gencmip6.get_date_init(file_utheo)
337
338  # .. Fill in data ..
339  # ==================
340  # ... Initialization ...
341  # ----------------------
342  bilan = DataDict()
343  bilan.init_range(gencmip6.date_init, gencmip6.deadline)
344
345  # ... Extract data from file ...
346  # ------------------------------
347  bilan.fill_data(file_list)
348
349  # # ... Compute theoratical use from known data  ...
350  # # ------------------------------------------------
351  # bilan.theo_equation()
352
353  # .. Extract data depending on C.L. arguments ..
354  # ==============================================
355  if args.full:
356    selected_items = bilan.get_items_in_full_range(args.inc)
357  elif args.range:
358    selected_items = bilan.get_items_in_range(
359      args.range[0], args.range[1], args.inc
360    )
361  else:
362    # selected_items = bilan.get_items(args.inc)
363    range_end   = today
364    range_start = range_end + dt.timedelta(weeks=-WEEK_NB) - dt.timedelta(days=1)
365    selected_items = bilan.get_items_in_range(
366      range_start, range_end, args.inc
367    )
368
369  # .. Compute data to be plotted ..
370  # ================================
371  nb_items = len(selected_items)
372
373  xcoord   = np.linspace(1, nb_items, num=nb_items)
374  dates  = [item.date for item in selected_items]
375
376  if args.full:
377    run_jobs = np.array([item.run_mean for item in selected_items],
378                         dtype=float)
379    pen_jobs = np.array([item.pen_mean for item in selected_items],
380                         dtype=float)
381    run_std  = np.array([item.run_std for item in selected_items],
382                         dtype=float)
383    pen_std  = np.array([item.pen_std for item in selected_items],
384                         dtype=float)
385  else:
386    run_jobs = np.array([item.run for item in selected_items],
387                         dtype=float)
388    pen_jobs = np.array([item.pen for item in selected_items],
389                         dtype=float)
390    run_std  = np.nan
391    pen_std  = np.nan
392
393  if args.verbose:
394    for i in selected_items:
395      if not np.isnan(i.run_mean):
396        print(
397          "{} {:13.2f} {:13.2f} {:13.2f} {:13.2f}".format(
398           i.date,
399           i.run_mean, i.pen_mean,
400           i.run_std, i.pen_std
401          )
402        )
403
404  conso_per_day = gencmip6.alloc / (gencmip6.days * 24.)
405
406  # .. Plot stuff ..
407  # ================
408  # ... Initialize figure ...
409  # -------------------------
410  (fig, ax) = plot_init()
411
412  # ... Plot data ...
413  # -----------------
414  plot_data(ax, xcoord, dates, run_jobs, pen_jobs, run_std, pen_std)
415
416  # # ... Tweak figure ...
417  # # --------------------
418  # if args.max:
419  #   ymax = gencmip6.alloc
420  # else:
421  #   ymax = np.nanmax(consos) + np.nanmax(consos)*.1
422
423  title = "Suivi des jobs {}\n({:%d/%m/%Y} - {:%d/%m/%Y})".format(
424    gencmip6.project.upper(),
425    gencmip6.date_init,
426    gencmip6.deadline
427  )
428
429  plot_config(fig, ax, xcoord, dates, title, conso_per_day)
430
431  # ... Save figure ...
432  # -------------------
433  img_in  = os.path.join(DIR["PLOT"], "{}.pdf".format(img_name))
434  img_out = os.path.join(DIR["SAVEPLOT"],
435                         "{}_w{:02d}.pdf".format(img_name, weeknum))
436
437  plot_save(img_in, img_out, title)
438
439  # ... Publish figure on dods ...
440  # ------------------------------
441  if args.dods:
442    dods_cp(img_in)
443
444  if args.show:
445    plt.show()
446
447  exit(0)
Note: See TracBrowser for help on using the repository browser.