示例#1
0
    def set_address(self, models=None):
        """
        Set addresses for differential and algebraic variables.
        """
        if models is None:
            models = self._models_flag['pflow']

        # set internal variable addresses
        for mdl in models.values():
            if mdl.flags['address'] is True:
                logger.debug(f'{mdl.class_name:10s}: addresses exist.')
                continue
            if mdl.n == 0:
                continue

            n = mdl.n
            m0 = self.dae.m
            n0 = self.dae.n
            m_end = m0 + len(mdl.algebs) * n
            n_end = n0 + len(mdl.states) * n
            collate = mdl.flags['collate']

            if not collate:
                for idx, item in enumerate(mdl.algebs.values()):
                    item.set_address(np.arange(m0 + idx * n, m0 + (idx + 1) * n))
                for idx, item in enumerate(mdl.states.values()):
                    item.set_address(np.arange(n0 + idx * n, n0 + (idx + 1) * n))
            else:
                for idx, item in enumerate(mdl.algebs.values()):
                    item.set_address(np.arange(m0 + idx, m_end, len(mdl.algebs)))
                for idx, item in enumerate(mdl.states.values()):
                    item.set_address(np.arange(n0 + idx, n_end, len(mdl.states)))

            self.dae.m = m_end
            self.dae.n = n_end
            mdl.flags['address'] = True

        # set external variable addresses
        for mdl in models.values():
            # handle external groups
            for name, instance in mdl.cache.vars_ext.items():
                ext_name = instance.model
                try:
                    ext_model = self.__dict__[ext_name]
                except KeyError:
                    raise KeyError(f'<{ext_name}> is not a model or group name.')

                instance.link_external(ext_model)

        # pre-allocate for names
        if len(self.dae.y_name) == 0:
            self.dae.x_name = [''] * self.dae.n
            self.dae.y_name = [''] * self.dae.m
            self.dae.x_tex_name = [''] * self.dae.n
            self.dae.y_tex_name = [''] * self.dae.m
        else:
            self.dae.x_name.extend([''] * (self.dae.n - len(self.dae.x_name)))
            self.dae.y_name.extend([''] * (self.dae.m - len(self.dae.y_name)))
            self.dae.x_tex_name.extend([''] * (self.dae.n - len(self.dae.x_tex_name)))
            self.dae.y_tex_name.extend([''] * (self.dae.m - len(self.dae.y_tex_name)))
示例#2
0
    def store_sparse_pattern(self,
                             models: Optional[Union[str, List,
                                                    OrderedDict]] = None):
        models = self._get_models(models)
        self._call_models_method('store_sparse_pattern', models)

        # add variable jacobian values
        for j_name in self.dae.jac_name:
            ii, jj, vv = list(), list(), list()

            # for `gy` matrix, always make sure the diagonal is reserved
            # It is a safeguard if the modeling user omitted the diagonal
            # term in the equations
            if j_name == 'gy':
                ii.extend(np.arange(self.dae.m))
                jj.extend(np.arange(self.dae.m))
                vv.extend(np.zeros(self.dae.m))

            # logger.debug(f'Jac <{j_name}>, row={ii}')

            for mdl in models.values():
                row_idx = mdl.row_of(f'{j_name}')
                col_idx = mdl.col_of(f'{j_name}')

                # logger.debug(f'Model <{name}>, row={row_idx}')
                ii.extend(row_idx)
                jj.extend(col_idx)
                vv.extend(np.zeros(len(np.array(row_idx))))

                # add the constant jacobian values
                for row, col, val in mdl.zip_ijv(f'{j_name}c'):
                    ii.extend(row)
                    jj.extend(col)

                    if isinstance(val, (float, int)):
                        vv.extend(val * np.ones(len(row)))
                    elif isinstance(val, (list, np.ndarray)):
                        vv.extend(val)
                    else:
                        raise TypeError(
                            f'Unknown type {type(val)} in constant jacobian {j_name}'
                        )

            if len(ii) > 0:
                ii = np.array(ii).astype(int)
                jj = np.array(jj).astype(int)
                vv = np.array(vv).astype(float)

            self.dae.store_sparse_ijv(j_name, ii, jj, vv)
            self.dae.build_pattern(j_name)
