Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could not find platform dependent libraries and kernel always busy. Im waiting and kernel still busy but my energyplus was completed succesfully. #3260

Open
P3ngh4ncur opened this issue Mar 8, 2024 · 4 comments

Comments

@P3ngh4ncur
Copy link

Could not find platform dependent libraries and kernel always busy. Im waiting and kernel still busy but my energyplus was completed succesfully.

[2024-03-08 14:58:19,486] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:Could not find platform independent libraries

[2024-03-08 14:58:19,486] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:Could not find platform independent libraries

[2024-03-08 14:58:19,575] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:Could not find platform dependent libraries <exec_prefix>

[2024-03-08 14:58:19,575] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:Could not find platform dependent libraries <exec_prefix>

[2024-03-08 14:58:19,580] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:Consider setting $PYTHONHOME to [:<exec_prefix>]

[2024-03-08 14:58:19,580] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:Consider setting $PYTHONHOME to [:<exec_prefix>]

[2024-03-08 14:58:47,259] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:EnergyPlus Completed Successfully.

[2024-03-08 14:58:47,259] EPLUS_ENV_TesisDivEnv_MainThread-EPLUSPROCESS_EPI_0 ERROR:EnergyPlus Completed Successfully.

my kernel still busy and i cannot to next cell

@pseudo-rnd-thoughts
Copy link
Contributor

Could you provide example code to reproduce the issue?

@P3ngh4ncur
Copy link
Author

env = gym.make('TesisDivEnv')
ob = env.reset()

this code still make kernel busy, it's possible the problem in my Object Oriented Program or Python Library etc?

@P3ngh4ncur
Copy link
Author

#Wrap the EnergyPLus simulator into the Openai gym env
#Author: Zhiang Zhang, Hadi Christian

import socket
import os
import time
import copy
import signal
import _thread
import logging
import subprocess
import threading
import numpy as np

from shutil import copyfile, rmtree
from gym import Env, spaces
from gym.envs.registration import register
from xml.etree.ElementTree import Element, SubElement, Comment, tostring

from ..util.logger import Logger
from ..util.time import (get_hours_to_now, get_time_string, get_delta_seconds,
WEEKDAY_ENCODING)

YEAR = 1991 # Non leap year
CWD = os.getcwd();
LOG_LEVEL_MAIN = 'INFO';
LOG_LEVEL_EPLS = 'ERROR';
LOG_FMT = "[%(asctime)s] %(name)s %(levelname)s:%(message)s";

class TesisDivEnv(Env):
"""EnergyPlus gym environment

Args:
eplus_path: String
  EnergyPlus executive command path.
weather_path: String
  EnergyPlus weather file path (.epw).
bcvtb_path: String
  BCVTB installation path.
variable_path: String
  variable.cfg path.
idf_path: String
  EnergyPlus input description file (.idf) path.
env_name: str
  The environment name.
act_repeat: int
  The number of times to repeat the control action.
max_ep_data_store_num: int
  The number of simulation results to keep.
"""

def __init__(self, eplus_path, weather_path, bcvtb_path, variable_path, idf_path, env_name,
                act_repeat = 1, max_ep_data_store_num = 10):
    self._env_name = env_name;
    self._thread_name = threading.current_thread().getName();
    self.logger_main = Logger().getLogger('EPLUS_ENV_%s_%s_ROOT'%(env_name, self._thread_name),
                                        LOG_LEVEL_MAIN, LOG_FMT);

    # Set the environment variable for bcvtb
    os.environ['BCVTB_HOME'] = bcvtb_path;
    # Create a socket for communication with the EnergyPlus
    self.logger_main.debug('Creating socket for communication...')
    s = socket.socket()
    host = socket.gethostname() # Get local machine name
    s.bind((host, 0))           # Bind to the host and any available port
    sockname = s.getsockname();
    port = sockname[1];         # Get the port number
    s.listen(60)                # Listen on request
    self.logger_main.debug('Socket is listening on host %s port %d'%(sockname));
    self._env_working_dir_parent = self._get_eplus_working_folder(CWD, '-%s-res'%(env_name));
    os.makedirs(self._env_working_dir_parent);
    self._host = host;
    self._port = port;
    self._socket = s;
    self._eplus_path = eplus_path
    self._weather_path = weather_path
    self._variable_path = variable_path
    self._idf_path = idf_path
    self._episode_existed = False;
    (self._eplus_run_st_mon, self._eplus_run_st_day,
     self._eplus_run_ed_mon, self._eplus_run_ed_day,
     self._eplus_run_st_weekday,
     self._eplus_run_stepsize) = self._get_eplus_run_info(idf_path);
    self._eplus_run_stepsize = 3600 / self._eplus_run_stepsize # Stepsize in second
    self._eplus_one_epi_len = self._get_one_epi_len(self._eplus_run_st_mon,
                                                    self._eplus_run_st_day,
                                                    self._eplus_run_ed_mon,
                                                    self._eplus_run_ed_day);
    self._epi_num = 0;
    self._act_repeat = act_repeat;
    self._max_ep_data_store_num = max_ep_data_store_num;
    self._last_action = [20.0];

    # Variabel untuk RL
    self.action_space = spaces.MultiDiscrete([7, 7, 7, 7]);
    self.observation_space = spaces.Box(low = 0, high = np.inf, shape=(6,));

