class SaveCitySimResults(NotCacheable, Module): """ Save the results of a CitySim simulation run to a specified directory, renaming them... use the output from RunCitySim (citysim_basename, results_path) """ _input_ports = [IPort(name='source_path', signature='basic:Path'), IPort(name='citysim_basename', signature='basic:String'), IPort(name='target_path', signature='basic:Path'), IPort(name='target_basename', signature='basic:String')] def compute(self): import shutil source_path = self.getInputFromPort('source_path').name citysim_basename = self.getInputFromPort('citysim_basename') target_path = self.getInputFromPort('target_path').name target_basename = self.getInputFromPort('target_basename') shutil.copyfile(os.path.join(source_path, citysim_basename + '_TH.out'), os.path.join(target_path, target_basename + '_TH.out')) shutil.copyfile(os.path.join(source_path, citysim_basename + '.xml'), os.path.join(target_path, target_basename + '.xml'))
class SaveEnergyPlusResults(NotCacheable, Module): """ Save the results of an EnergyPlus run (.eso, .err file) to a specified directory, renaming them... use the output from RunEnergyPlus (results_path) as the input to source_path. use a directory name for target_path. use a basename for target_name (like: test01). """ _input_ports = [IPort(name='source_path', signature='basic:Path'), IPort(name='target_path', signature='basic:Path'), IPort(name='target_basename', signature='basic:String', optional=True)] def compute(self): import shutil source_path = self.get_input('source_path').name target_path = self.get_input('target_path').name target_basename = self.force_get_input('target_basename', None) if not target_basename: target_basename = replace_vars('$basename') if not os.path.exists(target_path): os.makedirs(target_path) shutil.copyfile(os.path.join(source_path, 'eplusout.eso'), os.path.join(target_path, target_basename + '.eso')) shutil.copyfile(os.path.join(source_path, 'eplusout.err'), os.path.join(target_path, target_basename + '.err')) shutil.copyfile(os.path.join(source_path, 'eplusout.rdd'), os.path.join(target_path, target_basename + '.rdd')) shutil.copyfile(os.path.join(source_path, 'in.idf'), os.path.join(target_path, target_basename + '.idf'))
class MapEnergyPlusGeometryToCitySim(NotCacheable, Module): """Go through each wall, roof, floor and shading surface in the energyplus geometry and map the vertices of the idf file back to the citysim file. Expects naming conventions to be those of CitySimToEnergyPlus: - Wall<CitySimID> - Roof<CitySimID> - Floor<CitySimID> - ShadingB<CitySimBuildingID>W<CitySimID> as a side effect, the epid tag is entered to all surfaces matched, this is a prerequisite for co-simulation.""" _input_ports = [IPort(name='citysim', signature=signature('CitySimXml')), IPort(name='idf', signature=signature('Idf'))] _output_ports = [OPort(name='citysim', signature=signature('CitySimXml'))] def compute(self): import mapepgeom reload(mapepgeom) citysim = self.get_input('citysim') idf = self.get_input('idf') result = mapepgeom.map_ep_geom(citysim=citysim, idf=idf) self.set_output('citysim', result)
class AddOutputVariableList(NotCacheable, Module): """adds an Output:Variable object to the IDF file for each variable name in `variables`. input and output are both strings containing the contents of the IDF file (as opposed to paths)""" _input_ports = [ IPort(name='idf', signature=signature('Idf')), IPort(name='key', signature='basic:String', default='*'), IPort(name='variables', signature='basic:List'), IPort(name='frequency', signature='basic:String', default='timestep')] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): idf = self.get_input('idf') key = self.get_input('key') variables = list(self.get_input('variables')) frequency = self.get_input('frequency') for variable in variables: output_variable = idf.newidfobject('OUTPUT:VARIABLE') output_variable.Key_Value = key output_variable.Variable_Name = variable output_variable.Reporting_Frequency = frequency # output the result self.set_output('idf', idf)
class WriteElementTree(NotCacheable, Module): """Take an ElementTree and write it out to disc.""" _input_ports = [IPort(name='file', signature='basic:File'), IPort(name='xml', signature=signature('XmlElementTree'))] def compute(self): fpath = self.get_input('file').name tree = self.get_input('xml') tree.write(fpath)
class RunCoSimulation(NotCacheable, Module): """Run the co-simulation EnergyPlus/CitySim""" _input_ports = [ IPort( name='citysim', signature=signature('CitySimXml')), IPort( name='fmu_path', signature='basic:Path'), IPort( name='cli_path', signature='basic:Path'), IPort( name='citysim_path', signature='basic:Path')] _output_ports = [ OPort( name='results_path', signature='basic:Path'), OPort( name='citysim_basename', signature='basic:String'), OPort( name='eplus_basename', signature='basic:String')] def compute(self): citysim_xml = self.get_input('citysim') fmu_path = self.get_input('fmu_path').name cli_path = self.getInputFromPort('cli_path').name citysim_path = self.get_input('citysim_path').name tmp = tempfile.mkdtemp( prefix=datetime.datetime.now().strftime('%Y.%m.%d.%H.%M.%S') + "_RunCoSimulation_") root = citysim_xml.getroot() root.find('Climate').set('location', cli_path) building = root.find(".//Building[@Simulate='ep']") assert len(building), 'CitySimXml does not contain Simulate="ep"' building.set('fmu', fmu_path) building.set('tmp', tmp) citysim_xml_fd, citysim_xml_path = tempfile.mkstemp( suffix='.xml', dir=tmp) with os.fdopen(citysim_xml_fd, 'w') as citysim_xml_file: etree.ElementTree(root).write(citysim_xml_file) subprocess.check_call([citysim_path, citysim_xml_path], cwd=tmp) self.set_output('results_path', basic.PathObject(tmp)) self.set_output('citysim_basename', os.path.basename(citysim_xml_path)[:-4]) self.set_output('eplus_basename', os.path.join('Output_EPExport_RevitToCitySim', os.path.basename(fmu_path)[:-4]))
class WriteIdf(NotCacheable, Module): """Take an IDF object and write it out to disc.""" _input_ports = [IPort(name='idf', signature=signature('Idf')), IPort(name='file', signature='basic:File')] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): idf = self.get_input('idf') fpath = self.get_input('file').name with open(fpath, 'w') as out: out.write(idf.idfstr()) self.set_output('idf', idf)
class RemoveIdfObject(NotCacheable, Module): """Delete an IdfObject from an IDF file.""" _input_ports = [IPort(name='idf', signature=signature('Idf')), IPort(name='type_name', signature='basic:String'), IPort(name='name', signature='basic:String')] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): idf = self.get_input('idf') type_name = self.get_input('type_name') name = self.get_input('name') obj = idf.getobject(type_name, name) if obj: idf.removeidfobject(obj) self.set_output('idf', idf)
class RunEnergyPlus(NotCacheable, Module): """ Run an IDF file with EnergyPlus in a temporary folder using a Weatherfile. The idf is expected to be a string containing the contents of the file. The epw_path is expected to be the path to a *.epw weather file. """ _input_ports = [ IPort(name='idf', signature=signature('Idf')), IPort(name='epw', signature='basic:File'), IPort(name='idd', signature='basic:File', optional=True), IPort(name='energyplus', signature='basic:File', optional=True), IPort(name='copy_list', signature='basic:String', optional=True)] _output_ports = [OPort(name='results', signature='basic:Path')] def compute(self): import shutil idf = self.get_input('idf') idd_path = force_get_path(self, 'idd', find_idd()) epw_path = self.get_input('epw').name energyplus_path = force_get_path(self, 'energyplus', find_energyplus()) tmp = tempfile.mkdtemp( prefix=datetime.datetime.now().strftime('%Y.%m.%d.%H.%M.%S') + "_RunEnergyPlus_") idf_path = os.path.join(tmp, 'in.idf') with open(idf_path, 'w') as out: out.write(idf.idfstr()) shutil.copy(idd_path, tmp) shutil.copyfile(epw_path, os.path.join(tmp, 'in.epw')) copy_list = self.force_get_input('copy_list', None) if copy_list: relnames = copy_list.split(';') from vistrails.core import application app = application.get_vistrails_application() wf_path = app.get_vistrail().locator.name wf_folder = os.path.dirname(wf_path) for relname in relnames: absolute_path = os.path.normpath( os.path.join(wf_folder, relname)) shutil.copy(absolute_path, tmp) subprocess.check_call([energyplus_path], cwd=tmp) self.set_output('results', basic.PathObject(tmp))
class MergeIdf(NotCacheable, Module): """Merges two idf files, left and right. Objects in right overwrite objects of same type / name in left. Left is modyfied by this. And left is returned.""" _input_ports = [IPort(name='left', signature=signature('Idf')), IPort(name='right', signature=signature('Idf'))] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): left = self.get_input('left') right = self.get_input('right') for obj_type in right.idfobjects.keys(): for obj in right.idfobjects[obj_type]: if left.getobject(obj_type, obj.Name): left.removeidfobject(left.getobject(obj_type, obj.Name)) left.copyidfobject(obj) self.set_output('idf', left)
class XPathSetAttribute(NotCacheable, Module): """applies an XPATH expression to a string containing xml code. The result is a list of matches, each converted back to strings.""" _input_ports = [ IPort(name='xml', signature=signature('XmlElementTree')), IPort(name='xpath', signature='basic:String'), IPort(name='attrib', signature='basic:String'), IPort(name='new_value', signature='basic:String')] _output_ports = [OPort(name='xml', signature=signature('XmlElementTree'))] def compute(self): tree = self.get_input('xml') xpath = self.get_input('xpath') attrib = self.get_input('attrib') new_value = self.get_input('new_value') for element in tree.findall(xpath): element.set(attrib, new_value) self.set_output('xml', tree)
class CastToCitySimXml(NotCacheable, Module): """Cast an XmlElemntTree back to CitySimXml""" _input_ports = [IPort(name='xml', signature=signature('XmlElementTree'))] _output_ports = [OPort(name='citysim', signature=signature('CitySimXml'))] def compute(self): citysim = self.get_input('xml') self.set_output('citysim', citysim)
class Idf(NotCacheable, Module): """Wraps an eppy IDF3 object for use in the VisTrails system. the default EnergyPlus IDD file will be used if none is specified. This is done by looking through $PATH to find the EnergyPlus executable and use the `Energy+.idd` file in the same folder. CONVENTION: ports with type Idf exchange eppy.IDF instances.""" _input_ports = [ IPort(name='idf', signature='basic:Path', optional=True), IPort(name='idd', signature='basic:Path'), ] _output_ports = [OPort(name='idf', signature=signature('Idf'))] # noqa def __init__(self): super(Idf, self).__init__() self.idf = None def compute(self): from eppy.modeleditor import IDF, IDDAlreadySetError from StringIO import StringIO idf = self.force_get_input('idf', None) idd = self.get_input('idd').name try: IDF.setiddname(idd) except IDDAlreadySetError: pass if idf: idf_file = open(idf.name, 'r') else: idf_file = StringIO('') self.idf = IDF(idf_file) self.set_output('idf', self.idf)
class SaveCoSimResults(NotCacheable, Module): """ Save the results of a co-simulation run (.eso, .err file, but also the CitySim stuff) to a specified directory, renaming them... use the output from RunCoSimulation (citysim_basename, results_path, eplus_basename) if the target_basename is not set, the basename of the workflow is used... """ _input_ports = [IPort(name='source_path', signature='basic:Path'), IPort(name='citysim_basename', signature='basic:String'), IPort(name='eplus_basename', signature='basic:String'), IPort(name='target_path', signature='basic:Path'), IPort(name='target_basename', signature='basic:String', optional=True)] def compute(self): import shutil source_path = self.get_input('source_path').name citysim_basename = self.get_input('citysim_basename') eplus_basename = self.get_input('eplus_basename') target_path = self.get_input('target_path').name target_basename = self.force_get_input('target_basename', None) if not target_basename: target_basename = replace_vars('$basename') if not os.path.exists(target_path): os.makedirs(target_path) shutil.copyfile(os.path.join(source_path, eplus_basename + '.eso'), os.path.join(target_path, target_basename + '.eso')) shutil.copyfile(os.path.join(source_path, eplus_basename + '.err'), os.path.join(target_path, target_basename + '.err')) shutil.copyfile(os.path.join(source_path, eplus_basename + '.rdd'), os.path.join(target_path, target_basename + '.rdd')) shutil.copyfile(os.path.join(source_path, eplus_basename + '.idf'), os.path.join(target_path, target_basename + '.idf')) shutil.copyfile(os.path.join(source_path, citysim_basename + '_TH.out'), os.path.join(target_path, target_basename + '_TH.out')) shutil.copyfile(os.path.join(source_path, citysim_basename + '.xml'), os.path.join(target_path, target_basename + '.xml'))
class AddIdealLoadsAirSystem(NotCacheable, Module): """add the IdealLoadsAirSystem to the zones in the building. This is already expanded, similar to what ExpandObjects.exe does. this adds an HVAC system to the output of the CitySimToEnergyPlus module. it requires a VENTILATIONSCHEDULE to be defined as a fraction of the air_changes_per_hour to use.""" _input_ports = [IPort(name='idf', signature=signature('Idf')), IPort(name='air_changes_per_hour', signature='basic:Float', optional=True, default=0.7), IPort(name='cooling_system', signature='basic:Boolean', optional=True, default=True), IPort(name='sensible_heat_recovery_effectiveness', signature='basic:Float', optional=True, default=0.2)] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): import addidealloads reload(addidealloads) idf = self.get_input('idf') idf = addidealloads.add_ideal_loads_air_system( idf, air_changes_per_hour=self.get_input('air_changes_per_hour'), cooling_system=self.get_input('cooling_system'), sensible_heat_recovery_effectiveness=self.get_input( 'sensible_heat_recovery_effectiveness')) self.set_output('idf', idf) pass
class SimplifyShading(NotCacheable, Module): """Simplify shading surfaces in the EnergyPlus model by joining rectangular adjacent, coplanar surfaces""" _input_ports = [IPort(name='idf', signature=signature('Idf'))] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): import shading reload(shading) idf = self.get_input('idf') idf = shading.simplify(idf) self.set_output('idf', idf)
class RemoveIdfObjectList(NotCacheable, Module): """Delete a list of IdfObjects from an IDF file. The list is given as the path to a CSV file with two columns, the first is the IDF key name (e.g. 'SHADING:BUILDING:DETAILED'), the second is the Name fields of the object to delete.""" _input_ports = [IPort(name='idf', signature=signature('Idf')), IPort(name='csv_path', signature='basic:File')] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): import csv idf = self.get_input('idf') csv_path = self.get_input('csv_path').name with open(csv_path, 'r') as f: csv_reader = csv.reader(f) for key, name in csv_reader: obj = idf.getobject(key, name) if obj: idf.removeidfobject(obj) self.set_output('idf', idf)
class GenerateIdf(NotCacheable, Module): """Send a ModelSnapshot to the BIM/DPV to be converted to an IDF file.""" _input_ports = [IPort(name='snapshot', signature=signature('ModelSnapshot')), # noqa IPort(name='url', signature='basic:String', default='http://localhost:8014/idf', optional=True), IPort(name='idd', signature='basic:Path', optional=True)] _output_ports = [OPort(name='idf', signature=signature('Idf'))] # noqa def __init__(self): super(GenerateIdf, self).__init__() self.idf = None def compute(self): import requests from eppy.modeleditor import IDF, IDDAlreadySetError from StringIO import StringIO url = self.get_input('url') snapshot = self.get_input('snapshot') r = requests.post(url, etree.tostring(snapshot)) if r.ok: idf_file = StringIO(r.text.strip().replace('\r\n', '\n')) idd = force_get_path(self, 'idd', find_idd()) try: IDF.setiddname(idd) except IDDAlreadySetError: pass self.idf = IDF(idf_file) self.set_output('idf', self.idf) else: raise Exception('Could not request IDF from BIM')
class RunCitySim(NotCacheable, Module): """Run just the CitySim simulation (no co-simulation)""" _input_ports = [IPort(name='citysim_xml', signature=signature('CitySimXml')), IPort(name='cli_path', signature='basic:File'), IPort(name='citysim_exe', signature='basic:File', label='CitySim.exe')] _output_ports = [OPort(name='results_path', signature='basic:Path'), OPort(name='citysim_basename', signature='basic:String')] def compute(self): citysim_xml = self.get_input('citysim_xml') cli_path = self.get_input('cli_path').name citysim_exe = self.get_input('citysim_exe').name tmp = tempfile.mkdtemp( prefix=datetime.datetime.now().strftime('%Y.%m.%d.%H.%M.%S') + "_RunCitySim_") root = citysim_xml.getroot() root.find('Climate').set('location', cli_path) # make sure we turn off co-simulation buildings: for building in root.findall(".//Building[@Simulate='ep']"): building.set('Simulate', 'true') citysim_xml_fd, citysim_xml_path = tempfile.mkstemp( suffix='.xml', dir=tmp) with os.fdopen(citysim_xml_fd, 'w') as citysim_xml_file: citysim_xml.write(citysim_xml_file) subprocess.check_call([citysim_exe, citysim_xml_path], cwd=tmp) self.set_output('results_path', basic.PathObject(tmp)) self.set_output('citysim_basename', os.path.basename(citysim_xml_path)[:-4])
class CitySimToEnergyPlus(NotCacheable, Module): """Extract an EnergyPlus model from a CitySim scene. Uses the CitySim building id to find the building to extract and uses a template for the single zone HVAC system added. The script adds the materials and constructions and surfaces to the template.""" _input_ports = [IPort(name='citysim', signature=signature('CitySimXml')), IPort(name='building', signature='basic:String'), IPort(name='template', signature=signature('Idf'))] _output_ports = [OPort(name='idf', signature=signature('Idf'))] def compute(self): import citysimtoenergyplus reload(citysimtoenergyplus) citysim = self.get_input('citysim') building = self.get_input('building') template = self.get_input('template') idf = citysimtoenergyplus.extractidf( citysim=citysim, building=building, template=template) self.set_output('idf', idf)
class CitySimXml(XmlElementTree): """Wraps the XML file used to describe a CitySim scene for use in the VisTrails system. CONVENTION: ports with type CitySimXml exchange xml.etree.ElementTree objects.""" _input_ports = [IPort(name='file', signature='basic:File')] _output_ports = [OPort(name='citysim_xml', signature=signature('CitySimXml'))] # noqa def compute(self): path = self.get_input('file').name scene = etree.parse(open(path, 'r')) self.set_output('citysim_xml', scene)
class EnergyPlusToFmu(NotCacheable, Module): """Run the EnergyPlusToFMU.py script. Use VisTrails variables to configure where the script is. """ _input_ports = [ IPort( name='idf', signature=signature('Idf')), IPort(name='epw_path', signature='basic:Path'), IPort(name='EnergyPlusToFmu_path', signature='basic:Path'), IPort(name='idd_path', signature='basic:Path')] _output_ports = [ OPort(name='fmu_path', signature='basic:Path')] def compute(self): try: ep2fmu_path = self.get_input('EnergyPlusToFmu_path').name idd_path = self.get_input('idd_path').name idf = self.get_input('idf') epw_path = self.get_input('epw_path').name idf_fd, idf_path = tempfile.mkstemp(suffix='.idf') with os.fdopen(idf_fd, 'w') as idf_file: idf_file.write(idf.idfstr()) cwd = tempfile.gettempdir() call_args = ['python', ep2fmu_path, '-i', idd_path, '-d', '-L', '-w', epw_path, idf_path] print call_args subprocess.check_call(call_args, cwd=cwd) self.set_output('fmu_path', basic.PathObject(idf_path[:-4] + '.fmu')) except: raise
class SimplifyCitySimGeometry(NotCacheable, Module): """Simplify CitySimXml geometry by joining rectangular adjacent, coplanar surfaces that have the same construction and belong to the same Zone in the same Building.""" _input_ports = [IPort(name='citysim_xml', signature=signature('CitySimXml'))] _output_ports = [OPort(name='citysim_xml', signature=signature('CitySimXml'))] def compute(self): import simplifycitysimgeometry reload(simplifycitysimgeometry) citysim_xml = self.get_input('citysim_xml') citysim_xml = simplifycitysimgeometry.simplify(citysim_xml) self.set_output('citysim_xml', citysim_xml)
class XmlElementTree(NotCacheable, Module): """A module to use as output and input ports that contain XML data. CONVENTION: ports with type XmlElementTree exchange xml.etree.ElementTree objects.""" _input_ports = [IPort(name='file', signature='basic:File', label='An XML file to read')] _output_ports = [OPort(name='xml', signature=signature('XmlElementTree'))] # noqa def compute(self): path = self.get_input('file') xml = etree.parse(open(path, 'r')) self.set_output('xml', xml)
class ModelSnapshot(XmlElementTree): """Wraps an XML serialization of a DPV ModelSnapshot object for use in the VisTrails system. CONVENTION: ports with type ModelSnapshot exchange xml.etree.ElementTree objects.""" _input_ports = [IPort(name='file', signature='basic:File', label='An XML file to read')] _output_ports = [OPort(name='snapshot', signature=signature('ModelSnapshot'))] # noqa def compute(self): path = self.get_input('file') snapshot = etree.parse(open(path, 'r')) self.set_output('snapshot', snapshot)
class AddFmuToIdfLwr(NotCacheable, Module): """ Augment the IDF file with the information necessary for EnergyPlusToFMU and implement the CitySim/EnergyPlus interface. Includes the interface for LWR (replaces AddFmuToIdf) """ _input_ports = [IPort( name='idf', signature=signature('Idf'))] _output_ports = [OPort( name='idf', signature=signature('Idf'))] def compute(self): import addfmutoidf reload(addfmutoidf) idf = self.get_input('idf') idf = addfmutoidf.process_idf(idf) self.set_output('idf', idf)
class RelativePath(NotCacheable, Module): """resolve a string denoting a path relative to the current vistrails document to a Path object for input into other modules.""" _input_ports = [IPort(name='relative_path', signature='basic:String')] _output_ports = [OPort(name='absolute_path', signature='basic:Path')] def compute(self): from vistrails.core import application app = application.get_vistrails_application() wf_path = app.get_vistrail().locator.name wf_folder = os.path.dirname(wf_path) relative_path = self.get_input('relative_path') relative_path = replace_vars(relative_path) absolute_path = os.path.normpath( os.path.join(wf_folder, relative_path)) self.set_output('absolute_path', basic.PathObject(absolute_path))
class AcquireModelSnapshot(NotCacheable, Module): """AcquireModelSnapshot acquires an xml serialization of a ModelSnapshot from Revit Architecture using the DesignPerformanceViewer plugin. It is dependant on the BIM_URL configuration parameter, that points to the DPV web server (typically localhost on port 8010, but the port can be changed in the DPV configuration file).""" _input_ports = [IPort(name='url', signature='basic:String', label='URL of DPV BIM snapshot extraction', default='http://localhost:8010/snapshot', optional=True)] _output_ports = [OPort(name='snapshot', signature=signature('ModelSnapshot'))] # noqa def compute(self): url = self.get_input('url') snapshot = etree.parse(url) self.set_output('snapshot', snapshot)