ltbams 1.0.10__py3-none-any.whl → 1.0.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ams/_version.py CHANGED
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-05-23T00:18:06-0400",
11
+ "date": "2025-05-29T20:16:06-0400",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "f467fb0017c81d3946c1c566802adc4f411ad05e",
15
- "version": "1.0.10"
14
+ "full-revisionid": "2166f4368af3d382720af38408153a70502eb9f5",
15
+ "version": "1.0.12"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
ams/core/documenter.py CHANGED
@@ -6,26 +6,12 @@ import re
6
6
 
7
7
  import logging
8
8
  from collections import OrderedDict
9
- from andes.core.documenter import Documenter as andes_Documenter
10
9
  from andes.utils.tab import make_doc_table, math_wrap
11
10
 
12
11
  logger = logging.getLogger(__name__)
13
12
 
14
13
 
15
- def disable_method(func):
16
- def wrapper(*args, **kwargs):
17
- msg = f"Method `{func.__name__}` is included in ANDES Documenter but not supported in AMS Documenter."
18
- logger.warning(msg)
19
- return None
20
- return wrapper
21
-
22
-
23
- def disable_methods(methods):
24
- for method in methods:
25
- setattr(Documenter, method, disable_method(getattr(Documenter, method)))
26
-
27
-
28
- class Documenter(andes_Documenter):
14
+ class Documenter:
29
15
  """
30
16
  Helper class for documenting models.
31
17
 
@@ -37,16 +23,6 @@ class Documenter(andes_Documenter):
37
23
 
38
24
  def __init__(self, parent):
39
25
  self.parent = parent
40
- self.system = parent.system
41
- self.class_name = parent.class_name
42
- self.config = parent.config
43
- self.params = parent.params
44
- self.algebs = parent.algebs
45
- self.services = parent.services
46
-
47
- func_to_disable = ['_init_doc', '_eq_doc',
48
- '_discrete_doc', '_block_doc']
49
- disable_methods(func_to_disable)
50
26
 
51
27
  def get(self, max_width=78, export='plain'):
52
28
  """
@@ -68,14 +44,15 @@ class Documenter(andes_Documenter):
68
44
  if export == 'rest':
69
45
  max_width = 0
70
46
  model_header = '-' * 80 + '\n'
71
- out += f'.. _{self.class_name}:\n\n'
47
+ out += f'.. _{self.parent.class_name}:\n\n'
72
48
  else:
73
49
  model_header = ''
74
50
 
75
51
  if export == 'rest':
76
- out += model_header + f'{self.class_name}\n' + model_header
52
+ out += model_header + f'{self.parent.class_name}\n' + model_header
77
53
  else:
78
- out += model_header + f'Model <{self.class_name}> in Group <{self.parent.group}>\n' + model_header
54
+ out += model_header + \
55
+ f'Model <{self.parent.class_name}> in Group <{self.parent.group}>\n' + model_header
79
56
 
80
57
  if self.parent.__doc__ is not None:
81
58
  out += inspect.cleandoc(self.parent.__doc__)
@@ -86,20 +63,35 @@ class Documenter(andes_Documenter):
86
63
  out += self._var_doc(max_width=max_width, export=export)
87
64
  out += self._service_doc(max_width=max_width, export=export)
88
65
  # TODO: fix and add the config doc later on
89
- # out += self.config.doc(max_width=max_width, export=export)
66
+ # out += self.parent.config.doc(max_width=max_width, export=export)
90
67
 
91
68
  return out
92
69
 
93
70
  def _var_doc(self, max_width=78, export='plain'):
71
+ """
72
+ Export formatted model variable documentation as a string.
73
+
74
+ Parameters
75
+ ----------
76
+ max_width : int, optional = 80
77
+ Maximum table width. If export format is ``rest`` it will be unlimited.
78
+ export : str, optional = 'plain'
79
+ Export format, 'plain' for plain text, 'rest' for restructuredText.
80
+
81
+ Returns
82
+ -------
83
+ str
84
+ Tabulated output in a string
85
+ """
94
86
  # variable documentation