def reset(self):
    """Reset the environment.

    This method does the followings:
    1: Make a new EnergyPlus working directory
    2: Copy .idf and variables.cfg file to the working directory
    3: Create the socket.cfg file in the working directory
    4: Create the EnergyPlus subprocess
    5: Establish the socket connection with EnergyPlus
    6: Read the first sensor data from the EnergyPlus

    Return: (float, [float], boolean)
        The index 0 is current_simulation_time in second,
        index 1 is EnergyPlus results in 1-D python list requested by the
        variable.cfg, index 2 is the boolean indicating whether the episode terminates.
    """
    ret = [];
    # End the last episode if exists
    if self._episode_existed:
        self._end_episode()
        self.logger_main.info('Last EnergyPlus process has been closed. ')
        self._epi_num += 1;

    # Create EnergyPlus simulaton process
    self.logger_main.info('Creating EnergyPlus simulation environment...')
    eplus_working_dir = self._get_eplus_working_folder(
                            self._env_working_dir_parent, '-sub_run');
    os.makedirs(eplus_working_dir); # Create the Eplus working directory
    self._rm_past_history_dir(eplus_working_dir, '-sub_run'); # Remove redundant past working directories
    eplus_working_idf_path = (eplus_working_dir +
                              '/' +
                              self._get_file_name(self._idf_path));
    eplus_working_var_path = (eplus_working_dir +
                              '/' +
                              'variables.cfg'); # Variable file must be with this name
    eplus_working_out_path = (eplus_working_dir +
                              '/' +
                              'output');
    copyfile(self._idf_path, eplus_working_idf_path);
                                # Copy the idf file to the working directory
    copyfile(self._variable_path, eplus_working_var_path);
                                # Copy the variable.cfg file to the working dir
    self._create_socket_cfg(self._host,
                            self._port,
                            eplus_working_dir);
                                # Create the socket.cfg file in the working dir
    self.logger_main.info('EnergyPlus working directory is in %s'
                          %(eplus_working_dir));
    eplus_process = self._create_eplus(self._eplus_path, self._weather_path,
                                        eplus_working_idf_path,
                                        eplus_working_out_path,
                                        eplus_working_dir);
    self.logger_main.debug('EnergyPlus process is still running ? %r'
                            %self._get_is_subprocess_running(eplus_process))
    self._eplus_process = eplus_process;
    # Log the Eplus output
    eplus_logger = Logger().getLogger('EPLUS_ENV_%s_%s-EPLUSPROCESS_EPI_%d'
                                    %(self._env_name, self._thread_name, self._epi_num),
                                    LOG_LEVEL_EPLS, LOG_FMT);
    _thread.start_new_thread(self._log_subprocess_info,
                            (eplus_process.stdout,
                             eplus_logger));
    _thread.start_new_thread(self._log_subprocess_err,
                            (eplus_process.stderr,
                             eplus_logger));
    # Establish connection with EnergyPlus
    conn, addr = self._socket.accept()     # Establish connection with client.
    self.logger_main.debug('Got connection from %s at port %d.'%(addr));
    # Start the first data exchange
    rcv_1st = conn.recv(2048).decode(encoding = 'ISO-8859-1');
    self.logger_main.debug('Got the first message successfully: ' + rcv_1st);
    version, flag, nDb, nIn, nBl, curSimTim, Dblist \
                                            = self._disassembleMsg(rcv_1st);
    ret.append(curSimTim);
    ret.append(Dblist);
    # Remember the message header, useful when send data back to EnergyPlus
    self._eplus_msg_header = [version, flag];
    self._curSimTim = curSimTim;
    # Check if episode terminates
    is_terminal = False;
    if curSimTim >= self._eplus_one_epi_len:
        is_terminal = True;
    ret.append(is_terminal);
    # Change some attributes
    self._conn = conn;
    self._eplus_working_dir = eplus_working_dir;
    self._episode_existed = True;
    # Process for episode terminal
    if is_terminal:
        self._end_episode();

    obs = self._get_observation(Dblist);

    return obs

