Пример #1
0
    def __init__(self, system):
        self.system = system

        self.params_built = False
        self.SysParam = dict()
        self.SysName = dict()
        self.Idxvgs = dict()
        self.ModuleInfo = dict()
        self.Varheader = list()
        self.last_devices = list()
        self.has_pmu = False

        config = system.config
        if not config.dime_enabled:
            return
        try:
            self.dimec = DimeClient(
                config.dime_protocol,
                config.dime_address,
            )
            self.dimec.join(config.dime_name)
        except FileNotFoundError:
            logger.error(
                f'Dime sever not found at "{config.dime_address}" over {config.dime_protocol}'
            )
Пример #2
0
    def __init__(self,
                 name,
                 protocol,
                 dime_address,
                 ip_list,
                 port_list=None,
                 dime_port=None,
                 loglevel=logging.INFO):
        self._name = name
        self._dime_address = dime_address
        self._loglevel = loglevel

        self.dimec = DimeClient(protocol, dime_address, dime_port)
        self.dimec.join("ISLANDING")

        self.ip_list = ip_list
        self.port_list = port_list  # not being used now

        # check if the lengths of `ip_list` and `port_list` match

        self.pdc = {}
        self.header = {}
        self.config = {}

        self.last_var = None
        # state flags
        self.andes_online = False
Пример #3
0
    def __init__(self,
                 name: str = '',
                 dime_address: str = 'ipc:///tmp/dime',
                 pmu_idx: list = list(),
                 max_store: int = 1000,
                 pmu_ip: str = '0.0.0.0',
                 pmu_port: int = 1410,
                 **kwargs):
        """
        Create a MiniPMU instance for PMU data streaming over Mininet.

        Assumptions made for

        Parameters
        ----------
        name
        dime_address
        pmu_idx
        max_store
        pmu_ip
        pmu_port
        kwargs
        """
        assert name, 'PMU Receiver name is empty'
        assert pmu_idx, 'PMU idx is empty'
        self.name = name
        self.dime_address = dime_address
        self.pmu_idx = pmu_idx
        self.max_store = max_store

        # for recording
        self.max_store_record = 30 * 600  # 600 seconds

        self.reset = True
        self.pmu_configured = False
        self.pmu_streaming = False

        self.reset_var()

        spl = dime_address.split(":")
        spl[1] = spl[1][2:]
        if len(spl) == 3:
            spl[2] = int(spl[2])
        self.dimec = DimeClient(*spl)
        self.dimec.join(self.name)

        self.pmu = Pmu(ip=pmu_ip, port=pmu_port)
Пример #4
0
    def connect(self):
        """
        Connect to DiME 2 server.

        If ``dime_address`` and ``dime_protocol`` are both specified
        from command-line, streaming will be enabled.
        Otherwise, settings from the Config file will be used.
        """
        config = self.system.config
        options = self.system.options

        # enable only when both arguments are supplied
        if options.get("dime_protocol") is not None and options.get(
                "dime_address") is not None:

            config.dime_enabled = True
            config.dime_protocol = options.get("dime_protocol")
            config.dime_address = options.get("dime_address")

        if not config.dime_enabled:
            return False

        try:
            self.dimec = DimeClient(
                config.dime_protocol,
                config.dime_address,
                config.dime_port,
            )
            self.dimec.join(config.dime_name)
            logger.info(
                f"Dime connection to {config.dime_address} over {config.dime_protocol} was successful."
            )
            return True
        except NameError:
            logger.warning(
                'Dime not installed. Set System config `dime_enabled` to `0` to suppress warning.'
            )
            self.system.config.dime_enabled = False

        except FileNotFoundError:
            logger.warning(
                f'Dime sever not found at "{config.dime_address}" over {config.dime_protocol}.'
            )
            self.system.config.dime_enabled = False

        return False
Пример #5
0
    def connect(self):
        config = self.system.config
        if not config.dime_enabled:
            return False

        try:
            self.dimec = DimeClient(config.dime_protocol,
                                    config.dime_address,
                                    )
            self.dimec.join(config.dime_name)
            logger.info(f"Dime connection to {config.dime_address} over {config.dime_protocol} was successful.")
            return True
        except NameError:
            logger.warning('Dime not installed. Set System config `dime_enabled` to `0` to suppress warning.')
            self.system.config.dime_enabled = False

        except FileNotFoundError:
            logger.warning(f'Dime sever not found at "{config.dime_address}" over {config.dime_protocol}.')
            self.system.config.dime_enabled = False

        return False
Пример #6
0
    def connect(self):
        """
        Connect to DiME 2 server.

        If ``dime_address`` is specified from the command-line,
        streaming will be automatically enabled.
        Otherwise, settings from the Config file will be used.
        """
        config = self.system.config
        options = self.system.options

        # enable only when both arguments are supplied
        if options.get("dime_address") is not None:

            config.dime_enabled = True
            config.dime_address = options.get("dime_address")

        if not config.dime_enabled:
            return False

        try:
            self.dimec = DimeClient(config.dime_address)
            self.dimec.join(config.dime_name)
            logger.info('Dime connection to "%s" was successful.',
                        config.dime_address)
            return True
        except NameError:
            logger.error(
                'Dime not installed. Set System config `dime_enabled` to `0` to suppress warning.'
            )
            self.system.config.dime_enabled = False

        except FileNotFoundError:
            logger.error('Dime sever not found at "%s".', config.dime_address)
            self.system.config.dime_enabled = False

        return False
