예제 #1
0
 def setVariableOrFloats(self, value):
     """
   Set variable
   @ In, value, str or float or list, the value of given variable
   @ Out, ret, str or float or numpy.array, the recasted value
 """
     ret = None
     # multi-entry or single-entry?
     if len(value) == 1:
         # single entry should be either a float (price) or string (raven variable)
         value = value[0]
         if utils.isAString(value) or utils.isAFloatOrInt(value):
             ret = value
         else:
             raise IOError(
                 'Unrecognized alpha/driver type: "{}" with type "{}"'.
                 format(value, type(value)))
     else:
         # should be floats; InputData assures the entries are the same type already
         if not utils.isAFloatOrInt(value[0]):
             raise IOError(
                 'Multiple non-number entries for alpha/driver found, but require either a single variable name or multiple float entries: {}'
                 .format(value))
         ret = np.asarray(value)
     return ret
예제 #2
0
 def findRow(self,row,csv):
   """
     Searches for "row" in "csv"
     @ In, row, pd.Series, row of data
     @ In, csv, pd.Dataframe, dataframe to look in
     @ Out, match, pd.Dataframe or list, matching row of data (or empty list if none found)
   """
   if debug:
     print('')
     print('Looking for:\n',row)
     print('Looking in:\n',csv)
   match = csv.copy()
   # TODO can I do this as a single search, using binomial on floats +- rel_err?
   for idx, val in row.iteritems():
     if debug:
       print('  checking index',idx,'value',val)
     # Due to relative matches in floats, we may not be sorted with respect to this index.
     ## In an ideal world with perfect matches, we would be.  Unfortunately, we have to sort again.
     match = match.sort_values(idx)
     # check type consistency
     ## get a sample from the matching CSV column
     ### TODO could check indices ONCE and re-use instead of checking each time
     matchVal = match[idx].values.item(0) if match[idx].values.shape[0] != 0 else None
     ## find out if match[idx] and/or "val" are numbers
     matchIsNumber = mathUtils.isAFloatOrInt(matchVal)
     valIsNumber = mathUtils.isAFloatOrInt(val)
     ## if one is a number and the other is not, consider it a non-match.
     if matchIsNumber != valIsNumber:
       if debug:
         print('  Not same type (number)! lfor: "{}" lin: "{}"'.format(valIsNumber,matchIsNumber))
       return []
     # find index of lowest and highest possible matches
     ## if values are floats, then matches could be as low as val(1-rel_err) and as high as val(1+rel_err)
     if matchIsNumber:
       # adjust for negative values
       sign = np.sign(val)
       lowest = np.searchsorted(match[idx].values,val*(1.0-sign*self.__rel_err))
       highest = np.searchsorted(match[idx].values,val*(1.0+sign*self.__rel_err),side='right')-1
     ## if not floats, then check exact matches
     else:
       lowest = np.searchsorted(match[idx].values,val)
       highest = np.searchsorted(match[idx].values,val,side='right')-1
     if debug:
       print('  low/hi match index:',lowest,highest)
     ## if lowest is past end of array, no match found
     if lowest == len(match[idx]):
       if debug:
         print('  Match is past end of sort list!')
       return []
     ## if entry at lowest index doesn't match entry, then it's not to be found
     if not self.matches(match[idx].values[lowest],val,matchIsNumber,self.__rel_err):
       if debug:
         print('  Match is not equal to insert point!')
       return []
     ## otherwise, we have some range of matches
     match = match[slice(lowest,highest+1)]
     if debug:
       print('  After searching for {}={}, remaining matches:\n'.format(idx,val),match)
   return match
예제 #3
0
 def extendParameters(self, toExtend, t):
     """
   Extend values of parameters to the length of lifetime t
   @ In, toExtend, dict, the dict of parameters that need to extend
   @ In, t, int, the given life time
   @ Out, toExtend, dict, dict to extend
 """
     # for capex, both the Driver and Alpha are nonzero in year 1 and zero thereafter
     for name, value in toExtend.items():
         if name.lower() in ['alpha', 'driver']:
             if utils.isAFloatOrInt(value) or (
                     len(value) == 1 and utils.isAFloatOrInt(value[0])):
                 new = np.zeros(t)
                 new[0] = float(value)
                 toExtend[name] = new
     return toExtend
