openstudio::analysisdriver::SimpleProject AnalysisDriverFixture::getCleanPATProject(
    const std::string& projectName)
{
  // place in directory of same name
  std::string dirName = openstudio::toUpperCamelCase(projectName);
  openstudio::path workingDir = toPath("AnalysisDriverFixtureData") / toPath(dirName);
  LOG(Debug,"Creating working directory at " << toString(workingDir) << ".");

  if (!boost::filesystem::exists(toPath("AnalysisDriverFixtureData"))) {
    boost::filesystem::create_directory(toPath("AnalysisDriverFixtureData"));
  }

  // clean out old results
  if (boost::filesystem::exists(workingDir)) {
    boost::filesystem::remove_all(workingDir);
  }

  SimpleProjectOptions options;
  if (boost::optional<LogLevel> logLevel = logFile->logLevel()) {
    options.setLogLevel(*logLevel);
  }

  LOG(Debug,"Creating PAT SimpleProject in directory " << toString(workingDir) << ".");
  return createPATProject(workingDir,options).get();
}
SimpleProject AnalysisDriverTestLibrarySingleton::createProject(
    const std::string& projectName,
    bool isPAT,
    const LibraryProblem& libraryProblem,
    const std::string& baselineModelName)
{
    openstudio::path projectDir = outputDataDirectory() / toPath(projectName);
    if (boost::filesystem::exists(projectDir)) {
        boost::filesystem::remove_all(projectDir);
    }

    OptionalSimpleProject result;
    SimpleProjectOptions options;
    options.setLogLevel(Debug);
    if (isPAT) {
        result = createPATProject(projectDir,options);
    }
    else {
        result = SimpleProject::create(projectDir,options);
    }
    OS_ASSERT(result);

    setProblem(*result,libraryProblem);

    std::vector<openstudio::path>::const_iterator it;
    it = std::find_if(m_baselineModels.begin(),
                      m_baselineModels.end(),
                      std::bind(AnalysisDriverTestLibrarySingleton::pathStemEquals,std::placeholders::_1,baselineModelName));
    OS_ASSERT(it != m_baselineModels.end());
    bool test = result->setSeed(FileReference(*it)).first;
    OS_ASSERT(test);

    return *result;
}
openstudio::analysisdriver::SimpleProject AnalysisDriverFixture::getPATProject(
    const std::string& projectName)
{
  // mimic above, just don't blow away old databases
  std::string dirName = openstudio::toUpperCamelCase(projectName);
  openstudio::path workingDir = toPath("AnalysisDriverFixtureData") / toPath(dirName);

  SimpleProjectOptions options;
  if (boost::optional<LogLevel> logLevel = logFile->logLevel()) {
    options.setLogLevel(*logLevel);
  }
  return openPATProject(workingDir,options).get();
}
SimpleProject AnalysisDriverTestLibrarySingleton::openProject(
    const std::string& projectName,
    bool requirePAT)
{
    openstudio::path projectDir = outputDataDirectory() / toPath(projectName);

    OptionalSimpleProject result;
    SimpleProjectOptions options;
    options.setLogLevel(Debug);
    if (requirePAT) {
        result = openPATProject(projectDir,options);
    }
    else {
        result = SimpleProject::open(projectDir,options);
    }
    OS_ASSERT(result);

    return *result;
}
TEST_F(CloudFixture,CloudAnalysisDriver_RunPrototypeProject) {
  {
    // open prototype project
    openstudio::path projectDir = vagrantServerPath().parent_path().parent_path() / 
                                   toPath("prototype/pat/PATTest");  
    SimpleProjectOptions options;
    options.setLogLevel(Debug);
    SimpleProject project = openPATProject(projectDir,options).get();

    // save as into new folder
    projectDir = AnalysisDriverTestLibrary::instance().outputDataDirectory() / toPath("CloudAnalysisDriver_RunPrototypeProject");
    if (boost::filesystem::exists(projectDir)) {
      boost::filesystem::remove_all(projectDir);
    }
    OptionalSimpleProject temp = saveAs(project,projectDir);
    ASSERT_TRUE(temp);
    project = temp.get();

    // run it
    CloudAnalysisDriver driver(provider->session(),project);
    driver.run();
    EXPECT_TRUE(driver.lastRunSuccess());

    // check data points
    BOOST_FOREACH(const DataPoint& dataPoint,project.analysis().dataPoints()) {
      EXPECT_TRUE(dataPoint.isComplete());
      EXPECT_TRUE(dataPoint.runType() == DataPointRunType::CloudSlim);
      EXPECT_FALSE(dataPoint.outputAttributes().empty());
      EXPECT_TRUE(dataPoint.directory().empty());
      std::vector<WorkflowStepJob> jobsByStep = project.analysis().problem().getJobsByWorkflowStep(dataPoint);
      unsigned jobCount(0);
      unsigned messageCount(0);
      BOOST_FOREACH(const WorkflowStepJob& jobStep,jobsByStep) {
        if (jobStep.job) {
          ++jobCount;
          messageCount += jobStep.job.get().errors().errors().size();
          messageCount += jobStep.job.get().errors().warnings().size();
          messageCount += jobStep.job.get().errors().infos().size();
          messageCount += jobStep.job.get().errors().initialConditions().size();
          messageCount += jobStep.job.get().errors().finalConditions().size();
        }
      }
      EXPECT_GT(jobCount,0u);
      EXPECT_GT(messageCount,0u);
    }
  }

  {
    // reopen prototype project and make sure data is still there
    openstudio::path projectDir = AnalysisDriverTestLibrary::instance().outputDataDirectory() / toPath("CloudAnalysisDriver_RunPrototypeProject");
    SimpleProjectOptions options;
    options.setLogLevel(Debug);
    SimpleProject project = openPATProject(projectDir,options).get();

    // check data points
    BOOST_FOREACH(const DataPoint& dataPoint,project.analysis().dataPoints()) {
      EXPECT_TRUE(dataPoint.isComplete());
      EXPECT_TRUE(dataPoint.runType() == DataPointRunType::CloudSlim);
      EXPECT_FALSE(dataPoint.outputAttributes().empty());
      EXPECT_TRUE(dataPoint.directory().empty());
      std::vector<WorkflowStepJob> jobsByStep = project.analysis().problem().getJobsByWorkflowStep(dataPoint);
      unsigned jobCount(0);
      unsigned messageCount(0);
      BOOST_FOREACH(const WorkflowStepJob& jobStep,jobsByStep) {
        if (jobStep.job) {
          ++jobCount;
          messageCount += jobStep.job.get().errors().errors().size();
          messageCount += jobStep.job.get().errors().warnings().size();
          messageCount += jobStep.job.get().errors().infos().size();
          messageCount += jobStep.job.get().errors().initialConditions().size();
          messageCount += jobStep.job.get().errors().finalConditions().size();
        }
      }
      EXPECT_GT(jobCount,0u);
      EXPECT_GT(messageCount,0u);
    }

    // now request detailed results
    CloudAnalysisDriver driver(provider->session(),project);
    DataPointVector dataPoints = project.analysis().dataPoints();
    BOOST_FOREACH(DataPoint& dataPoint,dataPoints) {
      driver.requestDownloadDetailedResults(dataPoint);
    }
    driver.waitForFinished();
    EXPECT_TRUE(driver.lastDownloadDetailedResultsSuccess());
    // check outcome
    BOOST_FOREACH(const DataPoint& dataPoint,project.analysis().dataPoints()) {
      EXPECT_TRUE(dataPoint.isComplete());
      EXPECT_TRUE(dataPoint.runType() == DataPointRunType::CloudDetailed);
      EXPECT_FALSE(dataPoint.outputAttributes().empty());
      EXPECT_FALSE(dataPoint.directory().empty());
      EXPECT_TRUE(dataPoint.model());
      if (OptionalModel model = dataPoint.model()) {
        LOG(Debug,"DataPoint '" << dataPoint.name() << "' has " << model->numObjects() 
            << " in its OpenStudio Model.");
      }
    }
  }