示例#3
0
    def _run_odeint(self, tspan, x0=None, asolver=None, verbose=False, h=0.05, hmax=0, hmin=0):
        """
        Run integration with ``scipy.odeint``.

        Warnings
        --------
        Function is NOT working. The time-based switching is not handled correctly.
        """
        self._initialize()
        if x0 is None:
            x0 = self.system.dae.x
        times = np.arange(tspan[0], tspan[1], h)

        # build critical time list
        tcrit = np.hstack([np.linspace(i, i+0.5, 100) for i in self.system.switch_times])
        ret = odeint(self._solve_ivp_wrapper,
                     x0,
                     times,
                     tfirst=True,
                     args=(asolver, verbose),
                     full_output=True,
                     hmax=hmax,
                     hmin=hmin,
                     tcrit=tcrit
                     )

        # store the last step algebraic variables
        self.system.dae.store_yt_single()
        self.system.dae.store_xt_array(ret[0], times)
        return ret
示例#4
0
    def link_external(self, ext_model):
        """
        Update parameter values provided by external models. This needs to be called before pu conversion.

        Parameters
        ----------
        ext_model : Model, Group
            Instance of the parent model or group, provided by the System calling this method.

        """
        self.parent_model = ext_model

        if hasattr(ext_model, "_idx2model"):
            # copy properties from models in the group

            # TODO: the three `get` calls below is a bit inefficient - same loops for three times
            try:
                self.v = ext_model.get(src=self.src, idx=self.indexer.v, attr='v',
                                       allow_none=self.allow_none, default=self.default)
            except IndexError:
                pass

            try:
                self.vin = ext_model.get(src=self.src, idx=self.indexer.v, attr='vin',
                                         allow_none=self.allow_none, default=self.default)
                self.pu_coeff = ext_model.get(src=self.src, idx=self.indexer.v, attr='vin',
                                              allow_none=self.allow_none, default=self.default)
            except KeyError:  # idx param without vin
                pass
            except TypeError:  # vin or pu_coeff is None
                pass

        else:
            if self.allow_none:
                raise NotImplementedError(f"{self.name}: allow_none not implemented for Model")

            parent_instance = ext_model.__dict__[self.src]
            self.property = dict(parent_instance.property)

            if self.indexer is None:
                # if `idx` is None, retrieve all the values
                uid = np.arange(ext_model.n)
            else:
                if len(self.indexer.v) == 0:
                    return
                else:
                    uid = ext_model.idx2uid(self.indexer.v)

            # pull in values
            if isinstance(parent_instance.v, np.ndarray):
                self.v = parent_instance.v[uid]
            else:
                self.v = [parent_instance.v[i] for i in uid]
            try:
                self.vin = parent_instance.vin[uid]
                self.pu_coeff = parent_instance.pu_coeff[uid]
            except KeyError:
                pass
            except AttributeError:
                pass
示例#5
0
    def check_var(self, dae_t, *args, **kwargs):

        # Storage:
        # Output values is in the first col.
        # Latest values are stored in /appended to the last column
        self.rewind = False

        if dae_t == 0:
            self._v_mem[:] = self.u.v[:, None]

        elif dae_t < self.t[-1]:
            self.rewind = True
            self.t[-1] = dae_t
            self._v_mem[:, -1] = self.u.v

        elif dae_t == self.t[-1]:
            self._v_mem[:, -1] = self.u.v

        elif dae_t > self.t[-1]:
            if self.mode == 'step':
                self.t[:-1] = self.t[1:]
                self.t[-1] = dae_t

                self._v_mem[:, :-1] = self._v_mem[:, 1:]
                self._v_mem[:, -1] = self.u.v
            else:
                self.t = np.append(self.t, dae_t)
                self._v_mem = np.hstack((self._v_mem, self.u.v[:, None]))

                if dae_t - self.t[0] > self.delay:
                    t_interp = dae_t - self.delay
                    idx = np.argmax(self.t >= t_interp) - 1
                    v_interp = interp_n2(t_interp, self.t[idx:idx + 2],
                                         self._v_mem[:, idx:idx + 2])

                    self.t[idx] = t_interp
                    self._v_mem[:, idx] = v_interp

                    self.t = np.delete(self.t, np.arange(0, idx))
                    self._v_mem = np.delete(self._v_mem,
                                            np.arange(0, idx),
                                            axis=1)

        self.v[:] = self._v_mem[:, 0]