def step(self, action):
    """Execute the specified action.

    This method does the followings:
    1: Send a list of float to EnergyPlus
    2: Recieve EnergyPlus results for the next step (state)

    Parameters
    ----------
    action: python list of float
      Control actions that will be passed to the EnergyPlus

    Return: (float, [float], boolean)
        The index 0 is current_simulation_time in second,
        index 1 is EnergyPlus results in 1-D python list requested by the
        variable.cfg, index 2 is the boolean indicating whether the episode terminates.
    """
    # Send to the EnergyPlus
    action = action + np.ones((4,), dtype=np.int8)*22 # Aksi yang dikirim berupa temperatur antara 20-26 sebanyak 7
    curSimTim = self._curSimTim;

    self.logger_main.debug('Perform one step.')
    header = self._eplus_msg_header;
    runFlag = 0 # 0 is normal flag
    tosend = self._assembleMsg(header[0], runFlag, len(action), 0,
                               0, curSimTim, action);
    self._conn.send(tosend.encode());
    # Recieve from the EnergyPlus
    rcv = self._conn.recv(2048).decode(encoding = 'ISO-8859-1');
    self.logger_main.debug('Got message successfully: ' + rcv);
    # Process received msg
    version, flag, nDb, nIn, nBl, curSimTim, Dblist \
                                = self._disassembleMsg(rcv);

    if curSimTim < self._eplus_one_epi_len:
        is_terminal = False;
    elif curSimTim >= self._eplus_one_epi_len:
        is_terminal = True;
        # Remember the last action
        self._last_action = action;

    # Change some attributes
    self._curSimTim = curSimTim;

    obs = self._get_observation(Dblist);
    reward = self._get_reward(obs, Dblist);

    info = {}

    return obs, reward, is_terminal, info

def render(self, mode='human', close=False):
    pass;

def _seed(self):
    return 1;

def _rm_past_history_dir(self, cur_eplus_working_dir, dir_sig):
    """Remove the past simulation results.

    Args:
        cur_eplus_working_dir: str
            The current eplus working directory
        dir_sig: str
            The directory split signature

    Reture: None

    """

    cur_dir_name, cur_dir_id = cur_eplus_working_dir.split(dir_sig)
    cur_dir_id = int(cur_dir_id);
    if cur_dir_id - self._max_ep_data_store_num > 0:
        rm_dir_id = cur_dir_id - self._max_ep_data_store_num;
        rm_dir_full_name = cur_dir_name + dir_sig + str(rm_dir_id);
        rmtree(rm_dir_full_name);

def _create_eplus(self, eplus_path, weather_path,
                  idf_path, out_path, eplus_working_dir):

    eplus_process = subprocess.Popen('%s -w %s -d %s -x %s'
                    %(eplus_path + '/energyplus', weather_path,
                      out_path, idf_path),
                    shell = True,
                    cwd = eplus_working_dir,
                    stdout = subprocess.PIPE,
                    stderr = subprocess.PIPE,
                    preexec_fn=os.setsid);
    return eplus_process;

def _get_eplus_working_folder(self, parent_dir, dir_sig = '-run'):
    """Return Eplus output folder.

    Assumes folders in the parent_dir have suffix -run{run
    number}. Finds the highest run number and sets the output folder
    to that number + 1.

    Parameters
    ----------
    parent_dir: str
    Parent dir of the Eplus output directory.

    Returns
    -------
    parent_dir/run_dir
    Path to Eplus save directory.
    """
    os.makedirs(parent_dir, exist_ok=True)
    experiment_id = 0
    for folder_name in os.listdir(parent_dir):
        if not os.path.isdir(os.path.join(parent_dir, folder_name)):
            continue
        try:
            folder_name = int(folder_name.split(dir_sig)[-1])
            if folder_name > experiment_id:
                experiment_id = folder_name
        except:
            pass
    experiment_id += 1

    parent_dir = os.path.join(parent_dir, 'Eplus-env')
    parent_dir = parent_dir + '%s%d'%(dir_sig, experiment_id)
    return parent_dir

