Esempio n. 1
0
void FloodPlot::timeseriesData(TimeSeries tsData)
{
  if (tsData.values().empty()){
    return;
  }

  m_startDateTime = tsData.firstReportDateTime();
  m_endDateTime = tsData.firstReportDateTime() + Time(tsData.daysFromFirstReport(tsData.daysFromFirstReport().size()-1));
  m_duration = (m_endDateTime-m_startDateTime).totalDays();
  m_xAxisMin = 0.0;
  m_xAxisMax = m_duration;
  if (m_plot2DTimeAxis == NULL) 
  {
    m_plot2DTimeAxis = new Plot2DTimeAxis(m_startDateTime, m_duration);
    m_qwtPlot->setAxisTitle(QwtPlot::xBottom, " Simulation Time");
    m_qwtPlot->setAxisScale(QwtPlot::xBottom, 0, m_duration);
    m_qwtPlot->setAxisScaleDraw(QwtPlot::xBottom, m_plot2DTimeAxis);
    m_qwtPlot->setAxisLabelRotation(QwtPlot::xBottom, -90.0);
    m_qwtPlot->setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom);
  } 
  else 
  {
    m_plot2DTimeAxis->startDateTime(m_startDateTime);
    m_plot2DTimeAxis->duration(m_duration);
  }

  TimeSeriesFloodPlotData::Ptr data = TimeSeriesFloodPlotData::create(tsData);
  floodPlotData(data);
}
Esempio n. 2
0
TimeSeriesFloodPlotData::TimeSeriesFloodPlotData(TimeSeries timeSeries,  QwtDoubleInterval colorMapRange)
: m_timeSeries(timeSeries),
  m_minValue(minimum(timeSeries.values())),
  m_maxValue(maximum(timeSeries.values())),
  m_minX(timeSeries.firstReportDateTime().date().dayOfYear()),
  m_maxX(ceil(timeSeries.daysFromFirstReport()[timeSeries.daysFromFirstReport().size()-1]+timeSeries.firstReportDateTime().date().dayOfYear()+timeSeries.firstReportDateTime().time().totalDays())), // end day
  m_minY(0), // start hour
  m_maxY(24), // end hour
  m_startFractionalDay(timeSeries.firstReportDateTime().date().dayOfYear()+timeSeries.firstReportDateTime().time().totalDays()),
  m_colorMapRange(colorMapRange)
{
  // data range
  setBoundingRect(QwtDoubleRect(m_minX, m_minY, m_maxX-m_minX, m_maxY-m_minY));
}
Esempio n. 3
0
TimeSeriesLinePlotData::TimeSeriesLinePlotData(TimeSeries timeSeries, double fracDaysOffset)
: m_timeSeries(timeSeries),
  m_minX(timeSeries.firstReportDateTime().date().dayOfYear()+timeSeries.firstReportDateTime().time().totalDays()),
  m_maxX(timeSeries.daysFromFirstReport()[timeSeries.daysFromFirstReport().size()-1]+timeSeries.firstReportDateTime().date().dayOfYear()+timeSeries.firstReportDateTime().time().totalDays()), // end day
  m_minY(minimum(timeSeries.values())),
  m_maxY(maximum(timeSeries.values())),
  m_size(timeSeries.values().size())
{
  m_boundingRect = QwtDoubleRect(m_minX, m_minY, (m_maxX - m_minX), (m_maxY - m_minY));
  m_minValue = m_minY;
  m_maxValue = m_maxY;
  m_units = timeSeries.units();
  m_fracDaysOffset = fracDaysOffset; // note updating in xValue does not affect scaled axis
  m_x = m_timeSeries.daysFromFirstReport();
  m_y = m_timeSeries.values();
}
Esempio n. 4
0
void LinePlot::timeseriesData(TimeSeries tsData, const std::string& name, QColor color)
{
  if (tsData.values().empty()){
    return;
  }

  double offset=0.0;
  if (m_plot2DTimeAxis == NULL) 
  {
    m_startDateTime = tsData.firstReportDateTime();
    m_endDateTime = tsData.firstReportDateTime() + Time(tsData.daysFromFirstReport(tsData.daysFromFirstReport().size()-1));
    m_duration = (m_endDateTime-m_startDateTime).totalDays();
    m_plot2DTimeAxis = new Plot2DTimeAxis(m_startDateTime, m_duration);
    m_qwtPlot->setAxisTitle(QwtPlot::xBottom, " Simulation Time");
    m_qwtPlot->setAxisScaleDraw(QwtPlot::xBottom, m_plot2DTimeAxis);
    m_xAxisMin = 0.0;
    m_xAxisMax = m_duration;
    m_qwtPlot->setAxisScale(QwtPlot::xBottom, 0, m_duration);
    m_qwtPlot->setAxisLabelRotation(QwtPlot::xBottom, -90.0);
    m_qwtPlot->setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom);
  } 
  else 
  {
    if (tsData.firstReportDateTime() < m_startDateTime) {
      m_xAxisMin = (tsData.firstReportDateTime() - m_startDateTime).totalDays();
      offset = m_xAxisMin;
    } else {
      offset = (tsData.firstReportDateTime() - m_startDateTime).totalDays();
    }

    if ((tsData.firstReportDateTime() + Time(tsData.daysFromFirstReport(tsData.daysFromFirstReport().size()-1))) > m_endDateTime) {
      m_xAxisMax += ((tsData.firstReportDateTime() + Time(tsData.daysFromFirstReport(tsData.daysFromFirstReport().size()-1))) - m_endDateTime).totalDays();
    }
  }

  TimeSeriesLinePlotData::Ptr data = TimeSeriesLinePlotData::create(tsData, offset);
  linePlotData(data, name, color, offset);
}
Esempio n. 5
0
TEST_F(DataFixture,TimeSeries_AddSubtractSameTimePeriod)
{
  std::string units = "W";

  Date startDate(Date(MonthOfYear(MonthOfYear::Feb),21));
  DateTime startDateTime(startDate, Time(0,1,0,0));

  // interval
  Time interval = Time(0,1,0,0);
  Vector intervalValues(3);
  intervalValues(0) = 0;
  intervalValues(1) = 1;
  intervalValues(2) = 2;

  TimeSeries intervalTimeSeries(startDateTime, interval, intervalValues, units);
  ASSERT_TRUE(!intervalTimeSeries.values().empty());

  // detailed
  DateTimeVector dateTimes;
  dateTimes.push_back(startDateTime + Time(0,0,0,0));
  dateTimes.push_back(startDateTime + Time(0,0,30,0));
  dateTimes.push_back(startDateTime + Time(0,1,0,0));
  dateTimes.push_back(startDateTime + Time(0,1,30,0));
  dateTimes.push_back(startDateTime + Time(0,2,0,0));
  Vector detailedValues(5);
  detailedValues(0) = 0.0; // 1:00
  detailedValues(1) = 0.5; // 1:30
  detailedValues(2) = 1.0; // 2:00
  detailedValues(3) = 1.5; // 2:30
  detailedValues(4) = 2.0; // 3:00

  TimeSeries detailedTimeSeries(dateTimes, detailedValues, units);
  ASSERT_TRUE(!detailedTimeSeries.values().empty());

  // sum and difference
  TimeSeries sum = intervalTimeSeries + detailedTimeSeries;
  TimeSeries diff1 = intervalTimeSeries - detailedTimeSeries;
  TimeSeries diff2 = detailedTimeSeries - intervalTimeSeries;
  ASSERT_TRUE(!sum.values().empty());
  ASSERT_TRUE(!diff1.values().empty());
  ASSERT_TRUE(!diff2.values().empty());

//  EXPECT_EQ((unsigned)5, sum.dateTimes().size());
//  EXPECT_EQ((unsigned)5, diff1.dateTimes().size());
//  EXPECT_EQ((unsigned)5, diff2.dateTimes().size());
  EXPECT_EQ((unsigned)5, sum.daysFromFirstReport().size());
  EXPECT_EQ((unsigned)5, diff1.daysFromFirstReport().size());
  EXPECT_EQ((unsigned)5, diff2.daysFromFirstReport().size());

//  EXPECT_EQ(startDateTime, sum.dateTimes().front());
//  EXPECT_EQ(startDateTime, diff1.dateTimes().front());
//  EXPECT_EQ(startDateTime, diff2.dateTimes().front());
  EXPECT_EQ(startDateTime, sum.firstReportDateTime());
  EXPECT_EQ(startDateTime, diff1.firstReportDateTime());
  EXPECT_EQ(startDateTime, diff2.firstReportDateTime());

  DateTime endDateTime = startDateTime + Time(0,2,0,0);
//  EXPECT_EQ(endDateTime, sum.dateTimes().back());
//  EXPECT_EQ(endDateTime, diff1.dateTimes().back());
//  EXPECT_EQ(endDateTime, diff2.dateTimes().back());
  EXPECT_EQ(endDateTime, sum.firstReportDateTime() + Time(sum.daysFromFirstReport(sum.daysFromFirstReport().size()-1)));
  EXPECT_EQ(endDateTime, diff1.firstReportDateTime() +  Time(diff1.daysFromFirstReport(diff1.daysFromFirstReport().size()-1)));
  EXPECT_EQ(endDateTime, diff2.firstReportDateTime() +  Time(diff2.daysFromFirstReport(diff2.daysFromFirstReport().size()-1)));

  // 1:00
  EXPECT_EQ(0, sum.value(Time(0,0,0,0)));
  EXPECT_EQ(0, diff1.value(Time(0,0,0,0)));
  EXPECT_EQ(0, diff2.value(Time(0,0,0,0)));

  // 1:30
  EXPECT_EQ(1.5, sum.value(Time(0,0,30,0)));
  EXPECT_EQ(0.5, diff1.value(Time(0,0,30,0)));
  EXPECT_EQ(-0.5, diff2.value(Time(0,0,30,0)));

  // 2:00
  EXPECT_EQ(2, sum.value(Time(0,1,0,0)));
  EXPECT_EQ(0.0, diff1.value(Time(0,1,0,0)));
  EXPECT_EQ(0.0, diff2.value(Time(0,1,0,0)));

  // 2:30
  EXPECT_EQ(3.5, sum.value(Time(0,1,30,0)));
  EXPECT_EQ(0.5, diff1.value(Time(0,1,30,0)));
  EXPECT_EQ(-0.5, diff2.value(Time(0,1,30,0)));

  // Test helper function for summing a vector.
  TimeSeriesVector sumAndDiffs;
  sumAndDiffs.push_back(sum);
  sumAndDiffs.push_back(diff1);
  sumAndDiffs.push_back(diff2);

  TimeSeries ans = openstudio::sum(sumAndDiffs);
  EXPECT_FALSE(ans.values().empty());
  // 1:00
  EXPECT_DOUBLE_EQ(0, ans.value(Time(0,0,0,0)));
  // 1:30
  EXPECT_DOUBLE_EQ(1.5, ans.value(Time(0,0,30,0)));
  // 2:00
  EXPECT_DOUBLE_EQ(2.0, ans.value(Time(0,1,0,0)));
  // 2:30
  EXPECT_DOUBLE_EQ(3.5, ans.value(Time(0,1,30,0)));

  // Test multiplication and division with a scalar
  sumAndDiffs.push_back(sum/2.0);
  sumAndDiffs.push_back(3.0*diff1);
  ans = openstudio::sum(sumAndDiffs);
  EXPECT_FALSE(ans.values().empty());
  // 1:00
  EXPECT_DOUBLE_EQ(0, ans.value(Time(0,0,0,0)));
  // 1:30
  EXPECT_DOUBLE_EQ(3.75, ans.value(Time(0,0,30,0)));
  // 2:00
  EXPECT_DOUBLE_EQ(3.0, ans.value(Time(0,1,0,0)));
  // 2:30
  EXPECT_DOUBLE_EQ(6.75, ans.value(Time(0,1,30,0)));
}
boost::optional<IdfObject> ForwardTranslator::translateScheduleVariableInterval( ScheduleVariableInterval & modelObject )
{
  IdfObject idfObject( openstudio::IddObjectType::Schedule_Compact );

  m_idfObjects.push_back(idfObject);

  idfObject.setName(modelObject.name().get());

  boost::optional<ScheduleTypeLimits> scheduleTypeLimits = modelObject.scheduleTypeLimits();
  if (scheduleTypeLimits){
    boost::optional<IdfObject> idfScheduleTypeLimits = translateAndMapModelObject(*scheduleTypeLimits);
    if (idfScheduleTypeLimits){
      idfObject.setString(Schedule_CompactFields::ScheduleTypeLimitsName, idfScheduleTypeLimits->name().get());
    }
  }

  TimeSeries timeseries = modelObject.timeSeries();
  // Check that the time series has at least one point
  if(timeseries.values().size() == 0)
  {
    LOG(Error,"Time series in schedule '" << modelObject.name().get() << "' has no values, schedule will not be translated");
    return boost::optional<IdfObject>();
  }
  DateTime firstReportDateTime = timeseries.firstReportDateTime();
  Vector daysFromFirst = timeseries.daysFromFirstReport();
  std::vector<long> secondsFromFirst = timeseries.secondsFromFirstReport();
  Vector values = timeseries.values();

  // We aren't using this - should we?
  std::string interpolateField = "Interpolate:No";
  if (modelObject.interpolatetoTimestep()){
    interpolateField = "Interpolate:Yes";
  }

  // New version assumes that the interval is less than one day.
  // The original version did not, so it was a bit more complicated.
  // The last date data was written
  Date lastDate = firstReportDateTime.date();
  Time dayDelta = Time(1.0);
  // The day number of the date that data was last written relative to the first date
  //double lastDay = 0.0;
  int lastDay = 0;
  // Adjust the floating point day delta to be relative to the beginning of the first day and
  // shift the start of the loop if needed
  int secondShift = firstReportDateTime.time().totalSeconds();
  unsigned int start = 0;
  if(secondShift == 0) {
    start = 1;
  } else {
    for(unsigned int i=0;i<secondsFromFirst.size();i++) {
      secondsFromFirst[i] += secondShift;
    }
  }

  // Start the input into the schedule object
  unsigned fieldIndex = Schedule_CompactFields::ScheduleTypeLimitsName + 1;
  //idfObject.setString(fieldIndex, interpolateField);
  //++fieldIndex;
  fieldIndex = startNewDay(idfObject,fieldIndex,lastDate);

  for(unsigned int i=start; i < values.size()-1; i++){
    // Loop over the time series values and write out values to the
    // schedule. This version is based on the seconds from the start
    // of the time series, so should not be vulnerable to round-off.
    // It was translated from the day version, so there could be
    // issues associated with that.
    //
    // We still have a potential aliasing problem unless the API has
    // enforced that the times in the time series are all distinct when
    // rounded to the minute. Is that happening?
    int secondsFromStartOfDay = secondsFromFirst[i] % 86400;
    int today = (secondsFromFirst[i]-secondsFromStartOfDay)/86400;
    // Check to see if we are at the end of a day.
    if(secondsFromStartOfDay==0 || secondsFromStartOfDay==86400) {
      // This value is an end of day value, so end the day and set up the next
      // Note that 00:00:00 counts as the end of the previous day - we only write
      // out the 24:00:00 value and not both.
      fieldIndex = addUntil(idfObject,fieldIndex,24,0,values[i]);
      lastDate += dayDelta;
      fieldIndex = startNewDay(idfObject,fieldIndex,lastDate);
    } else {
      // This still could be on a different day
      if(today != lastDay) {
        // We're on a new day, need a 24:00:00 value and set up the next day
        fieldIndex = addUntil(idfObject,fieldIndex,24,0,values[i]);
        lastDate += dayDelta;
        fieldIndex = startNewDay(idfObject,fieldIndex,lastDate);
      }
      if(values[i] == values[i+1]){
        // Bail on values that match the next value
        continue;
      }
      // Write out the current entry
      Time time(0,0,0,secondsFromStartOfDay);
      int hours = time.hours();
      int minutes = time.minutes() + floor((time.seconds()/60.0) + 0.5);
      // This is a little dangerous, but all of the problematic 24:00
      // times that might need to cause a day++ should be caught above.
      if(minutes==60){
        hours += 1;
        minutes = 0;
      }
      fieldIndex = addUntil(idfObject,fieldIndex,hours,minutes,values[i]);
    }
    lastDay = today;
  }
  // Handle the last point a little differently to make sure that the schedule ends exactly on the end of a day
  unsigned int i = values.size()-1;
  // We'll skip a sanity check here, but it might be a good idea to add one at some point
  fieldIndex = addUntil(idfObject,fieldIndex,24,0,values[i]);

  return idfObject;
}
boost::optional<IdfObject> ForwardTranslator::translateScheduleFixedInterval( ScheduleFixedInterval & modelObject )
{
  IdfObject idfObject( openstudio::IddObjectType::Schedule_Compact );

  m_idfObjects.push_back(idfObject);

  idfObject.setName(modelObject.name().get());
  
  boost::optional<ScheduleTypeLimits> scheduleTypeLimits = modelObject.scheduleTypeLimits();
  if (scheduleTypeLimits){
    boost::optional<IdfObject> idfScheduleTypeLimits = translateAndMapModelObject(*scheduleTypeLimits);
    if (idfScheduleTypeLimits){
      idfObject.setString(Schedule_CompactFields::ScheduleTypeLimitsName, idfScheduleTypeLimits->name().get());
    }
  }

  TimeSeries timeseries = modelObject.timeSeries();
  // Check that the time series has at least one point
  if(timeseries.values().size() == 0)
  {
    LOG(Error,"Time series in schedule '" << modelObject.name().get() << "' has no values, schedule will not be translated");
    return boost::optional<IdfObject>();
  }
  DateTime firstReportDateTime = timeseries.firstReportDateTime();
  Vector daysFromFirst = timeseries.daysFromFirstReport();
  Vector values = timeseries.values();

  // We aren't using this - should we?
  std::string interpolateField;
  if (modelObject.interpolatetoTimestep()){
    interpolateField = "Interpolate:Yes";
  }else{
    interpolateField = "Interpolate:No";
  }

  // New version assumes that the interval is less than one day.
  // The original version did not, so it was a bit more complicated.
  // 5.787x10^-6 days is a little less than half a second
  double eps = 5.787e-6;
  double intervalDays = modelObject.intervalLength();
  // The last date data was written
  Date lastDate = firstReportDateTime.date();
  Time dayDelta = Time(1.0);
  // The day number of the date that data was last written relative to the first date
  double lastDay = 0.0; 
  // Adjust the floating point day delta to be relative to the beginning of the first day and
  // shift the start of the loop if needed
  double timeShift = firstReportDateTime.time().totalDays();
  unsigned int start = 0;
  if(timeShift == 0.0)
  {
    start = 1;
  }
  else
  {
    for(unsigned int i=0;i<daysFromFirst.size();i++)
    {
      daysFromFirst[i] += timeShift;
    }
  }

  // Start the input into the schedule object
  unsigned fieldIndex = Schedule_CompactFields::ScheduleTypeLimitsName + 1;
  fieldIndex = startNewDay(idfObject,fieldIndex,lastDate);

  for(unsigned int i=start; i < values.size()-1; i++)
  {
    // We could loop over the entire array and use the fact that the
    // last entry in the daysFromFirstReport vector should be a round
    // number to avoid logic. However, this whole thing is very, very
    // sensitive to round off issues. We still have a HUGE aliasing
    // problem unless the API has enforced that the times in the 
    // time series are all distinct when rounded to the minute. Is that
    // happening?
    double today = floor(daysFromFirst[i]);
    double hms = daysFromFirst[i]-today;
    // Here, we need to make sure that we aren't nearly the end of a day
    if(fabs(1.0-hms) < eps)
    {
      today += 1;
      hms = 0.0;
    }
    if(hms < eps)
    {
      // This value is an end of day value, so end the day and set up the next
      fieldIndex = addUntil(idfObject,fieldIndex,24,0,values[i]);
      lastDate += dayDelta;
      fieldIndex = startNewDay(idfObject,fieldIndex,lastDate);
    }
    else
    {
      if(today != lastDay)
      {
        // We're on a new day, need a 24:00:00 value and set up the next day
        fieldIndex = addUntil(idfObject,fieldIndex,24,0,values[i]);
        lastDate += dayDelta;
        fieldIndex = startNewDay(idfObject,fieldIndex,lastDate);
      }
      if(values[i] == values[i+1])
      {
        // Bail on values that match the next value
        continue;
      }
      // Write out the current entry
      Time time(hms);
      int hours = time.hours();
      int minutes = time.minutes() + floor((time.seconds()/60.0) + 0.5);
      // This is a little dangerous, but all of the problematic 24:00 
      // times that might need to cause a day++ should be caught above.
      if(minutes==60)
      {
        hours += 1;
        minutes = 0;
      }
      fieldIndex = addUntil(idfObject,fieldIndex,hours,minutes,values[i]);
    }
    lastDay = today;
  }
  // Handle the last point a little differently to make sure that the schedule ends exactly on the end of a day
  unsigned int i = values.size()-1;
  // We'll skip a sanity check here, but it might be a good idea to add one at some point
  fieldIndex = addUntil(idfObject,fieldIndex,24,0,values[i]);
  
  return idfObject;
}