ltbams 0.9.10__tar.gz → 0.9.12__tar.gz

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 (207) hide show
  1. {ltbams-0.9.10 → ltbams-0.9.12}/LICENSE +1 -1
  2. {ltbams-0.9.10/ltbams.egg-info → ltbams-0.9.12}/PKG-INFO +37 -17
  3. {ltbams-0.9.10 → ltbams-0.9.12}/README.md +21 -3
  4. ltbams-0.9.12/ams/__init__.py +14 -0
  5. {ltbams-0.9.10 → ltbams-0.9.12}/ams/_version.py +3 -3
  6. ltbams-0.9.12/ams/benchmarks.py +302 -0
  7. ltbams-0.9.12/ams/cases/5bus/pjm5bus_jumper.xlsx +0 -0
  8. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/5bus/pjm5bus_uced_esd1.xlsx +0 -0
  9. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cli.py +6 -0
  10. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/documenter.py +74 -6
  11. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/matprocessor.py +23 -7
  12. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/param.py +7 -3
  13. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/service.py +47 -26
  14. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/symprocessor.py +22 -6
  15. ltbams-0.9.10/ams/interop/andes.py → ltbams-0.9.12/ams/interface.py +101 -64
  16. {ltbams-0.9.10 → ltbams-0.9.12}/ams/io/__init__.py +0 -1
  17. {ltbams-0.9.10 → ltbams-0.9.12}/ams/io/json.py +2 -9
  18. {ltbams-0.9.10 → ltbams-0.9.12}/ams/io/matpower.py +14 -14
  19. {ltbams-0.9.10 → ltbams-0.9.12}/ams/io/xlsx.py +3 -10
  20. {ltbams-0.9.10 → ltbams-0.9.12}/ams/main.py +83 -4
  21. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/__init__.py +1 -1
  22. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/group.py +10 -3
  23. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/line.py +28 -0
  24. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/reserve.py +4 -4
  25. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/static/gen.py +9 -3
  26. ltbams-0.9.12/ams/opt/__init__.py +12 -0
  27. ltbams-0.9.12/ams/opt/constraint.py +172 -0
  28. ltbams-0.9.12/ams/opt/exprcalc.py +139 -0
  29. ltbams-0.9.12/ams/opt/expression.py +200 -0
  30. ltbams-0.9.12/ams/opt/objective.py +174 -0
  31. ltbams-0.9.12/ams/opt/omodel.py +432 -0
  32. ltbams-0.9.12/ams/opt/optbase.py +155 -0
  33. ltbams-0.9.12/ams/opt/param.py +156 -0
  34. ltbams-0.9.12/ams/opt/var.py +245 -0
  35. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/routines/opf.py +1 -1
  36. {ltbams-0.9.10 → ltbams-0.9.12}/ams/report.py +21 -4
  37. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/__init__.py +2 -1
  38. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/acopf.py +7 -9
  39. ltbams-0.9.12/ams/routines/dcopf.py +194 -0
  40. ltbams-0.9.12/ams/routines/dcpf.py +205 -0
  41. ltbams-0.9.10/ams/routines/dcpf.py → ltbams-0.9.12/ams/routines/dcpf0.py +12 -13
  42. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/dopf.py +1 -1
  43. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/ed.py +22 -31
  44. ltbams-0.9.12/ams/routines/pflow.py +255 -0
  45. ltbams-0.9.10/ams/routines/pflow.py → ltbams-0.9.12/ams/routines/pflow0.py +11 -11
  46. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/routine.py +135 -56
  47. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/rted.py +15 -14
  48. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/uc.py +15 -12
  49. {ltbams-0.9.10 → ltbams-0.9.12}/ams/shared.py +34 -9
  50. {ltbams-0.9.10 → ltbams-0.9.12}/ams/system.py +19 -10
  51. ltbams-0.9.12/ams/utils/__init__.py +59 -0
  52. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/api.rst +4 -2
  53. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/conf.py +1 -1
  54. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/examples/index.rst +2 -1
  55. ltbams-0.9.12/docs/source/genmodelref.py +61 -0
  56. ltbams-0.9.12/docs/source/genroutineref.py +47 -0
  57. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/install.rst +2 -2
  58. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/modeling/example.rst +1 -1
  59. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/modeling/routine.rst +5 -12
  60. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/release-notes.rst +67 -25
  61. {ltbams-0.9.10 → ltbams-0.9.12/ltbams.egg-info}/PKG-INFO +37 -17
  62. {ltbams-0.9.10 → ltbams-0.9.12}/ltbams.egg-info/SOURCES.txt +27 -5
  63. {ltbams-0.9.10 → ltbams-0.9.12}/ltbams.egg-info/requires.txt +28 -23
  64. ltbams-0.9.12/pyproject.toml +73 -0
  65. ltbams-0.9.12/requirements-extra.txt +19 -0
  66. {ltbams-0.9.10 → ltbams-0.9.12}/requirements.txt +3 -1
  67. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_1st_system.py +1 -1
  68. ltbams-0.9.12/tests/test_andes_mats.py +61 -0
  69. ltbams-0.9.12/tests/test_benchmarks.py +149 -0
  70. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_case.py +2 -2
  71. ltbams-0.9.12/tests/test_cli.py +34 -0
  72. ltbams-0.9.10/tests/test_andes.py → ltbams-0.9.12/tests/test_interop.py +8 -63
  73. ltbams-0.9.12/tests/test_io.py +32 -0
  74. ltbams-0.9.12/tests/test_jumper.py +27 -0
  75. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_known_good.py +4 -2
  76. ltbams-0.9.10/tests/test_mats.py → ltbams-0.9.12/tests/test_matp.py +4 -0
  77. ltbams-0.9.12/tests/test_omodel.py +119 -0
  78. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_routine.py +3 -85
  79. ltbams-0.9.12/tests/test_rtn_dcopf.py +77 -0
  80. ltbams-0.9.12/tests/test_rtn_ed.py +184 -0
  81. ltbams-0.9.12/tests/test_rtn_pflow.py +219 -0
  82. ltbams-0.9.12/tests/test_rtn_rted.py +176 -0
  83. ltbams-0.9.12/tests/test_rtn_uc.py +165 -0
  84. ltbams-0.9.10/ams/__init__.py +0 -20
  85. ltbams-0.9.10/ams/interop/__init__.py +0 -18
  86. ltbams-0.9.10/ams/opt/__init__.py +0 -5
  87. ltbams-0.9.10/ams/opt/omodel.py +0 -927
  88. ltbams-0.9.10/ams/routines/dcopf.py +0 -360
  89. ltbams-0.9.10/ams/utils/__init__.py +0 -13
  90. ltbams-0.9.10/requirements-extra.txt +0 -23
  91. ltbams-0.9.10/tests/test_cli.py +0 -13
  92. ltbams-0.9.10/tests/test_dctypes.py +0 -111
  93. {ltbams-0.9.10 → ltbams-0.9.12}/CONTRIBUTING.rst +0 -0
  94. {ltbams-0.9.10 → ltbams-0.9.12}/MANIFEST.in +0 -0
  95. {ltbams-0.9.10 → ltbams-0.9.12}/ams/__main__.py +0 -0
  96. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/5bus/pjm5bus_demo.xlsx +0 -0
  97. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/5bus/pjm5bus_uced.json +0 -0
  98. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/5bus/pjm5bus_uced.xlsx +0 -0
  99. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/5bus/pjm5bus_uced_ev.xlsx +0 -0
  100. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee123/ieee123.xlsx +0 -0
  101. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee123/ieee123_regcv1.xlsx +0 -0
  102. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee14/ieee14.json +0 -0
  103. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee14/ieee14.raw +0 -0
  104. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee14/ieee14_uced.xlsx +0 -0
  105. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee39/ieee39.xlsx +0 -0
  106. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee39/ieee39_uced.xlsx +0 -0
  107. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee39/ieee39_uced_esd1.xlsx +0 -0
  108. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee39/ieee39_uced_pvd1.xlsx +0 -0
  109. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/ieee39/ieee39_uced_vis.xlsx +0 -0
  110. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/matpower/benchmark.json +0 -0
  111. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/matpower/case118.m +0 -0
  112. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/matpower/case14.m +0 -0
  113. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/matpower/case300.m +0 -0
  114. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/matpower/case39.m +0 -0
  115. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/matpower/case5.m +0 -0
  116. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/matpower/case_ACTIVSg2000.m +0 -0
  117. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/npcc/npcc.m +0 -0
  118. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/npcc/npcc_uced.xlsx +0 -0
  119. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/pglib/pglib_opf_case39_epri__api.m +0 -0
  120. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/wecc/wecc.m +0 -0
  121. {ltbams-0.9.10 → ltbams-0.9.12}/ams/cases/wecc/wecc_uced.xlsx +0 -0
  122. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/__init__.py +0 -0
  123. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/model.py +0 -0
  124. {ltbams-0.9.10 → ltbams-0.9.12}/ams/core/var.py +0 -0
  125. {ltbams-0.9.10 → ltbams-0.9.12}/ams/extension/__init__.py +0 -0
  126. {ltbams-0.9.10 → ltbams-0.9.12}/ams/extension/eva.py +0 -0
  127. {ltbams-0.9.10 → ltbams-0.9.12}/ams/io/psse.py +0 -0
  128. {ltbams-0.9.10 → ltbams-0.9.12}/ams/io/pypower.py +0 -0
  129. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/area.py +0 -0
  130. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/bus.py +0 -0
  131. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/cost.py +0 -0
  132. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/distributed/__init__.py +0 -0
  133. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/distributed/esd1.py +0 -0
  134. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/distributed/ev.py +0 -0
  135. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/distributed/pvd1.py +0 -0
  136. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/info.py +0 -0
  137. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/region.py +0 -0
  138. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/renewable/__init__.py +0 -0
  139. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/renewable/regc.py +0 -0
  140. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/shunt.py +0 -0
  141. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/static/__init__.py +0 -0
  142. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/static/pq.py +0 -0
  143. {ltbams-0.9.10 → ltbams-0.9.12}/ams/models/timeslot.py +0 -0
  144. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/__init__.py +0 -0
  145. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/_compat.py +0 -0
  146. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/core/__init__.py +0 -0
  147. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/core/pips.py +0 -0
  148. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/core/ppoption.py +0 -0
  149. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/core/ppver.py +0 -0
  150. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/core/solver.py +0 -0
  151. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/eps.py +0 -0
  152. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/idx.py +0 -0
  153. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/io.py +0 -0
  154. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/make/__init__.py +0 -0
  155. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/make/matrices.py +0 -0
  156. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/make/pdv.py +0 -0
  157. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/routines/__init__.py +0 -0
  158. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/routines/cpf.py +0 -0
  159. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/routines/cpf_callbacks.py +0 -0
  160. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/routines/opffcns.py +0 -0
  161. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/routines/pflow.py +0 -0
  162. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/toggle.py +0 -0
  163. {ltbams-0.9.10 → ltbams-0.9.12}/ams/pypower/utils.py +0 -0
  164. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/cpf.py +0 -0
  165. {ltbams-0.9.10 → ltbams-0.9.12}/ams/routines/type.py +0 -0
  166. {ltbams-0.9.10 → ltbams-0.9.12}/ams/utils/paths.py +0 -0
  167. {ltbams-0.9.10 → ltbams-0.9.12}/docs/Makefile +0 -0
  168. {ltbams-0.9.10 → ltbams-0.9.12}/docs/make.bat +0 -0
  169. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/_templates/autosummary/base.rst +0 -0
  170. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/_templates/autosummary/class.rst +0 -0
  171. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/_templates/autosummary/module.rst +0 -0
  172. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/_templates/autosummary/module_toctree.rst +0 -0
  173. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/copyright.rst +0 -0
  174. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/formats/index.rst +0 -0
  175. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/formats/matpower.rst +0 -0
  176. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/formats/psse.rst +0 -0
  177. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/formats/pypower.rst +0 -0
  178. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/formats/xlsx.png +0 -0
  179. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/formats/xlsx.rst +0 -0
  180. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/index.rst +0 -0
  181. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/overview.rst +0 -0
  182. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/testcase.rst +0 -0
  183. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/getting_started/verification.rst +0 -0
  184. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/images/dcopf_time.png +0 -0
  185. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/images/sponsors/CURENT_Logo_NameOnTrans.png +0 -0
  186. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/images/sponsors/CURENT_Logo_Transparent.png +0 -0
  187. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/images/sponsors/CURENT_Logo_Transparent_Name.png +0 -0
  188. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/images/sponsors/doe.png +0 -0
  189. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/index.rst +0 -0
  190. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/modeling/index.rst +0 -0
  191. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/modeling/model.rst +0 -0
  192. {ltbams-0.9.10 → ltbams-0.9.12}/docs/source/modeling/system.rst +0 -0
  193. {ltbams-0.9.10 → ltbams-0.9.12}/ltbams.egg-info/dependency_links.txt +0 -0
  194. {ltbams-0.9.10 → ltbams-0.9.12}/ltbams.egg-info/entry_points.txt +0 -0
  195. {ltbams-0.9.10 → ltbams-0.9.12}/ltbams.egg-info/top_level.txt +0 -0
  196. {ltbams-0.9.10 → ltbams-0.9.12}/setup.cfg +0 -0
  197. {ltbams-0.9.10 → ltbams-0.9.12}/setup.py +0 -0
  198. {ltbams-0.9.10 → ltbams-0.9.12}/tests/__init__.py +0 -0
  199. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_addressing.py +1 -1
  200. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_export_csv.py +0 -0
  201. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_group.py +0 -0
  202. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_model.py +0 -0
  203. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_paths.py +0 -0
  204. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_report.py +0 -0
  205. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_repr.py +0 -0
  206. {ltbams-0.9.10 → ltbams-0.9.12}/tests/test_service.py +0 -0
  207. {ltbams-0.9.10 → ltbams-0.9.12}/versioneer.py +0 -0