def _create_socket_cfg(self, host, port, write_dir):
    """
    Create the socket.cfg required by BCVTB.

    Args:
        host: String
            Socket host name.
        port: int
            Socket port number.
        write_dir: String
            The write directory.
    Return: None
    """
    top = Element('BCVTB-client');
    ipc = SubElement(top, 'ipc');
    socket = SubElement(ipc, 'socket'
                        ,{'port':str(port),
                          'hostname':host,})
    xml_str = tostring(top, encoding='ISO-8859-1').decode();

    with open(write_dir + '/' + 'socket.cfg', 'w+') as socket_file:
        socket_file.write(xml_str);

def _get_file_name(self, file_path):
    path_list = file_path.split('/');
    return path_list[-1];

def _log_subprocess_info(self, out, logger):
    for line in iter(out.readline, b''):
        logger.info(line.decode())

def _log_subprocess_err(self, out, logger):
    for line in iter(out.readline, b''):
        logger.error(line.decode())

def _get_is_subprocess_running(self, subprocess):
    if subprocess.poll() is None:
        return True;
    else:
        return False;

def get_is_eplus_running(self):
    return self._get_is_subprocess_running(self._eplus_process);

def end_env(self):
    """
    This method is called after finishing using the environment.
    """
    self._end_episode();
    self._socket.shutdown(socket.SHUT_RDWR);
    self._socket.close();

def end_episode(self):
    self._end_episode();

def _end_episode(self):
    """
    This method terminates the current EnergyPlus subprocess.

    This method is usually called by the reset() function before it
    resets the EnergyPlus environment.
    """
    # Send the final msg to EnergyPlus
    header = self._eplus_msg_header;
    flag = 1.0; # Terminate flag is 1.0, specified by EnergyPlus
    action = self._last_action;
    action_size = len(self._last_action);
    tosend = self._assembleMsg(header[0], flag, action_size, 0,
                                0, self._curSimTim, action);
    self.logger_main.debug('Send the final msg to Eplus.');
    self._conn.send(tosend.encode());
    # Recieve the final msg from Eplus
    rcv = self._conn.recv(2048).decode(encoding = 'ISO-8859-1');
    self.logger_main.debug('Final msh from Eplus: %s', rcv)
    self._conn.send(tosend.encode()); # Send again, don't know why
    # Remove the connection
    self._conn.close();
    self._conn = None;
    # Process the output
    time.sleep(1);# Sleep the thread so EnergyPlus has time to do the
                  # post processing

    # Kill subprocess
    os.killpg(self._eplus_process.pid, signal.SIGTERM);
    self._episode_existed = False;

def _run_eplus_outputProcessing(self):
    eplus_outputProcessing_process =\
     subprocess.Popen('%s'
                    %(self._eplus_path + '/PostProcess/ReadVarsESO'),
                    shell = True,
                    cwd = self._eplus_working_dir + '/output',
                    stdout = subprocess.PIPE,
                    stderr = subprocess.PIPE,
                    preexec_fn=os.setsid)


def _assembleMsg(self, version, flag, nDb, nIn, nBl, curSimTim, Dblist):
    """
    Assemble the send msg to the EnergyPlus based on the protocal.
    Send msg must a blank space seperated string, [verison, flag, nDb
    , nIn, nBl, curSimTim, float, float, float ....]

    Return:
        The send msg.
    """
    ret = '';
    ret += '%d'%(version);
    ret += ' ';
    ret += '%d'%(flag);
    ret += ' ';
    ret += '%d'%(nDb);
    ret += ' ';
    ret += '%d'%(nIn);
    ret += ' ';
    ret += '%d'%(nBl);
    ret += ' ';
    ret += '%20.15e'%(curSimTim);
    ret += ' ';
    for i in range(len(Dblist)):
        ret += '%20.15e'%(Dblist[i]);
        ret += ' ';
    ret += '\n';

    return ret;

def _disassembleMsg(self, rcv):
    rcv = rcv.split(' ');
    version = int(rcv[0]);
    flag = int(rcv[1]);
    nDb = int(rcv[2]);
    nIn = int(rcv[3]);
    nBl = int(rcv[4]);
    curSimTim = float(rcv[5]);
    Dblist = [];
    for i in range(6, len(rcv) - 1):
        Dblist.append(float(rcv[i]));

    return (version, flag, nDb, nIn, nBl, curSimTim, Dblist);