예제 #4
0
 def prep_data_frame(self, csv, tol):
     """
   Does several prep actions:
     - For any columns that contain numbers, drop near-zero numbers to zero
     - replace infs and nans with symbolic values
   @ In, csv, pd.DataFrame, contents to reduce
   @ In, tol, float, tolerance sufficently near zero
   @ Out, csv, converted dataframe
 """
     # use absolute or relative?
     key = {'atol': tol} if self.__check_absolute_values else {'rtol': tol}
     # take care of infinites
     csv = csv.replace(np.inf, -sys.float_info.max)
     csv = csv.replace(np.nan, sys.float_info.max)
     for col in csv.columns:
         example = csv[col].values.item(
             0) if csv[col].values.shape[0] != 0 else None
         # skip columns that aren't numbers TODO might skip float columns with "None" early on
         if not mathUtils.isAFloatOrInt(example):
             continue
         # flatten near-zeros
         csv[col].values[np.isclose(csv[col].values, 0, **key)] = 0
     # TODO would like to sort here, but due to relative errors it doesn't do
     #  enough good.  Instead, sort in findRow.
     return csv
예제 #5
0
 def extendParameters(self, toExtend, t):
     """
   Extend values of parameters to the length of lifetime t
   @ In, toExtend, dict, the dict of parameters that need to extend
   @ In, t, int, the given life time
   @ Out, None
 """
     # for recurring, both the Driver and Alpha are zero in year 1 and nonzero thereafter
     # FIXME: we're going to integrate alpha * D over time (not year time, intrayear time)
     for name, value in toExtend.items():
         if name.lower() in ['alpha']:
             if utils.isAFloatOrInt(value) or (
                     len(value) == 1 and utils.isAFloatOrInt(value[0])):
                 new = np.ones(t) * float(value)
                 new[0] = 0
                 toExtend[name] = new
     return toExtend
예제 #6
0
def componentLifeCashflow(comp, cf, variables, lifetimeCashflows, v=100):
  """
    Calcualtes the annual lifetime-based cashflow for a cashflow of a component
    @ In, comp, CashFlows.Component, component whose cashflow is being analyzed
    @ In, cf, CashFlows.CashFlow, cashflow who is being analyzed
    @ In, variables, dict, RAVEN variables as name: value
    @ In, v, int, verbosity
    @ Out, lifeCashflow, np.array, array of cashflow values with length of component life
  """
  m = 'compLife'
  vprint(v, 1, m, "-"*75)
  print('DEBUGG comp:', comp.name, cf)
  vprint(v, 1, m, 'Computing LIFETIME cash flow for Component "{}" CashFlow "{}" ...'.format(comp.name, cf.name))
  paramText = '... {:^10.10s}: {: 1.9e}'
  # do cashflow
  results = cf.calculateCashflow(variables, lifetimeCashflows, comp.getLifetime()+1, v)
  lifeCashflow = results['result']

  if v < 1:
    # print out all of the parts of the cashflow calc
    for item, value in results.items():
      if item == 'result':
        continue
      if utils.isAFloatOrInt(value):
        vprint(v, 1, m, paramText.format(item, value))
      else:
        orig = cf.getParam(item)
        if utils.isSingleValued(orig):
          name = orig
        else:
          name = '(from input)'
        vprint(v, 1, m, '... {:^10.10s}: {}'.format(item, name))
        vprint(v, 1, m, '...           mean: {: 1.9e}'.format(value.mean()))
        vprint(v, 1, m, '...           std : {: 1.9e}'.format(value.std()))
        vprint(v, 1, m, '...           min : {: 1.9e}'.format(value.min()))
        vprint(v, 1, m, '...           max : {: 1.9e}'.format(value.max()))
        vprint(v, 1, m, '...           nonz: {:d}'.format(np.count_nonzero(value)))

    yx = max(len(str(len(lifeCashflow))),4)
    vprint(v, 0, m, 'LIFETIME cash flow summary by year:')
    vprint(v, 0, m, '    {y:^{yx}.{yx}s}, {a:^10.10s}, {d:^10.10s}, {c:^15.15s}'.format(y='year',
                                                                                        yx=yx,
                                                                                        a='alpha',
                                                                                        d='driver',
                                                                                        c='cashflow'))
    for y, cash in enumerate(lifeCashflow):
      if cf.type in ['Capex']:
        vprint(v, 1, m, '    {y:^{yx}d}, {a: 1.3e}, {d: 1.3e}, {c: 1.9e}'.format(y=y,
                                                                                 yx=yx,
                                                                                 a=results['alpha'][y],
                                                                                 d=results['driver'][y],
                                                                                 c=cash))
      elif cf.type == 'Recurring':
        vprint(v, 1, m, '    {y:^{yx}d}, -- N/A -- , -- N/A -- , {c: 1.9e}'.format(y=y,
                                                           yx=yx,
                                                           c=cash))
  return lifeCashflow
예제 #7
0
 def setVariable(self, value):
   """
     Set value if a float/int/list is provided in the node text, othersise treat the provided value as RAVEN variable
     @ In, value, str or float or list, the value of given variable
     @ Out, ret, str or float or numpy.array, the recasted value
   """
   ret = None
   # multi-entry or single-entry?
   if len(value) == 1:
     if not utils.isAFloatOrInt(value[0]):
       ret = value[0]
     else:
       ret = np.atleast_1d(value)
   else:
     # should be floats; InputData assures the entries are the same type already
     if not utils.isAFloatOrInt(value[0]):
       raise IOError('Multiple non-number entries are found, but require either a single variable name or multiple float entries: {}'.format(value))
     ret = np.asarray(value)
   return ret
예제 #8
0
 def extendParameters(self, toExtend, t):
     """
   Extend values of parameters to the length of lifetime t
   @ In, toExtend, dict, the dict of parameters that need to extend
   @ In, t, int, the given life time
   @ Out, None
 """
     # unlike normal capex, for amortization we expand the driver to all nonzero entries and keep alpha as is
     # TODO forced driver values for now
     driver = toExtend['driver']
     # how we treat the driver depends on if this is the amortizer or the depreciator
     if self.name.split('_')[-2] == 'amortize':
         if not utils.isAString(driver):
             toExtend['driver'] = np.ones(t) * driver[0] * -1.0
             toExtend['driver'][0] = 0.0
         for name, value in toExtend.items():
             if name.lower() in ['driver']:
                 if utils.isAFloatOrInt(value) or (
                         len(value) == 1 and utils.isAFloatOrInt(value[0])):
                     new = np.zeros(t)
                     new[1:] = float(value)
                     toExtend[name] = new
     return toExtend
예제 #9
0
def _createEvalProcess(components, variables):
  """
    Sorts the cashflow evaluation process so sensible evaluation order is used
    @ In, components, list, list of CashFlows.Component instances
    @ In, variables, dict, variable-value map from RAVEN
    @ Out, ordered, list, list of ordered cashflows to evaluate (in order)
  """
  # TODO does this work with float drivers (e.g. already-evaluated drivers)?
  # storage for creating graph sequence
  driverGraph = defaultdict(list)
  driverGraph['EndNode'] = []
  evaluated = [] # for cashflows that have already been evaluated and don't need more treatment
  for comp in components:
    lifetime = comp.getLifetime()
    # find multiplier variables
    multipliers = comp.getMultipliers()
    for mult in multipliers:
      if mult is None:
        continue
      if mult not in variables.keys():
        raise RuntimeError('CashFlow: multiplier "{}" required for Component "{}" but not found among variables!'.format(mult, comp.name))
    # find order in which to evaluate cash flow components
    for c, cf in enumerate(comp.getCashflows()):
      # keys for graph are drivers, cash flow names
      driver = cf.getParam('driver')
      # does the driver come from the variable list, or from another cashflow, or is it already evaluated?
      cfn = '{}|{}'.format(comp.name, cf.name)
      found = False
      if driver is None or utils.isAFloatOrInt(driver) or isinstance(driver, np.ndarray):
        found = True
        # TODO assert it's already filled?
        evaluated.append(cfn)
        continue
      elif driver in variables:
        found = True
        # check length of driver
        n = len(np.atleast_1d(variables[driver]))
        if n > 1 and n != lifetime+1:
          raise RuntimeError(('Component "{c}" TEAL {cf} driver variable "{d}" has "{n}" entries, '+\
                              'but "{c}" has a lifetime of {el}!')
                             .format(c=comp.name,
                                     cf=cf.name,
                                     d=driver,
                                     n=n,
                                     el=lifetime))
      else:
        # driver should be in cash flows if not in variables
        driverComp, driverCf = driver.split('|')
        for matchComp in components:
          if matchComp.name == driverComp:
            # for cross-referencing, component lifetimes have to be the same!
            if matchComp.getLifetime() != comp.getLifetime():
              raise RuntimeError(('Lifetimes for Component "{d}" and cross-referenced Component {m} ' +\
                                  'do not match, so no cross-reference possible!')
                                 .format(d=driverComp, m=matchComp.name))
            found = True # here this means that so far the component was found, not the specific cash flow.
            break
        else:
          found = False
        # if the component was found, check the cash flow is part of the component
        if found:
          if driverCf not in list(m_cf.name for m_cf in matchComp.getCashflows()):
            found = False
      if not found:
        raise RuntimeError(('Component "{c}" TEAL {cf} driver variable "{d}" was not found ' +\
                            'among variables or other cashflows!')
                           .format(c=comp.name,
                                   cf=cf.name,
                                   d=driver))

      # assure each cashflow is in the mix, and has an EndNode to rely on (helps graph construct accurately)
      driverGraph[cfn].append('EndNode')
      # each driver depends on its cashflow
      driverGraph[driver].append(cfn)
  return evaluated + graphObject(driverGraph).createSingleListOfVertices()
예제 #10
0
checkAnswer('isSingleValued set', mathUtils.isSingleValued((1, )), False)
checkAnswer('isSingleValued nparray', mathUtils.isSingleValued(np.array([1])),
            False)
checkAnswer('isSingleValued dict', mathUtils.isSingleValued({1: 2}), False)

# isAString
# TODO how to get a string (not unicode) after import unicode literals?
#checkAnswer('isAString string',mathUtils.isAString(bytes_to_native_str(b'alpha')),True)
checkAnswer('isAString strish', mathUtils.isAString('alpha'), True)
checkAnswer('isAString unicode', mathUtils.isAString(u'beta'), True)
checkAnswer('isAString float', mathUtils.isAString(1.0), False)
checkAnswer('isAString int', mathUtils.isAString(1), False)
checkAnswer('isAString bool', mathUtils.isAString(True), False)

# isAFloatOrInt
checkAnswer('isAFloatOrInt 0', mathUtils.isAFloatOrInt(0), True)
checkAnswer('isAFloatOrInt 1', mathUtils.isAFloatOrInt(1), True)
checkAnswer('isAFloatOrInt 3.14', mathUtils.isAFloatOrInt(3.14), True)
checkAnswer('isAFloatOrInt str', mathUtils.isAFloatOrInt('gamma'), False)
checkAnswer('isAFloatOrInt bool', mathUtils.isAFloatOrInt(True), False)

checkAnswer('isAFloatOrInt nan ok', mathUtils.isAFloatOrInt(np.nan), True)
checkAnswer('isAFloatOrInt inf ok', mathUtils.isAFloatOrInt(np.inf), True)
checkAnswer('isAFloatOrInt nan not ok',
            mathUtils.isAFloatOrInt(np.nan, nanOk=False), False)
checkAnswer('isAFloatOrInt inf not ok',
            mathUtils.isAFloatOrInt(np.inf, nanOk=False), False)
checkAnswer('isAFloatOrInt long',
            mathUtils.isAFloatOrInt(123456789012345678901234567890), True)

# isAFloat