webgme-gridlabd
Version:
Metamodel, visualization, and model generators for gridlab-d in WebGME. Allows graphical model-driven development and simulation of power grids and power generation / transmission / distribution / storage systems.
238 lines (203 loc) • 6.57 kB
JavaScript
/*globals define*/
/*jshint node:true, browser:true*/
/**
* Generated by PluginGenerator 0.14.0 from webgme on Mon Apr 04 2016 12:18:55 GMT-0700 (PDT).
*/
define([
'plugin/PluginConfig',
'text!./metadata.json',
'plugin/PluginBase',
'gridlabd/meta',
'gridlabd/modelLoader',
'gridlabd/renderer',
'q'
], function (
PluginConfig,
pluginMetadata,
PluginBase,
MetaTypes,
loader,
renderer,
Q) {
'use strict';
pluginMetadata = JSON.parse(pluginMetadata);
/**
* Initializes a new instance of SimulateWithGridlabD.
* @class
* @augments {PluginBase}
* @classdesc This class represents the plugin SimulateWithGridlabD.
* @constructor
*/
var SimulateWithGridlabD = function () {
// Call base class' constructor.
PluginBase.call(this);
this.pluginMetadata = pluginMetadata;
this.metaTypes = MetaTypes;
};
/**
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
* This is also available at the instance at this.pluginMetadata.
* @type {object}
*/
SimulateWithGridlabD.metadata = pluginMetadata;
// Prototypal inheritance from PluginBase.
SimulateWithGridlabD.prototype = Object.create(PluginBase.prototype);
SimulateWithGridlabD.prototype.constructor = SimulateWithGridlabD;
SimulateWithGridlabD.prototype.notify = function(level, msg) {
var self = this;
var prefix = self.projectId + '::' + self.projectName + '::' + level + '::';
if (level=='error')
self.logger.error(msg);
else if (level=='debug')
self.logger.debug(msg);
else if (level=='info')
self.logger.info(msg);
else if (level=='warning')
self.logger.warn(msg);
self.createMessage(self.activeNode, msg, level);
self.sendNotification(prefix+msg);
};
/**
* Main function for the plugin to execute. This will perform the execution.
* Notes:
* - Always log with the provided logger.[error,warning,info,debug].
* - Do NOT put any user interaction logic UI, etc. inside this method.
* - callback always has to be called even if error happened.
*
* @param {function(string, plugin.PluginResult)} callback - the result callback
*/
SimulateWithGridlabD.prototype.main = function (callback) {
// Use self to access core, project, result, logger etc from PluginBase.
// These are all instantiated at this point.
var self = this,
modelNode;
self.result.success = false;
if (typeof WebGMEGlobal !== 'undefined') {
var msg = 'You must run this plugin on the server!';
self.notify('error', msg);
callback(new Error(msg), self.result);
}
self.updateMETA(self.metaTypes);
// What did the user select for our configuration?
var currentConfig = self.getCurrentConfig();
self.returnZip = currentConfig.returnZip;
modelNode = self.activeNode;
self.modelName = self.core.getAttribute(modelNode, 'name');
self.fileName = self.modelName + '.glm';
var path = require('path');
var filendir = require('filendir');
self.root_dir = path.join(process.cwd(),
'generated',
self.project.projectId,
self.branchName,
'models');
return loader.loadModel(self.core, modelNode, true, true)
.then(function(powerModel) {
self.powerModel = powerModel;
})
.then(function() {
return self.renderModel();
})
.then(function() {
return self.writeInputs();
})
.then(function() {
return self.runSimulation();
})
.then(function() {
return self.generateBlobArtifacts();
})
.then(function() {
self.result.success = true;
self.createMessage(self.activeNode, 'Simulation Complete.');
callback(null, self.result);
})
.catch(function(err) {
self.result.success = false;
self.createMessage(self.activeNode, err, 'error');
callback(err, self.result);
});
};
SimulateWithGridlabD.prototype.renderModel = function() {
var self = this;
self.notify('info', 'Rendering GLM');
self.fileData = renderer.renderGLM(self.powerModel, self.core, self.META);
};
SimulateWithGridlabD.prototype.writeInputs = function() {
var self = this,
basePath = self.root_dir,
inputFiles = {},
fs = require('fs'),
path = require('path'),
filendir = require('filendir');
inputFiles[self.fileName] = self.fileData;
self.notify('info', 'Creating input files');
var fileNames = Object.keys(inputFiles);
var tasks = fileNames.map((fileName) => {
var deferred = Q.defer();
var data = inputFiles[fileName];
filendir.writeFile(path.join(basePath, fileName), data, (err) => {
if (err) {
deferred.reject('Couldnt write ' + fileName + ': ' + err);
}
else {
deferred.resolve();
}
});
return deferred.promise;
});
return Q.all(tasks)
.then(function() {
self.notify('info', 'Generated artifacts.');
});
};
SimulateWithGridlabD.prototype.runSimulation = function() {
var self = this;
var path = require('path');
var cp = require('child_process');
self.notify('info', 'Starting Simulation');
var deferred = Q.defer();
var fname = path.join(self.root_dir, self.fileName);
self.sim_stdout = '';
self.sim_stderr = '';
self.simProcess = cp.spawn('gridlabd', [fname], {
cwd: self.root_dir
});
self.simProcess.stdout.on('data', (data) => {
self.sim_stdout += data;
});
self.simProcess.stderr.on('data', (data) => {
self.sim_stderr += data;
});
self.simProcess.on('close', (code) => {
self.notify('info', 'Simulation exited with code: ' + code);
deferred.resolve();
});
self.simProcess.on('error', (err) => {
deferred.reject('Couldnt run simulation: ' + err);
});
return deferred.promise;
};
SimulateWithGridlabD.prototype.generateBlobArtifacts = function() {
var self = this;
if (!self.returnZip) {
self.notify('info', 'User did not request the output to be returned.');
return;
}
var path = require('path');
var stdoutFile = self.modelName + '.stdout';
var stderrFile = self.modelName + '.stderr';
self.notify('info', 'Returning output to user.');
return self.blobClient.putFile(stdoutFile, self.sim_stdout)
.then(function (hash) {
self.result.addArtifact(hash);
})
.then(function() {
return self.blobClient.putFile(stderrFile, self.sim_stderr);
})
.then(function (hash) {
self.result.addArtifact(hash);
});
};
return SimulateWithGridlabD;
});