def _get_eplus_run_info(self, idf_path):
    """
    This method read the .idf file and find the running start month, start
    date, end month, end date and the step size.

    Args:
        idf_path: String
            The .idf file path.

    Return: (int, int, int, int, int, int)
        (start month, start date, end month, end date, start weekday,
        step size)
    """
    ret = [];

    with open(idf_path, encoding = 'ISO-8859-1') as idf:
        contents = idf.readlines();

    # Run period
    tgtIndex = None;

    for i in range(len(contents)):
        line = contents[i];
        effectiveContent = line.strip().split('!')[0] # Ignore contents after '!'
        effectiveContent = effectiveContent.strip().split(',')[0]
                                                      # Remove tailing ','
        if effectiveContent.lower() == 'runperiod':
            tgtIndex = i;
            break;

    for i in range(2, 7):
        if i != 4:
            ret.append(int(contents[tgtIndex + i].strip()
                                                 .split('!')[0]
                                                 .strip()
                                                 .split(',')[0]
                                                 .strip()
                                                 .split(';')[0]));
    # Start weekday
    ret.append(WEEKDAY_ENCODING[contents[tgtIndex + i + 2].strip()
                                                      .split('!')[0]
                                                      .strip()
                                                      .split(',')[0]
                                                      .strip()
                                                      .split(';')[0]
                                                      .strip()
                                                      .lower()]);
    # Step size
    line_count = 0;
    for line in contents:
        effectiveContent = line.strip().split('!')[0] # Ignore contents after '!'
        effectiveContent = effectiveContent.strip().split(',');
        if effectiveContent[0].strip().lower() == 'timestep':
            if len(effectiveContent) > 1 and len(effectiveContent[1]) > 0:
                ret.append(int(effectiveContent[1]
                               .split(';')[0]
                               .strip()));
            else:
                ret.append(int(contents[line_count + 1].strip()
                                              .split('!')[0]
                                              .strip()
                                              .split(',')[0]
                                              .strip()
                                              .split(';')[0]));
            break;
        line_count += 1;

    return tuple(ret);

def _get_one_epi_len(self, st_mon, st_day, ed_mon, ed_day):
    """
    Get the length of one episode (One EnergyPlus process run to the end).

    Args:
        st_mon, st_day, ed_mon, ed_day: int
            The EnergyPlus simulation start month, start day, end month,
            end day.

    Return: int
        The simulation time step that the simulation ends.
    """
    return get_delta_seconds(YEAR, st_mon, st_day, ed_mon, ed_day);

def _get_observation(self, Dblist):
    """
    Convert all observations to distance and normalize them
    """
    Phvac = Dblist[5];
    PMV = Dblist[7];

    obs = [];
    for i in range(4):
        distemp = np.abs((Dblist[i]-24)/(27-24));
        obs.append(distemp);
    obs.append(Phvac);
    obs.append(PMV);

    return obs

def _get_reward(self, obs, Dblist):
    """
    Calculate reward suitable for the objective
    """
    Phvac = Dblist[5];
    PMV = Dblist[7];
    hvac_reward = 0;
    pmv_reward = 0;

    pmv_reward += 1 - PMV**0.4
    pmv_reward = pmv_reward/4;

    ratio_energy = Phvac/12115
    hvac_reward = 1-ratio_energy**0.4;

    reward = hvac_reward+pmv_reward;

    return reward;

@property
def start_year(self):
    """
    Return the EnergyPlus simulaton year.

    Return: int
    """
    return YEAR;

@property
def start_mon(self):
    """
    Return the EnergyPlus simulaton start month.

    Return: int
    """
    return self._eplus_run_st_mon;

@property
def start_day(self):
    """
    Return the EnergyPlus simulaton start day of the month.

    Return: int
    """
    return self._eplus_run_st_day;

@property
def start_weekday(self):
    """
    Return the EnergyPlus simulaton start weekday. 0 is Monday, 6 is Sunday.

    Return: int
    """
    return self._eplus_run_st_weekday;

@property
def env_name(self):
    """
    Return the environment name.

    Return: string
    """
    return self._env_name;

@pseudo-rnd-thoughts
Copy link
Contributor

I would add debug statements (prints) for lines in reset in order to find which statement isn't printed. This should allow you to identify where the problems are

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants