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

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