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

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