@@ -670,7 +670,7 @@ Also add information on how to contact you by electronic and paper mail.
670
670
  If the program does terminal interaction, make it output a short
671
671
  notice like this when it starts in an interactive mode:
672
672
 
673
- AMS Copyright (C) 2023 Jinning Wang
673
+ AMS Copyright (C) 2023 - 2024 Jinning Wang
674
674
  This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
675
675
  This is free software, and you are welcome to redistribute it
676
676
  under certain conditions; type `show c' for details.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ltbams
3
- Version: 0.9.10
3
+ Version: 0.9.12
4
4
  Summary: Python software for scheduling modeling and co-simulation with dynanics.
5
5
  Home-page: https://github.com/CURENT/ams
6
6
  Author: Jinning Wang
@@ -14,21 +14,23 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (G
14
14
  Classifier: Environment :: Console
15
15
  Description-Content-Type: text/markdown
16
16
  Provides-Extra: all
17
- Provides-Extra: coverage
17
+ Provides-Extra: coverage
18
18
  Provides-Extra: dev
19
19
  Provides-Extra: doc
20
- Provides-Extra: flake8
21
- Provides-Extra: ipython
22
- Provides-Extra: myst-parser
23
- Provides-Extra: nbsphinx
24
- Provides-Extra: numpydoc
25
- Provides-Extra: pydata-sphinx-theme
26
- Provides-Extra: pyscipopt
27
- Provides-Extra: pytest
28
- Provides-Extra: pytest-cov
29
- Provides-Extra: sphinx
30
- Provides-Extra: sphinx-copybutton
31
- Provides-Extra: sphinx-panels
20
+ Provides-Extra: flake8
21
+ Provides-Extra: ipython
22
+ Provides-Extra: myst-parser
23
+ Provides-Extra: nbsphinx
24
+ Provides-Extra: numpydoc
25
+ Provides-Extra: pandoc
26
+ Provides-Extra: pydata-sphinx-theme
27
+ Provides-Extra: pyscipopt
28
+ Provides-Extra: pytest
29
+ Provides-Extra: pytest-cov
30
+ Provides-Extra: sphinx
31
+ Provides-Extra: sphinx-copybutton
32
+ Provides-Extra: sphinx-panels
33
+ Provides-Extra: toml
32
34
  License-File: LICENSE
33
35
 
34
36
  # LTB AMS
@@ -37,7 +39,7 @@ Python Software for Power System Scheduling Modeling and Co-Simulation with Dyna
37
39
 
38
40
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://github.com/CURENT/ams/blob/master/LICENSE)
39
41
  ![platforms](https://anaconda.org/conda-forge/ltbams/badges/platforms.svg)
40
- [![Python Versions](https://img.shields.io/badge/Python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)](https://www.python.org/)
42
+ [![Python Versions](https://img.shields.io/badge/Python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/)
41
43
  ![Repo Size](https://img.shields.io/github/repo-size/CURENT/ams)
42
44
  [![GitHub last commit (master)](https://img.shields.io/github/last-commit/CURENT/ams/master?label=last%20commit%20to%20master)](https://github.com/CURENT/ams/commits/master/)
43
45
  [![GitHub last commit (develop)](https://img.shields.io/github/last-commit/CURENT/ams/develop?label=last%20commit%20to%20develop)](https://github.com/CURENT/ams/commits/develop/)
@@ -61,7 +63,12 @@ Python Software for Power System Scheduling Modeling and Co-Simulation with Dyna
61
63
 
62
64
  # Why AMS
63
65
 
64
- With the built-in interface with dynamic simulation engine, ANDES, AMS enables Dynamics Interfaced Stability Constrained Production Cost and Market Operation Modeling.
66
+ With the built-in interface with ANDES, AMS enables **Dynamics Incorporated**
67
+ **Stability-Constrained Scheduling**.
68
+
69
+ AMS is a **Modeling Framework** that provides a descriptive way to formulate
70
+ scheduling problems. The optimization problems are then handled by **CVXPY**
71
+ and solved with third-party solvers.
65
72
 
66
73
  AMS produces credible scheduling results and competitive performance.
67
74
  The following results show the comparison of DCOPF between AMS and other tools.
@@ -92,7 +99,7 @@ Use the following resources to get involved.
92
99
  # Installation
93
100
 
94
101
  ***NOTE:***
95
- - Version **0.9.9** has known issues. Please avoid using this version
102
+ - Version **0.9.9** has known issues and has been yanked from PyPI
96
103
  - `kvxopt` is recommended to install via `conda` as sometimes ``pip`` struggles to set the correct path for compiled libraries
97
104
  - `cvxpy` versions **below 1.5** are incompatible with `numpy` versions **2.0 and above**
98
105
 
@@ -115,6 +122,19 @@ Install from GitHub source:
115
122
  pip install git+https://github.com/CURENT/ams.git
116
123
  ```
