Exemple #1
0
 def adjust(self, tariff, balance, diff=0):
     # Adjust values
     if self.gaps:
         raise Exception('Is not possible to adjust a profile with gaps')
     profile = Profile(self.start_date, self.end_date, self.measures)
     dragger = Dragger()
     energy_per_period = profile.get_consumption_per_period(tariff)
     for period_name, period_balance in balance.items():
         period_profile = energy_per_period[period_name]
         margin_bottom = period_balance - diff
         margin_top = period_balance + diff
         if not margin_bottom <= period_profile <= margin_top:
             profile.adjusted_periods.append(period_name)
             for idx, measure in enumerate(profile.measures):
                 period = tariff.get_period_by_date(measure.date).code
                 if period != period_name:
                     continue
                 values = measure._asdict()
                 values['valid'] = True
                 if not energy_per_period[period]:
                     values['measure'] = dragger.drag(measure.measure * 0)
                 else:
                     values['measure'] = dragger.drag(measure.measure * (
                         balance[period] / energy_per_period[period]
                     ))
                 profile.measures[idx] = measure._replace(**values)
     return profile
Exemple #2
0
 def adjust(self, tariff, balance, diff=0):
     # Adjust values
     if self.gaps:
         raise Exception('Is not possible to adjust a profile with gaps')
     profile = Profile(self.start_date, self.end_date, self.measures)
     dragger = Dragger()
     energy_per_period = profile.get_consumption_per_period(tariff)
     for period_name, period_balance in balance.items():
         period_profile = energy_per_period[period_name]
         margin_bottom = period_balance - diff
         margin_top = period_balance + diff
         if not margin_bottom <= period_profile <= margin_top:
             profile.adjusted_periods.append(period_name)
             for idx, measure in enumerate(profile.measures):
                 dt = measure.date - timedelta(minutes=1)
                 period = tariff.get_period_by_date(dt).code
                 if period != period_name:
                     continue
                 values = measure._asdict()
                 values['valid'] = True
                 if not energy_per_period[period]:
                     values['measure'] = dragger.drag(measure.measure * 0)
                 else:
                     values['measure'] = dragger.drag(
                         measure.measure *
                         (balance[period] / energy_per_period[period]))
                 profile.measures[idx] = measure._replace(**values)
     return profile
Exemple #3
0
 def simple_dragger(measures):
     dragger = Dragger()
     for idx, measure in enumerate(measures):
         values = measure._asdict()
         consumption = dragger.drag(measure.measure)
         values['measure'] = consumption
         measures[idx] = measure._replace(**values)
     return measures
Exemple #4
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
Exemple #5
0
 def adjust(self, tariff, balance):
     # Adjust values
     if self.gaps:
         raise Exception('Is not possible to adjust a profile with gaps')
     profile = Profile(self.start_date, self.end_date, self.measures)
     dragger = Dragger()
     if profile.total_consumption != sum(balance.values()):
         energy_per_period = profile.get_consumption_per_period(tariff)
         for idx, measure in enumerate(profile.measures):
             period = tariff.get_period_by_date(measure.date).code
             values = measure._asdict()
             values['valid'] = True
             if not energy_per_period[period]:
                 values['measure'] = dragger.drag(measure.measure * 0)
             else:
                 values['measure'] = dragger.drag(measure.measure * (
                     balance[period] / energy_per_period[period]
                 ))
             profile.measures[idx] = measure._make(values.values())
     return profile