95
- if len(self.algebs) == 0:
87
+ if len(self.parent.algebs) == 0:
96
88
  return ''
97
89
 
98
90
  names, symbols, units = list(), list(), list()
99
91
  info = list()
100
92
  units_rest, ty = list(), list()
101
93
 
102
- for p in self.algebs.values():
94
+ for p in self.parent.algebs.values():
103
95
  names.append(p.name)
104
96
  ty.append(p.class_name)
105
97
  info.append(p.info if p.info else '')
@@ -110,7 +102,7 @@ class Documenter(andes_Documenter):
110
102
 
111
103
  # replace with latex math expressions if export is ``rest``
112
104
  if export == 'rest':
113
- symbols = [item.tex_name for item in self.algebs.values()]
105
+ symbols = [item.tex_name for item in self.parent.algebs.values()]
114
106
  symbols = math_wrap(symbols, export=export)
115
107
  title = 'Variables\n---------'
116
108
 
@@ -132,14 +124,29 @@ class Documenter(andes_Documenter):
132
124
  rest_dict=rest_dict)
133
125
 
134
126
  def _service_doc(self, max_width=78, export='plain'):
135
- if len(self.services) == 0:
127
+ """
128
+ Export formatted model service documentation as a string.
129
+
130
+ Parameters
131
+ ----------
132
+ max_width : int, optional = 80
133
+ Maximum table width. If export format is ``rest`` it will be unlimited.
134
+ export : str, optional = 'plain'
135
+ Export format, 'plain' for plain text, 'rest' for restructuredText.
136
+
137
+ Returns
138
+ -------
139
+ str
140
+ Tabulated output in a string
141
+ """
142
+ if len(self.parent.services) == 0:
136
143
  return ''
137
144
 
138
145
  names, symbols = list(), list()
139
146
  info = list()
140
147
  class_names = list()
141
148
 
142
- for p in self.services.values():
149
+ for p in self.parent.services.values():
143
150
  names.append(p.name)
144
151
  class_names.append(p.class_name)
145
152
  info.append(p.info if p.info else '')
@@ -165,6 +172,74 @@ class Documenter(andes_Documenter):
165
172
  plain_dict=plain_dict,
166
173
  rest_dict=rest_dict)
167
174
 
175
+ def _param_doc(self, max_width=78, export='plain'):
176
+ """
177
+ Export formatted model parameter documentation as a string.
178
+
179
+ Parameters
180
+ ----------
181
+ max_width : int, optional = 80
182
+ Maximum table width. If export format is ``rest`` it will be unlimited.
183
+
184
+ export : str, optional = 'plain'
185
+ Export format, 'plain' for plain text, 'rest' for restructuredText.
186
+
187
+ Returns
188
+ -------
189
+ str
190
+ Tabulated output in a string
191
+ """
192
+ if len(self.parent.params) == 0:
193
+ return ''
194
+
195
+ # prepare temporary lists
196
+ names, units, class_names = list(), list(), list()
197
+ info, defaults, properties = list(), list(), list()
198
+ units_rest = list()
199
+
200
+ for p in self.parent.params.values():
201
+ names.append(p.name)
202
+ class_names.append(p.class_name)
203
+ info.append(p.info if p.info else '')
204
+ defaults.append(p.default if p.default is not None else '')
205
+ units.append(f'{p.unit}' if p.unit else '')
206
+ units_rest.append(f'*{p.unit}*' if p.unit else '')
207
+
208
+ plist = []
209
+ for key, val in p.property.items():
210
+ if val is True:
211
+ plist.append(key)
212
+ properties.append(','.join(plist))
213
+
214
+ # symbols based on output format
215
+ if export == 'rest':
216
+ symbols = [item.tex_name for item in self.parent.params.values()]
217
+ symbols = math_wrap(symbols, export=export)
218
+ title = 'Parameters\n----------'
219
+ else:
220
+ symbols = [item.name for item in self.parent.params.values()]
221
+ title = 'Parameters'
222
+
223
+ plain_dict = OrderedDict([('Name', names),
224
+ ('Description', info),
225
+ ('Default', defaults),
226
+ ('Unit', units),
227
+ ('Properties', properties)])
228
+
229
+ rest_dict = OrderedDict([('Name', names),
230
+ ('Symbol', symbols),
231
+ ('Description', info),
232
+ ('Default', defaults),
233
+ ('Unit', units_rest),
234
+ ('Properties', properties)])
235
+
236
+ # convert to rows and export as table
237
+ return make_doc_table(title=title,
238
+ max_width=max_width,
239
+ export=export,
240
+ plain_dict=plain_dict,
241
+ rest_dict=rest_dict)
242
+
168
243
 
