optiwindnet 0.2.1__tar.gz → 0.2.2__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 (228) hide show
  1. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/CHANGELOG.md +36 -0
  2. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/PKG-INFO +6 -2
  3. optiwindnet-0.2.2/_run_chain_tests.py +137 -0
  4. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/__init__.py +6 -4
  5. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/_core.py +5 -4
  6. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/_core.pyi +1 -2
  7. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/cplex.py +1 -1
  8. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/fscip.py +3 -2
  9. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/gurobi.py +2 -1
  10. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/ortools.py +2 -1
  11. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/pyomo.py +5 -3
  12. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/MILP/scip.py +2 -1
  13. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/__init__.py +2 -1
  14. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/api.py +121 -29
  15. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/api_utils.py +34 -24
  16. optiwindnet-0.2.2/optiwindnet/baselines/_core.py +43 -0
  17. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/baselines/hgs.py +23 -42
  18. optiwindnet-0.2.2/optiwindnet/baselines/lkh.py +986 -0
  19. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/clustering.py +1 -2
  20. optiwindnet-0.2.2/optiwindnet/crossings.py +861 -0
  21. optiwindnet-0.2.2/optiwindnet/data/Amrumbank West.osm.pbf +0 -0
  22. optiwindnet-0.2.2/optiwindnet/data/Baltic 2.osm.pbf +0 -0
  23. optiwindnet-0.2.2/optiwindnet/data/Belwind.osm.pbf +0 -0
  24. optiwindnet-0.2.2/optiwindnet/data/Fecamp.osm.pbf +0 -0
  25. optiwindnet-0.2.2/optiwindnet/data/Gemini 1.osm.pbf +0 -0
  26. optiwindnet-0.2.2/optiwindnet/data/Gemini 2.osm.pbf +0 -0
  27. optiwindnet-0.2.2/optiwindnet/data/He Dreiht.osm.pbf +0 -0
  28. optiwindnet-0.2.2/optiwindnet/data/Hollandse Kust Zuid.osm.pbf +0 -0
  29. optiwindnet-0.2.2/optiwindnet/data/Humber Gateway.osm.pbf +0 -0
  30. optiwindnet-0.2.2/optiwindnet/data/Kaskasi.osm.pbf +0 -0
  31. optiwindnet-0.2.2/optiwindnet/data/Lillgrund.osm.pbf +0 -0
  32. optiwindnet-0.2.2/optiwindnet/data/Lincs.osm.pbf +0 -0
  33. optiwindnet-0.2.2/optiwindnet/data/Luchterduinen.osm.pbf +0 -0
  34. optiwindnet-0.2.2/optiwindnet/data/Mermaid.osm.pbf +0 -0
  35. optiwindnet-0.2.2/optiwindnet/data/Neart na Gaoithe.osm.pbf +0 -0
  36. optiwindnet-0.2.2/optiwindnet/data/Nordsee One.osm.pbf +0 -0
  37. optiwindnet-0.2.2/optiwindnet/data/Nordsee Ost.osm.pbf +0 -0
  38. optiwindnet-0.2.2/optiwindnet/data/Norther.osm.pbf +0 -0
  39. optiwindnet-0.2.2/optiwindnet/data/Northwind.osm.pbf +0 -0
  40. optiwindnet-0.2.2/optiwindnet/data/Nysted.osm.pbf +0 -0
  41. optiwindnet-0.2.2/optiwindnet/data/Rentel.osm.pbf +0 -0
  42. optiwindnet-0.2.2/optiwindnet/data/Sandbank.osm.pbf +0 -0
  43. optiwindnet-0.2.2/optiwindnet/data/Seagreen.osm.pbf +0 -0
  44. optiwindnet-0.2.2/optiwindnet/data/Veja Mate.osm.pbf +0 -0
  45. optiwindnet-0.2.2/optiwindnet/data/Westermost Rough.osm.pbf +0 -0
  46. optiwindnet-0.2.2/optiwindnet/data/Zhejiang Jiaxing 1.osm.pbf +0 -0
  47. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/db/migrate.py +3 -2
  48. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/db/model.py +1 -0
  49. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/geometric.py +170 -108
  50. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/heuristics/ClassicEsauWilliams.py +8 -3
  51. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/heuristics/CrossingPreventingEW.py +9 -5
  52. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/heuristics/EW_presolver.py +7 -4
  53. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/heuristics/NonBranchingEW.py +9 -4
  54. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/heuristics/ObstacleBypassingEW.py +13 -5
  55. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/heuristics/__init__.py +1 -0
  56. optiwindnet-0.2.2/optiwindnet/heuristics/_deprecation.py +49 -0
  57. optiwindnet-0.2.2/optiwindnet/heuristics/constructor.py +798 -0
  58. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/heuristics/priorityqueue.py +6 -6
  59. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/importer.py +7 -4
  60. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/interarraylib.py +153 -25
  61. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/interface.py +21 -0
  62. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/mesh.py +54 -56
  63. optiwindnet-0.2.2/optiwindnet/pathfinding.py +2165 -0
  64. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/plotting.py +9 -7
  65. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/repair.py +1 -0
  66. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/svg.py +308 -36
  67. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/themes.py +2 -0
  68. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/version.py +3 -3
  69. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet.egg-info/PKG-INFO +6 -2
  70. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet.egg-info/SOURCES.txt +5 -0
  71. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet.egg-info/requires.txt +1 -1
  72. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/pyproject.toml +13 -1
  73. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/conftest.py +5 -3
  74. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/helpers.py +15 -9
  75. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/solutions.pkl +0 -0
  76. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_MILP.py +6 -6
  77. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_api_WindFarmNetwork.py +9 -6
  78. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_augmentation.py +5 -3
  79. optiwindnet-0.2.2/tests/test_constructor.py +271 -0
  80. optiwindnet-0.2.2/tests/test_crossings.py +283 -0
  81. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_db.py +11 -9
  82. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_end_to_end.py +6 -3
  83. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_geometric.py +3 -31
  84. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_importer.py +0 -1
  85. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_interarraylib.py +36 -5
  86. optiwindnet-0.2.2/tests/test_lkh.py +340 -0
  87. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_mesh.py +7 -5
  88. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_pathfinding.py +50 -15
  89. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_repair.py +4 -3
  90. optiwindnet-0.2.2/tests/test_svg.py +212 -0
  91. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_themes.py +0 -1
  92. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/test_utils.py +1 -2
  93. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/update_expected_values.py +7 -5
  94. optiwindnet-0.2.1/optiwindnet/baselines/lkh.py +0 -514
  95. optiwindnet-0.2.1/optiwindnet/crossings.py +0 -370
  96. optiwindnet-0.2.1/optiwindnet/data/Amrumbank West.osm.pbf +0 -0
  97. optiwindnet-0.2.1/optiwindnet/data/Baltic 2.osm.pbf +0 -0
  98. optiwindnet-0.2.1/optiwindnet/data/Belwind.osm.pbf +0 -0
  99. optiwindnet-0.2.1/optiwindnet/data/Fecamp.osm.pbf +0 -0
  100. optiwindnet-0.2.1/optiwindnet/data/Gemini 1.osm.pbf +0 -0
  101. optiwindnet-0.2.1/optiwindnet/data/Gemini 2.osm.pbf +0 -0
  102. optiwindnet-0.2.1/optiwindnet/data/He Dreiht.osm.pbf +0 -0
  103. optiwindnet-0.2.1/optiwindnet/data/Hollandse Kust Zuid.osm.pbf +0 -0
  104. optiwindnet-0.2.1/optiwindnet/data/Humber Gateway.osm.pbf +0 -0
  105. optiwindnet-0.2.1/optiwindnet/data/Kaskasi.osm.pbf +0 -0
  106. optiwindnet-0.2.1/optiwindnet/data/Lillgrund.osm.pbf +0 -0
  107. optiwindnet-0.2.1/optiwindnet/data/Lincs.osm.pbf +0 -0
  108. optiwindnet-0.2.1/optiwindnet/data/Luchterduinen.osm.pbf +0 -0
  109. optiwindnet-0.2.1/optiwindnet/data/Mermaid.osm.pbf +0 -0
  110. optiwindnet-0.2.1/optiwindnet/data/Neart na Gaoithe.osm.pbf +0 -0
  111. optiwindnet-0.2.1/optiwindnet/data/Nordsee One.osm.pbf +0 -0
  112. optiwindnet-0.2.1/optiwindnet/data/Nordsee Ost.osm.pbf +0 -0
  113. optiwindnet-0.2.1/optiwindnet/data/Norther.osm.pbf +0 -0
  114. optiwindnet-0.2.1/optiwindnet/data/Northwind.osm.pbf +0 -0
  115. optiwindnet-0.2.1/optiwindnet/data/Nysted.osm.pbf +0 -0
  116. optiwindnet-0.2.1/optiwindnet/data/Rentel.osm.pbf +0 -0
  117. optiwindnet-0.2.1/optiwindnet/data/Sandbank.osm.pbf +0 -0
  118. optiwindnet-0.2.1/optiwindnet/data/Seagreen.osm.pbf +0 -0
  119. optiwindnet-0.2.1/optiwindnet/data/Veja Mate.osm.pbf +0 -0
  120. optiwindnet-0.2.1/optiwindnet/data/Westermost Rough.osm.pbf +0 -0
  121. optiwindnet-0.2.1/optiwindnet/data/Zhejiang Jiaxing 1.osm.pbf +0 -0
  122. optiwindnet-0.2.1/optiwindnet/pathfinding.py +0 -997
  123. optiwindnet-0.2.1/tests/test_crossings.py +0 -69
  124. optiwindnet-0.2.1/tests/test_lkh.py +0 -296
  125. optiwindnet-0.2.1/tests/test_svg.py +0 -14
  126. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/.github/workflows/release.yml +0 -0
  127. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/.zenodo.json +0 -0
  128. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/CITATION.cff +0 -0
  129. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/LICENSE.txt +0 -0
  130. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/README.md +0 -0
  131. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/augmentation.py +3 -3
  132. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/baselines/__init__.py +0 -0
  133. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/baselines/utils.py +0 -0
  134. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Albatros.osm.pbf +0 -0
  135. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Anholt.yaml +0 -0
  136. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Arkona.osm.pbf +0 -0
  137. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/BARD Offshore 1.osm.pbf +0 -0
  138. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Baltic Eagle.osm.pbf +0 -0
  139. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Beatrice.osm.pbf +0 -0
  140. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Borkum Riffgrund 1.yaml +0 -0
  141. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Borkum Riffgrund 2.yaml +0 -0
  142. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Borkum Riffgrund 3.osm.pbf +0 -0
  143. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Borssele.yaml +0 -0
  144. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Butendiek.yaml +0 -0
  145. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/CECEP Yangjiang Nanpeng Island.osm.pbf +0 -0
  146. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/CGN Rudong Demonstration.osm.pbf +0 -0
  147. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Cazzaro-2022.yaml +0 -0
  148. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Cazzaro-2022G-140.yaml +0 -0
  149. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Cazzaro-2022G-210.yaml +0 -0
  150. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Coastal Virginia.osm.pbf +0 -0
  151. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/DanTysk.yaml +0 -0
  152. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Deutsche Bucht.osm.pbf +0 -0
  153. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Dogger Bank A.yaml +0 -0
  154. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Dogger Bank B.osm.pbf +0 -0
  155. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Dogger Bank C.osm.pbf +0 -0
  156. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Dudgeon.yaml +0 -0
  157. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/East Anglia ONE.yaml +0 -0
  158. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Galloper Inner.osm.pbf +0 -0
  159. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Global Tech 1.osm.pbf +0 -0
  160. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Gode Wind 1.yaml +0 -0
  161. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Greater Changhua 1.osm.pbf +0 -0
  162. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Greater Gabbard Inner.yaml +0 -0
  163. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Gwynt y Mor.yaml +0 -0
  164. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Hohe See.osm.pbf +0 -0
  165. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Horns Rev 1.yaml +0 -0
  166. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Horns Rev 2.yaml +0 -0
  167. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Horns Rev 3.yaml +0 -0
  168. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Hornsea One.yaml +0 -0
  169. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Hornsea Two West.yaml +0 -0
  170. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Huizhou Gangkou 1.osm.pbf +0 -0
  171. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Huizhou Gangkou 2.osm.pbf +0 -0
  172. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Inch Cape.osm.pbf +0 -0
  173. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Kriegers Flak A.osm.pbf +0 -0
  174. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Kriegers Flak B.osm.pbf +0 -0
  175. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Laoting Bodhi Island.osm.pbf +0 -0
  176. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/London Array.yaml +0 -0
  177. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Meerwind.osm.pbf +0 -0
  178. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Merkur.osm.pbf +0 -0
  179. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Moray East.yaml +0 -0
  180. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Moray West.yaml +0 -0
  181. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Noirmoutier.osm.pbf +0 -0
  182. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Ormonde.yaml +0 -0
  183. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Princess Amalia.osm.pbf +0 -0
  184. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Race Bank.yaml +0 -0
  185. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Rampion.yaml +0 -0
  186. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Riffgat.osm.pbf +0 -0
  187. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Robin Rigg.osm.pbf +0 -0
  188. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Rudong H10.osm.pbf +0 -0
  189. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Rudong H6.osm.pbf +0 -0
  190. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Rudong H8.osm.pbf +0 -0
  191. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/R/303/270dsand 2.yaml +0 -0
  192. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/SPIC Binhai North H2.osm.pbf +0 -0
  193. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Saint-Brieuc.osm.pbf +0 -0
  194. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Saint-Nazaire.osm.pbf +0 -0
  195. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Shengsi 2.osm.pbf +0 -0
  196. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Sheringham Shoal.osm.pbf +0 -0
  197. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Sofia.yaml +0 -0
  198. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Taylor-2023.yaml +0 -0
  199. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Thanet.yaml +0 -0
  200. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Thor.osm.pbf +0 -0
  201. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Trianel Windpark Borkum.osm.pbf +0 -0
  202. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Triton Knoll.yaml +0 -0
  203. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Tr/303/251port.osm.pbf +0 -0
  204. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Vineyard Wind 1.osm.pbf +0 -0
  205. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Walney 1.yaml +0 -0
  206. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Walney 2.yaml +0 -0
  207. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Walney Extension.yaml +0 -0
  208. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/West of Duddon Sands.yaml +0 -0
  209. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Wikinger.osm.pbf +0 -0
  210. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Yi-2019.yaml +0 -0
  211. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/data/Yunlin.osm.pbf +0 -0
  212. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/db/__init__.py +0 -0
  213. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/db/_core.py +0 -0
  214. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/db/model.pyi +0 -0
  215. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/db/storage.py +2 -2
  216. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/py.typed +0 -0
  217. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/synthetic.py +0 -0
  218. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/utils.py +0 -0
  219. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet/weighting.py +0 -0
  220. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet.egg-info/dependency_links.txt +0 -0
  221. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/optiwindnet.egg-info/top_level.txt +0 -0
  222. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/setup.cfg +0 -0
  223. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/sitecustomize.py +0 -0
  224. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/__init__.py +0 -0
  225. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/locations/example_1ss_300wt.osm.pbf +0 -0
  226. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/locations/example_4ss_300wt.osm.pbf +0 -0
  227. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/locations/example_location.yaml +0 -0
  228. {optiwindnet-0.2.1 → optiwindnet-0.2.2}/tests/paths.py +0 -0
