package org.djutils.stats.summarizers.event; import java.io.Serializable; import java.util.Calendar; import org.djutils.event.Event; import org.djutils.event.EventInterface; import org.djutils.event.EventListenerInterface; import org.djutils.event.EventProducer; import org.djutils.event.TimedEvent; import org.djutils.stats.summarizers.TimestampTallyInterface; import org.djutils.stats.summarizers.TimestampWeightedTally; /** * The TimestampWeightedTally class defines a time-weighted tally based on timestamped data. The difference with a normal * time-weighed tally is that the weight of a value is only known at the occurrence of the next timestamp. Furthermore, a last * timestamp needs to be specified to determine the weight of the last value. This EventBased version of the tally can be * notified with timestamps and values using the EventListenerInterface. It also produces events when values are tallied and * when the tally is initialized. Timestamps can be Number based or Calendar based. *

* Copyright (c) 2020-2021 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See * for project information https://simulation.tudelft.nl. The DSOL * project is distributed under a three-clause BSD-style license, which can be found at * * https://simulation.tudelft.nl/dsol/3.0/license.html.
* @author Alexander Verbraeck */ public class EventBasedTimestampWeightedTally extends EventProducer implements EventListenerInterface, TimestampTallyInterface { /** */ private static final long serialVersionUID = 20200228L; /** the wrapped timestamp weighted tally. */ private TimestampWeightedTally wrappedTimestampWeightedTally; /** * constructs a new EventBasefdTimestampWeightedTally with a description. * @param description String; the description of this EventBasedTimestampWeightedTally */ public EventBasedTimestampWeightedTally(final String description) { this.wrappedTimestampWeightedTally = new TimestampWeightedTally(description); initialize(); } /** {@inheritDoc} */ @Override public Serializable getSourceId() { return this; } /** {@inheritDoc} */ @Override public void initialize() { this.wrappedTimestampWeightedTally.initialize(); fireEvent(new Event(StatisticsEvents.INITIALIZED_EVENT, this, null)); } /** {@inheritDoc} */ @Override public final boolean isActive() { return this.wrappedTimestampWeightedTally.isActive(); } /** {@inheritDoc} */ @Override public void endObservations(final Number timestamp) { this.wrappedTimestampWeightedTally.endObservations(timestamp); fireEvents(timestamp.doubleValue(), this.wrappedTimestampWeightedTally.getLastValue()); } /** {@inheritDoc} */ @Override public void endObservations(final Calendar timestamp) { this.wrappedTimestampWeightedTally.endObservations(timestamp); fireEvents(timestamp.getTimeInMillis(), this.wrappedTimestampWeightedTally.getLastValue()); } /** {@inheritDoc} */ @Override public void notify(final EventInterface event) { if (event instanceof TimedEvent) { TimedEvent timedEvent = (TimedEvent) event; double value = 0.0; if (event.getContent() instanceof Number) { value = ((Number) event.getContent()).doubleValue(); } else { throw new IllegalArgumentException( "EventBasedTimestampWeightedTally.notify: Content " + event.getContent() + " should be a Number"); } Object timestamp = timedEvent.getTimeStamp(); if (timestamp instanceof Number) { ingest(((Number) timestamp).doubleValue(), value); } else if (timestamp instanceof Calendar) { ingest(((Calendar) timestamp).getTimeInMillis(), value); } else { throw new IllegalArgumentException( "EventBasedTimestampWeightedTally.notify: timestamp should be a Number or Calendar"); } } else { throw new IllegalArgumentException("EventBasedTimestampWeightedTally.notify: Event should be a TimedEvent"); } } /** * Process one observed value. * @param timestamp Calendar; the Calendar object representing the timestamp * @param value double; the value to process * @return double; the value */ public double ingest(final Calendar timestamp, final double value) { this.wrappedTimestampWeightedTally.ingest(timestamp, value); fireEvents(timestamp, value); return value; } /** * Process one observed value. * @param a type for the timestamp that extends Number and is Comparable, e.g., a Double, a Long, or a djunits Time * @param timestamp T; the object representing the timestamp * @param value double; the value to process * @return double; the value */ public > double ingest(final T timestamp, final double value) { this.wrappedTimestampWeightedTally.ingest(timestamp, value); fireEvents(timestamp, value); return value; } /** * Fire the events to potential listeners with the timestamp and value. * @param a type for the timestamp that is Serializable and Comparable * @param timestamp T; Number or Calendar timestamp * @param value double; observation value */ private > void fireEvents(final T timestamp, final double value) { if (hasListeners()) { this.fireEvent( new Event(StatisticsEvents.TIMESTAMPED_OBSERVATION_ADDED_EVENT, this, new Object[] {timestamp, value})); fireEvents(timestamp); } } /** * Method that can be overridden to fire own events or additional events when ingesting an observation. * @param a type for the timestamp that is Serializable and Comparable * @param timestamp T; the timestamp to use in the TimedEvents */ protected > void fireEvents(final T timestamp) { fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_N_EVENT, this, getN(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_MIN_EVENT, this, getMin(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_MAX_EVENT, this, getMax(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_WEIGHTED_POPULATION_MEAN_EVENT, this, getWeightedPopulationMean(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_WEIGHTED_POPULATION_VARIANCE_EVENT, this, getWeightedPopulationVariance(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_WEIGHTED_POPULATION_STDEV_EVENT, this, getWeightedPopulationStDev(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_WEIGHTED_SUM_EVENT, this, getWeightedSum(), timestamp)); fireTimedEvent( new TimedEvent(StatisticsEvents.TIMED_WEIGHTED_SAMPLE_MEAN_EVENT, this, getWeightedSampleMean(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_WEIGHTED_SAMPLE_VARIANCE_EVENT, this, getWeightedSampleVariance(), timestamp)); fireTimedEvent(new TimedEvent(StatisticsEvents.TIMED_WEIGHTED_SAMPLE_STDEV_EVENT, this, getWeightedSampleStDev(), timestamp)); } /** {@inheritDoc} */ @Override public final String getDescription() { return this.wrappedTimestampWeightedTally.getDescription(); } /** {@inheritDoc} */ @Override public final long getN() { return this.wrappedTimestampWeightedTally.getN(); } /** {@inheritDoc} */ @Override public final double getMax() { return this.wrappedTimestampWeightedTally.getMax(); } /** {@inheritDoc} */ @Override public final double getMin() { return this.wrappedTimestampWeightedTally.getMin(); } /** {@inheritDoc} */ @Override public final double getWeightedSampleMean() { return this.wrappedTimestampWeightedTally.getWeightedSampleMean(); } /** {@inheritDoc} */ @Override public final double getWeightedSampleStDev() { return this.wrappedTimestampWeightedTally.getWeightedSampleStDev(); } /** {@inheritDoc} */ @Override public final double getWeightedPopulationStDev() { return this.wrappedTimestampWeightedTally.getWeightedPopulationStDev(); } /** {@inheritDoc} */ @Override public final double getWeightedSampleVariance() { return this.wrappedTimestampWeightedTally.getWeightedSampleVariance(); } /** {@inheritDoc} */ @Override public final double getWeightedPopulationVariance() { return this.wrappedTimestampWeightedTally.getWeightedPopulationVariance(); } /** {@inheritDoc} */ @Override public final double getWeightedSum() { return this.wrappedTimestampWeightedTally.getWeightedSum(); } /** {@inheritDoc} */ @Override @SuppressWarnings("checkstyle:designforextension") public String toString() { return this.wrappedTimestampWeightedTally.toString(); } }