TEST_F(ProjectFixture,AnalysisRecord_AddAndRemoveDataPoints) { // create an analysis with data points, no results Analysis analysis("My Analysis", Problem("My Problem",VariableVector(),runmanager::Workflow()), FileReferenceType::OSM); Problem problem = analysis.problem(); DiscretePerturbationVector perturbations; int pi = 1; std::stringstream ss; for (int i = 0; i < 3; ++i) { perturbations.push_back(NullPerturbation()); for (int j = 0; j < 4; ++j) { ss << "measure" << pi << ".rb"; perturbations.push_back(RubyPerturbation(toPath(ss.str()), FileReferenceType::OSM, FileReferenceType::OSM,true)); ss.str(""); ++pi; } ss << "Variable " << i+1; problem.push(DiscreteVariable(ss.str(),perturbations)); perturbations.clear(); ss.str(""); } EXPECT_EQ(3u,analysis.problem().variables().size()); ASSERT_FALSE(problem.variables().empty()); EXPECT_EQ(5u,problem.variables()[0].cast<DiscreteVariable>().numPerturbations(true)); problem.pushResponse( LinearFunction("Energy Use", VariableVector(1u,OutputAttributeVariable("Energy Use","Total.Energy.Use")))); EXPECT_EQ(1u,problem.responses().size()); std::vector<QVariant> values(3u,0); OptionalDataPoint dataPoint = problem.createDataPoint(values); ASSERT_TRUE(dataPoint); bool test = analysis.addDataPoint(*dataPoint); EXPECT_TRUE(test); values[1] = 3; dataPoint = problem.createDataPoint(values); ASSERT_TRUE(dataPoint); test = analysis.addDataPoint(*dataPoint); EXPECT_TRUE(test); values[0] = 1; values[1] = 2; values[2] = 4; dataPoint = problem.createDataPoint(values); ASSERT_TRUE(dataPoint); test = analysis.addDataPoint(*dataPoint); EXPECT_TRUE(test); EXPECT_TRUE(analysis.isDirty()); EXPECT_TRUE(problem.isDirty()); BOOST_FOREACH(const Variable& variable, problem.variables()) { EXPECT_TRUE(variable.isDirty()); ASSERT_TRUE(variable.optionalCast<DiscreteVariable>()); BOOST_FOREACH(const DiscretePerturbation& perturbation,variable.cast<DiscreteVariable>().perturbations(false)) { EXPECT_TRUE(perturbation.isDirty()); } } BOOST_FOREACH(const Function& response, problem.responses()) { EXPECT_TRUE(response.isDirty()); } BOOST_FOREACH(const DataPoint& dataPoint, analysis.dataPoints()) { EXPECT_TRUE(dataPoint.isDirty()); } // save to database, make sure everything is there, make sure clean signal filters down ProjectDatabase database = getCleanDatabase("AnalysisRecord_AddAndRemoveDataPoints"); { bool transactionStarted = database.startTransaction(); EXPECT_TRUE(transactionStarted); AnalysisRecord analysisRecord(analysis,database); database.save(); test = database.commitTransaction(); EXPECT_TRUE(test); EXPECT_EQ(analysis.uuid(),analysisRecord.handle()); EXPECT_EQ(analysis.versionUUID(),analysisRecord.uuidLast()); ASSERT_NO_THROW(analysisRecord.problemRecord()); ProblemRecord problemRecord = analysisRecord.problemRecord(); InputVariableRecordVector variableRecords = problemRecord.inputVariableRecords(); EXPECT_EQ(3u,variableRecords.size()); ASSERT_FALSE(variableRecords.empty()); ASSERT_TRUE(variableRecords[0].optionalCast<DiscreteVariableRecord>()); DiscretePerturbationRecordVector perturbationRecords = variableRecords[0].cast<DiscreteVariableRecord>().discretePerturbationRecords(false); EXPECT_EQ(5u,perturbationRecords.size()); ASSERT_TRUE(perturbationRecords.size() > 1); EXPECT_TRUE(perturbationRecords[0].optionalCast<NullPerturbationRecord>()); EXPECT_TRUE(perturbationRecords[1].optionalCast<RubyPerturbationRecord>()); EXPECT_EQ(3u,analysisRecord.dataPointRecords().size()); EXPECT_TRUE(analysisRecord.completeDataPointRecords().empty()); } analysis.clearDirtyFlag(); EXPECT_FALSE(analysis.isDirty()); EXPECT_FALSE(problem.isDirty()); BOOST_FOREACH(const Variable& variable, problem.variables()) { EXPECT_FALSE(variable.isDirty()); ASSERT_TRUE(variable.optionalCast<DiscreteVariable>()); BOOST_FOREACH(const DiscretePerturbation& perturbation,variable.cast<DiscreteVariable>().perturbations(false)) { EXPECT_FALSE(perturbation.isDirty()); } } BOOST_FOREACH(const Function& response, problem.responses()) { EXPECT_FALSE(response.isDirty()); } BOOST_FOREACH(const DataPoint& dataPoint, analysis.dataPoints()) { EXPECT_FALSE(dataPoint.isDirty()); } // make some more data points and make sure dirty flag bubbles up values[0] = 3; values[1] = 2; values[2] = 2; dataPoint = problem.createDataPoint(values); ASSERT_TRUE(dataPoint); test = analysis.addDataPoint(*dataPoint); EXPECT_TRUE(test); values[0] = 0; values[1] = 4; values[2] = 0; dataPoint = problem.createDataPoint(values); ASSERT_TRUE(dataPoint); test = analysis.addDataPoint(*dataPoint); EXPECT_TRUE(test); EXPECT_EQ(5u,analysis.dataPoints().size()); EXPECT_TRUE(analysis.isDirty()); EXPECT_FALSE(problem.isDirty()); BOOST_FOREACH(const Variable& variable, problem.variables()) { EXPECT_FALSE(variable.isDirty()); ASSERT_TRUE(variable.optionalCast<DiscreteVariable>()); BOOST_FOREACH(const DiscretePerturbation& perturbation,variable.cast<DiscreteVariable>().perturbations(false)) { EXPECT_FALSE(perturbation.isDirty()); } } BOOST_FOREACH(const Function& response, problem.responses()) { EXPECT_FALSE(response.isDirty()); } int i = 0; BOOST_FOREACH(const DataPoint& dataPoint, analysis.dataPoints()) { if (i < 3) { EXPECT_FALSE(dataPoint.isDirty()); } else { EXPECT_TRUE(dataPoint.isDirty()); } ++i; } // save to database, make sure changes made it in { bool transactionStarted = database.startTransaction(); EXPECT_TRUE(transactionStarted); database.unloadUnusedCleanRecords(); // ETH@20130201 - Having to call this is awkward. // Where is the best place? AnalysisRecord analysisRecord(analysis,database); database.save(); test = database.commitTransaction(); EXPECT_TRUE(test); EXPECT_EQ(analysis.uuid(),analysisRecord.handle()); EXPECT_EQ(analysis.versionUUID(),analysisRecord.uuidLast()); ASSERT_NO_THROW(analysisRecord.problemRecord()); ProblemRecord problemRecord = analysisRecord.problemRecord(); EXPECT_EQ(problemRecord.handle(),analysisRecord.problemRecord().handle()); EXPECT_EQ(problemRecord.uuidLast(),analysisRecord.problemRecord().uuidLast()); InputVariableRecordVector variableRecords = problemRecord.inputVariableRecords(); EXPECT_EQ(3u,variableRecords.size()); ASSERT_FALSE(variableRecords.empty()); ASSERT_TRUE(variableRecords[0].optionalCast<DiscreteVariableRecord>()); DiscretePerturbationRecordVector perturbationRecords = variableRecords[0].cast<DiscreteVariableRecord>().discretePerturbationRecords(false); EXPECT_EQ(5u,perturbationRecords.size()); ASSERT_TRUE(perturbationRecords.size() > 1); EXPECT_TRUE(perturbationRecords[0].optionalCast<NullPerturbationRecord>()); EXPECT_TRUE(perturbationRecords[1].optionalCast<RubyPerturbationRecord>()); EXPECT_EQ(5u,analysisRecord.dataPointRecords().size()); EXPECT_TRUE(analysisRecord.completeDataPointRecords().empty()); } analysis.clearDirtyFlag(); EXPECT_FALSE(analysis.isDirty()); EXPECT_FALSE(problem.isDirty()); BOOST_FOREACH(const Variable& variable, problem.variables()) { EXPECT_FALSE(variable.isDirty()); ASSERT_TRUE(variable.optionalCast<DiscreteVariable>()); BOOST_FOREACH(const DiscretePerturbation& perturbation,variable.cast<DiscreteVariable>().perturbations(false)) { EXPECT_FALSE(perturbation.isDirty()); } } BOOST_FOREACH(const Function& response, problem.responses()) { EXPECT_FALSE(response.isDirty()); } BOOST_FOREACH(const DataPoint& dataPoint, analysis.dataPoints()) { EXPECT_FALSE(dataPoint.isDirty()); } // remove a data point and save database. make sure point actually disappears DataPoint toRemove = analysis.dataPoints()[3]; test = analysis.removeDataPoint(toRemove); EXPECT_TRUE(test); EXPECT_TRUE(analysis.isDirty()); { bool transactionStarted = database.startTransaction(); EXPECT_TRUE(transactionStarted); database.unloadUnusedCleanRecords(); // ETH@20130201 - Having to call this is awkward. // Where is the best place? AnalysisRecord analysisRecord(analysis,database); database.save(); test = database.commitTransaction(); EXPECT_TRUE(test); EXPECT_EQ(analysis.uuid(),analysisRecord.handle()); EXPECT_EQ(analysis.versionUUID(),analysisRecord.uuidLast()); ASSERT_NO_THROW(analysisRecord.problemRecord()); ProblemRecord problemRecord = analysisRecord.problemRecord(); EXPECT_EQ(problemRecord.handle(),analysisRecord.problemRecord().handle()); EXPECT_EQ(problemRecord.uuidLast(),analysisRecord.problemRecord().uuidLast()); InputVariableRecordVector variableRecords = problemRecord.inputVariableRecords(); EXPECT_EQ(3u,variableRecords.size()); ASSERT_FALSE(variableRecords.empty()); ASSERT_TRUE(variableRecords[0].optionalCast<DiscreteVariableRecord>()); DiscretePerturbationRecordVector perturbationRecords = variableRecords[0].cast<DiscreteVariableRecord>().discretePerturbationRecords(false); EXPECT_EQ(5u,perturbationRecords.size()); ASSERT_TRUE(perturbationRecords.size() > 1); EXPECT_TRUE(perturbationRecords[0].optionalCast<NullPerturbationRecord>()); EXPECT_TRUE(perturbationRecords[1].optionalCast<RubyPerturbationRecord>()); EXPECT_EQ(4u,analysisRecord.dataPointRecords().size()); OptionalDataPointRecord searchResult = database.getObjectRecordByHandle<DataPointRecord>(toRemove.uuid()); EXPECT_FALSE(searchResult); EXPECT_EQ(4u,DataPointRecord::getDataPointRecords(database).size()); } EXPECT_EQ(4u,analysis.dataPoints().size()); test = analysis.clearDirtyFlag(); EXPECT_TRUE(test); }
analysis::Problem ProblemRecord_Impl::problem() const { InputVariableRecordVector inputVariableRecords = this->inputVariableRecords(); WorkflowRecordVector workflowRecords = this->workflowRecords(); analysis::WorkflowStepVector workflow; // mesh InputVariables and WorkItems together to form overall workflow int ivrIndex(0); // index into input variable records int wrIndex(0); // index into workflow records int wIndex(0); // index into workflow int ivrN = inputVariableRecords.size(); int wrN = workflowRecords.size(); OptionalInt ivrWIndex; // saved index into workflow for next input variable OptionalInt wrWIndex; // saved index into workflow for next workflow record if (!inputVariableRecords.empty()) { ivrWIndex = inputVariableRecords[ivrIndex].variableVectorIndex(); } if (!workflowRecords.empty()) { wrWIndex = workflowRecords[wrIndex].workflowIndex(); } for (int i = 0, n = ivrN + wrN; i < n; ++i) { if (!wrWIndex || (ivrWIndex && (*ivrWIndex < *wrWIndex))) { // InputVariable is next BOOST_ASSERT(*ivrWIndex == wIndex); // saved and expected index into workflow match BOOST_ASSERT(ivrIndex < ivrN); // there is an input variable record to deserialize workflow.push_back(WorkflowStep(inputVariableRecords[ivrIndex].inputVariable())); ++ivrIndex; // go to next input variable record ++wIndex; // and next index into workflow BOOST_ASSERT(wIndex == int(workflow.size())); // next index into workflow should match current size if (ivrIndex < ivrN) { ivrWIndex = inputVariableRecords[ivrIndex].variableVectorIndex(); } else { ivrWIndex.reset(); // no more input variables to deserialize } } else { // Workflow is next BOOST_ASSERT(wrWIndex); int temp = *wrWIndex; // for debugging BOOST_ASSERT(temp == wIndex); // saved index into workflow should match expected value BOOST_ASSERT(wrIndex < wrN); // there is a workflow record to deserialize std::vector<runmanager::WorkItem> workItems = workflowRecords[wrIndex].workflow().toWorkItems(); workflow.insert(workflow.end(),workItems.begin(),workItems.end()); ++wrIndex; // go to next workflow record wIndex += workItems.size(); // update next expected workflow index BOOST_ASSERT(wIndex == int(workflow.size())); // next index into workflow should match current size if (wrIndex < wrN) { wrWIndex = workflowRecords[wrIndex].workflowIndex(); } else { wrWIndex.reset(); // no more workflow records to deserialize } } } analysis::FunctionVector responses; FunctionRecordVector responseRecords = this->responseRecords(); BOOST_FOREACH(const FunctionRecord responseRecord,responseRecords) { responses.push_back(responseRecord.function()); }