source: TOOLS/ConsoGENCMIP6/bin/plot_jobs_hourly.py @ 3734

Last change on this file since 3734 was 2849, checked in by labetoulle, 8 years ago

[gencmip6] running/pending jobs:

  • Gather data for whole Curie in addition to that from gencmip6 project
  • Plot hourly data and daily mean
  • Property svn:executable set to *
File size: 13.4 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
13import pprint
14
15# Application library imports
16from libconso import *
17
18pp = pprint.PrettyPrinter(indent=2)
19
20
21########################################
22class DataDict(dict):
23  #---------------------------------------
24  def __init__(self):
25    self = {}
26
27  #---------------------------------------
28  def init_range(self, date_beg, date_end, inc=1):
29    """
30    """
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, projet, mode="project"):
43    """
44    """
45
46    for filein in sorted(file_list):
47      filedate = dt.datetime.strptime(
48        os.path.basename(filein).split("_")[-1],
49        "%Y%m%d"
50      )
51      if filedate < projet.date_init or \
52         filedate > projet.deadline:
53        continue
54
55      try:
56        data = np.genfromtxt(
57          filein,
58          skip_header=1,
59          converters={
60            0: string_to_datetime,
61            1: float,
62            2: float,
63          },
64          missing_values="nan",
65        )
66      except Exception as rc:
67        print("Problem with file {} :\n{}".format(filein, rc))
68        exit(1)
69
70      for date, run, pen in data:
71        date = dt.datetime(
72          date.year,
73          date.month,
74          date.day,
75          date.hour,
76          0
77        )
78
79        if mode == "project":
80          # self.add_item(
81          #   date=date,
82          #   runp=run,
83          #   penp=pen,
84          # )
85          self[date].runp = run
86          self[date].penp = pen
87        elif mode == "machine":
88          # self.add_item(
89          #   date=date,
90          #   runf=run,
91          #   penf=pen,
92          # )
93          self[date].runf = run
94          self[date].penf = pen
95        self[date].fill()
96
97  #---------------------------------------
98  def add_item(self, date, runp=np.nan, penp=np.nan, runf=np.nan, penf=np.nan):
99    """
100    """
101    self[date] = Conso(
102      date,
103      runp,
104      penp,
105      runf,
106      penf,
107    )
108
109  #---------------------------------------
110  def get_items_in_range(self, date_beg, date_end, inc=1):
111    """
112    """
113    items = (item for item in self.itervalues()
114                   if item.date >= date_beg and
115                      item.date <= date_end)
116    items = sorted(items, key=lambda item: item.date)
117
118    return items[::inc]
119
120  #---------------------------------------
121  def get_items(self, inc=1):
122    """
123    """
124    items = (item for item in self.itervalues()
125                   if item.isfilled())
126    items = sorted(items, key=lambda item: item.date)
127
128    return items[::inc]
129
130
131class Conso(object):
132  #---------------------------------------
133  def __init__(self, date, runp=np.nan, penp=np.nan, runf=np.nan, penf=np.nan):
134
135    self.date     = date
136    self.runp     = runp
137    self.penp     = penp
138    self.runf     = runf
139    self.penf     = penf
140    self.filled   = False
141
142  #---------------------------------------
143  def __repr__(self):
144    return "R{:.0f} P{:.0f}".format(
145      self.runp,
146      self.penp,
147    )
148
149  #---------------------------------------
150  def isfilled(self):
151    return self.filled
152
153  #---------------------------------------
154  def fill(self):
155    self.filled = True
156
157
158########################################
159def plot_init():
160  paper_size  = np.array([29.7, 21.0])
161  fig, (ax_jobsp, ax_jobsf) = plt.subplots(
162    nrows=2,
163    ncols=1,
164    sharex=True,
165    squeeze=True,
166    figsize=(paper_size/2.54)
167  )
168
169  return fig, ax_jobsp, ax_jobsf
170
171
172########################################
173def plot_data(
174  ax_jobsp, ax_jobsf, xcoord, dates,
175  runp, penp, runf, penf
176):
177  """
178  """
179  line_width = 0.
180  width = 1.05
181
182  ax_jobsp.bar(
183    xcoord, runp, width=width,
184    linewidth=line_width, align="center",
185    color="lightgreen", ecolor="green", antialiased=True,
186    label="jobs running"
187  )
188  ax_jobsp.bar(
189    xcoord, penp, bottom=runp, width=width,
190    linewidth=line_width, align="center",
191    color="firebrick", antialiased=True,
192    label="jobs pending"
193  )
194
195  ax_jobsf.bar(
196    xcoord, runf, width=width,
197    linewidth=line_width, align="center",
198    color="lightgreen", ecolor="green", antialiased=True,
199    label="jobs running"
200  )
201  ax_jobsf.bar(
202    xcoord, penf, bottom=runf, width=width,
203    linewidth=line_width, align="center",
204    color="firebrick", antialiased=True,
205    label="jobs pending\n(Ressources & Priority)"
206  )
207
208
209########################################
210def plot_config(
211  fig, ax_jobsp, ax_jobsf, xcoord, dates,
212  title, conso_per_day, conso_per_day_2
213):
214  """
215  """
216  from matplotlib.ticker import AutoMinorLocator
217
218  # ... Compute useful stuff ...
219  # ----------------------------
220  conso_jobsf = 80000.
221
222  multialloc = False
223  if conso_per_day_2:
224    date_inter = projet.date_init + dt.timedelta(days=projet.days//2)
225    if projet.date_init in dates:
226      xi = dates.index(projet.date_init)
227    else:
228      xi = 0
229
230    if projet.deadline in dates:
231      xf = dates.index(projet.deadline)
232    else:
233      xf = len(dates)
234
235    if date_inter in dates:
236      xn = dates.index(date_inter)
237      yi = conso_per_day
238      yf = conso_per_day_2
239      multialloc = True
240    else:
241      if dates[-1] < date_inter:
242        xn = xf
243        yi = conso_per_day
244        yf = conso_per_day
245      elif dates[0] > date_inter:
246        xn = xi
247        yi = conso_per_day_2
248        yf = conso_per_day_2
249
250  print("config")
251
252  # ... Config axes ...
253  # -------------------
254  # 1) Range
255  xmin, xmax = xcoord[0]-1, xcoord[-1]+1
256  if multialloc:
257    ymax_jobsp = 4. * max(yi, yf)
258  else:
259    ymax_jobsp = 4. * yi
260  ymax_jobsf = 4. * conso_jobsf
261  ax_jobsp.set_xlim(xmin, xmax)
262  ax_jobsp.set_ylim(0, ymax_jobsp)
263  ax_jobsf.set_ylim(0, ymax_jobsf)
264
265  # 2) Plot ideal daily consumption
266  line_color = "blue"
267  line_alpha = 0.5
268  line_label = "conso journaliÚre idéale"
269  ax_jobsp.plot(
270    [xi, xn, xn, xf], [yi, yi, yf, yf],
271    color=line_color, alpha=line_alpha, label=line_label,
272  )
273  ax_jobsf.axhline(
274    y=conso_jobsf,
275    color=line_color, alpha=line_alpha
276  )
277
278  # 3) Ticks labels
279  (date_beg, date_end) = (dates[0], dates[-1])
280
281  if date_end - date_beg > dt.timedelta(weeks=9):
282    date_fmt = "{:%d-%m}"
283    maj_xticks = [x for x, d in zip(xcoord, dates)
284                     if d.weekday() == 0 and d.hour == 0]
285    maj_xlabs  = [date_fmt.format(d) for d in dates
286                     if d.weekday() == 0 and d.hour == 0]
287  else:
288    date_fmt = "{:%d-%m %Hh}"
289    maj_xticks = [x for x, d in zip(xcoord, dates)
290                     if d.hour == 0 or d.hour == 12]
291    maj_xlabs  = [date_fmt.format(d) for d in dates
292                     if d.hour == 0 or d.hour == 12]
293
294  ax_jobsf.set_xticks(xcoord, minor=True)
295  ax_jobsf.set_xticks(maj_xticks, minor=False)
296  ax_jobsf.set_xticklabels(maj_xlabs, rotation="vertical", size="x-small")
297
298  for ax in (ax_jobsp, ax_jobsf):
299    minor_locator = AutoMinorLocator()
300    ax.yaxis.set_minor_locator(minor_locator)
301
302  yticks = list(ax_jobsp.get_yticks())
303  yticks.append(conso_per_day)
304  if multialloc:
305    yticks.append(conso_per_day_2)
306  ax_jobsp.set_yticks(yticks)
307
308  yticks = list(ax_jobsf.get_yticks())
309  yticks.append(conso_jobsf)
310  ax_jobsf.set_yticks(yticks)
311
312  for x, d in zip(xcoord, dates):
313    if d.weekday() == 0 and d.hour == 0:
314      for ax in (ax_jobsp, ax_jobsf):
315        ax.axvline(x=x, color="black", linewidth=1., linestyle=":")
316
317  # 4) Define axes title
318  for ax, label in (
319    (ax_jobsp, "cœurs (projet)"),
320    (ax_jobsf, "cœurs (machine)"),
321  ):
322    ax.set_ylabel(label, fontweight="bold")
323    ax.tick_params(axis="y", labelsize="small")
324
325  # 5) Define plot size
326  fig.subplots_adjust(
327    left=0.08,
328    bottom=0.09,
329    right=0.93,
330    top=0.93,
331    hspace=0.1,
332    wspace=0.1,
333  )
334
335  # ... Main title and legend ...
336  # -----------------------------
337  fig.suptitle(title, fontweight="bold", size="large")
338  # ax_jobsp.legend(loc="upper right", fontsize="x-small", frameon=False)
339  for ax, subtitle, loc_legend in (
340    (ax_jobsp, "Projet", "upper right"),
341    (ax_jobsf, "Tout Curie", "upper right"),
342  ):
343    ax.legend(loc=loc_legend, fontsize="x-small", frameon=False)
344    ax.set_title(subtitle, loc="left")
345
346
347########################################
348def get_arguments():
349  parser = ArgumentParser()
350  parser.add_argument("-v", "--verbose", action="store_true",
351                      help="verbose mode")
352  parser.add_argument("-i", "--increment", action="store",
353                      type=int, default=1, dest="inc",
354                      help="sampling increment")
355  parser.add_argument("-r", "--range", action="store", nargs=2,
356                      type=string_to_date,
357                      help="date range: ssaa-mm-jj ssaa-mm-jj")
358  parser.add_argument("-s", "--show", action="store_true",
359                      help="interactive mode")
360  parser.add_argument("-d", "--dods", action="store_true",
361                      help="copy output on dods")
362
363  return parser.parse_args()
364
365
366########################################
367if __name__ == '__main__':
368
369  # .. Initialization ..
370  # ====================
371  # ... Command line arguments ...
372  # ------------------------------
373  args = get_arguments()
374
375  # ... Constants ...
376  # -----------------
377  WEEK_NB = 3
378
379  # ... Turn interactive mode off ...
380  # ---------------------------------
381  if not args.show:
382    import matplotlib
383    matplotlib.use('Agg')
384
385  import matplotlib.pyplot as plt
386  # from matplotlib.backends.backend_pdf import PdfPages
387
388  if not args.show:
389    plt.ioff()
390
391  # ... Files and directories ...
392  # -----------------------------
393  project_name, DIR, OUT = parse_config("bin/config.ini")
394
395  (file_param, file_utheo) = \
396      get_input_files(DIR["SAVEDATA"], [OUT["PARAM"], OUT["UTHEO"]])
397
398  jobsp_file_list = glob.glob(
399    os.path.join(DIR["SAVEDATA"], "OUT_JOBS_PENDING_*")
400  )
401  jobsf_file_list = glob.glob(
402    os.path.join(DIR["SAVEDATA"], "OUT_JOBS_PEN_FULL_*")
403  )
404
405  img_name = os.path.splitext(
406               os.path.basename(__file__)
407             )[0].replace("plot_", "")
408
409  today   = dt.datetime.today()
410  weeknum = today.isocalendar()[1]
411
412  if args.verbose:
413    fmt_str = "{:10s} : {}"
414    print(fmt_str.format("args", args))
415    print(fmt_str.format("today", today))
416    print(fmt_str.format("file_param", file_param))
417    print(fmt_str.format("file_utheo", file_utheo))
418    print(fmt_str.format("jobsp", jobsp_file_list))
419    print(fmt_str.format("jobsf", jobsf_file_list))
420    print(fmt_str.format("img_name", img_name))
421
422  # .. Get project info ..
423  # ======================
424  projet = Project(project_name)
425  projet.fill_data(file_param)
426  projet.get_date_init(file_utheo)
427
428  # .. Fill in data ..
429  # ==================
430  # ... Initialization ...
431  # ----------------------
432  bilan = DataDict()
433  bilan.init_range(projet.date_init, projet.deadline)
434  # ... Extract data from file ...
435  # ------------------------------
436  bilan.fill_data(jobsp_file_list, projet, mode="project")
437  bilan.fill_data(jobsf_file_list, projet, mode="machine")
438
439  # .. Extract data depending on C.L. arguments ..
440  # ==============================================
441  if args.range:
442    selected_items = bilan.get_items_in_range(
443      args.range[0], args.range[1], args.inc
444    )
445  else:
446    range_end   = today
447    range_start = (
448      range_end + dt.timedelta(weeks=-WEEK_NB) - dt.timedelta(days=1)
449    )
450    selected_items = bilan.get_items_in_range(
451      range_start, range_end, args.inc
452    )
453
454  # .. Compute data to be plotted ..
455  # ================================
456  nb_items = len(selected_items)
457
458  xcoord   = np.linspace(1, nb_items, num=nb_items)
459  dates  = [item.date for item in selected_items]
460
461  runp = np.array([item.runp for item in selected_items],
462                   dtype=float)
463  penp = np.array([item.penp for item in selected_items],
464                   dtype=float)
465  runf = np.array([item.runf for item in selected_items],
466                   dtype=float)
467  penf = np.array([item.penf for item in selected_items],
468                   dtype=float)
469
470  if projet.project == "gencmip6":
471    alloc1 = (1 * projet.alloc) / 3
472    alloc2 = (2 * projet.alloc) / 3
473    conso_per_day   = 2 * alloc1 / (projet.days * 24.)
474    conso_per_day_2 = 2 * alloc2 / (projet.days * 24.)
475  else:
476    conso_per_day = projet.alloc / (projet.days * 24.)
477    conso_per_day_2 = None
478
479  # .. Plot stuff ..
480  # ================
481  # ... Initialize figure ...
482  # -------------------------
483  (fig, ax_jobsp, ax_jobsf) = plot_init()
484
485  # ... Plot data ...
486  # -----------------
487  plot_data(
488    ax_jobsp, ax_jobsf, xcoord, dates,
489    runp, penp, runf, penf
490  )
491
492  # ... Tweak figure ...
493  # --------------------
494  title = "Suivi des jobs {}\n({:%d/%m/%Y} - {:%d/%m/%Y})".format(
495    projet.project.upper(),
496    projet.date_init,
497    projet.deadline
498  )
499
500  plot_config(
501    fig, ax_jobsp, ax_jobsf,
502    xcoord, dates, title, 
503    conso_per_day, conso_per_day_2
504  )
505
506  # ... Save figure ...
507  # -------------------
508  img_in  = os.path.join(DIR["PLOT"], "{}.pdf".format(img_name))
509  img_out = os.path.join(DIR["SAVEPLOT"],
510                         "{}_w{:02d}.pdf".format(img_name, weeknum))
511
512  plot_save(img_in, img_out, title, DIR)
513
514  # ... Publish figure on dods ...
515  # ------------------------------
516  if args.dods:
517    dods_cp(img_in, DIR)
518
519  if args.show:
520    plt.show()
521
522  exit(0)
Note: See TracBrowser for help on using the repository browser.