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

Misc #110

Merged
merged 22 commits into from
Dec 13, 2024
Merged

Misc #110

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ams/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
__version__ = _version.get_versions()['version']

from ams import opt # NOQA
from ams import benchmarks # NOQA

from ams.main import config_logger, load, run # NOQA
from ams.system import System # NOQA
Expand Down
Binary file modified ams/cases/5bus/pjm5bus_demo.xlsx
Binary file not shown.
Binary file modified ams/cases/5bus/pjm5bus_jumper.xlsx
Binary file not shown.
2 changes: 1 addition & 1 deletion ams/cases/5bus/pjm5bus_uced.json
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@
"name": 3
}
],
"Region": [
"Zone": [
{
"idx": "ZONE_1",
"u": 1.0,
Expand Down
Binary file modified ams/cases/5bus/pjm5bus_uced.xlsx
Binary file not shown.
Binary file modified ams/cases/5bus/pjm5bus_uced_esd1.xlsx
Binary file not shown.
Binary file modified ams/cases/5bus/pjm5bus_uced_ev.xlsx
Binary file not shown.
Binary file modified ams/cases/ieee14/ieee14_uced.xlsx
Binary file not shown.
Binary file modified ams/cases/ieee39/ieee39.xlsx
Binary file not shown.
Binary file modified ams/cases/ieee39/ieee39_uced.xlsx
Binary file not shown.
Binary file modified ams/cases/ieee39/ieee39_uced_esd1.xlsx
Binary file not shown.
Binary file modified ams/cases/ieee39/ieee39_uced_pvd1.xlsx
Binary file not shown.
Binary file modified ams/cases/ieee39/ieee39_uced_vis.xlsx
Binary file not shown.
Binary file modified ams/cases/npcc/npcc_uced.xlsx
Binary file not shown.
Binary file modified ams/cases/wecc/wecc_uced.xlsx
Binary file not shown.
35 changes: 26 additions & 9 deletions ams/core/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,17 +212,17 @@
self.__dict__[src].__dict__[attr][uid] = value
return True

def alter(self, src, idx, value):
def alter(self, src, idx, value, attr='v'):
"""
Alter values of input parameters or constant service.

If the method operates on an input parameter, the new data should be in
the same base as that in the input file. This function will convert the
new value to per unit in the system base.
the same base as that in the input file. This function will convert
``value`` to per unit in the system base whenever necessary.

The values for storing the input data, i.e., the ``vin`` field of the
parameter, will be overwritten, thus the update will be reflected in the
dumped case file.
The values for storing the input data, i.e., the parameter's ``vin``
field, will be overwritten. As a result, altered values will be
reflected in the dumped case file.

Parameters
----------
Expand All @@ -232,14 +232,31 @@
The device to alter
value : float
The desired value
attr : str
The attribute to alter, default is 'v'.

Notes
-----
New in version 0.9.14: Added the signature `attr` to alter specific attributes.
This feature is useful when you need to manipulate parameter values in the system
base and ensure that these changes are reflected in the dumped case file.
"""

instance = self.__dict__[src]

if hasattr(instance, 'vin') and (instance.vin is not None):
self.set(src, idx, 'vin', value)
instance.v[:] = instance.vin * instance.pu_coeff
else:
uid = self.idx2uid(idx)
if attr == 'vin':
self.set(src, idx, 'vin', value / instance.pu_coeff[uid])
self.set(src, idx, 'v', value=value)

Check warning on line 251 in ams/core/model.py

View check run for this annotation

Codecov / codecov/patch

ams/core/model.py#L250-L251

Added lines #L250 - L251 were not covered by tests
else:
self.set(src, idx, 'vin', value)
self.set(src, idx, 'v', value * instance.pu_coeff[uid])
elif not hasattr(instance, 'vin') and attr == 'vin':
logger.warning(f"{self.class_name}.{src} has no `vin` attribute, changing `v`.")

Check warning on line 256 in ams/core/model.py

View check run for this annotation

Codecov / codecov/patch

ams/core/model.py#L255-L256

Added lines #L255 - L256 were not covered by tests
self.set(src, idx, 'v', value)
else:
self.set(src, idx, attr=attr, value=value)

Check warning on line 259 in ams/core/model.py

View check run for this annotation

Codecov / codecov/patch

ams/core/model.py#L259

Added line #L259 was not covered by tests

def idx2uid(self, idx):
"""
Expand Down
10 changes: 5 additions & 5 deletions ams/core/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def v(self):
ue = self.u.owner.get(src='u', attr='v', idx=u_idx)
u_bus = self.u.owner.get(src='bus', attr='v', idx=u_idx)
u_zone = sys.Bus.get(src='zone', attr='v', idx=u_bus)
u_yloc = np.array(sys.Region.idx2uid(u_zone))
u_yloc = np.array(sys.Zone.idx2uid(u_zone))
p0s = np.multiply(self.sd.v[:, u_yloc].transpose(),
(ue * self.u.v)[:, np.newaxis])
if self.sparse:
Expand Down Expand Up @@ -587,12 +587,12 @@ def v0(self):
class ZonalSum(NumOp):
"""
Build zonal sum matrix for a vector in the shape of collection model,
``Area`` or ``Region``.
``Area`` or ``Zone``.
The value array is in the shape of (nr, nc), where nr is the length of
rid instance idx, and nc is the length of the cid value.

In an IEEE-14 Bus system, we have the zonal definition by the
``Region`` model. Suppose in it we have two regions, "ZONE1" and
``Zone`` model. Suppose in it we have two regions, "ZONE1" and
"ZONE2".

Follwing it, we have a zonal SFR requirement model ``SFR`` that
Expand All @@ -606,7 +606,7 @@ class ZonalSum(NumOp):
In the `RTED` model, we have the Vars ``pru`` and ``prd`` in the
shape of generators.

Then, the Region model has idx ['ZONE1', 'ZONE2'], and the ``gsm`` value
Then, the Zone model has idx ['ZONE1', 'ZONE2'], and the ``gsm`` value
will be [[1, 1, 0, 0, 1], [0, 0, 1, 1, 0]].

Finally, the zonal reserve requirements can be formulated as
Expand All @@ -621,7 +621,7 @@ class ZonalSum(NumOp):
u : Callable
Input.
zone : str
Zonal model name, e.g., "Area" or "Region".
Zonal model name, e.g., "Area" or "Zone".
name : str
Instance name.
tex_name : str
Expand Down
2 changes: 1 addition & 1 deletion ams/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
'rea': 'RenAerodynamics',
'rep': 'RenPitch',
'busf': 'BusFreq',
'zone': 'Region',
'zone': 'Zone',
'gen': 'StaticGen',
'pq': 'PQ', }

Expand Down
6 changes: 3 additions & 3 deletions ams/io/matpower.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,11 @@ def mpc2system(mpc: dict, system) -> bool:
c2=c2, c1=c1, c0=c0
)

# --- region ---
# --- Zone ---
zone_id = np.unique(system.Bus.zone.v).astype(int)
for zone in zone_id:
zone_idx = f'ZONE_{zone}'
system.add('Region', idx=zone_idx, name=None)
system.add('Zone', idx=zone_idx, name=None)
bus_zone = system.Bus.zone.v
bus_zone = [f'ZONE_{int(zone)}' for zone in bus_zone]
system.Bus.zone.v = bus_zone
Expand Down Expand Up @@ -313,7 +313,7 @@ def system2mpc(system) -> dict:
bus[:, 12] = system.Bus.vmin.v

# --- zone ---
ZONE_I = system.Region.idx.v
ZONE_I = system.Zone.idx.v
if len(ZONE_I) > 0:
mapping = {busi0: i for i, busi0 in enumerate(ZONE_I)}
bus[:, 10] = np.array([mapping[busi0] for busi0 in system.Bus.zone.v])
Expand Down
2 changes: 1 addition & 1 deletion ams/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
('distributed', ['PVD1', 'ESD1', 'EV1', 'EV2']),
('renewable', ['REGCA1', 'REGCV1', 'REGCV2']),
('area', ['Area']),
('region', ['Region']),
('zone', ['Zone']),
('reserve', ['SFR', 'SR', 'NSR', 'VSGR']),
('cost', ['GCost', 'SFRCost', 'SRCost', 'NSRCost', 'VSGCost']),
('cost', ['DCost']),
Expand Down
4 changes: 2 additions & 2 deletions ams/models/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ def __init__(self, system, config):
Model.__init__(self, system, config)

self.group = 'ACTopology'
# NOTE: in ANDES, self.zone is defined to trace a non-existing model "Region"
# NOTE: in ANDES, self.zone is defined to trace a non-existing model "Zone"
# in AMS, model "Zone" is developed,
# so we need to change the model name of IdxParam self.zone
self.zone.model = 'Region'
self.zone.model = 'Zone'

self.type = NumParam(name='type',
info='bus type, 1=PQ, 2=PV, 3=ref, 4=isolated (place holder)',
Expand Down
6 changes: 3 additions & 3 deletions ams/models/group.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import logging # NOQA
import logging

from andes.models.group import GroupBase as andes_GroupBase
from andes.models.group import GroupBase as adGroupBase
from andes.core.service import BackRef

logger = logging.getLogger(__name__)


class GroupBase(andes_GroupBase):
class GroupBase(adGroupBase):
"""
Base class for groups.

Expand Down
4 changes: 2 additions & 2 deletions ams/models/timeslot.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class EDTSlot(TimeSlot):

`sd` is the zonal load scaling factor.
Cells in `sd` should have `nz` values seperated by comma,
where `nz` is the number of `Region` in the system.
where `nz` is the number of `Zone` in the system.

`ug` is the unit commitment decisions.
Cells in `ug` should have `ng` values seperated by comma,
Expand All @@ -62,7 +62,7 @@ class UCTSlot(TimeSlot):

`sd` is the zonal load scaling factor.
Cells in `sd` should have `nz` values seperated by comma,
where `nz` is the number of `Region` in the system.
where `nz` is the number of `Zone` in the system.
"""

def __init__(self, system=None, config=None):
Expand Down
17 changes: 7 additions & 10 deletions ams/models/region.py → ams/models/zone.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,21 @@
logger = logging.getLogger(__name__)


class RegionData(ModelData):
def __init__(self):
super().__init__()


class Region(RegionData, Model):
class Zone(ModelData, Model):
"""
Region model for zonal vars.
Zone model for zonal items.

An ``area`` can have multiple zones.

Notes
-----
1. Region is a collection of buses.
2. Model ``Region`` is not actually defined in ANDES.
1. Zone is a collection of buses.
2. Model ``Zone`` is not actually defined in ANDES.

"""

def __init__(self, system, config):
RegionData.__init__(self)
ModelData.__init__(self)
Model.__init__(self, system, config)

self.group = 'Collection'
Expand Down
6 changes: 6 additions & 0 deletions ams/opt/constraint.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
self.dual = None
self.code = None

def get_idx(self):
raise NotImplementedError

Check warning on line 68 in ams/opt/constraint.py

View check run for this annotation

Codecov / codecov/patch

ams/opt/constraint.py#L68

Added line #L68 was not covered by tests

def get_all_idxes(self):
raise NotImplementedError

Check warning on line 71 in ams/opt/constraint.py

View check run for this annotation

Codecov / codecov/patch

ams/opt/constraint.py#L71

Added line #L71 was not covered by tests

@ensure_symbols
def parse(self):
"""
Expand Down
14 changes: 1 addition & 13 deletions ams/opt/exprcalc.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,11 @@ def __init__(self,
model: Optional[str] = None,
src: Optional[str] = None,
):
OptzBase.__init__(self, name=name, info=info, unit=unit)
OptzBase.__init__(self, name=name, info=info, unit=unit, model=model)
self.optz = None
self.e_str = e_str
self.code = None
self.model = model
self.owner = None
self.src = src
self.is_group = False

def get_idx(self):
if self.is_group:
return self.owner.get_idx()
elif self.owner is None:
logger.info(f'ExpressionCalc <{self.name}> has no owner.')
return None
else:
return self.owner.idx.v

@ensure_symbols
def parse(self):
Expand Down
14 changes: 1 addition & 13 deletions ams/opt/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,14 @@ def __init__(self,
vtype: Optional[str] = float,
horizon: Optional[str] = None,
):
OptzBase.__init__(self, name=name, info=info, unit=unit)
OptzBase.__init__(self, name=name, info=info, unit=unit, model=model)
self.tex_name = tex_name
self.e_str = e_str
self.optz = None
self.code = None
self.model = model
self.owner = None
self.src = src
self.is_group = False
self.horizon = horizon

def get_idx(self):
if self.is_group:
return self.owner.get_idx()
elif self.owner is None:
logger.info(f'ExpressionCalc <{self.name}> has no owner.')
return None
else:
return self.owner.idx.v

@ensure_symbols
def parse(self):
"""
Expand Down
13 changes: 13 additions & 0 deletions ams/opt/optbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
name: Optional[str] = None,
info: Optional[str] = None,
unit: Optional[str] = None,
model: Optional[str] = None,
):
self.om = None
self.name = name
Expand All @@ -97,6 +98,9 @@
self.rtn = None
self.optz = None # corresponding optimization element
self.code = None
self.model = model # indicate if this element belongs to a model or group
self.owner = None # instance of the owner model or group
self.is_group = False

@ensure_symbols
def parse(self):
Expand Down Expand Up @@ -153,3 +157,12 @@

def __repr__(self):
return f'{self.__class__.__name__}: {self.name}'

def get_idx(self):
if self.is_group:
return self.owner.get_idx()
elif self.owner is None:
logger.info(f'{self.class_name} <{self.name}> has no owner.')
return None

Check warning on line 166 in ams/opt/optbase.py

View check run for this annotation

Codecov / codecov/patch

ams/opt/optbase.py#L165-L166

Added lines #L165 - L166 were not covered by tests
else:
return self.owner.idx.v
14 changes: 1 addition & 13 deletions ams/opt/var.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,8 @@ def __init__(self,
self.tex_name = tex_name if tex_name else name
# variable internal index inside a model (assigned in run time)
self.id = None
OptzBase.__init__(self, name=name, info=info, unit=unit)
OptzBase.__init__(self, name=name, info=info, unit=unit, model=model)
self.src = src
self.is_group = False
self.model = model # indicate if this variable is a group variable
self.owner = None # instance of the owner model or group
self.v0 = v0
self.horizon = horizon
self._shape = shape
Expand Down Expand Up @@ -166,15 +163,6 @@ def v(self, value):
else:
self.optz.value = value

def get_idx(self):
if self.is_group:
return self.owner.get_idx()
elif self.owner is None:
logger.info(f'Variable <{self.name}> has no owner.')
return None
else:
return self.owner.idx.v

@ensure_symbols
def parse(self):
"""
Expand Down
4 changes: 2 additions & 2 deletions ams/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def update(self):
'Lines': system.Line.n,
'Transformers': np.count_nonzero(system.Line.trans.v == 1),
'Areas': system.Area.n,
'Regions': system.Region.n,
'Zones': system.Zone.n,
})

def collect(self, rtn, horizon=None):
Expand Down Expand Up @@ -324,7 +324,7 @@ def collect_owners(rtn):
# initialize data section by model
owners_all = ['Bus', 'Line', 'StaticGen',
'PV', 'Slack', 'RenGen',
'DG', 'ESD1', 'PVD1',
'DG', 'ESD1', 'PVD1', 'VSG',
'StaticLoad']

# Filter owners that exist in the system
Expand Down
2 changes: 2 additions & 0 deletions ams/routines/ed.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ def __init__(self) -> None:
self.pg.info = '2D Gen power'
self.aBus.horizon = self.timeslot
self.aBus.info = '2D Bus angle'
self.vBus.horizon = self.timeslot
self.vBus.info = '2D Bus voltage'
self.pi.horizon = self.timeslot


Expand Down
2 changes: 1 addition & 1 deletion ams/routines/routine.py
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,6 @@ def collect_data(rtn: RoutineBase, data_dict: Dict, items: Dict, attr: str):
data_v = rtn.get(src=key, attr=attr, idx=idx_v,
horizon=rtn.timeslot.v if hasattr(rtn, 'timeslot') else None).round(6)
except Exception as e:
logger.error(f"Error collecting data for '{key}': {e}")
logger.debug(f"Error with collecting data for '{key}': {e}")
data_v = [np.nan] * len(idx_v)
data_dict.update(OrderedDict(zip([f'{key} {dev}' for dev in idx_v], data_v)))
Loading
Loading