Exemple #6
0
 def profile(self, tariff, measures, drag_method='hour'):
     """
     :param tariff:
     :param measures:
     :param drag_method: 'hour' means drag is passed to the next hour
                         'period' means drag is passed to the next hour for
                         the same period
     :return:
     """
     # {'PX': [(date(XXXX-XX-XX), 100), (date(XXXX-XX-XX), 110)]}
     _measures = list(measures)
     measures = {}
     for m in sorted(_measures):
         measures.setdefault(m.period.code, [])
         measures[m.period.code].append(m)
     measures_intervals = EnergyMeasure.intervals(_measures)
     logger.debug('Profiling {0} intervals'.format(len(measures_intervals)))
     for idx, measure_date in enumerate(measures_intervals):
         if idx + 1 == len(measures_intervals):
             break
         start = measure_date
         if idx > 0:
             start += timedelta(days=1)
         end = measures_intervals[idx + 1]
         logger.debug('Getting coeffs from {0} to {1}'.format(
             start, end
         ))
         sum_cofs = self.coefficient.get_coefs_by_tariff(tariff, start, end)
         dragger = Dragger()
         for hour, cof in self.coefficient.get_range(start, end):
             period = tariff.get_period_by_date(hour)
             if drag_method == 'hour':
                 dp = 'hour'
             else:
                 dp = period.code
             d = hour.date()
             if hour.hour == 0:
                 d -= timedelta(days=1)
             # To take the first measure
             if d == start:
                 d += timedelta(days=1)
             fake_m = Measure(d, period, 0)
             pos = bisect.bisect_left(measures[period.code], fake_m)
             consumption = measures[period.code][pos].consumption
             logger.debug('Hour: {0} Period: {1} Consumption: {2}'.format(
                 hour, period.code, consumption
             ))
             cof = cof[tariff.cof]
             hour_c = ((consumption * cof) / sum_cofs[period.code])
             aprox = dragger.drag(hour_c, key=dp)
             yield (
                 hour,
                 {
                     'aprox': aprox,
                     'drag': dragger[dp],
                     'consumption': consumption,
                     'consumption_date': measures[period.code][pos].date,
                     'sum_cofs': sum_cofs[period.code],
                     'cof': cof,
                     'period': period.code
                 }
             )
Exemple #7
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
Exemple #8
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
Exemple #9
0
 def profile(self, tariff, measures, drag_method='hour'):
     """
     :param tariff:
     :param measures:
     :param drag_method: 'hour' means drag is passed to the next hour
                         'period' means drag is passed to the next hour for
                         the same period
     :return:
     """
     # {'PX': [(date(XXXX-XX-XX), 100), (date(XXXX-XX-XX), 110)]}
     _measures = list(measures)
     measures = {}
     for m in sorted(_measures):
         measures.setdefault(m.period.code, [])
         measures[m.period.code].append(m)
     measures_intervals = EnergyMeasure.intervals(_measures)
     # Detect single day profiling case
     if len(measures_intervals) == 1:
         measures_intervals.append(
             measures_intervals[-1]
         )  # duplicate measure date to do not skip loop below
     logger.debug('Profiling {0} intervals'.format(len(measures_intervals)))
     for idx, measure_date in enumerate(measures_intervals):
         if idx + 1 == len(measures_intervals):
             break
         start = measure_date
         if idx > 0:
             start += timedelta(days=1)
         end = measures_intervals[idx + 1]
         logger.debug('Getting coeffs from {0} to {1}'.format(start, end))
         sum_cofs = self.coefficient.get_coefs_by_tariff(tariff, start, end)
         dragger = Dragger()
         for hour, cof in self.coefficient.get_range(start, end):
             dt = hour - timedelta(minutes=1)
             period = tariff.get_period_by_date(dt)
             if drag_method == 'hour':
                 dp = 'hour'
             else:
                 dp = period.code
             d = hour.date()
             if hour.hour == 0:
                 d -= timedelta(days=1)
             # To take the first measure
             if d == start and len(
                     set(measures_intervals
                         )) != 1:  # if single day case, do not regress date
                 d += timedelta(days=1)
             fake_m = Measure(d, period, 0)
             pos = bisect.bisect_left(measures.get(period.code, []), fake_m)
             pcode = period.code
             if pcode not in measures or pos >= len(measures[period.code]):
                 consumption = 0
                 consumption_date = None
             else:
                 consumption = measures[period.code][pos].consumption
                 consumption_date = measures[period.code][pos].date
             logger.debug('Hour: {0} Period: {1} Consumption: {2}'.format(
                 hour, period.code, consumption))
             cof = cof[tariff.cof]
             hour_c = ((consumption * cof) / sum_cofs[period.code])
             aprox = dragger.drag(hour_c, key=dp)
             yield (hour, {
                 'aprox': aprox,
                 'drag': dragger[dp],
                 'consumption': consumption,
                 'consumption_date': consumption_date,
                 'sum_cofs': sum_cofs[period.code],
                 'cof': cof,
                 'period': period.code
             })