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.
- ams/__init__.py +4 -11
- ams/_version.py +3 -3
- ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
- ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced.json +1062 -0
- ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
- ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
- ams/cases/ieee123/ieee123.xlsx +0 -0
- ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
- ams/cases/ieee14/ieee14.json +1166 -0
- ams/cases/ieee14/ieee14.raw +92 -0
- ams/cases/ieee14/ieee14_conn.xlsx +0 -0
- ams/cases/ieee14/ieee14_uced.xlsx +0 -0
- ams/cases/ieee39/ieee39.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
- ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
- ams/cases/matpower/benchmark.json +1594 -0
- ams/cases/matpower/case118.m +787 -0
- ams/cases/matpower/case14.m +129 -0
- ams/cases/matpower/case300.m +1315 -0
- ams/cases/matpower/case39.m +205 -0
- ams/cases/matpower/case5.m +62 -0
- ams/cases/matpower/case_ACTIVSg2000.m +9460 -0
- ams/cases/npcc/npcc.m +644 -0
- ams/cases/npcc/npcc_uced.xlsx +0 -0
- ams/cases/pglib/pglib_opf_case39_epri__api.m +243 -0
- ams/cases/wecc/wecc.m +714 -0
- ams/cases/wecc/wecc_uced.xlsx +0 -0
- ams/cli.py +6 -0
- ams/core/__init__.py +2 -0
- ams/core/documenter.py +652 -0
- ams/core/matprocessor.py +782 -0
- ams/core/model.py +330 -0
- ams/core/param.py +322 -0
- ams/core/service.py +918 -0
- ams/core/symprocessor.py +224 -0
- ams/core/var.py +59 -0
- ams/extension/__init__.py +5 -0
- ams/extension/eva.py +401 -0
- ams/interface.py +1085 -0
- ams/io/__init__.py +133 -0
- ams/io/json.py +82 -0
- ams/io/matpower.py +406 -0
- ams/io/psse.py +6 -0
- ams/io/pypower.py +103 -0
- ams/io/xlsx.py +80 -0
- ams/main.py +81 -4
- ams/models/__init__.py +24 -0
- ams/models/area.py +40 -0
- ams/models/bus.py +52 -0
- ams/models/cost.py +169 -0
- ams/models/distributed/__init__.py +3 -0
- ams/models/distributed/esd1.py +71 -0
- ams/models/distributed/ev.py +60 -0
- ams/models/distributed/pvd1.py +67 -0
- ams/models/group.py +231 -0
- ams/models/info.py +26 -0
- ams/models/line.py +238 -0
- ams/models/renewable/__init__.py +5 -0
- ams/models/renewable/regc.py +119 -0
- ams/models/reserve.py +94 -0
- ams/models/shunt.py +14 -0
- ams/models/static/__init__.py +2 -0
- ams/models/static/gen.py +165 -0
- ams/models/static/pq.py +61 -0
- ams/models/timeslot.py +69 -0
- ams/models/zone.py +49 -0
- ams/opt/__init__.py +12 -0
- ams/opt/constraint.py +175 -0
- ams/opt/exprcalc.py +127 -0
- ams/opt/expression.py +188 -0
- ams/opt/objective.py +174 -0
- ams/opt/omodel.py +432 -0
- ams/opt/optzbase.py +192 -0
- ams/opt/param.py +156 -0
- ams/opt/var.py +233 -0
- ams/pypower/__init__.py +8 -0
- ams/pypower/_compat.py +9 -0
- ams/pypower/core/__init__.py +8 -0
- ams/pypower/core/pips.py +894 -0
- ams/pypower/core/ppoption.py +244 -0
- ams/pypower/core/ppver.py +18 -0
- ams/pypower/core/solver.py +2451 -0
- ams/pypower/eps.py +6 -0
- ams/pypower/idx.py +174 -0
- ams/pypower/io.py +604 -0
- ams/pypower/make/__init__.py +11 -0
- ams/pypower/make/matrices.py +665 -0
- ams/pypower/make/pdv.py +506 -0
- ams/pypower/routines/__init__.py +7 -0
- ams/pypower/routines/cpf.py +513 -0
- ams/pypower/routines/cpf_callbacks.py +114 -0
- ams/pypower/routines/opf.py +1803 -0
- ams/pypower/routines/opffcns.py +1946 -0
- ams/pypower/routines/pflow.py +852 -0
- ams/pypower/toggle.py +1098 -0
- ams/pypower/utils.py +293 -0
- ams/report.py +212 -50
- ams/routines/__init__.py +23 -0
- ams/routines/acopf.py +117 -0
- ams/routines/cpf.py +65 -0
- ams/routines/dcopf.py +241 -0
- ams/routines/dcpf.py +209 -0
- ams/routines/dcpf0.py +196 -0
- ams/routines/dopf.py +150 -0
- ams/routines/ed.py +312 -0
- ams/routines/pflow.py +255 -0
- ams/routines/pflow0.py +113 -0
- ams/routines/routine.py +1033 -0
- ams/routines/rted.py +519 -0
- ams/routines/type.py +160 -0
- ams/routines/uc.py +376 -0
- ams/shared.py +63 -9
- ams/system.py +61 -22
- ams/utils/__init__.py +3 -0
- ams/utils/misc.py +77 -0
- ams/utils/paths.py +257 -0
- docs/Makefile +21 -0
- docs/make.bat +35 -0
- docs/source/_templates/autosummary/base.rst +5 -0
- docs/source/_templates/autosummary/class.rst +35 -0
- docs/source/_templates/autosummary/module.rst +65 -0
- docs/source/_templates/autosummary/module_toctree.rst +66 -0
- docs/source/api.rst +102 -0
- docs/source/conf.py +203 -0
- docs/source/examples/index.rst +34 -0
- docs/source/genmodelref.py +61 -0
- docs/source/genroutineref.py +47 -0
- docs/source/getting_started/copyright.rst +20 -0
- docs/source/getting_started/formats/index.rst +20 -0
- docs/source/getting_started/formats/matpower.rst +183 -0
- docs/source/getting_started/formats/psse.rst +46 -0
- docs/source/getting_started/formats/pypower.rst +223 -0
- docs/source/getting_started/formats/xlsx.png +0 -0
- docs/source/getting_started/formats/xlsx.rst +23 -0
- docs/source/getting_started/index.rst +76 -0
- docs/source/getting_started/install.rst +234 -0
- docs/source/getting_started/overview.rst +26 -0
- docs/source/getting_started/testcase.rst +45 -0
- docs/source/getting_started/verification.rst +13 -0
- docs/source/images/curent.ico +0 -0
- docs/source/images/dcopf_time.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
- docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
- docs/source/images/sponsors/doe.png +0 -0
- docs/source/index.rst +108 -0
- docs/source/modeling/example.rst +159 -0
- docs/source/modeling/index.rst +17 -0
- docs/source/modeling/model.rst +210 -0
- docs/source/modeling/routine.rst +122 -0
- docs/source/modeling/system.rst +51 -0
- docs/source/release-notes.rst +398 -0
- ltbams-1.0.2a1.dist-info/METADATA +210 -0
- ltbams-1.0.2a1.dist-info/RECORD +188 -0
- {ltbams-0.9.9.dist-info → ltbams-1.0.2a1.dist-info}/WHEEL +1 -1
- ltbams-1.0.2a1.dist-info/top_level.txt +3 -0
- tests/__init__.py +0 -0
- tests/test_1st_system.py +33 -0
- tests/test_addressing.py +40 -0
- tests/test_andes_mats.py +61 -0
- tests/test_case.py +266 -0
- tests/test_cli.py +34 -0
- tests/test_export_csv.py +89 -0
- tests/test_group.py +83 -0
- tests/test_interface.py +216 -0
- tests/test_io.py +32 -0
- tests/test_jumper.py +27 -0
- tests/test_known_good.py +267 -0
- tests/test_matp.py +437 -0
- tests/test_model.py +54 -0
- tests/test_omodel.py +119 -0
- tests/test_paths.py +22 -0
- tests/test_report.py +251 -0
- tests/test_repr.py +21 -0
- tests/test_routine.py +178 -0
- tests/test_rtn_dcopf.py +101 -0
- tests/test_rtn_dcpf.py +77 -0
- tests/test_rtn_ed.py +279 -0
- tests/test_rtn_pflow.py +219 -0
- tests/test_rtn_rted.py +273 -0
- tests/test_rtn_uc.py +248 -0
- tests/test_service.py +73 -0
- ltbams-0.9.9.dist-info/LICENSE +0 -692
- ltbams-0.9.9.dist-info/METADATA +0 -859
- ltbams-0.9.9.dist-info/RECORD +0 -14
- ltbams-0.9.9.dist-info/top_level.txt +0 -1
- {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
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
|