bool MeasureGroup_Impl::insert(int index, const Measure& measure) { if ((index < 0) || (index > int(numMeasures(false)))) { return false; } if (index == int(numMeasures(false))) { return push(measure); } // position does not matter for compatibility checking MeasureVector candidates = measures(false); candidates.push_back(measure); if (!measuresAreCompatible(candidates)) { return false; } auto it = m_measures.begin(); for (int count = 0; count < index; ++count, ++it); it = m_measures.insert(it,measure); for (int i = index, n = int(m_measures.size()); i < n; ++i) { m_measures[i].onChange(); } connectChild(m_measures[index],true); onChange(AnalysisObject_Impl::InvalidatesDataPoints); return true; }
TEST_F(AnalysisFixture, MeasureGroup_DeselectMeasures) { MeasureVector measures; // null, ruby, ruby measures.push_back(NullMeasure()); openstudio::path rubyScriptPath = toPath(rubyLibDir()) / toPath("openstudio/runmanager/rubyscripts/PerturbObject.rb"); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::OSM)); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::OSM)); MeasureGroup variable("Variable",measures); EXPECT_EQ(3u,variable.numMeasures(true)); EXPECT_EQ(3u,variable.numMeasures(false)); measures[1].setIsSelected(false); EXPECT_EQ(2u,variable.numMeasures(true)); ASSERT_EQ(2u,variable.measures(true).size()); EXPECT_TRUE(variable.measures(true)[1] == measures[2]); EXPECT_EQ(3u,variable.numMeasures(false)); measures[0].setIsSelected(false); measures[2].setIsSelected(false); EXPECT_EQ(0u,variable.numMeasures(true)); EXPECT_EQ(3u,variable.numMeasures(false)); }
bool MeasureGroup_Impl::push(const Measure& measure) { MeasureVector candidates = measures(false); candidates.push_back(measure); if (!measuresAreCompatible(candidates)) { return false; } m_measures.push_back(measure); m_measures.back().onChange(); connectChild(m_measures.back(),true); onChange(AnalysisObject_Impl::Benign); return true; }
std::vector<Measure> MeasureGroup_Impl::measures( bool selectedMeasuresOnly) const { if (selectedMeasuresOnly) { MeasureVector result; for (const Measure& measure : m_measures) { if (measure.isSelected()) { result.push_back(measure); } } return result; } return m_measures; }
bool MeasureGroup_Impl::fileTypesAreCompatible( const Measure& childMeasure, const FileReferenceType& proposedInputFileType, const FileReferenceType& proposedOutputFileType) const { // can only change file types if no null measures if (proposedInputFileType != proposedOutputFileType) { NullMeasureVector nullMeasures = subsetCastVector<NullMeasure>(m_measures); if (!nullMeasures.empty()) { return false; } } // check proposals against file types of other measures MeasureVector pv = measures(false); auto it = std::find(pv.begin(),pv.end(),childMeasure); OS_ASSERT(it != pv.end()); pv.erase(it); std::pair<bool,OptionalFileReferenceType> inputFileTypeResult = detail::inputFileType(pv); OS_ASSERT(inputFileTypeResult.first); if (inputFileTypeResult.second && (proposedInputFileType != *(inputFileTypeResult.second))) { return false; } std::pair<bool,OptionalFileReferenceType> outputFileTypeResult = detail::outputFileType(pv); if (outputFileTypeResult.second && (proposedOutputFileType != *(outputFileTypeResult.second))) { return false; } // either proposals match current file types, or at least one current file type is null. // if matches current, should be a-okay. // otherwise, proposing a new file type on input or output side for this variable, so // ask problem if ok. if (OptionalAnalysisObject parent = this->parent()) { if (!inputFileTypeResult.second || !outputFileTypeResult.second) { if (!(parent->cast<WorkflowStep>().fileTypesAreCompatible(proposedInputFileType, proposedOutputFileType))) { return false; } } } return true; }
TEST_F(AnalysisFixture, MeasureGroup_Constructors) { MeasureVector measures; // At most one null measure is allowed. measures.push_back(NullMeasure()); measures.push_back(NullMeasure()); measures.push_back(NullMeasure()); measures.push_back(NullMeasure()); MeasureGroup variable("Variable",measures); EXPECT_EQ(1u,variable.numMeasures(false)); // deserialization constructor UUID uuid = createUUID(); UUID versionUUID = createUUID(); measures = variable.measures(false); variable = MeasureGroup(uuid,versionUUID,"Variable","","",boost::none,measures); EXPECT_EQ("Variable",variable.name()); EXPECT_TRUE(variable.uuid() == uuid); EXPECT_TRUE(variable.versionUUID() == versionUUID); EXPECT_TRUE(variable.measures(false) == measures); // Inconsistent file types in measures (should throw) measures.clear(); openstudio::path rubyScriptPath = toPath(rubyLibDir()) / toPath("openstudio/runmanager/rubyscripts/PerturbObject.rb"); measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::IDF)); EXPECT_THROW(MeasureGroup("Variable 2",measures),std::exception); // Inconsistent file types in measures (should throw) measures.clear(); measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::IDF, FileReferenceType::IDF)); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::OSM)); EXPECT_THROW(MeasureGroup("Variable",measures),std::exception); }
TEST_F(ProjectFixture, RubyMeasureRecord_RubyScript) { // Measures MeasureVector measures; // Null Measure measures.push_back(NullMeasure()); openstudio::path rubyLibDirPath = openstudio::toPath(rubyLibDir()); openstudio::path perturbScript = rubyLibDirPath/openstudio::toPath("openstudio/runmanager/rubyscripts/PerturbObject.rb"); RubyMeasure rubyMeasure(perturbScript, FileReferenceType::OSM, FileReferenceType::OSM); rubyMeasure.addArgument("inputPath", "in.osm"); rubyMeasure.addArgument("outputPath", "out.osm"); rubyMeasure.addArgument("objectType", "OS:Material"); rubyMeasure.addArgument("nameRegex", "I02 50mm insulation board"); rubyMeasure.addArgument("field", "3"); rubyMeasure.addArgument("value", "0.10"); // RubyMeasure measures.push_back(rubyMeasure); // Variables VariableVector variables; variables.push_back(MeasureGroup("Wall Construction",measures)); // Workflow openstudio::runmanager::Workflow workflow; // Problem Problem problem("Variable",variables,workflow); // Save to database { ProjectDatabase database = getCleanDatabase("RubyMeasureRecord_RubyScript"); bool didStartTransaction = database.startTransaction(); EXPECT_TRUE(didStartTransaction); // Problem Record ProblemRecord problemRecord = ProblemRecord::factoryFromProblem(problem,database); database.save(); if (didStartTransaction) { EXPECT_TRUE(database.commitTransaction()); } // Variable Records InputVariableRecordVector measureGroupRecords = problemRecord.inputVariableRecords(); EXPECT_EQ(1u,measureGroupRecords.size()); // Discrete Variable Record MeasureGroupRecord measureGroupRecord = measureGroupRecords.at(0).cast<MeasureGroupRecord>(); EXPECT_EQ(2u,measureGroupRecord.measureRecordIds(true).size()); EXPECT_EQ(2u,measureGroupRecord.measureRecords(true).size()); RubyMeasureRecord rubyMeasureRecord(rubyMeasure,measureGroupRecord,0); EXPECT_EQ("MeasureRecords",rubyMeasureRecord.databaseTableName()); ObjectRecordVector objectRecordVector = rubyMeasureRecord.children(); EXPECT_EQ(6u,objectRecordVector.size()); // arguments objectRecordVector = rubyMeasureRecord.resources(); EXPECT_EQ(1u,objectRecordVector.size()); // script FileReferenceRecord scriptRecord = rubyMeasureRecord.fileReferenceRecord(); EXPECT_EQ("FileReferenceRecords",scriptRecord.databaseTableName()); Measure measure = rubyMeasureRecord.measure(); EXPECT_EQ(true,measure.isSelected()); ASSERT_TRUE(measure.optionalCast<RubyMeasure>()); RubyMeasure rubyMeasureCopy = measure.cast<RubyMeasure>(); EXPECT_FALSE(rubyMeasureCopy.usesBCLMeasure()); EXPECT_FALSE(rubyMeasureCopy.isUserScript()); EXPECT_EQ(6u,rubyMeasureCopy.arguments().size()); MeasureGroupRecord measureGroupRecordFromRuby = rubyMeasureRecord.measureGroupRecord().get(); EXPECT_EQ(measureGroupRecord.databaseTableName(),measureGroupRecordFromRuby.databaseTableName()); EXPECT_EQ(measureGroupRecord.id(),measureGroupRecordFromRuby.id()); } // Reopen database { ProjectDatabase database = getExistingDatabase("RubyMeasureRecord_RubyScript"); ProblemRecordVector problemRecords = ProblemRecord::getProblemRecords(database); ASSERT_FALSE(problemRecords.empty()); EXPECT_EQ(1u,problemRecords.size()); ProblemRecord problemRecord = problemRecords[0]; // COPY-PASTED FROM ABOVE // Variable Records InputVariableRecordVector measureGroupRecords = problemRecord.inputVariableRecords(); EXPECT_EQ(1u,measureGroupRecords.size()); // Discrete Variable Record MeasureGroupRecord measureGroupRecord = measureGroupRecords.at(0).cast<MeasureGroupRecord>(); EXPECT_EQ(2u,measureGroupRecord.measureRecordIds(true).size()); EXPECT_EQ(2u,measureGroupRecord.measureRecords(true).size()); RubyMeasureRecord rubyMeasureRecord(rubyMeasure,measureGroupRecord,0); EXPECT_EQ("MeasureRecords",rubyMeasureRecord.databaseTableName()); ObjectRecordVector objectRecordVector = rubyMeasureRecord.children(); EXPECT_EQ(6u,objectRecordVector.size()); // arguments objectRecordVector = rubyMeasureRecord.resources(); EXPECT_EQ(1u,objectRecordVector.size()); // script FileReferenceRecord scriptRecord = rubyMeasureRecord.fileReferenceRecord(); EXPECT_EQ("FileReferenceRecords",scriptRecord.databaseTableName()); Measure measure = rubyMeasureRecord.measure(); EXPECT_EQ(true,measure.isSelected()); ASSERT_TRUE(measure.optionalCast<RubyMeasure>()); RubyMeasure rubyMeasureCopy = measure.cast<RubyMeasure>(); EXPECT_FALSE(rubyMeasureCopy.usesBCLMeasure()); EXPECT_FALSE(rubyMeasureCopy.isUserScript()); EXPECT_EQ(6u,rubyMeasureCopy.arguments().size()); MeasureGroupRecord measureGroupRecordFromRuby = rubyMeasureRecord.measureGroupRecord().get(); EXPECT_EQ(measureGroupRecord.databaseTableName(),measureGroupRecordFromRuby.databaseTableName()); EXPECT_EQ(measureGroupRecord.id(),measureGroupRecordFromRuby.id()); } }
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(AnalysisFixture,DDACEAlgorithm_CompatibleProblemType) { // continuous problem with five variables VariableVector variables; BCLMeasure bclMeasure(resourcesPath() / toPath("utilities/BCL/Measures/v2/SetWindowToWallRatioByFacade")); RubyMeasure measure(bclMeasure); variables.push_back(RubyContinuousVariable("Var 1",OSArgument::makeDoubleArgument("wwr1"),measure)); variables.push_back(RubyContinuousVariable("Var 2",OSArgument::makeDoubleArgument("wwr2"),measure)); variables.push_back(RubyContinuousVariable("Var 3",OSArgument::makeDoubleArgument("wwr3"),measure)); variables.push_back(RubyContinuousVariable("Var 4",OSArgument::makeDoubleArgument("wwr4"),measure)); variables.push_back(RubyContinuousVariable("Var 5",OSArgument::makeDoubleArgument("wwr5"),measure)); Problem cProblem("Continuous Problem",variables,runmanager::Workflow()); EXPECT_EQ(5,cProblem.numVariables()); EXPECT_EQ(5,cProblem.numContinuousVariables()); variables.clear(); // mixed problem with three variables, ignorable discrete variable MeasureVector measures; variables.push_back(RubyContinuousVariable("Var 1",OSArgument::makeDoubleArgument("wwr1"),measure)); measures.push_back(RubyMeasure(toPath("script.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); variables.push_back(MeasureGroup("Var 2",measures)); measures.clear(); variables.push_back(RubyContinuousVariable("Var 3",OSArgument::makeDoubleArgument("wwr3"),measure)); Problem mProblem("Mixed Problem",variables,runmanager::Workflow()); EXPECT_EQ(3,mProblem.numVariables()); EXPECT_EQ(2,mProblem.numContinuousVariables()); EXPECT_EQ(1,mProblem.numDiscreteVariables()); EXPECT_EQ(1,mProblem.numStaticTransformations()); variables.clear(); // discrete problem measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(toPath("script1.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); measures.back().cast<RubyMeasure>().addArgument("wwr","0.2"); measures.push_back(RubyMeasure(toPath("script1.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); measures.back().cast<RubyMeasure>().addArgument("wwr","0.4"); variables.push_back(MeasureGroup("Var 1",measures)); measures.clear(); measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(toPath("script2.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); measures.back().cast<RubyMeasure>().addArgument("cop","3.0"); measures.back().cast<RubyMeasure>().addArgument("fan_eff","0.3"); measures.push_back(RubyMeasure(toPath("script2.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); measures.back().cast<RubyMeasure>().addArgument("cop","3.5"); measures.back().cast<RubyMeasure>().addArgument("fan_eff","0.3"); measures.push_back(RubyMeasure(toPath("script2.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); measures.back().cast<RubyMeasure>().addArgument("cop","3.0"); measures.back().cast<RubyMeasure>().addArgument("fan_eff","0.5"); measures.push_back(RubyMeasure(toPath("script2.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); measures.back().cast<RubyMeasure>().addArgument("cop","3.5"); measures.back().cast<RubyMeasure>().addArgument("fan_eff","0.5"); variables.push_back(MeasureGroup("Var 2",measures)); measures.clear(); Problem dProblem("Discrete Problem",variables,runmanager::Workflow()); EXPECT_EQ(2,dProblem.numVariables()); EXPECT_EQ(2,dProblem.numDiscreteVariables()); EXPECT_EQ(0,dProblem.numStaticTransformations()); variables.clear(); // box-behnken DDACEAlgorithmOptions options(DDACEAlgorithmType::box_behnken); DDACEAlgorithm algorithm(options); EXPECT_TRUE(algorithm.isCompatibleProblemType(cProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(mProblem)); EXPECT_FALSE(algorithm.isCompatibleProblemType(dProblem)); options.setSamples(DDACEAlgorithmOptions::samplesForBoxBehnken(cProblem)); ASSERT_TRUE(algorithm.ddaceAlgorithmOptions().samples()); EXPECT_EQ(81,algorithm.ddaceAlgorithmOptions().samples().get()); EXPECT_EQ(5,DDACEAlgorithmOptions::samplesForBoxBehnken(mProblem)); EXPECT_EQ(0,DDACEAlgorithmOptions::samplesForBoxBehnken(dProblem)); // central-composite options = DDACEAlgorithmOptions(DDACEAlgorithmType::central_composite); algorithm = DDACEAlgorithm(options); EXPECT_TRUE(algorithm.isCompatibleProblemType(cProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(mProblem)); EXPECT_FALSE(algorithm.isCompatibleProblemType(dProblem)); options.setSamples(DDACEAlgorithmOptions::samplesForCentralComposite(cProblem)); ASSERT_TRUE(algorithm.ddaceAlgorithmOptions().samples()); EXPECT_EQ(43,algorithm.ddaceAlgorithmOptions().samples().get()); EXPECT_EQ(9,DDACEAlgorithmOptions::samplesForCentralComposite(mProblem)); EXPECT_EQ(0,DDACEAlgorithmOptions::samplesForCentralComposite(dProblem)); // grid options = DDACEAlgorithmOptions(DDACEAlgorithmType::grid); algorithm = DDACEAlgorithm(options); EXPECT_TRUE(algorithm.isCompatibleProblemType(cProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(mProblem)); EXPECT_FALSE(algorithm.isCompatibleProblemType(dProblem)); EXPECT_TRUE(options.setSamplesForGrid(3,cProblem)); ASSERT_TRUE(algorithm.ddaceAlgorithmOptions().symbols()); ASSERT_TRUE(algorithm.ddaceAlgorithmOptions().samples()); EXPECT_EQ(3,algorithm.ddaceAlgorithmOptions().symbols().get()); EXPECT_EQ(243,algorithm.ddaceAlgorithmOptions().samples().get()); EXPECT_TRUE(algorithm.ddaceAlgorithmOptions().setSamplesForGrid(5,mProblem)); ASSERT_TRUE(algorithm.ddaceAlgorithmOptions().symbols()); ASSERT_TRUE(algorithm.ddaceAlgorithmOptions().samples()); EXPECT_EQ(5,algorithm.ddaceAlgorithmOptions().symbols().get()); EXPECT_EQ(25,algorithm.ddaceAlgorithmOptions().samples().get()); EXPECT_FALSE(options.setSamplesForGrid(2,dProblem)); // lhs options = DDACEAlgorithmOptions(DDACEAlgorithmType::lhs); algorithm = DDACEAlgorithm(options); EXPECT_TRUE(algorithm.isCompatibleProblemType(cProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(mProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(dProblem)); // oa_lhs options = DDACEAlgorithmOptions(DDACEAlgorithmType::oa_lhs); algorithm = DDACEAlgorithm(options); EXPECT_TRUE(algorithm.isCompatibleProblemType(cProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(mProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(dProblem)); // oas options = DDACEAlgorithmOptions(DDACEAlgorithmType::oas); algorithm = DDACEAlgorithm(options); EXPECT_TRUE(algorithm.isCompatibleProblemType(cProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(mProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(dProblem)); // random options = DDACEAlgorithmOptions(DDACEAlgorithmType::random); algorithm = DDACEAlgorithm(options); EXPECT_TRUE(algorithm.isCompatibleProblemType(cProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(mProblem)); EXPECT_TRUE(algorithm.isCompatibleProblemType(dProblem)); }
TEST_F(AnalysisFixture, Problem_Constructors) { VariableVector variables; MeasureVector measures; runmanager::Workflow workflow; // almost-default constructor Problem problem("Problem",variables,workflow); EXPECT_EQ(0,problem.numVariables()); OptionalInt combinatorialSize = problem.combinatorialSize(true); ASSERT_TRUE(combinatorialSize); EXPECT_EQ(0,*combinatorialSize); // variables with consistent file types variables.clear(); measures.clear(); measures.push_back(NullMeasure()); openstudio::path rubyScriptPath = toPath(rubyLibDir()) / toPath("openstudio/runmanager/rubyscripts/PerturbObject.rb"); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::OSM)); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::OSM)); variables.push_back(MeasureGroup("Variable 1",measures)); measures.clear(); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::IDF)); variables.push_back(MeasureGroup("Variable 2",measures)); measures.clear(); measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::IDF, FileReferenceType::IDF)); variables.push_back(MeasureGroup("Variable 3",measures)); problem = Problem("Problem",variables,workflow); EXPECT_EQ(3,problem.numVariables()); EXPECT_EQ(6,problem.combinatorialSize(true).get()); // variables with inconistent file types variables.clear(); measures.clear(); measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::OSM)); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::OSM, FileReferenceType::OSM)); variables.push_back(MeasureGroup("Variable 1",measures)); measures.clear(); measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::IDF, FileReferenceType::IDF)); variables.push_back(MeasureGroup("Variable 2",measures)); EXPECT_THROW(Problem("Problem",variables,workflow),std::exception); // variables and non-null workflow with consistent file types variables.clear(); measures.clear(); measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(rubyScriptPath, FileReferenceType::IDF, FileReferenceType::IDF)); variables.push_back(MeasureGroup("Variable 1",measures)); workflow = runmanager::Workflow(); workflow.addJob(openstudio::runmanager::JobType::EnergyPlus); problem = Problem("Problem",variables,workflow); problem.setDisplayName("Display Name"); problem.setDescription("long winded description"); EXPECT_EQ(1,problem.numVariables()); EXPECT_EQ(2,problem.combinatorialSize(true).get()); // deserialization Problem problemCopy(problem.uuid(), problem.versionUUID(), problem.name(), problem.displayName(), problem.description(), problem.workflow(), problem.responses()); EXPECT_FALSE(problem == problemCopy); // different impls EXPECT_TRUE(problem.uuid() == problemCopy.uuid()); EXPECT_TRUE(problem.versionUUID() == problemCopy.versionUUID()); EXPECT_EQ(problem.name(),problemCopy.name()); EXPECT_EQ(problem.displayName(),problemCopy.displayName()); EXPECT_EQ(problem.description(),problemCopy.description()); EXPECT_TRUE(problem.workflow() == problemCopy.workflow()); // variables and non-null workflow with inconsistent file types workflow = runmanager::Workflow(); workflow.addJob(openstudio::runmanager::JobType::ModelToIdf); workflow.addJob(openstudio::runmanager::JobType::EnergyPlus); EXPECT_THROW(Problem("Problem",variables,workflow),std::exception); }
TEST_F(AnalysisFixture, SequentialSearch) { // define dummy problem VariableVector variables; std::stringstream ss; for (int i = 0; i < 5; ++i) { MeasureVector measures; measures.push_back(NullMeasure()); measures.push_back(RubyMeasure(toPath("in.rb"),FileReferenceType::OSM,FileReferenceType::OSM)); ss << "var " << i + 1; variables.push_back(MeasureGroup(ss.str(),measures)); ss.str(""); } FunctionVector functions; functions.push_back(LinearFunction("",VariableVector(1u,OutputAttributeContinuousVariable("f1","f1")))); functions.push_back(LinearFunction("",VariableVector(1u,OutputAttributeContinuousVariable("f2","f2")))); OptimizationProblem problem("By-Hand Problem",functions,variables,runmanager::Workflow()); // solve dummy problem and check results SequentialSearch algorithm(SequentialSearchOptions(0)); FileReference seed(toPath("in.osm")); Analysis analysis("By-Hand Analysis",problem,algorithm,seed); int numAdded = algorithm.createNextIteration(analysis); EXPECT_EQ(1,numAdded); OptimizationDataPointVector nextIteration = castVector<OptimizationDataPoint>(analysis.dataPointsToQueue()); EXPECT_EQ(1u,nextIteration.size()); while (!nextIteration.empty()) { int n = analysis.dataPoints().size(); LOG(Debug,"Conducting iteration " << algorithm.iter() << " of Sequential Search."); OptimizationDataPointVector completeDataPoints = castVector<OptimizationDataPoint>(analysis.completeDataPoints()); OptimizationDataPointVector currentDataPoints = castVector<OptimizationDataPoint>(analysis.getDataPoints("current")); EXPECT_EQ(1u,currentDataPoints.size()); ASSERT_FALSE(currentDataPoints.empty()); EXPECT_EQ(unsigned(algorithm.iter()),analysis.getDataPoints("explored").size()); if (algorithm.iter() == 0) { EXPECT_EQ(1,n); EXPECT_EQ(0u,completeDataPoints.size()); } else if (algorithm.iter() == 1) { EXPECT_DOUBLE_EQ(20.0,currentDataPoints[0].objectiveValues()[0]); EXPECT_DOUBLE_EQ(20.0,currentDataPoints[0].objectiveValues()[1]); EXPECT_EQ(6,n); EXPECT_EQ(1u,completeDataPoints.size()); EXPECT_TRUE(currentDataPoints[0] == completeDataPoints[0]); EXPECT_TRUE(completeDataPoints[0].isTag("curve0")); EXPECT_TRUE(completeDataPoints[0].isTag("current")); EXPECT_TRUE(completeDataPoints[0].isTag("explored")); EXPECT_EQ(5u,nextIteration.size()); } else if (algorithm.iter() == 2) { EXPECT_DOUBLE_EQ(17.0,currentDataPoints[0].objectiveValues()[0]); EXPECT_DOUBLE_EQ(19.0,currentDataPoints[0].objectiveValues()[1]); EXPECT_EQ(10,n); EXPECT_EQ(6u,completeDataPoints.size()); EXPECT_EQ(2u,analysis.getDataPoints("curve0").size()); EXPECT_EQ(4u,nextIteration.size()); } else if (algorithm.iter() == 3) { EXPECT_DOUBLE_EQ(16.0,currentDataPoints[0].objectiveValues()[0]); EXPECT_DOUBLE_EQ(16.0,currentDataPoints[0].objectiveValues()[1]); EXPECT_EQ(13,n); EXPECT_EQ(10u,completeDataPoints.size()); EXPECT_EQ(3u,analysis.getDataPoints("curve0").size()); EXPECT_EQ(3u,nextIteration.size()); } else if (algorithm.iter() == 4) { // backtracking EXPECT_DOUBLE_EQ(15.0,currentDataPoints[0].objectiveValues()[0]); EXPECT_DOUBLE_EQ(19.0,currentDataPoints[0].objectiveValues()[1]); EXPECT_EQ(16,n); EXPECT_EQ(13u,completeDataPoints.size()); EXPECT_EQ(2u,analysis.getDataPoints("curve0").size()); EXPECT_EQ(3u,nextIteration.size()); } else if (algorithm.iter() == 5) { // backtracking EXPECT_DOUBLE_EQ(18.0,currentDataPoints[0].objectiveValues()[0]); EXPECT_DOUBLE_EQ(20.0,currentDataPoints[0].objectiveValues()[1]); EXPECT_EQ(18,n); EXPECT_EQ(16u,completeDataPoints.size()); EXPECT_EQ(2u,analysis.getDataPoints("curve0").size()); EXPECT_EQ(2u,nextIteration.size()); } else if (algorithm.iter() == 6) { EXPECT_DOUBLE_EQ(17.0,currentDataPoints[0].objectiveValues()[0]); EXPECT_DOUBLE_EQ(14.0,currentDataPoints[0].objectiveValues()[1]); EXPECT_EQ(20,n); EXPECT_EQ(18u,completeDataPoints.size()); EXPECT_EQ(5u,analysis.getDataPoints("curve0").size()); EXPECT_EQ(2u,nextIteration.size()); } else if (algorithm.iter() == 7) { EXPECT_DOUBLE_EQ(20.0,currentDataPoints[0].objectiveValues()[0]); EXPECT_DOUBLE_EQ(12.0,currentDataPoints[0].objectiveValues()[1]); EXPECT_EQ(23,n); EXPECT_EQ(20u,completeDataPoints.size()); EXPECT_EQ(6u,analysis.getDataPoints("curve0").size()); EXPECT_EQ(3u,nextIteration.size()); } EXPECT_EQ(static_cast<size_t>(n),completeDataPoints.size() + nextIteration.size()); for (const OptimizationDataPoint& point : nextIteration) { std::vector<QVariant> values = point.variableValues(); DoubleVector objectiveValues = getObjectiveValues(values); for (int i = 0; i < 5; ++i) { int value = values[i].toInt(); if (value == 0) { ss << " "; } else { EXPECT_EQ(1,value); ss << i + 1 << " "; } } ss << ": " << objectiveValues[0] << ", " << objectiveValues[1]; LOG(Debug,ss.str()); ss.str(""); completeDataPoints.push_back(OptimizationDataPoint(point.uuid(), createUUID(), "","","", problem, true, false, true, DataPointRunType::Local, values, DoubleVector(), objectiveValues, openstudio::path(), boost::none, boost::none, boost::none, boost::none, std::vector<openstudio::path>(), point.tags(), point.outputAttributes())); // DLM: Elaine is this ok? } EXPECT_EQ(static_cast<size_t>(n),completeDataPoints.size()); analysis = Analysis(analysis.uuid(), createUUID(), analysis.name(), analysis.displayName(), analysis.description(), problem, algorithm, seed, boost::none, castVector<DataPoint>(completeDataPoints), false, false); algorithm.createNextIteration(analysis); nextIteration = castVector<OptimizationDataPoint>(analysis.dataPointsToQueue()); } EXPECT_EQ(23u,analysis.successfulDataPoints().size()); OptimizationDataPointVector minimumCurve = algorithm.getMinimumCurve(0,analysis); ASSERT_EQ(6u,minimumCurve.size()); DoubleVector values = minimumCurve[0].objectiveValues(); EXPECT_DOUBLE_EQ(20.0,values[0]); EXPECT_DOUBLE_EQ(20.0,values[1]); values = minimumCurve[1].objectiveValues(); EXPECT_DOUBLE_EQ(18.0,values[0]); EXPECT_DOUBLE_EQ(20.0,values[1]); values = minimumCurve[2].objectiveValues(); EXPECT_DOUBLE_EQ(15.0,values[0]); EXPECT_DOUBLE_EQ(19.0,values[1]); values = minimumCurve[3].objectiveValues(); EXPECT_DOUBLE_EQ(16.0,values[0]); EXPECT_DOUBLE_EQ(16.0,values[1]); values = minimumCurve[4].objectiveValues(); EXPECT_DOUBLE_EQ(17.0,values[0]); EXPECT_DOUBLE_EQ(14.0,values[1]); values = minimumCurve[5].objectiveValues(); EXPECT_DOUBLE_EQ(20.0,values[0]); EXPECT_DOUBLE_EQ(12.0,values[1]); OptimizationDataPointVector paretoFront = algorithm.getParetoFront(analysis); for (const OptimizationDataPoint& paretoPoint : paretoFront) { EXPECT_FALSE(std::find(minimumCurve.begin(),minimumCurve.end(),paretoPoint) == minimumCurve.end()); } ASSERT_EQ(4u,paretoFront.size()); // expect same order as curve0, although different method for calculating values = paretoFront[0].objectiveValues(); EXPECT_DOUBLE_EQ(15.0,values[0]); EXPECT_DOUBLE_EQ(19.0,values[1]); // minimizes f0 values = paretoFront[1].objectiveValues(); EXPECT_DOUBLE_EQ(16.0,values[0]); EXPECT_DOUBLE_EQ(16.0,values[1]); values = paretoFront[2].objectiveValues(); EXPECT_DOUBLE_EQ(17.0,values[0]); EXPECT_DOUBLE_EQ(14.0,values[1]); values = paretoFront[3].objectiveValues(); EXPECT_DOUBLE_EQ(20.0,values[0]); EXPECT_DOUBLE_EQ(12.0,values[1]); // minimizes f1 }