@@ -1,3 +1,39 @@
1
+ # v0.2.2
2
+
3
+ [Commit history since v0.2.1](https://gitlab.windenergy.dtu.dk/TOPFARM/OptiWindNet/-/compare/v0.2.1...v0.2.2)
4
+
5
+ ## Breaking Changes
6
+ - **Advanced API Cleanups**: Helper functions for root-assignment and link-blockage moved from `optiwindnet.geometric` to `optiwindnet.interarraylib`. Users should import `add_terminal_closest_root()`, `add_link_blockmap()`, and `add_link_cosines()` from `optiwindnet.interarraylib`.
7
+
8
+ ## Important Changes
9
+ - **Default Vector SVG Plotting**: High-level `WindFarmNetwork` plotting methods (`plot()`, `plot_location()`, `plot_available_links()`, `plot_navigation_mesh()`, and `plot_selected_links()`) now use a modern, interactive vector SVG plotting backend (`svgplot`/`svgpplot`) by default. This delivers clean, high-resolution inline displays in Jupyter notebooks. The legacy Matplotlib-based backend remains fully accessible by passing an explicit `ax` argument (including `ax=None` to dynamically instantiate Matplotlib figures).
10
+ - **svgplot() matches gplot()'s features**: SVG plots now support node labeling, boundary/obstacle vertex tagging, and figure legend.
11
+ - **Informative String Representations**: Added descriptive, debugger-safe string representations (`__repr__`) for `WindFarmNetwork` and `Router` subclasses (`EWRouter`, `HGSRouter`, `MILPRouter`) displaying key configuration parameters and solved network metrics.
12
+ - **Shorter Substation Labels**: Pre-packaged offshore wind farm datasets (.osm.pbf format) have been updated with short, human-readable substation abbreviations (such as "Alpha", "Beta", "OSS") to fit cleanly in visualization labels.
13
+ - **New Fused Heuristic**: Added `heuristics.constructor()` with `esau_williams`, `biased_EW`, `rootlust`, and `radial_EW` methods, unifying the constructive routing heuristics. The high-level `EWRouter` now uses this path, offering radial topology and the performant rootlust method.
14
+ - **LKH-3 Solver Parity**: Added `lkh3()` as the preferred LKH entry point, bringing it to feature parity with the HGS solver. It supports single- and multi-root configurations, per-root clustering, warm starts, capacity-violation retries, crossing repair, and improved solver metadata.
15
+ - **Expanded Crossing Diagnostics**: Added Shapely-based `find_geometric_crossings()` for geometry-first validation of arbitrary routesets, including detours, contour clones, shared-run overlap crossings, and branch-split cases.
16
+ - **Robust PathFinder Detours**: Major robustness improvements when routing detours among cable routes that follow boundaries or exclusion zones, significantly reducing cable use on sites with many obstacles.
17
+
18
+ ## Deprecated
19
+ - Standalone EW heuristics (`ClassicEW`, `CPEW`, `NBEW`, `OBEW`, and `EW_presolver`) are deprecated and will be removed in v0.3. They are superseded by the new unified `heuristics.constructor()`. Note that `constructor` expects the available-links graph `A`, not the location graph `L`.
20
+ - The legacy `optiwindnet.interface` module (`heuristic_wrapper()`, `HeuristicFactory`) is deprecated and will be removed in v0.3; use `WindFarmNetwork`/`EWRouter` instead.
21
+
22
+ ## Fixes
23
+ - **Pathfinder Robustness**: Resolved fatal crashes (`KeyError` and triangulation flip failures) when constructing detours.
24
+ - **Diagonal Mesh Exclusion**: Prevented invalid diagonal paths by skipping edges in the site's boundary polygon during navigation mesh generation.
25
+ - **Logging & Diagnostics**: Replaced all remaining raw `print()` statements across the API and utility modules with standard Python logging.
26
+ - **LKH and Heuristic Repairs**: Fixed LKH warm-start tour construction (indexing, walk order within clusters) and aligned HGS/LKH repair behavior for capacity-violating and crossing routes.
27
+ - **Overflow Prevention**: Added checks for LKH weight-matrix construction with clear guidance when inputs need normalization.
28
+ - **Crossing Detection**: Fixed shared-route overlap crossing detection and added geometric handling for route intersections not expressible as available-edge crossings.
29
+
30
+ ## Refactoring & Maintenance
31
+ - **Python 3.11–3.14 Support**: Explicitly declared support for Python 3.11 through 3.14 with standard Trove classifiers on PyPI.
32
+ - **Updated OR-Tools Floor**: Aligned OR-Tools requirements in `pyproject.toml` to `>=9.14.6206` for consistency across development and production environments.
33
+ - **Strict Deprecation Testing**: Test suite configured to treat `DeprecationWarning` as errors to guarantee API health.
34
+ - **Linting & Code Quality**: Enforced strict Ruff linting and formatting rules via continuous integration.
35
+ - **Performance Optimizations**: Optimized pathfinding sector lookups and precomputed chain-end topologies to speed up execution.
36
+
1
37
  # v0.2.1
2
38
 
3
39
  [Commit history since v0.2.0](https://gitlab.windenergy.dtu.dk/TOPFARM/OptiWindNet/-/compare/v0.2.0...v0.2.1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: optiwindnet
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Tool for designing and optimizing the electrical cable network of offshore wind farms
5
5
  Author-email: DTU Wind Energy <mikf@dtu.dk>, Mauricio Souza de Alencar <ma___@dtu.dk>, Amir Arasteh <am___@dtu.dk>
6
6
  License-Expression: MIT
@@ -15,6 +15,10 @@ Classifier: Development Status :: 4 - Beta
15
15
  Classifier: Intended Audience :: Developers
16
16
  Classifier: Intended Audience :: Science/Research
17
17
  Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
18
22
  Classifier: Operating System :: OS Independent
19
23
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
24
  Classifier: Topic :: Scientific/Engineering
@@ -32,7 +36,7 @@ Requires-Dist: matplotlib>=3.10.1
32
36
  Requires-Dist: networkx>=3.6
33
37
  Requires-Dist: numba>=0.62.1
34
38
  Requires-Dist: numpy>=2.0
35
- Requires-Dist: ortools>=9.12.4544
39
+ Requires-Dist: ortools>=9.14.6206
36
40
  Requires-Dist: peewee>=3.17
37
41
  Requires-Dist: Pyomo>=6.9.5
38
42
  Requires-Dist: PyYAML>=6.0.2
@@ -0,0 +1,137 @@
1
+ """Validation driver for the chain-sleeve pathfinding feature.
2
+
3
+ Loads pickled G_db routesets for four RIDs and re-runs PathFinder, checking
4
+ that the expected feeder paths and total length are produced.
5
+
6
+ Usage:
7
+ python _run_chain_tests.py
8
+ """
9
+
10
+ import math
11
+ import pickle
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ from optiwindnet.interarraylib import G_from_S, L_from_G, S_from_G
16
+ from optiwindnet.mesh import make_planar_embedding
17
+ from optiwindnet.pathfinding import PathFinder
18
+
19
+ EXPECTED = {
20
+ 22822: {
21
+ 'length': 9.4484,
22
+ 'feeders': [[-1, 46, 70, 35], [-1, 46, 70, 26]],
23
+ },
24
+ 33303: {
25
+ 'length': 9.5741,
26
+ 'feeders': [[-1, 46, 70, 35], [-1, 46, 70, 26]],
27
+ },
28
+ 33372: {
29
+ 'length': 11.1059,
30
+ 'feeders': [[-1, 40, 57, 44], [-1, 40, 57, 58, 59, 5]],
31
+ },
32
+ 35875: {
33
+ 'length': None,
34
+ 'feeders': [[-1, 60, 75, 76, 77, 8]],
35
+ },
36
+ }
37
+
38
+
39
+ def _feeder_paths(G):
40
+ """Extract every -1->...->terminal path through the routeset, mapped to primes."""
41
+ R = G.graph['R']
42
+ T = G.graph['T']
43
+ fnT = G.graph.get('fnT')
44
+
45
+ def prime(n):
46
+ if n < 0:
47
+ return n
48
+ if fnT is not None and n < len(fnT):
49
+ return int(fnT[n])
50
+ return n
51
+
52
+ feeders = []
53
+ # walk every root->...->terminal path through detour clones and contour
54
+ # helpers; emit one feeder per terminal-anchored path that starts at root
55
+ for r in range(-R, 0):
56
+ for first in G.neighbors(r):
57
+ # DFS to find paths root → ... → terminal (prime in [0, T))
58
+ stack = [(first, [r, first], {r, first})]
59
+ while stack:
60
+ cur, path, visited = stack.pop()
61
+ # Terminate on actual terminal node (not a clone whose prime is
62
+ # a terminal — those happen along contour helpers).
63
+ if 0 <= cur < T:
64
+ feeders.append([prime(x) for x in path])
65
+ continue
66
+ for nxt in G.neighbors(cur):
67
+ if nxt in visited:
68
+ continue
69
+ stack.append((nxt, path + [nxt], visited | {nxt}))
70
+ return feeders
71
+
72
+
73
+ def _run_one(rid):
74
+ p = Path(__file__).parent / 'tests' / 'locations' / f'G_{rid}.pkl'
75
+ with open(p, 'rb') as f:
76
+ G_db = pickle.load(f)
77
+
78
+ # reconstruct site → planar+A → topology → tentative → PathFinder
79
+ L = L_from_G(G_db)
80
+ L.graph['border'] = G_db.graph['border']
81
+ L.graph['VertexC'] = G_db.graph['VertexC'][
82
+ : G_db.graph['T'] + G_db.graph['B'] - G_db.graph.get('D', 0)
83
+ ] if False else G_db.graph['VertexC'][
84
+ : G_db.graph['T'] + G_db.graph['B']
85
+ ].copy()
86
+ # Stitch the actual VertexC together: terminals + borders + roots
87
+ import numpy as np
88
+ R, T, B = G_db.graph['R'], G_db.graph['T'], G_db.graph['B']
89
+ VertexC = G_db.graph['VertexC']
90
+ L.graph['VertexC'] = np.vstack((VertexC[: T + B], VertexC[-R:]))
91
+ L.graph['B'] = B
92
+ L.graph['R'] = R
93
+ L.graph['T'] = T
94
+
95
+ P, A = make_planar_embedding(L)
96
+ S = S_from_G(G_db)
97
+ G_tent = G_from_S(S, A)
98
+ pf = PathFinder(G_tent, planar=P, A=A)
99
+ G_out = pf.create_detours()
100
+ length = G_out.size(weight='length')
101
+ feeders = _feeder_paths(G_out)
102
+ return length, feeders
103
+
104
+
105
+ def main():
106
+ failures = 0
107
+ for rid, expected in EXPECTED.items():
108
+ try:
109
+ length, feeders = _run_one(rid)
110
+ except Exception as e:
111
+ print(f' RID {rid}: ERROR {type(e).__name__}: {e}')
112
+ failures += 1
113
+ continue
114
+ ok_len = (
115
+ expected['length'] is None
116
+ or math.isclose(length, expected['length'], abs_tol=1e-3)
117
+ )
118
+ # Match expected feeders as multisets of prime-vertex sequences
119
+ got_set = {tuple(f) for f in feeders}
120
+ want_set = {tuple(f) for f in expected['feeders']}
121
+ missing = want_set - got_set
122
+ ok_feeders = not missing
123
+ status = 'OK' if (ok_len and ok_feeders) else 'FAIL'
124
+ if status == 'FAIL':
125
+ failures += 1
126
+ print(
127
+ f'RID {rid}: {status} length={length:.4f}'
128
+ + (f' (expected {expected["length"]})' if expected['length'] else '')
129
+ )
130
+ if missing:
131
+ print(f' missing feeders: {sorted(missing)}')
132
+ print(f' got feeders: {sorted(got_set)}')
133
+ return failures
134
+
135
+
136
+ if __name__ == '__main__':
137
+ sys.exit(main())
@@ -9,8 +9,8 @@ from ._core import (
9
9
  FeederRoute,
10
10
  ModelMetadata,
11
11
  ModelOptions,
12
- OWNWarmupFailed,
13
12
  OWNSolutionNotFound,
13
+ OWNWarmupFailed,
14
14
  SolutionInfo,
15
15
  Solver,
16
16
  Topology,
@@ -99,8 +99,9 @@ def solver_factory(solver_name: str) -> Solver:
99
99
  return SolverFSCIP()
100
100
  else:
101
101
  raise FileNotFoundError(
102
- "Executable 'fscip' not found. Ensure the system PATH includes the "
103
- "path to 'fscip' (part of scipoptsuite from https://www.scipopt.org)."
102
+ "Executable 'fscip' not found. Ensure the system PATH includes"
103
+ " the path to 'fscip' (part of scipoptsuite from"
104
+ ' https://www.scipopt.org).'
104
105
  )
105
106
  else:
106
107
  raise ModuleNotFoundError(
@@ -109,9 +110,10 @@ def solver_factory(solver_name: str) -> Solver:
109
110
  )
110
111
  case 'highs':
111
112
  if find_spec('highspy'):
112
- from .pyomo import SolverPyomoAppsi
113
113
  from pyomo.contrib.appsi.solvers.highs import Highs
114
114
 
115
+ from .pyomo import SolverPyomoAppsi
116
+
115
117
  return SolverPyomoAppsi(solver_name, Highs)
116
118
  raise ModuleNotFoundError(
117
119
  "Package 'highspy' not found. Try 'pip install highspy' or "
@@ -5,12 +5,11 @@ import abc
5
5
  import logging
6
6
  import os
7
7
  import sys
8
+ from collections.abc import Mapping
8
9
  from dataclasses import asdict, dataclass, field
9
- from pathlib import Path
10
-
11
10
  from enum import StrEnum, auto
12
11
  from itertools import chain
13
- from collections.abc import Mapping
12
+ from pathlib import Path
14
13
  from typing import Any
15
14
 
16
15
  import networkx as nx
@@ -85,7 +84,9 @@ class FeederRoute(StrEnum):
85
84
 
86
85
 
87
86
  class FeederLimit(StrEnum):
88
- 'Whether to limit the maximum number of feeders, if set to "specified", additional kwarg "max_feeders" must be given.'
87
+ 'Whether to limit the maximum number of feeders, if set to "specified",'
88
+
89
+ ' additional kwarg "max_feeders" must be given.'
89
90
 
90
91
  UNLIMITED = auto()
91
92
  SPECIFIED = auto()
@@ -5,12 +5,11 @@
5
5
  import abc
6
6
  from collections.abc import Mapping
7
7
  from dataclasses import dataclass, field
8
+ from enum import StrEnum
8
9
  from typing import Any
9
10
 
10
11
  import networkx as nx
11
12
 
12
- from enum import StrEnum
13
-
14
13
  def physical_core_count() -> int: ...
15
14
 
16
15
  class OWNWarmupFailed(Exception): ...
@@ -9,7 +9,7 @@ import pyomo.environ as pyo
9
9
 
10
10
  from ..interarraylib import G_from_S
11
11
  from ..pathfinding import PathFinder
12
- from ._core import FeederRoute, PoolHandler, Topology, ModelOptions
12
+ from ._core import FeederRoute, ModelOptions, PoolHandler, Topology
13
13
  from .pyomo import SolverPyomo
14
14
 
15
15
  __all__ = ()
@@ -13,7 +13,6 @@ import networkx as nx
13
13
 
14
14
  from ..interarraylib import G_from_S
15
15
  from ..pathfinding import PathFinder
16
- from .scip import make_min_length_model, warmup_model
17
16
  from ._core import (
18
17
  FeederRoute,
19
18
  ModelOptions,
@@ -24,6 +23,7 @@ from ._core import (
24
23
  Topology,
25
24
  physical_core_count,
26
25
  )
26
+ from .scip import make_min_length_model, warmup_model
27
27
 
28
28
  __all__ = ('make_min_length_model', 'warmup_model')
29
29
 
@@ -202,7 +202,8 @@ class SolverFSCIP(Solver, PoolHandler):
202
202
  num_solutions = model.getNSols()
203
203
  if num_solutions == 0:
204
204
  raise OWNSolutionNotFound(
205
- f'Unable to find a solution. Solver {self.name} terminated with: {model.getStatus()}'
205
+ f'Unable to find a solution. Solver {self.name} terminated'
206
+ f' with: {model.getStatus()}'
206
207
  )
207
208
  termination = 'unknown'
208
209
  solving_time = float('nan')
@@ -100,7 +100,8 @@ class SolverGurobi(SolverPyomo, PoolHandler):
100
100
  termination = result['Solver'][0]['Termination condition'].name
101
101
  if num_solutions == 0:
102
102
  raise OWNSolutionNotFound(
103
- f'Unable to find a solution. Solver gurobi terminated with: {termination}'
103
+ f'Unable to find a solution. Solver gurobi terminated'
104
+ f' with: {termination}'
104
105
  )
105
106
  self.result = result
106
107
  objective = result['Problem'][0]['Upper bound']
@@ -185,7 +185,8 @@ class SolverORTools(Solver, PoolHandler):
185
185
  termination = result.termination.reason.name
186
186
  if num_solutions == 0:
187
187
  raise OWNSolutionNotFound(
188
- f'Unable to find a solution. Solver {self.name} terminated with: {termination}'
188
+ f'Unable to find a solution. Solver {self.name} terminated'
189
+ f' with: {termination}'
189
190
  )
190
191
  storer.solutions.reverse()
191
192
  self._solution_pool = storer.solutions
@@ -132,7 +132,8 @@ class SolverPyomo(Solver):
132
132
  termination = result['Solver'][0]['Termination condition'].name
133
133
  if len(result.solution) == 0:
134
134
  raise OWNSolutionNotFound(
135
- f'Unable to find a solution. Solver {self.name} terminated with: {termination}'
135
+ f'Unable to find a solution. Solver {self.name} terminated'
136
+ f' with: {termination}'
136
137
  )
137
138
  self.result = result
138
139
  if self.name != 'scip':
@@ -238,7 +239,8 @@ class SolverPyomoAppsi(Solver):
238
239
  termination = result.termination_condition.name
239
240
  if objective is None:
240
241
  raise OWNSolutionNotFound(
241
- f'Unable to find a solution. Solver {self.name} terminated with: {termination}'
242
+ f'Unable to find a solution. Solver {self.name} terminated'
243
+ f' with: {termination}'
242
244
  )
243
245
  bound = result.best_objective_bound
244
246
  solution_info = SolutionInfo(
@@ -503,7 +505,7 @@ def make_min_length_model(
503
505
  # radial or branched topology
504
506
  if topology is Topology.RADIAL:
505
507
  # just need to limit incoming edges since the outgoing are
506
- # limited by the m.cons_one_out_edge
508
+ # limited by the m.cons_single_out_link
507
509
  m.cons_radial = pyo.Constraint(
508
510
  m.T,
509
511
  rule=(
@@ -96,7 +96,8 @@ class SolverSCIP(Solver, PoolHandler):
96
96
  num_solutions = model.getNSols()
97
97
  if num_solutions == 0:
98
98
  raise OWNSolutionNotFound(
99
- f'Unable to find a solution. Solver {self.name} terminated with: {model.getStatus()}'
99
+ f'Unable to find a solution. Solver {self.name} terminated'
100
+ f' with: {model.getStatus()}'
100
101
  )
101
102
  bound = model.getDualbound()
102
103
  objective = model.getObjVal()
@@ -5,7 +5,8 @@
5
5
  __author__ = 'Mauricio Souza de Alencar'
6
6
 
7
7
  __doc__ = """
8
- Tool for designing and optimizing the electrical cable network (collection system) for offshore wind power plants.
8
+ Tool for designing and optimizing the electrical cable network (collection system)
9
+ for offshore wind power plants.
9
10
 
10
11
  https://gitlab.windenergy.dtu.dk/TOPFARM/OptiWindNet/
11
12
  """