169
244
  class RDocumenter:
170
245
  """
@@ -172,20 +247,12 @@ class RDocumenter:
172
247
 
173
248
  Parameters
174
249
  ----------
175
- parent : Model
176
- The `Model` instance to document
250
+ parent : ams.core.routine.RoutineBase
251
+ The `RoutineBase` instance to document
177
252
  """
178
253
 
179
254
  def __init__(self, parent):
180
255
  self.parent = parent
181
- self.system = parent.system
182
- self.class_name = parent.class_name
183
- self.config = parent.config
184
- self.services = parent.services
185
- self.rparams = parent.rparams
186
- self.vars = parent.vars
187
- self.constrs = parent.constrs
188
- self.obj = parent.obj
189
256
 
190
257
  def get(self, max_width=78, export='plain'):
191
258
  """
@@ -207,14 +274,15 @@ class RDocumenter:
207
274
  if export == 'rest':
208
275
  max_width = 0
209
276
  model_header = '-' * 80 + '\n'
210
- out += f'.. _{self.class_name}:\n\n'
277
+ out += f'.. _{self.parent.class_name}:\n\n'
211
278
  else:
212
279
  model_header = ''
213
280
 
214
281
  if export == 'rest':
215
- out += model_header + f'{self.class_name}\n' + model_header
282
+ out += model_header + f'{self.parent.class_name}\n' + model_header
216
283
  else:
217
- out += model_header + f'Routine <{self.class_name}> in Type <{self.parent.type}>\n' + model_header
284
+ out += model_header + \
285
+ f'Routine <{self.parent.class_name}> in Type <{self.parent.type}>\n' + model_header
218
286
 
219
287
  if self.parent.__doc__ is not None:
220
288
  out += inspect.cleandoc(self.parent.__doc__)
@@ -229,20 +297,20 @@ class RDocumenter:
229
297
  out += self._exprc_doc(max_width=max_width, export=export)
230
298
  out += self._service_doc(max_width=max_width, export=export)
231
299
  out += self._param_doc(max_width=max_width, export=export)
232
- out += self.config.doc(max_width=max_width, export=export)
300
+ out += self.parent.config.doc(max_width=max_width, export=export)
233
301
 
234
302
  return out
235
303
 
236
304
  def _service_doc(self, max_width=78, export='plain'):
237
305
  # routine service documentation
238
- if len(self.services) == 0:
306
+ if len(self.parent.services) == 0:
239
307
  return ''
240
308
 
241
309
  names, symbols = list(), list()
242
310
  info = list()
243
311
  class_names = list()
244
312
 
245
- for p in self.services.values():
313
+ for p in self.parent.services.values():
246
314
  names.append(p.name)
247
315
  info.append(p.info if p.info else '')
248
316
  class_names.append(p.class_name)
@@ -251,7 +319,7 @@ class RDocumenter:
251
319
 
252
320
  # replace with latex math expressions if export is ``rest``
253
321
  if export == 'rest':
254
- symbols = [item.tex_name for item in self.services.values()]
322
+ symbols = [item.tex_name for item in self.parent.services.values()]
255
323
  symbols = math_wrap(symbols, export=export)
256
324
  title = 'Services\n---------'
257
325
 
@@ -272,13 +340,13 @@ class RDocumenter:
272
340
 
273
341
  def _constr_doc(self, max_width=78, export='plain'):
274
342
  # constraint documentation
275
- if len(self.constrs) == 0:
343
+ if len(self.parent.constrs) == 0:
276
344
  return ''
277
345
 
278
346
  # prepare temporary lists
279
347
  names, class_names, info = list(), list(), list()
280
348
 
281
- for p in self.constrs.values():
349
+ for p in self.parent.constrs.values():
282
350
  names.append(p.name)
283
351
  class_names.append(p.class_name)
284
352
  info.append(p.info if p.info else '')
@@ -286,7 +354,7 @@ class RDocumenter:
286
354
  # expressions based on output format
287
355
  expressions = []
288
356
  if export == 'rest':
289
- for p in self.constrs.values():
357
+ for p in self.parent.constrs.values():
290
358
  expr = _tex_pre(self, p, self.parent.syms.tex_map)
291
359
  if p.is_eq:
292
360
  expr = f'{expr} = 0'
@@ -460,7 +528,7 @@ class RDocumenter:
460
528
  # NOTE: this is for the optimization variables
461
529
  # not the _var_doc for ANDES parameters
462
530
  # variable documentation
463
- if len(self.vars) == 0:
531
+ if len(self.parent.vars) == 0:
464
532
  return ''
465
533
 
466
534
  # prepare temporary lists
@@ -469,7 +537,7 @@ class RDocumenter:
469
537
  sources = list()
470
538
  units_rest = list()
471
539
 
472
- for p in self.vars.values():
540
+ for p in self.parent.vars.values():
473
541
  names.append(p.name)
474
542
  class_names.append(p.class_name)
475
543
  info.append(p.info if p.info else '')
@@ -493,11 +561,11 @@ class RDocumenter:
493
561
 
494
562
  # symbols based on output format
495
563
  if export == 'rest':
496
- symbols = [item.tex_name for item in self.vars.values()]
564
+ symbols = [item.tex_name for item in self.parent.vars.values()]
497
565
  symbols = math_wrap(symbols, export=export)
498
566
  title = 'Vars\n----------------------------------'
499
567
  else:
500
- symbols = [item.name for item in self.vars.values()]
568
+ symbols = [item.name for item in self.parent.vars.values()]
501
569
  title = 'Vars'
502
570
 
503
571
  plain_dict = OrderedDict([('Name', names),
@@ -536,7 +604,7 @@ class RDocumenter:
536
604
  str
537
605
  Tabulated output in a string
538
606
  """
