Cross-platform collection of software tools to support whole building energy modeling using EnergyPlus and advanced daylight analysis using Radiance
—
Orchestration of complete building simulation workflows from initial model through results processing. The workflow system manages the complete analysis pipeline including model measures, EnergyPlus simulation, and reporting measures with comprehensive error handling and progress tracking.
Main workflow coordination class managing the complete simulation pipeline.
/**
* Main workflow orchestrator for complete building simulation workflows
*/
class OSWorkflow {
public:
// Constructors
OSWorkflow();
explicit OSWorkflow(const Path& oswPath);
explicit OSWorkflow(const WorkflowJSON& workflowJSON);
// Workflow execution
bool run();
bool run(const Path& oswPath);
// Workflow configuration
WorkflowJSON workflowJSON() const;
void setWorkflowJSON(const WorkflowJSON& workflowJSON);
// Model and simulation access
boost::optional<Model> model() const;
boost::optional<Workspace> workspace() const;
boost::optional<SqlFile> sqlFile() const;
// Results and logging
std::vector<LogMessage> errors() const;
std::vector<LogMessage> warnings() const;
std::vector<LogMessage> info() const;
// Workflow state
bool completed() const;
std::string completedStatus() const;
// Progress tracking
void setProgressCallback(std::function<void(int)> callback);
// Step-by-step execution
bool runInitialization();
bool runOpenStudioMeasures();
bool runTranslator();
bool runEnergyPlus();
bool runReportingMeasures();
bool runCleanup();
// Working directory management
Path rootDirectory() const;
Path runDirectory() const;
void setRunDirectory(const Path& runDirectory);
// Simulation files
Path osmPath() const;
Path idfPath() const;
boost::optional<Path> sqlPath() const;
boost::optional<Path> epwPath() const;
};Usage Examples:
#include <openstudio/workflow/OSWorkflow.hpp>
#include <openstudio/utilities/filetypes/WorkflowJSON.hpp>
using namespace openstudio;
// Simple workflow execution
OSWorkflow workflow;
// Load workflow configuration
WorkflowJSON workflowJSON = WorkflowJSON::load(Path("simulation_workflow.osw")).get();
workflow.setWorkflowJSON(workflowJSON);
// Run complete workflow
bool success = workflow.run();
if (success) {
// Access results
boost::optional<Model> finalModel = workflow.model();
boost::optional<SqlFile> results = workflow.sqlFile();
if (results) {
std::cout << "Simulation completed successfully" << std::endl;
}
} else {
// Handle errors
std::vector<LogMessage> errors = workflow.errors();
for (const auto& error : errors) {
std::cout << "Workflow Error: " << error.logMessage() << std::endl;
}
}JSON-based workflow configuration and serialization.
/**
* JSON-based workflow configuration
*/
class WorkflowJSON {
public:
// Constructors
WorkflowJSON();
WorkflowJSON(const Path& seedFile, const Path& weatherFile);
// File I/O
static boost::optional<WorkflowJSON> load(const Path& path);
bool save(const Path& path) const;
bool saveAs(const Path& path);
// Seed file (starting model)
boost::optional<Path> seedFile() const;
bool setSeedFile(const Path& seedFile);
void resetSeedFile();
// Weather file
boost::optional<Path> weatherFile() const;
bool setWeatherFile(const Path& weatherFile);
void resetWeatherFile();
// Measure steps
std::vector<MeasureStep> measures() const;
bool addMeasure(const MeasureStep& measureStep);
bool insertMeasure(int index, const MeasureStep& measureStep);
bool removeMeasure(int index);
void clearMeasures();
// File paths
std::vector<Path> filePaths() const;
bool addFilePath(const Path& filePath);
// Run options
boost::optional<RunOptions> runOptions() const;
void setRunOptions(const RunOptions& runOptions);
// Root directory
boost::optional<Path> rootDirectory() const;
void setRootDirectory(const Path& rootDirectory);
// JSON access
std::string string() const;
Json::Value toJSON() const;
// Validation
bool isValid() const;
std::vector<std::string> errors() const;
};
/**
* Individual measure step configuration
*/
class MeasureStep {
public:
// Constructors
MeasureStep();
MeasureStep(const std::string& measureDirName);
MeasureStep(const BCLMeasure& bclMeasure);
// Measure identification
std::string measureDirName() const;
void setMeasureDirName(const std::string& measureDirName);
boost::optional<std::string> name() const;
void setName(const std::string& name);
boost::optional<std::string> description() const;
void setDescription(const std::string& description);
// Measure arguments
std::map<std::string, OSArgument> arguments() const;
bool setArgument(const OSArgument& argument);
bool setArgument(const std::string& name, const std::string& value);
bool setArgument(const std::string& name, double value);
bool setArgument(const std::string& name, int value);
bool setArgument(const std::string& name, bool value);
// Step properties
boost::optional<MeasureType> measureType() const;
void setMeasureType(MeasureType measureType);
// Results
boost::optional<StepResult> result() const;
void setResult(const StepResult& result);
void resetResult();
};
/**
* Workflow run options and simulation settings
*/
class RunOptions {
public:
// Constructors
RunOptions();
// EnergyPlus options
boost::optional<bool> debug() const;
void setDebug(bool debug);
boost::optional<bool> fastExecution() const;
void setFastExecution(bool fastExecution);
boost::optional<bool> preserveRunDir() const;
void setPreserveRunDir(bool preserveRunDir);
boost::optional<bool> cleanup() const;
void setCleanup(bool cleanup);
// Simulation options
boost::optional<int> maxDatapoints() const;
void setMaxDatapoints(int maxDatapoints);
boost::optional<int> numParallel() const;
void setNumParallel(int numParallel);
// Custom options
std::map<std::string, std::string> customOptions() const;
void setCustomOption(const std::string& key, const std::string& value);
};Individual workflow step implementations for different phases of simulation.
/**
* Base class for workflow steps
*/
class WorkflowStep {
public:
// Step identification
virtual std::string stepName() const = 0;
virtual std::string stepDescription() const = 0;
// Execution
virtual StepResult run(OSWorkflow& workflow) = 0;
// Step type
virtual WorkflowStepType stepType() const = 0;
};
/**
* Initialization step - validates inputs and sets up workflow
*/
class RunInitialization : public WorkflowStep {
public:
RunInitialization();
virtual std::string stepName() const override { return "Initialization"; }
virtual std::string stepDescription() const override {
return "Initialize workflow and validate inputs";
}
virtual StepResult run(OSWorkflow& workflow) override;
virtual WorkflowStepType stepType() const override { return WorkflowStepType::Initialization; }
};
/**
* OpenStudio measures step - applies model measures
*/
class RunOpenStudioMeasures : public WorkflowStep {
public:
RunOpenStudioMeasures();
virtual std::string stepName() const override { return "OpenStudio Measures"; }
virtual std::string stepDescription() const override {
return "Apply OpenStudio model measures";
}
virtual StepResult run(OSWorkflow& workflow) override;
virtual WorkflowStepType stepType() const override { return WorkflowStepType::ModelMeasures; }
// Measure filtering
void setMeasureFilter(std::function<bool(const MeasureStep&)> filter);
};
/**
* Translation step - converts OpenStudio model to EnergyPlus IDF
*/
class RunTranslator : public WorkflowStep {
public:
RunTranslator();
virtual std::string stepName() const override { return "Forward Translator"; }
virtual std::string stepDescription() const override {
return "Translate OpenStudio model to EnergyPlus IDF";
}
virtual StepResult run(OSWorkflow& workflow) override;
virtual WorkflowStepType stepType() const override { return WorkflowStepType::Translation; }
// Translation options
void setTranslationOptions(const ForwardTranslatorOptions& options);
};
/**
* EnergyPlus simulation step
*/
class RunEnergyPlus : public WorkflowStep {
public:
RunEnergyPlus();
virtual std::string stepName() const override { return "EnergyPlus"; }
virtual std::string stepDescription() const override {
return "Run EnergyPlus simulation";
}
virtual StepResult run(OSWorkflow& workflow) override;
virtual WorkflowStepType stepType() const override { return WorkflowStepType::Simulation; }
// Simulation options
void setEnergyPlusPath(const Path& energyPlusPath);
void setNumThreads(int numThreads);
};
/**
* Reporting measures step - processes simulation results
*/
class RunReportingMeasures : public WorkflowStep {
public:
RunReportingMeasures();
virtual std::string stepName() const override { return "Reporting Measures"; }
virtual std::string stepDescription() const override {
return "Apply reporting measures to process results";
}
virtual StepResult run(OSWorkflow& workflow) override;
virtual WorkflowStepType stepType() const override { return WorkflowStepType::ReportingMeasures; }
};
// Workflow step type enumeration
enum class WorkflowStepType {
Initialization,
ModelMeasures,
EnergyPlusMeasures,
Translation,
Simulation,
ReportingMeasures,
Cleanup
};Comprehensive result tracking and status management for workflow execution.
/**
* Step execution result
*/
class StepResult {
public:
// Result status
enum class Status {
NotStarted,
Running,
Success,
Fail,
Skip,
NA // Not Applicable
};
// Constructors
StepResult();
StepResult(Status initialStatus);
// Status management
Status status() const;
void setStatus(Status status);
std::string statusDescription() const;
void setStatusDescription(const std::string& description);
// Execution details
boost::optional<DateTime> startTime() const;
void setStartTime(const DateTime& startTime);
boost::optional<DateTime> endTime() const;
void setEndTime(const DateTime& endTime);
boost::optional<double> elapsedTime() const;
// Error and warning messages
std::vector<LogMessage> errors() const;
void addError(const LogMessage& error);
std::vector<LogMessage> warnings() const;
void addWarning(const LogMessage& warning);
std::vector<LogMessage> info() const;
void addInfo(const LogMessage& info);
// Step outputs
std::vector<StepFile> stepFiles() const;
void addStepFile(const StepFile& stepFile);
std::vector<OSAttribute> stepValues() const;
void addStepValue(const OSAttribute& stepValue);
// Initial and final conditions
boost::optional<std::string> initialCondition() const;
void setInitialCondition(const std::string& condition);
boost::optional<std::string> finalCondition() const;
void setFinalCondition(const std::string& condition);
};
/**
* File output from workflow steps
*/
class StepFile {
public:
// Constructors
StepFile();
StepFile(const Path& path);
// File properties
Path path() const;
void setPath(const Path& path);
std::string displayName() const;
void setDisplayName(const std::string& displayName);
boost::optional<std::string> description() const;
void setDescription(const std::string& description);
// File type
std::string fileType() const;
void setFileType(const std::string& fileType);
// Usage type (input, output, resource)
std::string usageType() const;
void setUsageType(const std::string& usageType);
};
/**
* Workflow progress tracking
*/
class WorkflowProgress {
public:
WorkflowProgress();
// Overall progress
double overallProgress() const;
void setOverallProgress(double progress);
// Current step
boost::optional<WorkflowStepType> currentStep() const;
void setCurrentStep(WorkflowStepType step);
double stepProgress() const;
void setStepProgress(double progress);
std::string currentActivity() const;
void setCurrentActivity(const std::string& activity);
// Step results
std::vector<StepResult> stepResults() const;
void addStepResult(const StepResult& result);
// Callback registration
void setProgressCallback(std::function<void(double)> callback);
void setStepCallback(std::function<void(WorkflowStepType, double, const std::string&)> callback);
};Support for parallel workflow execution and datapoint management.
/**
* Parallel workflow execution for multiple datapoints
*/
class ParallelWorkflow {
public:
// Constructor
ParallelWorkflow();
ParallelWorkflow(int numParallel);
// Datapoint management
void addDatapoint(const WorkflowJSON& datapoint);
void addDatapoints(const std::vector<WorkflowJSON>& datapoints);
std::vector<WorkflowJSON> datapoints() const;
int numDatapoints() const;
// Execution settings
int numParallel() const;
void setNumParallel(int numParallel);
// Execute all datapoints
bool run();
bool run(const Path& outputDirectory);
// Results access
std::vector<StepResult> results() const;
StepResult result(int datapointIndex) const;
bool allSucceeded() const;
int numSucceeded() const;
int numFailed() const;
// Progress tracking
void setProgressCallback(std::function<void(int, int)> callback);
// Cancel execution
void cancel();
bool cancelled() const;
};
/**
* Distributed workflow execution
*/
class DistributedWorkflow {
public:
DistributedWorkflow();
// Cluster configuration
void setServerConfig(const std::string& serverUrl, int port);
void setAuthToken(const std::string& token);
// Job submission
std::string submitJob(const WorkflowJSON& workflow);
std::vector<std::string> submitJobs(const std::vector<WorkflowJSON>& workflows);
// Job monitoring
enum class JobStatus { Queued, Running, Completed, Failed, Cancelled };
JobStatus getJobStatus(const std::string& jobId);
std::map<std::string, JobStatus> getJobStatuses(const std::vector<std::string>& jobIds);
// Results retrieval
boost::optional<StepResult> getJobResult(const std::string& jobId);
std::vector<Path> getJobOutputFiles(const std::string& jobId);
// Job management
bool cancelJob(const std::string& jobId);
bool deleteJob(const std::string& jobId);
};#include <openstudio/workflow/OSWorkflow.hpp>
#include <openstudio/utilities/filetypes/WorkflowJSON.hpp>
using namespace openstudio;
// Create workflow configuration
WorkflowJSON workflowJSON;
// Set seed model and weather file
workflowJSON.setSeedFile(Path("baseline_model.osm"));
workflowJSON.setWeatherFile(Path("weather.epw"));
// Add model measures
MeasureStep improveLighting;
improveLighting.setMeasureDirName("improve_lighting_efficiency");
improveLighting.setArgument("lighting_power_density_reduction", 0.3);
workflowJSON.addMeasure(improveLighting);
MeasureStep improveHVAC;
improveHVAC.setMeasureDirName("improve_hvac_efficiency");
improveHVAC.setArgument("cop_improvement", 0.15);
workflowJSON.addMeasure(improveHVAC);
// Add reporting measure
MeasureStep energyReport;
energyReport.setMeasureDirName("energy_use_summary_report");
workflowJSON.addMeasure(energyReport);
// Set run options
RunOptions runOptions;
runOptions.setPreserveRunDir(true);
runOptions.setDebug(false);
workflowJSON.setRunOptions(runOptions);
// Execute workflow
OSWorkflow workflow;
workflow.setWorkflowJSON(workflowJSON);
std::cout << "Starting workflow execution..." << std::endl;
bool success = workflow.run();
if (success) {
std::cout << "Workflow completed successfully!" << std::endl;
// Access final results
boost::optional<SqlFile> sqlFile = workflow.sqlFile();
if (sqlFile) {
// Process simulation results
boost::optional<double> totalEnergy = sqlFile->totalSiteEnergy();
if (totalEnergy) {
std::cout << "Total site energy: " << *totalEnergy << " GJ" << std::endl;
}
}
} else {
std::cout << "Workflow failed!" << std::endl;
// Print errors
std::vector<LogMessage> errors = workflow.errors();
for (const auto& error : errors) {
std::cout << "Error: " << error.logMessage() << std::endl;
}
}#include <openstudio/workflow/OSWorkflow.hpp>
using namespace openstudio;
OSWorkflow workflow(Path("detailed_workflow.osw"));
// Execute workflow step by step with detailed monitoring
std::cout << "Step 1: Initialization..." << std::endl;
if (!workflow.runInitialization()) {
std::cout << "Initialization failed!" << std::endl;
return false;
}
std::cout << "Step 2: Applying model measures..." << std::endl;
if (!workflow.runOpenStudioMeasures()) {
std::cout << "Model measures failed!" << std::endl;
return false;
}
// Check intermediate model
boost::optional<Model> model = workflow.model();
if (model) {
std::vector<ThermalZone> zones = model->getConcreteModelObjects<ThermalZone>();
std::cout << "Model now has " << zones.size() << " thermal zones" << std::endl;
}
std::cout << "Step 3: Translating to EnergyPlus..." << std::endl;
if (!workflow.runTranslator()) {
std::cout << "Translation failed!" << std::endl;
return false;
}
std::cout << "Step 4: Running EnergyPlus simulation..." << std::endl;
if (!workflow.runEnergyPlus()) {
std::cout << "EnergyPlus simulation failed!" << std::endl;
return false;
}
std::cout << "Step 5: Processing results..." << std::endl;
if (!workflow.runReportingMeasures()) {
std::cout << "Reporting measures failed!" << std::endl;
return false;
}
std::cout << "Step 6: Cleanup..." << std::endl;
if (!workflow.runCleanup()) {
std::cout << "Cleanup failed!" << std::endl;
return false;
}
std::cout << "All workflow steps completed successfully!" << std::endl;#include <openstudio/workflow/ParallelWorkflow.hpp>
using namespace openstudio;
// Create base workflow
WorkflowJSON baseWorkflow;
baseWorkflow.setSeedFile(Path("base_model.osm"));
baseWorkflow.setWeatherFile(Path("weather.epw"));
// Create parametric study
ParallelWorkflow parallelWorkflow(4); // Use 4 parallel processes
std::vector<double> wwrValues = {0.2, 0.3, 0.4, 0.5}; // Window-to-wall ratios
std::vector<double> insulationValues = {0.1, 0.15, 0.2, 0.25}; // Insulation R-values
for (double wwr : wwrValues) {
for (double insulation : insulationValues) {
// Create datapoint workflow
WorkflowJSON datapoint = baseWorkflow;
// Add parametric measures
MeasureStep wwrMeasure;
wwrMeasure.setMeasureDirName("set_window_to_wall_ratio");
wwrMeasure.setArgument("wwr", wwr);
datapoint.addMeasure(wwrMeasure);
MeasureStep insulationMeasure;
insulationMeasure.setMeasureDirName("set_wall_insulation");
insulationMeasure.setArgument("r_value", insulation);
datapoint.addMeasure(insulationMeasure);
// Add to parallel execution
parallelWorkflow.addDatapoint(datapoint);
}
}
// Set progress callback
parallelWorkflow.setProgressCallback([](int completed, int total) {
double progress = (double)completed / total * 100.0;
std::cout << "Progress: " << completed << "/" << total
<< " (" << std::fixed << std::setprecision(1) << progress << "%)" << std::endl;
});
// Execute all datapoints
std::cout << "Starting parametric study with " << parallelWorkflow.numDatapoints() << " datapoints..." << std::endl;
bool success = parallelWorkflow.run(Path("parametric_results"));
if (success) {
std::cout << "Parametric study completed!" << std::endl;
std::cout << "Successful runs: " << parallelWorkflow.numSucceeded()
<< "/" << parallelWorkflow.numDatapoints() << std::endl;
// Process results from all datapoints
std::vector<StepResult> results = parallelWorkflow.results();
for (size_t i = 0; i < results.size(); ++i) {
if (results[i].status() == StepResult::Status::Success) {
std::cout << "Datapoint " << i << " completed successfully" << std::endl;
} else {
std::cout << "Datapoint " << i << " failed: " << results[i].statusDescription() << std::endl;
}
}
} else {
std::cout << "Parametric study failed!" << std::endl;
}#include <openstudio/workflow/WorkflowStep.hpp>
using namespace openstudio;
/**
* Custom workflow step for model validation
*/
class ModelValidationStep : public WorkflowStep {
public:
virtual std::string stepName() const override {
return "Model Validation";
}
virtual std::string stepDescription() const override {
return "Validate model geometry and HVAC systems";
}
virtual StepResult run(OSWorkflow& workflow) override {
StepResult result(StepResult::Status::Running);
boost::optional<Model> model = workflow.model();
if (!model) {
result.setStatus(StepResult::Status::Fail);
result.addError(LogMessage(LogLevel::Error, "No model available for validation"));
return result;
}
std::vector<std::string> validationIssues;
// Check for spaces without thermal zones
std::vector<Space> spaces = model->getConcreteModelObjects<Space>();
for (const auto& space : spaces) {
if (!space.thermalZone()) {
validationIssues.push_back("Space '" + space.name().get_value_or("Unnamed") +
"' is not assigned to a thermal zone");
}
}
// Check for surfaces without constructions
std::vector<Surface> surfaces = model->getConcreteModelObjects<Surface>();
for (const auto& surface : surfaces) {
if (!surface.construction()) {
validationIssues.push_back("Surface '" + surface.name().get_value_or("Unnamed") +
"' has no construction assigned");
}
}
// Report validation results
if (validationIssues.empty()) {
result.setStatus(StepResult::Status::Success);
result.setFinalCondition("Model validation passed with no issues");
} else {
result.setStatus(StepResult::Status::Success); // Warnings, not errors
for (const auto& issue : validationIssues) {
result.addWarning(LogMessage(LogLevel::Warn, issue));
}
result.setFinalCondition("Model validation completed with " +
std::to_string(validationIssues.size()) + " warnings");
}
return result;
}
virtual WorkflowStepType stepType() const override {
return WorkflowStepType::ModelMeasures; // Custom type could be added
}
};
// Usage in custom workflow
void runCustomWorkflow() {
OSWorkflow workflow(Path("model.osm"));
// Add custom validation step
ModelValidationStep validationStep;
StepResult validationResult = validationStep.run(workflow);
if (validationResult.status() != StepResult::Status::Success) {
std::cout << "Validation failed, aborting workflow" << std::endl;
return;
}
// Continue with standard workflow steps
workflow.runTranslator();
workflow.runEnergyPlus();
workflow.runReportingMeasures();
}Install with Tessl CLI
npx tessl i tessl/pypi-openstudio