From d44a08393b2604b87b98a1a2fed0717d2731ec86 Mon Sep 17 00:00:00 2001 From: "Jason W. DeGraw" Date: Fri, 22 Nov 2013 03:12:31 -0500 Subject: [PATCH 1/5] CONTAM model object impl-ized, FT work started --- .../src/contam/ForwardTranslator.cpp | 170 ++++++++-------- .../src/contam/ForwardTranslator.hpp | 20 +- openstudiocore/src/contam/PrjModel.cpp | 190 +++++++++--------- openstudiocore/src/contam/PrjModel.hpp | 143 +++++++------ 4 files changed, 278 insertions(+), 245 deletions(-) diff --git a/openstudiocore/src/contam/ForwardTranslator.cpp b/openstudiocore/src/contam/ForwardTranslator.cpp index 953bddaa051..1affa80fdd7 100644 --- a/openstudiocore/src/contam/ForwardTranslator.cpp +++ b/openstudiocore/src/contam/ForwardTranslator.cpp @@ -142,11 +142,23 @@ bool CvFile::write(openstudio::path filepath) return false; } -ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, bool translateHVAC, ProgressBar* progressBar) +ForwardTranslator::ForwardTranslator() { m_logSink.setLogLevel(Warn); m_logSink.setChannelRegex(boost::regex("openstudio\\.contam\\.ForwardTranslator")); m_logSink.setThreadId(QThread::currentThread()); + clear(); +} + +//void ForwardTranslator::translate(const openstudio::model::Model& model, bool translateHVAC, ProgressBar* progressBar) +//{ + //read(std::string(":/templates/template.prj")); + //if(valid()) + //{ + // The template is a legal PRJ file, so it has one level. Not for long. + // setLevels(std::vector()); + // } + /* m_model = model; m_ratioOverride=false; m_returnSupplyRatio=1.0; @@ -154,8 +166,10 @@ ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, bool init(); setAirtightnessLevel("Average"); translate(translateHVAC); -} + */ +//} +/* ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, std::string leakageDescriptor, bool translateHVAC, ProgressBar* progressBar) { @@ -230,22 +244,22 @@ ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, doub setExteriorFlowRate(flow,n,deltaP); translate(translateHVAC); } +*/ -void ForwardTranslator::init() +void ForwardTranslator::clear() { - m_ready=false; - read(std::string(":/templates/template.prj")); - if(valid()) - { - // The template is a legal PRJ file, so it has one level. Not for long. - setLevels(std::vector()); - } m_afeMap = std::map(); m_levelMap = QMap (); m_zoneMap = std::map (); m_pathMap = QMap (); m_surfaceMap = std::map (); m_ahsMap = QMap (); + m_leakageDescriptor = boost::optional("Average"); + m_returnSupplyRatio = 1.0; + m_ratioOverride = false; + m_startDateTime = boost::optional(); + m_endDateTime = boost::optional(); + ProgressBar* m_progressBar = 0; } int ForwardTranslator::tableLookup(QMap map, std::string str, const char *name) @@ -463,7 +477,7 @@ bool ForwardTranslator::toPrj(const openstudio::path& path) bool ForwardTranslator::modelToPrj(const openstudio::model::Model& model, const openstudio::path& path, bool translateHVAC, std::string leakageDescriptor, ProgressBar* progressBar) { - ForwardTranslator translator(model,leakageDescriptor,translateHVAC,progressBar); + ForwardTranslator translator; //model,leakageDescriptor,translateHVAC,progressBar); boost::optional output; output = translator.toString(); @@ -491,14 +505,24 @@ bool compareElevation(openstudio::model::BuildingStory a, openstudio::model::Bui // This function is altogether too long and needs to be broken up into smaller functions. // This is particularly true for the HVAC translation. -bool ForwardTranslator::translate(bool translateHVAC) +boost::optional ForwardTranslator::translate(model::Model model, bool translateHVAC) { m_logSink.setThreadId(QThread::currentThread()); m_logSink.resetStringStream(); + + contam::CxModel cxModel; + cxModel.read(std::string(":/templates/template.prj")); + if(!cxModel.valid()) + { + return boost::optional(); + } + // The template is a legal PRJ file, so it has one level. Not for long. + setLevels(std::vector()); + QString output; int nr; // Set top-level model info - boost::optional building = m_model.getOptionalUniqueModelObject(); + boost::optional building = model.getOptionalUniqueModelObject(); QString modelDescr = QString("Automatically generated OpenStudio model"); if(building) { @@ -506,9 +530,9 @@ bool ForwardTranslator::translate(bool translateHVAC) if(name) modelDescr = QString("Automatically generated from \"%1\" OpenStudio model").arg(openstudio::toQString(name.get())); } - rc().setPrjdesc(modelDescr.toStdString()); + cxModel.rc().setPrjdesc(modelDescr.toStdString()); // Set the simulation length to match the length of the E+ simulation - boost::optional rp = m_model.runPeriod(); + boost::optional rp = model.runPeriod(); if(rp) { bool goodDates = true; @@ -530,17 +554,17 @@ bool ForwardTranslator::translate(bool translateHVAC) if(goodDates) { // Turn on transient simulation - rc().setSim_af(1); + cxModel.rc().setSim_af(1); // Set start date - rc().setDate_0(startString); - rc().setTime_0("00:00:00"); + cxModel.rc().setDate_0(startString); + cxModel.rc().setTime_0("00:00:00"); // Set start date - rc().setDate_1(endString); - rc().setTime_1("24:00:00"); + cxModel.rc().setDate_1(endString); + cxModel.rc().setTime_1("24:00:00"); } } // Get stories - std::vector stories = m_model.getModelObjects(); + std::vector stories = model.getModelObjects(); // It appears that we will need for each story to have an elevation BOOST_FOREACH(const openstudio::model::BuildingStory& buildingStory, stories) { @@ -548,8 +572,7 @@ bool ForwardTranslator::translate(bool translateHVAC) if(!elevation) { LOG(Error, "Story '" << buildingStory.name().get() << "' has no elevation, translation aborted"); - m_ready = false; - return false; + return boost::optional(); } } // Sort the stories by elevation @@ -567,23 +590,22 @@ bool ForwardTranslator::translate(bool translateHVAC) level.setNr(nr); level.setRefht(QString("%1").arg(z).toStdString()); level.setDelht(QString("%1").arg(ht).toStdString()); - addLevel(level); + cxModel.addLevel(level); nr++; if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); } } - rc().setWind_H(QString().sprintf("%g",totalHeight).toStdString()); + cxModel.rc().setWind_H(QString().sprintf("%g",totalHeight).toStdString()); // Check for levels - translation can't proceed without levels - if(levels().size() == 0) + if(cxModel.levels().size() == 0) { LOG(Error, "Failed to find building stories in model, translation aborted"); - m_ready = false; - return false; + return boost::optional(); } // Translate each thermal zone and generate a lookup table by name. - std::vector thermalZones = m_model.getConcreteModelObjects(); + std::vector thermalZones = model.getConcreteModelObjects(); if (m_progressBar) { m_progressBar->setWindowTitle(openstudio::toString("Translating Zones")); @@ -592,7 +614,7 @@ bool ForwardTranslator::translate(bool translateHVAC) m_progressBar->setValue(0); } nr=0; - BOOST_FOREACH(openstudio::model::ThermalZone thermalZone, thermalZones) + BOOST_FOREACH(model::ThermalZone thermalZone, thermalZones) { nr++; openstudio::contam::Zone zone; @@ -647,12 +669,11 @@ bool ForwardTranslator::translate(bool translateHVAC) else { LOG(Error, "Unable to set level for zone '" << thermalZone.name().get() << "', translation aborted"); - m_ready = false; - return false; + return boost::optional(); } // set T0 zone.setT0(QString("293.15").toStdString()); - addZone(zone); + cxModel.addZone(zone); if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); @@ -660,7 +681,7 @@ bool ForwardTranslator::translate(bool translateHVAC) } // Create paths and generate a lookup table by name - std::vector surfaces = m_model.getConcreteModelObjects(); + std::vector surfaces = model.getConcreteModelObjects(); if (m_progressBar) { m_progressBar->setWindowTitle(openstudio::toString("Translating Surfaces")); @@ -671,10 +692,10 @@ bool ForwardTranslator::translate(bool translateHVAC) nr = 0; // Loop over surfaces and generate paths QList used; - double wind_H = QString().fromStdString(rc().wind_H()).toDouble(); - BOOST_FOREACH(openstudio::model::Surface surface,surfaces) + double wind_H = QString().fromStdString(cxModel.rc().wind_H()).toDouble(); + BOOST_FOREACH(model::Surface surface,surfaces) { - openstudio::contam::Path path; + contam::Path path; std::string bc = surface.outsideBoundaryCondition(); if(!used.contains(surface.handle()) && bc != "Ground") { @@ -710,7 +731,7 @@ bool ForwardTranslator::translate(bool translateHVAC) } continue; } - openstudio::contam::Zone zone = zones()[zoneNr-1]; + contam::Zone zone = zones()[zoneNr-1]; // Get the surface area - will need to do more work here later if large openings are present double area = surface.grossArea(); std::string type = surface.surfaceType(); @@ -747,7 +768,7 @@ bool ForwardTranslator::translate(bool translateHVAC) } path.setNr(++nr); m_surfaceMap[surface.handle()] = path.nr(); - addPath(path); + cxModel.addPath(path); } else if (bc == "Surface") { @@ -755,22 +776,19 @@ bool ForwardTranslator::translate(bool translateHVAC) if(!adjacentSurface) { LOG(Error, "Unable to find adjacent surface for surface '" << surface.name().get() << "'"); - m_ready = false; - return false; + return boost::optional(); } boost::optional adjacentSpace = adjacentSurface->space(); if(!adjacentSpace) { LOG(Error, "Unattached adjacent surface '" << adjacentSurface->name().get() << "'"); - m_ready = false; - return false; + return boost::optional(); } boost::optional adjacentZone = adjacentSpace->thermalZone(); if(!adjacentZone) { LOG(Error, "Unattached adjacent space '" << adjacentSpace->name().get() << "'"); - m_ready = false; - return false; + return boost::optional(); } if(adjacentZone.get() != thermalZone.get()) // I don't really like doing this { @@ -788,7 +806,7 @@ bool ForwardTranslator::translate(bool translateHVAC) } path.setNr(++nr); m_surfaceMap[surface.handle()] = path.nr(); - addPath(path); + cxModel.addPath(path); used << adjacentSurface->handle(); } } @@ -802,7 +820,7 @@ bool ForwardTranslator::translate(bool translateHVAC) if(translateHVAC) { // Generate air handling systems - std::vector systems = m_model.getConcreteModelObjects(); + std::vector systems = model.getConcreteModelObjects(); if (m_progressBar) { m_progressBar->setWindowTitle(openstudio::toString("Translating AirLoops")); @@ -847,8 +865,8 @@ bool ForwardTranslator::translate(bool translateHVAC) ahs.setZone_r(rz.nr()); ahs.setZone_s(sz.nr()); // Add them to the zone list - addZone(rz); - addZone(sz); + cxModel.addZone(rz); + cxModel.addZone(sz); // Now hook the served zones up to the supply and return zones BOOST_FOREACH(openstudio::model::ThermalZone thermalZone, airloop.thermalZones()) { @@ -872,10 +890,10 @@ bool ForwardTranslator::translate(bool translateHVAC) rp.setSystem(true); m_pathMap[(thermalZone.name().get()+" return")] = rp.nr(); // Add the paths to the path list - addPath(sp); + cxModel.addPath(sp); addPath(rp); } - addAhs(ahs); + cxModel.addAhs(ahs); if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); @@ -920,13 +938,13 @@ bool ForwardTranslator::translate(bool translateHVAC) exhaust.setExhaust(true); m_pathMap[loopName + " exhaust"] = exhaust.nr(); // Add the paths to the path list - addPath(recirc); - addPath(oa); - addPath(exhaust); + cxModel.addPath(recirc); + cxModel.addPath(oa); + cxModel.addPath(exhaust); // Store the nrs in the ahs - ahs()[i].setPath_r(recirc.nr()); - ahs()[i].setPath_s(oa.nr()); - ahs()[i].setPath_x(exhaust.nr()); + cxModel.ahs()[i].setPath_r(recirc.nr()); + cxModel.ahs()[i].setPath_s(oa.nr()); + cxModel.ahs()[i].setPath_x(exhaust.nr()); if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); @@ -937,7 +955,7 @@ bool ForwardTranslator::translate(bool translateHVAC) // Try to use E+ results to set temperatures and flow rates. The supply and return flow paths are in the path // lookup table under the names thermalZone.name + supply|return (see above) - boost::optional sqlFile = m_model.sqlFile(); + boost::optional sqlFile = model.sqlFile(); if(sqlFile) { std::vector available = sqlFile->availableTimeSeries(); @@ -955,7 +973,7 @@ bool ForwardTranslator::translate(bool translateHVAC) if(std::find(available.begin(), available.end(), "Zone Mean Air Temperature")!=available.end()) { // Loop through and get a time series for each zone we can find - BOOST_FOREACH(model::ThermalZone thermalZone, m_model.getModelObjects()) + BOOST_FOREACH(model::ThermalZone thermalZone, model.getModelObjects()) { boost::optional name = thermalZone.name(); if(!name) @@ -978,9 +996,9 @@ bool ForwardTranslator::translate(bool translateHVAC) CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - addControlNode(ctrl); + cxModel.addControlNode(ctrl); // Connect to the zone - zones()[nr-1].setPc(ctrl.nr()); + cxModel.zones()[nr-1].setPc(ctrl.nr()); } else { @@ -997,7 +1015,7 @@ bool ForwardTranslator::translate(bool translateHVAC) LOG(Warn, "Zone equipment not yet accounted for."); // get sizing results, get flow rate schedules for each zone's inlet, return, and exhaust nodes // This should be moved to inside the contam translator - BOOST_FOREACH(model::ThermalZone thermalZone, m_model.getModelObjects()) + BOOST_FOREACH(model::ThermalZone thermalZone, model.getModelObjects()) { // todo: this does not include OA from zone equipment (PTAC, PTHP, etc) or exhaust fans @@ -1030,9 +1048,9 @@ bool ForwardTranslator::translate(bool translateHVAC) CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - addControlNode(ctrl); + cxModel.addControlNode(ctrl); // Connect to the path - paths()[nr-1].setPc(ctrl.nr()); + cxModel.paths()[nr-1].setPc(ctrl.nr()); if(m_ratioOverride) // This assumes that there *is* a return, which could be wrong? maybe? { // Create a new time series @@ -1051,9 +1069,9 @@ bool ForwardTranslator::translate(bool translateHVAC) CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - addControlNode(ctrl); + cxModel.addControlNode(ctrl); // Connect to the path - paths()[nr-1].setPc(ctrl.nr()); + cxModel.paths()[nr-1].setPc(ctrl.nr()); } } } @@ -1089,9 +1107,9 @@ bool ForwardTranslator::translate(bool translateHVAC) CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - addControlNode(ctrl); + cxModel.addControlNode(ctrl); // Connect to the path - paths()[nr-1].setPc(ctrl.nr()); + cxModel.paths()[nr-1].setPc(ctrl.nr()); } } } @@ -1107,7 +1125,7 @@ bool ForwardTranslator::translate(bool translateHVAC) LOG(Warn, "Simulation results not available, using 1 scfm/ft^2 to set supply flows"); // Use the 1 scfm/ft^2 approximation with 90% return BOOST_FOREACH(openstudio::model::ThermalZone thermalZone, - m_model.getConcreteModelObjects()) + model.getConcreteModelObjects()) { double area=0.0; BOOST_FOREACH(openstudio::model::Space space, thermalZone.spaces()) @@ -1126,20 +1144,19 @@ bool ForwardTranslator::translate(bool translateHVAC) int supplyNr = m_pathMap.value(supplyName,0); if(supplyNr) { - paths()[supplyNr-1].setFahs(QString().sprintf("%g",flowRate).toStdString()); + cxModel.paths()[supplyNr-1].setFahs(QString().sprintf("%g",flowRate).toStdString()); } int returnNr = m_pathMap.value(returnName,0); if(returnNr) { - paths()[returnNr-1].setFahs(QString().sprintf("%g",m_returnSupplyRatio*flowRate).toStdString()); + cxModel.paths()[returnNr-1].setFahs(QString().sprintf("%g",m_returnSupplyRatio*flowRate).toStdString()); } } } } } - m_ready = true; - return true; + return boost::optional(cxModel); // these are probably useful, will have to ask Kyle // Kyle, should these functions be const? @@ -1178,13 +1195,6 @@ boost::optional ForwardTranslator::translateEpw(openstudio::path epwpat return epw; } -std::string ForwardTranslator::toString() -{ - if(ready()) - return Model::toString(); - return std::string(); -} - /* boost::optional > ForwardTranslator::zoneInfiltration(openstudio::path simPath) { diff --git a/openstudiocore/src/contam/ForwardTranslator.hpp b/openstudiocore/src/contam/ForwardTranslator.hpp index c334a2058eb..084e228726f 100644 --- a/openstudiocore/src/contam/ForwardTranslator.hpp +++ b/openstudiocore/src/contam/ForwardTranslator.hpp @@ -59,10 +59,14 @@ class CONTAM_API CvFile Date m_end; }; -class CONTAM_API ForwardTranslator : public Model +class CONTAM_API ForwardTranslator : public CxModel { public: - ForwardTranslator(const openstudio::model::Model& model, bool translateHVAC=true, ProgressBar* progressBar=NULL); + ForwardTranslator(); + + //void translate(const openstudio::model::Model& model, bool translateHVAC, ProgressBar* progressBar); + + /*ForwardTranslator(const openstudio::model::Model& model, bool translateHVAC=true, ProgressBar* progressBar=NULL); ForwardTranslator(const openstudio::model::Model& model, std::string leakageDescriptor, bool translateHVAC=true, ProgressBar* progressBar=NULL); ForwardTranslator(const openstudio::model::Model& model, double flow, double n, double deltaP, @@ -72,9 +76,8 @@ class CONTAM_API ForwardTranslator : public Model ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, std::string leakageDescriptor, bool translateHVAC=true, ProgressBar* progressBar=NULL); ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, double flow, double n, - double deltaP, bool translateHVAC=true, ProgressBar* progressBar=NULL); + double deltaP, bool translateHVAC=true, ProgressBar* progressBar=NULL);*/ - std::string toString(); bool toPrj(const openstudio::path& path); // Static translation function @@ -150,7 +153,7 @@ class CONTAM_API ForwardTranslator : public Model private: // Translators - bool translate(bool translateHVAC=true); + boost::optional translate(model::Model model, bool translateHVAC=true); // Really need to look at these and determine if they are really needed int tableLookup(QMap map, std::string str, const char *name); @@ -159,7 +162,7 @@ class CONTAM_API ForwardTranslator : public Model std::string reverseLookup(QMap map, int nr, const char *name); Handle reverseLookup(QMap map, int nr, const char *name); - void init(); + void clear(); // Maps - will be populated after a call of translateToPrj // All map to the CONTAM index (1,2,...,nElement) @@ -171,13 +174,16 @@ class CONTAM_API ForwardTranslator : public Model std::map m_surfaceMap; // Surface paths stored by handle QMap m_ahsMap; // Airloop to AHS map by handle - openstudio::model::Model m_model; + //openstudio::model::Model m_model; CvFile m_cvf; //boost::optional m_epwFile; boost::optional m_startDateTime; boost::optional m_endDateTime; bool m_ready; boost::optional m_leakageDescriptor; + boost::optional m_flow; + boost::optional m_n; + boost::optional m_deltaP; double m_returnSupplyRatio; bool m_ratioOverride; diff --git a/openstudiocore/src/contam/PrjModel.cpp b/openstudiocore/src/contam/PrjModel.cpp index c0d077197ec..42e1a1323b1 100644 --- a/openstudiocore/src/contam/PrjModel.cpp +++ b/openstudiocore/src/contam/PrjModel.cpp @@ -24,31 +24,31 @@ namespace openstudio { namespace contam { -Model::Model(openstudio::path path) +CxModel::CxModel(openstudio::path path) { read(path); } -Model::Model(std::string filename) +CxModel::CxModel(std::string filename) { read(filename); } -Model::Model(Reader &input) +CxModel::CxModel(Reader &input) { read(input); } -bool Model::read(openstudio::path path) +bool CxModel::read(openstudio::path path) { return read(openstudio::toString(path)); } -bool Model::read(std::string filename) +bool CxModel::read(std::string filename) { QFile fp(QString().fromStdString(filename)); - m_valid = false; + d->valid = false; if (fp.open(QFile::ReadOnly)) { QTextStream stream(&fp); @@ -56,177 +56,177 @@ bool Model::read(std::string filename) read(input); } - return m_valid; + return d->valid; } -bool Model::read(Reader &input) +bool CxModel::read(Reader &input) { - m_valid = false; + d->valid = false; // Section 1: Project, Weather, Simulation, and Output Controls - m_rc.read(input); // Read the run control section + d->rc.read(input); // Read the run control section input.read999(FILELINE); // Section 2: Species and Contaminants - m_contaminants = input.readIntVector(FILELINEC false); - m_species = input.readSectionVector(FILELINEC "species"); + d->contaminants = input.readIntVector(FILELINEC false); + d->species = input.readSectionVector(FILELINEC "species"); // Section 3: Level and Icon Data - m_levels = input.readSectionVector(FILELINEC "level"); + d->levels = input.readSectionVector(FILELINEC "level"); // Section 4: Day Schedules - m_daySchedules = input.readSectionVector(FILELINEC "day schedule"); + d->daySchedules = input.readSectionVector(FILELINEC "day schedule"); // Section 5: Week Schedules - m_weekSchedules = input.readSectionVector(FILELINEC "week schedule"); + d->weekSchedules = input.readSectionVector(FILELINEC "week schedule"); // Section 6: Wind Pressure Profiles - m_windPressureProfiles = input.readSectionVector(FILELINEC "wind pressure profiles"); + d->windPressureProfiles = input.readSectionVector(FILELINEC "wind pressure profiles"); // Section 7: Kinetic Reactions std::string kinr = input.readSection(FILELINE); // Skip it - m_unsupported["KineticReaction"] = kinr; + d->unsupported["KineticReaction"] = kinr; // Section 8a: Filter Elements std::string flte = input.readSection(FILELINE); // Skip it - m_unsupported["FilterElement"] = flte; + d->unsupported["FilterElement"] = flte; // Section 8b: Filters std::string filt = input.readSection(FILELINE); // Skip it - m_unsupported["Filter"] = filt; + d->unsupported["Filter"] = filt; // Section 9: Source/Sink Elements std::string cse = input.readSection(FILELINE); // Skip it - m_unsupported["SourceSink"] = cse; + d->unsupported["SourceSink"] = cse; // Section 10: Airflow Elements - m_airflowElements = input.readElementVector(FILELINEC "airflow element"); + d->airflowElements = input.readElementVector(FILELINEC "airflow element"); // Section 11: Duct Elements std::string dfe = input.readSection(FILELINE); // Skip it - m_unsupported["DuctElement"] = dfe; + d->unsupported["DuctElement"] = dfe; // Section 12a: Control Super Elements std::string selmt = input.readSection(FILELINE); // Skip it - m_unsupported["ControlSuperElements"] = selmt; + d->unsupported["ControlSuperElements"] = selmt; // Section 12b: Control Nodes //std::string ctrl = input.readSection(FILELINE); // Skip it //m_unsupported["ControlNode"] = ctrl; - m_controlNodes = input.readElementVector(FILELINEC "control node"); + d->controlNodes = input.readElementVector(FILELINEC "control node"); // Section 13: Simple Air Handling System (AHS) - m_ahs = input.readSectionVector(FILELINEC "ahs"); + d->ahs = input.readSectionVector(FILELINEC "ahs"); // Section 14: Zones - m_zones = input.readSectionVector(FILELINEC "zone"); + d->zones = input.readSectionVector(FILELINEC "zone"); // Section 15: Initial Zone Concentrations readZoneIc(input); // Section 16: Airflow Paths - m_paths = input.readSectionVector(FILELINEC "path"); + d->paths = input.readSectionVector(FILELINEC "path"); // Section 17: Duct Junctions std::string jct = input.readSection(FILELINE); // Skip it - m_unsupported["DuctJunction"] = jct; + d->unsupported["DuctJunction"] = jct; // Section 18: Initial Junction Concentrations std::string jctic = input.readSection(FILELINE); // Skip it - m_unsupported["JunctionIC"] = jctic; + d->unsupported["JunctionIC"] = jctic; // Section 19: Duct Segments std::string dct = input.readSection(FILELINE); // Skip it - m_unsupported["DuctSegment"] = dct; + d->unsupported["DuctSegment"] = dct; // Section 20: Source/Sinks //m_sourceSinks = input.readSectionVector(FILELINEC QString("source/sink")); std::string css = input.readSection(FILELINE); // Skip it - m_unsupported["SourceSink"] = css; + d->unsupported["SourceSink"] = css; // Section 21: Occupancy Schedules std::string osch = input.readSection(FILELINE); // Skip it - m_unsupported["OccupancySchedule"] = osch; + d->unsupported["OccupancySchedule"] = osch; // Section 22: Exposures std::string pexp = input.readSection(FILELINE); // Skip it - m_unsupported["Exposure"] = pexp; + d->unsupported["Exposure"] = pexp; // Section 23: Annotations std::string note = input.readSection(FILELINE); // Skip it - m_unsupported["Annotation"] = note; + d->unsupported["Annotation"] = note; input.readEnd(FILELINE); - m_valid = true; + d->valid = true; return true; } -std::string Model::toString() +std::string CxModel::toString() { std::string output; - if(!m_valid) + if(!d->valid) { return output; } // Section 1: Project, Weather, Simulation, and Output Controls - output += m_rc.write(); + output += d->rc.write(); output += "-999\n"; // Section 2: Species and Contaminants - output += writeArray(m_contaminants,"contaminants:"); - output += writeSectionVector(m_species,"species:"); + output += writeArray(d->contaminants,"contaminants:"); + output += writeSectionVector(d->species,"species:"); // Section 3: Level and Icon Data - output += writeSectionVector(m_levels,"levels:"); + output += writeSectionVector(d->levels,"levels:"); // Section 4: Day Schedules - output += writeSectionVector(m_daySchedules,"day-schedules:"); + output += writeSectionVector(d->daySchedules,"day-schedules:"); // Section 5: Week Schedules - output += writeSectionVector(m_weekSchedules,"week-schedules:"); + output += writeSectionVector(d->weekSchedules,"week-schedules:"); // Section 6: Wind Pressure Profiles - output += writeSectionVector(m_windPressureProfiles,"wind pressure profiles:"); + output += writeSectionVector(d->windPressureProfiles,"wind pressure profiles:"); // Section 7: Kinetic Reactions - output += m_unsupported["KineticReaction"]; + output += d->unsupported["KineticReaction"]; // Section 8a: Filter Elements - output += m_unsupported["FilterElement"]; + output += d->unsupported["FilterElement"]; // Section 8b: Filters - output += m_unsupported["Filter"]; + output += d->unsupported["Filter"]; // Section 9: Source/Sink Elements - output += m_unsupported["SourceSink"]; + output += d->unsupported["SourceSink"]; // Section 10: Airflow Elements - output += writeSectionVector(m_airflowElements,"flow elements:"); + output += writeSectionVector(d->airflowElements,"flow elements:"); // Section 11: Duct Elements - output += m_unsupported["DuctElement"]; + output += d->unsupported["DuctElement"]; // Section 12a: Control Super Elements - output += m_unsupported["ControlSuperElements"]; + output += d->unsupported["ControlSuperElements"]; // Section 12b: Control Nodes //output += m_unsupported["ControlNode"]; - output += writeSectionVector(m_controlNodes,"control nodes:"); + output += writeSectionVector(d->controlNodes,"control nodes:"); // Section 13: Simple Air Handling System (AHS) - output += writeSectionVector(m_ahs,"simple AHS:"); + output += writeSectionVector(d->ahs,"simple AHS:"); // Section 14: Zones - output += writeSectionVector(m_zones,"zones:"); + output += writeSectionVector(d->zones,"zones:"); // Section 15: Initial Zone Concentrations output += writeZoneIc(); // Section 16: Airflow Paths - output += writeSectionVector(m_paths,"flow paths:"); + output += writeSectionVector(d->paths,"flow paths:"); // Section 17: Duct Junctions - output += m_unsupported["DuctJunction"]; + output += d->unsupported["DuctJunction"]; // Section 18: Initial Junction Concentrations - output += m_unsupported["JunctionIC"]; + output += d->unsupported["JunctionIC"]; // Section 19: Duct Segments - output += m_unsupported["DuctSegment"]; + output += d->unsupported["DuctSegment"]; // Section 20: Source/Sinks - output += m_unsupported["SourceSink"]; + output += d->unsupported["SourceSink"]; // Section 21: Occupancy Schedules - output += m_unsupported["OccupancySchedule"]; + output += d->unsupported["OccupancySchedule"]; // Section 22: Exposures - output += m_unsupported["Exposure"]; + output += d->unsupported["Exposure"]; // Section 23: Annotations - output += m_unsupported["Annotation"]; + output += d->unsupported["Annotation"]; // End of the PRJ file output += "* end project file."; return output; } -std::vector > Model::zoneExteriorFlowPaths() +std::vector > CxModel::zoneExteriorFlowPaths() { - std::vector > paths(m_zones.size()); + std::vector > paths(d->zones.size()); - for(unsigned int i=0;ipaths.size();i++) { - if(m_paths[i].pzn() == -1) + if(d->paths[i].pzn() == -1) { - int nr = m_paths[i].pzm(); - if(nr > 0 && (unsigned int)nr<=m_zones.size()) + int nr = d->paths[i].pzm(); + if(nr > 0 && (unsigned int)nr<=d->zones.size()) { - paths[nr-1].push_back(-m_paths[i].nr()); // This flow path is negative for flow into zone + paths[nr-1].push_back(-d->paths[i].nr()); // This flow path is negative for flow into zone } } - else if(m_paths[i].pzm() == -1) + else if(d->paths[i].pzm() == -1) { - int nr = m_paths[i].pzn(); - if(nr > 0 && (unsigned int)nr<=m_zones.size()) + int nr = d->paths[i].pzn(); + if(nr > 0 && (unsigned int)nr<=d->zones.size()) { - paths[nr-1].push_back(m_paths[i].nr()); // This flow path is positive for flow into zone + paths[nr-1].push_back(d->paths[i].nr()); // This flow path is positive for flow into zone } } } return paths; } -std::vector Model::zoneInfiltration(SimFile *sim) +std::vector CxModel::zoneInfiltration(SimFile *sim) { // This should probably include a lot more checks of things and is written in // somewhat strange way to avoid taking too much advantage of the specifics @@ -235,7 +235,7 @@ std::vector Model::zoneInfiltration(SimFile *sim) //std::vector > flow0 = sim->F0(); std::vector > paths = zoneExteriorFlowPaths(); unsigned int ntimes = sim->dateTimes().size(); - for(unsigned int i=0; izones.size(); i++) { // This is lame, but I can't tell for sure if the values of a Vector are actually zero. Vector inf = createVector(std::vector(ntimes,0)); @@ -312,26 +312,26 @@ std::vector Model::zoneInfiltration(SimFile *sim) return results; } -void Model::rebuildContaminants() +void CxModel::rebuildContaminants() { - m_contaminants.clear(); - for(unsigned int i=1;i<=m_species.size();i++) + d->contaminants.clear(); + for(unsigned int i=1;i<=d->species.size();i++) { - m_species[i].setNr(i); - if(m_species[i].sflag()) + d->species[i].setNr(i); + if(d->species[i].sflag()) { - m_contaminants.push_back(i); + d->contaminants.push_back(i); } } } -void Model::readZoneIc(Reader &input) +void CxModel::readZoneIc(Reader &input) { unsigned int nn = input.readUInt(FILELINE); if(nn != 0) { - unsigned int nctm = m_contaminants.size(); - if(nn != nctm*m_zones.size()) + unsigned int nctm = d->contaminants.size(); + if(nn != nctm*d->zones.size()) { QString mesg("Mismatch between number of zones, contaminants, and initial conditions"); #ifndef NOFILELINE @@ -339,7 +339,7 @@ void Model::readZoneIc(Reader &input) #endif LOG_FREE_AND_THROW("openstudio.contam.ForwardTranslator",mesg.toStdString()); } - for(unsigned int i=0;izones.size();i++) { unsigned int nr = input.readUInt(FILELINE); if(nr != i+1) @@ -356,29 +356,29 @@ void Model::readZoneIc(Reader &input) { ic.push_back(input.readNumber(FILELINE)); } - m_zones[i].setIc(ic); + d->zones[i].setIc(ic); } } input.read999("Failed to find zone IC section termination" CFILELINE); } -std::string Model::writeZoneIc(int start) +std::string CxModel::writeZoneIc(int start) { int offset = 1; if(start != 0) { offset = 1-start; } - int nctm = m_contaminants.size()*(m_zones.size()-start); + int nctm = d->contaminants.size()*(d->zones.size()-start); std::string string = openstudio::toString(nctm) + " ! initial zone concentrations:\n"; if(nctm) { - for(unsigned int i=start;izones.size();i++) { string += openstudio::toString(i+offset); - for(unsigned int j=0;jcontaminants.size();j++) { - string += ' ' + openstudio::toString(m_zones[i].ic(j)); + string += ' ' + openstudio::toString(d->zones[i].ic(j)); } string += '\n'; } @@ -396,13 +396,13 @@ std::string Model::writeZoneIc(int start) //template void Model::addAirflowElement(PlrTest1); -int Model::airflowElementNrByName(std::string name) const +int CxModel::airflowElementNrByName(std::string name) const { - for(int i=0;iairflowElements.size();i++) { - if(m_airflowElements[i]->name() == name) + if(d->airflowElements[i]->name() == name) { - return m_airflowElements[i]->nr(); + return d->airflowElements[i]->nr(); } } return 0; diff --git a/openstudiocore/src/contam/PrjModel.hpp b/openstudiocore/src/contam/PrjModel.hpp index 37b5889da54..3092c0599b4 100644 --- a/openstudiocore/src/contam/PrjModel.hpp +++ b/openstudiocore/src/contam/PrjModel.hpp @@ -23,6 +23,9 @@ #include "PrjReader.hpp" #include "PrjPublic.hpp" +#include +#include + #include #include @@ -33,13 +36,42 @@ namespace contam { class SimFile; -class CONTAM_API Model +class CxModelPrivate : public QSharedData +{ +public: + CxModelPrivate() + { + valid = false; + } + + bool valid; + + std::map unsupported; + + RunControl rc; + std::vector contaminants; + std::vector species; + std::vector levels; + std::vector daySchedules; + std::vector weekSchedules; + std::vector windPressureProfiles; + QVector > airflowElements; + QVector > controlNodes; + std::vector ahs; + std::vector zones; + std::vector paths; +}; + +class CONTAM_API CxModel { public: - Model(){m_valid=false;} - explicit Model(openstudio::path path); - explicit Model(std::string filename); - explicit Model(Reader &input); + CxModel() + { + d = new CxModelPrivate(); + } + explicit CxModel(openstudio::path path); + explicit CxModel(std::string filename); + explicit CxModel(Reader &input); bool read(openstudio::path path); bool read(std::string filename); bool read(Reader &input); @@ -50,77 +82,77 @@ class CONTAM_API Model RunControl rc() const { - return m_rc; + return d->rc; } void setRc(const RunControl rc) { - m_rc = rc; + d->rc = rc; } std::vector contaminants() const { - return m_contaminants; + return d->contaminants; } std::vector species() const { - return m_species; + return d->species; } void setSpecies(const std::vector species) { - m_species = species; + d->species = species; rebuildContaminants(); } std::vector levels() const { - return m_levels; + return d->levels; } void setLevels(const std::vector levels) { - m_levels = levels; + d->levels = levels; } void addLevel(Level level) { - level.setNr(m_levels.size()+1); - m_levels.push_back(level); + level.setNr(d->levels.size()+1); + d->levels.push_back(level); } std::vector daySchedules() const { - return m_daySchedules; + return d->daySchedules; } void setDaySchedules(const std::vector daySchedules) { - m_daySchedules = daySchedules; + d->daySchedules = daySchedules; } std::vector weekSchedules() const { - return m_weekSchedules; + return d->weekSchedules; } void setWeekSchedules(const std::vector weekSchedules) { - m_weekSchedules = weekSchedules; + d->weekSchedules = weekSchedules; } std::vector windPressureProfiles() const { - return m_windPressureProfiles; + return d->windPressureProfiles; } void setWindPressureProfiles(const std::vector windPressureProfiles) { - m_windPressureProfiles = windPressureProfiles; + d->windPressureProfiles = windPressureProfiles; } std::vector getPlrTest1() const { std::vector afe; - for(int i=0;iairflowElements.size();i++) { - if(m_airflowElements[i]->dataType() == "plr_test1") + if(d->airflowElements[i]->dataType() == "plr_test1") { - afe.push_back(*(m_airflowElements[i].dynamicCast().data())); + afe.push_back(*(d->airflowElements[i].dynamicCast().data())); } } return afe; @@ -141,8 +173,8 @@ class CONTAM_API Model AirflowElement *pointer = dynamic_cast(copy); if(pointer) { - copy->setNr(m_airflowElements.size()+1); - m_airflowElements.push_back(QSharedPointer(pointer)); + copy->setNr(d->airflowElements.size()+1); + d->airflowElements.push_back(QSharedPointer(pointer)); } } @@ -150,7 +182,7 @@ class CONTAM_API Model template bool replaceAirflowElement(int nr, T element) { - if(nr>0 && nr<=m_airflowElements.size()) + if(nr>0 && nr<=d->airflowElements.size()) { T *copy = new T; *copy = element; @@ -158,7 +190,7 @@ class CONTAM_API Model if(pointer) { copy->setNr(nr); - m_airflowElements.replace(nr-1,QSharedPointer(pointer)); + d->airflowElements.replace(nr-1,QSharedPointer(pointer)); return true; } } @@ -168,9 +200,9 @@ class CONTAM_API Model std::vector getCvfDat() { std::vector ctrl; - for(int i=0;icontrolNodes.size();i++) { - QSharedPointer cast = m_controlNodes[i].dynamicCast(); + QSharedPointer cast = d->controlNodes[i].dynamicCast(); if(!cast.isNull()) { ctrl.push_back(*(cast.data())); @@ -186,60 +218,60 @@ class CONTAM_API Model ControlNode *pointer = dynamic_cast(copy); if(pointer) { - copy->setNr(m_controlNodes.size()+1); + copy->setNr(d->controlNodes.size()+1); if(sequence) { copy->setSeqnr(copy->nr()); } - m_controlNodes.push_back(QSharedPointer(pointer)); + d->controlNodes.push_back(QSharedPointer(pointer)); } } std::vector ahs() const { - return m_ahs; + return d->ahs; } void setAhs(const std::vector ahs) { - m_ahs = ahs; + d->ahs = ahs; } void addAhs(Ahs ahs) { - ahs.setNr(m_ahs.size()+1); - m_ahs.push_back(ahs); + ahs.setNr(d->ahs.size()+1); + d->ahs.push_back(ahs); } std::vector zones() const { - return m_zones; + return d->zones; } void setZones(const std::vector zones) { - m_zones = zones; + d->zones = zones; } void addZone(Zone zone) { - zone.setNr(m_zones.size()+1); - m_zones.push_back(zone); + zone.setNr(d->zones.size()+1); + d->zones.push_back(zone); } std::vector paths() const { - return m_paths; + return d->paths; } void setPaths(const std::vector paths) { - m_paths = paths; + d->paths = paths; } void addPath(Path path) { - path.setNr(m_paths.size()+1); - m_paths.push_back(path); + path.setNr(d->paths.size()+1); + d->paths.push_back(path); } bool valid() const { - return m_valid; + return d->valid; } private: @@ -254,25 +286,10 @@ class CONTAM_API Model template std::string writeSectionVector(QVector > vector, std::string label=std::string(), int start=0); template std::string writeArray(std::vector vector, std::string label=std::string(), int start=0); - bool m_valid; - - std::map m_unsupported; - - RunControl m_rc; - std::vector m_contaminants; - std::vector m_species; - std::vector m_levels; - std::vector m_daySchedules; - std::vector m_weekSchedules; - std::vector m_windPressureProfiles; - QVector > m_airflowElements; - QVector > m_controlNodes; - std::vector m_ahs; - std::vector m_zones; - std::vector m_paths; + QExplicitlySharedDataPointer d; }; -template std::string Model::writeSectionVector(std::vector vector, std::string label, int start) +template std::string CxModel::writeSectionVector(std::vector vector, std::string label, int start) { std::string string; int number = vector.size()-start; @@ -315,7 +332,7 @@ return string; } */ -template std::string Model::writeSectionVector(QVector > vector, +template std::string CxModel::writeSectionVector(QVector > vector, std::string label, int start) { std::string string; @@ -336,7 +353,7 @@ template std::string Model::writeSectionVector(QVector std::string Model::writeArray(std::vector vector, std::string label, int start) +template std::string CxModel::writeArray(std::vector vector, std::string label, int start) { std::string string; int number = vector.size()-start; From e3307bb677442c89696b26f0b955fd8fc8e940d9 Mon Sep 17 00:00:00 2001 From: "Jason W. DeGraw" Date: Fri, 22 Nov 2013 19:42:20 -0500 Subject: [PATCH 2/5] New objects pass unit test, more testing up next --- .../src/contam/ForwardTranslator.cpp | 526 +++++++----------- .../src/contam/ForwardTranslator.hpp | 100 +--- 2 files changed, 222 insertions(+), 404 deletions(-) diff --git a/openstudiocore/src/contam/ForwardTranslator.cpp b/openstudiocore/src/contam/ForwardTranslator.cpp index 1affa80fdd7..0038b24e62a 100644 --- a/openstudiocore/src/contam/ForwardTranslator.cpp +++ b/openstudiocore/src/contam/ForwardTranslator.cpp @@ -1,21 +1,21 @@ /********************************************************************** - * Copyright (c) 2008-2013, Alliance for Sustainable Energy. - * All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - **********************************************************************/ +* Copyright (c) 2008-2013, Alliance for Sustainable Energy. +* All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +**********************************************************************/ #include #include @@ -62,9 +62,16 @@ namespace openstudio { namespace contam { CvFile::CvFile() +{ + clear(); +} + +void CvFile::clear() { m_start = Date(MonthOfYear::Jan,1); m_end = Date(MonthOfYear::Dec,31); + m_names = std::vector(); + m_series = std::vector(); } void CvFile::addTimeSeries(std::string name, TimeSeries series) @@ -88,7 +95,7 @@ bool CvFile::write(openstudio::path filepath) textStream << "ContinuousValuesFile ContamW 2.1\n"; textStream << "CVF file from E+ results\n"; textStream << month(m_start.monthOfYear()) << '/' << m_start.dayOfMonth() << '\t' - << month(m_end.monthOfYear()) << '/' << m_end.dayOfMonth() << '\n'; + << month(m_end.monthOfYear()) << '/' << m_end.dayOfMonth() << '\n'; textStream << m_names.size() << '\n'; for(unsigned int i=0;i()); - // } - /* - m_model = model; - m_ratioOverride=false; - m_returnSupplyRatio=1.0; - m_progressBar = progressBar; - init(); - setAirtightnessLevel("Average"); - translate(translateHVAC); - */ -//} - -/* -ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, std::string leakageDescriptor, bool translateHVAC, - ProgressBar* progressBar) -{ - m_logSink.setLogLevel(Warn); - m_logSink.setChannelRegex(boost::regex("openstudio\\.contam\\.ForwardTranslator")); - m_logSink.setThreadId(QThread::currentThread()); - m_model = model; - m_ratioOverride=false; - m_returnSupplyRatio=1.0; - m_progressBar = progressBar; - init(); - setAirtightnessLevel(leakageDescriptor); - translate(translateHVAC); -} - -ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, double flow, double n, double deltaP, - bool translateHVAC, ProgressBar* progressBar) -{ - m_logSink.setLogLevel(Warn); - m_logSink.setChannelRegex(boost::regex("openstudio\\.contam\\.ForwardTranslator")); - m_logSink.setThreadId(QThread::currentThread()); - m_model = model; - m_ratioOverride=false; - m_returnSupplyRatio=1.0; - m_progressBar = progressBar; - init(); - setExteriorFlowRate(flow,n,deltaP); - translate(translateHVAC); -} - -ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, bool translateHVAC, - ProgressBar* progressBar) -{ - m_logSink.setLogLevel(Warn); - m_logSink.setChannelRegex(boost::regex("openstudio\\.contam\\.ForwardTranslator")); - m_logSink.setThreadId(QThread::currentThread()); - m_model = model; - m_ratioOverride=true; - m_returnSupplyRatio=returnSupplyRatio; - m_progressBar = progressBar; - init(); - setAirtightnessLevel("Average"); - translate(translateHVAC); -} - -ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, - std::string leakageDescriptor, bool translateHVAC, ProgressBar* progressBar) -{ - m_logSink.setLogLevel(Warn); - m_logSink.setChannelRegex(boost::regex("openstudio\\.contam\\.ForwardTranslator")); - m_logSink.setThreadId(QThread::currentThread()); - m_model = model; - m_ratioOverride=true; - m_returnSupplyRatio=returnSupplyRatio; - m_progressBar = progressBar; - init(); - setAirtightnessLevel(leakageDescriptor); - translate(translateHVAC); -} - -ForwardTranslator::ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, double flow, double n, - double deltaP, bool translateHVAC, ProgressBar* progressBar) -{ - m_logSink.setLogLevel(Warn); - m_logSink.setChannelRegex(boost::regex("openstudio\\.contam\\.ForwardTranslator")); - m_logSink.setThreadId(QThread::currentThread()); - m_model = model; - m_ratioOverride=true; - m_returnSupplyRatio=returnSupplyRatio; - m_progressBar = progressBar; - init(); - setExteriorFlowRate(flow,n,deltaP); - translate(translateHVAC); -} -*/ - void ForwardTranslator::clear() { m_afeMap = std::map(); @@ -259,7 +170,8 @@ void ForwardTranslator::clear() m_ratioOverride = false; m_startDateTime = boost::optional(); m_endDateTime = boost::optional(); - ProgressBar* m_progressBar = 0; + m_translateHVAC = true; + m_progressBar = 0; } int ForwardTranslator::tableLookup(QMap map, std::string str, const char *name) @@ -333,135 +245,169 @@ Handle ForwardTranslator::reverseLookup(QMap map, int nr, const char return Handle(); } +// Getters and setters +double ForwardTranslator::returnSupplyRatio() const +{ + return m_returnSupplyRatio; +} +void ForwardTranslator::setReturnSupplyRatio(double returnSupplyRatio) +{ + m_returnSupplyRatio = fabs(returnSupplyRatio); +} + +bool ForwardTranslator::ratioOverride() const +{ + return m_ratioOverride; +} +void ForwardTranslator::setRatioOverride(bool ratioOverride) +{ + m_ratioOverride = ratioOverride; +} + +bool ForwardTranslator::translateHVAC() const +{ + return m_translateHVAC; +} +void ForwardTranslator::setTranslateHVAC(bool translateHVAC) +{ + m_translateHVAC = translateHVAC; +} + +boost::optional ForwardTranslator::startDateTime() const +{ + return m_startDateTime; +} + +boost::optional ForwardTranslator::endDateTime() const +{ + return m_endDateTime; +} + boost::optional ForwardTranslator::airtightnessLevel() const { return m_leakageDescriptor; } -bool ForwardTranslator::setAirtightnessLevel(std::string level) +void ForwardTranslator::setAirtightnessLevel(std::string level) +{ + m_leakageDescriptor = boost::optional(level); + m_flow = boost::optional(); + m_n = boost::optional(); + m_deltaP = boost::optional(); +} + +bool ForwardTranslator::applyAirtightnessLevel(contam::CxModel cxModel) { // For this to work, the "standard" names must be in the PRJ data - if(m_afeMap.size()) + if(!m_leakageDescriptor) { - // Set the leakage elements after initial translation, not yet implemented - LOG(Warn,"Setting the leakage elements after initial translation is not yet implemented"); return false; } - else + std::map afeMap; + QList grade, wallExt, wallInt, floor, roof; + grade << "Leaky" << "Average" << "Tight"; + wallExt << "ExtWallLeaky" << "ExtWallAvg" << "ExtWallTight"; + wallInt << "IntWallLeaky" << "IntWallAvg" << "IntWallTight"; + floor << "FloorLeaky" << "FloorAvg" << "FloorTight"; + roof << "RoofLeaky" << "RoofAvg" << "RoofTight"; + int index = grade.indexOf(m_leakageDescriptor.get()); + if(index == -1) // Default to average, unknown leakage level { - std::map afeMap; - QList grade, wallExt, wallInt, floor, roof; - grade << "Leaky" << "Average" << "Tight"; - wallExt << "ExtWallLeaky" << "ExtWallAvg" << "ExtWallTight"; - wallInt << "IntWallLeaky" << "IntWallAvg" << "IntWallTight"; - floor << "FloorLeaky" << "FloorAvg" << "FloorTight"; - roof << "RoofLeaky" << "RoofAvg" << "RoofTight"; - int index = grade.indexOf(level); - if(index == -1) // Default to average, unknown leakage level - { - LOG(Warn, "Unknown airtightness level '" << level << "', defaulting to 'Average'"); - index = 1; - } - int nr; - // Exterior walls - nr = airflowElementNrByName(wallExt[index]); - if(!nr) - { - return false; - } - afeMap["exterior"] = nr; - // Interior walls - nr = airflowElementNrByName(wallInt[index]); - if(!nr) - { - return false; - } - afeMap["interior"] = nr; - // Floors - nr = airflowElementNrByName(floor[index]); - if(!nr) - { - return false; - } - afeMap["floor"] = nr; - // Roof - nr = airflowElementNrByName(roof[index]); - if(!nr) - { - return false; - } - afeMap["roof"] = nr; - m_afeMap = afeMap; - m_leakageDescriptor = boost::optional(level); + LOG(Warn, "Unknown airtightness level '" << m_leakageDescriptor.get() << "', defaulting to 'Average'"); + index = 1; + } + int nr; + // Exterior walls + nr = cxModel.airflowElementNrByName(wallExt[index]); + if(!nr) + { + return false; } + afeMap["exterior"] = nr; + // Interior walls + nr = cxModel.airflowElementNrByName(wallInt[index]); + if(!nr) + { + return false; + } + afeMap["interior"] = nr; + // Floors + nr = cxModel.airflowElementNrByName(floor[index]); + if(!nr) + { + return false; + } + afeMap["floor"] = nr; + // Roof + nr = cxModel.airflowElementNrByName(roof[index]); + if(!nr) + { + return false; + } + afeMap["roof"] = nr; + m_afeMap = afeMap; return true; } -double ForwardTranslator::exteriorFlowRate() const +boost::optional ForwardTranslator::exteriorFlowRate() const { - std::vector plrt1s = getPlrTest1(); - BOOST_FOREACH(PlrTest1 plr, plrt1s) - { - if(plr.name() == "exterior") - { - return QString().fromStdString(plr.Flow()).toDouble(); - } - } - return 0; + return m_flow; } -double ForwardTranslator::exteriorExponent() const +boost::optional ForwardTranslator::exteriorExponent() const { - std::vector plrt1s = getPlrTest1(); - BOOST_FOREACH(PlrTest1 plr, plrt1s) - { - if(plr.name() == "exterior") - { - return QString().fromStdString(plr.expt()).toDouble(); - } - } - return 0; + return m_n; } -double ForwardTranslator::exteriorDeltaP() const +boost::optional ForwardTranslator::exteriorDeltaP() const { - std::vector plrt1s = getPlrTest1(); - BOOST_FOREACH(PlrTest1 plr, plrt1s) - { - if(plr.name() == "exterior") - { - return QString().fromStdString(plr.dP()).toDouble(); - } - } - return 0; + return m_deltaP; } -bool ForwardTranslator::setExteriorFlowRate(double flow,double n,double deltaP) +bool ForwardTranslator::setExteriorFlowRate(double flow, double n, double deltaP) { - if(m_afeMap.size()) + if(flow > 0 && m_n > 0 && m_deltaP > 0) { - // Set the leakage elements after initial translation, not yet implemented - LOG(Warn,"Setting the leakage elements after initial translation is not yet implemented"); - return false; + m_flow = boost::optional(flow); + m_n = boost::optional(n); + m_deltaP = boost::optional(deltaP); + m_leakageDescriptor = boost::optional(); + return true; } - else + return false; +} + +bool ForwardTranslator::applyExteriorFlowRate(contam::CxModel cxModel) +{ + if(m_flow && m_n && m_deltaP) { std::map afeMap; - afeMap["exterior"] = addNewAirflowElement("CustomExterior",flow,n,deltaP); - afeMap["roof"] = addNewAirflowElement("CustomRoof",flow,n,deltaP); - afeMap["interior"] = addNewAirflowElement("CustomInterior",2*flow,n,deltaP); - afeMap["floor"] = addNewAirflowElement("CustomFloor",2*flow,n,deltaP); + afeMap["exterior"] = addNewAirflowElement(cxModel,"CustomExterior",m_flow.get(),m_n.get(),m_deltaP.get()); + afeMap["roof"] = addNewAirflowElement(cxModel,"CustomRoof",m_flow.get(),m_n.get(),m_deltaP.get()); + afeMap["interior"] = addNewAirflowElement(cxModel,"CustomInterior",2*m_flow.get(),m_n.get(),m_deltaP.get()); + afeMap["floor"] = addNewAirflowElement(cxModel,"CustomFloor",2*m_flow.get(),m_n.get(),m_deltaP.get()); m_afeMap = afeMap; m_leakageDescriptor = boost::optional(); + return true; } - return true; + return false; } -bool ForwardTranslator::toPrj(const openstudio::path& path) +bool ForwardTranslator::modelToPrj(const openstudio::model::Model& model, const openstudio::path& path, + bool translateHVAC, std::string leakageDescriptor, ProgressBar* progressBar) { - boost::optional output = this->toString(); - if(output) + ForwardTranslator translator; + translator.setTranslateHVAC(translateHVAC); + translator.setAirtightnessLevel(leakageDescriptor); + + boost::optional cxModel = translator.translate(model); + if(cxModel) { + boost::optional output = cxModel->toString(); + if (!output) + { + return false; + } QFile file(toQString(path)); if(file.open(QFile::WriteOnly)) { @@ -474,28 +420,6 @@ bool ForwardTranslator::toPrj(const openstudio::path& path) return false; } -bool ForwardTranslator::modelToPrj(const openstudio::model::Model& model, const openstudio::path& path, - bool translateHVAC, std::string leakageDescriptor, ProgressBar* progressBar) -{ - ForwardTranslator translator; //model,leakageDescriptor,translateHVAC,progressBar); - - boost::optional output; - output = translator.toString(); - if (!output) - { - return false; - } - QFile file(toQString(path)); - if(file.open(QFile::WriteOnly)) - { - QTextStream textStream(&file); - textStream << *output; - file.close(); - return true; - } - return false; -} - bool compareElevation(openstudio::model::BuildingStory a, openstudio::model::BuildingStory b) { double a_z = a.nominalZCoordinate().get(); @@ -505,7 +429,7 @@ bool compareElevation(openstudio::model::BuildingStory a, openstudio::model::Bui // This function is altogether too long and needs to be broken up into smaller functions. // This is particularly true for the HVAC translation. -boost::optional ForwardTranslator::translate(model::Model model, bool translateHVAC) +boost::optional ForwardTranslator::translate(model::Model model) { m_logSink.setThreadId(QThread::currentThread()); m_logSink.resetStringStream(); @@ -517,7 +441,25 @@ boost::optional ForwardTranslator::translate(model::Model model return boost::optional(); } // The template is a legal PRJ file, so it has one level. Not for long. - setLevels(std::vector()); + cxModel.setLevels(std::vector()); + + // Do some setup work + if(m_leakageDescriptor) + { + if(!applyAirtightnessLevel(cxModel)) + { + LOG(Error,"Application of airtightness level failed."); + return boost::optional(); + } + } + else + { + if(!applyExteriorFlowRate(cxModel)) + { + LOG(Error,"Application of exterior flow rate failed."); + return boost::optional(); + } + } QString output; int nr; @@ -731,7 +673,7 @@ boost::optional ForwardTranslator::translate(model::Model model } continue; } - contam::Zone zone = zones()[zoneNr-1]; + contam::Zone zone = cxModel.zones()[zoneNr-1]; // Get the surface area - will need to do more work here later if large openings are present double area = surface.grossArea(); std::string type = surface.surfaceType(); @@ -742,7 +684,7 @@ boost::optional ForwardTranslator::translate(model::Model model averageZ += point.z(); } // Now set the path info - path.setRelHt(QString().sprintf("%g",averageZ / numVertices - QString().fromStdString(levels()[zone.pl()-1].refht()).toDouble()).toStdString()); + path.setRelHt(QString().sprintf("%g",averageZ / numVertices - QString().fromStdString(cxModel.levels()[zone.pl()-1].refht()).toDouble()).toStdString()); path.setPld(zone.pl()); path.setMult(QString().sprintf("%g",area).toStdString()); // Now for the type specific info @@ -817,7 +759,7 @@ boost::optional ForwardTranslator::translate(model::Model model } } - if(translateHVAC) + if(m_translateHVAC) { // Generate air handling systems std::vector systems = model.getConcreteModelObjects(); @@ -846,7 +788,7 @@ boost::optional ForwardTranslator::translate(model::Model model ahs.setName(QString("AHS_%1").arg(nr).toStdString()); // Create supply and return zones openstudio::contam::Zone rz; - rz.setNr(zones().size()+1); + rz.setNr(cxModel.zones().size()+1); rz.setPl(1); rz.setT0(QString("293.15").toStdString()); rz.setSystem(true); @@ -873,7 +815,7 @@ boost::optional ForwardTranslator::translate(model::Model model int zoneNr = tableLookup(m_zoneMap,thermalZone.handle(),"zoneMap"); // Supply path openstudio::contam::Path sp; - sp.setNr(paths().size()+1); + sp.setNr(cxModel.paths().size()+1); sp.setPld(1); sp.setPzn(ahs.zone_s()); sp.setPzm(zoneNr); @@ -891,7 +833,7 @@ boost::optional ForwardTranslator::translate(model::Model model m_pathMap[(thermalZone.name().get()+" return")] = rp.nr(); // Add the paths to the path list cxModel.addPath(sp); - addPath(rp); + cxModel.addPath(rp); } cxModel.addAhs(ahs); if (m_progressBar) @@ -904,21 +846,21 @@ boost::optional ForwardTranslator::translate(model::Model model { m_progressBar->setWindowTitle(openstudio::toString("Connecting AHS to zones")); m_progressBar->setMinimum(0); - m_progressBar->setMaximum(ahs().size()); + m_progressBar->setMaximum(cxModel.ahs().size()); m_progressBar->setValue(0); } // Now loop back through the AHS list and connect the supply and return zones together - for(unsigned int i=0;i ForwardTranslator::translate(model::Model model oa.setNr(recirc.nr()+1); oa.setPld(1); oa.setPzn(-1); - oa.setPzm(ahs()[i].zone_s()); + oa.setPzm(cxModel.ahs()[i].zone_s()); oa.setOutsideAir(true); m_pathMap[loopName + " oa"] = oa.nr(); // Exhaust path; openstudio::contam::Path exhaust; exhaust.setNr(oa.nr()+1); exhaust.setPld(1); - exhaust.setPzn(ahs()[i].zone_r()); + exhaust.setPzn(cxModel.ahs()[i].zone_r()); exhaust.setPzm(-1); exhaust.setExhaust(true); m_pathMap[loopName + " exhaust"] = exhaust.nr(); @@ -1195,89 +1137,7 @@ boost::optional ForwardTranslator::translateEpw(openstudio::path epwpat return epw; } -/* -boost::optional > ForwardTranslator::zoneInfiltration(openstudio::path simPath) -{ - std::vector results; - - // Collect results - eventually this should use the SQLite results - openstudio::contam::sim::LinkFlow lfr; - openstudio::path lfrPath = simPath.replace_extension(openstudio::toPath("lfr").string()); - if(!lfr.read(lfrPath)) - { - LOG(Error,"Failed to read link flow results."); - return boost::optional >(); - } - - // Do some error checking - std::vector > flow0 = lfr.F0(); - if(flow0.size() != paths().size()) - { - LOG(Error,"Mismatch between lfr data and model path count."); - return boost::optional >(); - } - unsigned int ntimes = flow0[0].size(); - for(unsigned int i=1;i >(); - } - } - - // Collect a vector of the exterior paths - std::vector extPaths; - BOOST_FOREACH(openstudio::contam::Path path, paths()) - { - if(path.flags() == 0 || path.flags() == 1) // These should be it... hopefully... maybe collect this during translation? - { - if(path.pzm() == -1 || path.pzn() == -1) - { - extPaths.push_back(path); - } - } - } - - std::vector dateTimes = lfr.dateTimes(); - - // Initialize storage - std::vector values; - for(unsigned int j=0; j 0) - { - values[pzn-1][i] += flow; - } - } - } - - // Create TimeSeries objects - for(unsigned int j=0; j >(results); -} -*/ - -bool ForwardTranslator::setSteadyWeather(double windSpeed, double windDirection) +bool ForwardTranslator::setSteadyWeather(contam::CxModel cxModel, double windSpeed, double windDirection) { if(windSpeed < 0) { @@ -1285,8 +1145,8 @@ bool ForwardTranslator::setSteadyWeather(double windSpeed, double windDirection) windSpeed = -windSpeed; // Maybe should return false in this case? } // Is a negative wind direction allowed? Will have to check - rc().ssWeather().setWindspd(QString().sprintf("%g",windSpeed).toStdString()); - rc().ssWeather().setWinddir(QString().sprintf("%g",windDirection).toStdString()); + cxModel.rc().ssWeather().setWindspd(QString().sprintf("%g",windSpeed).toStdString()); + cxModel.rc().ssWeather().setWinddir(QString().sprintf("%g",windDirection).toStdString()); return true; } @@ -1322,7 +1182,7 @@ static double laminarCoefficient(double Ct, double x) } -int ForwardTranslator::addNewAirflowElement(std::string name, double flow,double n,double deltaP) +int ForwardTranslator::addNewAirflowElement(contam::CxModel cxModel,std::string name, double flow,double n,double deltaP) { // flow - volume flow rate in m^3/h // deltaP - pressure difference in Pa @@ -1330,7 +1190,7 @@ int ForwardTranslator::addNewAirflowElement(std::string name, double flow,double double RHOAIR = 1.20410; // density of standard air double SRHO = 1.097315; // sqrt( RHOAIR ) - + double F = RHOAIR*flow/3600.0; // mass flow in kg/s double Ct = F/(SRHO*std::pow(deltaP,n)); @@ -1347,7 +1207,7 @@ int ForwardTranslator::addNewAirflowElement(std::string name, double flow,double // Create a 1-point test element with display units of m^3/h PlrTest1 afe(0, 0, name, " ", lam, turb, expt, dP, Flow, u_P, u_F); - addAirflowElement(afe); + cxModel.addAirflowElement(afe); return afe.nr(); } diff --git a/openstudiocore/src/contam/ForwardTranslator.hpp b/openstudiocore/src/contam/ForwardTranslator.hpp index 084e228726f..7a094da66bb 100644 --- a/openstudiocore/src/contam/ForwardTranslator.hpp +++ b/openstudiocore/src/contam/ForwardTranslator.hpp @@ -50,6 +50,7 @@ class CONTAM_API CvFile Date end() const {return m_end;} void setEnd(Date date){m_end=date;} bool isEmpty() {return m_names.size() == 0;} + void clear(); private: std::vector m_names; @@ -59,88 +60,49 @@ class CONTAM_API CvFile Date m_end; }; -class CONTAM_API ForwardTranslator : public CxModel +class CONTAM_API ForwardTranslator// : public CxModel { public: ForwardTranslator(); - //void translate(const openstudio::model::Model& model, bool translateHVAC, ProgressBar* progressBar); - - /*ForwardTranslator(const openstudio::model::Model& model, bool translateHVAC=true, ProgressBar* progressBar=NULL); - ForwardTranslator(const openstudio::model::Model& model, std::string leakageDescriptor, bool translateHVAC=true, - ProgressBar* progressBar=NULL); - ForwardTranslator(const openstudio::model::Model& model, double flow, double n, double deltaP, - bool translateHVAC=true, ProgressBar* progressBar=NULL); - ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, bool translateHVAC=true, - ProgressBar* progressBar=NULL); - ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, std::string leakageDescriptor, - bool translateHVAC=true, ProgressBar* progressBar=NULL); - ForwardTranslator(const openstudio::model::Model& model, double returnSupplyRatio, double flow, double n, - double deltaP, bool translateHVAC=true, ProgressBar* progressBar=NULL);*/ - - bool toPrj(const openstudio::path& path); + // Clear out the translator and reset to the defaults + void clear(); + + // Translator + boost::optional translate(model::Model model); // Static translation function static bool modelToPrj(const openstudio::model::Model& model, const openstudio::path& path, bool translateHVAC=true, std::string leakageDescriptor="Average", ProgressBar* progressBar=NULL); - // Secondary translation functions - need to add more of these by chopping out parts of the main translation function + // Secondary translation functions - this doesn't really fit here any more, so maybe it needs + // to be moved elsewhere, could be made static boost::optional translateEpw(openstudio::path epwpath, openstudio::path outpath); - bool ready() const {return m_ready && valid();} + // Accessors to the element maps std::map surfaceMap() const {return m_surfaceMap;} std::map zoneMap() const {return m_zoneMap;} - // Getters and setters - the setters modify how translation is done or modify the model after translation (eventually). + // Getters and setters - the setters modify how translation // Setters that could fail return a boolean boost::optional airtightnessLevel() const; - bool setAirtightnessLevel(std::string level); - double exteriorFlowRate() const; - double exteriorExponent() const; - double exteriorDeltaP() const; - bool setExteriorFlowRate(double flow,double n=0.65,double deltaP=75.0); - - // Getters and setters - double returnSupplyRatio() const - { - return m_returnSupplyRatio; - } - void setReturnSupplyRatio(double returnSupplyRatio) - { - m_returnSupplyRatio = fabs(returnSupplyRatio); - } - - bool ratioOverride() const - { - return m_ratioOverride; - } - /* - void setRatioOverride(bool ratioOverride) - { - m_ratioOverride = ratioOverride; - } - */ - - //boost::optional epwFile() const - //{ - // return m_epwFile; - //} - - boost::optional startDateTime() const - { - return m_startDateTime; - } - - boost::optional endDateTime() const - { - return m_endDateTime; - } - // Postprocessing Functions - //boost::optional > zoneInfiltration(openstudio::path simPath); + void setAirtightnessLevel(std::string level); + boost::optional exteriorFlowRate() const; + boost::optional exteriorExponent() const; + boost::optional exteriorDeltaP() const; + bool setExteriorFlowRate(double flow, double n, double deltaP); + double returnSupplyRatio() const; + void setReturnSupplyRatio(double returnSupplyRatio); + bool ratioOverride() const; + void setRatioOverride(bool ratioOverride); + bool translateHVAC() const; + void setTranslateHVAC(bool translateHVAC); + boost::optional startDateTime() const; + boost::optional endDateTime() const; // We may need more functions like this that modify the CONTAM model - bool setSteadyWeather(double windSpeed, double windDirection); - int addNewAirflowElement(std::string name,double flow,double n=0.65,double deltaP=75.0); + bool setSteadyWeather(contam::CxModel cxModel,double windSpeed, double windDirection); + int addNewAirflowElement(contam::CxModel cxModel,std::string name,double flow,double n=0.65,double deltaP=75.0); // Write control files bool writeCvFile(openstudio::path filepath); @@ -152,8 +114,8 @@ class CONTAM_API ForwardTranslator : public CxModel std::vector errors() const; private: - // Translators - boost::optional translate(model::Model model, bool translateHVAC=true); + bool applyExteriorFlowRate(contam::CxModel cxModel); + bool applyAirtightnessLevel(contam::CxModel cxModel); // Really need to look at these and determine if they are really needed int tableLookup(QMap map, std::string str, const char *name); @@ -162,8 +124,6 @@ class CONTAM_API ForwardTranslator : public CxModel std::string reverseLookup(QMap map, int nr, const char *name); Handle reverseLookup(QMap map, int nr, const char *name); - void clear(); - // Maps - will be populated after a call of translateToPrj // All map to the CONTAM index (1,2,...,nElement) std::map m_afeMap; // Map from descriptor ("exterior", "floor", etc.) to CONTAM airflow element index @@ -174,18 +134,16 @@ class CONTAM_API ForwardTranslator : public CxModel std::map m_surfaceMap; // Surface paths stored by handle QMap m_ahsMap; // Airloop to AHS map by handle - //openstudio::model::Model m_model; CvFile m_cvf; - //boost::optional m_epwFile; boost::optional m_startDateTime; boost::optional m_endDateTime; - bool m_ready; boost::optional m_leakageDescriptor; boost::optional m_flow; boost::optional m_n; boost::optional m_deltaP; double m_returnSupplyRatio; bool m_ratioOverride; + bool m_translateHVAC; ProgressBar* m_progressBar; From 9f9acd5a3297bd0e66ad6bb202e4e1de78c0212f Mon Sep 17 00:00:00 2001 From: "Jason W. DeGraw" Date: Sat, 23 Nov 2013 15:39:09 -0500 Subject: [PATCH 3/5] More cleanup for utility programs --- openstudiocore/src/contam/ForwardTranslator.cpp | 13 ------------- openstudiocore/src/contam/ForwardTranslator.hpp | 1 - openstudiocore/src/contam/PrjModel.cpp | 12 ++++++++++++ openstudiocore/src/contam/PrjModel.hpp | 1 + 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/openstudiocore/src/contam/ForwardTranslator.cpp b/openstudiocore/src/contam/ForwardTranslator.cpp index 0038b24e62a..d8a5e453fe7 100644 --- a/openstudiocore/src/contam/ForwardTranslator.cpp +++ b/openstudiocore/src/contam/ForwardTranslator.cpp @@ -1137,19 +1137,6 @@ boost::optional ForwardTranslator::translateEpw(openstudio::path epwpat return epw; } -bool ForwardTranslator::setSteadyWeather(contam::CxModel cxModel, double windSpeed, double windDirection) -{ - if(windSpeed < 0) - { - LOG(Warn, "Steady state wind speed is negative, using absolute value."); - windSpeed = -windSpeed; // Maybe should return false in this case? - } - // Is a negative wind direction allowed? Will have to check - cxModel.rc().ssWeather().setWindspd(QString().sprintf("%g",windSpeed).toStdString()); - cxModel.rc().ssWeather().setWinddir(QString().sprintf("%g",windDirection).toStdString()); - return true; -} - static double laminarCoefficient(double Ct, double x) { // Ct turbulent flow coefficient diff --git a/openstudiocore/src/contam/ForwardTranslator.hpp b/openstudiocore/src/contam/ForwardTranslator.hpp index 7a094da66bb..91c7391a35e 100644 --- a/openstudiocore/src/contam/ForwardTranslator.hpp +++ b/openstudiocore/src/contam/ForwardTranslator.hpp @@ -101,7 +101,6 @@ class CONTAM_API ForwardTranslator// : public CxModel boost::optional endDateTime() const; // We may need more functions like this that modify the CONTAM model - bool setSteadyWeather(contam::CxModel cxModel,double windSpeed, double windDirection); int addNewAirflowElement(contam::CxModel cxModel,std::string name,double flow,double n=0.65,double deltaP=75.0); // Write control files diff --git a/openstudiocore/src/contam/PrjModel.cpp b/openstudiocore/src/contam/PrjModel.cpp index 42e1a1323b1..2714acf3222 100644 --- a/openstudiocore/src/contam/PrjModel.cpp +++ b/openstudiocore/src/contam/PrjModel.cpp @@ -408,5 +408,17 @@ int CxModel::airflowElementNrByName(std::string name) const return 0; } +bool CxModel::setSteadyWeather(double windSpeed, double windDirection) +{ + if(windSpeed < 0) + { + windSpeed = -windSpeed; // Maybe should return false in this case? + } + // Is a negative wind direction allowed? Will have to check + d->rc.ssWeather().setWindspd(QString().sprintf("%g",windSpeed).toStdString()); + d->rc.ssWeather().setWinddir(QString().sprintf("%g",windDirection).toStdString()); + return true; +} + } // contam } // openstudio diff --git a/openstudiocore/src/contam/PrjModel.hpp b/openstudiocore/src/contam/PrjModel.hpp index 3092c0599b4..f397501e903 100644 --- a/openstudiocore/src/contam/PrjModel.hpp +++ b/openstudiocore/src/contam/PrjModel.hpp @@ -79,6 +79,7 @@ class CONTAM_API CxModel std::vector > zoneExteriorFlowPaths(); std::vector zoneInfiltration(SimFile *sim); + bool setSteadyWeather(double windSpeed, double windDirection); RunControl rc() const { From 8397bf6bad44b3cba8f9eab26f9c99854a3a9ff4 Mon Sep 17 00:00:00 2001 From: "Jason W. DeGraw" Date: Sat, 23 Nov 2013 20:35:05 -0500 Subject: [PATCH 4/5] Load EPW data if requested and not present, add unit test --- .../src/utilities/filetypes/EpwFile.cpp | 37 +++++++++++- .../src/utilities/filetypes/EpwFile.hpp | 6 +- .../filetypes/test/EpwFile_GTest.cpp | 56 +++++++++++++++++++ 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/openstudiocore/src/utilities/filetypes/EpwFile.cpp b/openstudiocore/src/utilities/filetypes/EpwFile.cpp index 208537af2df..30a0a9f5e09 100644 --- a/openstudiocore/src/utilities/filetypes/EpwFile.cpp +++ b/openstudiocore/src/utilities/filetypes/EpwFile.cpp @@ -1631,13 +1631,24 @@ boost::optional EpwFile::endDateActualYear() const return m_endDateActualYear; } -std::vector EpwFile::data() const +std::vector EpwFile::data() { + if(m_data.size()==0){ + if (!parse(true)){ + LOG(Error,"EpwFile '" << toString(m_path) << "' cannot be processed"); + } + } return m_data; } -boost::optional EpwFile::timeSeries(std::string name) +boost::optional EpwFile::getTimeSeries(std::string name) { + if(m_data.size()==0){ + if (!parse(true)){ + LOG(Error,"EpwFile '" << toString(m_path) << "' cannot be processed"); + return boost::optional(); + } + } EpwDataField id; try { @@ -1672,8 +1683,17 @@ boost::optional EpwFile::timeSeries(std::string name) return boost::optional(); } -bool EpwFile::translateToWth(openstudio::path path, std::string description) const +bool EpwFile::translateToWth(openstudio::path path, std::string description) { + if(m_data.size()==0) + { + if (!parse(true)) + { + LOG(Error,"EpwFile '" << toString(m_path) << "' cannot be processed"); + return false; + } + } + if(description.empty()) { description = "Translated from " + openstudio::toString(this->path()); @@ -1944,11 +1964,22 @@ bool EpwFile::parseDataPeriod(const std::string& line) boost::regex dataPeriodRegex("^DATA PERIODS,(.*?),(.*?),(.*?),(.*?),(.*?),(.*?)$"); boost::smatch matches; if (boost::regex_search(line, matches, dataPeriodRegex)){ + std::string nDataPeriods = std::string(matches[1].first, matches[1].second); boost::trim(nDataPeriods); std::string timeStep = std::string(matches[2].first, matches[2].second); boost::trim(timeStep); std::string startDayOfWeek = std::string(matches[4].first, matches[4].second); boost::trim(startDayOfWeek); std::string startDate = std::string(matches[5].first, matches[5].second); boost::trim(startDate); std::string endDate = std::string(matches[6].first, matches[6].second); boost::trim(endDate); + try{ + int N = boost::lexical_cast(nDataPeriods); + if(N>1) + { + LOG(Error, "More than one data period in EPW file '" << m_path << "', which is not supported"); + result = false; + } + }catch(...){ + result = false; + } try{ m_timeStep = Time(boost::lexical_cast(timeStep) / 24.0); }catch(...){ diff --git a/openstudiocore/src/utilities/filetypes/EpwFile.hpp b/openstudiocore/src/utilities/filetypes/EpwFile.hpp index 13209a3dad1..b09b90fa246 100644 --- a/openstudiocore/src/utilities/filetypes/EpwFile.hpp +++ b/openstudiocore/src/utilities/filetypes/EpwFile.hpp @@ -303,14 +303,14 @@ class UTILITIES_API EpwFile{ boost::optional endDateActualYear() const; /// get the weather data - std::vector data() const; + std::vector data(); /// get a time series of a particular weather field // This will probably need to include the period at some point, but for now just dump everything into a time series - boost::optional timeSeries(std::string field); + boost::optional getTimeSeries(std::string field); /// export to CONTAM WTH file - bool translateToWth(openstudio::path path,std::string description=std::string()) const; + bool translateToWth(openstudio::path path,std::string description=std::string()); private: diff --git a/openstudiocore/src/utilities/filetypes/test/EpwFile_GTest.cpp b/openstudiocore/src/utilities/filetypes/test/EpwFile_GTest.cpp index 8334e7e6c1d..8f84752e9fb 100644 --- a/openstudiocore/src/utilities/filetypes/test/EpwFile_GTest.cpp +++ b/openstudiocore/src/utilities/filetypes/test/EpwFile_GTest.cpp @@ -59,6 +59,62 @@ TEST(Filetypes, EpwFile) } } +TEST(Filetypes, EpwFile_Data) +{ + try{ + path p = resourcesPath() / toPath("runmanager/USA_CO_Golden-NREL.724666_TMY3.epw"); + EpwFile epwFile(p); + EXPECT_EQ(p, epwFile.path()); + EXPECT_EQ("E2EFCD8E", epwFile.checksum()); + EXPECT_EQ("Denver Centennial Golden Nr", epwFile.city()); + EXPECT_EQ("CO", epwFile.stateProvinceRegion()); + EXPECT_EQ("USA", epwFile.country()); + EXPECT_EQ("TMY3", epwFile.dataSource()); + EXPECT_EQ("724666", epwFile.wmoNumber()); + EXPECT_EQ(39.74, epwFile.latitude()); + EXPECT_EQ(-105.18, epwFile.longitude()); + EXPECT_EQ(-7, epwFile.timeZone()); + EXPECT_EQ(1829, epwFile.elevation()); + EXPECT_EQ(Time(0,1,0,0), epwFile.timeStep()); + EXPECT_EQ(DayOfWeek(DayOfWeek::Sunday), epwFile.startDayOfWeek()); + EXPECT_EQ(Date(MonthOfYear::Jan, 1), epwFile.startDate()); + EXPECT_EQ(Date(MonthOfYear::Dec, 31), epwFile.endDate()); + // Up to here, everything should be the same as the first test. Now ask for the data + std::vector data = epwFile.data(); + EXPECT_EQ(8760,data.size()); + // The last data point should be on 12/31/1996, with a dry bulb temp of 4C and presure 81100 + EXPECT_EQ(4.0,data[8759].dryBulbTemperature().get()); + EXPECT_EQ(81100,data[8759].atmosphericStationPressure().get()); + // Try out the alternate access functions, dew point temperature should be -1C + EXPECT_EQ(-1.0,data[8759].fieldByName("Dew Point Temperature").get()); + EXPECT_EQ(-1.0,data[8759].field(EpwDataField("Dew Point Temperature")).get()); + // The last data point should not have a liquid precipitation depth + EXPECT_FALSE(data[8759].fieldByName("Liquid Precipitation Depth")); + // Get a time series + boost::optional series = epwFile.getTimeSeries("Wind Speed"); + EXPECT_TRUE(series); + EXPECT_EQ(8760,series->values().size()); + // We should redo the original tests because we have reparsed the entire file + EXPECT_EQ(p, epwFile.path()); + EXPECT_EQ("E2EFCD8E", epwFile.checksum()); + EXPECT_EQ("Denver Centennial Golden Nr", epwFile.city()); + EXPECT_EQ("CO", epwFile.stateProvinceRegion()); + EXPECT_EQ("USA", epwFile.country()); + EXPECT_EQ("TMY3", epwFile.dataSource()); + EXPECT_EQ("724666", epwFile.wmoNumber()); + EXPECT_EQ(39.74, epwFile.latitude()); + EXPECT_EQ(-105.18, epwFile.longitude()); + EXPECT_EQ(-7, epwFile.timeZone()); + EXPECT_EQ(1829, epwFile.elevation()); + EXPECT_EQ(Time(0,1,0,0), epwFile.timeStep()); + EXPECT_EQ(DayOfWeek(DayOfWeek::Sunday), epwFile.startDayOfWeek()); + EXPECT_EQ(Date(MonthOfYear::Jan, 1), epwFile.startDate()); + EXPECT_EQ(Date(MonthOfYear::Dec, 31), epwFile.endDate()); + }catch(...){ + ASSERT_TRUE(false); + } +} + TEST(Filetypes, EpwFile_TMY) { try{ From 57301b3277382d96bb34953f1ae3229bc66d4440 Mon Sep 17 00:00:00 2001 From: "Jason W. DeGraw" Date: Mon, 25 Nov 2013 01:28:52 -0500 Subject: [PATCH 5/5] More clean up for merge --- .../src/contam/ForwardTranslator.cpp | 154 +++++++++--------- .../src/contam/ForwardTranslator.hpp | 29 +++- openstudiocore/src/contam/PrjDefines.hpp | 8 +- openstudiocore/src/contam/PrjModel.cpp | 67 ++------ openstudiocore/src/contam/PrjModel.hpp | 77 ++++----- 5 files changed, 147 insertions(+), 188 deletions(-) diff --git a/openstudiocore/src/contam/ForwardTranslator.cpp b/openstudiocore/src/contam/ForwardTranslator.cpp index d8a5e453fe7..a03c59f4a76 100644 --- a/openstudiocore/src/contam/ForwardTranslator.cpp +++ b/openstudiocore/src/contam/ForwardTranslator.cpp @@ -296,7 +296,7 @@ void ForwardTranslator::setAirtightnessLevel(std::string level) m_deltaP = boost::optional(); } -bool ForwardTranslator::applyAirtightnessLevel(contam::CxModel cxModel) +bool ForwardTranslator::applyAirtightnessLevel(contam::PrjModel prjModel) { // For this to work, the "standard" names must be in the PRJ data if(!m_leakageDescriptor) @@ -318,28 +318,28 @@ bool ForwardTranslator::applyAirtightnessLevel(contam::CxModel cxModel) } int nr; // Exterior walls - nr = cxModel.airflowElementNrByName(wallExt[index]); + nr = prjModel.airflowElementNrByName(wallExt[index]); if(!nr) { return false; } afeMap["exterior"] = nr; // Interior walls - nr = cxModel.airflowElementNrByName(wallInt[index]); + nr = prjModel.airflowElementNrByName(wallInt[index]); if(!nr) { return false; } afeMap["interior"] = nr; // Floors - nr = cxModel.airflowElementNrByName(floor[index]); + nr = prjModel.airflowElementNrByName(floor[index]); if(!nr) { return false; } afeMap["floor"] = nr; // Roof - nr = cxModel.airflowElementNrByName(roof[index]); + nr = prjModel.airflowElementNrByName(roof[index]); if(!nr) { return false; @@ -377,15 +377,15 @@ bool ForwardTranslator::setExteriorFlowRate(double flow, double n, double deltaP return false; } -bool ForwardTranslator::applyExteriorFlowRate(contam::CxModel cxModel) +bool ForwardTranslator::applyExteriorFlowRate(contam::PrjModel prjModel) { if(m_flow && m_n && m_deltaP) { std::map afeMap; - afeMap["exterior"] = addNewAirflowElement(cxModel,"CustomExterior",m_flow.get(),m_n.get(),m_deltaP.get()); - afeMap["roof"] = addNewAirflowElement(cxModel,"CustomRoof",m_flow.get(),m_n.get(),m_deltaP.get()); - afeMap["interior"] = addNewAirflowElement(cxModel,"CustomInterior",2*m_flow.get(),m_n.get(),m_deltaP.get()); - afeMap["floor"] = addNewAirflowElement(cxModel,"CustomFloor",2*m_flow.get(),m_n.get(),m_deltaP.get()); + afeMap["exterior"] = addNewAirflowElement(prjModel,"CustomExterior",m_flow.get(),m_n.get(),m_deltaP.get()); + afeMap["roof"] = addNewAirflowElement(prjModel,"CustomRoof",m_flow.get(),m_n.get(),m_deltaP.get()); + afeMap["interior"] = addNewAirflowElement(prjModel,"CustomInterior",2*m_flow.get(),m_n.get(),m_deltaP.get()); + afeMap["floor"] = addNewAirflowElement(prjModel,"CustomFloor",2*m_flow.get(),m_n.get(),m_deltaP.get()); m_afeMap = afeMap; m_leakageDescriptor = boost::optional(); return true; @@ -400,10 +400,10 @@ bool ForwardTranslator::modelToPrj(const openstudio::model::Model& model, const translator.setTranslateHVAC(translateHVAC); translator.setAirtightnessLevel(leakageDescriptor); - boost::optional cxModel = translator.translate(model); - if(cxModel) + boost::optional prjModel = translator.translate(model); + if(prjModel) { - boost::optional output = cxModel->toString(); + boost::optional output = prjModel->toString(); if (!output) { return false; @@ -429,35 +429,35 @@ bool compareElevation(openstudio::model::BuildingStory a, openstudio::model::Bui // This function is altogether too long and needs to be broken up into smaller functions. // This is particularly true for the HVAC translation. -boost::optional ForwardTranslator::translate(model::Model model) +boost::optional ForwardTranslator::translate(model::Model model) { m_logSink.setThreadId(QThread::currentThread()); m_logSink.resetStringStream(); - contam::CxModel cxModel; - cxModel.read(std::string(":/templates/template.prj")); - if(!cxModel.valid()) + contam::PrjModel prjModel; + prjModel.read(std::string(":/templates/template.prj")); + if(!prjModel.valid()) { - return boost::optional(); + return boost::optional(); } // The template is a legal PRJ file, so it has one level. Not for long. - cxModel.setLevels(std::vector()); + prjModel.setLevels(std::vector()); // Do some setup work if(m_leakageDescriptor) { - if(!applyAirtightnessLevel(cxModel)) + if(!applyAirtightnessLevel(prjModel)) { LOG(Error,"Application of airtightness level failed."); - return boost::optional(); + return boost::optional(); } } else { - if(!applyExteriorFlowRate(cxModel)) + if(!applyExteriorFlowRate(prjModel)) { LOG(Error,"Application of exterior flow rate failed."); - return boost::optional(); + return boost::optional(); } } @@ -472,7 +472,7 @@ boost::optional ForwardTranslator::translate(model::Model model if(name) modelDescr = QString("Automatically generated from \"%1\" OpenStudio model").arg(openstudio::toQString(name.get())); } - cxModel.rc().setPrjdesc(modelDescr.toStdString()); + prjModel.rc().setPrjdesc(modelDescr.toStdString()); // Set the simulation length to match the length of the E+ simulation boost::optional rp = model.runPeriod(); if(rp) @@ -496,13 +496,13 @@ boost::optional ForwardTranslator::translate(model::Model model if(goodDates) { // Turn on transient simulation - cxModel.rc().setSim_af(1); + prjModel.rc().setSim_af(1); // Set start date - cxModel.rc().setDate_0(startString); - cxModel.rc().setTime_0("00:00:00"); + prjModel.rc().setDate_0(startString); + prjModel.rc().setTime_0("00:00:00"); // Set start date - cxModel.rc().setDate_1(endString); - cxModel.rc().setTime_1("24:00:00"); + prjModel.rc().setDate_1(endString); + prjModel.rc().setTime_1("24:00:00"); } } // Get stories @@ -514,7 +514,7 @@ boost::optional ForwardTranslator::translate(model::Model model if(!elevation) { LOG(Error, "Story '" << buildingStory.name().get() << "' has no elevation, translation aborted"); - return boost::optional(); + return boost::optional(); } } // Sort the stories by elevation @@ -532,19 +532,19 @@ boost::optional ForwardTranslator::translate(model::Model model level.setNr(nr); level.setRefht(QString("%1").arg(z).toStdString()); level.setDelht(QString("%1").arg(ht).toStdString()); - cxModel.addLevel(level); + prjModel.addLevel(level); nr++; if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); } } - cxModel.rc().setWind_H(QString().sprintf("%g",totalHeight).toStdString()); + prjModel.rc().setWind_H(QString().sprintf("%g",totalHeight).toStdString()); // Check for levels - translation can't proceed without levels - if(cxModel.levels().size() == 0) + if(prjModel.levels().size() == 0) { LOG(Error, "Failed to find building stories in model, translation aborted"); - return boost::optional(); + return boost::optional(); } // Translate each thermal zone and generate a lookup table by name. std::vector thermalZones = model.getConcreteModelObjects(); @@ -611,11 +611,11 @@ boost::optional ForwardTranslator::translate(model::Model model else { LOG(Error, "Unable to set level for zone '" << thermalZone.name().get() << "', translation aborted"); - return boost::optional(); + return boost::optional(); } // set T0 zone.setT0(QString("293.15").toStdString()); - cxModel.addZone(zone); + prjModel.addZone(zone); if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); @@ -634,7 +634,7 @@ boost::optional ForwardTranslator::translate(model::Model model nr = 0; // Loop over surfaces and generate paths QList used; - double wind_H = QString().fromStdString(cxModel.rc().wind_H()).toDouble(); + double wind_H = QString().fromStdString(prjModel.rc().wind_H()).toDouble(); BOOST_FOREACH(model::Surface surface,surfaces) { contam::Path path; @@ -673,7 +673,7 @@ boost::optional ForwardTranslator::translate(model::Model model } continue; } - contam::Zone zone = cxModel.zones()[zoneNr-1]; + contam::Zone zone = prjModel.zones()[zoneNr-1]; // Get the surface area - will need to do more work here later if large openings are present double area = surface.grossArea(); std::string type = surface.surfaceType(); @@ -684,7 +684,7 @@ boost::optional ForwardTranslator::translate(model::Model model averageZ += point.z(); } // Now set the path info - path.setRelHt(QString().sprintf("%g",averageZ / numVertices - QString().fromStdString(cxModel.levels()[zone.pl()-1].refht()).toDouble()).toStdString()); + path.setRelHt(QString().sprintf("%g",averageZ / numVertices - QString().fromStdString(prjModel.levels()[zone.pl()-1].refht()).toDouble()).toStdString()); path.setPld(zone.pl()); path.setMult(QString().sprintf("%g",area).toStdString()); // Now for the type specific info @@ -710,7 +710,7 @@ boost::optional ForwardTranslator::translate(model::Model model } path.setNr(++nr); m_surfaceMap[surface.handle()] = path.nr(); - cxModel.addPath(path); + prjModel.addPath(path); } else if (bc == "Surface") { @@ -718,19 +718,19 @@ boost::optional ForwardTranslator::translate(model::Model model if(!adjacentSurface) { LOG(Error, "Unable to find adjacent surface for surface '" << surface.name().get() << "'"); - return boost::optional(); + return boost::optional(); } boost::optional adjacentSpace = adjacentSurface->space(); if(!adjacentSpace) { LOG(Error, "Unattached adjacent surface '" << adjacentSurface->name().get() << "'"); - return boost::optional(); + return boost::optional(); } boost::optional adjacentZone = adjacentSpace->thermalZone(); if(!adjacentZone) { LOG(Error, "Unattached adjacent space '" << adjacentSpace->name().get() << "'"); - return boost::optional(); + return boost::optional(); } if(adjacentZone.get() != thermalZone.get()) // I don't really like doing this { @@ -748,7 +748,7 @@ boost::optional ForwardTranslator::translate(model::Model model } path.setNr(++nr); m_surfaceMap[surface.handle()] = path.nr(); - cxModel.addPath(path); + prjModel.addPath(path); used << adjacentSurface->handle(); } } @@ -788,7 +788,7 @@ boost::optional ForwardTranslator::translate(model::Model model ahs.setName(QString("AHS_%1").arg(nr).toStdString()); // Create supply and return zones openstudio::contam::Zone rz; - rz.setNr(cxModel.zones().size()+1); + rz.setNr(prjModel.zones().size()+1); rz.setPl(1); rz.setT0(QString("293.15").toStdString()); rz.setSystem(true); @@ -807,15 +807,15 @@ boost::optional ForwardTranslator::translate(model::Model model ahs.setZone_r(rz.nr()); ahs.setZone_s(sz.nr()); // Add them to the zone list - cxModel.addZone(rz); - cxModel.addZone(sz); + prjModel.addZone(rz); + prjModel.addZone(sz); // Now hook the served zones up to the supply and return zones BOOST_FOREACH(openstudio::model::ThermalZone thermalZone, airloop.thermalZones()) { int zoneNr = tableLookup(m_zoneMap,thermalZone.handle(),"zoneMap"); // Supply path openstudio::contam::Path sp; - sp.setNr(cxModel.paths().size()+1); + sp.setNr(prjModel.paths().size()+1); sp.setPld(1); sp.setPzn(ahs.zone_s()); sp.setPzm(zoneNr); @@ -832,10 +832,10 @@ boost::optional ForwardTranslator::translate(model::Model model rp.setSystem(true); m_pathMap[(thermalZone.name().get()+" return")] = rp.nr(); // Add the paths to the path list - cxModel.addPath(sp); - cxModel.addPath(rp); + prjModel.addPath(sp); + prjModel.addPath(rp); } - cxModel.addAhs(ahs); + prjModel.addAhs(ahs); if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); @@ -846,21 +846,21 @@ boost::optional ForwardTranslator::translate(model::Model model { m_progressBar->setWindowTitle(openstudio::toString("Connecting AHS to zones")); m_progressBar->setMinimum(0); - m_progressBar->setMaximum(cxModel.ahs().size()); + m_progressBar->setMaximum(prjModel.ahs().size()); m_progressBar->setValue(0); } // Now loop back through the AHS list and connect the supply and return zones together - for(unsigned int i=0;i ForwardTranslator::translate(model::Model model oa.setNr(recirc.nr()+1); oa.setPld(1); oa.setPzn(-1); - oa.setPzm(cxModel.ahs()[i].zone_s()); + oa.setPzm(prjModel.ahs()[i].zone_s()); oa.setOutsideAir(true); m_pathMap[loopName + " oa"] = oa.nr(); // Exhaust path; openstudio::contam::Path exhaust; exhaust.setNr(oa.nr()+1); exhaust.setPld(1); - exhaust.setPzn(cxModel.ahs()[i].zone_r()); + exhaust.setPzn(prjModel.ahs()[i].zone_r()); exhaust.setPzm(-1); exhaust.setExhaust(true); m_pathMap[loopName + " exhaust"] = exhaust.nr(); // Add the paths to the path list - cxModel.addPath(recirc); - cxModel.addPath(oa); - cxModel.addPath(exhaust); + prjModel.addPath(recirc); + prjModel.addPath(oa); + prjModel.addPath(exhaust); // Store the nrs in the ahs - cxModel.ahs()[i].setPath_r(recirc.nr()); - cxModel.ahs()[i].setPath_s(oa.nr()); - cxModel.ahs()[i].setPath_x(exhaust.nr()); + prjModel.ahs()[i].setPath_r(recirc.nr()); + prjModel.ahs()[i].setPath_s(oa.nr()); + prjModel.ahs()[i].setPath_x(exhaust.nr()); if (m_progressBar) { m_progressBar->setValue(m_progressBar->value() + 1); @@ -938,9 +938,9 @@ boost::optional ForwardTranslator::translate(model::Model model CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - cxModel.addControlNode(ctrl); + prjModel.addControlNode(ctrl); // Connect to the zone - cxModel.zones()[nr-1].setPc(ctrl.nr()); + prjModel.zones()[nr-1].setPc(ctrl.nr()); } else { @@ -990,9 +990,9 @@ boost::optional ForwardTranslator::translate(model::Model model CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - cxModel.addControlNode(ctrl); + prjModel.addControlNode(ctrl); // Connect to the path - cxModel.paths()[nr-1].setPc(ctrl.nr()); + prjModel.paths()[nr-1].setPc(ctrl.nr()); if(m_ratioOverride) // This assumes that there *is* a return, which could be wrong? maybe? { // Create a new time series @@ -1011,9 +1011,9 @@ boost::optional ForwardTranslator::translate(model::Model model CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - cxModel.addControlNode(ctrl); + prjModel.addControlNode(ctrl); // Connect to the path - cxModel.paths()[nr-1].setPc(ctrl.nr()); + prjModel.paths()[nr-1].setPc(ctrl.nr()); } } } @@ -1049,9 +1049,9 @@ boost::optional ForwardTranslator::translate(model::Model model CvfDat ctrl; ctrl.setName(controlName); ctrl.setValuename(valueName); - cxModel.addControlNode(ctrl); + prjModel.addControlNode(ctrl); // Connect to the path - cxModel.paths()[nr-1].setPc(ctrl.nr()); + prjModel.paths()[nr-1].setPc(ctrl.nr()); } } } @@ -1086,19 +1086,19 @@ boost::optional ForwardTranslator::translate(model::Model model int supplyNr = m_pathMap.value(supplyName,0); if(supplyNr) { - cxModel.paths()[supplyNr-1].setFahs(QString().sprintf("%g",flowRate).toStdString()); + prjModel.paths()[supplyNr-1].setFahs(QString().sprintf("%g",flowRate).toStdString()); } int returnNr = m_pathMap.value(returnName,0); if(returnNr) { - cxModel.paths()[returnNr-1].setFahs(QString().sprintf("%g",m_returnSupplyRatio*flowRate).toStdString()); + prjModel.paths()[returnNr-1].setFahs(QString().sprintf("%g",m_returnSupplyRatio*flowRate).toStdString()); } } } } } - return boost::optional(cxModel); + return boost::optional(prjModel); // these are probably useful, will have to ask Kyle // Kyle, should these functions be const? @@ -1169,7 +1169,7 @@ static double laminarCoefficient(double Ct, double x) } -int ForwardTranslator::addNewAirflowElement(contam::CxModel cxModel,std::string name, double flow,double n,double deltaP) +int ForwardTranslator::addNewAirflowElement(contam::PrjModel prjModel,std::string name, double flow,double n,double deltaP) { // flow - volume flow rate in m^3/h // deltaP - pressure difference in Pa @@ -1194,7 +1194,7 @@ int ForwardTranslator::addNewAirflowElement(contam::CxModel cxModel,std::string // Create a 1-point test element with display units of m^3/h PlrTest1 afe(0, 0, name, " ", lam, turb, expt, dP, Flow, u_P, u_F); - cxModel.addAirflowElement(afe); + prjModel.addAirflowElement(afe); return afe.nr(); } diff --git a/openstudiocore/src/contam/ForwardTranslator.hpp b/openstudiocore/src/contam/ForwardTranslator.hpp index 91c7391a35e..e2e0b6597dc 100644 --- a/openstudiocore/src/contam/ForwardTranslator.hpp +++ b/openstudiocore/src/contam/ForwardTranslator.hpp @@ -39,6 +39,17 @@ class ProgressBar; namespace contam{ +/** CvFile is a container for data that is to be written to a CONTAM CVF. + * + * CvFile contains time series data that is to be written to a CONTAM + * Continuous Values File, which is documented here: + * + * www.bfrl.nist.gov/IAQanalysis/CONTAM/manual/Content/html/IDH_UsingControls_CVF.htm + * + * Data is input as TimeSeries that should cover the entire time period to + * be simulated. + * + */ class CONTAM_API CvFile { public: @@ -60,7 +71,15 @@ class CONTAM_API CvFile Date m_end; }; -class CONTAM_API ForwardTranslator// : public CxModel +/** ForwardTranslator translates an OpenStudio model into a CONTAM model. + * + * ForwardTranslator translates an OpenStudio energy model into a CONTAM + * airflow model using a streamlined approach. Each wall is assigned an + * overall leakage rate, and individual components are not presently + * represented. + * + */ +class CONTAM_API ForwardTranslator { public: ForwardTranslator(); @@ -69,7 +88,7 @@ class CONTAM_API ForwardTranslator// : public CxModel void clear(); // Translator - boost::optional translate(model::Model model); + boost::optional translate(model::Model model); // Static translation function static bool modelToPrj(const openstudio::model::Model& model, const openstudio::path& path, @@ -101,7 +120,7 @@ class CONTAM_API ForwardTranslator// : public CxModel boost::optional endDateTime() const; // We may need more functions like this that modify the CONTAM model - int addNewAirflowElement(contam::CxModel cxModel,std::string name,double flow,double n=0.65,double deltaP=75.0); + int addNewAirflowElement(contam::PrjModel prjModel,std::string name,double flow,double n=0.65,double deltaP=75.0); // Write control files bool writeCvFile(openstudio::path filepath); @@ -113,8 +132,8 @@ class CONTAM_API ForwardTranslator// : public CxModel std::vector errors() const; private: - bool applyExteriorFlowRate(contam::CxModel cxModel); - bool applyAirtightnessLevel(contam::CxModel cxModel); + bool applyExteriorFlowRate(contam::PrjModel prjModel); + bool applyAirtightnessLevel(contam::PrjModel prjModel); // Really need to look at these and determine if they are really needed int tableLookup(QMap map, std::string str, const char *name); diff --git a/openstudiocore/src/contam/PrjDefines.hpp b/openstudiocore/src/contam/PrjDefines.hpp index 6d4f7823539..24f4993c028 100644 --- a/openstudiocore/src/contam/PrjDefines.hpp +++ b/openstudiocore/src/contam/PrjDefines.hpp @@ -23,16 +23,10 @@ #define RX_IS_STRING #ifdef RX_IS_STRING -#ifndef STD_STRING -#define RX QString -#define RX_C(v) v -#define RX_INIT(v) QString(#v) -#else #define RX std::string #define RX_C(v) v #define RX_INIT(v) std::string(#v) #endif -#endif #define NOFILELINE @@ -174,6 +168,8 @@ #define EXP_2 253 /* FD 375 exponent 2 */ #define SUB_2 254 /* FE 376 subscript 2 */ +// The defines below were mainly for the ReverseTranslator object - so +// can be eliminated if that object doesn't ever come back. // Directional icon defines: E=1, N=2, W=4, S=8 #define BIT_E 1 #define BIT_N 2 diff --git a/openstudiocore/src/contam/PrjModel.cpp b/openstudiocore/src/contam/PrjModel.cpp index 2714acf3222..0d0b0fb493d 100644 --- a/openstudiocore/src/contam/PrjModel.cpp +++ b/openstudiocore/src/contam/PrjModel.cpp @@ -24,27 +24,27 @@ namespace openstudio { namespace contam { -CxModel::CxModel(openstudio::path path) +PrjModel::PrjModel(openstudio::path path) { read(path); } -CxModel::CxModel(std::string filename) +PrjModel::PrjModel(std::string filename) { read(filename); } -CxModel::CxModel(Reader &input) +PrjModel::PrjModel(Reader &input) { read(input); } -bool CxModel::read(openstudio::path path) +bool PrjModel::read(openstudio::path path) { return read(openstudio::toString(path)); } -bool CxModel::read(std::string filename) +bool PrjModel::read(std::string filename) { QFile fp(QString().fromStdString(filename)); @@ -59,7 +59,7 @@ bool CxModel::read(std::string filename) return d->valid; } -bool CxModel::read(Reader &input) +bool PrjModel::read(Reader &input) { d->valid = false; // Section 1: Project, Weather, Simulation, and Output Controls @@ -97,8 +97,6 @@ bool CxModel::read(Reader &input) std::string selmt = input.readSection(FILELINE); // Skip it d->unsupported["ControlSuperElements"] = selmt; // Section 12b: Control Nodes - //std::string ctrl = input.readSection(FILELINE); // Skip it - //m_unsupported["ControlNode"] = ctrl; d->controlNodes = input.readElementVector(FILELINEC "control node"); // Section 13: Simple Air Handling System (AHS) d->ahs = input.readSectionVector(FILELINEC "ahs"); @@ -118,7 +116,6 @@ bool CxModel::read(Reader &input) std::string dct = input.readSection(FILELINE); // Skip it d->unsupported["DuctSegment"] = dct; // Section 20: Source/Sinks - //m_sourceSinks = input.readSectionVector(FILELINEC QString("source/sink")); std::string css = input.readSection(FILELINE); // Skip it d->unsupported["SourceSink"] = css; // Section 21: Occupancy Schedules @@ -135,7 +132,7 @@ bool CxModel::read(Reader &input) return true; } -std::string CxModel::toString() +std::string PrjModel::toString() { std::string output; if(!d->valid) @@ -200,7 +197,7 @@ std::string CxModel::toString() return output; } -std::vector > CxModel::zoneExteriorFlowPaths() +std::vector > PrjModel::zoneExteriorFlowPaths() { std::vector > paths(d->zones.size()); @@ -226,13 +223,12 @@ std::vector > CxModel::zoneExteriorFlowPaths() return paths; } -std::vector CxModel::zoneInfiltration(SimFile *sim) +std::vector PrjModel::zoneInfiltration(SimFile *sim) { // This should probably include a lot more checks of things and is written in // somewhat strange way to avoid taking too much advantage of the specifics // of the text form outputs. std::vector results; - //std::vector > flow0 = sim->F0(); std::vector > paths = zoneExteriorFlowPaths(); unsigned int ntimes = sim->dateTimes().size(); for(unsigned int i=0; izones.size(); i++) @@ -282,37 +278,12 @@ std::vector CxModel::zoneInfiltration(SimFile *sim) } } } - /* - // Run through the times and compute the infiltration - for(unsigned int j=0; j 0) // Positive value is infiltration - { - nr -= 1; - if(flow0[nr][j] > 0) - { - inf[j] += flow0[nr][j]; - } - } - else // Negative value is infiltration - { - nr = -nr - 1; - if(flow0[nr][j] < 0) - { - inf[j] -= flow0[nr][j]; - } - } - } - }*/ results.push_back(openstudio::TimeSeries(sim->dateTimes(),inf,"kg/s")); } return results; } -void CxModel::rebuildContaminants() +void PrjModel::rebuildContaminants() { d->contaminants.clear(); for(unsigned int i=1;i<=d->species.size();i++) @@ -325,7 +296,7 @@ void CxModel::rebuildContaminants() } } -void CxModel::readZoneIc(Reader &input) +void PrjModel::readZoneIc(Reader &input) { unsigned int nn = input.readUInt(FILELINE); if(nn != 0) @@ -362,7 +333,7 @@ void CxModel::readZoneIc(Reader &input) input.read999("Failed to find zone IC section termination" CFILELINE); } -std::string CxModel::writeZoneIc(int start) +std::string PrjModel::writeZoneIc(int start) { int offset = 1; if(start != 0) @@ -386,17 +357,7 @@ std::string CxModel::writeZoneIc(int start) return string + "-999\n"; } -//template void Model::addAirflowElement(T element) -//{ -// T *copy = new T; -// *copy = element; -// copy->setNr(m_airflowElements.size()+1); -// m_airflowElements.push_back(QSharedPointer((AirflowElement*)copy)); -//} - -//template void Model::addAirflowElement(PlrTest1); - -int CxModel::airflowElementNrByName(std::string name) const +int PrjModel::airflowElementNrByName(std::string name) const { for(int i=0;iairflowElements.size();i++) { @@ -408,7 +369,7 @@ int CxModel::airflowElementNrByName(std::string name) const return 0; } -bool CxModel::setSteadyWeather(double windSpeed, double windDirection) +bool PrjModel::setSteadyWeather(double windSpeed, double windDirection) { if(windSpeed < 0) { diff --git a/openstudiocore/src/contam/PrjModel.hpp b/openstudiocore/src/contam/PrjModel.hpp index f397501e903..04f458d4405 100644 --- a/openstudiocore/src/contam/PrjModel.hpp +++ b/openstudiocore/src/contam/PrjModel.hpp @@ -36,10 +36,12 @@ namespace contam { class SimFile; -class CxModelPrivate : public QSharedData +namespace detail { + +class PrjModelPrivate : public QSharedData { public: - CxModelPrivate() + PrjModelPrivate() { valid = false; } @@ -62,16 +64,32 @@ class CxModelPrivate : public QSharedData std::vector paths; }; -class CONTAM_API CxModel +} // detail + +/** PrjModel is primarily a container for CONTAM airflow model data. + * + * PrjModel contains CONTAM airflow model elements and has several methods + * to produce the PRJ file. The PRJ file is a positional text file and is + * the primary way in which data is provided to the ContamX solver. The + * format is documented here: + * + * www.bfrl.nist.gov/IAQanalysis/CONTAM/manual/Content/html/PRJ/PRJ_PRJ_Sections.htm + * + * Note that the representation in this object is not very sophisticated. In + * particular, links between many items are based upon array indices, so + * modifications to the model should be made with care. + * + */ +class CONTAM_API PrjModel { public: - CxModel() + PrjModel() { - d = new CxModelPrivate(); + d = new detail::PrjModelPrivate(); } - explicit CxModel(openstudio::path path); - explicit CxModel(std::string filename); - explicit CxModel(Reader &input); + explicit PrjModel(openstudio::path path); + explicit PrjModel(std::string filename); + explicit PrjModel(Reader &input); bool read(openstudio::path path); bool read(std::string filename); bool read(Reader &input); @@ -159,14 +177,6 @@ class CONTAM_API CxModel return afe; } - // template void addAirflowElement(T element); - // { - // T *copy = new T; - // *copy = element; - // copy->setNr(m_airflowElements.size()+1); - // m_airflowElements.push_back(QSharedPointer((AirflowElement*)copy)); - // } - template void addAirflowElement(T element) { T *copy = new T; @@ -280,17 +290,13 @@ class CONTAM_API CxModel void readZoneIc(Reader &input); std::string writeZoneIc(int start=0); template std::string writeSectionVector(std::vector vector, std::string label=std::string(), int start=0); - // SWIG has some problems with this template for some reason. Comment out for now, delete if it doesn't - // get uncommented soon. - // template class U> std::string writeSectionVector(U > vector, - // std::string label=std::string(), int start=0); template std::string writeSectionVector(QVector > vector, std::string label=std::string(), int start=0); template std::string writeArray(std::vector vector, std::string label=std::string(), int start=0); - QExplicitlySharedDataPointer d; + QExplicitlySharedDataPointer d; }; -template std::string CxModel::writeSectionVector(std::vector vector, std::string label, int start) +template std::string PrjModel::writeSectionVector(std::vector vector, std::string label, int start) { std::string string; int number = vector.size()-start; @@ -310,30 +316,7 @@ template std::string CxModel::writeSectionVector(std::vector vector return string; } -/* -template class U> STRING Model::writeSectionVector(U > vector, -STRING label, int start) -{ -std::string string; -int number = vector.size()-start; -if(label.empty()) -{ -string += openstudio::toString(number) + '\n'; -} -else -{ -string += openstudio::toString(number) + " ! " + label + '\n'; -} -for(int i=start;iwrite(); -} -string += "-999\n"; -return string; -} -*/ - -template std::string CxModel::writeSectionVector(QVector > vector, +template std::string PrjModel::writeSectionVector(QVector > vector, std::string label, int start) { std::string string; @@ -354,7 +337,7 @@ template std::string CxModel::writeSectionVector(QVector std::string CxModel::writeArray(std::vector vector, std::string label, int start) +template std::string PrjModel::writeArray(std::vector vector, std::string label, int start) { std::string string; int number = vector.size()-start;