示例#6
0
    def store_sparse_pattern(self, models: Optional[Union[str, List, OrderedDict]] = None):
        """
        Collect and store the sparsity pattern of Jacobian matrices.

        This is a runtime function specific to cases.

        Notes
        -----
        For `gy` matrix, always make sure the diagonal is reserved.
        It is a safeguard if the modeling user omitted the diagonal
        term in the equations.
        """
        models = self._get_models(models)
        self._call_models_method('store_sparse_pattern', models)

        # add variable jacobian values
        for jname in jac_names:
            ii, jj, vv = list(), list(), list()

            if jname == 'gy':
                ii.extend(np.arange(self.dae.m))
                jj.extend(np.arange(self.dae.m))
                vv.extend(np.zeros(self.dae.m))

            for mdl in models.values():
                for row, col, val in mdl.triplets.zip_ijv(jname):
                    ii.extend(row)
                    jj.extend(col)
                    vv.extend(np.zeros_like(row))
                for row, col, val in mdl.triplets.zip_ijv(jname + 'c'):
                    # process constant Jacobians separately
                    ii.extend(row)
                    jj.extend(col)
                    vv.extend(val * np.ones_like(row))

            if len(ii) > 0:
                ii = np.array(ii, dtype=int)
                jj = np.array(jj, dtype=int)
                vv = np.array(vv, dtype=float)

            self.dae.store_sparse_ijv(jname, ii, jj, vv)
            self.dae.build_pattern(jname)
示例#7
0
文件: var.py 项目: JiweiTian/andes
    def link_external(self, ext_model):
        """
        Update variable addresses provided by external models

        This method sets attributes including `parent_model`,
        `parent_instance`, `uid`, `a`, `n`, `e_code` and
        `v_code`. It initializes the `e` and `v` to zero.

        Returns
        -------
        None

        Parameters
        ----------
        ext_model : Model
            Instance of the parent model
        """
        self.parent = ext_model

        if isinstance(ext_model, GroupBase):
            if self.indexer.n > 0 and isinstance(self.indexer.v[0],
                                                 (list, np.ndarray)):
                self._n = [len(i) for i in self.indexer.v
                           ]  # number of elements in each sublist
                self._idx = np.concatenate(
                    [np.array(i) for i in self.indexer.v])
            else:
                self._n = [len(self.indexer.v)]
                self._idx = self.indexer.v

            self.a = ext_model.get(src=self.src, idx=self._idx,
                                   attr='a').astype(int)
            self.n = len(self.a)
            self.v = np.zeros(self.n)
            self.e = np.zeros(self.n)

        else:
            original_var = ext_model.__dict__[self.src]

            if self.indexer is not None:
                uid = ext_model.idx2uid(self.indexer.v)
            else:
                uid = np.arange(ext_model.n, dtype=int)

            self._n = [len(uid)]
            if len(uid) > 0:
                self.a = original_var.a[uid]
            else:
                self.a = np.array([], dtype=int)

            # set initial v and e values to zero
            self.n = len(self.a)
            self.v = np.zeros(self.n)
            self.e = np.zeros(self.n)
