ltbams 0.9.9__py3-none-any.whl → 1.0.2a1__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.
Files changed (191) hide show
  1. ams/__init__.py +4 -11
  2. ams/_version.py +3 -3
  3. ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
  4. ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
  5. ams/cases/5bus/pjm5bus_uced.json +1062 -0
  6. ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
  7. ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
  8. ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
  9. ams/cases/ieee123/ieee123.xlsx +0 -0
  10. ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
  11. ams/cases/ieee14/ieee14.json +1166 -0
  12. ams/cases/ieee14/ieee14.raw +92 -0
  13. ams/cases/ieee14/ieee14_conn.xlsx +0 -0
  14. ams/cases/ieee14/ieee14_uced.xlsx +0 -0
  15. ams/cases/ieee39/ieee39.xlsx +0 -0
  16. ams/cases/ieee39/ieee39_uced.xlsx +0 -0
  17. ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
  18. ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
  19. ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
  20. ams/cases/matpower/benchmark.json +1594 -0
  21. ams/cases/matpower/case118.m +787 -0
  22. ams/cases/matpower/case14.m +129 -0
  23. ams/cases/matpower/case300.m +1315 -0
  24. ams/cases/matpower/case39.m +205 -0
  25. ams/cases/matpower/case5.m +62 -0
  26. ams/cases/matpower/case_ACTIVSg2000.m +9460 -0
  27. ams/cases/npcc/npcc.m +644 -0
  28. ams/cases/npcc/npcc_uced.xlsx +0 -0
  29. ams/cases/pglib/pglib_opf_case39_epri__api.m +243 -0
  30. ams/cases/wecc/wecc.m +714 -0
  31. ams/cases/wecc/wecc_uced.xlsx +0 -0
  32. ams/cli.py +6 -0
  33. ams/core/__init__.py +2 -0
  34. ams/core/documenter.py +652 -0
  35. ams/core/matprocessor.py +782 -0
  36. ams/core/model.py +330 -0
  37. ams/core/param.py +322 -0
  38. ams/core/service.py +918 -0
  39. ams/core/symprocessor.py +224 -0
  40. ams/core/var.py +59 -0
  41. ams/extension/__init__.py +5 -0
  42. ams/extension/eva.py +401 -0
  43. ams/interface.py +1085 -0
  44. ams/io/__init__.py +133 -0
  45. ams/io/json.py +82 -0
  46. ams/io/matpower.py +406 -0
  47. ams/io/psse.py +6 -0
  48. ams/io/pypower.py +103 -0
  49. ams/io/xlsx.py +80 -0
  50. ams/main.py +81 -4
  51. ams/models/__init__.py +24 -0
  52. ams/models/area.py +40 -0
  53. ams/models/bus.py +52 -0
  54. ams/models/cost.py +169 -0
  55. ams/models/distributed/__init__.py +3 -0
  56. ams/models/distributed/esd1.py +71 -0
  57. ams/models/distributed/ev.py +60 -0
  58. ams/models/distributed/pvd1.py +67 -0
  59. ams/models/group.py +231 -0
  60. ams/models/info.py +26 -0
  61. ams/models/line.py +238 -0
  62. ams/models/renewable/__init__.py +5 -0
  63. ams/models/renewable/regc.py +119 -0
  64. ams/models/reserve.py +94 -0
  65. ams/models/shunt.py +14 -0
  66. ams/models/static/__init__.py +2 -0
  67. ams/models/static/gen.py +165 -0
  68. ams/models/static/pq.py +61 -0
  69. ams/models/timeslot.py +69 -0
  70. ams/models/zone.py +49 -0
  71. ams/opt/__init__.py +12 -0
  72. ams/opt/constraint.py +175 -0
  73. ams/opt/exprcalc.py +127 -0
  74. ams/opt/expression.py +188 -0
  75. ams/opt/objective.py +174 -0
  76. ams/opt/omodel.py +432 -0
  77. ams/opt/optzbase.py +192 -0
  78. ams/opt/param.py +156 -0
  79. ams/opt/var.py +233 -0
  80. ams/pypower/__init__.py +8 -0
  81. ams/pypower/_compat.py +9 -0
  82. ams/pypower/core/__init__.py +8 -0
  83. ams/pypower/core/pips.py +894 -0
  84. ams/pypower/core/ppoption.py +244 -0
  85. ams/pypower/core/ppver.py +18 -0
  86. ams/pypower/core/solver.py +2451 -0
  87. ams/pypower/eps.py +6 -0
  88. ams/pypower/idx.py +174 -0
  89. ams/pypower/io.py +604 -0
  90. ams/pypower/make/__init__.py +11 -0
  91. ams/pypower/make/matrices.py +665 -0
  92. ams/pypower/make/pdv.py +506 -0
  93. ams/pypower/routines/__init__.py +7 -0
  94. ams/pypower/routines/cpf.py +513 -0
  95. ams/pypower/routines/cpf_callbacks.py +114 -0
  96. ams/pypower/routines/opf.py +1803 -0
  97. ams/pypower/routines/opffcns.py +1946 -0
  98. ams/pypower/routines/pflow.py +852 -0
  99. ams/pypower/toggle.py +1098 -0
  100. ams/pypower/utils.py +293 -0
  101. ams/report.py +212 -50
  102. ams/routines/__init__.py +23 -0
  103. ams/routines/acopf.py +117 -0
  104. ams/routines/cpf.py +65 -0
  105. ams/routines/dcopf.py +241 -0
  106. ams/routines/dcpf.py +209 -0
  107. ams/routines/dcpf0.py +196 -0
  108. ams/routines/dopf.py +150 -0
  109. ams/routines/ed.py +312 -0
  110. ams/routines/pflow.py +255 -0
  111. ams/routines/pflow0.py +113 -0
  112. ams/routines/routine.py +1033 -0
  113. ams/routines/rted.py +519 -0
  114. ams/routines/type.py +160 -0
  115. ams/routines/uc.py +376 -0
  116. ams/shared.py +63 -9
  117. ams/system.py +61 -22
  118. ams/utils/__init__.py +3 -0
  119. ams/utils/misc.py +77 -0
  120. ams/utils/paths.py +257 -0
  121. docs/Makefile +21 -0
  122. docs/make.bat +35 -0
  123. docs/source/_templates/autosummary/base.rst +5 -0
  124. docs/source/_templates/autosummary/class.rst +35 -0
  125. docs/source/_templates/autosummary/module.rst +65 -0
  126. docs/source/_templates/autosummary/module_toctree.rst +66 -0
  127. docs/source/api.rst +102 -0
  128. docs/source/conf.py +203 -0
  129. docs/source/examples/index.rst +34 -0
  130. docs/source/genmodelref.py +61 -0
  131. docs/source/genroutineref.py +47 -0
  132. docs/source/getting_started/copyright.rst +20 -0
  133. docs/source/getting_started/formats/index.rst +20 -0
  134. docs/source/getting_started/formats/matpower.rst +183 -0
  135. docs/source/getting_started/formats/psse.rst +46 -0
  136. docs/source/getting_started/formats/pypower.rst +223 -0
  137. docs/source/getting_started/formats/xlsx.png +0 -0
  138. docs/source/getting_started/formats/xlsx.rst +23 -0
  139. docs/source/getting_started/index.rst +76 -0
  140. docs/source/getting_started/install.rst +234 -0
  141. docs/source/getting_started/overview.rst +26 -0
  142. docs/source/getting_started/testcase.rst +45 -0
  143. docs/source/getting_started/verification.rst +13 -0
  144. docs/source/images/curent.ico +0 -0
  145. docs/source/images/dcopf_time.png +0 -0
  146. docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
  147. docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
  148. docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
  149. docs/source/images/sponsors/doe.png +0 -0
  150. docs/source/index.rst +108 -0
  151. docs/source/modeling/example.rst +159 -0
  152. docs/source/modeling/index.rst +17 -0
  153. docs/source/modeling/model.rst +210 -0
  154. docs/source/modeling/routine.rst +122 -0
  155. docs/source/modeling/system.rst +51 -0
  156. docs/source/release-notes.rst +398 -0
  157. ltbams-1.0.2a1.dist-info/METADATA +210 -0
  158. ltbams-1.0.2a1.dist-info/RECORD +188 -0
  159. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/WHEEL +1 -1
  160. ltbams-1.0.2a1.dist-info/top_level.txt +3 -0
  161. tests/__init__.py +0 -0
  162. tests/test_1st_system.py +33 -0
  163. tests/test_addressing.py +40 -0
  164. tests/test_andes_mats.py +61 -0
  165. tests/test_case.py +266 -0
  166. tests/test_cli.py +34 -0
  167. tests/test_export_csv.py +89 -0
  168. tests/test_group.py +83 -0
  169. tests/test_interface.py +216 -0
  170. tests/test_io.py +32 -0
  171. tests/test_jumper.py +27 -0
  172. tests/test_known_good.py +267 -0
  173. tests/test_matp.py +437 -0
  174. tests/test_model.py +54 -0
  175. tests/test_omodel.py +119 -0
  176. tests/test_paths.py +22 -0
  177. tests/test_report.py +251 -0
  178. tests/test_repr.py +21 -0
  179. tests/test_routine.py +178 -0
  180. tests/test_rtn_dcopf.py +101 -0
  181. tests/test_rtn_dcpf.py +77 -0
  182. tests/test_rtn_ed.py +279 -0
  183. tests/test_rtn_pflow.py +219 -0
  184. tests/test_rtn_rted.py +273 -0
  185. tests/test_rtn_uc.py +248 -0
  186. tests/test_service.py +73 -0
  187. ltbams-0.9.9.dist-info/LICENSE +0 -692
  188. ltbams-0.9.9.dist-info/METADATA +0 -859
  189. ltbams-0.9.9.dist-info/RECORD +0 -14
  190. ltbams-0.9.9.dist-info/top_level.txt +0 -1
  191. {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/entry_points.txt +0 -0
Binary file
ams/cli.py CHANGED
@@ -29,6 +29,12 @@ def create_parser():
29
29
  -------
30
30
  argparse.ArgumentParser
31
31
  Parser with all AMS options
32
+
33
+ Notes
34
+ -----
35
+ Revised from the ANDES project (https://github.com/CURENT/andes).
36
+ Original author: Hantao Cui
37
+ License: GPL3
32
38
  """
33
39
 
34
40
  parser = argparse.ArgumentParser()
ams/core/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from ams.core.model import Model # NOQA
2
+ from ams.core.var import Algeb # NOQA
ams/core/documenter.py ADDED
@@ -0,0 +1,652 @@
1
+ """
2
+ Documenter class for AMS models.
3
+ """
4
+ import inspect
5
+ import re
6
+
7
+ import logging
8
+ from collections import OrderedDict
9
+ from andes.core.documenter import Documenter as andes_Documenter
10
+ from andes.utils.tab import make_doc_table, math_wrap
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
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):
29
+ """
30
+ Helper class for documenting models.
31
+
32
+ Parameters
33
+ ----------
34
+ parent : Model
35
+ The `Model` instance to document
36
+ """
37
+
38
+ def __init__(self, parent):
39
+ 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
+
51
+ def get(self, max_width=78, export='plain'):
52
+ """
53
+ Return the model documentation in table-formatted string.
54
+
55
+ Parameters
56
+ ----------
57
+ max_width : int
58
+ Maximum table width. Automatically et to 0 if format is ``rest``.
59
+ export : str, ('plain', 'rest')
60
+ Export format. Use fancy table if is ``rest``.
61
+
62
+ Returns
63
+ -------
64
+ str
65
+ A string with the documentations.
66
+ """
67
+ out = ''
68
+ if export == 'rest':
69
+ max_width = 0
70
+ model_header = '-' * 80 + '\n'
71
+ out += f'.. _{self.class_name}:\n\n'
72
+ else:
73
+ model_header = ''
74
+
75
+ if export == 'rest':
76
+ out += model_header + f'{self.class_name}\n' + model_header
77
+ else:
78
+ out += model_header + f'Model <{self.class_name}> in Group <{self.parent.group}>\n' + model_header
79
+
80
+ if self.parent.__doc__ is not None:
81
+ out += inspect.cleandoc(self.parent.__doc__)
82
+ out += '\n\n' # this fixes the indentation for the next line
83
+
84
+ # add tables
85
+ out += self._param_doc(max_width=max_width, export=export)
86
+ out += self._var_doc(max_width=max_width, export=export)
87
+ out += self._service_doc(max_width=max_width, export=export)
88
+ # TODO: fix and add the config doc later on
89
+ # out += self.config.doc(max_width=max_width, export=export)
90
+
91
+ return out
92
+
93
+ def _var_doc(self, max_width=78, export='plain'):
94
+ # variable documentation
95
+ if len(self.algebs) == 0:
96
+ return ''
97
+
98
+ names, symbols, units = list(), list(), list()
99
+ info = list()
100
+ units_rest, ty = list(), list()
101
+
102
+ for p in self.algebs.values():
103
+ names.append(p.name)
104
+ ty.append(p.class_name)
105
+ info.append(p.info if p.info else '')
106
+ units.append(p.unit if p.unit else '')
107
+ units_rest.append(f'*{p.unit}*' if p.unit else '')
108
+
109
+ title = 'Variables'
110
+
111
+ # replace with latex math expressions if export is ``rest``
112
+ if export == 'rest':
113
+ symbols = [item.tex_name for item in self.algebs.values()]
114
+ symbols = math_wrap(symbols, export=export)
115
+ title = 'Variables\n---------'
116
+
117
+ plain_dict = OrderedDict([('Name', names),
118
+ ('Type', ty),
119
+ ('Description', info),
120
+ ('Unit', units)])
121
+
122
+ rest_dict = OrderedDict([('Name', names),
123
+ ('Symbol', symbols),
124
+ ('Type', ty),
125
+ ('Description', info),
126
+ ('Unit', units_rest)])
127
+
128
+ return make_doc_table(title=title,
129
+ max_width=max_width,
130
+ export=export,
131
+ plain_dict=plain_dict,
132
+ rest_dict=rest_dict)
133
+
134
+ def _service_doc(self, max_width=78, export='plain'):
135
+ if len(self.services) == 0:
136
+ return ''
137
+
138
+ names, symbols = list(), list()
139
+ info = list()
140
+ class_names = list()
141
+
142
+ for p in self.services.values():
143
+ names.append(p.name)
144
+ class_names.append(p.class_name)
145
+ info.append(p.info if p.info else '')
146
+ symbols.append(p.tex_name if p.tex_name is not None else '')
147
+
148
+ title = 'Services'
149
+ if export == 'rest':
150
+ symbols = math_wrap(symbols, export=export)
151
+ title = 'Services\n----------'
152
+
153
+ plain_dict = OrderedDict([('Name', names),
154
+ ('Description', info),
155
+ ('Type', class_names)])
156
+
157
+ rest_dict = OrderedDict([('Name', names),
158
+ ('Description', info),
159
+ ('Symbol', symbols),
160
+ ('Type', class_names)])
161
+
162
+ return make_doc_table(title=title,
163
+ max_width=max_width,
164
+ export=export,
165
+ plain_dict=plain_dict,
166
+ rest_dict=rest_dict)
167
+
168
+
169
+ class RDocumenter:
170
+ """
171
+ Helper class for documenting routines.
172
+
173
+ Parameters
174
+ ----------
175
+ parent : Model
176
+ The `Model` instance to document
177
+ """
178
+
179
+ def __init__(self, parent):
180
+ 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
+
190
+ def get(self, max_width=78, export='plain'):
191
+ """
192
+ Return the routine documentation in table-formatted string.
193
+
194
+ Parameters
195
+ ----------
196
+ max_width : int
197
+ Maximum table width. Automatically et to 0 if format is ``rest``.
198
+ export : str, ('plain', 'rest')
199
+ Export format. Use fancy table if is ``rest``.
200
+
201
+ Returns
202
+ -------
203
+ str
204
+ A string with the documentations.
205
+ """
206
+ out = ''
207
+ if export == 'rest':
208
+ max_width = 0
209
+ model_header = '-' * 80 + '\n'
210
+ out += f'.. _{self.class_name}:\n\n'
211
+ else:
212
+ model_header = ''
213
+
214
+ if export == 'rest':
215
+ out += model_header + f'{self.class_name}\n' + model_header
216
+ else:
217
+ out += model_header + f'Routine <{self.class_name}> in Type <{self.parent.type}>\n' + model_header
218
+
219
+ if self.parent.__doc__ is not None:
220
+ out += inspect.cleandoc(self.parent.__doc__)
221
+ out += '\n\n' # this fixes the indentation for the next line
222
+
223
+ # add tables
224
+ self.parent.syms.generate_symbols()
225
+ out += self._obj_doc(max_width=max_width, export=export)
226
+ out += self._expr_doc(max_width=max_width, export=export)
227
+ out += self._constr_doc(max_width=max_width, export=export)
228
+ out += self._var_doc(max_width=max_width, export=export)
229
+ out += self._exprc_doc(max_width=max_width, export=export)
230
+ out += self._service_doc(max_width=max_width, export=export)
231
+ out += self._param_doc(max_width=max_width, export=export)
232
+ out += self.config.doc(max_width=max_width, export=export)
233
+
234
+ return out
235
+
236
+ def _service_doc(self, max_width=78, export='plain'):
237
+ # routine service documentation
238
+ if len(self.services) == 0:
239
+ return ''
240
+
241
+ names, symbols = list(), list()
242
+ info = list()
243
+ class_names = list()
244
+
245
+ for p in self.services.values():
246
+ names.append(p.name)
247
+ info.append(p.info if p.info else '')
248
+ class_names.append(p.class_name)
249
+
250
+ title = 'Services'
251
+
252
+ # replace with latex math expressions if export is ``rest``
253
+ if export == 'rest':
254
+ symbols = [item.tex_name for item in self.services.values()]
255
+ symbols = math_wrap(symbols, export=export)
256
+ title = 'Services\n---------'
257
+
258
+ plain_dict = OrderedDict([('Name', names),
259
+ ('Description', info),
260
+ ('Type', class_names)])
261
+
262
+ rest_dict = OrderedDict([('Name', names),
263
+ ('Symbol', symbols),
264
+ ('Description', info),
265
+ ('Type', class_names)])
266
+
267
+ return make_doc_table(title=title,
268
+ max_width=max_width,
269
+ export=export,
270
+ plain_dict=plain_dict,
271
+ rest_dict=rest_dict)
272
+
273
+ def _constr_doc(self, max_width=78, export='plain'):
274
+ # constraint documentation
275
+ if len(self.constrs) == 0:
276
+ return ''
277
+
278
+ # prepare temporary lists
279
+ names, class_names, info = list(), list(), list()
280
+
281
+ for p in self.constrs.values():
282
+ names.append(p.name)
283
+ class_names.append(p.class_name)
284
+ info.append(p.info if p.info else '')
285
+
286
+ # expressions based on output format
287
+ expressions = []
288
+ if export == 'rest':
289
+ for p in self.constrs.values():
290
+ expr = _tex_pre(self, p, self.parent.syms.tex_map)
291
+ if p.is_eq:
292
+ expr = f'{expr} = 0'
293
+ else:
294
+ expr = f'{expr} \\leq 0'
295
+ logger.debug(f'{p.name} math: {expr}')
296
+ expressions.append(expr)
297
+
298
+ title = 'Constraints\n----------------------------------'
299
+ else:
300
+ title = 'Constraints'
301
+ expressions = math_wrap(expressions, export=export)
302
+
303
+ plain_dict = OrderedDict([('Name', names),
304
+ ('Description', info),
305
+ ])
306
+
307
+ rest_dict = OrderedDict([('Name', names),
308
+ ('Description', info),
309
+ ('Expression', expressions),
310
+ ])
311
+
312
+ # convert to rows and export as table
313
+ return make_doc_table(title=title,
314
+ max_width=max_width,
315
+ export=export,
316
+ plain_dict=plain_dict,
317
+ rest_dict=rest_dict)
318
+
319
+ def _expr_doc(self, max_width=78, export='plain'):
320
+ # Expression documentation
321
+ if len(self.parent.exprs) == 0:
322
+ return ''
323
+
324
+ # prepare temporary lists
325
+ names, info = list(), list()
326
+ units, sources, units_rest = list(), list(), list()
327
+
328
+ for p in self.parent.exprs.values():
329
+ names.append(p.name)
330
+ info.append(p.info if p.info else '')
331
+ units.append(p.unit if p.unit else '')
332
+ units_rest.append(f'*{p.unit}*' if p.unit else '')
333
+
334
+ slist = []
335
+ if p.owner is not None and p.src is not None:
336
+ slist.append(f'{p.owner.class_name}.{p.src}')
337
+ elif p.owner is not None and p.src is None:
338
+ slist.append(f'{p.owner.class_name}')
339
+ sources.append(','.join(slist))
340
+
341
+ # expressions based on output format
342
+ expressions = []
343
+ if export == 'rest':
344
+ for p in self.parent.exprs.values():
345
+ expr = _tex_pre(self, p, self.parent.syms.tex_map)
346
+ logger.debug(f'{p.name} math: {expr}')
347
+ expressions.append(expr)
348
+
349
+ title = 'Expressions\n----------------------------------'
350
+ else:
351
+ title = 'Expressions'
352
+ expressions = math_wrap(expressions, export=export)
353
+
354
+ plain_dict = OrderedDict([('Name', names),
355
+ ('Description', info),
356
+ ('Unit', units),
357
+ ])
358
+ rest_dict = OrderedDict([('Name', names),
359
+ ('Description', info),
360
+ ('Expression', expressions),
361
+ ('Unit', units_rest),
362
+ ('Source', sources),
363
+ ])
364
+
365
+ # convert to rows and export as table
366
+ return make_doc_table(title=title,
367
+ max_width=max_width,
368
+ export=export,
369
+ plain_dict=plain_dict,
370
+ rest_dict=rest_dict)
371
+
372
+ def _exprc_doc(self, max_width=78, export='plain'):
373
+ # ExpressionCalc documentation
374
+ if len(self.parent.exprcs) == 0:
375
+ return ''
376
+
377
+ # prepare temporary lists
378
+ names, info = list(), list()
379
+ units, sources, units_rest = list(), list(), list()
380
+
381
+ for p in self.parent.exprcs.values():
382
+ names.append(p.name)
383
+ info.append(p.info if p.info else '')
384
+ units.append(p.unit if p.unit else '')
385
+ units_rest.append(f'*{p.unit}*' if p.unit else '')
386
+
387
+ slist = []
388
+ if p.owner is not None and p.src is not None:
389
+ slist.append(f'{p.owner.class_name}.{p.src}')
390
+ elif p.owner is not None and p.src is None:
391
+ slist.append(f'{p.owner.class_name}')
392
+ sources.append(','.join(slist))
393
+
394
+ # expressions based on output format
395
+ expressions = []
396
+ if export == 'rest':
397
+ for p in self.parent.exprcs.values():
398
+ expr = _tex_pre(self, p, self.parent.syms.tex_map)
399
+ logger.debug(f'{p.name} math: {expr}')
400
+ expressions.append(expr)
401
+
402
+ title = 'ExpressionCalcs\n----------------------------------'
403
+ else:
404
+ title = 'ExpressionCalcs'
405
+ expressions = math_wrap(expressions, export=export)
406
+
407
+ plain_dict = OrderedDict([('Name', names),
408
+ ('Description', info),
409
+ ('Unit', units),
410
+ ])
411
+ rest_dict = OrderedDict([('Name', names),
412
+ ('Description', info),
413
+ ('Expression', expressions),
414
+ ('Unit', units_rest),
415
+ ('Source', sources),
416
+ ])
417
+
418
+ # convert to rows and export as table
419
+ return make_doc_table(title=title,
420
+ max_width=max_width,
421
+ export=export,
422
+ plain_dict=plain_dict,
423
+ rest_dict=rest_dict)
424
+
425
+ def _obj_doc(self, max_width=78, export='plain'):
426
+ # variable documentation
427
+ if self.parent.obj is None:
428
+ return ''
429
+
430
+ # prepare temporary lists
431
+ units, units_rest = list(), list()
432
+
433
+ p = self.parent.obj
434
+ units.append(p.unit if p.unit else '')
435
+ units_rest.append(f'*{p.unit}*' if p.unit else '')
436
+
437
+ # expressions based on output format
438
+ expr = _tex_pre(self, p, self.parent.syms.tex_map)
439
+ expr = p.sense + '. ' + expr # minimize or maximize
440
+ expr = [expr]
441
+ if export == 'rest':
442
+ expr = math_wrap(expr, export=export)
443
+ title = 'Objective\n----------------------------------'
444
+ else:
445
+ title = 'Objective'
446
+
447
+ plain_dict = OrderedDict([('Unit', units),])
448
+
449
+ rest_dict = OrderedDict([('Unit', units_rest),
450
+ ('Expression', expr)])
451
+
452
+ # convert to rows and export as table
453
+ return make_doc_table(title=title,
454
+ max_width=max_width,
455
+ export=export,
456
+ plain_dict=plain_dict,
457
+ rest_dict=rest_dict)
458
+
459
+ def _var_doc(self, max_width=78, export='plain'):
460
+ # NOTE: this is for the optimization variables
461
+ # not the _var_doc for ANDES parameters
462
+ # variable documentation
463
+ if len(self.vars) == 0:
464
+ return ''
465
+
466
+ # prepare temporary lists
467
+ names, units, class_names = list(), list(), list()
468
+ properties, info = list(), list()
469
+ sources = list()
470
+ units_rest = list()
471
+
472
+ for p in self.vars.values():
473
+ names.append(p.name)
474
+ class_names.append(p.class_name)
475
+ info.append(p.info if p.info else '')
476
+ # defaults.append(p.default if p.default is not None else '')
477
+ units.append(f'{p.unit}' if p.unit else '')
478
+ units_rest.append(f'*{p.unit}*' if p.unit else '')
479
+
480
+ # collect properties defined in config
481
+ plist = []
482
+ for key, val in p.config.as_dict().items():
483
+ if val is True:
484
+ plist.append(key)
485
+ properties.append(','.join(plist))
486
+
487
+ slist = []
488
+ if p.owner is not None and p.src is not None:
489
+ slist.append(f'{p.owner.class_name}.{p.src}')
490
+ elif p.owner is not None and p.src is None:
491
+ slist.append(f'{p.owner.class_name}')
492
+ sources.append(','.join(slist))
493
+
494
+ # symbols based on output format
495
+ if export == 'rest':
496
+ symbols = [item.tex_name for item in self.vars.values()]
497
+ symbols = math_wrap(symbols, export=export)
498
+ title = 'Vars\n----------------------------------'
499
+ else:
500
+ symbols = [item.name for item in self.vars.values()]
501
+ title = 'Vars'
502
+
503
+ plain_dict = OrderedDict([('Name', names),
504
+ ('Description', info),
505
+ ('Unit', units),
506
+ ('Properties', properties)])
507
+
508
+ rest_dict = OrderedDict([('Name', names),
509
+ ('Symbol', symbols),
510
+ ('Description', info),
511
+ ('Unit', units_rest),
512
+ ('Source', sources),
513
+ ('Properties', properties)])
514
+
515
+ # convert to rows and export as table
516
+ return make_doc_table(title=title,
517
+ max_width=max_width,
518
+ export=export,
519
+ plain_dict=plain_dict,
520
+ rest_dict=rest_dict)
521
+
522
+ def _param_doc(self, max_width=78, export='plain'):
523
+ """
524
+ Export formatted routine parameter documentation as a string.
525
+
526
+ Parameters
527
+ ----------
528
+ max_width : int, optional = 80
529
+ Maximum table width. If export format is ``rest`` it will be unlimited.
530
+
531
+ export : str, optional = 'plain'
532
+ Export format, 'plain' for plain text, 'rest' for restructuredText.
533
+
534
+ Returns
535
+ -------
536
+ str
537
+ Tabulated output in a string
538
+ """
539
+ if len(self.rparams) == 0:
540
+ return ''
541
+
542
+ # prepare temporary lists
543
+ names, units, class_names = list(), list(), list()
544
+ info = list()
545
+ sources = list()
546
+ units_rest = list()
547
+
548
+ for p in self.rparams.values():
549
+ names.append(p.name)
550
+ class_names.append(p.class_name)
551
+ info.append(p.info if p.info else '')
552
+ # defaults.append(p.default if p.default is not None else '')
553
+ units.append(f'{p.unit}' if p.unit else '')
554
+ units_rest.append(f'*{p.unit}*' if p.unit else '')
555
+
556
+ slist = []
557
+ if p.owner is not None and p.src is not None:
558
+ slist.append(f'{p.owner.class_name}.{p.src}')
559
+ elif p.owner is not None and p.src is None:
560
+ slist.append(f'{p.owner.class_name}')
561
+ sources.append(','.join(slist))
562
+
563
+ # symbols based on output format
564
+ if export == 'rest':
565
+ symbols = [item.tex_name for item in self.rparams.values()]
566
+ symbols = math_wrap(symbols, export=export)
567
+ title = 'Parameters\n----------------------------------'
568
+ else:
569
+ symbols = [item.name for item in self.rparams.values()]
570
+ title = 'Parameters'
571
+
572
+ plain_dict = OrderedDict([('Name', names),
573
+ ('Description', info),
574
+ ('Unit', units),
575
+ ])
576
+
577
+ rest_dict = OrderedDict([('Name', names),
578
+ ('Symbol', symbols),
579
+ ('Description', info),
580
+ ('Unit', units_rest),
581
+ ('Source', sources),
582
+ ])
583
+
584
+ # convert to rows and export as table
585
+ return make_doc_table(title=title,
586
+ max_width=max_width,
587
+ export=export,
588
+ plain_dict=plain_dict,
589
+ rest_dict=rest_dict)
590
+
591
+
592
+ def _tex_pre(docm, p, tex_map):
593
+ """
594
+ Prepare the expression for pretty printing.
595
+
596
+ Parameters
597
+ ----------
598
+ docm : Documenter
599
+ The Documenter instance.
600
+ p : obj or const
601
+ The objective or constraint instance.
602
+ tex_map : dict
603
+ The tex map to use.
604
+ """
605
+
606
+ # NOTE: in the future, there might occur special math symbols
607
+ map_before = OrderedDict([
608
+ ('sum', 'SUM'),
609
+ (r'\sum', 'SUM'),
610
+ (r'\eta', 'ETA'),
611
+ (r'\gamma', 'GAMMA'),
612
+ (r'\theta', 'THETA'),
613
+ (r'\phi', 'PHI'),
614
+ (r'\frac', 'FRAC'),
615
+ (r'\overline', 'OVERLINE'),
616
+ (r'\underline', 'UNDERLINE'),
617
+ ])
618
+ map_post = OrderedDict([
619
+ ('SUM', r'\sum'),
620
+ ('THETA', r'\theta'),
621
+ ('ETA', r'\eta'),
622
+ ('GAMMA', r'\gamma'),
623
+ ('PHI', r'\phi'),
624
+ ('FRAC', r'\frac'),
625
+ ('OVERLINE', r'\overline'),
626
+ ('UNDERLINE', r'\underline'),
627
+ ])
628
+
629
+ expr = p.e_str
630
+
631
+ for pattern, replacement in tex_map.items():
632
+ for key, val in map_before.items():
633
+ if key in replacement:
634
+ replacement = replacement.replace(key, val)
635
+ if r'\p' in replacement:
636
+ continue
637
+ try:
638
+ expr = re.sub(pattern, replacement, expr)
639
+ except re.error:
640
+ expr_pattern = pattern.removeprefix('\\b').removesuffix('\\b')
641
+ msg = f'Failed to parse <{expr_pattern}> in {docm.parent.class_name} <{p.name}>, check its tex_name.'
642
+ logger.error(msg)
643
+ expr = ''
644
+ try:
645
+ expr = expr.replace('*', ' ')
646
+ except re.error:
647
+ logger.error('Remains '*' in the expression.')
648
+
649
+ for pattern, replacement in map_post.items():
650
+ expr = expr.replace(pattern, replacement)
651
+
652
+ return expr