def compute(self,
                fractions_dict, concentration_dict,
                start_date, end_date):
        """Compute and return the concentration time series.

        Parameters:
        * fractions_list -- dict of fractions timeseries in [0.0, 1.0]
        * concentration_list -- dict of label keys with concentration values in [mg/l]

        Computation is based on constant concentration of the fractions
        """


        timeseries = SparseTimeseriesStub()
        for events in enumerate_dict_events(fractions_dict):
            date = events['date']
            del(events['date'])
            concentration = 0
            for key, value in events.items():
                if key in ['intakes', 'defined_input']:
                    for key_intake, value_intake in value.items():
                        if key_intake == 'intake_wl_control':
                            concentration += value_intake[1] * concentration_dict[key_intake]
                        else:
                            concentration += value_intake[1] * concentration_dict[key_intake.label.program_name]
                else:
                    concentration += value[1] * concentration_dict[key]

            timeseries.add_value(date, concentration)

        return timeseries
    def compute(self, start_date, end_date, level_control_timeseries, # pylint: disable=C0301, R0201
                measured_timeseries):
        """Compute and return the sluice error time series.

        The sluice error on a specific day is defined as the sum of the
        (calculated) level control intakes and pumps values minus the sum of the
        measured (non level control) intakes and pumps values.

        This function returns the sluice error time series as a
        SparseTimeseriesStub.

        Parameters:
          * level_control_timeseries *
            list of calculated time series of the level control intakes and pumps
          * measured_timeseries *
            list of measured time series of the (non level control) intakes and pumps
          * start_date *
            first date for which to compute the sluice error
          * end_date *
            date after the last date for which to compute the sluice error

        """
        sluice_error_timeseries = SparseTimeseriesStub()

        timeseries = level_control_timeseries + \
           [multiply_timeseries(ts, -1.0) for ts in measured_timeseries]
        for date, value in add_timeseries(*timeseries).events(): # pylint: disable=C0301, W0142
            if date < start_date:
                continue
            elif date < end_date:
                sluice_error_timeseries.add_value(date, value)
            else:
                break

        return sluice_error_timeseries
