Esempio n. 1
0
    def __init__(self,
                 start,
                 end,
                 measures,
                 accumulated=None,
                 drag_by_periods=True):
        self.measures = measures[:]
        self.gaps = []  # Containing the gaps and invalid measures
        self.adjusted_periods = []  # If a period is adjusted
        self.start_date = start
        self.end_date = end
        self.profile_class = REEProfile

        assert type(
            drag_by_periods) == bool, "drag_by_periods must be a Boolean"
        self.drag_by_periods = drag_by_periods

        self.accumulated = Decimal(0)
        if accumulated:
            assert type(accumulated) == float or isinstance(
                accumulated,
                Decimal), "Provided accumulated must be a Decimal or a float"
            assert accumulated < 1 and accumulated > -1, "Provided accumulated '{}' must be -1 < accumulated < 1".format(
                accumulated)
            self.accumulated = accumulated

        measures_by_date = dict([(m.date, m.measure) for m in measures
                                 if m.valid])
        # End is included
        while start <= end:
            if measures_by_date.pop(TIMEZONE.normalize(start), None) is None:
                self.gaps.append(start)
            start += timedelta(hours=1)
Esempio n. 2
0
    def __init__(self, start, end, measures, accumulated=None, drag_by_periods=True):
        self.measures = measures[:]
        self.gaps = []  # Containing the gaps and invalid measures
        self.adjusted_periods = [] # If a period is adjusted
        self.start_date = start
        self.end_date = end
        self.profile_class = REEProfile

        assert type(drag_by_periods) == bool, "drag_by_periods must be a Boolean"
        self.drag_by_periods = drag_by_periods

        self.accumulated = Decimal(0)
        if accumulated:
            assert type(accumulated) == float or isinstance(accumulated, Decimal), "Provided accumulated must be a Decimal or a float"
            assert accumulated < 1 and accumulated > -1, "Provided accumulated '{}' must be -1 < accumulated < 1".format(accumulated)
            self.accumulated = accumulated

        measures_by_date = dict(
            [(m.date, m.measure) for m in measures if m.valid]
        )
        # End is included
        while start <= end:
            if measures_by_date.pop(TIMEZONE.normalize(start), None) is None:
                self.gaps.append(start)
            start += timedelta(hours=1)
Esempio n. 3
0
def get_station(dt):
    assert isinstance(dt, datetime)
    if not dt.tzinfo:
        dt = TIMEZONE.localize(dt)
    if TIMEZONE.normalize(dt).dst():
        return 'summer'
    else:
        return 'winter'
Esempio n. 4
0
 def get(self, dt):
     assert isinstance(dt, datetime)
     if dt.dst() is None:
         dt = TIMEZONE.localize(dt)
     dt = TIMEZONE.normalize(dt)
     pos = bisect.bisect_left(self.coefs, Coefficent(dt, {}))
     self._check_pos(pos)
     return self.coefs[pos]
Esempio n. 5
0
 def get(self, dt):
     assert isinstance(dt, datetime)
     if dt.dst() is None:
         dt = TIMEZONE.localize(dt)
     dt = TIMEZONE.normalize(dt)
     pos = bisect.bisect_left(self.coefs, Coefficent(dt, {}))
     self._check_pos(pos)
     return self.coefs[pos]
Esempio n. 6
0
 def get(cls, year, month):
     try:
         import ssl
         try:
             _create_unverified_https_context = ssl._create_unverified_context
         except AttributeError:
             pass
         else:
             ssl._create_default_https_context = _create_unverified_https_context
     except ImportError:
         pass
     try:
         cls.down_lock.acquire()
         import csv
         import httplib
         key = '%(year)s%(month)02i' % locals()
         conn = None
         if key in cls._CACHE:
             logger.debug('Using CACHE for REEProfile {0}'.format(key))
             return cls._CACHE[key]
         perff_file = 'PERFF_%(key)s.gz' % locals()
         conn = httplib.HTTPSConnection(cls.HOST)
         conn.request('GET', '%s/%s' % (cls.PATH, perff_file))
         logger.debug('Downloading REEProfile from {0}/{1}'.format(
             cls.PATH, perff_file))
         r = conn.getresponse()
         if r.msg.type == 'application/x-gzip':
             import gzip
             c = StringIO(r.read())
             m = StringIO(gzip.GzipFile(fileobj=c).read())
             c.close()
             reader = csv.reader(m, delimiter=';')
             header = True
             cofs = []
             coeffs_list = get_tariff_coeffs_list(year, month)
             for vals in reader:
                 if header:
                     header = False
                     continue
                 if int(vals[3]) == 1:
                     n_hour = 1
                 dt = datetime(int(vals[0]), int(vals[1]), int(vals[2]))
                 day = TIMEZONE.localize(dt, is_dst=bool(not int(vals[4])))
                 day += timedelta(hours=n_hour)
                 n_hour += 1
                 cofs.append(
                     Coefficent(
                         TIMEZONE.normalize(day),
                         dict((k, float(vals[i]))
                              for i, k in enumerate(coeffs_list, 5))))
             cls._CACHE[key] = cofs
             return cofs
         else:
             raise Exception('Profiles from REE not found')
     finally:
         if conn is not None:
             conn.close()
         cls.down_lock.release()
