diff --git a/.readthedocs.yml b/.readthedocs.yml index 87c5221ea..aecedb7f1 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -19,5 +19,3 @@ python: path: . extra_requirements: - doc - - method: setuptools - path: . diff --git a/andes/core/discrete.py b/andes/core/discrete.py index bcb0feea3..f45eaca96 100644 --- a/andes/core/discrete.py +++ b/andes/core/discrete.py @@ -494,8 +494,8 @@ def do_adjust_lower(self, val, lower, allow_adjust=True, adjust_lower=False): """ if allow_adjust: - mask = (val < lower) - + ue = self.owner.services.get('ue', self.owner.params.get('u', np.ones(self.owner.n))).v + mask = np.logical_and(val < lower, ue) if sum(mask) == 0: return @@ -540,7 +540,8 @@ def do_adjust_upper(self, val, upper, allow_adjust=True, adjust_upper=False): """ if allow_adjust: - mask = (val > upper) + ue = self.owner.services.get('ue', self.owner.params.get('u', np.ones(self.owner.n))).v + mask = (val >= ue * upper) if sum(mask) == 0: return diff --git a/andes/core/model/modeldata.py b/andes/core/model/modeldata.py index 47811c5df..fec7b3e24 100644 --- a/andes/core/model/modeldata.py +++ b/andes/core/model/modeldata.py @@ -162,7 +162,7 @@ def add(self, **kwargs): value = kwargs.pop(name, None) instance.add(value) if len(kwargs) > 0: - logger.warning("%s: unused data %s", self.class_name, str(kwargs)) + logger.warning("%s: unused data %s.", self.class_name, str(kwargs)) def as_dict(self, vin=False): """ diff --git a/andes/core/param.py b/andes/core/param.py index eb3ba9716..e3d5b7cfb 100644 --- a/andes/core/param.py +++ b/andes/core/param.py @@ -465,19 +465,19 @@ def add(self, value=None): if isinstance(value, float): # check for non-zero if value == 0.0 and self.get_property('non_zero'): - logger.warning('Non-zero parameter %s.%s corrected to %s', + logger.warning('Non-zero parameter %s.%s corrected to %s.', self.owner.class_name, self.name, self.default) value = self.default # check for non-positive if value > 0.0 and self.get_property('non_positive'): - logger.warning('Non-Positive parameter %s.%s corrected to %s', + logger.warning('Non-Positive parameter %s.%s corrected to %s. ', self.owner.class_name, self.name, self.default) value = self.default # check for non-negative if value < 0.0 and self.get_property('non_negative'): - logger.warning('Non-negative parameter %s.%s corrected to %s', + logger.warning('Non-negative parameter %s.%s corrected to %s. ', self.owner.class_name, self.name, self.default) value = self.default diff --git a/andes/core/service.py b/andes/core/service.py index 4adad09bf..a41e0ef0b 100644 --- a/andes/core/service.py +++ b/andes/core/service.py @@ -1237,9 +1237,18 @@ def check(self): if limit is None: continue + # Determine the operational status of devices, use ue when applicable + ue = np.asarray(self.owner.services.get( + 'ue', self.owner.params.get('u', np.ones(self.owner.n))).v).astype(bool) + # Identify online devices + online_devices = np.where(ue)[0] + + # Update the flag for devices violating the condition self.v[:] = np.logical_or(self.v, func(self.u.v, limit.v)) - pos = np.argwhere(func(self.u.v, limit.v)).ravel() + # Find positions of online devices violating the condition + violating_devices = np.argwhere(func(self.u.v, limit.v)).ravel() + pos = np.intersect1d(violating_devices, online_devices) if len(pos) == 0: continue diff --git a/andes/models/group.py b/andes/models/group.py index 49c3dba9c..b7cd142a9 100644 --- a/andes/models/group.py +++ b/andes/models/group.py @@ -808,6 +808,7 @@ class RenPlant(GroupBase): def __init__(self): super().__init__() + self.common_params.extend(('ree',)) class RenGovernor(GroupBase): @@ -880,6 +881,7 @@ class TurbineGov(GroupBase): def __init__(self): super().__init__() + self.common_params.extend(('syn',)) self.common_vars.extend(('pout',)) @@ -904,7 +906,7 @@ class VoltComp(GroupBase): def __init__(self): super().__init__() - self.common_params.extend(('rc', 'xc',)) + self.common_params.extend(('rc', 'xc', 'avr',)) self.common_vars.extend(('vcomp',)) @@ -913,6 +915,7 @@ class PSS(GroupBase): def __init__(self): super().__init__() + self.common_params.extend(('avr',)) self.common_vars.extend(('vsout',)) @@ -941,6 +944,7 @@ class FreqMeasurement(GroupBase): def __init__(self): super().__init__() + self.common_params.extend(('bus',)) self.common_vars.extend(('f',)) @@ -949,6 +953,7 @@ class PhasorMeasurement(GroupBase): def __init__(self): super().__init__() + self.common_params.extend(('bus',)) self.common_vars.extend(('am', 'vm')) @@ -957,6 +962,7 @@ class PLL(GroupBase): def __init__(self): super().__init__() + self.common_params.extend(('bus',)) self.common_vars.extend(('am',)) @@ -966,6 +972,7 @@ class Motor(GroupBase): def __init__(self): super().__init__() + self.common_params.extend(('bus',)) class Information(GroupBase): diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst index 5a10ff474..120b8453c 100644 --- a/docs/source/release-notes.rst +++ b/docs/source/release-notes.rst @@ -15,6 +15,7 @@ v1.9.4 (2025-xx-xx) list. - Fix a bug in line model that causes incorrect admittance matrix. - Correct a typo in the PSSE DYR parser, changing "Tprod" to "Tpord". +- Skip InitChecker logging and limiter adjust for offline devices. v1.9.3 (2025-01-05) ------------------- diff --git a/tests/test_services.py b/tests/test_services.py index 8fab6d9ef..91cd00d36 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -100,3 +100,37 @@ def test_no_find_or_add(self): # test if the flag for `am` is set to 0 to disable `am` measurement self.assertEqual(ss.REGCP1.zam.v[0], 0) + + +def test_init_checker_online(caplog): + """ + Test the initialization checker for online devices. + + This test ensures that the initialization checker raises a warning + when a device's parameters are out of the typical range during TDS + initialization process. + """ + ss = andes.run(andes.get_case("npcc/npcc.xlsx"), + setup=True, + default_config=True, + no_output=True) + with caplog.at_level("WARNING"): + ss.TDS.init() + assert "GENCLS (vf range) out of typical lower limit." in caplog.text + + +def test_init_checker_offline(caplog): + """ + Test the initialization checker for offline devices. + + This test ensures that the initialization checker does not raise warnings + for devices that are offline. + """ + ss = andes.run(andes.get_case("npcc/npcc.xlsx"), + setup=True, + default_config=True, + no_output=True) + ss.GENCLS.set(src='u', attr='v', idx=['GENCLS_3', 'GENCLS_4', 'GENCLS_16'], value=0) + with caplog.at_level("WARNING"): + ss.TDS.init() + assert "GENCLS (vf range) out of typical lower limit." not in caplog.text