docs: def execute(self, time_interval):
          """
          Execute the factor over the given time interval. Note that this is normally done by the workflow,
          but can also be done on the factor directly
  
          :param time_interval: The time interval
          :return: self (for chaining)
          """
          logging.info('{} running from {} to {}'.format(
              self.tool.__class__.__name__, time_interval.start, time_interval.end))
  
          input_plate_values = self.input_plate.values if self.input_plate else [None]
          output_plate_values = self.sink.plate_values
          meta_data_ids = [p.meta_data_id for p in self.sink.plates]
  
          def belongs(plate_value):
              return all(ii in plate_value for ii in input_plate_value)
  
          def meta_data_matches(plate_value):
              return filter(lambda x: x[0] in meta_data_ids, plate_value)
  
          for input_plate_value in input_plate_values:
              if input_plate_value:
                  # Select only the valid output plate values based on the input plate value
                  # filtered = filter(belongs, output_plate_values)
                  filtered = filter(belongs, output_plate_values)
              else:
                  filtered = output_plate_values
  
              sinks = [self.sink.streams[s] for s in filtered]
  
              sub_plate_values_only = map(meta_data_matches, filtered)
  
              if not self.source:
                  source = None
              elif input_plate_value in self.source.streams:
                  source = self.source.streams[input_plate_value]
              else:
                  logging.warn("{} with value {} not valid for source {}".format(
                      self.input_plate, input_plate_value, self.source))
                  continue
  
              if self.input_plate:
                  if len(self.output_plates) == 1:
                      if self.output_plates[0].parent.plate_id != self.input_plate.plate_id:
                          raise IncompatiblePlatesError("Parent plate of output plate does not match input plate")
              else:
                  if len(self.output_plates) != 1:
                      raise ValueError("Should be a single output plate if there is no input plate")
  
              if len(self.output_plates) > 1:
                  raise NotImplementedError
  
              splitting_stream = self.get_splitting_stream(input_plate_value)
  
              self.tool.execute(
                  source=source,
                  sinks=sinks,
                  interval=time_interval,
                  splitting_stream=splitting_stream,
                  meta_data_id=self.output_plates[0].meta_data_id,
                  output_plate_values=sub_plate_values_only)
              self.update_computed_intervals(sinks, time_interval)
  
          return self