Esempio n. 7
0
 def get_period_by_timestamp(self, timestamp):
     """
     Gets the number of energy period
     :param timestamp: datetime in format 'YYYY-MM-DD HH'
     :return: period number
     """
     day, hours = timestamp.split(' ')
     dt_tz = TIMEZONE.normalize(TIMEZONE.localize(datetime.strptime(day, '%Y-%m-%d')) + timedelta(hours=int(hours)))
     # "get_period_by_date" expects a local timestamp without timezone
     # decreases 1 minute because is final datetime open interval (not included)
     dt = dt_tz.replace(tzinfo=None) - timedelta(minutes=1)
     return self.get_period_by_date(dt).code
Esempio n. 8
0
    def estimate(self, tariff, balance):
        assert isinstance(tariff, Tariff)
        logger.debug('Estimating for tariff: {0}'.format(
            tariff.code
        ))
        measures = [x for x in self.measures if x.valid]
        start = self.start_date
        end = self.end_date
        cofs = self.profile_class.get_range(start, end)
        cofs = Coefficients(cofs)
        cofs_per_period = Counter()
        for gap in self.gaps:
            period = tariff.get_period_by_date(gap)
            gap_cof = cofs.get(gap)
            cofs_per_period[period.code] += gap_cof.cof[tariff.cof]

        logger.debug('Coefficients per period calculated: {0}'.format(
            cofs_per_period
        ))

        energy_per_period = self.get_estimable_consumption(tariff, balance)
        energy_per_period_rem = energy_per_period.copy()

        dragger = Dragger()

        for idx, gap in enumerate(self.gaps):
            logger.debug('Gap {0}/{1}'.format(
                idx + 1, len(self.gaps)
            ))
            drag_key = period.code
            period = tariff.get_period_by_date(gap)
            gap_cof = cofs.get(gap).cof[tariff.cof]
            energy = energy_per_period[period.code]
            # If the balance[period] < energy_profile[period] fill with 0
            # the gaps
            if energy < 0:
                energy = 0
            gap_energy = (energy * gap_cof) / cofs_per_period[period.code]
            aprox = dragger.drag(gap_energy, key=drag_key)
            energy_per_period_rem[period.code] -= gap_energy
            logger.debug(
                'Energy for hour {0} is {1}. {2} Energy {3}/{4}'.format(
                    gap, aprox, period.code,
                    energy_per_period_rem[period.code], energy
            ))
            pos = bisect.bisect_left(measures, ProfileHour(gap, 0, True))
            profile_hour = ProfileHour(TIMEZONE.normalize(gap), aprox, True)
            measures.insert(pos, profile_hour)
        profile = Profile(self.start_date, self.end_date, measures)
        return profile
Esempio n. 9
0
 def get(cls, year, month):
     try:
         cls.down_lock.acquire()
         import csv
         import httplib
         key = '%(year)s%(month)02i' % locals()
         conn = None
         if key in cls._CACHE:
             logger.debug('Using CACHE for REEProfile {0}'.format(key))
             return cls._CACHE[key]
         perff_file = 'PERFF_%(key)s.gz' % locals()
         conn = httplib.HTTPConnection(cls.HOST)
         conn.request('GET', '%s/%s' % (cls.PATH, perff_file))
         logger.debug('Downloading REEProfile from {0}/{1}'.format(
             cls.PATH, perff_file
         ))
         r = conn.getresponse()
         if r.msg.type == 'application/x-gzip':
             import gzip
             c = StringIO(r.read())
             m = StringIO(gzip.GzipFile(fileobj=c).read())
             c.close()
             reader = csv.reader(m, delimiter=';')
             header = True
             cofs = []
             for vals in reader:
                 if header:
                     header = False
                     continue
                 if int(vals[3]) == 1:
                     n_hour = 1
                 dt = datetime(
                     int(vals[0]), int(vals[1]), int(vals[2])
                 )
                 day = TIMEZONE.localize(dt, is_dst=bool(not int(vals[4])))
                 day += timedelta(hours=n_hour)
                 n_hour += 1
                 cofs.append(Coefficent(
                     TIMEZONE.normalize(day), dict(
                         (k, float(vals[i])) for i, k in enumerate('ABCD', 5)
                     ))
                 )
             cls._CACHE[key] = cofs
             return cofs
         else:
             raise Exception('Profiles from REE not found')
     finally:
         if conn is not None:
             conn.close()
         cls.down_lock.release()
