def simulate(self, terminate_after_warmup=False): """ Run the whole simulation once. If user use this method instead of the reset function, the user need to provide the Agent. :parameter terminate_after_warmup: True if the simulation should terminate after the warmup. :return: None. """ from pyenergyplus.api import EnergyPlusAPI self.replay.set_ignore(self.state_modifier.get_ignore_by_checkpoint()) if not self.use_lock: self._init_simulation() # for entry in self.zone_names: # print(entry) # self.current_handle["temperature"][entry] = \ # self.api.exchange.get_variable_handle("Zone Air Temperature", entry) # self.current_handle["temperature"] = self.api.exchange.get_variable_handle("SITE OUTDOOR AIR DRYBULB TEMPERATURE", "ENVIRONMENT") # self.current_handle["energy"] = self.api.exchange.get_meter_handle("Electricity:Facility") self.api = EnergyPlusAPI() if not terminate_after_warmup: self.api.runtime.callback_after_new_environment_warmup_complete( self._initialization) self.api.runtime.callback_begin_system_timestep_before_predictor( self._step_callback) else: self.api.runtime.callback_begin_new_environment( self._generate_output_files) self.api.runtime.run_energyplus(self.run_parameters)
def main(): parser = argparse.ArgumentParser() parser.add_argument('ipath') parser.add_argument('-w', required=True) parser.add_argument('-n', type=int) parser.add_argument('-f', action='store_true', default=False) args = parser.parse_args() api = EnergyPlusAPI() state = api.state_manager.new_state() if args.ipath.endswith('.idf'): raise RuntimeError('.idf not supported') logger = logging.getLogger('frads') formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_handler = logging.StreamHandler() logger.setLevel(logging.DEBUG) console_handler.setLevel(logging.DEBUG) console_handler.setFormatter(formatter) logger.addHandler(console_handler) init_radiance(args.ipath, run=True, nproc=args.n, overwrite=args.f) # api.runtime.callback_end_zone_timestep_after_zone_reporting( # time_step_handler) api.runtime.callback_begin_zone_timestep_before_init_heat_balance( state, time_step_handler) #api.exchange.request_variable("SITE DIRECT SOLAR RADIATION RATE PER AREA", "ENVIRONMENT") #api.exchange.request_variable("SITE DIFFUSE SOLAR RADIATION RATE PER AREA", "ENVIRONMENT") eplus_cmd = ['-w', args.w, args.ipath] api.runtime.run_energyplus(eplus_cmd)
def run(self): if os.path.exists("/eplus/installs/EnergyPlus-9-3-0/"): # if I am running locally, just use my local install ep_install_path = "/eplus/installs/EnergyPlus-9-3-0/" else: file_name = 'EnergyPlus-9.3.0-baff08990c-Linux-x86_64.tar.gz' url = 'https://github.com/NREL/EnergyPlus/releases/download/v9.3.0/%s' % file_name extract_dir = Path(tempfile.mkdtemp()) ep_tar_path = extract_dir / file_name _, headers = urllib.request.urlretrieve(url, ep_tar_path) extract_command = ['tar', '-xzf', file_name, '-C', extract_dir] check_call(extract_command, cwd=extract_dir) ep_install_path = extract_dir / 'EnergyPlus-9.3.0-baff08990c-Linux-x86_64' sys.path.insert(0, str(ep_install_path)) # noinspection PyUnresolvedReferences from pyenergyplus.api import EnergyPlusAPI # set up a run dir this_file_path = Path(os.path.realpath(__file__)) run_folder_name = datetime.now().strftime("%Y%m%d_%H%M%S") idf_run_dir = this_file_path.parent / 'runs' / run_folder_name os.makedirs(idf_run_dir) # build out the IDF d = Model() full_idf_string = d.idf_string idf_path = idf_run_dir / 'emerald.idf' with open(idf_path, 'w') as f: f.write(full_idf_string) # run the IDF using the EnergyPlus API (cool!) api = EnergyPlusAPI() print("Running in: " + str(idf_run_dir)) return_val = api.runtime.run_energyplus([ '-w', str(WeatherManager.path_to_tmy_okc_epw_file()), '-d', str(idf_run_dir), str(idf_path) ]) if return_val != 0: print("EnergyPlus failed - aborting") exit(return_val) # get EnergyPlus outputs sql_file = idf_run_dir / 'eplusout.sql' op = OutputProcessor(sql_file) print("EPLUS ELECTRICITY (kWh): ") print(op.monthly_electricity) # generate validation data v = ValidationManager() monthly_electricity = v.process_2019_raw_into_monthly() print("ACTUAL ELECTRICITY (kWh): ") print(monthly_electricity) # need gnuplot installed on the machine for this: r = ResultsAnalyzer(op.monthly_electricity, monthly_electricity) r.plot_electricity()
def __init__(self): """ Constructor for the Plugin interface base class. Does not take any arguments, initializes member variables. Note API is available on derived classes through: - self.api.functional provides access to a functional API class, instantiated and ready to go - self.api.exchange provides access to a data exchange API class, instantiated and ready to go """ super().__init__() self.api = EnergyPlusAPI(True) self.data = {}
def simulate(self): from pyenergyplus.api import EnergyPlusAPI self.idf.saveas("input.idf") self.api = EnergyPlusAPI() self.api.runtime.callback_after_new_environment_warmup_complete( self.env_make) self.api.runtime.callback_begin_system_timestep_before_predictor( self.env_reset) # self.api.runtime.callback_begin_zone_timestep_before_init_heat_balance(self.env_action) # self.api.runtime.callback_after_predictor_before_hvac_managers(self.env_action) self.api.runtime.callback_begin_system_timestep_before_predictor( self.env_action) self.api.runtime.callback_end_zone_timestep_after_zone_reporting( self.env_step) status = self.api.runtime.run_energyplus(self.run_parameters) print('Simulator return status: ', status)
def simulate(self): from pyenergyplus.api import EnergyPlusAPI self.idf.saveas("input.idf") self.zone_names = self.get_available_names_under_group("ZONE") self.get_thermal_names() # for name in self.zone_names: # print(name) # self.current_handle["temperature"][name] = \ # self.api.exchange.get_variable_handle("Zone Air Temperature", name) # self.current_handle["temperature"] = self.api.exchange.get_variable_handle( # "SITE OUTDOOR AIR DRYBULB TEMPERATURE", "ENVIRONMENT") # self.current_handle["electricity"] = self.api.exchange.get_meter_handle("Electricity:Facility") self.api = EnergyPlusAPI() # self.api.runtime.callback_begin_new_environment(self.initialization) self.api.runtime.callback_after_new_environment_warmup_complete(self.initialization) self.api.runtime.callback_begin_system_timestep_before_predictor(self.step) status = self.api.runtime.run_energyplus(self.run_parameters) print('Simulator return status: ', status) # self.api.runtime.clear_all_states()
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import sys from pyenergyplus.api import EnergyPlusAPI api = EnergyPlusAPI() state = api.state_manager.new_state() # GLYCOL TESTS glycol = api.functional.glycol(state, u"water") for t in [5.0, 15.0, 25.0]: cp = glycol.specific_heat(state, t) rho = glycol.density(state, t) k = glycol.conductivity(state, t) viscosity = glycol.viscosity(state, t) print("Python API Test: Calculated properties at T=%s: %f, %f, %f, %f" % (t, cp, rho, k, viscosity)) glycol.delete(state) # REFRIGERANT TESTS refrigerant = api.functional.refrigerant(state, "steam")
if self.count % self.plot_update_interval == 0: self.df = pd.DataFrame( { 'OA Temp': self.y_outdoor, 'Zone Temp': self.y_zone, 'Htg Tstat': self.y_htg, 'Clg Tstat': self.y_clg, 'Zone RH': self.y_rh, # CJE }, index=self.x) self.update_line() ################################## api = EnergyPlusAPI() api1 = EnergyPlusAPI() # global var state = api.state_manager.new_state() # TODO state1 = api1.state_manager.new_state() filename_to_run = project_path + 'test_CJE_act.idf' g = TwoGraphs(filename_to_run=filename_to_run, zone_name=openstudio.model.getThermalZones(m)[0].nameString()) g1 = TwoGraphs(filename_to_run=filename_to_run, zone_name=openstudio.model.getThermalZones(m)[0].nameString()) api.runtime.callback_begin_zone_timestep_after_init_heat_balance( state, g.callback_function) # api.runtime.callback_after_predictor_after_hvac_managers(state, g.callback_function) # api1.runtime.callback_begin_zone_timestep_after_init_heat_balance(state1, g1.callback_function)
def __init__(self, config): cur_dir = os.path.dirname(__file__) self.idf_file = cur_dir + '/buildings/MediumOffice/RefBldgMediumOfficeNew2004_Chicago.idf' # EnergyPlus weather file if 'weather_file' in config: self.weather_file = cur_dir + '/' + config['weather_file'] else: self.weather_file = cur_dir + '/weather/SPtMasterTable_587017_2012_amy.epw' self.eplus_path = config['eplus_path'] # EnergyPlus number of timesteps in an hour if 'timestep' in config: self.epTimeStep = config['timestep'] else: self.epTimeStep = 1 # EnergyPlus number of simulation days if 'days' in config: self.simDays = config['days'] else: self.simDays = 1 self.energy_temp_penalty_ratio = config['energy_temp_penalty_ratio'] self.multi_zone_control = config['multi_zone_control'] # Number of steps per day self.DAYSTEPS = int(24 * self.epTimeStep) # Total number of steps self.MAXSTEPS = int(self.simDays * self.DAYSTEPS) # Time difference between each step in seconds self.deltaT = (60 / self.epTimeStep) * 60 # Current step of the simulation self.kStep = 0 # actions are all the control inputs self.min_heat_setpoint = 0.15 # min HTGSETP_SCH self.max_heat_setpoint = 0.22 # max HTGSETP_SCH self.min_cool_setpoint = 0.22 # min CLGSETP_SCH self.max_cool_setpoint = 0.30 # max CLGSETP_SCH self.api = EnergyPlusAPI() self.zones = [ 'Core_bottom', 'Core_mid', 'Core_top', 'Perimeter_bot_ZN_1', 'Perimeter_bot_ZN_2', 'Perimeter_bot_ZN_3', 'Perimeter_bot_ZN_4', 'Perimeter_mid_ZN_1', 'Perimeter_mid_ZN_2', 'Perimeter_mid_ZN_3', 'Perimeter_mid_ZN_4', 'Perimeter_top_ZN_1', 'Perimeter_top_ZN_2', 'Perimeter_top_ZN_3', 'Perimeter_top_ZN_4' ] self.eplus_output_vars = ( [('Air System Total Heating Energy', f'VAV_{i}') for i in range(1, 4)] + [(f'Site Outdoor Air {cond}bulb Temperature', 'Environment') for cond in ['Dry', 'Wet']] + [('Zone Mean Air Temperature', zone) for zone in self.zones]) self.eplus_actuator_vars = [ ('Schedule:Constant', 'Schedule Value', f'{level}_SCH_{zone}') for zone in self.zones for level in ['HTGSETP', 'CLGSETP'] ] min_setpoints = [(self.min_heat_setpoint, self.min_cool_setpoint) for _ in self.eplus_actuator_vars] max_setpoints = [(self.max_heat_setpoint, self.max_cool_setpoint) for _ in self.eplus_actuator_vars] if self.multi_zone_control: self.action_space = spaces.Box( np.array(list(itertools.chain(*min_setpoints))), np.array(list(itertools.chain(*max_setpoints))), dtype=np.float32) else: self.action_space = spaces.Box( np.array([self.min_heat_setpoint, self.min_cool_setpoint]), np.array([self.max_heat_setpoint, self.max_cool_setpoint]), dtype=np.float32) self.min_zone_temp = 0 self.max_zone_temp = 0.40 self.min_total_power = 0 self.max_total_power = 1e8 self.desired_zone_temp = 0.22 self.observation_space = spaces.Box( np.array([0, 0, 0, -0.5, -0.5] + [self.min_zone_temp for _ in self.eplus_output_vars[5:]]), np.array([1, 1, 1, 0.5, 0.5] + [self.max_zone_temp for _ in self.eplus_output_vars[5:]]), dtype=np.float32) self.prev_output = tuple([0.5, 0.5, 0.5, 0.15, 0.15] + [ np.mean([self.min_zone_temp, self.max_zone_temp]) for _ in self.eplus_output_vars[5:] ]) self.prev_control = tuple([self.desired_zone_temp for _ in self.zones]) self.eplus_th = None self.control_queue = Queue() self.output_queue = Queue() self.simulation_complete = False self.is_data_ready = False self.is_warmup_done = False
def setUpClass(cls): """ A class method called before tests in an individual class are run """ cls.api = EnergyPlusAPI()
def run_energyplus(self, isIP, run_directory, file_name, args, by_api): full_file_path = os.path.join(run_directory, file_name) file_name_no_ext, extension = os.path.splitext(file_name) # the following is the same when .idf is used if 'workflow location' in args: energyplus_root_folder, _ = os.path.split( args['workflow location']) # Run EnergyPlus binary if platform.system() == 'Windows': energyplus_binary = os.path.join(energyplus_root_folder, 'energyplus.exe') else: energyplus_binary = os.path.join(energyplus_root_folder, 'energyplus') if not os.path.exists(energyplus_binary): return EPLaunchWorkflowResponse1( success=False, message="EnergyPlus binary not found: {}!".format( energyplus_binary), column_data=[]) else: return EPLaunchWorkflowResponse1( success=False, message="Workflow location missing: {}!".format( args['workflow location']), column_data=[]) v = Version() is_found, current_version, numeric_version = v.check_energyplus_version( full_file_path) if is_found: if by_api: # if calling through API, then the arguments don't include the E+ binary command_line_args = [] else: command_line_args = [energyplus_binary] if extension == '.imf': command_line_args += ['--epmacro'] # should be able to do this once we get pyExpandObjects going if extension != '.epJSON': command_line_args += ['--expandobjects'] # TODO: add -d run_directory support to the E+ call here # if not isIP: # if using SI output units just use readvars CLI option # command_line_args += ['--readvars'] # add some config parameters command_line_args += [ '--output-prefix', file_name_no_ext, '--output-suffix', 'C' ] # add in simulation control args if 'weather' in args and args['weather']: command_line_args += ['--weather', args['weather']] else: command_line_args += ['--design-day'] # and at the very end, add the file to run command_line_args += [full_file_path] # run E+ if by_api: # if by API then find the API wrapper relative to this workflow, import it, set up a callback, and run eplus_dir = Path(__file__).parent.parent.absolute() sys.path.insert(0, str(eplus_dir)) from pyenergyplus.api import EnergyPlusAPI x = lambda msg: self.callback("API Callback: " + str(msg)) api = EnergyPlusAPI() state = api.state_manager.new_state() api.runtime.callback_message(state, x) api.runtime.set_console_output_status(state, False) cur_dir = os.getcwd() os.chdir(run_directory) eplus_return = api.runtime.run_energyplus( state, command_line_args) os.chdir(cur_dir) if eplus_return != 0: self.callback("E+ FAILED") return EPLaunchWorkflowResponse1( success=False, message="EnergyPlus failed for file: %s!" % full_file_path, column_data={}) else: # if by CLI then just execute the full command line try: for message in self.execute_for_callback( command_line_args, run_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("E+ FAILED") return EPLaunchWorkflowResponse1( success=False, message="EnergyPlus failed for file: %s!" % full_file_path, column_data={}) # if isIP: # set up the ESO and MTR output files for either unit conversion or just ReadVarsESO # *.eso back to eplusout.eso eso_path = os.path.join(run_directory, file_name_no_ext + '.eso') eplusouteso_path = os.path.join(run_directory, 'eplusout.eso') if os.path.exists(eso_path): shutil.copy(eso_path, eplusouteso_path) # *.mtr back to eplusout.mtr mtr_path = os.path.join(run_directory, file_name_no_ext + '.mtr') eplusoutmtr_path = os.path.join(run_directory, 'eplusout.mtr') if os.path.exists(mtr_path): shutil.copy(mtr_path, eplusoutmtr_path) if isIP: # run the ConvertESOMTR program to create IP versions of the timestep based output files if platform.system() == 'Windows': convertESOMTR_binary = os.path.join( energyplus_root_folder, 'PostProcess', 'convertESOMTRpgm', 'convertESOMTR.exe') else: convertESOMTR_binary = os.path.join( energyplus_root_folder, 'PostProcess', 'convertESOMTRpgm', 'convertESOMTR') if os.path.exists(convertESOMTR_binary): converttxt_orig_path = os.path.join( energyplus_root_folder, 'PostProcess', 'convertESOMTRpgm', 'convert.txt') converttxt_run_path = os.path.join(run_directory, 'convert.txt') shutil.copy(converttxt_orig_path, converttxt_run_path) command_line_args = [convertESOMTR_binary] try: for message in self.execute_for_callback( command_line_args, run_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("ConvertESOMTR FAILED") return EPLaunchWorkflowResponse1( success=False, message="ConvertESOMTR failed for file: %s!" % full_file_path, column_data={}) # copy converted IP version of ESO file to users *.eso file ipeso_path = os.path.join(run_directory, 'ip.eso') if os.path.exists(ipeso_path): shutil.copy(ipeso_path, eso_path) os.replace(ipeso_path, eplusouteso_path) # copy converted IP version of MTR file to users *.mtr file ipmtr_path = os.path.join(run_directory, 'ip.mtr') if os.path.exists(ipmtr_path): shutil.copy(ipmtr_path, mtr_path) os.replace(ipmtr_path, eplusoutmtr_path) os.remove(converttxt_run_path) # run ReadVarsESO to convert the timestep based output files to CSV files if platform.system() == 'Windows': readvarseso_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'ReadVarsESO.exe') else: readvarseso_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'ReadVarsESO') if os.path.exists(readvarseso_binary): command_line_args = [readvarseso_binary] rvi_path = os.path.join(run_directory, file_name_no_ext + '.rvi') temp_rvi_path = os.path.join(run_directory, 'temp.rvi') eplusout_rvi_path = os.path.join(run_directory, 'eplusout.rvi') if os.path.exists(rvi_path): shutil.copy(rvi_path, eplusout_rvi_path) command_line_args.append('eplusout.rvi') else: f = open(temp_rvi_path, "w+") f.write('eplusout.eso \n') f.write('eplusout.csv \n') f.close() command_line_args.append('temp.rvi') command_line_args.append( 'unlimited') # no number of column limit try: for message in self.execute_for_callback( command_line_args, run_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("ReadVarsESO FAILED on ESO file") return EPLaunchWorkflowResponse1( success=False, message="ReadVarsESO failed for ESO file: %s!" % full_file_path, column_data={}) vari_csv_path = os.path.join(run_directory, file_name_no_ext + '.csv') eplusout_csv_path = os.path.join(run_directory, 'eplusout.csv') if os.path.exists(eplusout_csv_path): os.replace(eplusout_csv_path, vari_csv_path) command_line_args = [readvarseso_binary] mvi_path = os.path.join(run_directory, file_name_no_ext + '.mvi') temp_mvi_path = os.path.join(run_directory, 'temp.mvi') eplusout_mvi_path = os.path.join(run_directory, 'eplusout.mvi') if os.path.exists(mvi_path): shutil.copy(mvi_path, eplusout_mvi_path) command_line_args.append('eplusout.mvi') else: f = open(temp_mvi_path, "w+") f.write('eplusout.mtr \n') f.write('eplusmtr.csv \n') f.close() command_line_args.append('temp.mvi') command_line_args.append( 'unlimited') # no number of column limit try: for message in self.execute_for_callback( command_line_args, run_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("ReadVarsESO FAILED on MTR file") return EPLaunchWorkflowResponse1( success=False, message="ReadVarsESO failed for MTR file: %s!" % full_file_path, column_data={}) mtr_csv_path = os.path.join(run_directory, file_name_no_ext + 'Meter.csv') eplusmtr_csv_path = os.path.join(run_directory, 'eplusmtr.csv') if os.path.exists(eplusmtr_csv_path): os.replace(eplusmtr_csv_path, mtr_csv_path) readvars_audit_path = os.path.join(run_directory, 'readvars.audit') rv_audit_path = os.path.join(run_directory, file_name_no_ext + '.rvaudit') if os.path.exists(readvars_audit_path): os.replace(readvars_audit_path, rv_audit_path) # clean up things inside this IF block if os.path.exists(temp_rvi_path): os.remove(temp_rvi_path) if os.path.exists(temp_mvi_path): os.remove(temp_mvi_path) if os.path.exists(eplusout_rvi_path): os.remove(eplusout_rvi_path) if os.path.exists(eplusout_mvi_path): os.remove(eplusout_mvi_path) # clean up more things if os.path.exists(eplusouteso_path): os.remove(eplusouteso_path) if os.path.exists(eplusoutmtr_path): os.remove(eplusoutmtr_path) audit_out_path = os.path.join(run_directory, 'audit.out') if os.path.exists(audit_out_path): os.remove(audit_out_path) expanded_idf_path = os.path.join(run_directory, 'expanded.idf') if os.path.exists(expanded_idf_path): os.remove(expanded_idf_path) out_idf_path = os.path.join(run_directory, 'out.idf') if os.path.exists(out_idf_path): os.remove(out_idf_path) # run HVAC-Diagram if platform.system() == 'Windows': hvac_diagram_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'HVAC-Diagram.exe') else: hvac_diagram_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'HVAC-Diagram') if os.path.exists(hvac_diagram_binary): bnd_path = os.path.join(run_directory, file_name_no_ext + '.bnd') eplusout_bnd_path = os.path.join(run_directory, 'eplusout.bnd') if os.path.exists(bnd_path): shutil.copy(bnd_path, eplusout_bnd_path) command_line_args = [hvac_diagram_binary] try: for message in self.execute_for_callback( command_line_args, run_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("HVAC-Diagram FAILED on BND file") return EPLaunchWorkflowResponse1( success=False, message="HVAC-Diagram failed for BND file: %s!" % full_file_path, column_data={}) svg_path = os.path.join(run_directory, file_name_no_ext + '.svg') eplusout_svg_path = os.path.join(run_directory, 'eplusout.svg') if os.path.exists(eplusout_svg_path): os.replace(eplusout_svg_path, svg_path) if os.path.exists(eplusout_bnd_path): os.remove(eplusout_bnd_path) # check on .end file and finish up err_file_name = "{0}.err".format(file_name_no_ext) err_file_path = os.path.join(run_directory, err_file_name) success, errors, warnings, runtime = EPlusRunManager.get_end_summary_from_err( err_file_path) column_data = { ColumnNames.Errors: errors, ColumnNames.Warnings: warnings, ColumnNames.Runtime: runtime, ColumnNames.Version: current_version } # now leave return EPLaunchWorkflowResponse1( success=True, message="Ran EnergyPlus OK for file: %s!" % file_name, column_data=column_data) else: errors = "wrong version" column_data = { ColumnNames.Errors: errors, ColumnNames.Warnings: '', ColumnNames.Runtime: 0, ColumnNames.Version: current_version } # now leave return EPLaunchWorkflowResponse1( success=False, message="Incorrect Version found {}: {}!".format( current_version, file_name), column_data=column_data)
def run_energyplus(self, isIP, run_directory, file_name, args, by_api): full_file_path = os.path.join(run_directory, file_name) file_name_no_ext, extension = os.path.splitext(file_name) output_directory = os.path.join(run_directory, f"EPLaunchRun_{file_name_no_ext}") if os.path.exists(output_directory): shutil.rmtree(output_directory) os.makedirs(output_directory) def delete_if_exists(file_path): if os.path.exists(file_path): os.remove(file_path) if 'workflow location' in args: energyplus_root_folder, _ = os.path.split( args['workflow location']) # Run EnergyPlus binary if platform.system() == 'Windows': energyplus_binary = os.path.join(energyplus_root_folder, 'energyplus.exe') else: energyplus_binary = os.path.join(energyplus_root_folder, 'energyplus') if not os.path.exists(energyplus_binary): return EPLaunchWorkflowResponse1( success=False, message="EnergyPlus binary not found: {}!".format( energyplus_binary), column_data=[]) else: return EPLaunchWorkflowResponse1( success=False, message="Workflow location missing: {}!".format( args['workflow location']), column_data=[]) v = Version() is_found, current_version, numeric_version = v.check_energyplus_version( full_file_path) if not is_found: errors = "wrong version" column_data = { ColumnNames.Errors: errors, ColumnNames.Warnings: '', ColumnNames.Runtime: 0, ColumnNames.Version: current_version } return EPLaunchWorkflowResponse1( success=False, message="Incorrect Version found {}: {}!".format( current_version, file_name), column_data=column_data) if by_api: # if calling through API, then the arguments don't include the E+ binary command_line_args = [] else: command_line_args = [energyplus_binary] if extension == '.imf': command_line_args += ['--epmacro'] # So...ExpandObjects is weird in E+. It doesn't like running things in directories and accidentally symlinks # things into the current working directory even if you specify an output directory # We're just going to run it ourselves. (Side note it could be a similar problem for EPMacro) if extension != '.epJSON': if platform.system() == 'Windows': expand_objects = os.path.join(energyplus_root_folder, 'ExpandObjects.exe') else: expand_objects = os.path.join(energyplus_root_folder, 'ExpandObjects') if not os.path.exists(expand_objects): return EPLaunchWorkflowResponse1( success=False, message="ExpandObjects binary not found: {}!".format( expand_objects), column_data=[]) # go ahead and copy the target IDF and original IDD into the output_dir/in.idf for running ExpandObjects idf_path_in_output_dir = os.path.join(output_directory, 'in.idf') shutil.copy(full_file_path, idf_path_in_output_dir) idd_path = os.path.join( energyplus_root_folder, 'Energy+.idd') # yes for now we still need it idd_path_in_output_dir = os.path.join(output_directory, 'Energy+.idd') shutil.copy(idd_path, idd_path_in_output_dir) # run ExpandObjects try: for message in self.execute_for_callback([expand_objects], output_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("E+ FAILED") return EPLaunchWorkflowResponse1( success=False, message="EnergyPlus failed for file: %s!" % full_file_path, column_data={}) # regardless of what happened, clean up the temp files delete_if_exists(idf_path_in_output_dir) delete_if_exists(idd_path_in_output_dir) # if expanded.idf does not exist then we don't need to do anything, assume it just didn't have any templates # but if it does exist, then this needs to be the IDF that we run, *however* we can't just leave it here # as it may reference some other files back in the original directory. I'm going to go with a new file name # in the original directory of "FileName_Expanded.idf" expanded_path_in_output_dir = os.path.join(output_directory, 'expanded.idf') if os.path.exists(expanded_path_in_output_dir): target_expanded_file_name = os.path.join( run_directory, f"{file_name_no_ext}_Expanded.idf") shutil.copy(expanded_path_in_output_dir, target_expanded_file_name) full_file_path = target_expanded_file_name # Run EnergyPlus in a subdirectory command_line_args += ['-d', output_directory] # if not isIP: # if using SI output units just use readvars CLI option # command_line_args += ['--readvars'] # add some config parameters command_line_args += [ '--output-prefix', file_name_no_ext, '--output-suffix', 'C' ] # add in simulation control args if 'weather' in args and args['weather']: command_line_args += ['--weather', args['weather']] else: command_line_args += ['--design-day'] # and at the very end, add the file to run command_line_args += [full_file_path] # run E+ if by_api: # if by API then find the API wrapper relative to this workflow, import it, set up a callback, and run eplus_dir = Path(__file__).parent.parent.absolute() sys.path.insert(0, str(eplus_dir)) from pyenergyplus.api import EnergyPlusAPI x = lambda msg: self.callback("(E+API) " + msg.decode( 'utf-8', errors='ignore')) # x = lambda msg: print("(E+ API) : " + str(msg)) api = EnergyPlusAPI() state = api.state_manager.new_state() api.runtime.callback_message(state, x) api.runtime.set_console_output_status(state, False) # cur_dir = os.getcwd() # os.chdir(output_directory) eplus_return = api.runtime.run_energyplus(state, command_line_args) # os.chdir(cur_dir) if eplus_return != 0: self.callback("E+ FAILED") return EPLaunchWorkflowResponse1( success=False, message="EnergyPlus failed for file: %s!" % full_file_path, column_data={}) else: # if by CLI then just execute the full command line try: for message in self.execute_for_callback( command_line_args, output_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("E+ FAILED") return EPLaunchWorkflowResponse1( success=False, message="EnergyPlus failed for file: %s!" % full_file_path, column_data={}) # if isIP: # set up the ESO and MTR output files for either unit conversion or just ReadVarsESO # *.eso back to eplusout.eso eso_path = os.path.join(output_directory, file_name_no_ext + '.eso') eplusouteso_path = os.path.join(output_directory, 'eplusout.eso') if os.path.exists(eso_path): shutil.copy(eso_path, eplusouteso_path) # *.mtr back to eplusout.mtr mtr_path = os.path.join(output_directory, file_name_no_ext + '.mtr') eplusoutmtr_path = os.path.join(output_directory, 'eplusout.mtr') if os.path.exists(mtr_path): shutil.copy(mtr_path, eplusoutmtr_path) if isIP: # run the ConvertESOMTR program to create IP versions of the timestep based output files if platform.system() == 'Windows': converter = os.path.join(energyplus_root_folder, 'PostProcess', 'convertESOMTRpgm', 'convertESOMTR.exe') else: converter = os.path.join(energyplus_root_folder, 'PostProcess', 'convertESOMTRpgm', 'convertESOMTR') if os.path.exists(converter): txt_orig_path = os.path.join(energyplus_root_folder, 'PostProcess', 'convertESOMTRpgm', 'convert.txt') txt_run_path = os.path.join(output_directory, 'convert.txt') shutil.copy(txt_orig_path, txt_run_path) command_line_args = [converter] try: for message in self.execute_for_callback( command_line_args, output_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("ConvertESOMTR FAILED") return EPLaunchWorkflowResponse1( success=False, message="ConvertESOMTR failed for file: %s!" % full_file_path, column_data={}) # copy converted IP version of ESO file to users *.eso file ipeso_path = os.path.join(output_directory, 'ip.eso') if os.path.exists(ipeso_path): shutil.copy(ipeso_path, eso_path) os.replace(ipeso_path, eplusouteso_path) # copy converted IP version of MTR file to users *.mtr file ipmtr_path = os.path.join(output_directory, 'ip.mtr') if os.path.exists(ipmtr_path): shutil.copy(ipmtr_path, mtr_path) os.replace(ipmtr_path, eplusoutmtr_path) os.remove(txt_run_path) # run ReadVarsESO to convert the timestep based output files to CSV files if platform.system() == 'Windows': readvarseso_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'ReadVarsESO.exe') else: readvarseso_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'ReadVarsESO') if os.path.exists(readvarseso_binary): command_line_args = [readvarseso_binary] rvi_path = os.path.join(run_directory, file_name_no_ext + '.rvi') temp_rvi_path = os.path.join(output_directory, 'temp.rvi') eplusout_rvi_path = os.path.join(output_directory, 'eplusout.rvi') if os.path.exists(rvi_path): shutil.copy(rvi_path, eplusout_rvi_path) command_line_args.append('eplusout.rvi') else: with open(temp_rvi_path, "w") as f: f.write('eplusout.eso \n') f.write('eplusout.csv \n') command_line_args.append('temp.rvi') command_line_args.append('unlimited') # no number of column limit try: for message in self.execute_for_callback( command_line_args, output_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("ReadVarsESO FAILED on ESO file") return EPLaunchWorkflowResponse1( success=False, message="ReadVarsESO failed for ESO file: %s!" % full_file_path, column_data={}) vari_csv_path = os.path.join(run_directory, file_name_no_ext + '.csv') # TODO: What is this? eplusout_csv_path = os.path.join(output_directory, 'eplusout.csv') if os.path.exists(eplusout_csv_path): os.replace(eplusout_csv_path, vari_csv_path) command_line_args = [readvarseso_binary] mvi_path = os.path.join(run_directory, file_name_no_ext + '.mvi') temp_mvi_path = os.path.join(output_directory, 'temp.mvi') eplusout_mvi_path = os.path.join(output_directory, 'eplusout.mvi') if os.path.exists(mvi_path): shutil.copy(mvi_path, eplusout_mvi_path) command_line_args.append('eplusout.mvi') else: with open(temp_mvi_path, "w+") as f: f.write('eplusout.mtr \n') f.write('eplusmtr.csv \n') command_line_args.append('temp.mvi') command_line_args.append('unlimited') # no number of column limit try: for message in self.execute_for_callback( command_line_args, output_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("ReadVarsESO FAILED on MTR file") return EPLaunchWorkflowResponse1( success=False, message="ReadVarsESO failed for MTR file: %s!" % full_file_path, column_data={}) mtr_csv_path = os.path.join(output_directory, file_name_no_ext + 'Meter.csv') eplusmtr_csv_path = os.path.join(output_directory, 'eplusmtr.csv') if os.path.exists(eplusmtr_csv_path): os.replace(eplusmtr_csv_path, mtr_csv_path) readvars_audit_path = os.path.join(output_directory, 'readvars.audit') rv_audit_path = os.path.join(output_directory, file_name_no_ext + '.rvaudit') if os.path.exists(readvars_audit_path): os.replace(readvars_audit_path, rv_audit_path) # clean up things inside this IF block delete_if_exists(temp_rvi_path) delete_if_exists(temp_mvi_path) delete_if_exists(eplusout_rvi_path) delete_if_exists(eplusout_mvi_path) # clean up more things delete_if_exists(eplusouteso_path) delete_if_exists(eplusoutmtr_path) audit_out_path = os.path.join(output_directory, 'audit.out') delete_if_exists(audit_out_path) expanded_idf_path = os.path.join(output_directory, 'expanded.idf') delete_if_exists(expanded_idf_path) out_idf_path = os.path.join(output_directory, 'out.idf') delete_if_exists(out_idf_path) # run HVAC-Diagram if platform.system() == 'Windows': hvac_diagram_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'HVAC-Diagram.exe') else: hvac_diagram_binary = os.path.join(energyplus_root_folder, 'PostProcess', 'HVAC-Diagram') if os.path.exists(hvac_diagram_binary): bnd_path = os.path.join(output_directory, file_name_no_ext + '.bnd') eplusout_bnd_path = os.path.join(output_directory, 'eplusout.bnd') if os.path.exists(bnd_path): shutil.copy(bnd_path, eplusout_bnd_path) command_line_args = [hvac_diagram_binary] try: for message in self.execute_for_callback( command_line_args, output_directory): self.callback(message) except subprocess.CalledProcessError: self.callback("HVAC-Diagram FAILED on BND file") return EPLaunchWorkflowResponse1( success=False, message="HVAC-Diagram failed for BND file: %s!" % full_file_path, column_data={}) svg_path = os.path.join(output_directory, file_name_no_ext + '.svg') eplusout_svg_path = os.path.join(output_directory, 'eplusout.svg') if os.path.exists(eplusout_svg_path): os.replace(eplusout_svg_path, svg_path) if os.path.exists(eplusout_bnd_path): os.remove(eplusout_bnd_path) # Now the last thing to do is to collect all the relevant output files for this simulation and put them back # in the original run directory. This is because EP Launch will expect to find them right there. file_names_to_copy = [ f for f in os.listdir(output_directory) if f.startswith(file_name_no_ext) ] for f in file_names_to_copy: shutil.copy(os.path.join(output_directory, f), os.path.join(run_directory, f)) # check on .end file and finish up err_file_name = "{0}.err".format(file_name_no_ext) err_file_path = os.path.join(output_directory, err_file_name) success, errors, warnings, runtime = EPlusRunManager.get_end_summary_from_err( err_file_path) column_data = { ColumnNames.Errors: errors, ColumnNames.Warnings: warnings, ColumnNames.Runtime: runtime, ColumnNames.Version: current_version } # now leave return EPLaunchWorkflowResponse1( success=True, message="Ran EnergyPlus OK for file: %s!" % file_name, column_data=column_data)