# -*- coding: utf-8 -*- """ Created on Fri Nov 20 10:11:06 2015 @author: tlbl """ from __future__ import print_function from __future__ import division from __future__ import unicode_literals from __future__ import absolute_import # arctan and pi are required because they are in the formulas that are # evaluated from numpy import (floor, arctan, pi, log, log10, sin, cos, tan, e, arcsin, arccos) import pandas as pd import xlrd from argparse import ArgumentParser import os def multi_for(iterables): """ Routine to create list with combination of elements. """ if not iterables: yield () else: for item in iterables[0]: for rest_tuple in multi_for(iterables[1:]): yield (item,) + rest_tuple class GeneralDLC(object): """ Basic class to generate the DLC spreadsheets. It contains routines to handle the different types of tags. * Constants: are fixed in the current DLC, e.g. reference turbulence\ intensity, rotor radius, reference wind speed, .... * Variables: define the number of cases in a DLC through their combination\ e.g. wind speed, number of turbulence seeds, yaw angle, .... * Functions: depend on other tags e.g turbulence intensity, file name, .... """ def __init__(self): pass def remove_from_dict(self, non_defaults, defaults): for key in non_defaults.keys(): try: del defaults[key] except: pass return defaults def add_variables_tag(self, dlc, variables, variables_order): cases_len = [] for tag in variables_order: dlc[tag] = [] v = variables[tag] for i in range(len(v)-1): try: v.remove('') except: pass if tag == '[seed]': cases_len.append(int(v[0])) elif tag == '[wave_seed]': cases_len.append(int(v[0])) else: cases_len.append(len(v)) cases_index = multi_for(list(map(range, cases_len))) # when no seeds are used, otherwise i_seed is not set i_seed = -1 if '[wsp]' in variables_order: i_wsp = variables_order.index('[wsp]') len_wsp = len(variables['[wsp]']) else: raise ValueError('Missing VARIABLE (V) [wsp] tag!') if '[seed]' in variables_order: i_seed = variables_order.index('[seed]') if '[wave_seed]' in variables_order: i_wave_seed = variables_order.index('[wave_seed]') if i_seed > i_wsp: raise ValueError('column [seed] should come BEFORE [wsp] !!') for irow, row in enumerate(cases_index): for icol, col in enumerate(row): if variables_order[icol] == '[seed]': counter = floor(irow/len_wsp) + 1 value = '%4.4i' % (1000*counter + row[i_wsp] + 1) elif variables_order[icol] == '[wave_seed]': value = '%4.4i' % (100*(row[i_wsp]+1) + row[i_wave_seed] + 1) # value = '%4.4i' % (1000*counter + row[i_wsp] + 101) # value = '%4.4i' % (irow+1) # value = '%4.4i' % (10000*(row[i_wave_dir])] + 1) + \ # 1000*(row[i_Hs])] + 1) + \ # 10*(row[i_Tp])] + 1) +\ # row[i_seed])] + 1) else: value = variables[variables_order[icol]][col] if not isinstance(value, float) and not isinstance(value, int): value = str(value) dlc[variables_order[icol]].append(value) def add_constants_tag(self, dlc, constants): for key in constants.keys(): dlc[key] = [constants[key]]*len(dlc['[wsp]']) def sort_formulas(self, formulas): # sort formulas based on their dependency keys_list = sorted(formulas) for i in range(len(keys_list)): for ikey, key in enumerate(keys_list): formula = formulas[key] for ikey2, key2 in enumerate(keys_list): if key2 in formula: if ikey < ikey2: keys_list.pop(ikey) keys_list.insert(ikey2, key) break return keys_list def eval_formulas(self, dlc): for key in dlc.keys(): if isinstance(dlc[key][0], str): if "[" in dlc[key][0]: for key2 in dlc.keys(): for iformula, formula in enumerate(dlc[key]): if key2 in formula: dlc[key][iformula] = dlc[key][iformula].replace(key2, '%s'%dlc[key2][iformula]) for iformula, formula in enumerate(dlc[key]): formula = formula.replace(',', '.') formula = formula.replace(';', ',') dlc[key][iformula] = eval(formula) def add_formulas(self, dlc, formulas): keys_list = self.sort_formulas(formulas) # specify the precision of the tag as used in the formulas # this does NOT affect the precision of the tag itself, only when used # in a formula based tag. formats = {'[wsp]':'%02i', '[gridgustdelay]':'%02i', '[wdir]':'%03i', '[G_phi0]':'%03i', '[sign]':'%s', '[Hs]':'%05.02f', '[Tp]':'%05.02f'} for fkey in keys_list: flist = [] for i in range(len(dlc['[wsp]'])): formula = formulas[fkey] for key in dlc.keys(): if key in formula: if formula[0] == '"': try: fmt = formats[key] except KeyError: fmt = '%04i' try: value = float(dlc[key][i]) except ValueError: # this is for string tags value = dlc[key][i] fmt = '%s' formula = formula.replace(key, fmt % value) elif key in formula: formula = formula.replace(key, '%s' % dlc[key][i]) formula = formula.replace(',', '.') formula = formula.replace(';', ',') formula = formula.replace('\n', ' ') try: flist.append(eval(formula)) except Exception as exc: print('following formula failed to execute:') print(formula) print('and raised the following exception:') raise exc dlc[fkey] = flist class GenerateDLCCases(GeneralDLC): """ Class to generate Excell sheets for each DLB case starting from a single Excell sheet. Parameters ---------- filename: str Name of the excel spreadsheet containing the definition of all the cases to generate. folder: str Name of the folder in which to save the DLB cases. Example ------- DLB = GenerateDLCCases() DLB.execute() """ def execute(self, filename='DLCs.xlsx', folder='', isheets=None): book = xlrd.open_workbook(filename) if isheets is None: isheets = list(range(1, book.nsheets)) # Loop through all the sheets. Each sheet correspond to a DLC. for isheet in isheets: # Read all the initialization constants and functions in the # first sheet general_constants = {} general_functions = {} sheet = book.sheets()[0] for i in range(1, sheet.ncols): if sheet.cell_value(9, i) != '': general_constants[str(sheet.cell_value(9, i))] = \ sheet.cell_value(10, i) if sheet.cell_value(13, i) != '': general_functions[str(sheet.cell_value(13, i))] = \ sheet.cell_value(14, i) sheet = book.sheets()[isheet] print('Sheet #%i' % isheet, sheet.name) # Read the actual sheet. constants = {} variables = {} formulas = {} variables_order = [] # Loop through the columns for i in range(sheet.ncols): if sheet.cell_value(1, i) is not None: tag = str(sheet.cell_value(1, i)) if tag is not '': # FIXME: only works if [wsp] is defined as variable # and [seed] tags are present if sheet.cell_value(0, i) == 'C': constants[tag] = sheet.cell_value(2, i) if sheet.cell_value(0, i) == 'V': variables_order.append(tag) variables[tag] = \ [sheet.cell_value(j, i) for j in range(2, sheet.nrows)] if sheet.cell_value(0, i) == 'F': formulas[tag] = str(sheet.cell_value(2, i)) dlc = {} general_constants = self.remove_from_dict(variables, general_constants) general_constants = self.remove_from_dict(constants, general_constants) general_functions = self.remove_from_dict(formulas, general_functions) self.add_variables_tag(dlc, variables, variables_order) self.add_constants_tag(dlc, general_constants) self.add_constants_tag(dlc, constants) self.add_formulas(dlc, formulas) self.add_formulas(dlc, general_functions) # TODO: before eval, check if all tags in formula's are present self.eval_formulas(dlc) df = pd.DataFrame(dlc) if not os.path.exists(folder): os.makedirs(folder) df.to_excel(os.path.join(folder, sheet.name+'.xlsx'), index=False) if __name__ == '__main__': parser = ArgumentParser(description = "generator of DLB spreadsheets") parser.add_argument('--master', type=str, default='DLCs.xlsx', action='store', dest='filename', help='Master spreadsheet file') parser.add_argument('--folder', type=str, default='', action='store', dest='folder', help='Destination folder name') opt = parser.parse_args() DLB = GenerateDLCCases() DLB.execute(filename=opt.filename, folder=opt.folder)