Пример #7
0
def stresstest(socketfile, counter, counter_mut, barrier):
    with DimeClient("ipc", socketfile) as client:
        client.join(randstring(20), random.choice(TEST_SHARED_GROUPS))

        barrier.wait()

        devices = client.devices()

        while True:
            sent = {}

            for _ in range(3):
                sent[randstring(20)] = np.random.randn(random.randint(2, 500), random.randint(2, 500))

            client.send_r(random.choice(devices), **sent)
            received = client.sync_r()

            ct = 0

            for _, v in received.items():
                ct += v.shape[0] * v.shape[1]

            with counter_mut:
                counter.value += ct
Пример #8
0
import numpy as np
import sys

from dime import DimeClient

if __name__ != "__main__":
    raise RuntimeError()

d1 = DimeClient("tcp", sys.argv[1], int(sys.argv[2]))
d2 = DimeClient("tcp", sys.argv[1], int(sys.argv[2]))

d1.join("d1")
d2.join("d2")

d1["a"] = np.random.rand(500, 500)

d1.send("d2", "a")

d2.sync()

assert np.array_equal(d1["a"], d2["a"])
Пример #9
0
class Streaming:
    """
    ANDES data streaming class to interface with CURENT LTB.
    """
    def __init__(self, system):
        self.system = system

        self.params_built = False
        self.SysParam = dict()
        self.SysName = dict()
        self.Idxvgs = dict()
        self.ModuleInfo = dict()
        self.Varheader = list()
        self.last_devices = list()
        self.has_pmu = False
        self.dimec = None

    def connect(self):
        """
        Connect to DiME 2 server.

        If ``dime_address`` is specified from the command-line,
        streaming will be automatically enabled.
        Otherwise, settings from the Config file will be used.
        """
        config = self.system.config
        options = self.system.options

        # enable only when both arguments are supplied
        if options.get("dime_address") is not None:

            config.dime_enabled = True
            config.dime_address = options.get("dime_address")

        if not config.dime_enabled:
            return False

        try:
            self.dimec = DimeClient(config.dime_address)
            self.dimec.join(config.dime_name)
            logger.info('Dime connection to "%s" was successful.',
                        config.dime_address)
            return True
        except NameError:
            logger.error(
                'Dime not installed. Set System config `dime_enabled` to `0` to suppress warning.'
            )
            self.system.config.dime_enabled = False

        except FileNotFoundError:
            logger.error('Dime sever not found at "%s".', config.dime_address)
            self.system.config.dime_enabled = False

        return False

    def _build_SysParam(self):
        self.SysParam = self.system.as_dict(vin=True, skip_empty=True)
        self.params_built = True

    def _build_SysName(self):
        self.SysName['Bus'] = self.system.Bus.name.v
        if self.system.Area.n:
            self.SysName['Areas'] = self.system.Area.name.v

    def _build_Varheader(self):
        self.Varheader = self.system.dae.xy_name

    def _build_Idxvgs(self):
        m = self.system.dae.m
        n = self.system.dae.n
        mn = m + n  # NOQA

        self.Idxvgs['System'] = {
            'nBus': self.system.Bus.n,
            'nLine': self.system.Line.n,
        }
        self.Idxvgs['Bus'] = {
            'theta': 1 + n + self.system.Bus.a.a,
            'V': 1 + n + self.system.Bus.v.a,
            'w_Busfreq': 1 + n + self.system.BusFreq.f.a,
            # NO LONGER SUPPORTED
            # 'P': 1 + mn + array(range(self.system.Bus.n)),
            # 'Q': 1 + mn + self.system.Bus.n + array(range(self.system.Bus.n)),
        }
        self.Idxvgs['Pmu'] = {
            # NOT YET SUPPORTED
            'vm': 1 + self.system.PMU.vm.a,
            'am': 1 + self.system.PMU.am.a,
        }

        # NOT YET SUPPORTED
        # line0 = 1 + mn + 2 * self.system.Bus.n
        self.Idxvgs['Line'] = {
            # 'Pij': line0 + array(range(self.system.Line.n)),
            # 'Pji': line0 + self.system.Line.n + array(range(self.system.Line.n)),
            # 'Qij': line0 + 2 * self.system.Line.n + array(range(self.system.Line.n)),
            # 'Qji': line0 + 3 * self.system.Line.n + array(range(self.system.Line.n)),
        }

        self.Idxvgs['Syn'] = {
            'delta':
            1 +
            np.append(self.system.GENCLS.delta.a, self.system.GENROU.delta.a),
            'omega':
            1 +
            np.append(self.system.GENCLS.omega.a, self.system.GENROU.omega.a),
            'e1d':
            1 +
            np.append([0] * self.system.GENCLS.n, self.system.GENROU.e1d.a),
            'e1q':
            1 +
            np.append([0] * self.system.GENCLS.n, self.system.GENROU.e1q.a),
            'e2d':
            1 +
            np.append([0] * self.system.GENCLS.n, self.system.GENROU.e2d.a),
            'e2q':
            1 +
            np.append([0] * self.system.GENCLS.n, self.system.GENROU.e2q.a),
            'psid':
            1 +
            np.append([0] * self.system.GENCLS.n, self.system.GENROU.psid.a),
            'psiq':
            1 +
            np.append([0] * self.system.GENCLS.n, self.system.GENROU.psiq.a),
            # NOT SUPPORTED
            # 'p': 1 + n + array([0] * self.system.GENCLS.n + self.system.GENROU.p.a),
            # 'q': 1 + n + array([0] * self.system.GENCLS.n + self.system.GENROU.q.a),
        }
        self.Idxvgs['Tg'] = {
            'pm': 1 + n + self.system.TG2.pout.a,
            'wref': 1 + n + self.system.TG2.wref.a,
        }
        self.Idxvgs['Exc'] = {
            # NOT YET READY
            # 'vf':
            # 1 + n + array(self.system.AVR1.vfout + self.system.AVR2.vfout +
            #               self.system.AVR3.vfout),
            # 'vm':
            # 1 + array(self.system.AVR1.vm + self.system.AVR2.vm +
            #           self.system.AVR3.vm),
        }
        # NOT YET READY

        # if self.system.WTG3.n:
        #     self.Idxvgs['Dfig'] = {
        #         'omega_m': 1 + array(self.system.WTG3.omega_m),
        #         'theta_p': 1 + array(self.system.WTG3.theta_p),
        #         'idr': 1 + array(self.system.WTG3.ird),
        #         'iqr': 1 + array(self.system.WTG3.irq),
        #     }
        # if self.system.Node.n:
        #     self.Idxvgs['Node'] = {'v': 1 + n + array(self.system.Node.v)}
        #
        # dev_id = {
        #     1: 'R',
        #     2: 'C',
        #     3: 'L',
        #     4: 'RCp',
        #     5: 'RCs',
        #     6: 'RLCp',
        #     7: 'RLCs',
        #     8: 'RLs'
        # }
        # if 'DCLine' in self.SysParam:
        #     DCLine_types = set(self.SysParam['DCLine'][:, 2])
        #     idx = []
        #     for item in DCLine_types:
        #         item = int(item)
        #         idx.extend(self.system.__dict__[dev_id[item]].Idc)
        #     self.Idxvgs['DCLine'] = {'Idc': 1 + array(idx)}
        # else:
        #     DCLine_types = ()
        #     # self.Idxvgs['DCLine'] = {}

    def _build_list(self, model, params, ret=None):
        if not ret:
            ret = []
        else:
            ret = list(ret)

        for p in params:
            if type(p) in (int, float):
                ret.append([p] * len(ret[0]))
            elif type(p) == list:
                assert len(p) == len(ret[0])
                ret.append(p)
            else:
                val = list(self.system.__dict__[model].__dict__[p])
                # make sure val does not contain list
                if isinstance(val[0], list):
                    logger.warning(
                        '{}.{} contains list. Reset to zeros.'.format(
                            model, p))
                    val = [0] * len(val)
                ret.append(val)

        return ret

    def _find_pos(self, model, fkey, src_col=0):
        """Find the positions of foreign keys in the source model index list"""
        if type(fkey) == ndarray:
            fkey = fkey.tolist()
        elif type(fkey) in (int, float):
            fkey = [fkey]

        ret = []
        model_idx_list = self.SysParam[model][:, src_col].tolist()
        for item in fkey:
            ret.append(
                model_idx_list.index(item) if item in model_idx_list else 0)

        return ret

    def build_init(self):
        """
        Build `Varheader`, `Idxvgs` and `SysParam` after power flow routine

        """
        self._build_SysParam()
        self._build_SysName()
        self._build_Idxvgs()
        self._build_Varheader()

    def send_init(self, recepient='all'):
        """
        Broadcast `Varheader`, `Idxvgs` and `SysParam`
        to all DiME clients after power flow routine
        """
        if not self.system.config.dime_enabled:
            return
        if not self.params_built:
            self.build_init()

        if recepient == 'all':
            self.last_devices = self.dimec.devices()

            logger.debug('Connected modules are: ' +
                         ','.join(self.dimec.devices()))
            logger.debug(
                'Broadcasting Varheader, Idxvgs, SysParam and SysName...')

            sleep(0.05)
            self.dimec.broadcast_r(Varheader=self.Varheader)

            sleep(0.05)
            self.dimec.broadcast_r(Idxvgs=self.Idxvgs)

            sleep(0.05)
            try:
                self.dimec.broadcast_r(SysParam=self.SysParam)
                self.dimec.broadcast_r(SysName=self.SysName)
            except:  # NOQA
                logger.warning('SysParam or SysName broadcast error.'
                               ' Check bus coordinates.')
            sleep(0.5)
        else:
            if type(recepient) != list:
                recepient = [recepient]
            for item in recepient:
                self.dimec.send_r(item, Varheader=self.Varheader)
                self.dimec.send_r(item, Idxvgs=self.Idxvgs)
                self.dimec.send_r(item, SysParam=self.SysParam)
                self.dimec.send_r(item, SysName=self.SysName)

    def record_module_init(self, name, init_var):
        """
        Record the variable requests from modules
        """
        ivar = dict(init_var)
        var_idx = ivar['vgsvaridx']
        ivar['lastk'] = 0

        if name not in self.ModuleInfo:
            self.ModuleInfo[name] = {}

        if isinstance(var_idx, int):
            var_idx = array(var_idx, dtype=int)
        elif isinstance(var_idx, ndarray):
            var_idx = var_idx.tolist()
            # unwrap if nested
            if isinstance(var_idx[0], list):
                var_idx = array(var_idx[0], dtype=int)
            else:
                var_idx = array(var_idx, dtype=int)

        ivar['vgsvaridx'] = (var_idx - 1).tolist()
        ivar['lastk'] = 0

        self.ModuleInfo[name].update(ivar)

        logger.debug('Module <%s> requests index %s', name, var_idx)

    @staticmethod
    def transpose_matlab_row(a):
        if type(a) is ndarray:
            if a.shape[0] == 1:
                a = a[0]
        return a

    def handle_alter(self, Alter):
        """Handle parameter altering"""
        pass

    def handle_event(self, Event):
        """Handle Fault, Breaker, Syn and Load Events"""
        fields = ('name', 'id', 'action', 'time', 'duration')
        for key in fields:
            if key not in Event:
                logger.warning('Event has missing key {}.'.format(key))
                return

        names = self.transpose_matlab_row(Event.get('name'))
        idxes = self.transpose_matlab_row(Event.get('id'))
        actions = self.transpose_matlab_row(Event.get('action'))
        times = self.transpose_matlab_row(Event.get('time'))
        durations = self.transpose_matlab_row(Event.get('duration'))

        n = len(names)
        for i in range(n):
            try:
                name = names[i]
                idx = idxes[i]
                action = actions[i]  # NOQA
                time = times[i]
                duration = durations[i]
            except IndexError:
                logger.warning(
                    'Event key values might have different lengths.')
                continue

            if time == -1:
                time = max(self.system.dae.t, 0) + self.system.tds.config.tstep

            tf = time + duration
            if duration == 0.:
                tf = 9999

            if name.lower() == 'bus':
                param = {'tf': time, 'tc': tf, 'bus': idx}
                self.system.Fault.insert(**param)
                logger.debug(
                    'Event <Fault> added for bus %s at t = %.6g and tf = %g',
                    idx, time, tf)
            elif name.lower() == 'line':
                bus = self.system.Line.get_field(
                    'bus1', ['Line_' + str(int(idx - 1))])[0]
                param = {
                    'line': 'Line_' + str(idx - 1),
                    'bus': bus,
                    't1': time,
                    't2': tf,
                    'u1': 1,
                    'u2': 1 if duration else 0,
                }
                self.system.Breaker.insert(**param)
                logger.debug(
                    'Event <Breaker> added for line %s at t = %.6g and tf = %g',
                    idx, time, tf)

            self.system.call.build_vec()
            self.system.call._compile_int()
            self.system.dae.rebuild = True

    def sync_and_handle(self):
        """
        Sync until the queue is empty. Handle sync'ed commands.
        """
        if not self.system.config.dime_enabled:
            return
        current_devices = self.dimec.devices()

        # record MiniPMU
        if not self.has_pmu:
            for item in current_devices:
                if item.startswith('PMU_'):
                    self.has_pmu = True

        # send Varheader, SysParam and Idxvgs to modules on the fly
        if set(current_devices) != set(self.last_devices):
            new_devices = list(current_devices)
            new_devices.remove(self.system.config.dime_name)
            for item in self.last_devices:
                if item in new_devices:
                    new_devices.remove(item)
            self.send_init(new_devices)

            self.last_devices = current_devices

        while True:
            var_names = self.dimec.sync(1)

            if not var_names:
                break

            workspace = self.dimec.workspace

            for var_name in var_names:

                var_value = workspace[var_name]

                if var_name in current_devices:
                    self.record_module_init(var_name, var_value)

                elif var_name == 'Event':
                    self.handle_event(var_value)

                else:
                    logger.warning(
                        'Synced variable {} not handled'.format(var_name))

    def vars_to_pmu(self):
        """
        Broadcast all PMU measurements and BusFreq measurements
        in the variable `pmudata`

        """
        if not self.system.config.dime_enabled:
            return
        if not self.has_pmu:
            return

        idx = np.concatenate((
            self.system.PMU.vm.a,
            self.system.PMU.am.a,
            self.system.dae.n + self.system.BusFreq.f.a,
        ))

        t = self.system.dae.t.tolist()
        k = 0  # field `k` is not no use

        values = self.system.dae.xy[
            idx]  # a 1-d array as opposed to a N-by-1 2-d matrix

        pmudata = {
            't': t,
            'k': k,
            'vars': values,
        }
        self.dimec.broadcast_r(pmudata=pmudata)

    def vars_to_modules(self):
        """
        Stream the results from the last step to modules

        :return: None
        """
        if not self.system.config.dime_enabled:
            return

        for mod in self.ModuleInfo.keys():
            # skip PMU modules in this function. offload it to vars_to_pmu()
            if mod.startswith('PMU_'):
                continue

            limitsample = self.ModuleInfo[mod].get('limitsample', 0)

            idx = self.ModuleInfo[mod]['vgsvaridx']
            t = self.system.dae.t.tolist()
            k = 0

            lastk = self.ModuleInfo[mod]['lastk']
            if limitsample:
                every = 1 / self.system.tds.config.tstep / limitsample
                if (k - lastk) / every < 1:
                    continue
                else:
                    self.ModuleInfo[mod]['lastk'] = k

            values = self.system.dae.xy[idx]

            Varvgs = {
                't': t,
                'k': k,
                'vars': values,
                'accurate': values,
            }

            self.dimec.send_r(mod, Varvgs=Varvgs)
            logger.debug("Send Varvgs to module <%s>", mod)

    def finalize(self):
        """
        Send ``DONE`` signal when simulation completes

        :return: None
        """
        if not self.system.config.dime_enabled:
            return

        self.system.streaming.dimec.broadcast_r(DONE=1)
        self.system.streaming.dimec.close()
Пример #10
0
import numpy as np
import sys

from dime import DimeClient

if __name__ != "__main__":
    raise RuntimeError()

d1 = DimeClient("ipc", sys.argv[1])
d2 = DimeClient("ipc", sys.argv[1])

d1.join("d1")
d2.join("d2")

d1["a"] = np.random.rand(500, 500)
d1["b"] = np.random.rand(500, 500)
d1["c"] = np.random.rand(500, 500)
d1["d"] = np.random.rand(500, 500)
d1["e"] = np.random.rand(500, 500)

d2["a"] = None
d2["b"] = None
d2["c"] = None
d2["d"] = None
d2["e"] = None

d1.send("d2", "a", "b", "c")

d2.sync(2)

assert np.array_equal(d1["a"], d2["a"])
Пример #11
0
import numpy as np
import sys

from dime import DimeClient

if __name__ != "__main__":
    raise RuntimeError()

d1 = DimeClient("ipc", sys.argv[1])
d2 = DimeClient("ipc", sys.argv[1])
d3 = DimeClient("ipc", sys.argv[1])

d1.join("d1")
d2.join("d2")

d1["a"] = np.random.rand(500, 500)
d1["b"] = np.random.rand(500, 500)
d1["c"] = np.random.rand(500, 500)

d1.broadcast("a", "b", "c")

d2.sync()

assert np.array_equal(d1["a"], d2["a"])
assert np.array_equal(d1["b"], d2["b"])
assert np.array_equal(d1["c"], d2["c"])

d3.sync()

assert np.array_equal(d1["a"], d3["a"])
assert np.array_equal(d1["b"], d3["b"])
Пример #12
0
class MiniPDC(object):
    """A MiniPDC connecting to multiple PMUs and a DiME server
    """
    def __init__(self,
                 name,
                 protocol,
                 dime_address,
                 ip_list,
                 port_list=None,
                 dime_port=None,
                 loglevel=logging.INFO):
        self._name = name
        self._dime_address = dime_address
        self._loglevel = loglevel

        self.dimec = DimeClient(protocol, dime_address, dime_port)
        self.dimec.join("ISLANDING")

        self.ip_list = ip_list
        self.port_list = port_list  # not being used now

        # check if the lengths of `ip_list` and `port_list` match

        self.pdc = {}
        self.header = {}
        self.config = {}

        self.last_var = None
        # state flags
        self.andes_online = False
        # self.pdc_started = False

    @property
    def npmu(self):
        return len(self.ip_list)

    def initialize(self):
        """
        Reset or initialize, it is the same thing
        Returns
        -------

        """
        pass

    def sync_and_handle(self):
        """ Sync from DiME and handle the received data
        """
        self.last_var = self.dimec.sync(1)

        if len(self.last_var) == 0:
            return None

        self.last_var = list(self.last_var)[0]

        val = self.dimec.workspace[self.last_var]

        if self.last_var == 'DONE' and int(val) == 1:
            self.andes_online = False
            self.initialize()
            pass

        return self.last_var

    def start_dime(self):
        logger.info('Connecting to DiME at {}'.format(self._dime_address))
        logger.info('DiME connected')

    def init_pdc(self):

        for idx, item in enumerate(self.ip_list):
            pmu_idx = int(item.split('.')[3])

            self.pdc[idx] = Pdc(pdc_id=pmu_idx,
                                pmu_ip=self.ip_list[idx],
                                pmu_port=1410)

            self.pdc[idx].logger.setLevel("INFO")
        logger.info('PDC initialized')

    def get_header_config(self):
        for idx, item in self.pdc.items():  # each item is a PDC
            item.run()  # Connect to PMU

            self.header[idx] = item.get_header()
            self.config[idx] = item.get_config()

        for idx, item in self.pdc.items():  # each item is a PDC
            item.start()  # Request to start sending measurements
            self.pdc_started = True

        logger.info('PMU Header and ConfigFrame received')

    def collect_data(self):
        pass

    def process_data(self):
        pass

    def run(self):
        pass
Пример #13
0
ca.yaxis.set_tick_params(labelsize=12)

plt.ion()
plt.show()
plt.pause(0.1)

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(message)s')

fh = logging.FileHandler('/var/log/minipdc.log')
fh.setFormatter(formatter)
logger.addHandler(fh)

dimec = DimeClient('tcp', '192.168.1.20', 5000)
dimec.join("ISLANDING")

ISLANDING = {'vgsvaridx': np.array([1, 2])}
ISLANDING_idx = {'fdev': np.array([1]), 'thresh': np.array([2])}
ISLANDING_vars = {'t': 0, 'vars': np.array([0, 0.4])}
ISLANDING_header = ['fdev_WECC', 'thresh_WECC']
ISLANDING_info = ''


class MiniPDC(object):
    """A MiniPDC connecting to multiple PMUs and a DiME server
    """
    def __init__(self,
                 name,
                 protocol,
Пример #14
0
class MiniPMU(object):
    def __init__(self,
                 name: str = '',
                 dime_address: str = 'ipc:///tmp/dime',
                 pmu_idx: list = list(),
                 max_store: int = 1000,
                 pmu_ip: str = '0.0.0.0',
                 pmu_port: int = 1410,
                 **kwargs):
        """
        Create a MiniPMU instance for PMU data streaming over Mininet.

        Assumptions made for

        Parameters
        ----------
        name
        dime_address
        pmu_idx
        max_store
        pmu_ip
        pmu_port
        kwargs
        """
        assert name, 'PMU Receiver name is empty'
        assert pmu_idx, 'PMU idx is empty'
        self.name = name
        self.dime_address = dime_address
        self.pmu_idx = pmu_idx
        self.max_store = max_store

        # for recording
        self.max_store_record = 30 * 600  # 600 seconds

        self.reset = True
        self.pmu_configured = False
        self.pmu_streaming = False

        self.reset_var()

        spl = dime_address.split(":")
        spl[1] = spl[1][2:]
        if len(spl) == 3:
            spl[2] = int(spl[2])
        self.dimec = DimeClient(*spl)
        self.dimec.join(self.name)

        self.pmu = Pmu(ip=pmu_ip, port=pmu_port)

    def reset_var(self, retain_data=False):
        """
        Reset flags and memory
        :return: None
        """
        if not self.reset:
            return

        self.bus_name = []
        self.var_idx = {
            'am': [],
            'vm': [],
            'w': [],
        }

        self.fn = 60
        self.Vn = []

        self.Varheader = list()
        self.Idxvgs = dict()
        self.SysParam = dict()
        self.SysName = dict()
        self.Varvgs = ndarray([])

        self.t = ndarray([])
        self.data = ndarray([])
        self.count = 0

        # recording storage
        if not retain_data:
            self.t_record = ndarray([])
            self.data_record = ndarray([])
            self.count_record = 0
            self.counter_replay = 0  # replay index into `data_record` and `t_record`
            self.record_state = RecordState.IDLE

        self.last_data = None
        self.last_t = None

    def start_dime(self):
        """
        Starts the dime client stored in `self.dimec`
        """
        logger.info('Connecting to server at %s', self.dime_address)
        pass

        # logger.info('DiME client connected')

    def respond_to_sim(self):
        """
        DEPRECIATED: Respond with data streaming configuration to the simulator

        :return: None
        """
        pass

    def get_bus_name(self):
        """
        Return bus names based on ``self.pmu_idx`` and store bus names to
        ``self.bus_name``

        :return: list of bus names
        """

        # assign generic bus names
        self.bus_name = list(self.pmu_idx)

        for i in range(len(self.bus_name)):
            self.bus_name[i] = 'Bus_' + str(self.bus_name[i])

        # assign names from SysName if present
        if len(self.SysName) > 0:
            for i in range(len(self.bus_name)):
                self.bus_name[i] = self.SysName['Bus'][self.pmu_idx[i] - 1]

        # logger.debug('PMU names changed to: {}'.format(self.bus_name))
        return self.bus_name

    def get_bus_Vn(self):
        """
        Retrieve Bus.Vn

        Returns
        -------

        """
        self.Vn = [1] * len(self.pmu_idx)

        for i, idx in enumerate(self.pmu_idx):
            self.Vn[i] = self.SysParam['Bus']['Vn'][idx] * 1000  # get Vn

        logger.info('Retrieved bus Vn %g', self.Vn)

    def config_pmu(self):
        """
        Sets the ConfigFrame2 of the PMU

        :return: None
        """

        self.cfg = ConfigFrame2(
            pmu_id_code=self.pmu_idx[0],  # PMU_ID
            time_base=1000000,  # TIME_BASE
            num_pmu=1,  # Number of PMUs included in data frame
            station_name=self.bus_name[0],  # Station name
            id_code=self.pmu_idx[0],  # Data-stream ID(s)
            data_format=(
                True, True, True, True
            ),  # Data format - POLAR; PH - REAL; AN - REAL; FREQ - REAL;
            phasor_num=1,  # Number of phasors
            analog_num=1,  # Number of analog values
            digital_num=1,  # Number of digital status words
            channel_names=[
                "V_PHASOR", "ANALOG1", "BREAKER 1 STATUS", "BREAKER 2 STATUS",
                "BREAKER 3 STATUS", "BREAKER 4 STATUS", "BREAKER 5 STATUS",
                "BREAKER 6 STATUS", "BREAKER 7 STATUS", "BREAKER 8 STATUS",
                "BREAKER 9 STATUS", "BREAKER A STATUS", "BREAKER B STATUS",
                "BREAKER C STATUS", "BREAKER D STATUS", "BREAKER E STATUS",
                "BREAKER F STATUS", "BREAKER G STATUS"
            ],  # Channel Names
            ph_units=[
                (0, 'v')
            ],  # Conversion factor for phasor channels - (float representation, not important)
            an_units=[(1, 'pow')],  # Conversion factor for analog channels
            dig_units=[(0x0000, 0xffff)
                       ],  # Mask words for digital status words
            f_nom=60.0,  # Nominal frequency
            cfg_count=1,  # Configuration change count
            data_rate=30)  # Rate of phasor data transmission)

        self.hf = HeaderFrame(
            self.pmu_idx[0],  # PMU_ID
            "MiniPMU <{name}> {pmu_idx}".format(
                name=self.name, pmu_idx=self.pmu_idx))  # Header Message

        self.pmu.set_configuration(self.cfg)
        self.pmu.set_header(self.hf)
        # self.pmu.run()

    def find_var_idx(self):
        """
        Returns a dictionary of the indices into Varheader based on
        `self.pmu_idx`. Items in `self.pmu_idx` uses 1-indexing.

        For example, if `self.pmu_idx` == [1, 2], this function will return
        the indices of
         - Idxvgs.Pmu.vm[0] and Idxvgs.Pmu.vm[1] as vm
         - Idxvgs.Pmu.am[0] and Idxvgs.Pmu.am[1] as am
         - Idxvgs.Bus.w_Busfreq[0] and Idxvgs.Bus.w_Busfreq[1] as w
        in the dictionary `self. var_idx` with the above fields.

        :return: ``var_idx`` in ``pmudata``
        """
        npmu = len(self.Idxvgs['Pmu']['vm'])

        self.var_idx['vm'] = [int(i) - 1 for i in self.pmu_idx]
        self.var_idx['am'] = [npmu + int(i) - 1 for i in self.pmu_idx]
        self.var_idx['w'] = [2 * npmu + int(i) - 1 for i in self.pmu_idx]

    # TODO: make it static
    @property
    def vgsvaridx(self):
        return array(self.var_idx['vm'] + self.var_idx['am'] +
                     self.var_idx['w'],
                     dtype=int)

    def init_storage(self, flush=False):
        """
        Initialize data storage `self.t` and `self.data`

        :return: if the storage has been reset
        """
        # TODO: make it more efficient??
        ret = False

        if self.count % self.max_store == 0:
            self.t = zeros(shape=(self.max_store, 1), dtype=float)
            self.data = zeros(shape=(self.max_store, len(self.pmu_idx * 3)),
                              dtype=float)
            self.count = 0
            ret = True
        else:
            ret = False

        if (self.count_record % self.max_store_record == 0) or (flush is True):
            self.t_record = zeros(shape=(self.max_store_record, 1),
                                  dtype=float)
            self.data_record = zeros(shape=(self.max_store_record,
                                            len(self.pmu_idx * 3)),
                                     dtype=float)
            self.count_record = 0
            self.counter_replay = 0

            ret = ret and True
        else:
            ret = False

        return ret

    def sync_and_handle(self):
        """
        Sync and call data processing functins

        :return:
        """
        ret = False

        var = list(self.dimec.sync(1))

        if len(var) == 0:
            return ret

        var = var[0]

        if self.reset is True:
            logger.info('[%s] variable <%s> synced.', self.name, var)

        data = self.dimec.workspace[var]

        if var in ('SysParam', 'Idxvgs', 'Varheader'):
            # only handle these three variables during reset cycle

            if self.reset is True:
                self.__dict__[var] = data
            # else:
            #     logger.info('{} not handled outside reset cycle'.format(var))

        elif var == 'pmudata':
            # only handle pmudata during normal cycle
            if self.reset is False:
                logger.info('In, t=%.4f', data['t'])
                self.handle_measurement_data(data)
            # else:
            #     logger.info('{} not handled during reset cycle'.format(var))

        # handle SysName any time
        elif var == 'SysName':
            self.__dict__[var] = data
            self.get_bus_name()

        elif var == 'DONE' and data == 1:
            self.reset = True
            self.reset_var(retain_data=True)

        elif var == 'pmucmd' and isinstance(data, dict):
            cmd = ''
            if data.get('record', 0) == 1:
                # start recording
                if self.record_state == RecordState.IDLE \
                        or self.record_state == RecordState.RECORDED:

                    self.record_state = RecordState.RECORDING
                    cmd = 'start recording'
                # else:
                #     logger.warning('cannot start recording in state {}'
                #                    .format(self.record_state))

            elif data.get('record', 0) == 2:
                # stop recording if started
                if self.record_state == RecordState.RECORDING:
                    cmd = 'stop recording'
                    self.record_state = RecordState.RECORDED
                # else:
                #     logger.warning('cannot stop recording in state {}'
                #                    .format(self.record_state))

            if data.get('replay', 0) == 1:
                # start replay
                if self.record_state == RecordState.RECORDED:
                    cmd = 'start replay'
                    self.record_state = RecordState.REPLAYING
                # else:
                #     logger.warning('cannot start replaying in state {}'
                #                    .format(self.record_state))
            if data.get('replay', 0) == 2:
                # stop replay but retain the saved data
                if self.record_state == RecordState.REPLAYING:
                    cmd = 'stop replay'
                    self.record_state = RecordState.RECORDED
                # else:
                #     logger.warning('cannot stop replaying in state {}'
                #                    .format(self.record_state))
            if data.get('flush', 0) == 1:
                # flush storage
                cmd = 'flush storage'
                self.init_storage(flush=True)
                self.record_state = RecordState.IDLE

            # if cmd:
            #     logger.info('[{name}] <{cmd}>'.format(name=self.name, cmd=cmd))

        # else:
        #     logger.info('[{name}] {cmd} not handled during normal ops'
        #                 .format(name=self.name, cmd=var))

        return var

    def handle_measurement_data(self, data):
        """
        Store synced data into self.data and return in a tuple of (t, values)

        :return: (t, vars)
        """
        self.init_storage()

        self.data[self.count, :] = data['vars'][self.vgsvaridx]
        self.t[self.count, :] = data['t']
        self.count += 1

        # record
        if self.record_state == RecordState.RECORDING:
            self.data_record[self.count_record, :] = \
                    data['vars'][self.vgsvaridx]

            self.t_record[self.count_record, :] = data['t']
            self.count_record += 1

        self.last_data = data['vars']
        self.last_t = data['t']

        return data['t'], data['vars']

    def run(self):
        """
        Process control function

        :return None
        """
        self.start_dime()
        self.pmu.run()

        while True:
            if self.reset is True:
                # receive init and respond
                # logger.info('[{name}] Entering reset mode..'
                #             .format(name=self.name))

                while True:
                    var = self.sync_and_handle()

                    if var is False:
                        time.sleep(0.01)

                    if len(self.Varheader) > 0\
                            and len(self.Idxvgs) > 0\
                            and len(self.SysParam) > 0 \
                            and len(self.SysName) > 0:

                        self.find_var_idx()
                        self.get_bus_Vn()

                        break

                self.respond_to_sim()

                if self.pmu_configured is False:
                    self.config_pmu()
                    self.pmu_configured = True

                self.reset = False

            # logger.debug('Entering sync and short sleep...')

            var = self.sync_and_handle()
            time.sleep(0.001)

            if var is False:
                continue

            elif var == 'pmudata':
                if self.pmu.clients and not self.reset:

                    if self.record_state == RecordState.REPLAYING:
                        # prepare recorded data
                        npmu = len(self.pmu_idx)
                        v_mag = self.data_record[
                            self.counter_replay, :npmu] * self.Vn[0]
                        v_ang = wrap_angle(
                            self.data_record[self.counter_replay,
                                             npmu:2 * npmu])
                        v_freq = self.data_record[self.counter_replay,
                                                  2 * npmu:3 * npmu] * self.fn
                        self.counter_replay += 1

                        # at the end of replay, reset
                        if self.counter_replay == self.count_record:
                            self.counter_replay = 0
                            self.record_state = RecordState.RECORDED

                    else:
                        # use fresh data
                        v_mag = self.last_data[self.var_idx['vm']] * self.Vn[0]
                        v_ang = wrap_angle(self.last_data[self.var_idx['am']])
                        v_freq = self.last_data[self.var_idx['w']] * self.fn

                    # TODO: add noise to data

                    try:
                        # TODO: fix multiple measurement (multi-bus -> one PMU case)
                        self.pmu.send_data(
                            phasors=[(v_mag, v_ang)],
                            analog=[9.99],
                            digital=[0x0001],
                            #freq=(v_freq-60)*1000
                            freq=v_freq)

                        # logger.info('Out, f={f:.5f}, vm={vm:.1f}, am={am:.2f}'.format(f=v_freq[0], vm=v_mag[0], am=v_ang[0]))

                    except Exception as e:
                        logger.exception(e)
Пример #15
0
import numpy as np
import sys

from dime import DimeClient

if __name__ != "__main__":
    raise RuntimeError()

d1 = DimeClient("ipc", sys.argv[1])
d2 = DimeClient("ipc", sys.argv[1])
d3 = DimeClient("ipc", sys.argv[1])
d4 = DimeClient("ipc", sys.argv[1])

d1.join("a", "b", "c", "d", "e")
d2.join("a", "b", "c")
d3.join("e", "f")
d4.join("g")

devices = d1.devices()
devices.sort()

assert devices == ["a", "b", "c", "d", "e", "f", "g"]

d1.leave("a", "b", "c", "d")
d2.leave("a", "b")
d3.leave("e", "f")

d1.join("b")
d3.join("h")
d4.join("f")
import math
import numpy as np
import sys
import time

from dime import DimeClient

d = DimeClient("ipc", sys.argv[1]);
d.join("python");

while "matlab" not in d.devices():
    time.sleep(0.05)

time.sleep(1)

d.sync()

assert d["nothing"] is None
assert d["boolean"] is True
assert d["float"] == math.pi
assert d["int"] == 0xDEADBEEF
assert d["complexfloat"] == complex(math.sqrt(0.75), 0.5)
assert np.array_equal(d["matrix"], np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9.01]]))
assert d["string"] == "Hello world!"
assert d["sequence"] == [-1, ":)", False, None]
assert d["mapping"] == {"foo": 2, "bar": "Green eggs and spam"}

d.send("matlab", "nothing", "boolean", "int", "float", "complexfloat", "matrix", "string", "sequence", "mapping");
Пример #17
0
import numpy as np
import signal
import sys
import time

from dime import DimeClient

if __name__ != "__main__":
    raise RuntimeError()


def timeout(signum, frame):
    raise RuntimeError("\"wait\" command timed out")


d = DimeClient("ipc", sys.argv[1])

if int(sys.argv[2]) == 0:
    d.join("d1")

    while "d2" not in d.devices():
        time.sleep(0.05)

    d["a"] = "ping"
    d.send("d2", "a")

    n = d.wait()
    assert n == 1 or n == 2
    d.sync(1)

    assert d["a"] == "pong"