source: TOOLS/ConsoGENCMIP6/bin/plot_bilan.py @ 2426

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

Check exit status

  • Property svn:executable set to *
File size: 12.0 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 BilanDict(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
31    (deb, fin) = (0, delta.days+1)
32
33    dates = (date_beg + dt.timedelta(days=i)
34             for i in xrange(deb, fin, inc))
35
36    for date in dates:
37      self.add_item(date)
38
39  #---------------------------------------
40  def fill_data(self, filein):
41    data = np.genfromtxt(
42      filein,
43      skip_header=1,
44      converters={0: string_to_date,
45                  1: string_to_float,
46                  2: string_to_percent,
47                  3: string_to_percent},
48      missing_values="nan",
49    )
50
51    for date, conso, real_use, theo_use in data:
52      if date in self:
53        self.add_item(date, conso, real_use, theo_use)
54        self[date].fill()
55
56  #---------------------------------------
57  def add_item(self, date, conso=np.nan,
58               real_use=np.nan, theo_use=np.nan):
59    """
60    """
61    self[date] = Conso(date, conso, real_use, theo_use)
62
63  #---------------------------------------
64  def theo_equation(self):
65    """
66    """
67    (dates, theo_uses) = \
68      zip(*((item.date, item.theo_use)
69            for item in self.get_items_in_full_range()))
70
71    (idx_min, idx_max) = \
72        (np.nanargmin(theo_uses), np.nanargmax(theo_uses))
73
74    x1 = dates[idx_min].timetuple().tm_yday
75    x2 = dates[idx_max].timetuple().tm_yday
76
77    y1 = theo_uses[idx_min]
78    y2 = theo_uses[idx_max]
79
80    m = np.array([
81      [x1, 1.],
82      [x2, 1.]
83    ], dtype="float")
84    n = np.array([
85      y1,
86      y2
87    ], dtype="float")
88
89    try:
90      (a, b) = np.linalg.solve(m, n)
91    except np.linalg.linalg.LinAlgError:
92      (a, b) = (None, None)
93
94    if a and b:
95      for date in dates:
96        self[date].theo_equ = date.timetuple().tm_yday*a + b
97
98  #---------------------------------------
99  def get_items_in_range(self, date_beg, date_end, inc=1):
100    """
101    """
102    items = (item for item in self.itervalues()
103                   if item.date >= date_beg and
104                      item.date <= date_end)
105    items = sorted(items, key=lambda item: item.date)
106
107    return items[::inc]
108
109  #---------------------------------------
110  def get_items_in_full_range(self, inc=1):
111    """
112    """
113    items = (item for item in self.itervalues())
114    items = sorted(items, key=lambda item: item.date)
115
116    return items[::inc]
117
118  #---------------------------------------
119  def get_items(self, inc=1):
120    """
121    """
122    items = (item for item in self.itervalues()
123                   if item.isfilled())
124    items = sorted(items, key=lambda item: item.date)
125
126    return items[::inc]
127
128
129class Conso(object):
130  #---------------------------------------
131  def __init__(self, date, conso=np.nan,
132               real_use=np.nan, theo_use=np.nan):
133    self.date     = date
134    self.conso    = conso
135    self.real_use = real_use
136    self.theo_use = theo_use
137    self.theo_equ = np.nan
138    self.filled   = False
139
140  #---------------------------------------
141  def __repr__(self):
142    return "{:.2f} ({:.2%})".format(self.conso, self.real_use)
143
144  #---------------------------------------
145  def isfilled(self):
146    return self.filled
147
148  #---------------------------------------
149  def fill(self):
150    self.filled = True
151
152
153########################################
154def plot_init():
155  paper_size  = np.array([29.7, 21.0])
156  fig, ax_conso = plt.subplots(figsize=(paper_size/2.54))
157  ax_theo = ax_conso.twinx()
158
159  return fig, ax_conso, ax_theo
160
161
162########################################
163def plot_data(ax_conso, ax_theo, xcoord, xlabels,
164              consos, conso_per_day, theo_uses, real_uses, theo_equs):
165  """
166  """
167  if args.full:
168    line_style = "-"
169    line_width = 0.1
170  else:
171    line_style = "+-"
172    line_width = 0.2
173
174  ax_conso.bar(xcoord, consos, align="center", color="linen",
175               linewidth=line_width, label="conso (heures)")
176  # ax_conso.plot(xcoord, conso_per_day, line_style, color="blue",
177  #               linewidth=1, markersize=8, alpha=0.5,
178  #               # solid_capstyle="round", solid_joinstyle="round",
179  #               label="conso journaliÚre idéale (heures)")
180  ax_conso.axhline(y=conso_per_day[0], color="blue", alpha=0.5,
181                   label="conso journaliÚre idéale (heures)")
182
183  ax_theo.plot(xcoord, theo_equs, "--",
184               color="firebrick", linewidth=0.5,
185               solid_capstyle="round", solid_joinstyle="round")
186  ax_theo.plot(xcoord, theo_uses, line_style, color="firebrick",
187               linewidth=1, markersize=8,
188               # solid_capstyle="round", solid_joinstyle="round",
189               label="conso théorique (%)")
190  ax_theo.plot(xcoord, real_uses, line_style, color="forestgreen",
191               linewidth=1, markersize=8,
192               # solid_capstyle="round", solid_joinstyle="round",
193               label="conso réelle (%)")
194
195
196########################################
197def plot_config(ax_conso, ax_theo, xcoord, xlabels, ymax, title):
198  """
199  """
200  # ... Config axes ...
201  # -------------------
202  # 1) Range
203  xmin, xmax = xcoord[0]-1, xcoord[-1]+1
204  ax_conso.set_xlim(xmin, xmax)
205  ax_conso.set_ylim(0., ymax)
206  ax_theo.set_ylim(0., 100)
207
208  # 2) Ticks labels
209  inc_label = 7 if nb_items > 37 else 1
210  ax_conso.ticklabel_format(axis="y", style="sci", scilimits=(0, 0))
211  ax_conso.set_xticks(xcoord, minor=True)
212  ax_conso.set_xticks(xcoord[::inc_label], minor=False)
213  ax_conso.set_xticklabels(
214    xlabels[::inc_label], rotation="45", size="x-small"
215  )
216
217  # 3) Define axes title
218  ax_conso.set_ylabel("heures", fontweight="bold")
219  ax_theo.set_ylabel("%", fontweight="bold")
220
221  # ... Main title and legend ...
222  # -----------------------------
223  ax_conso.set_title(title, fontweight="bold", size="large")
224  ax_theo.legend(loc="upper right", fontsize="x-small", frameon=False)
225  ax_conso.legend(loc="upper left", fontsize="x-small", frameon=False)
226
227
228########################################
229def plot_save(img_name):
230  """
231  """
232  dpi = 200.
233
234  with PdfPages(img_name) as pdf:
235    pdf.savefig(dpi=dpi)
236
237    # pdf file's metadata
238    d = pdf.infodict()
239    d["Title"]   = "Conso GENCMIP6"
240    d["Author"]  = "plot_bilan.py"
241    # d["Subject"] = "Time spent over specific commands during create_ts \
242    #                 jobs at IDRIS and four configurations at TGCC"
243    # d["Keywords"] = "bench create_ts TGCC IDRIS ncrcat"
244    # d["CreationDate"] = dt.datetime(2009, 11, 13)
245    # d["ModDate"] = dt.datetime.today()
246
247
248########################################
249def get_arguments():
250  parser = ArgumentParser()
251  parser.add_argument("-v", "--verbose", action="store_true",
252                      help="verbose mode")
253  parser.add_argument("-f", "--full", action="store_true",
254                      help="plot the whole period")
255  parser.add_argument("-i", "--increment", action="store",
256                      type=int, default=1, dest="inc",
257                      help="sampling increment")
258  parser.add_argument("-r", "--range", action="store", nargs=2,
259                      type=string_to_date,
260                      help="date range: ssaa-mm-jj ssaa-mm-jj")
261  parser.add_argument("-m", "--max", action="store_true",
262                      help="plot with y_max = allocation")
263  parser.add_argument("-s", "--show", action="store_true",
264                      help="interactive mode")
265  parser.add_argument("-d", "--dods", action="store_true",
266                      help="copy output on dods")
267
268  return parser.parse_args()
269
270
271########################################
272if __name__ == '__main__':
273
274  # .. Initialization ..
275  # ====================
276  # ... Command line arguments ...
277  # ------------------------------
278  args = get_arguments()
279  if args.verbose:
280    print(args)
281
282  # ... Turn interactive mode off ...
283  # ---------------------------------
284  if not args.show:
285    import matplotlib
286    matplotlib.use('Agg')
287
288  import matplotlib.pyplot as plt
289  from matplotlib.backends.backend_pdf import PdfPages
290
291  if not args.show:
292    plt.ioff()
293
294  # ... Files and directories ...
295  # -----------------------------
296  file_param = get_last_file(DIR["SAVEDATA"], OUT["PARAM"])
297  file_utheo = get_last_file(DIR["SAVEDATA"], OUT["UTHEO"])
298  file_bilan = get_last_file(DIR["SAVEDATA"], OUT["BILAN"])
299
300  if file_param is None or \
301     file_utheo is None or \
302     file_bilan is None:
303    print("Missing one or more input files, we stop.")
304    print("=> PARAM: {}\n=> UTHEO: {}\n=> BILAN: {}".format(
305              file_param, file_utheo, file_bilan)
306          )
307    exit(1)
308
309  img_name = "bilan"
310  today = os.path.basename(file_param).strip(OUT["PARAM"])
311
312  if args.verbose:
313    print(file_param)
314    print(file_utheo)
315    print(file_bilan)
316    print(img_name)
317    print(today)
318    print(DIR)
319    print(OUT)
320
321  # .. Get project info ..
322  # ======================
323  gencmip6 = Project()
324  gencmip6.fill_data(file_param)
325  gencmip6.get_date_init(file_utheo)
326
327  # .. Fill in conso data ..
328  # ========================
329  # ... Initialization ...
330  # ----------------------
331  bilan = BilanDict()
332  bilan.init_range(gencmip6.date_init, gencmip6.deadline)
333  # ... Extract data from file ...
334  # ------------------------------
335  bilan.fill_data(file_bilan)
336  # ... Compute theoratical use from known data  ...
337  # ------------------------------------------------
338  bilan.theo_equation()
339
340  # .. Extract data depending on C.L. arguments ..
341  # ==============================================
342  if args.full:
343    selected_items = bilan.get_items_in_full_range(args.inc)
344  elif args.range:
345    selected_items = bilan.get_items_in_range(
346      args.range[0], args.range[1], args.inc
347    )
348  else:
349    selected_items = bilan.get_items(args.inc)
350
351  # .. Compute data to be plotted ..
352  # ================================
353  nb_items = len(selected_items)
354
355  xcoord    = np.linspace(1, nb_items, num=nb_items)
356  xlabels   = ["{:%d-%m}".format(item.date)
357               for item in selected_items]
358  cumul     = np.array([item.conso for item in selected_items],
359                        dtype=float)
360  consos    = []
361  consos.append(cumul[0])
362  consos[1:nb_items] = cumul[1:nb_items] - cumul[0:nb_items-1]
363  consos    = np.array(consos, dtype=float)
364
365  conso_per_day = np.array([gencmip6.alloc / nb_items
366                              for item in selected_items], dtype=float)
367
368  theo_uses = np.array([100.*item.theo_use for item in selected_items],
369                       dtype=float)
370  real_uses = np.array([100.*item.real_use for item in selected_items],
371                       dtype=float)
372  theo_equs = np.array([100.*item.theo_equ for item in selected_items],
373                       dtype=float)
374
375  # .. Plot stuff ..
376  # ================
377  # ... Initialize figure ...
378  # -------------------------
379  (fig, ax_conso, ax_theo) = plot_init()
380
381  # ... Plot data ...
382  # -----------------
383  plot_data(ax_conso, ax_theo, xcoord, xlabels,
384            consos, conso_per_day, theo_uses, real_uses, theo_equs)
385
386  # ... Tweak figure ...
387  # --------------------
388  if args.max:
389    ymax = gencmip6.alloc
390  else:
391    ymax = np.nanmax(consos) + np.nanmax(consos)*.1
392
393  title = "Consommation {}\n({:%d/%m/%Y} - {:%d/%m/%Y})".format(
394    gencmip6.project.upper(),
395    gencmip6.date_init,
396    gencmip6.deadline
397  )
398
399  plot_config(ax_conso, ax_theo, xcoord, xlabels, ymax, title)
400
401  # ... Save figure ...
402  # -------------------
403  # plot_save(os.path.join(DIR["PLOT"], img_name))
404  img_in  = os.path.join(DIR["PLOT"], "{}.pdf".format(img_name))
405  plot_save(img_in)
406  if os.path.isdir(DIR["SAVEPLOT"]):
407    img_out = os.path.join(DIR["SAVEPLOT"],
408                           "{}_{}.pdf".format(img_name, today))
409    shutil.copy(img_in, img_out)
410
411  # ... Publish figure on dods ...
412  # ------------------------------
413  if args.dods:
414    dods_cp(img_in)
415
416  if args.show:
417    plt.show()
418
419  exit(0)
Note: See TracBrowser for help on using the repository browser.