def transform_evaporation_timeseries_penman_to_makkink(evaporation_timeseries):
    """Return the adjusted evaporation timeserie.

    Parameters:
    * evaporation_timeseries -- timeserie with evaporation [mm/day]

    """
    result = SparseTimeseriesStub()
    month_factor = [0.400, 0.933, 1.267, 1.300, 1.300, 1.310, 1.267, 1.193, 1.170, 0.900, 0.700, 0.000]

    for evaporation_event in enumerate_events(evaporation_timeseries):
        month_number = evaporation_event[0][0].month
        factor = month_factor[month_number-1]
        result.add_value(evaporation_event[0][0], evaporation_event[0][1]*factor)

    return result
    def compute(self, open_water, buckets_summary, precipitation, evaporation, seepage, infiltration,
                minimum_level_timeseries, maximum_level_timeseries,
                intakes_timeseries, pumps_timeseries,
                max_intake = None, max_outtake = None):
        """Compute and return the pair of intake and pump time series.

        This function returns the pair of SparseTimeseriesStub(s) that consists of
        the intake time series and pump time series for the given open water.

        Parameters:
        * open_water -- OpenWater for which to compute the level control
        * buckets_summary -- BucketsSummary with the summed buckets outcome
        * precipitation,
        * evaporation,
        * seepage,
        * infiltration
        * intakes_timeseries -- dict of intake timeseries in [m3/day]
        * pumps_timeseries -- dict of pump timeseries in [m3/day]

        """
        storage = SparseTimeseriesStub()
        result = SparseTimeseriesStub()
        water_level_timeseries = SparseTimeseriesStub()
        pump_time_series = SparseTimeseriesStub()
        intake_time_series = SparseTimeseriesStub()
        total_incoming = SparseTimeseriesStub()
        total_outgoing = SparseTimeseriesStub()

        surface = 1.0 * open_water.surface
        water_level = open_water.init_water_level

        ts = {}
        ts['bucket_total_incoming'] = buckets_summary.total_incoming
        ts['bucket_total_outgoing'] = buckets_summary.total_outgoing
        ts['precipitation'] = precipitation
        ts['evaporation'] = evaporation
        ts['seepage'] = seepage
        ts['infiltration'] = infiltration
        ts['min_level'] = minimum_level_timeseries
        ts['max_level'] = maximum_level_timeseries

        ts['intakes'] = {}
        for intake, timeseries in intakes_timeseries.iteritems():
            if not intake.computed_level_control:
                ts['intakes'][intake] = timeseries

        ts['pumps'] = {}
        for pump, timeseries in pumps_timeseries.iteritems():
            if not pump.computed_level_control:
                ts['pumps'][pump] = timeseries

        for events in enumerate_dict_events(ts):
            date = events['date']
            if self.inside_range(date) < 0:
                continue
            elif self.inside_range(date) > 0:
                break

            if not events.has_key('intakes'):
                events['intakes'] = {}

            incoming_value = [ events['bucket_total_outgoing'][1],
                                  events['precipitation'][1],
                                  events['seepage'][1]] + \
                                  [event[1] for event in events['intakes'].values()]

            incoming_value = sum(incoming_value)

            if not events.has_key('pumps'):
                events['pumps'] = {}

            outgoing_value = [ events['bucket_total_incoming'][1],
                                  events['infiltration'][1],
                                  events['evaporation'][1]] + \
                                  [event[1] for event in events['pumps'].values()]

            outgoing_value = sum(outgoing_value)

            water_level += (incoming_value + outgoing_value) / surface

            level_control = self._compute_level_control(surface, water_level, events['min_level'][1], events['max_level'][1])

            if level_control < 0:
                if max_outtake is not None:
                    pump = max(level_control, -1*max_outtake)
                else:
                    pump = level_control
                intake = 0
            else:
                pump = 0
                if max_intake is not None:
                    intake = min(level_control, max_intake)
                else:
                    intake = level_control

            water_level += (pump + intake) / surface

            pump_time_series.add_value(date, pump)
            intake_time_series.add_value(date, intake)

            water_level_timeseries.add_value(date, water_level)

            storage_value = (water_level - open_water.bottom_height) * surface
            storage.add_value(date, storage_value)

            result.add_value(date, level_control)

            total_incoming.add_value(date, sum([incoming_value, intake]))
            total_outgoing.add_value(date, sum([outgoing_value, pump]))

            date += timedelta(1)

        return {'intake_wl_control':intake_time_series,
                'outtake_wl_control':pump_time_series,
                'storage':storage,
                'water_level':water_level_timeseries,
                'total_incoming':total_incoming,
                'total_outgoing':total_outgoing}
    def compute(self,
                inflow_dict, outflow_dict, storage, concentration_dict,
                start_date, end_date):
        """Compute and return the concentration time series.

        Parameters:
        * fractions_list -- dict of fractions timeseries in [0.0, 1.0]
        * concentration_list -- dict of label keys with concentration values in [mg/l]

        Computation is based on constant concentration of the fractions
        """

        total_outflow = SparseTimeseriesStub()
        for events in enumerate_dict_events(outflow_dict):
            date = events['date']
            del(events['evaporation'])
            del(events['date'])
            total= 0.0
            for key, event in events.items():
                if key in ['outtakes', 'defined_output']:
                    for key_outtake, event_outtake in event.items():
                        total += event_outtake[1]
                else:
                     total += event[1]
            total_outflow.add_value(date, total)


        start_storage = next(storage.events(start_date, end_date))[1]
        storage_chloride = start_storage * concentration_dict['initial']

        delta = SparseTimeseriesStub()

        timeseries = SparseTimeseriesStub()
        for events in enumerate_dict_events(dict(tuple(inflow_dict.items()) + (('total_outflow', total_outflow), ('storage', storage)))):
            date = events['date']
            if date < start_date:
                continue
            if date >= end_date:
                break

            total_outflow = -events['total_outflow'][1]
            storage = events['storage'][1]
            del(events['date'])
            del(events['total_outflow'])
            del(events['storage'])

            out = (storage_chloride/storage) * total_outflow

            plus = 0.0
            for key, value in events.items():
                if key in ['intakes', 'defined_input']:
                    for key_intake, value_intake in value.items():
                        if key_intake == 'intake_wl_control':
                            plus += value_intake[1] * concentration_dict[key_intake]
                        else:
                            plus += value_intake[1] * concentration_dict[key_intake.label.program_name]
                else:
                    plus += value[1] * concentration_dict[key]
            storage_chloride = storage_chloride + plus - out
            timeseries.add_value(date, storage_chloride/storage)
            delta.add_value(date, plus - out)

        return timeseries, delta
    def get_input_timeseries(self, start_date, end_date):
        """return (and collect) all input timeseries
        Args:
          *start_date*
            date of the first day for which to compute the time series
          *end_date*
            date of the day *after* the last day for which to compute the time
            series

        This method returns a tuple that contains
          1. a dictionary with all input timeseries.
            - precipitation
            - evaporation
            - seepage
            - open_water minimum_level/maximum_level
            - incoming_timeseries[intake]
        """
        if (self.input.has_key('timeseries') and
            self.input_info['timeseries']['start_date']==start_date and
            self.input_info['timeseries']['end_date']>=end_date):
            return self.input['timeseries']
        else:
            logger.debug("get input timeseries (%s - %s)..." % (
                    start_date.strftime('%Y-%m-%d'),
                    end_date.strftime('%Y-%m-%d')))

            input_ts = {}
            input_ts['precipitation'] = SparseTimeseriesStub()
            for event in self.configuration.retrieve_precipitation(start_date, end_date).events():
                input_ts['precipitation'].add_value(event[0], event[1])
            input_ts['evaporation'] = SparseTimeseriesStub()
            for event in self.configuration.retrieve_evaporation(start_date, end_date).events():
                input_ts['evaporation'].add_value(event[0], event[1])
            input_ts['seepage'] = SparseTimeseriesStub()
            for event in self.configuration.retrieve_seepage(start_date, end_date).events(): #for the time_being, officially part of each bucket + openwater
                input_ts['seepage'].add_value(event[0], event[1])

            input_ts['sewer'] = self.configuration.open_water.retrieve_sewer(start_date, end_date)

            input_ts['open_water'] = {}
            input_ts['open_water']['minimum_level'] = self.configuration.open_water.retrieve_minimum_level(start_date, end_date)
            input_ts['open_water']['maximum_level'] = self.configuration.open_water.retrieve_maximum_level(start_date, end_date)

            input_ts['open_water']['seepage'] = input_ts['seepage']

            for bucket in self.configuration.retrieve_buckets():
                input_ts[bucket] = {}
                input_ts[bucket]['seepage'] = bucket.retrieve_seepage(start_date, end_date)

            input_ts['incoming_timeseries'] = {}
            for intake, timeseries in self.configuration.open_water.retrieve_incoming_timeseries(only_input=False).iteritems():
                sparse_timeseries = SparseTimeseriesStub()
                for event in timeseries.events():
                    sparse_timeseries.add_value(event[0], event[1])
                input_ts['incoming_timeseries'][intake] = TimeseriesRestrictedStub(timeseries=sparse_timeseries,
                                                                start_date=start_date,
                                                                end_date=end_date)

            input_ts['outgoing_timeseries'] = {}
            for pump, timeseries in self.configuration.open_water.retrieve_outgoing_timeseries(only_input=False).iteritems():
                input_ts['outgoing_timeseries'][pump] = TimeseriesRestrictedStub(timeseries=timeseries,
                                                                start_date=start_date,
                                                                end_date=end_date)

            #store for later use (some kind of cache)
            self.input['timeseries'] = input_ts
            self.input_info['timeseries'] = {}
            self.input_info['timeseries']['start_date'] = start_date
            self.input_info['timeseries']['end_date'] = end_date

            self.updated = True

        return input_ts
    def compute(self, open_water, buckets_summary, precipitation_timeseries, seepage_timeseries,
                storage_timeseries, total_output_timeseries, intakes_timeseries, start_date, end_date):
        """Compute and return the fraction series.

        This function returns the pair of SparseTimeseriesStub(s) that consists of
        the intake time series and pump time series for the given open water.

        Parameters:
        * open_water -- OpenWater for which to compute the fractions
        * buckets_summary -- BucketsSummary with the summed buckets outcome
        * precipitation,
        * seepage,
        * storage_timeseries -- storage time series in [m3/day]
        * intakes_timeseries -- list of intake timeseries in [m3/day]

        """
        fractions_initial = SparseTimeseriesStub()
        fractions_precipitation = SparseTimeseriesStub()
        fractions_seepage = SparseTimeseriesStub()
        fractions_hardened = SparseTimeseriesStub()
        fractions_sewer = SparseTimeseriesStub()
        fractions_drained = SparseTimeseriesStub()
        fractions_undrained = SparseTimeseriesStub()
        fractions_flow_off = SparseTimeseriesStub()
        fractions_intakes = {}
        for key in intakes_timeseries.keys():
            fractions_intakes[key] = SparseTimeseriesStub()

        previous_initial = 100.0
        previous_precipitation = 0.0
        previous_seepage = 0.0
        previous_hardened = 0.0
        previous_sewer = 0.0
        previous_drained = 0.0
        previous_undrained = 0.0
        previous_flow_off = 0.0
        previous_intakes = {}
        for key in intakes_timeseries.keys():
            previous_intakes[key] = 0.0

        previous_storage = self.initial_storage(open_water)

        ts = {}
        ts['hardened'] = buckets_summary.hardened
        ts['drained'] = buckets_summary.drained
        ts['undrained'] = buckets_summary.undrained
        ts['flow_off'] = buckets_summary.flow_off
        ts['precipitation'] = precipitation_timeseries
        ts['seepage'] = seepage_timeseries
        ts['sewer'] = buckets_summary.sewer
        ts['storage'] = storage_timeseries
        ts['total_output'] = total_output_timeseries
        ts['intakes'] = intakes_timeseries

        first = True
        for events in enumerate_dict_events(ts):
            date = events['date']
            if date < start_date:
                continue
            if date >= end_date:
                break

            if first:
                first = False
                previous_storage = (open_water.init_water_level - open_water.bottom_height) * open_water.surface


            total_output = -1 * events['total_output'][1]
            current_storage = events['storage'][1]

            initial = self.compute_fraction(0,
                                            total_output,
                                            current_storage,
                                            previous_initial,
                                            previous_storage)

            precipitation = self.compute_fraction(events['precipitation'][1],
                                                  total_output,
                                                  current_storage,
                                                  previous_precipitation,
                                                  previous_storage)
            seepage = self.compute_fraction(events['seepage'][1],
                                                  total_output,
                                                  current_storage,
                                                  previous_seepage,
                                                  previous_storage)

            hardened = self.compute_fraction(events['hardened'][1],
                                                  total_output,
                                                  current_storage,
                                                  previous_hardened,
                                                  previous_storage)

            sewer = self.compute_fraction(events['sewer'][1],
                                                  total_output,
                                                  current_storage,
                                                  previous_sewer,
                                                  previous_storage)

            drained = self.compute_fraction(events['drained'][1],
                                                  total_output,
                                                  current_storage,
                                                  previous_drained,
                                                  previous_storage)

            undrained = self.compute_fraction(events['undrained'][1],
                                                  total_output,
                                                  current_storage,
                                                  previous_undrained,
                                                  previous_storage)

            flow_off = self.compute_fraction(events['flow_off'][1],
                                                  total_output,
                                                  current_storage,
                                                  previous_flow_off,
                                                  previous_storage)
            intakes = {}
            for key, intake_timeserie in events['intakes'].items():
                    intakes[key] = self.compute_fraction(intake_timeserie[1],
                                                           total_output,
                                                           current_storage,
                                                           previous_intakes[key],
                                                           previous_storage)

            # Due to rounding errors, the sum of the fractions is seldom equal
            # to 1.0. As the fraction of the next day depends on the fraction
            # of the previous day, this effect gets worse over time. To avoid
            # this effect, we divide each fraction by the sum of fractions.

            total_fractions = initial + precipitation + seepage + sewer + hardened + \
                              drained + undrained + flow_off + sum(intakes.values())

                #TO DO: dit is een correctie die niet mogelijk hoeft te zijn. graag een alert als dit niet klopt
                #initial /= total_fractions
                #precipitation /= total_fractions
                #seepage /= total_fractions
                #hardened /= total_fractions
                #drained /= total_fractions
                #undrained /= total_fractions
                #flow_off /= total_fractions
                #intakes = [intake / total_fractions for intake in intakes]

            fractions_initial.add_value(date, initial)
            previous_initial = initial
            fractions_precipitation.add_value(date, precipitation)
            previous_precipitation = precipitation
            fractions_seepage.add_value(date, seepage)
            previous_seepage = seepage
            fractions_hardened.add_value(date, hardened)
            previous_hardened = hardened
            fractions_sewer.add_value(date, sewer)
            previous_sewer = sewer
            fractions_drained.add_value(date, drained)
            previous_drained = drained
            fractions_undrained.add_value(date, undrained)
            previous_undrained = undrained
            fractions_flow_off.add_value(date, flow_off)
            previous_flow_off = flow_off

            previous_intakes = {}
            for key in intakes.keys():
                fractions_intakes[key].add_value(date, intakes[key])
                previous_intakes[key] = intakes[key]

            previous_storage = current_storage

        result = {'initial':fractions_initial,
                'precipitation':fractions_precipitation,
                'seepage':fractions_seepage,
                'hardened':fractions_hardened,
                'drained':fractions_drained,
                'sewer':fractions_sewer,
                'undrained':fractions_undrained,
                'flow_off':fractions_flow_off,
                'intakes': {} }

        for key in intakes_timeseries.keys():
            result['intakes'][key] = fractions_intakes[key]

        return result