示例#8
0
    def plot(self, left=-6, right=0.5, ymin=-8, ymax=8, damping=0.05,
             linewidth=0.5, dpi=150):
        mpl.rc('font', family='Times New Roman', size=12)

        mu_real = self.mu.real()
        mu_imag = self.mu.imag()
        p_mu_real, p_mu_imag = list(), list()
        z_mu_real, z_mu_imag = list(), list()
        n_mu_real, n_mu_imag = list(), list()

        for re, im in zip(mu_real, mu_imag):
            if re == 0:
                z_mu_real.append(re)
                z_mu_imag.append(im)
            elif re > 0:
                p_mu_real.append(re)
                p_mu_imag.append(im)
            elif re < 0:
                n_mu_real.append(re)
                n_mu_imag.append(im)

        if len(p_mu_real) > 0:
            logger.warning(
                'System is not stable due to {} positive eigenvalues.'.format(
                    len(p_mu_real)))
        else:
            logger.info(
                'System is small-signal stable in the initial neighbourhood.')

        mpl.rc('text', usetex=True)
        fig, ax = plt.subplots(dpi=dpi)
        ax.scatter(n_mu_real, n_mu_imag, marker='x', s=40, linewidth=0.5, color='black')
        ax.scatter(z_mu_real, z_mu_imag, marker='o', s=40, linewidth=0.5, facecolors='none', edgecolors='black')
        ax.scatter(p_mu_real, p_mu_imag, marker='x', s=40, linewidth=0.5, color='black')
        ax.axhline(linewidth=0.5, color='grey', linestyle='--')
        ax.axvline(linewidth=0.5, color='grey', linestyle='--')

        # plot 5% damping lines
        xin = np.arange(left, 0, 0.01)
        yneg = xin / damping
        ypos = - xin / damping

        ax.plot(xin, yneg, color='grey', linewidth=linewidth, linestyle='--')
        ax.plot(xin, ypos, color='grey', linewidth=linewidth, linestyle='--')
        ax.set_xlabel('Real')
        ax.set_ylabel('Imaginary')
        ax.set_xlim(left=left, right=right)
        ax.set_ylim(ymin, ymax)

        plt.show()

        return fig, ax
示例#9
0
文件: param.py 项目: JiweiTian/andes
    def link_external(self, ext_model):
        """
        Update parameter values provided by external models. This needs to be called before pu conversion.

        TODO: Check if the pu conversion is correct or not.

        Parameters
        ----------
        ext_model : Model, Group
            Instance of the parent model or group, provided by the System calling this method.

        """
        self.parent_model = ext_model

        if isinstance(ext_model, GroupBase):

            # TODO: the three lines below is a bit inefficient - 3x same loops
            self.v = ext_model.get(src=self.src, idx=self.indexer.v, attr='v')
            try:
                self.vin = ext_model.get(src=self.src,
                                         idx=self.indexer.v,
                                         attr='vin')
                self.pu_coeff = ext_model.get(src=self.src,
                                              idx=self.indexer.v,
                                              attr='vin')
            except KeyError:  # idx param without vin
                pass

            # TODO: copy properties from models in the group

        else:
            parent_instance = ext_model.__dict__[self.src]
            self.property = dict(parent_instance.property)

            if self.indexer is None:
                # if `idx` is None, retrieve all the values
                uid = np.arange(ext_model.n)
            else:
                if len(self.indexer.v) == 0:
                    return
                else:
                    uid = ext_model.idx2uid(self.indexer.v)

            # pull in values
            self.v = parent_instance.v[uid]
            try:
                self.vin = parent_instance.vin[uid]
                self.pu_coeff = parent_instance.pu_coeff[uid]
            except KeyError:
                pass
