TEST_F(AnalysisFixture, RubyPerturbation_FreeStandingUserScript) { // construct openstudio::path scriptPath = toPath("myUserScript.rb"); RubyPerturbation perturbation(scriptPath, FileReferenceType::IDF, FileReferenceType::IDF, true); EXPECT_EQ(FileReferenceType(FileReferenceType::IDF),perturbation.inputFileType()); EXPECT_EQ(FileReferenceType(FileReferenceType::IDF),perturbation.outputFileType()); EXPECT_FALSE(perturbation.usesBCLMeasure()); EXPECT_ANY_THROW(perturbation.measure()); EXPECT_ANY_THROW(perturbation.measureDirectory()); EXPECT_ANY_THROW(perturbation.measureUUID()); EXPECT_ANY_THROW(perturbation.measureVersionUUID()); FileReference scriptReference = perturbation.perturbationScript(); EXPECT_EQ(scriptPath,scriptReference.path().filename()); EXPECT_EQ(boost::filesystem::system_complete(scriptPath),scriptReference.path()); EXPECT_EQ(FileReferenceType(FileReferenceType::RB),scriptReference.fileType()); EXPECT_TRUE(perturbation.arguments().empty()); EXPECT_TRUE(perturbation.isUserScript()); EXPECT_FALSE(perturbation.hasIncompleteArguments()); // add arguments to fill in OSArgument numBoilers = OSArgument::makeIntegerArgument("numBoilers"); OSArgument numChillers = OSArgument::makeIntegerArgument("numChillers"); StringVector choices; choices.push_back("parallel"); choices.push_back("series"); OSArgument topology = OSArgument::makeChoiceArgument("topology",choices); EXPECT_TRUE(topology.setDefaultValue("parallel")); perturbation.setArgument(numBoilers); perturbation.setArgument(numChillers); perturbation.setArgument(topology); // verify that arguments are incomplete EXPECT_EQ(3u,perturbation.arguments().size()); EXPECT_EQ(2u,perturbation.incompleteArguments().size()); EXPECT_TRUE(perturbation.hasIncompleteArguments()); // set to different script and verify that arguments cleared scriptPath = toPath("myOtherUserScript.rb"); perturbation.setPerturbationScript(scriptPath, FileReferenceType::OSM, FileReferenceType::OSM, true); EXPECT_EQ(FileReferenceType(FileReferenceType::OSM),perturbation.inputFileType()); EXPECT_EQ(FileReferenceType(FileReferenceType::OSM),perturbation.outputFileType()); scriptReference = perturbation.perturbationScript(); EXPECT_EQ(scriptPath,scriptReference.path().filename()); EXPECT_TRUE(perturbation.arguments().empty()); EXPECT_TRUE(perturbation.isUserScript()); EXPECT_FALSE(perturbation.hasIncompleteArguments()); }
virtual std::vector<OSArgument> arguments(const Model& model) const { std::vector<OSArgument> result; OSArgument arg = makeChoiceArgumentOfWorkspaceObjects( "lights_definition", IddObjectType::OS_Lights_Definition, model); result.push_back(arg); arg = OSArgument::makeDoubleArgument("multiplier",false); arg.setDefaultValue(0.8); result.push_back(arg); return result; }
TEST_F(AnalysisFixture, RubyContinuousVariable_UserScript) { RubyMeasure userScript(toPath("setGeometry.rb"), FileReferenceType::OSM, FileReferenceType::OSM, true); OSArgument arg = OSArgument::makeDoubleArgument("floorToFloorHeight"); arg.setValue(3.0); userScript.addArgument(arg); arg = OSArgument::makeIntegerArgument("numFloors"); arg.setValue(1); userScript.addArgument(arg); EXPECT_EQ(2u,userScript.arguments().size()); EXPECT_TRUE(userScript.isUserScript()); EXPECT_EQ(toString(completeAndNormalize(toPath("setGeometry.rb"))), toString(userScript.perturbationScript().path())); arg = OSArgument::makeDoubleArgument("floorArea"); RubyContinuousVariable var("Floor Area (m^2)",arg,userScript); var.setMinimum(500.0); var.setMaximum(1000.0); EXPECT_EQ(2u,var.measure().arguments().size()); EXPECT_TRUE(var.measure().isUserScript()); EXPECT_EQ(toString(completeAndNormalize(toPath("setGeometry.rb"))), toString(var.measure().perturbationScript().path())); ASSERT_TRUE(var.minimum()); EXPECT_DOUBLE_EQ(500.0,var.minimum().get()); ASSERT_TRUE(var.maximum()); EXPECT_DOUBLE_EQ(1000.0,var.maximum().get()); EXPECT_FALSE(var.increment()); EXPECT_FALSE(var.nSteps()); EXPECT_TRUE(var.isFeasible(500.0)); EXPECT_FALSE(var.isFeasible(1500.0)); ASSERT_TRUE(var.truncate(1500.0)); EXPECT_DOUBLE_EQ(1000.0,var.truncate(1500.0).get()); WeibullDistribution distribution(1.5,1.0); EXPECT_DOUBLE_EQ(1.5,distribution.alpha()); EXPECT_DOUBLE_EQ(1.0,distribution.beta()); EXPECT_FALSE(var.uncertaintyDescription()); EXPECT_TRUE(var.setUncertaintyDescription(distribution)); ASSERT_TRUE(var.uncertaintyDescription()); ASSERT_TRUE(var.uncertaintyDescription().get().optionalCast<WeibullDistribution>()); EXPECT_DOUBLE_EQ(1.5,var.uncertaintyDescription().get().cast<WeibullDistribution>().alpha()); EXPECT_DOUBLE_EQ(1.0,var.uncertaintyDescription().get().cast<WeibullDistribution>().beta()); var.resetUncertaintyDescription(); EXPECT_FALSE(var.uncertaintyDescription()); }
openstudio::analysis::Analysis AnalysisFixture::analysis2(bool simulate) { // Create problem and analysis Problem problem("My Problem"); BCLMeasure bclMeasure(resourcesPath() / toPath("utilities/BCL/Measures/v2/SetWindowToWallRatioByFacade")); RubyMeasure measure(bclMeasure); StringVector choices; choices.push_back("North"); choices.push_back("South"); choices.push_back("East"); choices.push_back("West"); OSArgument facade = OSArgument::makeChoiceArgument("facade",choices); OSArgument wwr = OSArgument::makeDoubleArgument("wwr"); // RubyContinuousVariable for South Facade measure = measure.clone().cast<RubyMeasure>(); OSArgument arg = facade.clone(); arg.setValue("South"); measure.setArgument(arg); arg = wwr.clone(); RubyContinuousVariable southWWR("South Window to Wall Ratio",arg,measure); problem.push(southWWR); // RubyContinuousVariable for North Facade measure = measure.clone().cast<RubyMeasure>(); arg = facade.clone(); arg.setValue("North"); measure.setArgument(arg); arg = wwr.clone(); RubyContinuousVariable northWWR("North Window to Wall Ratio",arg,measure); problem.push(northWWR); if (simulate) { problem.push(WorkItem(JobType::ModelToIdf)); problem.push(WorkItem(JobType::EnergyPlusPreProcess)); problem.push(WorkItem(JobType::EnergyPlus)); problem.push(WorkItem(JobType::OpenStudioPostProcess)); } Analysis analysis("My Analysis",problem,FileReferenceType::OSM); return analysis; }
void RubyContinuousVariableRecord::constructRelatedRecords(const analysis::Variable& variable) { analysis::RubyContinuousVariable rubyContinuousVariable = variable.cast<analysis::RubyContinuousVariable>(); RubyContinuousVariableRecord copyOfThis(getImpl<detail::RubyContinuousVariableRecord_Impl>()); ProjectDatabase database = projectDatabase(); bool isNew = database.isNewRecord(copyOfThis); if (!isNew) { getImpl<detail::RubyContinuousVariableRecord_Impl>()->revertToLastRecordIds(); } // Save resource RubyMeasure if (isNew || rubyContinuousVariable.perturbation().isDirty()) { RubyMeasureRecord rubyMeasureRecord(rubyContinuousVariable.measure(),database); getImpl<detail::RubyContinuousVariableRecord_Impl>()->setRubyMeasureRecordId(rubyMeasureRecord.id()); } // Save child OSArgument OSArgument argument = rubyContinuousVariable.argument(); bool saveArgument = false; if (!isNew) { { // see if old argument record should be removed OSArgumentRecord oldArgumentRecord = osArgumentRecord(); if (oldArgumentRecord.handle() != argument.uuid()) { database.removeRecord(oldArgumentRecord); saveArgument = true; } else if (oldArgumentRecord.uuidLast() != argument.versionUUID()) { saveArgument = true; } } database.unloadUnusedCleanRecords(); } if (saveArgument || isNew) { OSArgumentRecord osArgumentRecord(argument,copyOfThis); } }
QVariant toVariant(const OSArgument& argument) { QVariantMap argumentData; argumentData["uuid"] = toQString(removeBraces(argument.uuid())); argumentData["version_uuid"] = toQString(removeBraces(argument.versionUUID())); argumentData["name"] = toQString(argument.name()); if (!argument.displayName().empty()) { argumentData["display_name"] = toQString(argument.displayName()); } if (argument.description() && !argument.description()->empty()) { argumentData["description"] = toQString(argument.description().get()); } OSArgumentType type = argument.type(); if (argument.units() && !argument.units()->empty()) { argumentData["units"] = toQString(argument.units().get()); } argumentData["type"] = toQString(type.valueName()); argumentData["required"] = argument.required(); argumentData["model_dependent"] = argument.modelDependent(); if (argument.hasValue()) { if (type == OSArgumentType::Quantity) { Quantity value = argument.valueAsQuantity(); argumentData["value"] = value.value(); argumentData["value_units"] = toQString(value.units().standardString()); } else { // use QVariant directly argumentData["value"] = argument.valueAsQVariant(); } } if (argument.hasDefaultValue()) { if (type == OSArgumentType::Quantity) { Quantity defaultValue = argument.defaultValueAsQuantity(); argumentData["default_value"] = defaultValue.value(); argumentData["default_value_units"] = toQString(defaultValue.units().standardString()); } else { // use QVariant directly argumentData["default_value"] = argument.defaultValueAsQVariant(); } } argumentData["domain_type"] = toQString(argument.domainType().valueName()); if (argument.hasDomain()) { QVariantList domainList; int index(0); for (const QVariant& dval : argument.domainAsQVariant()) { QVariantMap domainValueMap; domainValueMap["domain_value_index"] = index; if (type == OSArgumentType::Quantity) { Quantity q = dval.value<openstudio::Quantity>(); domainValueMap["value"] = q.value(); domainValueMap["units"] = toQString(q.units().standardString()); } else { domainValueMap["value"] = dval; } domainList.push_back(domainValueMap); ++index; } argumentData["domain"] = domainList; } if (type == OSArgumentType::Choice) { QVariantList choicesList; StringVector displayNames = argument.choiceValueDisplayNames(); int index(0), displayNamesN(displayNames.size()); for (const std::string& choice : argument.choiceValues()) { QVariantMap choiceMap; choiceMap["choice_index"] = index; choiceMap["value"] = toQString(choice); if (index < displayNamesN) { choiceMap["display_name"] = toQString(displayNames[index]); } choicesList.push_back(choiceMap); ++index; } argumentData["choices"] = QVariant(choicesList); } if (type == OSArgumentType::Path) { argumentData["is_read"] = argument.isRead(); argumentData["extension"] = toQString(argument.extension()); } return QVariant(argumentData); }
TEST_F(ProjectFixture, RubyMeasureRecord_BCLMeasure) { // Construct problem with RubyMeasure that points to BCLMeasure Problem problem("Problem",VariableVector(),runmanager::Workflow()); MeasureGroup dvar("Variable",MeasureVector()); problem.push(dvar); openstudio::path measuresPath = resourcesPath() / toPath("/utilities/BCL/Measures"); openstudio::path dir = measuresPath / toPath("SetWindowToWallRatioByFacade"); BCLMeasure measure = BCLMeasure::load(dir).get(); RubyMeasure rpert(measure); dvar.push(rpert); OSArgument arg = OSArgument::makeDoubleArgument("wwr"); arg.setValue(0.4); rpert.setArgument(arg); arg = OSArgument::makeIntegerArgument("typo_arg"); arg.setDefaultValue(1); rpert.setArgument(arg); // Serialize to database { ProjectDatabase database = getCleanDatabase("RubyMeasureRecord_BCLMeasure"); bool didStartTransaction = database.startTransaction(); EXPECT_TRUE(didStartTransaction); // Problem Record ProblemRecord problemRecord = ProblemRecord::factoryFromProblem(problem,database); database.save(); if (didStartTransaction) { EXPECT_TRUE(database.commitTransaction()); } } // Re-open database, de-serialize, verify that RubyMeasure is intact. openstudio::path tempDir1 = measuresPath / toPath(toString(createUUID())); { ProjectDatabase database = getExistingDatabase("RubyMeasureRecord_BCLMeasure"); ASSERT_EQ(1u,ProblemRecord::getProblemRecords(database).size()); ASSERT_EQ(1u,MeasureGroupRecord::getMeasureGroupRecords(database).size()); EXPECT_EQ(1u,RubyMeasureRecord::getRubyMeasureRecords(database).size()); MeasureRecordVector dprs = MeasureGroupRecord::getMeasureGroupRecords(database)[0].measureRecords(false); ASSERT_EQ(1u,dprs.size()); ASSERT_TRUE(dprs[0].optionalCast<RubyMeasureRecord>()); RubyMeasureRecord rpr = dprs[0].cast<RubyMeasureRecord>(); RubyMeasure rp = rpr.rubyMeasure(); EXPECT_TRUE(rp.usesBCLMeasure()); EXPECT_TRUE(rp.measure()); EXPECT_EQ(dir,rp.measureDirectory()); EXPECT_EQ(measure.uuid(),rp.measureUUID()); EXPECT_EQ(measure.versionUUID(),rp.measureVersionUUID()); EXPECT_ANY_THROW(rp.perturbationScript()); EXPECT_EQ(2u,rp.arguments().size()); EXPECT_FALSE(rp.hasIncompleteArguments()); // Update measure and save BCLMeasure newVersion = measure.clone(tempDir1).get(); newVersion.setDescription("Window to wall ratio with sill height configurable."); newVersion.save(); EXPECT_NE(measure.versionUUID(),newVersion.versionUUID()); OSArgumentVector args; args.push_back(OSArgument::makeDoubleArgument("wwr")); args.push_back(OSArgument::makeDoubleArgument("sillHeight")); Problem problemCopy = ProblemRecord::getProblemRecords(database)[0].problem(); problemCopy.updateMeasure(newVersion,args,false); bool didStartTransaction = database.startTransaction(); EXPECT_TRUE(didStartTransaction); // Problem Record ProblemRecord problemRecord = ProblemRecord::factoryFromProblem(problemCopy,database); database.save(); if (didStartTransaction) { EXPECT_TRUE(database.commitTransaction()); } } // Re-open database, check that old argument records are gone, check that de-serialized object ok openstudio::path tempDir2 = measuresPath / toPath(toString(createUUID())); { ProjectDatabase database = getExistingDatabase("RubyMeasureRecord_BCLMeasure"); ASSERT_EQ(1u,ProblemRecord::getProblemRecords(database).size()); EXPECT_EQ(1u,MeasureGroupRecord::getMeasureGroupRecords(database).size()); EXPECT_EQ(1u,RubyMeasureRecord::getRubyMeasureRecords(database).size()); EXPECT_EQ(1u,FileReferenceRecord::getFileReferenceRecords(database).size()); EXPECT_EQ(2u,OSArgumentRecord::getOSArgumentRecords(database).size()); Problem problemCopy = ProblemRecord::getProblemRecords(database)[0].problem(); InputVariableVector vars = problemCopy.variables(); ASSERT_FALSE(vars.empty()); ASSERT_TRUE(vars[0].optionalCast<MeasureGroup>()); MeasureVector dps = vars[0].cast<MeasureGroup>().measures(false); ASSERT_FALSE(dps.empty()); ASSERT_TRUE(dps[0].optionalCast<RubyMeasure>()); RubyMeasure rp = dps[0].cast<RubyMeasure>(); EXPECT_TRUE(rp.usesBCLMeasure()); EXPECT_TRUE(rp.measure()); EXPECT_EQ(tempDir1,rp.measureDirectory()); EXPECT_EQ(measure.uuid(),rp.measureUUID()); EXPECT_NE(measure.versionUUID(),rp.measureVersionUUID()); EXPECT_ANY_THROW(rp.perturbationScript()); ASSERT_EQ(2u,rp.arguments().size()); EXPECT_TRUE(rp.hasIncompleteArguments()); EXPECT_EQ("wwr",rp.arguments()[0].name()); ASSERT_EQ(1u,rp.incompleteArguments().size()); EXPECT_EQ("sillHeight",rp.incompleteArguments()[0].name()); // Set to different measure BCLMeasure measure2 = measure.clone(tempDir2).get(); measure2.changeUID(); measure2.incrementVersionId(); measure2.save(); measure2 = BCLMeasure::load(tempDir2).get(); EXPECT_NE(measure.uuid(),measure2.uuid()); EXPECT_NE(measure.versionUUID(),measure2.versionUUID()); rp.setMeasure(measure2); EXPECT_TRUE(rp.isDirty()); EXPECT_TRUE(problemCopy.isDirty()); bool didStartTransaction = database.startTransaction(); EXPECT_TRUE(didStartTransaction); // Problem Record ProblemRecord problemRecord = ProblemRecord::factoryFromProblem(problemCopy,database); database.save(); if (didStartTransaction) { EXPECT_TRUE(database.commitTransaction()); } } // Re-open database, check that old measure and all argument records are gone { ProjectDatabase database = getExistingDatabase("RubyMeasureRecord_BCLMeasure"); ASSERT_EQ(1u,ProblemRecord::getProblemRecords(database).size()); EXPECT_EQ(1u,MeasureGroupRecord::getMeasureGroupRecords(database).size()); EXPECT_EQ(1u,RubyMeasureRecord::getRubyMeasureRecords(database).size()); EXPECT_EQ(1u,FileReferenceRecord::getFileReferenceRecords(database).size()); EXPECT_EQ(0u,OSArgumentRecord::getOSArgumentRecords(database).size()); Problem problemCopy = ProblemRecord::getProblemRecords(database)[0].problem(); InputVariableVector vars = problemCopy.variables(); ASSERT_FALSE(vars.empty()); ASSERT_TRUE(vars[0].optionalCast<MeasureGroup>()); MeasureVector dps = vars[0].cast<MeasureGroup>().measures(false); ASSERT_FALSE(dps.empty()); ASSERT_TRUE(dps[0].optionalCast<RubyMeasure>()); RubyMeasure rp = dps[0].cast<RubyMeasure>(); EXPECT_TRUE(rp.usesBCLMeasure()); EXPECT_TRUE(rp.measure()); EXPECT_EQ(tempDir2,rp.measureDirectory()); EXPECT_NE(measure.uuid(),rp.measureUUID()); EXPECT_NE(measure.versionUUID(),rp.measureVersionUUID()); EXPECT_ANY_THROW(rp.perturbationScript()); ASSERT_EQ(0u,rp.arguments().size()); EXPECT_FALSE(rp.hasIncompleteArguments()); } boost::filesystem::remove_all(tempDir1); boost::filesystem::remove_all(tempDir2); }
TEST_F(AnalysisDriverFixture,SimpleProject_UpdateMeasure) { // create a new project SimpleProject project = getCleanSimpleProject("SimpleProject_UpdateMeasure"); Problem problem = project.analysis().problem(); // insert a measure into the project, extract and register its arguments openstudio::path measuresDir = resourcesPath() / toPath("/utilities/BCL/Measures"); openstudio::path dir = measuresDir / toPath("SetWindowToWallRatioByFacade"); BCLMeasure measure = BCLMeasure::load(dir).get(); BCLMeasure projectMeasure = project.insertMeasure(measure); OSArgumentVector args = argumentGetter->getArguments(projectMeasure, project.seedModel(), project.seedIdf()); project.registerArguments(projectMeasure,args); EXPECT_EQ(1u,project.measures().size()); // use the measure to create a new variable/ruby measure MeasureGroup dv("New Measure Group",MeasureVector()); EXPECT_TRUE(problem.push(dv)); RubyMeasure rp(projectMeasure); rp.setArguments(args); EXPECT_TRUE(dv.push(rp)); EXPECT_EQ(args.size(),rp.arguments().size()); EXPECT_TRUE(rp.hasIncompleteArguments()); BOOST_FOREACH(const OSArgument& arg,args) { if (arg.name() == "wwr") { OSArgument temp = arg.clone(); temp.setValue(0.6); rp.setArgument(temp); } if (arg.name() == "sillHeight") { OSArgument temp = arg.clone(); temp.setValue(1.0); rp.setArgument(temp); } if (arg.name() == "facade") { OSArgument temp = arg.clone(); temp.setValue("South"); rp.setArgument(temp); } } EXPECT_FALSE(rp.hasIncompleteArguments()); openstudio::path tempDir = measuresDir / toPath(toString(createUUID())); { // create fake new version of the measure BCLMeasure newVersion = measure.clone(tempDir).get(); newVersion.incrementVersionId(); newVersion.save(); OSArgumentVector newArgs = args; newArgs.push_back(OSArgument::makeDoubleArgument("frame_width")); // update the measure project.updateMeasure(newVersion,newArgs); // verify the final state of SimpleProject and RubyMeasure EXPECT_EQ(1u,project.measures().size()); BCLMeasure retrievedMeasure = project.getMeasureByUUID(measure.uuid()).get(); EXPECT_NE(measure.versionUUID(),retrievedMeasure.versionUUID()); EXPECT_EQ(newVersion.versionUUID(),retrievedMeasure.versionUUID()); ASSERT_TRUE(project.hasStoredArguments(retrievedMeasure)); OSArgumentVector retrievedArgs = project.getStoredArguments(retrievedMeasure); EXPECT_EQ(args.size() + 1u,retrievedArgs.size()); EXPECT_EQ(retrievedArgs.size(),rp.arguments().size()); EXPECT_TRUE(rp.hasIncompleteArguments()); } boost::filesystem::remove_all(tempDir); }
openstudio::analysis::Analysis AnalysisFixture::analysis1(AnalysisState state) { // Create problem and analysis Problem problem("My Problem"); BCLMeasure bclMeasure(resourcesPath() / toPath("utilities/BCL/Measures/SetWindowToWallRatioByFacade")); RubyMeasure measure(bclMeasure); // Measure Group StringVector choices; choices.push_back("North"); choices.push_back("South"); choices.push_back("East"); choices.push_back("West"); OSArgument facade = OSArgument::makeChoiceArgument("facade",choices); OSArgument arg = facade.clone(); arg.setValue("South"); measure.setArgument(arg); OSArgument wwr = OSArgument::makeDoubleArgument("wwr"); MeasureVector measures(1u,NullMeasure()); measures.push_back(measure.clone().cast<Measure>()); arg = wwr.clone(); arg.setValue(0.1); measures.back().cast<RubyMeasure>().setArgument(arg); measures.push_back(measure.clone().cast<Measure>()); arg = wwr.clone(); arg.setValue(0.2); measures.back().cast<RubyMeasure>().setArgument(arg); measures.push_back(measure.clone().cast<Measure>()); arg = wwr.clone(); arg.setValue(0.3); measures.back().cast<RubyMeasure>().setArgument(arg); problem.push(MeasureGroup("South Windows",measures)); // Continuous Variables Attached to Arguments arg = facade.clone(); arg.setValue("North"); measure.setArgument(arg); arg = wwr.clone(); RubyContinuousVariable wwrCV("Window to Wall Ratio",arg,measure); wwrCV.setMinimum(0.0); wwrCV.setMaximum(1.0); TriangularDistribution td(0.2,0.0,0.5); wwrCV.setUncertaintyDescription(td); problem.push(wwrCV); OSArgument offset = OSArgument::makeDoubleArgument("offset"); RubyContinuousVariable offsetCV("Offset",offset,measure); offsetCV.setMinimum(0.0); offsetCV.setMaximum(1.5); NormalDistribution nd(0.9,0.05); offsetCV.setUncertaintyDescription(nd); problem.push(offsetCV); // Simulation problem.push(WorkItem(JobType::ModelToIdf)); problem.push(WorkItem(JobType::EnergyPlusPreProcess)); problem.push(WorkItem(JobType::EnergyPlus)); problem.push(WorkItem(JobType::OpenStudioPostProcess)); // Responses LinearFunction response1("Energy Use Intensity", VariableVector(1u,OutputAttributeVariable("EUI","site.eui"))); problem.pushResponse(response1); VariableVector vars; vars.push_back(OutputAttributeVariable("Heating Energy","heating.energy.gas")); vars.push_back(OutputAttributeVariable("Cooling Energy","cooling.energy.elec")); DoubleVector coeffs; coeffs.push_back(1.0); // approx. source factor coeffs.push_back(2.5); // approx. source factor LinearFunction response2("Approximate Source Energy",vars,coeffs); problem.pushResponse(response2); LinearFunction response3("North WWR",VariableVector(1u,wwrCV)); // input variable as output problem.pushResponse(response3); Analysis analysis("My Analysis",problem,FileReferenceType::OSM); if (state == PreRun) { // Add three DataPoints std::vector<QVariant> values; values.push_back(0); values.push_back(0.2); values.push_back(0.9); OptionalDataPoint dataPoint = problem.createDataPoint(values); analysis.addDataPoint(*dataPoint); values[0] = 1; values[1] = 0.21851789; values[2] = 1.1681938; dataPoint = problem.createDataPoint(values); analysis.addDataPoint(*dataPoint); values[0] = 2; values[1] = 0.0; values[2] = 0.581563892; dataPoint = problem.createDataPoint(values); analysis.addDataPoint(*dataPoint); } else { // state == PostRun // Add one complete DataPoint std::vector<QVariant> values; values.push_back(1); values.push_back(0.3); values.push_back(0.9); DoubleVector responseValues; responseValues.push_back(58.281967); responseValues.push_back(718952.281); responseValues.push_back(0.3); TagVector tags; tags.push_back(Tag("custom")); tags.push_back(Tag("faked")); // attributes AttributeVector attributes; attributes.push_back(Attribute("electricity.Cooling",281.281567,"kWh")); attributes.push_back(Attribute("electricity.Lighting",19206.291876,"kWh")); attributes.push_back(Attribute("electricity.Equipment",5112.125718,"kWh")); attributes = AttributeVector(1u,Attribute("enduses.electric",attributes)); attributes.push_back(Attribute("eui",createQuantity(128.21689,"kBtu/ft^2").get())); // complete job // 1. get vector of work items std::vector<WorkItem> workItems; // 0 workItems.push_back(problem.variables()[0].cast<MeasureGroup>().createWorkItem(QVariant(1), toPath(rubyOpenStudioDir()))); RubyContinuousVariable rcv = problem.variables()[1].cast<RubyContinuousVariable>(); RubyMeasure rm = rcv.measure(); OSArgument arg = rcv.argument().clone(); arg.setValue(values[1].toDouble()); rm.setArgument(arg); rcv = problem.variables()[2].cast<RubyContinuousVariable>(); arg = rcv.argument().clone(); arg.setValue(values[2].toDouble()); rm.setArgument(arg); // 1 workItems.push_back(rm.createWorkItem(toPath(rubyOpenStudioDir()))); // 2 workItems.push_back(WorkItem(JobType::ModelToIdf)); // 3 workItems.push_back(WorkItem(JobType::EnergyPlusPreProcess)); // 4 workItems.push_back(WorkItem(JobType::EnergyPlus)); // 5 workItems.push_back(WorkItem(JobType::OpenStudioPostProcess)); // 2. step through work items and create jobs with results WorkItem wi = workItems[5]; std::vector<FileInfo> inFiles = wi.files.files(); inFiles.push_back(FileInfo("eplusout.sql", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,33,32)), "", toPath("myProject/fakeDataPoint/75-OpenStudioPostProcess-0/eplusout.sql"))); Files inFilesObject(inFiles); std::vector<std::pair<ErrorType, std::string> > errors; errors.push_back(std::make_pair(ErrorType::Info,"Post-process completed successfully.")); JobErrors errorsObject(OSResultValue::Success,errors); std::vector<FileInfo> outFiles; outFiles.push_back(FileInfo("report.xml", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,34,21)), "", toPath("myProject/fakeDataPoint/75-OpenStudioPostProcess-0/report.xml"))); Files outFilesObject(outFiles); Job job = JobFactory::createJob( wi.type, wi.tools, wi.params, inFilesObject, std::vector<openstudio::URLSearchPath>(), false, createUUID(), JobState( DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,34,21)), errorsObject, outFilesObject, AdvancedStatus(), openstudio::path()) ); // OpenStudioPostProcess Job jobLast = job; wi = workItems[4]; inFiles = wi.files.files(); inFiles.push_back(FileInfo("in.idf", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,23,05)), "", toPath("myProject/fakeDataPoint/74-EnergyPlus-0/in.idf"))); inFilesObject = Files(inFiles); errors.clear(); errors.push_back(std::make_pair(ErrorType::Warning,"ENERGYPLUS WARNING: ...")); errors.push_back(std::make_pair(ErrorType::Warning,"ENERGYPLUS WARNING: ...")); errors.push_back(std::make_pair(ErrorType::Warning,"ENERGYPLUS WARNING: ...")); errorsObject = JobErrors(OSResultValue::Success,errors); outFiles.clear(); outFiles.push_back(FileInfo("eplusout.sql", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,33,32)), "", toPath("myProject/fakeDataPoint/74-EnergyPlus-0/eplusout.sql"))); outFiles.push_back(FileInfo("eplusout.err", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,33,34)), "", toPath("myProject/fakeDataPoint/74-EnergyPlus-0/eplusout.err"))); outFilesObject = Files(outFiles); job = JobFactory::createJob( wi.type, wi.tools, wi.params, inFilesObject, std::vector<openstudio::URLSearchPath>(), false, createUUID(), JobState( DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,33,42)), errorsObject, outFilesObject, AdvancedStatus(), openstudio::path()) ); // EnergyPlus job.addChild(jobLast); jobLast = job; wi = workItems[3]; inFiles = wi.files.files(); inFiles.push_back(FileInfo("in.idf", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,22,30)), "", toPath("myProject/fakeDataPoint/73-EnergyPlusPreProcess-0/in.idf"))); inFilesObject = Files(inFiles); errors.clear(); errorsObject = JobErrors(OSResultValue::Success,errors); outFiles.clear(); outFiles.push_back(FileInfo("out.idf", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,23,05)), "", toPath("myProject/fakeDataPoint/73-EnergyPlusPreProcess-0/out.idf"))); outFilesObject = Files(outFiles); job = JobFactory::createJob( wi.type, wi.tools, wi.params, inFilesObject, std::vector<openstudio::URLSearchPath>(), false, createUUID(), JobState( DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,23,12)), errorsObject, outFilesObject, AdvancedStatus(), openstudio::path()) ); // EnergyPlusPreProcess job.addChild(jobLast); jobLast = job; wi = workItems[2]; inFiles = wi.files.files(); inFiles.push_back(FileInfo("in.osm", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,22,01)), "", toPath("myProject/fakeDataPoint/72-ModelToIdf-0/in.osm"))); inFilesObject = Files(inFiles); errors.clear(); errors.push_back(std::make_pair(ErrorType::Info,"Did not find ScheduleTypeLimits for Schedule ...")); errors.push_back(std::make_pair(ErrorType::Warning,"Unexpectedly did not find a child object of a certain type, replaced with a default one.")); errorsObject = JobErrors(OSResultValue::Success,errors); outFiles.clear(); outFiles.push_back(FileInfo("out.idf", DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,22,30)), "", toPath("myProject/fakeDataPoint/72-ModelToIdf-0/out.idf"))); outFilesObject = Files(outFiles); job = JobFactory::createJob( wi.type, wi.tools, wi.params, inFilesObject, std::vector<openstudio::URLSearchPath>(), false, createUUID(), JobState( DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,22,32)), errorsObject, outFilesObject, AdvancedStatus(), openstudio::path()) ); // ModelToIdf job.addChild(jobLast); jobLast = job; wi = workItems[1]; errors.clear(); errors.push_back(std::make_pair(ErrorType::InitialCondition,"Started with a window to wall ratio of ...")); errors.push_back(std::make_pair(ErrorType::FinalCondition,"Set the window to wall ratio ...")); errorsObject = JobErrors(OSResultValue::Success,errors); outFiles.clear(); outFilesObject = Files(outFiles); wi.params.append("outdir","myProject/fakeDataPoint/"); job = JobFactory::createJob( wi.type, wi.tools, wi.params, wi.files, std::vector<openstudio::URLSearchPath>(), false, createUUID(), JobState( DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,21,52)), errorsObject, outFilesObject, AdvancedStatus(), openstudio::path()) ); // Variables 2 & 3 job.addChild(jobLast); jobLast = job; wi = workItems[0]; errors.clear(); errors.push_back(std::make_pair(ErrorType::InitialCondition,"Started with a window to wall ratio of ...")); errors.push_back(std::make_pair(ErrorType::FinalCondition,"Set the window to wall ratio ...")); errorsObject = JobErrors(OSResultValue::Success,errors); outFiles.clear(); outFilesObject = Files(outFiles); // add outdir job param JobParams params = wi.params; params.append("outdir","myProject/fakeDataPoint"); job = JobFactory::createJob( wi.type, wi.tools, params, wi.files, std::vector<openstudio::URLSearchPath>(), false, createUUID(), JobState( DateTime(Date(MonthOfYear::Mar,21,2018),Time(0,8,21,10)), errorsObject, outFilesObject, AdvancedStatus(), openstudio::path()) ); // Variable 1 job.addChild(jobLast); DataPoint dataPoint(createUUID(), createUUID(), "fakeDataPoint", "Fake Data Point", "Demonstrating json serialization of complete DataPoint.", problem, true, false, true, DataPointRunType::Local, values, responseValues, toPath("myProject/fakeDataPoint/"), FileReference(toPath("myProject/fakeDataPoint/71-Ruby-0/out.osm")), FileReference(toPath("myProject/fakeDataPoint/72-ModelToIdf-0/out.idf")), FileReference(toPath("myProject/fakeDataPoint/74-EnergyPlus-0/eplusout.sql")), FileReferenceVector(1u,FileReference(toPath("myProject/fakeDataPoint/75-OpenStudioPostProcess-0/report.xml"))), job, std::vector<openstudio::path>(), tags, attributes); EXPECT_TRUE(analysis.addDataPoint(dataPoint)); } return analysis; }
TEST_F(AnalysisFixture, Problem_UpdateMeasure_MeasureGroups) { // open up example measure openstudio::path measuresPath = resourcesPath() / toPath("/utilities/BCL/Measures/v2"); openstudio::path dir = measuresPath / toPath("SetWindowToWallRatioByFacade"); ASSERT_TRUE(BCLMeasure::load(dir)); BCLMeasure measure1 = BCLMeasure::load(dir).get(); openstudio::path tempDir1 = measuresPath / toPath(toString(createUUID())); openstudio::path tempDir2 = measuresPath / toPath(toString(createUUID())); { // create multiple BCLMeasures BCLMeasure measure1_1 = measure1.clone(tempDir1).get(); measure1_1.setDescription("Window to wall ratio by wwr and offset."); measure1_1.save(); EXPECT_TRUE(measure1_1.uuid() == measure1.uuid()); EXPECT_FALSE(measure1_1.versionUUID() == measure1.versionUUID()); BCLMeasure measure2 = measure1.clone(tempDir2).get(); measure2.changeUID(); measure2.incrementVersionId(); measure2.save(); EXPECT_FALSE(measure2.uuid() == measure1.uuid()); EXPECT_FALSE(measure2.versionUUID() == measure1.versionUUID()); // create args for those measures OSArgumentVector args1, args1_1, args2; args1.push_back(OSArgument::makeDoubleArgument("wwr")); args1.push_back(OSArgument::makeDoubleArgument("sillHeight")); args1_1.push_back(OSArgument::makeDoubleArgument("wwr")); args1_1.push_back(OSArgument::makeDoubleArgument("offset")); args1_1.push_back(OSArgument::makeDoubleArgument("vt")); args2.push_back(OSArgument::makeIntegerArgument("numPeople")); // create a problem that uses multiple BCLMeasures Problem problem("Problem",VariableVector(),runmanager::Workflow()); MeasureGroup dv("South WWR",MeasureVector(1u,NullMeasure())); problem.push(dv); RubyMeasure rp(measure1); rp.setArguments(args1); dv.push(rp); dv.push(rp.clone().cast<RubyMeasure>()); ASSERT_EQ(3u,dv.numMeasures(false)); rp = dv.measures(false)[2].cast<RubyMeasure>(); EXPECT_EQ(2u,rp.arguments().size()); EXPECT_TRUE(rp.hasIncompleteArguments()); dv = MeasureGroup("Occupancy",MeasureVector(1u,NullMeasure())); problem.push(dv); rp = RubyMeasure(measure2); rp.setArguments(args2); dv.push(rp); OSArgument arg = args2[0].clone(); arg.setValue(100); rp.setArgument(arg); EXPECT_EQ(1u,rp.arguments().size()); EXPECT_FALSE(rp.hasIncompleteArguments()); dv = MeasureGroup("North WWR",MeasureVector(1u,NullMeasure())); problem.push(dv); rp = RubyMeasure(measure1); rp.setArguments(args1); arg = args1[0].clone(); arg.setValue(0.32); rp.setArgument(arg); arg = args1[1].clone(); arg.setValue(1.0); rp.setArgument(arg); EXPECT_EQ(2u,rp.arguments().size()); EXPECT_FALSE(rp.hasIncompleteArguments()); dv.push(rp); EXPECT_EQ(2u,dv.numMeasures(false)); // call update problem.clearDirtyFlag(); problem.updateMeasure(measure1_1,args1_1,false); // check state VariableVector vars = castVector<Variable>(problem.variables()); ASSERT_EQ(3u,vars.size()); EXPECT_TRUE(vars[0].isDirty()); EXPECT_FALSE(vars[1].isDirty()); EXPECT_TRUE(vars[2].isDirty()); dv = vars[0].cast<MeasureGroup>(); ASSERT_EQ(3u,dv.numMeasures(false)); MeasureVector ps = dv.measures(false); EXPECT_FALSE(ps[0].isDirty()); EXPECT_TRUE(ps[1].isDirty()); rp = ps[1].cast<RubyMeasure>(); EXPECT_EQ(3u,rp.arguments().size()); EXPECT_EQ(3u,rp.incompleteArguments().size()); EXPECT_TRUE(ps[2].isDirty()); rp = ps[2].cast<RubyMeasure>(); EXPECT_EQ(3u,rp.arguments().size()); EXPECT_EQ(3u,rp.incompleteArguments().size()); dv = vars[2].cast<MeasureGroup>(); ASSERT_EQ(2u,dv.numMeasures(false)); ps = dv.measures(false); EXPECT_FALSE(ps[0].isDirty()); EXPECT_TRUE(ps[1].isDirty()); rp = ps[1].cast<RubyMeasure>(); EXPECT_EQ(3u,rp.arguments().size()); EXPECT_EQ(2u,rp.incompleteArguments().size()); } boost::filesystem::remove_all(tempDir1); boost::filesystem::remove_all(tempDir2); }
TEST_F(RulesetFixture, OSArgument_Clone) { std::vector<std::string> choices; choices.push_back("On"); choices.push_back("Off"); OSArgument boolArgument = OSArgument::makeBoolArgument("bool"); OSArgument doubleArgument = OSArgument::makeDoubleArgument("double"); OSArgument integerArgument = OSArgument::makeIntegerArgument("integer"); OSArgument stringArgument = OSArgument::makeStringArgument("string"); OSArgument choiceArgument = OSArgument::makeChoiceArgument("choice", choices); EXPECT_FALSE(boolArgument.hasValue()); EXPECT_FALSE(doubleArgument.hasValue()); EXPECT_FALSE(integerArgument.hasValue()); EXPECT_FALSE(stringArgument.hasValue()); EXPECT_FALSE(choiceArgument.hasValue()); EXPECT_TRUE(boolArgument.setValue(true)); EXPECT_TRUE(doubleArgument.setValue(1.0)); EXPECT_TRUE(doubleArgument.setValue((int)1)); // can also set double arg using int EXPECT_TRUE(integerArgument.setValue((int)1)); EXPECT_TRUE(stringArgument.setValue(std::string("value"))); EXPECT_TRUE(choiceArgument.setValue(std::string("On"))); ASSERT_TRUE(boolArgument.hasValue()); ASSERT_TRUE(doubleArgument.hasValue()); ASSERT_TRUE(integerArgument.hasValue()); ASSERT_TRUE(stringArgument.hasValue()); ASSERT_TRUE(choiceArgument.hasValue()); EXPECT_EQ(true, boolArgument.valueAsBool()); EXPECT_EQ(1.0, doubleArgument.valueAsDouble()); EXPECT_EQ(1, integerArgument.valueAsInteger()); EXPECT_EQ("value", stringArgument.valueAsString()); EXPECT_EQ("On", choiceArgument.valueAsString()); OSArgument boolArgument2 = boolArgument.clone(); OSArgument doubleArgument2 = doubleArgument.clone(); OSArgument integerArgument2 = integerArgument.clone(); OSArgument stringArgument2 = stringArgument.clone(); OSArgument choiceArgument2 = choiceArgument.clone(); ASSERT_TRUE(boolArgument2.hasValue()); ASSERT_TRUE(doubleArgument2.hasValue()); ASSERT_TRUE(integerArgument2.hasValue()); ASSERT_TRUE(stringArgument2.hasValue()); ASSERT_TRUE(choiceArgument2.hasValue()); EXPECT_EQ(true, boolArgument2.valueAsBool()); EXPECT_EQ(1.0, doubleArgument2.valueAsDouble()); EXPECT_EQ(1, integerArgument2.valueAsInteger()); EXPECT_EQ("value", stringArgument2.valueAsString()); EXPECT_EQ("On", choiceArgument2.valueAsString()); std::vector<OSArgument> argumentVector; argumentVector.push_back(boolArgument); argumentVector.push_back(doubleArgument); argumentVector.push_back(integerArgument); argumentVector.push_back(stringArgument); argumentVector.push_back(choiceArgument); std::map<std::string,OSArgument> argumentMap = convertOSArgumentVectorToMap(argumentVector); ASSERT_FALSE(argumentMap.find("bool") == argumentMap.end()); ASSERT_FALSE(argumentMap.find("double") == argumentMap.end()); ASSERT_FALSE(argumentMap.find("integer") == argumentMap.end()); ASSERT_FALSE(argumentMap.find("string") == argumentMap.end()); ASSERT_FALSE(argumentMap.find("choice") == argumentMap.end()); ASSERT_TRUE(argumentMap.find("bool")->second.hasValue()); ASSERT_TRUE(argumentMap.find("double")->second.hasValue()); ASSERT_TRUE(argumentMap.find("integer")->second.hasValue()); ASSERT_TRUE(argumentMap.find("string")->second.hasValue()); ASSERT_TRUE(argumentMap.find("choice")->second.hasValue()); EXPECT_EQ(true, argumentMap.find("bool")->second.valueAsBool()); EXPECT_EQ(1.0, argumentMap.find("double")->second.valueAsDouble()); EXPECT_EQ(1, argumentMap.find("integer")->second.valueAsInteger()); EXPECT_EQ("value", argumentMap.find("string")->second.valueAsString()); EXPECT_EQ("On", argumentMap.find("choice")->second.valueAsString()); }
TEST_F(RulesetFixture, OSArgument_Domain) { OSArgument doubleArg = OSArgument::makeDoubleArgument("double", true); OSArgument integerArg = OSArgument::makeIntegerArgument("integer", true); OSArgument stringArg = OSArgument::makeStringArgument("string", true); EXPECT_FALSE(doubleArg.hasDomain()); EXPECT_FALSE(integerArg.hasDomain()); EXPECT_FALSE(stringArg.hasDomain()); double d = 0.0; int i = 0; EXPECT_TRUE(doubleArg.setMinValue(d)); EXPECT_TRUE(integerArg.setMinValue(i)); EXPECT_FALSE(stringArg.setMinValue(0.0)); ASSERT_TRUE(doubleArg.hasDomain()); ASSERT_TRUE(integerArg.hasDomain()); EXPECT_FALSE(stringArg.hasDomain()); EXPECT_EQ(0.0, doubleArg.domainAsDouble()[0]); EXPECT_EQ(std::numeric_limits<double>::max(), doubleArg.domainAsDouble()[1]); EXPECT_EQ(0, integerArg.domainAsInteger()[0]); EXPECT_EQ(std::numeric_limits<int>::max(), integerArg.domainAsDouble()[1]); d = 1.0; i = 1; EXPECT_TRUE(doubleArg.setMaxValue(i)); EXPECT_TRUE(integerArg.setMaxValue(d)); EXPECT_FALSE(stringArg.setMaxValue(1)); ASSERT_TRUE(doubleArg.hasDomain()); ASSERT_TRUE(integerArg.hasDomain()); EXPECT_FALSE(stringArg.hasDomain()); EXPECT_EQ(0.0, doubleArg.domainAsDouble()[0]); EXPECT_EQ(1.0, doubleArg.domainAsDouble()[1]); EXPECT_EQ(0, integerArg.domainAsInteger()[0]); EXPECT_EQ(1, integerArg.domainAsDouble()[1]); // the domain is not currently used to validate these values EXPECT_TRUE(doubleArg.setValue(-1.0)); EXPECT_TRUE(doubleArg.setValue(0.0)); EXPECT_TRUE(doubleArg.setValue(0.5)); EXPECT_TRUE(doubleArg.setValue(1.0)); EXPECT_TRUE(doubleArg.setValue(2.0)); EXPECT_TRUE(integerArg.setValue(-1)); EXPECT_TRUE(integerArg.setValue(0)); EXPECT_TRUE(integerArg.setValue(1)); EXPECT_TRUE(integerArg.setValue(2)); }
TEST_F(RulesetFixture, OSArgument_ClearValue) { std::vector<std::string> choices; choices.push_back("On"); choices.push_back("Off"); OSArgument boolArgument = OSArgument::makeBoolArgument("bool"); OSArgument doubleArgument = OSArgument::makeDoubleArgument("double"); OSArgument integerArgument = OSArgument::makeIntegerArgument("integer"); OSArgument stringArgument = OSArgument::makeStringArgument("string"); OSArgument choiceArgument = OSArgument::makeChoiceArgument("choice", choices); EXPECT_TRUE(boolArgument.setValue(true)); EXPECT_TRUE(doubleArgument.setValue(1.0)); EXPECT_TRUE(doubleArgument.setValue((int)1)); // can also set double arg using int EXPECT_TRUE(integerArgument.setValue((int)1)); EXPECT_TRUE(stringArgument.setValue(std::string("value"))); EXPECT_TRUE(choiceArgument.setValue(std::string("On"))); ASSERT_TRUE(boolArgument.hasValue()); ASSERT_TRUE(doubleArgument.hasValue()); ASSERT_TRUE(integerArgument.hasValue()); ASSERT_TRUE(stringArgument.hasValue()); ASSERT_TRUE(choiceArgument.hasValue()); boolArgument.clearValue(); doubleArgument.clearValue(); integerArgument.clearValue(); stringArgument.clearValue(); choiceArgument.clearValue(); EXPECT_FALSE(boolArgument.hasValue()); EXPECT_FALSE(doubleArgument.hasValue()); EXPECT_FALSE(integerArgument.hasValue()); EXPECT_FALSE(stringArgument.hasValue()); EXPECT_FALSE(choiceArgument.hasValue()); EXPECT_ANY_THROW(boolArgument.valueAsBool()); EXPECT_ANY_THROW(doubleArgument.valueAsDouble()); EXPECT_ANY_THROW(integerArgument.valueAsInteger()); EXPECT_ANY_THROW(stringArgument.valueAsString()); EXPECT_ANY_THROW(choiceArgument.valueAsString()); }
TEST_F(AnalysisFixture, RubyPerturbation_BCLMeasure) { // construct openstudio::path measuresPath = resourcesPath() / toPath("/utilities/BCL/Measures"); openstudio::path dir = measuresPath / toPath("SetWindowToWallRatioByFacade"); BCLMeasure measure = BCLMeasure::load(dir).get(); RubyPerturbation perturbation(measure); EXPECT_TRUE(perturbation.usesBCLMeasure()); ASSERT_TRUE(perturbation.measure()); EXPECT_TRUE(perturbation.measure().get() == measure); EXPECT_EQ(dir,perturbation.measureDirectory()); EXPECT_TRUE(measure.uuid() == perturbation.measureUUID()); EXPECT_TRUE(measure.versionUUID() == perturbation.measureVersionUUID()); EXPECT_ANY_THROW(perturbation.perturbationScript()); // isUserScript value is ignored in this case EXPECT_TRUE(perturbation.arguments().empty()); EXPECT_FALSE(perturbation.hasIncompleteArguments()); // add arguments to fill in OSArgumentVector args; args.push_back(OSArgument::makeDoubleArgument("wwr")); args.push_back(OSArgument::makeDoubleArgument("sillHeight")); perturbation.setArguments(args); // verify that arguments are incomplete EXPECT_EQ(2u,perturbation.incompleteArguments().size()); // fill in argument values OSArgument arg = OSArgument::makeDoubleArgument("wwr"); EXPECT_TRUE(arg.setValue(0.8)); perturbation.setArgument(arg); EXPECT_EQ(2u,perturbation.arguments().size()); EXPECT_EQ(1u,perturbation.incompleteArguments().size()); EXPECT_TRUE(perturbation.hasIncompleteArguments()); arg = OSArgument::makeDoubleArgument("sillHeight"); arg.setValue("0.1"); perturbation.setArgument(arg); EXPECT_EQ(2u,perturbation.arguments().size()); EXPECT_EQ(0u,perturbation.incompleteArguments().size()); EXPECT_FALSE(perturbation.hasIncompleteArguments()); // update measure openstudio::path tempDir = measuresPath / toPath(toString(createUUID())); { BCLMeasure newVersion = measure.clone(tempDir).get(); newVersion.setDescription("Window to wall ratio by wwr and offset."); newVersion.save(); EXPECT_TRUE(newVersion.uuid() == measure.uuid()); EXPECT_FALSE(newVersion.versionUUID() == measure.versionUUID()); args.pop_back(); args.push_back(OSArgument::makeDoubleArgument("offset")); perturbation.updateMeasure(newVersion,args); EXPECT_TRUE(perturbation.usesBCLMeasure()); ASSERT_TRUE(perturbation.measure()); EXPECT_TRUE(perturbation.measure().get() == newVersion); EXPECT_EQ(tempDir,perturbation.measureDirectory()); EXPECT_TRUE(newVersion.uuid() == perturbation.measureUUID()); EXPECT_TRUE(newVersion.versionUUID() == perturbation.measureVersionUUID()); EXPECT_ANY_THROW(perturbation.perturbationScript()); // verify that arguments updated correctly, values retained EXPECT_EQ(2u,perturbation.arguments().size()); ASSERT_EQ(1u,perturbation.incompleteArguments().size()); EXPECT_TRUE(perturbation.hasIncompleteArguments()); EXPECT_EQ("offset",perturbation.incompleteArguments()[0].name()); EXPECT_EQ("wwr",perturbation.arguments()[0].name()); EXPECT_EQ(0.8,perturbation.arguments()[0].valueAsDouble()); // set measure and verify that arguments cleared perturbation.setMeasure(newVersion); // always goes through setting motions, even if same EXPECT_TRUE(perturbation.usesBCLMeasure()); ASSERT_TRUE(perturbation.measure()); EXPECT_TRUE(perturbation.measure().get() == newVersion); EXPECT_EQ(tempDir,perturbation.measureDirectory()); EXPECT_TRUE(newVersion.uuid() == perturbation.measureUUID()); EXPECT_TRUE(newVersion.versionUUID() == perturbation.measureVersionUUID()); EXPECT_ANY_THROW(perturbation.perturbationScript()); // isUserScript value is ignored in this case EXPECT_TRUE(perturbation.arguments().empty()); EXPECT_FALSE(perturbation.hasIncompleteArguments()); } boost::filesystem::remove_all(tempDir); }
TEST_F(RulesetFixture, UserScript_TestModelUserScript2) { TestModelUserScript2 script; EXPECT_EQ("TestModelUserScript2", script.name()); Model model; // serialize ossrs openstudio::path fileDir = toPath("./OSResultOSSRs"); boost::filesystem::create_directory(fileDir); // call with no arguments TestOSRunner runner; std::map<std::string, OSArgument> user_arguments; bool ok = script.run(model,runner,user_arguments); EXPECT_FALSE(ok); OSResult result = runner.result(); EXPECT_TRUE(result.value() == OSResultValue::Fail); EXPECT_EQ(2u,result.errors().size()); // missing required and defaulted arguments EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_FALSE(result.initialCondition()); EXPECT_FALSE(result.finalCondition()); EXPECT_TRUE(result.attributes().empty()); result.save(fileDir / toPath("TestModelUserScript2_1.ossr"),true); // call with required argument, but no lights definitions in model LightsDefinition lightsDef(model); OSArgumentVector definitions = script.arguments(model); user_arguments = runner.getUserInput(definitions); OSArgument arg = definitions[0]; arg.setValue(toString(lightsDef.handle())); user_arguments["lights_definition"] = arg; lightsDef.remove(); EXPECT_EQ(0u,model.numObjects()); ok = script.run(model,runner,user_arguments); EXPECT_FALSE(ok); result = runner.result(); EXPECT_TRUE(result.value() == OSResultValue::Fail); EXPECT_EQ(1u,result.errors().size()); // object not in model EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_FALSE(result.initialCondition()); EXPECT_FALSE(result.finalCondition()); EXPECT_EQ(2u,result.attributes().size()); // registers argument values result.save(fileDir / toPath("TestModelUserScript2_2.ossr"),true); // save attributes json for inspection saveJSON(result.attributes(),fileDir / toPath("TestModelUserScript2_2.json"),true); // call properly using default multiplier, but lights definition not Watts/Area lightsDef = LightsDefinition(model); lightsDef.setLightingLevel(700.0); definitions = script.arguments(model); user_arguments = runner.getUserInput(definitions); arg = definitions[0]; arg.setValue(toString(lightsDef.handle())); user_arguments["lights_definition"] = arg; ok = script.run(model,runner,user_arguments); EXPECT_TRUE(ok); result = runner.result(); EXPECT_TRUE(result.value() == OSResultValue::NA); EXPECT_EQ(0u,result.errors().size()); EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(1u,result.info().size()); // Measure not applicable as called EXPECT_FALSE(result.initialCondition()); EXPECT_FALSE(result.finalCondition()); EXPECT_EQ(3u,result.attributes().size()); // Registers lights definition name, then fails result.save(fileDir / toPath("TestModelUserScript2_3.ossr"),true); // save attributes json for inspection saveJSON(result.attributes(),fileDir / toPath("TestModelUserScript2_3.json"),true); // call properly using default multiplier lightsDef.setWattsperSpaceFloorArea(10.0); ok = script.run(model,runner,user_arguments); EXPECT_TRUE(ok); result = runner.result(); EXPECT_TRUE(result.value() == OSResultValue::Success); EXPECT_EQ(0u,result.errors().size()); EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_TRUE(result.initialCondition()); // describes original state EXPECT_TRUE(result.finalCondition()); // describes changes EXPECT_EQ(8u,result.attributes().size()); result.save(fileDir / toPath("TestModelUserScript2_4.ossr"),true); EXPECT_DOUBLE_EQ(8.0,lightsDef.wattsperSpaceFloorArea().get()); // save attributes json for inspection saveJSON(result.attributes(),fileDir / toPath("TestModelUserScript2_4.json"),true); // call properly using different multiplier arg = definitions[1]; arg.setValue(0.5); user_arguments["multiplier"] = arg; ok = script.run(model,runner,user_arguments); EXPECT_TRUE(ok); result = runner.result(); EXPECT_TRUE(result.value() == OSResultValue::Success); EXPECT_EQ(0u,result.errors().size()); EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_TRUE(result.initialCondition()); // describes original state EXPECT_TRUE(result.finalCondition()); // describes changes EXPECT_EQ(8u,result.attributes().size()); result.save(fileDir / toPath("TestModelUserScript2_5.ossr"),true); EXPECT_DOUBLE_EQ(4.0,lightsDef.wattsperSpaceFloorArea().get()); // save attributes json for inspection saveJSON(result.attributes(),fileDir / toPath("TestModelUserScript2_5.json"),true); // check that can load ossrs OptionalOSResult temp = OSResult::load(fileDir / toPath("TestModelUserScript2_1.ossr")); ASSERT_TRUE(temp); result = temp.get(); EXPECT_TRUE(result.value() == OSResultValue::Fail); EXPECT_EQ(2u,result.errors().size()); // missing required argument EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_FALSE(result.initialCondition()); EXPECT_FALSE(result.finalCondition()); temp = OSResult::load(fileDir / toPath("TestModelUserScript2_2.ossr")); ASSERT_TRUE(temp); result = temp.get(); EXPECT_TRUE(result.value() == OSResultValue::Fail); EXPECT_EQ(1u,result.errors().size()); // object not in model EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_FALSE(result.initialCondition()); EXPECT_FALSE(result.finalCondition()); temp = OSResult::load(fileDir / toPath("TestModelUserScript2_3.ossr")); ASSERT_TRUE(temp); result = temp.get(); EXPECT_TRUE(result.value() == OSResultValue::NA); EXPECT_EQ(0u,result.errors().size()); EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(1u,result.info().size()); // Measure not applicable as called EXPECT_FALSE(result.initialCondition()); EXPECT_FALSE(result.finalCondition()); temp = OSResult::load(fileDir / toPath("TestModelUserScript2_4.ossr")); ASSERT_TRUE(temp); result = temp.get(); EXPECT_TRUE(result.value() == OSResultValue::Success); EXPECT_EQ(0u,result.errors().size()); EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_TRUE(result.initialCondition()); // describes original state EXPECT_TRUE(result.finalCondition()); // describes changes temp = OSResult::load(fileDir / toPath("TestModelUserScript2_5.ossr")); ASSERT_TRUE(temp); result = temp.get(); EXPECT_TRUE(result.value() == OSResultValue::Success); EXPECT_EQ(0u,result.errors().size()); EXPECT_EQ(0u,result.warnings().size()); EXPECT_EQ(0u,result.info().size()); EXPECT_TRUE(result.initialCondition()); // describes original state EXPECT_TRUE(result.finalCondition()); // describes changes // check that can load attribute jsons std::vector<Attribute> loadedAttributes; NameFinder<Attribute> lightsDefinitionFinder("lights_definition",true); NameFinder<Attribute> multiplierFinder("multiplier",true); NameFinder<Attribute> lightsDefinitionNameFinder("lights_definition_name",true); NameFinder<Attribute> lpdInFinder("lpd_in",true); NameFinder<Attribute> lpdOutFinder("lpd_out",true); NameFinder<Attribute> lightsDefinitionNumInstancesFinder("lights_definition_num_instances",true); NameFinder<Attribute> lightsDefinitionFloorAreaFinder("lights_definition_floor_area",true); NameFinder<Attribute> lightsDefinitionFloorAreaIPFinder("lights_definition_floor_area_ip",true); AttributeVector::const_iterator it; // lights definition not in model - load attributes loadedAttributes = toVectorOfAttribute(fileDir / toPath("TestModelUserScript2_2.json")); EXPECT_EQ(2u,loadedAttributes.size()); // lights_definition it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::String); EXPECT_FALSE(it->valueAsString().empty()); // multiplier it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),multiplierFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(0.8,it->valueAsDouble()); EXPECT_FALSE(it->units()); // run with bad lights definition type - load attributes loadedAttributes = toVectorOfAttribute(fileDir / toPath("TestModelUserScript2_3.json")); EXPECT_EQ(3u,loadedAttributes.size()); // lights_definition it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::String); EXPECT_FALSE(it->valueAsString().empty()); // multiplier it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),multiplierFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(0.8,it->valueAsDouble()); EXPECT_FALSE(it->units()); // lights_definition_name it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionNameFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::String); EXPECT_FALSE(it->valueAsString().empty()); // good run, default multiplier loadedAttributes = toVectorOfAttribute(fileDir / toPath("TestModelUserScript2_4.json")); EXPECT_EQ(8u,loadedAttributes.size()); // lights_definition it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::String); EXPECT_FALSE(it->valueAsString().empty()); // multiplier it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),multiplierFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(0.8,it->valueAsDouble()); EXPECT_FALSE(it->units()); // lights_definition_name it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionNameFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::String); EXPECT_FALSE(it->valueAsString().empty()); // lpd_in it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lpdInFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(10.0,it->valueAsDouble()); ASSERT_TRUE(it->units()); EXPECT_EQ("W/m^2",it->units().get()); // -- unit conversion example -- OptionalDouble ipValue = convert(it->valueAsDouble(),it->units().get(),"W/ft^2"); ASSERT_TRUE(ipValue); EXPECT_DOUBLE_EQ(0.9290304,*ipValue); // lpd_out it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lpdOutFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(8.0,it->valueAsDouble()); ASSERT_TRUE(it->units()); EXPECT_EQ("W/m^2",it->units().get()); // lights_definition_num_instances it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionNumInstancesFinder); ASSERT_FALSE(it == loadedAttributes.end()); //EXPECT_TRUE(it->valueType() == AttributeValueType::Integer); // JSON does not distinguish between int and float EXPECT_TRUE(it->valueType() == AttributeValueType::Double); // lights_definition_floor_area it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFloorAreaFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); ASSERT_TRUE(it->units()); EXPECT_EQ("m^2",it->units().get()); // lights_definition_floor_area_ip it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFloorAreaIPFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); ASSERT_TRUE(it->units()); EXPECT_EQ("ft^2",it->units().get()); // good run, different multiplier loadedAttributes = toVectorOfAttribute(fileDir / toPath("TestModelUserScript2_5.json")); EXPECT_EQ(8u,loadedAttributes.size()); // lights_definition it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::String); EXPECT_FALSE(it->valueAsString().empty()); // multiplier it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),multiplierFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(0.5,it->valueAsDouble()); EXPECT_FALSE(it->units()); // lights_definition_name it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionNameFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::String); EXPECT_FALSE(it->valueAsString().empty()); // lpd_in it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lpdInFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(8.0,it->valueAsDouble()); // uses previous example _out as _in ASSERT_TRUE(it->units()); EXPECT_EQ("W/m^2",it->units().get()); // -- unit conversion example -- ipValue = convert(it->valueAsDouble(),it->units().get(),"W/ft^2"); ASSERT_TRUE(ipValue); EXPECT_DOUBLE_EQ(0.74322432,*ipValue); // lpd_out it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lpdOutFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); EXPECT_DOUBLE_EQ(4.0,it->valueAsDouble()); ASSERT_TRUE(it->units()); EXPECT_EQ("W/m^2",it->units().get()); // lights_definition_num_instances it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionNumInstancesFinder); ASSERT_FALSE(it == loadedAttributes.end()); //EXPECT_TRUE(it->valueType() == AttributeValueType::Integer); // JSON does not distinguish between int and float EXPECT_TRUE(it->valueType() == AttributeValueType::Double); // lights_definition_floor_area it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFloorAreaFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); ASSERT_TRUE(it->units()); EXPECT_EQ("m^2",it->units().get()); // lights_definition_floor_area_ip it = std::find_if(loadedAttributes.begin(),loadedAttributes.end(),lightsDefinitionFloorAreaIPFinder); ASSERT_FALSE(it == loadedAttributes.end()); EXPECT_TRUE(it->valueType() == AttributeValueType::Double); ASSERT_TRUE(it->units()); EXPECT_EQ("ft^2",it->units().get()); }