Esempio n. 10
0
    def __init__(self, start, end, measures):
        self.measures = measures[:]
        self.gaps = []  # Containing the gaps and invalid measures
        self.start_date = start
        self.end_date = end
        self.profile_class = REEProfile

        measures_by_date = dict(
            [(m.date, m.measure) for m in measures if m.valid]
        )
        # End is included
        while start <= end:
            if measures_by_date.pop(TIMEZONE.normalize(start), None) is None:
                self.gaps.append(start)
            start += timedelta(hours=1)
Esempio n. 11
0
 def get(cls, m, header):
     import csv
     reader = csv.reader(m, delimiter=';')
     cofs = []
     n_hour = 0
     for vals in reader:
         if header:
             header = False
             continue
         if int(vals[3]) == 1:
             n_hour = 1
         dt = datetime(
             int(vals[0]), int(vals[1]), int(vals[2])
         )
         day = TIMEZONE.localize(dt, is_dst=bool(not int(vals[4])))
         day += timedelta(hours=n_hour)
         n_hour += 1
         cofs.append(
             (TIMEZONE.normalize(day), dict(
                 (k, float(vals[i])) for i, k in enumerate('ABCD', 5)
             ))
         )
     return cofs
Esempio n. 12
0
 def get(self, year, month):
     key = '%(year)s%(month)02i' % locals()
     if key in self._CACHE:
         logger.debug('Using CACHE for REEProfile {0}'.format(key))
         return self._CACHE[key]
     with open(self.path, 'r') as m:
         reader = csv.reader(m, delimiter=';')
         header = 2
         cofs = []
         for vals in reader:
             if header:
                 header -= 1
                 continue
             if int(vals[0]) != month:
                 continue
             dt = datetime(year, int(vals[0]), int(vals[1]))
             day = TIMEZONE.localize(dt) + timedelta(hours=int(vals[2]))
             cofs.append(
                 Coefficent(
                     TIMEZONE.normalize(day),
                     dict((k, float(vals[i]))
                          for i, k in enumerate('ABCD', 3))))
         self._CACHE[key] = cofs
         return cofs
Esempio n. 13
0
    def estimate(self, tariff, balance):
        assert isinstance(tariff, Tariff)
        logger.debug('Estimating for tariff: {0}'.format(
            tariff.code
        ))

        # Adapt balance for simplified T30A with just one period
        if isinstance(tariff, T30A_one_period) or isinstance(tariff, T31A_one_period):
            balance = {
                "P1": sum([values for values in balance.values()])
            }
        # Get balance for T31ALB
        if isinstance(tariff, T31A) and tariff.low_voltage_measure:
            balance = tariff.apply_31A_LB_cof(
                balance, self.start_date, self.end_date
            )

        measures = [x for x in self.measures if x.valid]
        start = self.start_date
        end = self.end_date
        # - REE cofs get from (year/month)
        # - Simel cofs get from (year/month/day hour) - can't substract one day
        if self.first_day_of_month or not issubclass(self.profile_class,
                                                     REEProfile):
            cofs = self.profile_class.get_range(start, end)
        else:
            cofs = self.profile_class.get_range(
                start, end - relativedelta(days=1)
            )
        cofs = Coefficients(cofs)
        cofs_per_period = Counter()

        for gap in self.gaps:
            period = tariff.get_period_by_date(gap)
            gap_cof = cofs.get(gap)
            cofs_per_period[period.code] += gap_cof.cof[tariff.cof]

        logger.debug('Coefficients per period calculated: {0}'.format(
            cofs_per_period
        ))

        energy_per_period = self.get_estimable_consumption(tariff, balance)
        energy_per_period_rem = energy_per_period.copy()

        dragger = Dragger()

        # Initialize the Dragger with passed accumulated value
        if len(self.gaps) > 0:
            # Drag by_hours
            if not self.drag_by_periods:
                init_drag_key = "default"
            else:
                init_drag_key = tariff.get_period_by_date(self.gaps[0]).code

            dragger.drag(self.accumulated, key=init_drag_key)

            for idx, gap in enumerate(self.gaps):
                logger.debug('Gap {0}/{1}'.format(
                    idx + 1, len(self.gaps)
                ))
                period = tariff.get_period_by_date(gap)

                drag_key = period.code if not self.drag_by_periods else "default"

                gap_cof = cofs.get(gap).cof[tariff.cof]
                energy = energy_per_period[period.code]
                # If the balance[period] < energy_profile[period] fill with 0
                if energy < 0:
                    energy = 0

                gap_energy = (energy * gap_cof) / cofs_per_period[period.code]
                aprox = dragger.drag(gap_energy, key=drag_key)
                energy_per_period_rem[period.code] -= gap_energy

                logger.debug(
                    'Energy for hour {0} is {1}. {2} Energy {3}/{4}'.format(
                        gap, aprox, period.code,
                        energy_per_period_rem[period.code], energy
                ))
                pos = bisect.bisect_left(measures, ProfileHour(gap, 0, True, 0.0))
                profile_hour = ProfileHour(TIMEZONE.normalize(gap), aprox, True, dragger[drag_key])

                measures.insert(pos, profile_hour)

        profile = Profile(self.start_date, self.end_date, measures)
        return profile