539
- if len(self.rparams) == 0:
607
+ if len(self.parent.rparams) == 0:
540
608
  return ''
541
609
 
542
610
  # prepare temporary lists
@@ -545,7 +613,7 @@ class RDocumenter:
545
613
  sources = list()
546
614
  units_rest = list()
547
615
 
548
- for p in self.rparams.values():
616
+ for p in self.parent.rparams.values():
549
617
  names.append(p.name)
550
618
  class_names.append(p.class_name)
551
619
  info.append(p.info if p.info else '')
@@ -562,11 +630,11 @@ class RDocumenter:
562
630
 
563
631
  # symbols based on output format
564
632
  if export == 'rest':
565
- symbols = [item.tex_name for item in self.rparams.values()]
633
+ symbols = [item.tex_name for item in self.parent.rparams.values()]
566
634
  symbols = math_wrap(symbols, export=export)
567
635
  title = 'Parameters\n----------------------------------'
568
636
  else:
569
- symbols = [item.name for item in self.rparams.values()]
637
+ symbols = [item.name for item in self.parent.rparams.values()]
570
638
  title = 'Parameters'
571
639
 
572
640
  plain_dict = OrderedDict([('Name', names),
ams/core/matprocessor.py CHANGED
@@ -3,7 +3,6 @@ Module for system matrix make.
3
3
  """
4
4
 
5
5
  import logging
6
- import os
7
6
  import sys
8
7
  from typing import Optional
9
8
 
@@ -14,6 +13,9 @@ from andes.shared import tqdm, tqdm_nb
14
13
  from andes.utils.misc import elapsed, is_notebook
15
14
 
16
15
  from ams.opt import Param
16
+
17
+ from ams.utils.paths import get_export_path
18
+
17
19
  from ams.shared import pd, sps
18
20
 
19
21
  logger = logging.getLogger(__name__)
@@ -75,31 +77,28 @@ class MParam(Param):
75
77
  """
76
78
  Export the matrix to a CSV file.
77
79
 
80
+ In the exported CSV, columns are the bus idxes, and Line idxes are
81
+ used as row indexes.
82
+
78
83
  Parameters
79
84
  ----------
80
85
  path : str, optional
81
- Path to the output CSV file.
86
+ Path of the csv file to export.
82
87
 
83
88
  Returns
84
89
  -------
85
90
  str
86
- The path of the exported csv file
91
+ The exported csv file name
87
92
  """
88
93
 
89
- if path is None:
90
- if self.owner.system.files.fullname is None:
91
- logger.info("Input file name not detacted. Using `Untitled`.")
92
- file_name = f'Untitled_{self.name}'
93
- else:
94
- file_name = os.path.splitext(self.owner.system.files.fullname)[0]
95
- file_name += f'_{self.name}'
96
- path = os.path.join(os.getcwd(), file_name + '.csv')
97
- else:
98
- file_name = os.path.splitext(os.path.basename(path))[0]
94
+ path, file_name = get_export_path(self.owner.system,
95
+ self.name,
96
+ path=path,
97
+ fmt='csv')
99
98
 
100
99
  pd.DataFrame(data=self.v, columns=self.col_names, index=self.row_names).to_csv(path)
101
100
 
102
- return file_name + '.csv'
101
+ return file_name
103
102
 
104
103
  @property
105
104
  def v(self):
ams/interface.py CHANGED
@@ -8,7 +8,7 @@ import logging
8
8
  from collections import OrderedDict, Counter
9
9
 
10
10
  from andes.utils.misc import elapsed
11
- from andes.system import System as andes_System
11
+ from andes.system import System as adSystem
12
12
 
13
13
  from ams.utils import create_entry
14
14
  from ams.io import input_formats
@@ -107,7 +107,7 @@ def to_andes_pflow(system, no_output=False, default_config=True, **kwargs):
107
107
  Additional arguments to be passed to ``andes.system.System()``.
108
108
  """
109
109
 
110
- adsys = andes_System(no_outpu=no_output, default_config=default_config, **kwargs)
110
+ adsys = adSystem(no_outpu=no_output, default_config=default_config, **kwargs)
111
111
  # FIXME: is there a systematic way to do this? Other config might be needed
112
112
  adsys.config.freq = system.config.freq
113
113
  adsys.config.mva = system.config.mva
ams/io/matpower.py CHANGED
@@ -455,16 +455,6 @@ def system2mpc(system) -> dict:
455
455
 
456
456
  This function is revised from ``andes.io.matpower.system2mpc``.
457
457
 
458
- In the ``gen`` section, slack generators are listed before PV generators.
459
-
460
- In the converted MPC, the indices of area (bus[:, 6]) and zone (bus[:, 10])
461
- may differ from the original MPC. However, the mapping relationship is preserved.
462
- For example, if the original MPC numbers areas starting from 1, the converted
463
- MPC may number them starting from 0.
464
-
465
- The coefficients ``c2`` and ``c1`` in the generator cost data are scaled by
466
- ``base_mva`` to match MATPOWER's unit convention (MW).
467
-
468
458
  Parameters
469
459
  ----------
470
460
  system : ams.core.system.System
@@ -474,6 +464,21 @@ def system2mpc(system) -> dict:
474
464
  -------
475
465
  mpc : dict
476
466
  A dictionary in MATPOWER format representing the converted AMS system.
467
+
468
+ Notes
469
+ -----
470
+ - In the `gen` section, slack generators are listed before PV generators.
471
+ - For uncontrolled generators (`ctrl.v == 0`), their max and min power
472
+ limits are set to their initial power (`p0.v`) in the converted MPC.
473
+ - In the converted MPC, the indices of area (`bus[:, 6]`) and zone (`bus[:, 10]`)
474
+ may differ from the original MPC. However, the mapping relationship is preserved.
475
+ For example, if the original MPC numbers areas starting from 1, the converted
476
+ MPC may number them starting from 0.
477
+ - The coefficients `c2` and `c1` in the generator cost data are scaled by
478
+ `baseMVA`.
479
+ - Unlike the XLSX and JSON converters, this implementation uses value providers
480
+ (`v`) instead of vin. As a result, any changes made through `model.set` will be
481
+ reflected in the generated MPC.
477
482
  """
478
483
 
479
484
  mpc = dict(version='2',
@@ -514,15 +519,31 @@ def system2mpc(system) -> dict:
514
519
  # --- PQ ---
515
520
  if system.PQ.n > 0:
516
521
  pq_pos = system.Bus.idx2uid(system.PQ.bus.v)
517
- u = system.PQ.u.v
518
- bus[pq_pos, 2] = u * system.PQ.p0.v * base_mva
519
- bus[pq_pos, 3] = u * system.PQ.q0.v * base_mva
522
+
523
+ p0e = system.PQ.u.v * system.PQ.p0.v
524
+ q0e = system.PQ.u.v * system.PQ.q0.v
525
+
526
+ # NOTE: ensure multiple PQ on the same bus are summed
527
+ # rather than overwritten. Same for Shunt.
528
+ p = np.zeros(system.Bus.n)
529
+ q = np.zeros(system.Bus.n)
530
+ np.add.at(p, pq_pos, p0e)
531
+ np.add.at(q, pq_pos, q0e)
532
+ bus[:, 2] = p * base_mva
533
+ bus[:, 3] = q * base_mva
520
534
 
521
535
  # --- Shunt ---
522
536
  if system.Shunt.n > 0:
523
537
  shunt_pos = system.Bus.idx2uid(system.Shunt.bus.v)
524
- bus[shunt_pos, 4] = system.Shunt.g.v * base_mva
525
- bus[shunt_pos, 5] = system.Shunt.b.v * base_mva
538
+
539
+ ge = system.Shunt.u.v * system.Shunt.g.v
540
+ be = system.Shunt.u.v * system.Shunt.b.v
541
+ g = np.zeros(system.Bus.n)
542
+ b = np.zeros(system.Bus.n)
543
+ np.add.at(g, shunt_pos, ge)
544
+ np.add.at(b, shunt_pos, be)
545
+ bus[:, 4] = g * base_mva
546
+ bus[:, 5] = b * base_mva
526
547
 
527
548
  # --- PV ---
528
549
  if system.PV.n > 0:
@@ -709,11 +730,6 @@ def write(system, outfile: str, overwrite: bool = None) -> bool:
709
730
  This function converts an AMS system object into a MATPOWER-compatible
710
731
  mpc dictionary and writes it to a specified output file in MATPOWER format.
711
732
 
712
- In the converted MPC, the indices of area (bus[:, 6]) and zone (bus[:, 10])
713
- may differ from the original MPC. However, the mapping relationship is preserved.
714
- For example, if the original MPC numbers areas starting from 1, the converted
715
- MPC may number them starting from 0.
716
-
717
733
  Parameters
718
734
  ----------
719
735
  system : ams.system.System
@@ -727,6 +743,21 @@ def write(system, outfile: str, overwrite: bool = None) -> bool:
727
743
  -------
728
744
  bool
729
745
  True if the file was successfully written, False otherwise.
746
+
747
+ Notes
748
+ -----
749
+ - In the `gen` section, slack generators are listed before PV generators.
750
+ - For uncontrolled generators (`ctrl.v == 0`), their max and min power
751
+ limits are set to their initial power (`p0.v`) in the converted MPC.
752
+ - In the converted MPC, the indices of area (`bus[:, 6]`) and zone (`bus[:, 10]`)
753
+ may differ from the original MPC. However, the mapping relationship is preserved.
754
+ For example, if the original MPC numbers areas starting from 1, the converted
755
+ MPC may number them starting from 0.
756
+ - The coefficients `c2` and `c1` in the generator cost data are scaled by
757
+ `baseMVA`.
758
+ - Unlike the XLSX and JSON converters, this implementation uses value providers
759
+ (`v`) instead of vin. As a result, any changes made through `model.set` will be
760
+ reflected in the generated MPC.
730
761
  """
731
762
  if not confirm_overwrite(outfile, overwrite=overwrite):
732
763
  return False
ams/io/psse.py CHANGED
@@ -46,6 +46,8 @@ def write_raw(system, outfile: str, overwrite: bool = None):
46
46
  """
47
47
  Convert AMS system to PSS/E RAW file.
48
48
 
49
+ This method has not been fully benchmarked yet!
50
+
49
51
  Parameters
50
52
  ----------
51
53
  system : System
ams/routines/grbopt.py CHANGED
@@ -10,6 +10,8 @@ import scipy.io
10
10
  from andes.shared import np, pd
11
11
  from andes.utils.misc import elapsed
12
12
 
13
+ from ams.core import Config
14
+
13
15
  from ams.io.pypower import system2ppc
14
16
 
15
17
  from ams.opt import Var, Objective
@@ -39,9 +41,13 @@ class OPF(DCPF1):
39
41
  self.info = 'Optimal Power Flow'
40
42
  self.type = 'ACED'
41
43
 
44
+ # Overwrite the config to be empty, as it is not used in this routine
45
+ self.config = Config(self.class_name)
46
+
42
47
  self.obj = Objective(name='obj',
43
48
  info='total cost, placeholder',
44
49
  e_str='sum(c2 * pg**2 + c1 * pg + c0)',
50
+ unit='$',
45
51
  sense='min',)
46
52
 
47
53
  self.pi = Var(info='Lagrange multiplier on real power mismatch',
@@ -97,23 +103,22 @@ class OPF(DCPF1):
97
103
  """
98
104
  Run the OPF routine using gurobi-optimods.
99
105
 
100
- This method invokes `self.solve(**kwargs)`, which internally utilizes
101
- `gurobi-optimods` to solve the OPF problem.
106
+ This method invokes `gurobi-optimods.opf.solve_opf` to solve the OPF problem.
102
107
 
103
- Keyword arguments
104
- -------------------
105
- - ``opftype`` : str
108
+ Parameters
109
+ ----------
110
+ - opftype : str
106
111
  Type of OPF to solve (default: 'AC').
107
- - ``branch_switching`` : bool
112
+ - branch_switching : bool
108
113
  Enable branch switching (default: False).
109
- - ``min_active_branches`` : float
114
+ - min_active_branches : float
110
115
  Defines the minimum number of branches that must be turned on when
111
116
  branch switching is active, i.e. the minimum number of turned on
112
117
  branches is equal to ``numbranches * min_active_branches``. Has no
113
118
  effect if ``branch_switching`` is set to False.
114
- - ``use_mip_start`` : bool
119
+ - use_mip_start : bool
115
120
  Use MIP start (default: False).
116
- - ``time_limit`` : float
121
+ - time_limit : float
117
122
  Time limit for the solver (default: 0.0, no limit).
118
123
  """
119
124
  if not self.initialized: