Skip to content
Draft
162 changes: 159 additions & 3 deletions src/epmodel/ScheduleInterval/ScheduleFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,44 @@
#include <utilities/idd/IddFactory.hxx>
#include <utilities/idd/IddObject.hpp>
#include <utilities/idd/Schedule_File_FieldEnums.hxx>
#include <utilities/core/DeprecatedHelpers.hpp>
#include <utilities/core/Logger.hpp>

#include "../utilities/data/TimeSeries.hpp"

namespace openstudio {
namespace epmodel {

ScheduleFile::ScheduleFile(const Model& model) : Schedule(ScheduleFile::iddObjectType(), model) {
// ScheduleFile(const ExternalFile& externalfile, int column = 1, int rowsToSkip = 0) : Schedule(ScheduleFile::iddObjectType(), model) {}

ScheduleFile::ScheduleFile(const Model& model, int column, int rowsToSkip) : Schedule(ScheduleFile::iddObjectType(), model) {
// Mirror preserved counterpart constructor behavior for required scalar fields.
bool ok = true;
ok &= setColumnNumber(1);
ok &= setRowstoSkipatTop(0);
ok &= setColumnNumber(column);
ok &= setRowstoSkipatTop(rowsToSkip);
OS_ASSERT(ok);
}

ScheduleFile::ScheduleFile(const Model& model, const openstudio::path& filePath, int column, int rowsToSkip, bool translateFileWithRelativePath)
: Schedule(ScheduleFile::iddObjectType(), model) {

openstudio::path p;
if (!exists(filePath)) {
this->remove();
LOG_FREE_AND_THROW("openstudio.epmodel.ScheduleFile", "Cannot find file \"" << toString(filePath) << "\" for " << briefDescription());
} else {
if (translateFileWithRelativePath) {
p = filePath;
} else {
// make the path correct for this system
p = system_complete(filePath);
}
}

bool ok = true;
ok &= getImpl<detail::ScheduleFile_Impl>()->setFileName(toString(p));
ok &= setColumnNumber(column);
ok &= setRowstoSkipatTop(rowsToSkip);
OS_ASSERT(ok);
}

Expand All @@ -39,6 +68,14 @@ namespace epmodel {
return getIddKeyNames(IddFactory::instance().getObject(iddObjectType()).get(), openstudio::Schedule_FileFields::MinutesperItem);
}

// std::string ScheduleFile::fileName() const {
// return getImpl<detail::ScheduleFile_Impl>()->fileName();
// }

// bool ScheduleFile::setFileName(std::string fileName) {
// return getImpl<detail::ScheduleFile_Impl>()->setFileName(fileName);
// }

int ScheduleFile::columnNumber() const {
return getImpl<detail::ScheduleFile_Impl>()->columnNumber();
}
Expand Down Expand Up @@ -139,13 +176,118 @@ namespace epmodel {
getImpl<detail::ScheduleFile_Impl>()->resetAdjustScheduleforDaylightSavings();
}

boost::optional<CSVFile> ScheduleFile::csvFile() const {
return getImpl<detail::ScheduleFile_Impl>()->csvFile();
}

bool ScheduleFile::translateFileWithRelativePath() const {
DEPRECATED_AT_MSG(4, 0, 0, "Schedule:File is no longer 'translated'.");
return false;
}

bool ScheduleFile::isTranslateFileWithRelativePathDefaulted() const {
DEPRECATED_AT_MSG(4, 0, 0, "Schedule:File is no longer 'translated'.");
return false;
}

bool ScheduleFile::setTranslateFileWithRelativePath(bool translateFileWithRelativePath) {
DEPRECATED_AT_MSG(4, 0, 0, "Schedule:File is no longer 'translated'.");
return false;
}

void ScheduleFile::resetTranslateFileWithRelativePath() {
DEPRECATED_AT_MSG(4, 0, 0, "Schedule:File is no longer 'translated'.");
}

openstudio::path ScheduleFile::translatedFilePath() const {
return getImpl<epmodel::detail::ScheduleFile_Impl>()->translatedFilePath();
}

boost::optional<ScheduleFile> ScheduleFile::fromTimeSeries(const openstudio::TimeSeries& timeSeries, Model& model) {
boost::optional<ScheduleFile> result;

boost::optional<openstudio::Time> intervalTime = timeSeries.intervalLength();
if (intervalTime) {
result = ScheduleFile(model, 2); // FT ScheduleFixedInterval wrote the dateTimes to file
const std::string name = result->nameString();
openstudio::path filePath = toPath(name + ".csv");

CSVFile csvFile;
csvFile.addColumn(timeSeries.dateTimes());
csvFile.addColumn(timeSeries.values());
csvFile.saveAs(filePath);

openstudio::path p;
if (!exists(filePath)) {
result->remove();
// LOG_AND_THROW("Cannot find file \"" << toString(filePath) << "\" for " << briefDescription());
} else {
// make the path correct for this system
p = system_complete(filePath);
}

bool ok = true;
ok &= result->getImpl<detail::ScheduleFile_Impl>()->setFileName(toString(p));
ok &= result->getImpl<detail::ScheduleFile_Impl>()->setTimeSeries(timeSeries);
OS_ASSERT(ok);
} else {
LOG_FREE(Warn, "openstudio.epmodel.ScheduleFile", "Timeseries does not have an interval length defined, but ScheduleVariableInterval is deprecated");
}

return result;
}

} // namespace epmodel
} // namespace openstudio

namespace openstudio {
namespace epmodel {
namespace detail {

bool ScheduleFile_Impl::setTimeSeries(const openstudio::TimeSeries& timeSeries) {
boost::optional<openstudio::Time> intervalTime = timeSeries.intervalLength();
if (!intervalTime) {
return false;
}

auto intervalLengthAsInteger = [](const double value) -> int {
double integralPart = 0.0;
if (std::modf(value, &integralPart) == 0.0) {
// The intervalLength is actually an int, not a double
return static_cast<int>(integralPart);
}
return -1;
};

// check the interval
const double intervalLengthDouble = intervalTime->totalMinutes();
const int intervalLength = intervalLengthAsInteger(intervalLengthDouble);
if (intervalLength < 0) {
return false;
}

bool ok = true;
ok &= this->setMinutesperItem(intervalLength);
// Do we actually need the following? They aren't required in the IDD.
//ok &= this->setNumberofHoursofData(8760);
//ok &= this->setColumnSeparator("Comma");
//ok &= this->setInterpolatetoTimestep(true);
//ok &= this->setAdjustScheduleforDaylightSavings(true);
return true;
}

std::string ScheduleFile_Impl::fileName() const {
const auto value = getString(openstudio::Schedule_FileFields::FileName, true);
OS_ASSERT(value);
return *value;
}

bool ScheduleFile_Impl::setFileName(std::string fileName) {
const bool result = setString(openstudio::Schedule_FileFields::FileName, fileName);
OS_ASSERT(result);
return result;
}

int ScheduleFile_Impl::columnNumber() const {
const auto value = getInt(openstudio::Schedule_FileFields::ColumnNumber, true);
OS_ASSERT(value);
Expand Down Expand Up @@ -255,6 +397,20 @@ namespace epmodel {
OS_ASSERT(setString(openstudio::Schedule_FileFields::AdjustScheduleforDaylightSavings, ""));
}

boost::optional<CSVFile> ScheduleFile_Impl::csvFile() const {
boost::optional<CSVFile> csvFile;
csvFile = CSVFile::load(this->fileName());
return csvFile;
}

openstudio::path ScheduleFile_Impl::translatedFilePath() const {
openstudio::path filePath = this->fileName();
if (!exists(filePath)) {
LOG_FREE(Warn, "openstudio.epmodel.ScheduleFile", "Cannot find file \"" << filePath << "\"");
}
return filePath;
}

std::vector<std::string> ScheduleFile_Impl::columnSeparatorValues() const {
return openstudio::epmodel::ScheduleFile::columnSeparatorValues();
}
Expand Down
25 changes: 24 additions & 1 deletion src/epmodel/ScheduleInterval/ScheduleFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@

#include "EPModelAPI.hpp"
#include "Schedule/Schedule.hpp"
#include "../../utilities/core/Path.hpp"
#include "../../utilities/filetypes/CSVFile.hpp"
#include <utilities/core/Deprecated.hpp>

#include <utilities/idd/IddEnums.hxx>

#include <memory>
#include <vector>

namespace openstudio {

namespace epmodel {

class Model;
Expand All @@ -26,7 +30,9 @@ namespace epmodel {
class EPMODEL_API ScheduleFile : public Schedule
{
public:
explicit ScheduleFile(const Model& model);
// explicit ScheduleFile(const ExternalFile& externalfile, int column = 1, int rowsToSkip = 0); // FIXME: how do we maintain this?
explicit ScheduleFile(const Model& model, int column = 1, int rowsToSkip = 0); // new ctor
explicit ScheduleFile(const Model& model, const openstudio::path& filePath, int column = 1, int rowsToSkip = 0, bool translateFileWithRelativePath = false); // old ctor

virtual ~ScheduleFile() override = default;
ScheduleFile(const ScheduleFile& other) = default;
Expand All @@ -47,6 +53,10 @@ namespace epmodel {
// - Field Mapping: ScheduleTypeLimitsName and FileName are intentionally excluded in this scalar-only pass
// (relationship/file-path behavior is handled separately from scalar accessors).
// - TODO(parity): Add relationship and path-translation parity APIs incrementally after scalar scaffold saturation.

// std::string fileName() const;
// bool setFileName(std::string fileName);

int columnNumber() const;
bool setColumnNumber(int columnNumber);

Expand Down Expand Up @@ -78,6 +88,16 @@ namespace epmodel {
bool setAdjustScheduleforDaylightSavings(bool adjustScheduleforDaylightSavings);
void resetAdjustScheduleforDaylightSavings();

static boost::optional<ScheduleFile> fromTimeSeries(const openstudio::TimeSeries& timeSeries, Model& model);

// Extra setters/getters
boost::optional<CSVFile> csvFile() const;
OS_DEPRECATED(4, 0, 0) bool translateFileWithRelativePath() const;
OS_DEPRECATED(4, 0, 0) bool isTranslateFileWithRelativePathDefaulted() const;
OS_DEPRECATED(4, 0, 0) bool setTranslateFileWithRelativePath(bool translateFileWithRelativePath);
OS_DEPRECATED(4, 0, 0) void resetTranslateFileWithRelativePath();
openstudio::path translatedFilePath() const;

protected:
using ImplType = detail::ScheduleFile_Impl;

Expand All @@ -86,6 +106,9 @@ namespace epmodel {
friend class openstudio::detail::IdfObject_Impl;

explicit ScheduleFile(std::shared_ptr<detail::ScheduleFile_Impl> impl);

private:
REGISTER_LOGGER("openstudio.epmodel.ScheduleFile");
};

} // namespace epmodel
Expand Down
16 changes: 16 additions & 0 deletions src/epmodel/ScheduleInterval/ScheduleFile_Impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define EPMODEL_SCHEDULEFILE_IMPL_HPP

#include "Schedule/Schedule_Impl.hpp"
#include "../utilities/filetypes/CSVFile.hpp"

#include <vector>

Expand All @@ -20,6 +21,9 @@ namespace epmodel {
using Schedule_Impl::Schedule_Impl;
virtual ~ScheduleFile_Impl() override = default;

std::string fileName() const;
bool setFileName(std::string fileName);

int columnNumber() const;
bool setColumnNumber(int columnNumber);

Expand Down Expand Up @@ -50,6 +54,18 @@ namespace epmodel {
bool setAdjustScheduleforDaylightSavings(bool adjustScheduleforDaylightSavings);
void resetAdjustScheduleforDaylightSavings();

// openstudio::TimeSeries timeSeries() const;
bool setTimeSeries(const openstudio::TimeSeries& timeSeries);

// Extra setters/getters
boost::optional<CSVFile> csvFile() const;
// bool translateFileWithRelativePath() const;
// bool isTranslateFileWithRelativePathDefaulted() const;
// void ensureNoLeapDays();
// bool setTranslateFileWithRelativePath(bool translateFileWithRelativePath);
// void resetTranslateFileWithRelativePath();
openstudio::path translatedFilePath() const;

std::vector<std::string> columnSeparatorValues() const;
std::vector<std::string> minutesperItemValues() const;
};
Expand Down
Loading