Esempio n. 14
0
    def estimate(self, tariff, balance):
        assert isinstance(tariff, Tariff)
        logger.debug('Estimating for tariff: {0}'.format(tariff.code))

        # Adapt balance for simplified T30A with just one period
        if isinstance(tariff, T30A_one_period) or isinstance(
                tariff, T31A_one_period):
            balance = {"P1": sum([values for values in balance.values()])}
        # Adapt T31A6P adding P4 to P1
        if isinstance(tariff, T31A) and balance.get('P4', 0) > 0:
            balance['P1'] += balance['P4']
            balance['P4'] = 0

        measures = [x for x in self.measures if x.valid]
        start = self.start_date
        end = self.end_date
        # - REE cofs get from (year/month)
        # - Simel cofs get from (year/month/day hour) - can't substract one day
        if self.first_day_of_month or not issubclass(self.profile_class,
                                                     REEProfile):
            cofs = self.profile_class.get_range(start, end)
        else:
            cofs = self.profile_class.get_range(start,
                                                end - relativedelta(days=1))
        cofs = Coefficients(cofs)
        cofs_per_period = Counter()

        for gap in self.gaps:
            dt = gap - timedelta(minutes=1)
            period = tariff.get_period_by_date(dt)
            gap_cof = cofs.get(dt)
            cofs_per_period[period.code] += gap_cof.cof[tariff.cof]

        logger.debug(
            'Coefficients per period calculated: {0}'.format(cofs_per_period))

        energy_per_period = self.get_estimable_consumption(tariff, balance)
        energy_per_period_rem = energy_per_period.copy()

        dragger = Dragger()

        # Initialize the Dragger with passed accumulated value
        if len(self.gaps) > 0:
            # Drag by_hours
            if not self.drag_by_periods:
                init_drag_key = "default"
            else:
                dt = self.gaps[0] - timedelta(minutes=1)
                init_drag_key = tariff.get_period_by_date(dt).code

            dragger.drag(self.accumulated, key=init_drag_key)

            for idx, gap in enumerate(self.gaps):
                logger.debug('Gap {0}/{1}'.format(idx + 1, len(self.gaps)))
                dt = gap - timedelta(minutes=1)
                period = tariff.get_period_by_date(dt)

                drag_key = period.code if not self.drag_by_periods else "default"

                gap_cof = cofs.get(gap).cof[tariff.cof]
                energy = energy_per_period[period.code]
                # If the balance[period] < energy_profile[period] fill with 0
                if energy < 0:
                    energy = 0

                try:
                    gap_energy = (energy *
                                  gap_cof) / cofs_per_period[period.code]
                except ZeroDivisionError as error:
                    gap_energy = 0
                    logger.debug(error)

                aprox = dragger.drag(gap_energy, key=drag_key)
                energy_per_period_rem[period.code] -= gap_energy

                logger.debug(
                    'Energy for hour {0} is {1}. {2} Energy {3}/{4}'.format(
                        gap, aprox, period.code,
                        energy_per_period_rem[period.code], energy))
                pos = bisect.bisect_left(measures,
                                         ProfileHour(gap, 0, True, 0.0))
                profile_hour = ProfileHour(TIMEZONE.normalize(gap), aprox,
                                           True, dragger[drag_key])

                measures.insert(pos, profile_hour)

        profile = Profile(self.start_date, self.end_date, measures)
        return profile