Example #1
0
    def run(self):
        """Run the co-simulation

        This method deploys and run the co-simulation and waits for manual nodes to bun launched.

        >>> from zerobnl import CoSim
        >>> sim = CoSim()
        --> Create complete co-simulation graph (meta-models, environments, nodes and links) with simulation sequence
        >>> sim.run()
        """
        self._create_and_fill_folders_to_mount_into_nodes()
        logger.debug("CREATE NODES")
        self._create_and_fill_orchestrator_folder()
        logger.debug("CREATE ORCH")
        self._launch_redis_and_docker_network()
        logger.debug("LAUNCH NETWORK+REDIS")
        nodes_to_run = self.nodes.loc[self.nodes["Local"] == False].index
        create_full_yaml(nodes_to_run)
        logger.debug("DUMP YAML")
        local_nodes = self.nodes.loc[self.nodes["Local"] == True]

        for node in local_nodes.index:
            logger.warning("Local node to run in [{}] > python {}".format(
                os.path.join(TEMP_FOLDER, node.lower()), NODE_WRAP_FILE))

        if len(local_nodes) > 0:
            logger.info("Waiting for local nodes to run...")

        start = time()
        self._docker_compose_up()
        stop = time() - start

        logger.info("Simulation finished in {} min and {} sec".format(
            int(stop // 60), int(round(stop % 60, 0))))
        logger.debug("FINISHED PROCESS")
Example #2
0
    def run(self):
        self.wait_for_nodes(sum(self.sequence))
        for idx, step in enumerate(self.steps):
            logger.debug("STEP {}/{}".format(idx + 1, len(self.steps)))
            for idx_group in range(len(self.sequence)):
                self.send_current_state_for_update()
                self.make_step(idx_group, step)

        self.pub.send_string("{} | {} | {}".format("ALL", "END", 0))
Example #3
0
    def _update_inputs(self, state):
        """

        :param state:
        """
        logger.debug("INPUTS {}".format(state))
        for key, value in state.items():
            if key in self.input_map:
                self.set_attribute(self.input_map[key], value)
Example #4
0
    def update_attributes(self, step, grp, nbr):
        """The update_attributes() method is used to send to nodes the last state of the complete system
        in order for the nodes to update theri inputs."""
        logger.debug("ORCH -> GRP {}, UPDATE {}".format(grp, step))
        self._pub.send_string("{} | {} | {}".format(grp, "UPDATE",
                                                    self._state))

        ack = 0
        while ack < nbr:
            self._receiver.recv_string()
            ack += 1
Example #5
0
    def __init__(self, sequence, steps, port_pub, port_pull):

        self._sequence = sequence  # [["GRP1", 2], ["GRP2", 1]]
        self._steps = steps  # [60, 60, 60, 60] (in sec)
        self._state = {}

        logger.debug("ORCH -> created")

        self._pub = self.CONTEXT.socket(zmq.PUB)
        self._pub.bind("tcp://*:{}".format(port_pub))

        logger.debug("ORCH -> PUB to {}".format(port_pub))

        self._receiver = self.CONTEXT.socket(zmq.PULL)
        self._receiver.bind("tcp://*:{}".format(port_pull))

        logger.debug("ORCH -> PULL to {}".format(port_pull))
Example #6
0
    def make_step(self, step, unit, grp, nbr):
        """The make_step() method allow to make a simulation step for a group,
        and used at each step for each group defined in the simulation sequence."""
        logger.debug("ORCH -> GRP {}, STEP {}".format(grp, step))
        self._pub.send_string("{} | {} | {}:{}".format(grp, "STEP", step,
                                                       unit))

        ack = 0
        while ack < nbr:
            string = self._receiver.recv_string()
            node, _, value = string.split(" | ")

            node_state = ast.literal_eval(value)

            if node not in self._state.keys():
                self._state[node] = {}

            for attr, value in node_state.items():
                self._state[node][attr] = value

            ack += 1
            logger.debug("ORCH -> STEP {} {}/{}".format(step, ack, nbr))

        logger.debug("STATE: {}".format(self._state))
Example #7
0
    def run(self):
        """

        """
        for attr, value in self.init_values.items():
            self.set_attribute(attr, value)

        self.sender.send_string("{}".format(self.name))
        logger.debug("INIT VALUES DONE")

        while True:
            string = self.sub.recv_string()
            grp, act, value = string.split(" | ")

            if act == "UPDATE":
                logger.debug("UPDATE")
                self._update_inputs(ast.literal_eval(value))
                self.sender.send_string("{} | Update | Done".format(self.name))
                logger.debug("UPDATE DONE")

            elif act == "STEP":
                logger.debug("STEP")
                self.step(float(value))
                state = {o: self.get_attribute(o) for o in self.outputs}
                for attr, value in state.items():
                    self._send_attribute_value_to_results_db(attr, value, opt="OUT")
                logger.debug("STATE {}".format(state))
                self.sender.send_string("{} | {} | {}".format(self.name, "STATE", state))
                logger.debug("STEP DONE")

            elif act == "END":
                self.exit()
                break
Example #8
0
 def exit(self):
     """[TO OVERRIDE (if an exit action is needed)] The exit() method is called to properly close the model"""
     logger.debug("EXIT")
Example #9
0
 def step(self, value):
     """[TO OVERRIDE] The step() method is called to make a step with the model with a given step size and unit."""
     self.real_time += pd.DateOffset(**{self.time_unit: value})
     self.simu_time += value
     logger.debug("NEW TIME")
Example #10
0
 def get_attribute(self, attr):
     """[TO OVERRIDE] The get_attribute() method is called to get the value of an attribute of the model."""
     logger.debug("GET ATTRIBUTE {}".format(attr))
Example #11
0
 def set_attribute(self, attr, value):
     """[TO OVERRIDE] The set_attribute() method is called to set an attribute of the model to a given value."""
     logger.debug("SET ATTRIBUTE {} to {}".format(attr, value))
Example #12
0
    def __init__(self):
        with open(NODE_CONFIG_FILE) as fp:
            config = json.load(fp)
            logger.debug("LOAD CONFIG NODE")

        self.name = config["NAME"]
        self.group = config["GROUP"]
        self.local = config["LOCAL"]

        self.input_map = ast.literal_eval(config["INPUT_MAP"])
        self.outputs = config["OUTPUTS"]
        self.init_values = config["INIT_VALUES"]
        self.parameters = config["PARAMETERS"]

        self.real_time = pd.to_datetime(config["START"])
        self.time_unit = config["TIME_UNIT"]
        self.simu_time = 0.0

        redis_host = {True: "localhost", False: REDIS_HOST_NAME}[self.local]
        self.redis = redis.StrictRedis(host=redis_host, port=REDIS_PORT, db=0)
        logger.debug("CONNECT REDIS")

        self.sub = zmq.Context().socket(zmq.SUB)
        self.sender = zmq.Context().socket(zmq.PUSH)
        logger.debug("CREATE SUB/SEND")

        zero_host = {True: "localhost", False: ORCH_HOST_NAME}[self.local]
        self.sub.connect("tcp://{}:{}".format(zero_host, PORT_PUB_SUB))
        self.sender.connect("tcp://{}:{}".format(zero_host, PORT_PUSH_PULL))
        logger.debug("CONNECT TO SUB/SEND")

        self.sub.setsockopt_string(zmq.SUBSCRIBE, self.group)
        self.sub.setsockopt_string(zmq.SUBSCRIBE, "ALL")
        logger.debug("SUBSCRIBED TO GRP/ALL")

        logger.debug("INIT DONE")