示例#10
0
文件: var.py 项目: treymingee/andes
    def link_external(self, ext_model):
        """
        Update variable addresses provided by external models

        This method sets attributes including `parent_model`,
        `parent_instance`, `uid`, `a`, `n`, `e_code` and
        `v_code`. It initializes the `e` and `v` to zero.

        Returns
        -------
        None

        Parameters
        ----------
        ext_model : Model
            Instance of the parent model

        Warnings
        --------
        `link_external` does not check if the ExtVar type is the same
        as the original variable to reduce performance overhead.
        It will be a silent error (a dimension too small error from `dae.build_pattern`)
        if a model uses `ExtAlgeb` to access a `State`, or vice versa.

        """

        self.parent = ext_model

        if isinstance(ext_model, GroupBase):
            # determine the number of elements based on `indexer.v`
            if self.indexer.n > 0 and isinstance(self.indexer.v[0],
                                                 (list, np.ndarray)):
                self._n = [len(i) for i in self.indexer.v
                           ]  # number of elements in each sublist
                self._idx = np.concatenate(
                    [np.array(i) for i in self.indexer.v])
            else:
                self._n = [len(self.indexer.v)]
                self._idx = self.indexer.v

            # use `0` for non-existent addresses (corr. to None in indexer)
            self.a = ext_model.get(
                src=self.src,
                idx=self._idx,
                attr='a',
                allow_none=self.allow_none,
                default=0,
            ).astype(int)

            # check if source var type is the same as this ExtVar
            vcodes = np.array(
                ext_model.get_field(src=self.src,
                                    idx=self._idx,
                                    field='v_code'))
            vcodes = vcodes[vcodes != np.array(None)].astype(str)

            if not all(vcodes == np.array(self.v_code)):
                raise TypeError(
                    "ExtVar <%s.%s> is of type <%s>, but source Vars <%s.%s> may not."
                    % (self.owner.class_name, self.name, self.v_code,
                       ext_model.class_name, self.src))

            self.n = len(self.a)

        else:
            original_var = ext_model.__dict__[self.src]

            if self.allow_none:
                raise NotImplementedError(
                    f"{self.name}: allow_none not implemented for Model")
            if original_var.v_code != self.v_code:
                raise TypeError("Linking %s of %s to %s of %s is not allowed" %
                                (self.name, self.class_name, original_var.name,
                                 original_var.class_name))

            if self.indexer is not None:
                uid = ext_model.idx2uid(self.indexer.v)
            else:
                uid = np.arange(ext_model.n, dtype=int)

            self._n = [len(uid)]
            if len(uid) > 0:
                self.a = original_var.a[uid]
            else:
                self.a = np.array([], dtype=int)

            # set initial v and e values to zero
            self.n = len(self.a)

        self.v = np.zeros(self.n)
示例#11
0
文件: system.py 项目: songcn206/andes
    def set_address(self, models):
        """
        Set addresses for differential and algebraic variables.
        """
        # set internal variable addresses
        for mdl in models.values():
            if mdl.flags.address is True:
                logger.debug(f'{mdl.class_name} address exists')
                continue
            if mdl.n == 0:
                continue

            logger.debug(f'Setting address for {mdl.class_name}')
            n = mdl.n
            m0 = self.dae.m
            n0 = self.dae.n
            m_end = m0 + len(mdl.algebs) * n
            n_end = n0 + len(mdl.states) * n
            collate = mdl.flags.collate

            if not collate:
                for idx, item in enumerate(mdl.algebs.values()):
                    item.set_address(np.arange(m0 + idx * n,
                                               m0 + (idx + 1) * n),
                                     contiguous=True)
                for idx, item in enumerate(mdl.states.values()):
                    item.set_address(np.arange(n0 + idx * n,
                                               n0 + (idx + 1) * n),
                                     contiguous=True)
            else:
                for idx, item in enumerate(mdl.algebs.values()):
                    item.set_address(np.arange(m0 + idx, m_end,
                                               len(mdl.algebs)),
                                     contiguous=False)
                for idx, item in enumerate(mdl.states.values()):
                    item.set_address(np.arange(n0 + idx, n_end,
                                               len(mdl.states)),
                                     contiguous=False)

            self.dae.m = m_end
            self.dae.n = n_end
            mdl.flags.address = True

        # set external variable addresses
        for mdl in models.values():
            # handle external groups
            for name, instance in mdl.cache.vars_ext.items():
                ext_name = instance.model
                try:
                    ext_model = self.__dict__[ext_name]
                except KeyError:
                    raise KeyError(
                        f'<{ext_name}> is not a model or group name.')

                instance.link_external(ext_model)

        # allocate memory for DAE arrays
        self.dae.resize_arrays()

        # set `v` and `e` in variables
        self._set_var_arrays(models=models)

        # pre-allocate for names
        if len(self.dae.y_name) == 0:
            self.dae.x_name = [''] * self.dae.n
            self.dae.y_name = [''] * self.dae.m
            self.dae.x_tex_name = [''] * self.dae.n
            self.dae.y_tex_name = [''] * self.dae.m
        else:
            self.dae.x_name.extend([''] * (self.dae.n - len(self.dae.x_name)))
            self.dae.y_name.extend([''] * (self.dae.m - len(self.dae.y_name)))
            self.dae.x_tex_name.extend([''] *
                                       (self.dae.n - len(self.dae.x_tex_name)))
            self.dae.y_tex_name.extend([''] *
                                       (self.dae.m - len(self.dae.y_tex_name)))