예제 #1
0
    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)
예제 #2
0
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)
예제 #3
0
    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()
예제 #4
0
    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 = {}
예제 #5
0
    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)
예제 #6
0
    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()
예제 #7
0
# 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")
예제 #8
0
        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
예제 #10
0
 def setUpClass(cls):
     """
     A class method called before tests in an individual class are run
     """
     cls.api = EnergyPlusAPI()
예제 #11
0
    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)
예제 #12
0
    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)