117
124
 
125
+ # Example Usage
126
+
127
+ Using AMS to run a Real-Time Economic Dispatch (RTED) simulation:
128
+
129
+ ```python
130
+ import ams
131
+
132
+ ss = ams.load(ams.get_case('ieee14_uced.xlsx'))
133
+ ss.RTED.run()
134
+
135
+ print(ss.RTED.pg.v)
136
+ ```
137
+
118
138
  # Sponsors and Contributors
119
139
  AMS is the scheduling simulation engine for the CURENT Largescale Testbed (LTB).
120
140
  More information about CURENT LTB can be found at the [LTB Repository][LTB Repository].
@@ -4,7 +4,7 @@ Python Software for Power System Scheduling Modeling and Co-Simulation with Dyna
4
4
 
5
5
  [![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://github.com/CURENT/ams/blob/master/LICENSE)
6
6
  ![platforms](https://anaconda.org/conda-forge/ltbams/badges/platforms.svg)
7
- [![Python Versions](https://img.shields.io/badge/Python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)](https://www.python.org/)
7
+ [![Python Versions](https://img.shields.io/badge/Python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/)
8
8
  ![Repo Size](https://img.shields.io/github/repo-size/CURENT/ams)
9
9
  [![GitHub last commit (master)](https://img.shields.io/github/last-commit/CURENT/ams/master?label=last%20commit%20to%20master)](https://github.com/CURENT/ams/commits/master/)
10
10
  [![GitHub last commit (develop)](https://img.shields.io/github/last-commit/CURENT/ams/develop?label=last%20commit%20to%20develop)](https://github.com/CURENT/ams/commits/develop/)
@@ -28,7 +28,12 @@ Python Software for Power System Scheduling Modeling and Co-Simulation with Dyna
28
28
 
29
29
  # Why AMS
30
30
 
31
- With the built-in interface with dynamic simulation engine, ANDES, AMS enables Dynamics Interfaced Stability Constrained Production Cost and Market Operation Modeling.
31
+ With the built-in interface with ANDES, AMS enables **Dynamics Incorporated**
32
+ **Stability-Constrained Scheduling**.
33
+
34
+ AMS is a **Modeling Framework** that provides a descriptive way to formulate
35
+ scheduling problems. The optimization problems are then handled by **CVXPY**
36
+ and solved with third-party solvers.
32
37
 
33
38
  AMS produces credible scheduling results and competitive performance.
34
39
  The following results show the comparison of DCOPF between AMS and other tools.
@@ -59,7 +64,7 @@ Use the following resources to get involved.
59
64
  # Installation
60
65
 
61
66
  ***NOTE:***
62
- - Version **0.9.9** has known issues. Please avoid using this version
67
+ - Version **0.9.9** has known issues and has been yanked from PyPI
63
68
  - `kvxopt` is recommended to install via `conda` as sometimes ``pip`` struggles to set the correct path for compiled libraries
64
69
  - `cvxpy` versions **below 1.5** are incompatible with `numpy` versions **2.0 and above**
65
70
 
@@ -82,6 +87,19 @@ Install from GitHub source:
82
87
  pip install git+https://github.com/CURENT/ams.git
83
88
  ```
84
89
 
90
+ # Example Usage
91
+
92
+ Using AMS to run a Real-Time Economic Dispatch (RTED) simulation:
93
+
94
+ ```python
95
+ import ams
96
+
97
+ ss = ams.load(ams.get_case('ieee14_uced.xlsx'))
98
+ ss.RTED.run()
99
+
100
+ print(ss.RTED.pg.v)
101
+ ```
102
+
85
103
  # Sponsors and Contributors
86
104
  AMS is the scheduling simulation engine for the CURENT Largescale Testbed (LTB).
87
105
  More information about CURENT LTB can be found at the [LTB Repository][LTB Repository].
@@ -0,0 +1,14 @@
1
+ from . import _version
2
+ __version__ = _version.get_versions()['version']
3
+
4
+ from ams import opt # NOQA
5
+ from ams import benchmarks # NOQA
6
+
7
+ from ams.main import config_logger, load, run # NOQA
8
+ from ams.system import System # NOQA
9
+ from ams.utils.paths import get_case, list_cases # NOQA
10
+ from ams.shared import ppc2df # NOQA
11
+
12
+ __author__ = 'Jining Wang'
13
+
14
+ __all__ = ['System', 'get_case']
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-09-03T22:41:38-0400",
11
+ "date": "2024-11-23T17:09:40-0500",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "8bc9504a8281c16236c73decd8e7365b682c706c",
15
- "version": "0.9.10"
14
+ "full-revisionid": "377b36f113e1e88f8c2d21d3c6ab8ff3728cffb0",
15
+ "version": "0.9.12"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -0,0 +1,302 @@
1
+ """
2
+ Benchmark functions.
3
+ """
4
+
5
+ import datetime
6
+ import sys
7
+ import importlib.metadata as importlib_metadata
8
+ import logging
9
+
10
+ try:
11
+ import pandapower as pdp
12
+ PANDAPOWER_AVAILABLE = True
13
+ except ImportError:
14
+ PANDAPOWER_AVAILABLE = False
15
+ logging.warning("pandapower is not available. Some functionalities will be disabled.")
16
+
17
+ from andes.utils.misc import elapsed
18
+
19
+ import ams
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+ _failed_time = -1
24
+ _failed_obj = -1
25
+
26
+ cols_pre = ['ams_mats', 'ams_parse', 'ams_eval', 'ams_final', 'ams_postinit']
27
+
28
+
29
+ def get_tool_versions(tools=None):
30
+ """
31
+ Get the current time, Python version, and versions of specified tools.
32
+
33
+ Parameters
34
+ ----------
35
+ tools : list of str, optional
36
+ List of tool names to check versions. If None, a default list of tools is used.
37
+
38
+ Returns
39
+ -------
40
+ dict
41
+ A dictionary containing the tool names and their versions.
42
+ """
43
+ if tools is None:
44
+ tools = ['ltbams', 'andes', 'cvxpy',
45
+ 'gurobipy', 'mosek', 'piqp',
46
+ 'pandapower', 'numba']
47
+
48
+ # Get current time and Python version
49
+ last_run_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
50
+ python_version = sys.version
51
+
52
+ # Collect tool versions
53
+ tool_versions = {}
54
+ for tool in tools:
55
+ try:
56
+ version = importlib_metadata.version(tool)
57
+ tool_versions[tool] = version
58
+ except importlib_metadata.PackageNotFoundError:
59
+ logger.error(f"Package {tool} not found.")
60
+ tool_versions[tool] = "Not installed"
61
+
62
+ # Print the results in a formatted way
63
+ logger.warning(f"Last run time: {last_run_time}")
64
+ logger.warning(f"Python: {python_version}\n")
65
+
66
+ # Calculate the width of the columns
67
+ max_tool_length = max(len(tool) for tool in tool_versions)
68
+ max_version_length = max(len(version) for version in tool_versions.values())
69
+
70
+ # Print the header
71
+ logger.warning(f"{'Tool':<{max_tool_length}} {'Version':<{max_version_length}}")
72
+ logger.warning(f"{'-' * max_tool_length} {'-' * max_version_length}")
73
+
74
+ # Print each tool and its version
75
+ for tool, version in tool_versions.items():
76
+ logger.warning(f"{tool:<{max_tool_length}} {version:<{max_version_length}}")
77
+
78
+ return tool_versions
79
+
80
+
81
+ def time_routine_solve(system, routine='DCOPF', **kwargs):
82
+ """
83
+ Run the specified routine with the given solver and method.
84
+
85
+ Parameters
86
+ ----------
87
+ system : ams.System
88
+ The system object containing the routine.
89
+ routine : str, optional
90
+ The name of the routine to run. Defaults to 'DCOPF'.
91
+
92
+ Other Parameters
93
+ ----------------
94
+ solver : str, optional
95
+ The solver to use.
96
+ ignore_dpp : bool, optional
97
+ Whether to ignore DPP. Defaults to True.
98
+
99
+ Returns
100
+ -------
101
+ tuple
102
+ A tuple containing the elapsed time (s) and the objective value ($).
103
+ """
104
+ rtn = system.routines[routine]
105
+ solver = kwargs.get('solver', None)
106
+ try:
107
+ t, _ = elapsed()
108
+ rtn.run(**kwargs)
109
+ _, s0 = elapsed(t)
110
+ elapsed_time = float(s0.split(' ')[0])
111
+ obj_value = rtn.obj.v
112
+ except Exception as e:
113
+ logger.error(f"Error running routine {routine} with solver {solver}: {e}")
114
+ elapsed_time = _failed_time
115
+ obj_value = _failed_obj
116
+ return elapsed_time, obj_value
117
+
118
+
119
+ def pre_solve(system, routine):
120
+ """
121
+ Time the routine preparation process.
122
+
123
+ Parameters
124
+ ----------
125
+ system : ams.System
126
+ The system object containing the routine.
127
+ routine : str
128
+ The name of the routine to prepare
129
+
130
+ Returns
131
+ -------
132
+ dict
133
+ A dictionary containing the preparation times in seconds for each step:
134
+ 'mats', 'parse', 'evaluate', 'finalize', 'postinit'.
135
+ """
136
+ rtn = system.routines[routine]
137
+
138
+ # Initialize AMS
139
+ # --- matrices build ---
140
+ t_mats, _ = elapsed()
141
+ system.mats.build(force=True)
142
+ _, s_mats = elapsed(t_mats)
143
+
144
+ # --- code generation ---
145
+ t_parse, _ = elapsed()
146
+ rtn.om.parse(force=True)
147
+ _, s_parse = elapsed(t_parse)
148
+
149
+ # --- code evaluation ---
150
+ t_evaluate, _ = elapsed()
151
+ rtn.om.evaluate(force=True)
152
+ _, s_evaluate = elapsed(t_evaluate)
153
+
154
+ # --- problem finalization ---
155
+ t_finalize, _ = elapsed()
156
+ rtn.om.finalize(force=True)
157
+ _, s_finalize = elapsed(t_finalize)
158
+
159
+ # --- rest init process ---
160
+ t_postinit, _ = elapsed()
161
+ rtn.init()
162
+ _, s_postinit = elapsed(t_postinit)
163
+
164
+ s_float = [float(s.split(' ')[0]) for s in [s_mats, s_parse, s_evaluate, s_finalize, s_postinit]]
165
+
166
+ pre_time = dict(zip(cols_pre, s_float))
167
+ return pre_time
168
+
169
+
170
+ def time_pdp_dcopf(ppn):
171
+ """
172
+ Test the execution time of DCOPF using pandapower.
173
+
174
+ Parameters
175
+ ----------
176
+ ppn : pandapowerNet
177
+ The pandapower network object.
178
+
179
+ Returns
180
+ -------
181
+ tuple
182
+ A tuple containing the elapsed time (s) and the objective value ($).
183
+ """
184
+ try:
185
+ t_pdp, _ = elapsed()
186
+ pdp.rundcopp(ppn)
187
+ _, s_pdp = elapsed(t_pdp)
188
+ elapsed_time = float(s_pdp.split(' ')[0])
189
+ obj_value = ppn.res_cost
190
+ except Exception as e:
191
+ logger.error(f"Error running pandapower: {e}")
192
+ elapsed_time = _failed_time
193
+ obj_value = _failed_obj
194
+ return elapsed_time, obj_value
195
+
196
+
197
+ def time_routine(system, routine='DCOPF', solvers=['CLARABEL'],
198
+ **kwargs):
199
+ """
200
+ Time the specified routine with the given solvers.
201
+
202
+ Parameters
203
+ ----------
204
+ system : ams.System
205
+ The system object containing the routine.
206
+ routine : str, optional
207
+ The name of the routine to run. Defaults to 'DCOPF'.
208
+ solvers : list of str, optional
209
+ List of solvers to use. Defaults to ['CLARABEL'].
210
+
211
+ Other Parameters
212
+ ----------------
213
+ ignore_dpp : bool, optional
214
+ Whether to ignore DPP. Defaults to True.
215
+
216
+ Returns
217
+ -------
218
+ tuple
219
+ A tuple containing the preparation times and the solution times in
220
+ seconds for each solver.
221
+ """
222
+ pre_time = pre_solve(system, routine)
223
+ sol = {f'{solver}': {'time': 0, 'obj': 0} for solver in solvers}
224
+
225
+ for solver in solvers:
226
+ if solver != 'pandapower':
227
+ s, obj = time_routine_solve(system, routine, solver=solver, **kwargs)
228
+ sol[solver]['time'] = s
229
+ sol[solver]['obj'] = obj
230
+ elif solver == 'pandapower' and PANDAPOWER_AVAILABLE and routine == 'DCOPF':
231
+ ppc = ams.io.pypower.system2ppc(system)
232
+ ppn = pdp.converter.from_ppc(ppc, f_hz=system.config.freq)
233
+ s, obj = time_pdp_dcopf(ppn)
234
+ sol[solver]['time'] = s
235
+ sol[solver]['obj'] = obj
236
+ else:
237
+ sol[solver]['time'] = _failed_time
238
+ sol[solver]['obj'] = _failed_obj
239
+
240
+ return pre_time, sol
241
+
242
+
243
+ def time_dcopf_with_lf(system, solvers=['CLARABEL'], load_factors=[1], ignore_dpp=False):
244
+ """
245
+ Time the execution of DCOPF with varying load factors.
246
+
247
+ Parameters
248
+ ----------
249
+ system : ams.System
250
+ The system object containing the routine.
251
+ solvers : list of str, optional
252
+ List of solvers to use. Defaults to ['CLARABEL'].
253
+ load_factors : list of float, optional
254
+ List of load factors to apply. Defaults to None.
255
+ ignore_dpp : bool, optional
256
+ Whether to ignore DPP.
257
+
258
+ Returns
259
+ -------
260
+ tuple
261
+ A tuple containing the list of times and the list of objective values.
262
+ """
263
+ pre_time = pre_solve(system, 'DCOPF')
264
+ sol = {f'{solver}': {'time': 0, 'obj': 0} for solver in solvers}
265
+
266
+ pd0 = system.PQ.p0.v.copy()
267
+ pq_idx = system.PQ.idx.v
268
+
269
+ for solver in solvers:
270
+ if solver != 'pandapower':
271
+ obj_all = 0
272
+ t_all, _ = elapsed()
273
+ for lf_k in load_factors:
274
+ system.PQ.set(src='p0', attr='v', idx=pq_idx, value=lf_k * pd0)
275
+ system.DCOPF.update(params=['pd'])
276
+ _, obj = time_routine_solve(system, 'DCOPF',
277
+ solver=solver, ignore_dpp=ignore_dpp)
278
+ obj_all += obj
279
+ _, s_all = elapsed(t_all)
280
+ system.PQ.set(src='p0', attr='v', idx=pq_idx, value=pd0)
281
+ s = float(s_all.split(' ')[0])
282
+ sol[solver]['time'] = s
283
+ sol[solver]['obj'] = obj_all
284
+ elif solver == 'pandapower' and PANDAPOWER_AVAILABLE:
285
+ ppc = ams.io.pypower.system2ppc(system)
286
+ ppn = pdp.converter.from_ppc(ppc, f_hz=system.config.freq)
287
+ p_mw0 = ppn.load['p_mw'].copy()
288
+ t_all, _ = elapsed()
289
+ obj_all = 0
290
+ for lf_k in load_factors:
291
+ ppn.load['p_mw'] = lf_k * p_mw0
292
+ _, obj = time_pdp_dcopf(ppn)
293
+ obj_all += obj
294
+ _, s_all = elapsed(t_all)
295
+ s = float(s_all.split(' ')[0])
296
+ sol[solver]['time'] = s
297
+ sol[solver]['obj'] = obj_all
298
+ else:
299
+ sol[solver]['time'] = _failed_time
300
+ sol[solver]['obj'] = _failed_obj
301
+
302
+ return pre_time, sol
@@ -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()
@@ -223,9 +223,10 @@ class RDocumenter:
223
223
  # add tables
224
224
  self.parent.syms.generate_symbols()
225
225
  out += self._obj_doc(max_width=max_width, export=export)
226
- out += self._constr_doc(max_width=max_width, export=export)
227
226
  out += self._expr_doc(max_width=max_width, export=export)
227
+ out += self._constr_doc(max_width=max_width, export=export)
228
228
  out += self._var_doc(max_width=max_width, export=export)
229
+ out += self._exprc_doc(max_width=max_width, export=export)
229
230
  out += self._service_doc(max_width=max_width, export=export)
230
231
  out += self._param_doc(max_width=max_width, export=export)
231
232
  out += self.config.doc(max_width=max_width, export=export)
@@ -316,17 +317,26 @@ class RDocumenter:
316
317
  rest_dict=rest_dict)
317
318
 
318
319
  def _expr_doc(self, max_width=78, export='plain'):
319
- # expression documentation
320
+ # Expression documentation
320
321
  if len(self.parent.exprs) == 0:
321
322
  return ''
322
323
 
323
324
  # prepare temporary lists
324
- names, var_names, info = list(), list(), list()
325
+ names, info = list(), list()
326
+ units, sources, units_rest = list(), list(), list()
325
327
 
326
328
  for p in self.parent.exprs.values():
327
329
  names.append(p.name)
328
- var_names.append(p.var)
329
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))
330
340
 
331
341
  # expressions based on output format
332
342
  expressions = []
@@ -342,13 +352,67 @@ class RDocumenter:
342
352
  expressions = math_wrap(expressions, export=export)
343
353
 
344
354
  plain_dict = OrderedDict([('Name', names),
345
- ('Variable', var_names),
346
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),
347
410
  ])
348
411
  rest_dict = OrderedDict([('Name', names),
349
- ('Variable', var_names),
350
412
  ('Description', info),
351
413
  ('Expression', expressions),
414
+ ('Unit', units_rest),
415
+ ('Source', sources),
352
416
  ])
353
417
 
354
418
  # convert to rows and export as table
@@ -423,6 +487,8 @@ class RDocumenter:
423
487
  slist = []
424
488
  if p.owner is not None and p.src is not None:
425
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}')
426
492
  sources.append(','.join(slist))
427
493
 
428
494
  # symbols based on output format
@@ -490,6 +556,8 @@ class RDocumenter:
490
556
  slist = []
491
557
  if p.owner is not None and p.src is not None:
492
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}')
493
561
  sources.append(','.join(slist))
494
562
 
495
563
  # symbols based on output format