xcoll 0.3.6__py3-none-any.whl → 0.5.0__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.

Potentially problematic release.


This version of xcoll might be problematic. Click here for more details.

Files changed (350) hide show
  1. xcoll/__init__.py +13 -4
  2. xcoll/beam_elements/__init__.py +14 -6
  3. xcoll/beam_elements/absorber.py +41 -7
  4. xcoll/beam_elements/base.py +1202 -247
  5. xcoll/beam_elements/blowup.py +198 -0
  6. xcoll/beam_elements/elements_src/black_absorber.h +136 -0
  7. xcoll/beam_elements/elements_src/black_crystal.h +129 -0
  8. xcoll/beam_elements/elements_src/blowup.h +42 -0
  9. xcoll/beam_elements/elements_src/emittance_monitor.h +109 -0
  10. xcoll/beam_elements/{collimators_src → elements_src}/everest_block.h +59 -30
  11. xcoll/beam_elements/elements_src/everest_collimator.h +237 -0
  12. xcoll/beam_elements/elements_src/everest_crystal.h +280 -0
  13. xcoll/beam_elements/everest.py +65 -119
  14. xcoll/beam_elements/monitor.py +428 -0
  15. xcoll/colldb.py +276 -747
  16. xcoll/general.py +5 -5
  17. xcoll/headers/checks.h +1 -1
  18. xcoll/headers/particle_states.h +2 -2
  19. xcoll/initial_distribution.py +207 -0
  20. xcoll/install.py +179 -0
  21. xcoll/interaction_record/__init__.py +1 -0
  22. xcoll/interaction_record/interaction_record.py +298 -0
  23. xcoll/interaction_record/interaction_record_src/interaction_record.h +98 -0
  24. xcoll/{impacts → interaction_record}/interaction_types.py +11 -4
  25. xcoll/line_tools.py +82 -0
  26. xcoll/lossmap.py +219 -0
  27. xcoll/manager.py +2 -937
  28. xcoll/rf_sweep.py +1 -1
  29. xcoll/scattering_routines/everest/amorphous.h +232 -0
  30. xcoll/scattering_routines/everest/channeling.h +240 -0
  31. xcoll/scattering_routines/everest/crystal_parameters.h +137 -0
  32. xcoll/scattering_routines/everest/everest.h +11 -30
  33. xcoll/scattering_routines/everest/everest.py +13 -10
  34. xcoll/scattering_routines/everest/jaw.h +28 -197
  35. xcoll/scattering_routines/everest/materials.py +37 -15
  36. xcoll/scattering_routines/everest/multiple_coulomb_scattering.h +31 -10
  37. xcoll/scattering_routines/everest/nuclear_interaction.h +86 -0
  38. xcoll/scattering_routines/everest/properties.h +6 -1
  39. xcoll/scattering_routines/fluka/flukaio/lib/libFlukaIO64.a +0 -0
  40. xcoll/scattering_routines/geant4/collimasim/.git +1 -0
  41. xcoll/scattering_routines/geant4/collimasim/.gitignore +12 -0
  42. xcoll/scattering_routines/geant4/collimasim/.gitmodules +3 -0
  43. xcoll/scattering_routines/geant4/collimasim/CMakeLists.txt +26 -0
  44. xcoll/scattering_routines/geant4/collimasim/README.md +21 -0
  45. xcoll/scattering_routines/geant4/collimasim/docs/Makefile +20 -0
  46. xcoll/scattering_routines/geant4/collimasim/docs/make.bat +35 -0
  47. xcoll/scattering_routines/geant4/collimasim/docs/source/collimasim.rst +10 -0
  48. xcoll/scattering_routines/geant4/collimasim/docs/source/conf.py +59 -0
  49. xcoll/scattering_routines/geant4/collimasim/docs/source/index.rst +26 -0
  50. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.appveyor.yml +37 -0
  51. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.clang-format +19 -0
  52. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.clang-tidy +65 -0
  53. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.cmake-format.yaml +73 -0
  54. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.git +1 -0
  55. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/CODEOWNERS +9 -0
  56. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/CONTRIBUTING.md +386 -0
  57. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/ISSUE_TEMPLATE/bug-report.yml +45 -0
  58. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/ISSUE_TEMPLATE/config.yml +8 -0
  59. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/dependabot.yml +16 -0
  60. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/labeler.yml +8 -0
  61. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/labeler_merged.yml +3 -0
  62. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/pull_request_template.md +19 -0
  63. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/workflows/ci.yml +969 -0
  64. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/workflows/configure.yml +84 -0
  65. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/workflows/format.yml +48 -0
  66. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/workflows/labeler.yml +16 -0
  67. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.github/workflows/pip.yml +103 -0
  68. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.gitignore +45 -0
  69. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.pre-commit-config.yaml +151 -0
  70. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/.readthedocs.yml +3 -0
  71. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/CMakeLists.txt +297 -0
  72. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/LICENSE +29 -0
  73. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/MANIFEST.in +6 -0
  74. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/README.rst +180 -0
  75. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/Doxyfile +23 -0
  76. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/Makefile +192 -0
  77. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/_static/theme_overrides.css +11 -0
  78. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/chrono.rst +81 -0
  79. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/custom.rst +93 -0
  80. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/eigen.rst +310 -0
  81. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/functional.rst +109 -0
  82. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/index.rst +43 -0
  83. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/overview.rst +171 -0
  84. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/stl.rst +251 -0
  85. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/cast/strings.rst +305 -0
  86. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/classes.rst +1297 -0
  87. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/embedding.rst +262 -0
  88. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/exceptions.rst +396 -0
  89. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/functions.rst +568 -0
  90. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/misc.rst +337 -0
  91. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/pycpp/index.rst +13 -0
  92. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/pycpp/numpy.rst +463 -0
  93. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/pycpp/object.rst +286 -0
  94. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/pycpp/utilities.rst +155 -0
  95. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/advanced/smart_ptrs.rst +174 -0
  96. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/basics.rst +308 -0
  97. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/benchmark.py +91 -0
  98. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/benchmark.rst +95 -0
  99. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/changelog.rst +2050 -0
  100. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/classes.rst +542 -0
  101. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/cmake/index.rst +8 -0
  102. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/compiling.rst +648 -0
  103. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/conf.py +381 -0
  104. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/faq.rst +343 -0
  105. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/index.rst +48 -0
  106. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/installing.rst +105 -0
  107. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/limitations.rst +72 -0
  108. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/pybind11-logo.png +0 -0
  109. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/pybind11_vs_boost_python1.png +0 -0
  110. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/pybind11_vs_boost_python1.svg +427 -0
  111. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/pybind11_vs_boost_python2.png +0 -0
  112. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/pybind11_vs_boost_python2.svg +427 -0
  113. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/reference.rst +130 -0
  114. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/release.rst +96 -0
  115. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/requirements.txt +8 -0
  116. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/docs/upgrade.rst +548 -0
  117. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/attr.h +605 -0
  118. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/buffer_info.h +144 -0
  119. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/cast.h +1432 -0
  120. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/chrono.h +213 -0
  121. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/common.h +2 -0
  122. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/complex.h +65 -0
  123. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/detail/class.h +709 -0
  124. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/detail/common.h +1021 -0
  125. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/detail/descr.h +104 -0
  126. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/detail/init.h +346 -0
  127. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/detail/internals.h +467 -0
  128. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/detail/type_caster_base.h +978 -0
  129. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/detail/typeid.h +55 -0
  130. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/eigen.h +606 -0
  131. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/embed.h +284 -0
  132. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/eval.h +163 -0
  133. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/functional.h +121 -0
  134. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/gil.h +193 -0
  135. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/iostream.h +275 -0
  136. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/numpy.h +1741 -0
  137. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/operators.h +163 -0
  138. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/options.h +65 -0
  139. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/pybind11.h +2497 -0
  140. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/pytypes.h +1879 -0
  141. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/stl/filesystem.h +103 -0
  142. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/stl.h +375 -0
  143. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/include/pybind11/stl_bind.h +747 -0
  144. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/noxfile.py +88 -0
  145. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/__init__.py +11 -0
  146. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/__main__.py +52 -0
  147. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/_version.py +12 -0
  148. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/_version.pyi +6 -0
  149. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/commands.py +21 -0
  150. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/py.typed +0 -0
  151. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/setup_helpers.py +482 -0
  152. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pybind11/setup_helpers.pyi +63 -0
  153. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/pyproject.toml +41 -0
  154. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/setup.cfg +56 -0
  155. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/setup.py +155 -0
  156. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/CMakeLists.txt +503 -0
  157. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/conftest.py +208 -0
  158. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/constructor_stats.h +275 -0
  159. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/cross_module_gil_utils.cpp +73 -0
  160. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/env.py +33 -0
  161. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/extra_python_package/pytest.ini +0 -0
  162. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/extra_python_package/test_files.py +279 -0
  163. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/extra_setuptools/pytest.ini +0 -0
  164. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/extra_setuptools/test_setuphelper.py +143 -0
  165. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/local_bindings.h +85 -0
  166. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/object.h +179 -0
  167. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/pybind11_cross_module_tests.cpp +151 -0
  168. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/pybind11_tests.cpp +91 -0
  169. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/pybind11_tests.h +85 -0
  170. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/pytest.ini +19 -0
  171. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/requirements.txt +12 -0
  172. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_async.cpp +26 -0
  173. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_async.py +25 -0
  174. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_buffers.cpp +216 -0
  175. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_buffers.py +163 -0
  176. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_builtin_casters.cpp +286 -0
  177. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_builtin_casters.py +536 -0
  178. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_call_policies.cpp +107 -0
  179. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_call_policies.py +248 -0
  180. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_callbacks.cpp +227 -0
  181. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_callbacks.py +202 -0
  182. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_chrono.cpp +84 -0
  183. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_chrono.py +210 -0
  184. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_class.cpp +550 -0
  185. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_class.py +473 -0
  186. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/CMakeLists.txt +84 -0
  187. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/embed.cpp +21 -0
  188. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/installed_embed/CMakeLists.txt +28 -0
  189. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/installed_function/CMakeLists.txt +39 -0
  190. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/installed_target/CMakeLists.txt +46 -0
  191. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/main.cpp +6 -0
  192. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/subdirectory_embed/CMakeLists.txt +41 -0
  193. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/subdirectory_function/CMakeLists.txt +35 -0
  194. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/subdirectory_target/CMakeLists.txt +41 -0
  195. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_cmake_build/test.py +10 -0
  196. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_constants_and_functions.cpp +165 -0
  197. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_constants_and_functions.py +53 -0
  198. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_copy_move.cpp +238 -0
  199. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_copy_move.py +126 -0
  200. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_custom_type_casters.cpp +141 -0
  201. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_custom_type_casters.py +117 -0
  202. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_custom_type_setup.cpp +41 -0
  203. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_custom_type_setup.py +50 -0
  204. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_docstring_options.cpp +69 -0
  205. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_docstring_options.py +42 -0
  206. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_eigen.cpp +348 -0
  207. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_eigen.py +771 -0
  208. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_embed/CMakeLists.txt +47 -0
  209. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_embed/catch.cpp +22 -0
  210. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_embed/external_module.cpp +23 -0
  211. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_embed/test_interpreter.cpp +326 -0
  212. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_embed/test_interpreter.py +15 -0
  213. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_enum.cpp +148 -0
  214. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_enum.py +272 -0
  215. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_eval.cpp +119 -0
  216. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_eval.py +51 -0
  217. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_eval_call.py +5 -0
  218. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_exceptions.cpp +285 -0
  219. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_exceptions.h +12 -0
  220. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_exceptions.py +265 -0
  221. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_factory_constructors.cpp +397 -0
  222. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_factory_constructors.py +520 -0
  223. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_gil_scoped.cpp +49 -0
  224. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_gil_scoped.py +94 -0
  225. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_iostream.cpp +125 -0
  226. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_iostream.py +331 -0
  227. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_kwargs_and_defaults.cpp +153 -0
  228. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_kwargs_and_defaults.py +284 -0
  229. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_local_bindings.cpp +107 -0
  230. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_local_bindings.py +257 -0
  231. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_methods_and_attributes.cpp +412 -0
  232. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_methods_and_attributes.py +517 -0
  233. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_modules.cpp +102 -0
  234. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_modules.py +92 -0
  235. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_multiple_inheritance.cpp +233 -0
  236. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_multiple_inheritance.py +360 -0
  237. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_numpy_array.cpp +472 -0
  238. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_numpy_array.py +593 -0
  239. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_numpy_dtypes.cpp +524 -0
  240. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_numpy_dtypes.py +441 -0
  241. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_numpy_vectorize.cpp +103 -0
  242. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_numpy_vectorize.py +267 -0
  243. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_opaque_types.cpp +73 -0
  244. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_opaque_types.py +59 -0
  245. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_operator_overloading.cpp +235 -0
  246. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_operator_overloading.py +146 -0
  247. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_pickling.cpp +189 -0
  248. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_pickling.py +82 -0
  249. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_pytypes.cpp +560 -0
  250. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_pytypes.py +651 -0
  251. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_sequences_and_iterators.cpp +500 -0
  252. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_sequences_and_iterators.py +253 -0
  253. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_smart_ptr.cpp +452 -0
  254. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_smart_ptr.py +318 -0
  255. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_stl.cpp +342 -0
  256. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_stl.py +291 -0
  257. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_stl_binders.cpp +131 -0
  258. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_stl_binders.py +318 -0
  259. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_tagbased_polymorphic.cpp +144 -0
  260. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_tagbased_polymorphic.py +29 -0
  261. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_thread.cpp +66 -0
  262. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_thread.py +44 -0
  263. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_union.cpp +22 -0
  264. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_union.py +9 -0
  265. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_virtual_functions.cpp +510 -0
  266. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/test_virtual_functions.py +408 -0
  267. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/valgrind-numpy-scipy.supp +140 -0
  268. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tests/valgrind-python.supp +117 -0
  269. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/FindCatch.cmake +70 -0
  270. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/FindEigen3.cmake +86 -0
  271. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/FindPythonLibsNew.cmake +257 -0
  272. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/check-style.sh +44 -0
  273. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/cmake_uninstall.cmake.in +23 -0
  274. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/libsize.py +39 -0
  275. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/make_changelog.py +64 -0
  276. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/pybind11Common.cmake +402 -0
  277. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/pybind11Config.cmake.in +233 -0
  278. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/pybind11NewTools.cmake +276 -0
  279. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/pybind11Tools.cmake +214 -0
  280. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/pyproject.toml +3 -0
  281. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/setup_global.py.in +65 -0
  282. xcoll/scattering_routines/geant4/collimasim/lib/pybind11/tools/setup_main.py.in +41 -0
  283. xcoll/scattering_routines/geant4/collimasim/pyproject.toml +8 -0
  284. xcoll/scattering_routines/geant4/collimasim/setup.py +144 -0
  285. xcoll/scattering_routines/geant4/collimasim/src/collimasim/BDSPyATInterface.cpp +403 -0
  286. xcoll/scattering_routines/geant4/collimasim/src/collimasim/BDSPyATInterface.hh +100 -0
  287. xcoll/scattering_routines/geant4/collimasim/src/collimasim/BDSXtrackInterface.cpp +763 -0
  288. xcoll/scattering_routines/geant4/collimasim/src/collimasim/BDSXtrackInterface.hh +118 -0
  289. xcoll/scattering_routines/geant4/collimasim/src/collimasim/__init__.py +8 -0
  290. xcoll/scattering_routines/geant4/collimasim/src/collimasim/bindings.cpp +63 -0
  291. xcoll/scattering_routines/geant4/collimasim/src/collimasim/pyCollimatorPass.py +142 -0
  292. xcoll/scattering_routines/geant4/collimasim/src/collimasim/xtrack_collimator.py +556 -0
  293. xcoll/scattering_routines/geant4/collimasim/src/collimasim.egg-info/PKG-INFO +6 -0
  294. xcoll/scattering_routines/geant4/collimasim/src/collimasim.egg-info/SOURCES.txt +24 -0
  295. xcoll/scattering_routines/geant4/collimasim/src/collimasim.egg-info/dependency_links.txt +1 -0
  296. xcoll/scattering_routines/geant4/collimasim/src/collimasim.egg-info/not-zip-safe +1 -0
  297. xcoll/scattering_routines/geant4/collimasim/src/collimasim.egg-info/top_level.txt +1 -0
  298. xcoll/scattering_routines/geant4/collimasim/tests/README.md +25 -0
  299. xcoll/scattering_routines/geant4/collimasim/tests/resources/CollDB_forions.dat +25 -0
  300. xcoll/scattering_routines/geant4/collimasim/tests/resources/CollDB_new_example.dat +18 -0
  301. xcoll/scattering_routines/geant4/collimasim/tests/resources/CollDB_old_example.dat +68 -0
  302. xcoll/scattering_routines/geant4/collimasim/tests/resources/CollDB_testing.dat +15 -0
  303. xcoll/scattering_routines/geant4/collimasim/tests/resources/CollDB_yaml_example.yaml +110 -0
  304. xcoll/scattering_routines/geant4/collimasim/tests/resources/collgaps.dat +7 -0
  305. xcoll/scattering_routines/geant4/collimasim/tests/resources/collgaps_pyat_test.dat +3 -0
  306. xcoll/scattering_routines/geant4/collimasim/tests/resources/collonly_twiss_file_example.tfs +54 -0
  307. xcoll/scattering_routines/geant4/collimasim/tests/resources/settings.gmad +3 -0
  308. xcoll/scattering_routines/geant4/collimasim/tests/resources/settings_black_absorber.gmad +3 -0
  309. xcoll/scattering_routines/geant4/collimasim/tests/resources/settings_ions.gmad +5 -0
  310. xcoll/scattering_routines/geant4/collimasim/tests/resources/twiss_file_testing.tfs +51 -0
  311. xcoll/scattering_routines/geant4/collimasim/tests/test_pyat.py +65 -0
  312. xcoll/scattering_routines/geant4/collimasim/tests/test_pyat_passmethod.py +59 -0
  313. xcoll/scattering_routines/geant4/collimasim/tests/test_pyat_tracking.py +102 -0
  314. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack.py +75 -0
  315. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_angle.py +74 -0
  316. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_colldb_load.py +84 -0
  317. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_interaction.py +159 -0
  318. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_interaction_ion.py +99 -0
  319. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_ions.py +78 -0
  320. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_lost_energy.py +88 -0
  321. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_tilt.py +80 -0
  322. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_tracking.py +97 -0
  323. xcoll/scattering_routines/geant4/collimasim/tests/test_xtrack_tracking_ions.py +96 -0
  324. xcoll/scattering_routines/geometry/__init__.py +6 -0
  325. xcoll/scattering_routines/geometry/collimator_geometry.h +218 -0
  326. xcoll/scattering_routines/geometry/crystal_geometry.h +153 -0
  327. xcoll/scattering_routines/geometry/geometry.py +26 -0
  328. xcoll/scattering_routines/geometry/get_s.h +92 -0
  329. xcoll/scattering_routines/geometry/methods.h +111 -0
  330. xcoll/scattering_routines/geometry/objects.h +154 -0
  331. xcoll/scattering_routines/geometry/rotation.h +23 -0
  332. xcoll/scattering_routines/geometry/segments.h +226 -0
  333. xcoll/scattering_routines/geometry/sort.h +184 -0
  334. {xcoll-0.3.6.dist-info → xcoll-0.5.0.dist-info}/METADATA +1 -1
  335. xcoll-0.5.0.dist-info/RECORD +413 -0
  336. xcoll/beam_elements/collimators_src/absorber.h +0 -141
  337. xcoll/beam_elements/collimators_src/everest_collimator.h +0 -142
  338. xcoll/beam_elements/collimators_src/everest_crystal.h +0 -115
  339. xcoll/collimator_settings.py +0 -457
  340. xcoll/impacts/__init__.py +0 -1
  341. xcoll/impacts/impacts.py +0 -102
  342. xcoll/impacts/impacts_src/impacts.h +0 -99
  343. xcoll/scattering_routines/everest/crystal.h +0 -1302
  344. xcoll/scattering_routines/everest/scatter.h +0 -169
  345. xcoll/scattering_routines/everest/scatter_crystal.h +0 -260
  346. xcoll/scattering_routines/fluka/build_fluka_input.py +0 -58
  347. xcoll-0.3.6.dist-info/RECORD +0 -111
  348. {xcoll-0.3.6.dist-info → xcoll-0.5.0.dist-info}/LICENSE +0 -0
  349. {xcoll-0.3.6.dist-info → xcoll-0.5.0.dist-info}/NOTICE +0 -0
  350. {xcoll-0.3.6.dist-info → xcoll-0.5.0.dist-info}/WHEEL +0 -0
xcoll/colldb.py CHANGED
@@ -1,33 +1,32 @@
1
1
  # copyright ############################### #
2
2
  # This file is part of the Xcoll Package. #
3
- # Copyright (c) CERN, 2023. #
3
+ # Copyright (c) CERN, 2024. #
4
4
  # ######################################### #
5
5
 
6
6
  import io
7
+ import re
7
8
  import json
8
9
  import numpy as np
9
10
  import pandas as pd
11
+ from pathlib import Path
10
12
 
13
+ import xtrack as xt
11
14
 
12
- #TODO: niet-active collimators op non-active etc (ook crystals)
15
+ from .beam_elements import BlackAbsorber, BlackCrystal, EverestCollimator, EverestCrystal, \
16
+ BaseCollimator, BaseCrystal, _all_collimator_classes
17
+ from .install import install_elements
18
+ from .scattering_routines.everest.materials import SixTrack_to_xcoll
13
19
 
14
- def load_SixTrack_colldb(filename, *, emit):
15
- print("Warning: Using 'xcoll.load_SixTrack_colldb()' is deprecated! "
16
- + "Use 'xcoll.CollimatorDatabase.from_SixTrack()' instead.")
17
- return CollimatorDatabase.from_SixTrack(file=filename, nemitt_x=emit, nemitt_y=emit)
18
20
 
19
-
20
- def _initialise_None(collimator):
21
- fields = {'s_center':None, 'align_to': None, 's_align_front': None, 's_align_back': None }
22
- fields.update({'gap_L': None, 'gap_R': None, 'angle_L': 0, 'angle_R': 0, 'offset': 0, 'parking': 1})
23
- fields.update({'jaw_LU': None, 'jaw_RU': None, 'jaw_LD': None, 'jaw_RD': None, 'family': None, 'overwritten_keys': []})
24
- fields.update({'side': 'both', 'material': None, 'stage': None, 'collimator_type': None, 'active': True})
25
- fields.update({'active_length': 0, 'inactive_front': 0, 'inactive_back': 0, 'sigmax': None, 'sigmay': None})
26
- fields.update({'crystal': None, 'bending_radius': None, 'xdim': 0, 'ydim': 0, 'miscut': 0, 'thick': 0})
21
+ def _initialise_None(dct):
22
+ fields = {'gap': None, 'angle': 0, 'offset': 0, 'parking': 1, 'jaw': None, 'family': None}
23
+ fields.update({'overwritten_keys': [], 'side': 'both', 'material': None, 'stage': None})
24
+ fields.update({'length': 0, 'collimator_type': None, 'active': True, 'crystal': None, 'tilt': 0})
25
+ fields.update({'bending_radius': None, 'bending_angle': None, 'width': 0, 'height': 0, 'miscut': 0})
27
26
  for f, val in fields.items():
28
- if f not in collimator.keys():
29
- collimator[f] = val
30
- for key in collimator.keys():
27
+ if f not in dct.keys():
28
+ dct[f] = val
29
+ for key in dct.keys():
31
30
  if key not in fields.keys():
32
31
  raise ValueError(f"Illegal setting {key} in collimator!")
33
32
 
@@ -47,7 +46,7 @@ def _get_coll_dct_by_beam(coll, beam):
47
46
  beam = f'b{beam}'
48
47
  beam = beam.lower()
49
48
  beam_in_db = list(coll.keys())
50
-
49
+
51
50
  if beam_in_db == ['b1','b2']:
52
51
  if beam is None:
53
52
  raise ValueError("Need to specify a beam, because the given dict is for both beams!")
@@ -67,16 +66,90 @@ def _get_coll_dct_by_beam(coll, beam):
67
66
 
68
67
  class CollimatorDatabase:
69
68
 
70
- _init_vars = ['collimator_dict', 'family_dict', 'beam', 'nemitt_x', 'nemitt_y', '_yaml_merged', 'ignore_crystals']
71
- _init_var_defaults = {'family_dict': {}, 'beam': None, '_yaml_merged': False, 'ignore_crystals': True}
69
+ def __init__(self, **kwargs):
70
+ # Get all arguments
71
+ for key in ['collimator_dict', 'nemitt_x', 'nemitt_y']:
72
+ if key not in kwargs.keys():
73
+ raise ValueError(f"CollimatorDatabase is missing required argument '{key}'!")
74
+
75
+ self._parse_dict(kwargs['collimator_dict'],
76
+ kwargs.get('family_dict', {}),
77
+ kwargs.get('beam', None),
78
+ kwargs.get('_yaml_merged', False),
79
+ kwargs.get('ignore_crystals', True))
80
+ self.nemitt_x = kwargs['nemitt_x']
81
+ self.nemitt_y = kwargs['nemitt_y']
82
+ self._elements = {}
83
+
84
+
85
+ def _parse_dict(self, coll, fam, beam=None, _yaml_merged=False, ignore_crystals=True):
86
+ # We make all keys case-insensitive to avoid confusion between different conventions
87
+ coll = _dict_keys_to_lower(coll)
88
+ fam = _dict_keys_to_lower(fam)
89
+
90
+ # The dictionary can be a CollimatorDatabase for a single beam (beam=None)
91
+ # or for both beams (beam='b1' or beam='b2)
92
+ coll = _get_coll_dct_by_beam(coll, beam)
93
+
94
+ # Apply family settings
95
+ crystals = []
96
+ for thiscoll, settings in coll.items():
97
+ settings = {k.lower(): v for k,v in settings.items()}
98
+ if 'family' in settings.keys() and settings['family'] is not None:
99
+ settings['family'] = settings['family'].lower()
100
+ thisfam = settings['family']
101
+ if thisfam not in fam.keys():
102
+ raise ValueError(f"Collimator {thiscoll} depends on family {thisfam}, "
103
+ + f"but the latter is not defined!")
104
+
105
+ # Check if some family settings are overwritten for this collimator
106
+ # Only do this check if we didn't do a YAML merge earlier (because then it
107
+ # is already taken care of)
108
+ if not _yaml_merged:
109
+ overwritten_keys = [key.lower() for key in settings.keys() if key in fam[thisfam]]
110
+ if len(overwritten_keys) > 0:
111
+ settings['overwritten_keys'] = overwritten_keys
112
+
113
+ # Load family settings, potentially overwriting settings for this collimator
114
+ settings = {**fam[thisfam], **settings}
115
+
116
+ else:
117
+ settings['family'] = None
118
+ coll[thiscoll] = settings
119
+
120
+ # Save list of crystals
121
+ if 'crystal' in settings:
122
+ if settings['crystal'] != 0.0:
123
+ crystals += [thiscoll]
124
+ else:
125
+ settings['crystal'] = None
126
+
127
+ # Remove crystals from colldb
128
+ if ignore_crystals:
129
+ for thiscoll in crystals:
130
+ del coll[thiscoll]
131
+
132
+ # Check that all collimators have gap settings
133
+ if not np.all(['gap' in val.keys() or 'jaw' in val.keys() for val in coll.values()]):
134
+ raise ValueError("Ill-defined CollimatorDatabase: Not all collimators have a gap or "
135
+ + "jaw setting, (or the keys / structure of the dictionary is wrong)!")
136
+
137
+ # Update collimators with default values for missing keys
138
+ for name, collimator in coll.items():
139
+ # Change all values to lower case
140
+ for key, val in collimator.items():
141
+ collimator[key] = val.lower() if isinstance(val, str) else val
142
+ _initialise_None(collimator)
143
+
144
+ self._collimator_dict = coll
145
+ self._family_dict = fam
146
+
147
+ # =======================================
148
+ # ====== Loading/dumping functions ======
149
+ # =======================================
72
150
 
73
- # -------------------------------
74
- # ------ Loading functions ------
75
- # -------------------------------
76
-
77
151
  @classmethod
78
152
  def from_yaml(cls, file, **kwargs):
79
-
80
153
  # Only do the import here, as to not force people to install
81
154
  # ruamel if they don't load CollimatorDatabase yaml's
82
155
  from ruamel.yaml import YAML
@@ -84,7 +157,8 @@ class CollimatorDatabase:
84
157
  if isinstance(file, io.IOBase):
85
158
  dct = yaml.load(file)
86
159
  else:
87
- with open(file, 'r') as fid:
160
+ file = Path(file).resolve()
161
+ with file.open('r') as fid:
88
162
  dct = yaml.load(fid)
89
163
  dct = _dict_keys_to_lower(dct)
90
164
 
@@ -119,6 +193,8 @@ class CollimatorDatabase:
119
193
  coll_dct = _get_coll_dct_by_beam(dct['collimators'], beam)
120
194
  full_coll_dct = _get_coll_dct_by_beam(full_dct[collkey], beam)
121
195
  for coll, full_coll in zip(coll_dct.values(), full_coll_dct.values()):
196
+ if not isinstance(coll['gap'], (int,float)):
197
+ coll['gap'] = None
122
198
  if 'family' in coll.keys():
123
199
  raise ValueError(f"Error in {coll}: Cannot use merging for families "
124
200
  + "and manually specify family as well!")
@@ -141,7 +217,8 @@ class CollimatorDatabase:
141
217
  if isinstance(file, io.IOBase):
142
218
  dct = json.load(file)
143
219
  else:
144
- with open(file, 'r') as fid:
220
+ file = Path(file).resolve()
221
+ with file.open('r') as fid:
145
222
  dct = json.load(fid)
146
223
  dct = _dict_keys_to_lower(dct)
147
224
  return cls.from_dict(dct, **kwargs)
@@ -186,17 +263,16 @@ class CollimatorDatabase:
186
263
 
187
264
  @classmethod
188
265
  def from_SixTrack(cls, file, ignore_crystals=True, **kwargs):
189
- # only import regex here
190
- import re
191
- with open(file, 'r') as infile:
266
+ file = Path(file).resolve()
267
+ with file.open('r') as fp:
192
268
  coll_data_string = ''
193
269
  family_settings = {}
194
270
  family_types = {}
195
271
  side = {}
196
- cry_fields = ['bending_radius', 'xdim', 'ydim', 'thick', 'miscut', 'crystal']
272
+ cry_fields = ['bending_radius', 'width', 'height', 'thick', 'tilt', 'miscut', 'crystal']
197
273
  cry = {}
198
274
 
199
- for l_no, line in enumerate(infile):
275
+ for line in fp:
200
276
  if line.startswith('#'):
201
277
  continue # Comment
202
278
  sline = line.split()
@@ -209,8 +285,8 @@ class CollimatorDatabase:
209
285
  elif sline[0].lower() == "crystal":
210
286
  cry[sline[1]] = {}
211
287
  for i, key in enumerate(cry_fields):
212
- idx = i+2 if i < 4 else i+3 # we skip "tilt"
213
- if i < 5:
288
+ idx = i+2
289
+ if i < 6:
214
290
  cry[sline[1]][key] = float(sline[idx])
215
291
  else:
216
292
  cry[sline[1]][key] = int(sline[idx])
@@ -224,16 +300,20 @@ class CollimatorDatabase:
224
300
 
225
301
  defaults = {}
226
302
  _initialise_None(defaults)
303
+ defaults['thick'] = 0
227
304
 
228
- famdct = {key: {'gap': family_settings[key], 'stage': family_types[key]} for key in family_settings}
229
- names = ['name', 'gap', 'material', 'active_length', 'angle', 'offset']
305
+ famdct = {key: {'gap': None if family_settings[key] > 900 else family_settings[key],
306
+ 'stage': family_types[key]} for key in family_settings}
307
+ names = ['name', 'gap', 'material', 'length', 'angle', 'offset']
230
308
 
231
309
  df = pd.read_csv(io.StringIO(coll_data_string), sep=r'\s+', index_col=False, names=names)
232
310
  df['family'] = df['gap'].copy()
233
311
  df['family'] = df['family'].apply(lambda s: None if re.match(r'^-?\d+(\.\d+)?$', str(s)) else s)
234
- df.insert(5,'stage', df['gap'].apply(lambda s: family_types.get(s, 'UNKNOWN')))
312
+ df.insert(5,'stage', df['gap'].apply(lambda s: None if s in family_types else 'UNKNOWN'))
313
+
314
+ df['gap'] = df['gap'].apply(lambda s: None if not isinstance(s, str) and s > 900 else s)
315
+ df['gap'] = df['gap'].apply(lambda s: None if isinstance(s, str) else s)
235
316
 
236
- df['gap'] = df['gap'].apply(lambda s: float(family_settings.get(s, s)))
237
317
  # TODO this breaks code if a key has upper case, e.g. gap_L
238
318
  df['name'] = df['name'].str.lower() # Make the names lowercase for easy processing
239
319
  df['parking'] = 0.025
@@ -243,6 +323,9 @@ class CollimatorDatabase:
243
323
  for key in cry_fields:
244
324
  df[key] = [cry[name][key] if name in cry else defaults[key]
245
325
  for name in df['name']]
326
+ if not np.allclose(np.unique(df.thick.values), 0):
327
+ print("Warning: Keyword 'thick' is currently not supported in xcoll! Ignoring.")
328
+ df = df.drop('thick', axis=1)
246
329
  df['crystal'] = ['strip' if s==1 else s for s in df['crystal']]
247
330
  df['crystal'] = ['quasi-mosaic' if s==2 else s for s in df['crystal']]
248
331
  df['side'] = [side[name] if name in side else defaults['side']
@@ -250,13 +333,32 @@ class CollimatorDatabase:
250
333
  df['side'] = ['both' if s==0 else s for s in df['side']]
251
334
  df['side'] = ['left' if s==1 else s for s in df['side']]
252
335
  df['side'] = ['right' if s==2 else s for s in df['side']]
336
+ if not np.allclose(np.unique(df.offset.values), 0):
337
+ print("Warning: Keyword 'offset' is currently not supported in xcoll! Ignoring.")
338
+ df = df.drop('offset', axis=1)
253
339
  df = df.set_index('name')
254
-
255
- return cls.from_dict({'collimators': df.transpose().to_dict(), 'families': famdct}, \
340
+ df = df.replace(np.nan, None)
341
+
342
+ colldict = df.transpose().to_dict()
343
+ # Remove Nonetype families
344
+ colldict = {coll: {kk: vv for kk, vv in coll_settings.items()
345
+ if kk != 'family' or vv is not None}
346
+ for coll, coll_settings in colldict.items()}
347
+ # Remove None gaps and stages if the collimator is assigned a family (they will be set in _parse_dict)
348
+ colldict = {coll: {kk: vv for kk, vv in coll_settings.items()
349
+ if kk != 'gap' or vv is not None or 'family' not in coll_settings}
350
+ for coll, coll_settings in colldict.items()}
351
+ colldict = {coll: {kk: vv for kk, vv in coll_settings.items()
352
+ if kk != 'stage' or vv is not None or 'family' not in coll_settings}
353
+ for coll, coll_settings in colldict.items()}
354
+
355
+ return cls.from_dict({'collimators': colldict, 'families': famdct}, \
256
356
  ignore_crystals=ignore_crystals, **kwargs)
257
357
 
358
+ def to_pandas(self):
359
+ return pd.DataFrame(self._collimator_dict).transpose()
258
360
 
259
- def write_to_yaml(self, out, lhc_style=True):
361
+ def to_yaml(self, out, lhc_style=True):
260
362
  """
261
363
  Writes a colldb in memory to disk in the yaml format.
262
364
 
@@ -286,18 +388,18 @@ class CollimatorDatabase:
286
388
  formatted_key = f'{key}:'.ljust(key_width)
287
389
  #formatted_values = formatted_values.ljust(key_width)
288
390
  return f"{spacing}{formatted_key} {{ {formatted_values} }}\n"
289
-
391
+
290
392
  def _print_values(keys, dct, file, spacing='', mapping=False):
291
393
  # Writes formatted dictionary entries to a file
292
394
  for key in keys:
293
395
  file.write(_format_dict_entry(key, dct[key], spacing=spacing, mapping=mapping))
294
-
396
+
295
397
  def _print_colls(colls, dcts, beam, file):
296
398
  # Filters and formats collimator data, then writes to a file
297
399
  coll_items_to_print = ['<<','gap','angle','material','active','length','side']
298
400
  file.write(f' {beam}:\n')
299
401
  for coll in colls:
300
- coll_dict = dcts._colldb.transpose().to_dict()[coll]
402
+ coll_dict = dcts.to_pandas().transpose().to_dict()[coll]
301
403
  fam = coll_dict['family']
302
404
  fam_keys = []
303
405
  if fam is not None:
@@ -305,19 +407,19 @@ class CollimatorDatabase:
305
407
  coll_dict = {**{'<<': '*'+fam}, **coll_dict}
306
408
  temp_items_to_print = []
307
409
  if coll_dict['crystal'] and str(coll_dict['crystal'])!='nan':
308
- temp_items_to_print = ['bending_radius','xdim','ydim','miscut','crystal', 'thick']
309
- if coll_dict['angle_L'] == coll_dict['angle_R']:
310
- coll_dict.update({'angle': coll_dict['angle_L']})
311
- else:
312
- temp_items_to_print = temp_items_to_print + ['angle_L','angle_R']
313
- if coll_dict['gap_L'] == coll_dict['gap_R']:
314
- coll_dict.update({'gap': coll_dict['gap_L']})
315
- elif coll_dict['gap_L'] is None and coll_dict['gap_R'] is not None:
316
- coll_dict.update({'gap': coll_dict['gap_R']})
317
- elif coll_dict['gap_L'] is not None and coll_dict['gap_R'] is None:
318
- coll_dict.update({'gap': coll_dict['gap_L']})
319
- else:
320
- temp_items_to_print = temp_items_to_print + ['gap_L','gap_R']
410
+ temp_items_to_print = ['bending_radius','width','height','miscut','crystal']
411
+ # if 'angle_L' in coll_dict and coll_dict['angle_L'] == coll_dict['angle_R']:
412
+ # coll_dict.update({'angle': coll_dict['angle_L']})
413
+ # else:
414
+ # temp_items_to_print = temp_items_to_print + ['angle_L','angle_R']
415
+ # if coll_dict['gap_L'] == coll_dict['gap_R']:
416
+ # coll_dict.update({'gap': coll_dict['gap_L']})
417
+ # elif coll_dict['gap_L'] is None and coll_dict['gap_R'] is not None:
418
+ # coll_dict.update({'gap': coll_dict['gap_R']})
419
+ # elif coll_dict['gap_L'] is not None and coll_dict['gap_R'] is None:
420
+ # coll_dict.update({'gap': coll_dict['gap_L']})
421
+ # else:
422
+ # temp_items_to_print = temp_items_to_print + ['gap_L','gap_R']
321
423
  value = {}
322
424
  overwritten_keys = coll_dict['overwritten_keys']
323
425
  for key, val in coll_dict.items():
@@ -326,8 +428,7 @@ class CollimatorDatabase:
326
428
  if (key in coll_items_to_print+temp_items_to_print) and (key not in (set(fam_keys)-set(overwritten_keys))) and (val != 'both'):
327
429
  value.update({key: val})
328
430
  file.write(_format_dict_entry(coll, value, spacing=' '))
329
- file.write('\n')
330
-
431
+ file.write('\n')
331
432
 
332
433
  LHC_families = ['tcp3', 'tcsg3', 'tcsm3', 'tcla3', 'tcp7', 'tcsg7', 'tcsm7', 'tcla7', 'tcli', 'tdi', 'tcdq', 'tcstcdq', 'tcth1', 'tcth2', 'tcth5', 'tcth8', 'tctv1', 'tctv2', 'tctv5', 'tctv8', 'tclp', 'tcxrp', 'tcryo', 'tcl4', 'tcl5', 'tcl6', 'tct15', 'tct2', 'tct8', 'tcsp', 'tcld']
333
434
  with open(f'{out}.yaml', 'w') as file:
@@ -376,15 +477,15 @@ class CollimatorDatabase:
376
477
  _print_values(self._family_dict.keys(), self._family_dict, file, spacing=' - &', mapping=True)
377
478
 
378
479
  # Emittance section
379
- ex = self.emittance[0]
380
- ey = self.emittance[1]
480
+ ex = self.nemitt_x
481
+ ey = self.nemitt_y
381
482
  file.write(f'\nemittance:\n x: {ex}\n y: {ey}\n')
382
483
 
383
484
  # Collimators section
384
485
  file.write('\ncollimators:\n')
385
486
  b1_colls, b2_colls, bx_colls = [], [], []
386
- for coll in self._colldb.index:
387
- if coll == 'tclia.4r2' or coll == 'tclia.4l8':
487
+ for coll in self.to_pandas().index:
488
+ if coll == 'tclia.4r2' or coll == 'tclia.4l8': # TODO: hardcoded!!!
388
489
  b1_colls.append(coll)
389
490
  b2_colls.append(coll)
390
491
  elif coll[-2:] == 'b1':
@@ -393,7 +494,7 @@ class CollimatorDatabase:
393
494
  b2_colls.append(coll)
394
495
  else:
395
496
  bx_colls.append(coll)
396
-
497
+
397
498
  # Handle special cases for collimators
398
499
  if (('tclia.4r2' in b1_colls) or ('tclia.4l8' in b1_colls)) and (len(b1_colls) <= 2):
399
500
  b1_colls = []
@@ -410,701 +511,129 @@ class CollimatorDatabase:
410
511
  print('WARNING -- some collimators could not be assigned to b1 or b2. Tracking might not work with those collimators. Please manually change the output file if necessary.')
411
512
 
412
513
 
413
- def __init__(self, **kwargs):
414
- # Get all arguments
415
- for var in self._init_vars:
416
- if var in self._init_var_defaults:
417
- kwargs.setdefault(var, self._init_var_defaults[var])
418
- elif var not in kwargs.keys():
419
- raise ValueError(f"CollimatorDatabase is missing required argument '{var}'!")
420
-
421
- self._optics = pd.DataFrame(columns=['x', 'px', 'y', 'py', 'betx', 'bety', 'alfx', 'alfy', 'dx', 'dy'])
422
- self._parse_dict(kwargs['collimator_dict'], kwargs['family_dict'],
423
- kwargs['beam'], kwargs['_yaml_merged'], kwargs.get('ignore_crystals', True))
424
- self.emittance = [kwargs['nemitt_x'], kwargs['nemitt_y']]
425
- self._beta_gamma_rel = None
426
-
427
-
428
- def __getitem__(self, name):
429
- return CollimatorSettings(name, self._colldb)
430
-
431
- def to_pandas(self):
432
- return pd.DataFrame({
433
- 's_center': self.s_center,
434
- 'gap': self.gap,
435
- 'jaw': self.jaw,
436
- 'beam_size': self.beam_size,
437
- 'aligned_to': self.align_to,
438
- 'angle': self.angle,
439
- 'material': self.material,
440
- # 'offset': self.offset,
441
- # 'tilt': self.tilt,
442
- 'stage': self.stage,
443
- 'active_length': self.active_length,
444
- 'collimator_type': self.collimator_type,
445
- }, index=self.name)
446
-
447
-
448
- def _parse_dict(self, coll, fam, beam=None, _yaml_merged=False, ignore_crystals=True):
449
-
450
- # We make all keys case-insensitive to avoid confusion between different conventions
451
- coll = _dict_keys_to_lower(coll)
452
- fam = _dict_keys_to_lower(fam)
453
-
454
- # The dictionary can be a CollimatorDatabase for a single beam (beam=None)
455
- # or for both beams (beam='b1' or beam='b2)
456
- coll = _get_coll_dct_by_beam(coll, beam)
457
-
458
- # Apply family settings
459
- crystals = []
460
- for thiscoll, settings in coll.items():
461
- settings = {k.lower(): v for k,v in settings.items()}
462
- if 'family' in settings.keys() and settings['family'] is not None:
463
- settings['family'] = settings['family'].lower()
464
- thisfam = settings['family']
465
- if thisfam not in fam.keys():
466
- raise ValueError(f"Collimator {thiscoll} depends on family {thisfam}, "
467
- + f"but the latter is not defined!")
468
-
469
- # Check if some family settings are overwritten for this collimator
470
- # Only do this check if we didn't do a YAML merge earlier (because then it
471
- # is already taken care of)
472
- if not _yaml_merged:
473
- overwritten_keys = [key.lower() for key in settings.keys() if key in fam[thisfam]]
474
- if len(overwritten_keys) > 0:
475
- settings['overwritten_keys'] = overwritten_keys
476
-
477
- # Load family settings, potentially overwriting settings for this collimator
478
- settings = {**fam[thisfam], **settings}
479
-
480
- else:
481
- settings['family'] = None
482
- coll[thiscoll] = settings
483
-
484
- # Save list of crystals
485
- if 'crystal' in settings:
486
- if settings['crystal'] != 0.0:
487
- crystals += [thiscoll]
488
- else:
489
- settings['crystal'] = None
490
-
491
- # Remove crystals from colldb
492
- if ignore_crystals:
493
- for thiscoll in crystals:
494
- del coll[thiscoll]
495
-
496
- # Check that all collimators have gap settings
497
- if not np.all(['gap' in val.keys() or 'opening' in val.keys() for val in coll.values()]):
498
- raise ValueError("Ill-defined CollimatorDatabase: Not all collimators have a gap or "
499
- + "opening setting, (or the keys / structure of the dictionary is wrong)!")
500
-
501
- # Update collimators with default values for missing keys
502
- for collimator in coll.values():
503
- # Change all values to lower case
504
- for key, val in collimator.items():
505
- collimator[key] = val.lower() if isinstance(val, str) else val
506
- if 'length' in collimator.keys():
507
- collimator['active_length'] = collimator.pop('length')
508
- if 'gap' in collimator.keys():
509
- if collimator['gap'] is not None and collimator['gap'] > 900:
510
- collimator['gap'] = None
511
- if 'side' in collimator.keys() and collimator['side'] == 'left':
512
- collimator['gap_L'] = collimator.pop('gap')
513
- collimator['gap_R'] = None
514
- elif 'side' in collimator.keys() and collimator['side'] == 'right':
515
- collimator['gap_L'] = None
516
- collimator['gap_R'] = collimator.pop('gap')
517
- else:
518
- collimator['gap_L'] = collimator['gap']
519
- collimator['gap_R'] = collimator.pop('gap')
520
- if 'angle' in collimator.keys():
521
- collimator['angle_L'] = collimator['angle']
522
- collimator['angle_R'] = collimator.pop('angle')
523
- _initialise_None(collimator)
524
-
525
- self._collimator_dict = coll
526
- self._family_dict = fam
527
- self._colldb = pd.DataFrame(coll).transpose()
528
-
529
-
530
- @property
531
- def name(self):
532
- return self._colldb.index.values
533
-
534
-
535
- # TODO: - VALIDATION OF TYPES (e.g. material, stage, align, ..)
536
- # - IMPLEMENTATION OF TILT
537
- # - CRYSTAL PROPERTIES: only valid if crystal == True (add mask to _set_property?)
538
- # make second dataframe for crystals
539
- # - show as __repr__
540
-
541
- # The CollimatorDatabase class has the following fields (those marked
542
- # with an * are set automatically and cannot be overwritten):
543
- # - name
544
- # - gap
545
- # - jaw *
546
- # - beam_size *
547
- # - s_center *
548
- # - angle
549
- # - material
550
- # - offset
551
- # - tilt
552
- # - stage
553
- # - side
554
- # - active_length
555
- # - inactive_front
556
- # - inactive_back
557
- # - total_length *
558
- # - collimator_type *
559
- # - betx
560
- # - bety
561
- # - x
562
- # - px
563
- # - y
564
- # - py
565
- # - gamma_rel
566
- # - emit
567
-
568
- @property
569
- def angle(self):
570
- # angles = np.array([self._colldb.angle_L.values,self._colldb.angle_R.values])
571
- # return pd.Series([ L if L == R else [L,R] for L, R in angles.T ], index=self._colldb.index, dtype=object)
572
- return self._colldb['angle_L']
573
-
574
- @angle.setter
575
- def angle(self, angle):
576
- self._set_property_LR('angle', angle)
577
- self._compute_jaws()
578
-
579
- @property
580
- def material(self):
581
- return self._colldb['material']
582
-
583
- @material.setter
584
- def material(self, material):
585
- self._set_property('material', material)
586
-
587
- @property
588
- def offset(self):
589
- return self._colldb['offset']
590
-
591
- @offset.setter
592
- def offset(self, offset):
593
- self._set_property('offset', offset, single_default_allowed=True)
594
- self._compute_jaws()
595
-
596
- @property
597
- def tilt(self):
598
- tilts = np.array([self._colldb.tilt_L.values,self._colldb.tilt_R.values])
599
- return pd.Series([ L if L == R else [L,R] for L, R in tilts.T ], index=self._colldb.index, dtype=object)
600
-
601
- @tilt.setter
602
- def tilt(self, tilts):
603
- self._set_property_LR('tilt', tilts)
604
- self._compute_jaws()
605
-
606
- @property
607
- def stage(self):
608
- return self._colldb['stage']
609
-
610
- @stage.setter
611
- def stage(self, stage):
612
- self._set_property('stage', stage)
613
-
614
- @property
615
- def parking(self):
616
- return self._colldb['parking']
617
-
618
- @parking.setter
619
- def parking(self, parking):
620
- self._set_property('parking', parking, single_default_allowed=True)
621
- self._compute_jaws()
622
-
623
- @property
624
- def active(self):
625
- return self._colldb['active']
626
-
627
- @active.setter
628
- def active(self, active):
629
- self._set_property('active', active, single_default_allowed=True)
630
-
631
- # @property
632
- # def crystal(self):
633
- # return self._colldb['crystal']
634
-
635
- # @crystal.setter
636
- # def crystal(self, crystal):
637
- # self._set_property('crystal', crystal)
638
-
639
- # @property
640
- # def bend(self):
641
- # return self._colldb['bend']
642
-
643
- # @bend.setter
644
- # def bend(self, bend):
645
- # self._set_property('bend', bend)
646
-
647
- # @property
648
- # def xdim(self):
649
- # return self._colldb['xdim']
650
-
651
- # @xdim.setter
652
- # def xdim(self, xdim):
653
- # self._set_property('xdim', xdim)
654
-
655
- # @property
656
- # def ydim(self):
657
- # return self._colldb['ydim']
658
-
659
- # @ydim.setter
660
- # def ydim(self, ydim):
661
- # self._set_property('ydim', ydim)
662
-
663
- # @property
664
- # def miscut(self):
665
- # return self._colldb['miscut']
666
-
667
- # @miscut.setter
668
- # def miscut(self, miscut):
669
- # self._set_property('miscut', miscut)
670
-
671
- # @property
672
- # def thick(self):
673
- # return self._colldb['thick']
674
-
675
- # @thick.setter
676
- # def thick(self, thick):
677
- # self._set_property('thick', thick)
678
-
679
- @property
680
- def s_center(self):
681
- return self._colldb['s_center']
682
-
683
- @property
684
- def collimator_type(self):
685
- return self._colldb['collimator_type']
686
-
687
- @property
688
- def active_length(self):
689
- return self._colldb['active_length']
690
-
691
- @active_length.setter
692
- def active_length(self, length):
693
- self._set_property('active_length', length)
694
- self.align_to = {}
695
-
696
- @property
697
- def inactive_front(self):
698
- return self._colldb['inactive_front']
699
-
700
- @inactive_front.setter
701
- def inactive_front(self, length):
702
- self._set_property('inactive_front', length)
703
-
704
- @property
705
- def inactive_back(self):
706
- return self._colldb['inactive_back']
707
-
708
- @inactive_back.setter
709
- def inactive_back(self, length):
710
- self._set_property('inactive_back', length)
711
-
712
- @property
713
- def total_length(self):
714
- return self._colldb['active_length'] + self._colldb['inactive_front'] + self._colldb['inactive_back']
715
-
716
- @property
717
- def gap(self):
718
- gaps = np.array([self._colldb.gap_L.values,self._colldb.gap_R.values])
719
- return pd.Series([ L if L == R else [L,R] for L, R in gaps.T ], index=self._colldb.index, dtype=object)
720
-
721
- @gap.setter
722
- def gap(self, gaps):
723
- df = self._colldb
724
- correct_format = False
725
- # The variable gaps is a Series or a list
726
- if isinstance(gaps, pd.Series) or isinstance(gaps, list) or isinstance(gaps, np.ndarray):
727
- correct_format = True
728
- if len(gaps) != len(self.name):
729
- raise ValueError("The variable 'gaps' has a different length than the number "
730
- + "of collimators in the CollimatorDatabase. Use a dictionary instead.")
731
- # Some of the gaps are list (e.g. two different values for both gaps): loop over gaps as dict
732
- if any(hasattr(gap, '__iter__') for gap in gaps):
733
- gaps = dict(zip(self.name, gaps))
734
- # All gaps are single values: use pandas-style assignment
514
+ # ====================================
515
+ # ====== Installing collimators ======
516
+ # ====================================
517
+
518
+ def _get_names_from_line(self, line, names, families):
519
+ if names is None and families is None:
520
+ names = self.collimator_names
521
+ elif names is None:
522
+ names = self.get_collimators_from_family(families)
523
+ elif families is not None:
524
+ names.append(self.get_collimators_from_family(families))
525
+ return list(set(names)) # Remove duplicates
526
+
527
+ def _check_installed(self, line, name, collimator_class):
528
+ # Check that collimator is not installed as different type
529
+ # TODO: automatically replace collimator type and print warning
530
+ if isinstance(line[name], _all_collimator_classes):
531
+ raise ValueError(f"Trying to install {name} as {collimator_class.__name__}, "
532
+ + f"but it is already installed as {line[name].__class__.__name__}!\n"
533
+ + f"Please reconstruct the line.")
534
+ # TODO: only allow Marker elements, no Drifts!!
535
+ # How to do this with importing a line for MAD-X or SixTrack...?
536
+ # Maybe we want a DriftCollimator type in Xtrack as a general placeholder
537
+ elif not isinstance(line[name], (xt.Marker, xt.Drift)):
538
+ raise ValueError(f"Trying to install {name} as {collimator_class.__name__}, "
539
+ + f"but the line element to replace is not an xtrack.Marker "
540
+ + f"(or xtrack.Drift)!\nPlease check the name, or correct the "
541
+ + f"element.")
542
+
543
+ def _create_collimator(self, line, collimator_class, name, **kwargs):
544
+ assert issubclass(collimator_class, BaseCollimator)
545
+ self._check_installed(line, name, collimator_class)
546
+ if kwargs.pop('verbose', False):
547
+ print(f"Installing {name:20} as {collimator_class.__name__}")
548
+ el = collimator_class(gap=self[name]['gap'], angle=self[name]['angle'],
549
+ length=self[name]['length'], side=self[name]['side'],
550
+ _tracking=False, **kwargs)
551
+ el.emittance = [self.nemitt_x, self.nemitt_y]
552
+ self._elements[name] = el
553
+
554
+ def _create_crystal(self, line, crystal_class, name, **kwargs):
555
+ assert issubclass(crystal_class, BaseCrystal)
556
+ self._check_installed(line, name, crystal_class)
557
+ if kwargs.pop('verbose', False):
558
+ print(f"Installing {name:20} as {crystal_class.__name__}")
559
+ el = crystal_class(gap=self[name]['gap'], angle=self[name]['angle'],
560
+ length=self[name]['length'], side=self[name]['side'],
561
+ bending_radius=self[name]['bending_radius'],
562
+ width=self[name]['width'], height=self[name]['height'],
563
+ _tracking=False, **kwargs)
564
+ el.emittance = [self.nemitt_x, self.nemitt_y]
565
+ self._elements[name] = el
566
+
567
+ def install_black_absorbers(self, line, *, names=None, families=None, verbose=False, need_apertures=True):
568
+ names = self._get_names_from_line(line, names, families)
569
+ for name in names:
570
+ if self[name]['bending_radius'] is None:
571
+ self._create_collimator(line, BlackAbsorber, name, verbose=verbose)
735
572
  else:
736
- # mask those that have an active side for the gap under consideration
737
- # and have a setting less than 900; the others are set to None
738
- mask_L = np.logical_and(df.side.isin(['both','left']), ~(gaps >= 900))
739
- mask_R = np.logical_and(df.side.isin(['both','right']), ~(gaps >= 900))
740
- df.loc[mask_L, 'gap_L'] = gaps[mask_L]
741
- df.loc[~mask_L, 'gap_L'] = None
742
- df.loc[mask_R, 'gap_R'] = gaps[mask_R]
743
- df.loc[~mask_R, 'gap_R'] = None
744
-
745
- # The variable gaps is a dictionary
746
- if isinstance(gaps, dict):
747
- correct_format = True
748
- for name, gap in gaps.items():
749
- if name not in self.name:
750
- raise ValueError(f"Collimator {name} not found in CollimatorDatabase!")
751
- side = df.side[name]
752
- if hasattr(gap, '__iter__'):
753
- if isinstance(gap, str):
754
- raise ValueError("The gap setting has to be a number!")
755
- elif len(gap) == 2:
756
- gap_L = gap[0]
757
- gap_R = gap[1]
758
- if side != 'both':
759
- if side == 'left' and gap_R is not None:
760
- print(f"Warning: collimator {name} is left-sided but a finite right gap is specified. "
761
- + "Verify that this is what you want.")
762
- elif side == 'right' and gap_L is not None:
763
- print(f"Warning: collimator {name} is right-sided but a finite left gap is specified. "
764
- + "Verify that this is what you want.")
765
- elif len(gap) == 1:
766
- gap_L = gap[0] if side in ['both','left'] else None
767
- gap_R = gap[0] if side in ['both','right'] else None
768
- else:
769
- raise ValueError("The gap setting must have one or two values (for the left and the right jaw)!")
770
- else:
771
- gap_L = gap if side in ['both','left'] else None
772
- gap_R = gap if side in ['both','right'] else None
773
- gap_L = None if (gap_L is not None and gap_L >= 900) else gap_L
774
- gap_R = None if (gap_R is not None and gap_R >= 900) else gap_R
775
- df.loc[name, 'gap_L'] = gap_L
776
- df.loc[name, 'gap_R'] = gap_R
777
-
778
- if not correct_format:
779
- raise ValueError("Variable 'gaps' needs to be a pandas Series, dict, numpy array, or list!")
780
-
781
- df.gap_L = df.gap_L.astype('object', copy=False)
782
- df.gap_R = df.gap_R.astype('object', copy=False)
783
- self._compute_jaws()
784
-
785
- @property
786
- def jaw(self):
787
- jaws = list(np.array([
788
- self._colldb.jaw_LU.values,
789
- self._colldb.jaw_RU.values,
790
- self._colldb.jaw_LD.values,
791
- self._colldb.jaw_RD.values
792
- ]).T)
793
- # Need special treatment if there are None's
794
- def flip(jaw):
795
- return None if jaw is None else -jaw
796
- for i, jaw in enumerate(jaws):
797
- # All 4 jaw points are the same
798
- if jaw[0] == flip(jaw[1]) == jaw[2] == flip(jaw[3]):
799
- jaws[i] = jaw[0]
800
- # Upstream and downstream jaws are the same
801
- # (all cases except angular alignment and/or tilt)
802
- elif jaw[0] == jaw[2] and jaw[1] == jaw[3]:
803
- jaws[i] = [ jaw[0], jaw[1] ]
573
+ self._create_crystal(line, BlackCrystal, name, verbose=verbose)
574
+ elements = [self._elements[name] for name in names]
575
+ install_elements(line, names, elements, need_apertures=need_apertures)
576
+
577
+ def install_everest_collimators(self, line, *, names=None, families=None, verbose=False, need_apertures=True):
578
+ names = self._get_names_from_line(line, names, families)
579
+ for name in names:
580
+ mat = SixTrack_to_xcoll(self[name]['material'])
581
+ if self[name]['bending_radius'] is None:
582
+ self._create_collimator(line, EverestCollimator, name, material=mat[0],
583
+ verbose=verbose)
804
584
  else:
805
- jaws[i] = [ [jaw[0],jaw[1]], [jaw[2],jaw[3]] ]
806
- return pd.Series(jaws, index=self._colldb.index, dtype=object)
585
+ self._create_crystal(line, EverestCrystal, name, material=mat[1],
586
+ lattice=self[name]['crystal'], verbose=verbose,
587
+ miscut=self[name]['miscut'])
588
+ elements = [self._elements[name] for name in names]
589
+ install_elements(line, names, elements, need_apertures=need_apertures)
807
590
 
808
- @property
809
- def side(self):
810
- return self._colldb.side
811
591
 
812
- @side.setter
813
- def side(self, sides):
814
- self._set_property('side', sides, single_default_allowed=True)
815
- self.gap = self.gap
592
+ # ==================================
593
+ # ====== Accessing attributes ======
594
+ # ==================================
816
595
 
817
596
  @property
818
- def gamma_rel(self):
819
- return np.sqrt(self._beta_gamma_rel**2+1)
820
-
821
- @gamma_rel.setter
822
- def gamma_rel(self, gamma_rel):
823
- self._beta_gamma_rel = np.sqrt(gamma_rel**2-1)
824
- self._compute_jaws()
597
+ def collimator_names(self):
598
+ return list(self._collimator_dict.keys())
825
599
 
826
600
  @property
827
- def emittance(self):
828
- return [self._emitx, self._emity]
829
-
830
- @emittance.setter
831
- def emittance(self, emit):
832
- if hasattr(emit, '__iter__'):
833
- if isinstance(emit, str):
834
- raise ValueError(f"The 'emit' setting has to be a number!")
835
- elif len(emit) == 2:
836
- self._emitx = emit[0]
837
- self._emity = emit[1]
838
- elif len(emit) == 1:
839
- self._emitx = emit[0]
840
- self._emity = emit[0]
601
+ def collimator_families(self):
602
+ families = {fam: [] for fam in self._family_dict.keys()}
603
+ families["no family"] = []
604
+ for name in self.collimator_names:
605
+ if 'family' not in self[name] or self[name]['family'].lower() == 'unknown':
606
+ families["no family"].append(name)
841
607
  else:
842
- raise ValueError(f"The 'emit' setting must have one or two values (for emitx and emity)!")
843
- else:
844
- self._emitx = emit
845
- self._emity = emit
846
- self._compute_jaws()
847
-
848
- @property
849
- def align_to(self):
850
- return self._colldb.align_to
851
-
852
- @align_to.setter
853
- def align_to(self, align):
854
- self._set_property('align_to', align, single_default_allowed=True, limit_to=['front', 'center', 'back', 'angular'])
855
- if np.any(self.align_to == 'maximum'):
856
- raise NotImplementedError
857
- s_front = self.s_center - self.active_length/2
858
- s_center = self.s_center
859
- s_back = self.s_center + self.active_length/2
860
- mask = self.align_to == 'front'
861
- self._colldb.loc[mask,'s_align_front'] = s_front[mask]
862
- self._colldb.loc[mask,'s_align_back'] = s_front[mask]
863
- mask = self.align_to == 'center'
864
- self._colldb.loc[mask,'s_align_front'] = s_center[mask]
865
- self._colldb.loc[mask,'s_align_back'] = s_center[mask]
866
- mask = self.align_to == 'back'
867
- self._colldb.loc[mask,'s_align_front'] = s_back[mask]
868
- self._colldb.loc[mask,'s_align_back'] = s_back[mask]
869
- mask = self.align_to == 'angular'
870
- self._colldb.loc[mask,'s_align_front'] = s_front[mask]
871
- self._colldb.loc[mask,'s_align_back'] = s_back[mask]
872
- self._compute_jaws()
873
-
874
- # TODO: when does this need to be unset?
875
- @property
876
- def _optics_is_ready(self):
877
- pos = set(self._colldb.s_align_front.values) | set(self._colldb.s_align_back.values)
878
- return np.all([s in self._optics.index for s in pos]) and self._beta_gamma_rel is not None
879
-
880
- @property
881
- def betx(self):
882
- vals = np.array([
883
- [ self._optics.loc[s,'betx'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
884
- [ self._optics.loc[s,'betx'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
885
- ])
886
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
887
-
888
- @property
889
- def bety(self):
890
- vals = np.array([
891
- [ self._optics.loc[s,'bety'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
892
- [ self._optics.loc[s,'bety'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
893
- ])
894
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
895
-
896
- @property
897
- def alfx(self):
898
- vals = np.array([
899
- [ self._optics.loc[s,'alfx'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
900
- [ self._optics.loc[s,'alfx'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
901
- ])
902
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
903
-
904
- @property
905
- def alfy(self):
906
- vals = np.array([
907
- [ self._optics.loc[s,'alfy'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
908
- [ self._optics.loc[s,'alfy'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
909
- ])
910
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
911
-
912
- @property
913
- def dx(self):
914
- vals = np.array([
915
- [ self._optics.loc[s,'dx'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
916
- [ self._optics.loc[s,'dx'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
917
- ])
918
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
919
-
920
- @property
921
- def dy(self):
922
- vals = np.array([
923
- [ self._optics.loc[s,'dy'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
924
- [ self._optics.loc[s,'dy'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
925
- ])
926
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
927
-
928
- @property
929
- def x(self):
930
- vals = np.array([
931
- [ self._optics.loc[s,'x'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
932
- [ self._optics.loc[s,'x'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
933
- ])
934
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
935
-
936
- @property
937
- def px(self):
938
- vals = np.array([
939
- [ self._optics.loc[s,'px'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
940
- [ self._optics.loc[s,'px'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
941
- ])
942
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
943
-
944
- @property
945
- def y(self):
946
- vals = np.array([
947
- [ self._optics.loc[s,'y'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
948
- [ self._optics.loc[s,'y'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
949
- ])
950
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
608
+ families[self[name]['family']].append(name)
609
+ return families
610
+
611
+ def get_collimators_from_family(self, family):
612
+ if not hasattr(family, '__iter__') and not isinstance(family, str):
613
+ family = [family]
614
+ result = []
615
+ for fam in family:
616
+ if fam not in self.collimator_families:
617
+ raise ValueError(f"Family '{fam}' not found in CollimatorDatabase!")
618
+ result += self.collimator_families[fam]
619
+ return result
951
620
 
952
621
  @property
953
- def py(self):
954
- vals = np.array([
955
- [ self._optics.loc[s,'py'] if s in self._optics.index else None for s in self._colldb.s_align_front.values ],
956
- [ self._optics.loc[s,'py'] if s in self._optics.index else None for s in self._colldb.s_align_back.values ]
957
- ])
958
- return pd.Series([ F if F == B else [F,B] for F,B in vals.T ], index=self._colldb.index, dtype=object)
622
+ def properties(self):
623
+ return {attr for d in self._collimator_dict.values() for attr in d.keys()}
959
624
 
960
- @property
961
- def beam_size(self):
962
- if self._optics_is_ready:
963
- beam_size = np.array([self._beam_size_front,self._beam_size_back])
964
- return pd.Series([ F if F == B else [F,B] for F, B in beam_size.T ], index=self._colldb.index, dtype=object)
625
+ def __getattr__(self, attr):
626
+ if attr in self.properties:
627
+ # TODO: include families
628
+ return {kk: vv.get(attr, None) for kk, vv in self._collimator_dict.items()}
965
629
  else:
966
- return None
967
-
968
- @property
969
- def _beam_size_front(self):
970
- # TODO: curretnly only for angle_L
971
- df = self._colldb
972
- opt = self._optics
973
- betx = opt.loc[df.s_align_front,'betx'].astype(float)
974
- bety = opt.loc[df.s_align_front,'bety'].astype(float)
975
- sigmax = np.sqrt(betx*self._emitx/self._beta_gamma_rel)
976
- sigmay = np.sqrt(bety*self._emity/self._beta_gamma_rel)
977
- result = np.sqrt(
978
- (sigmax*np.cos(np.float_(df.angle_L.values)*np.pi/180))**2
979
- + (sigmay*np.sin(np.float_(df.angle_L.values)*np.pi/180))**2
980
- )
981
- result.index = self._colldb.index
982
- return result
630
+ raise ValueError(f"Property `{attr}` not present in CollimatorDatabase!")
983
631
 
984
- @property
985
- def _beam_size_back(self):
986
- # TODO: curretnly only for angle_L
987
- df = self._colldb
988
- opt = self._optics
989
- betx = opt.loc[df.s_align_back,'betx'].astype(float)
990
- bety = opt.loc[df.s_align_back,'bety'].astype(float)
991
- sigmax = np.sqrt(betx*self._emitx/self._beta_gamma_rel)
992
- sigmay = np.sqrt(bety*self._emity/self._beta_gamma_rel)
993
- result = np.sqrt(
994
- (sigmax*np.cos(np.float_(df.angle_L.values)*np.pi/180))**2
995
- + (sigmay*np.sin(np.float_(df.angle_L.values)*np.pi/180))**2
996
- )
997
- result.index = self._colldb.index
998
- return result
999
-
1000
- # parking is defined with respect to closed orbit
1001
- # TODO: tilt
1002
- # 'upstr' => 'front' en 'downstr' => 'back'
1003
- def _compute_jaws(self):
1004
- if self._optics_is_ready:
1005
- df = self._colldb
1006
- beam_size_front = self._beam_size_front
1007
- beam_size_back = self._beam_size_back
1008
- jaw_LU = df['gap_L']*beam_size_front + self.offset
1009
- jaw_RU = df['gap_R']*beam_size_front - self.offset
1010
- jaw_LD = df['gap_L']*beam_size_back + self.offset
1011
- jaw_RD = df['gap_R']*beam_size_back - self.offset
1012
- df['jaw_LU'] = df['parking'] if df['gap_L'] is None else np.minimum(jaw_LU,df['parking'])
1013
- df['jaw_RU'] = -df['parking'] if df['gap_R'] is None else -np.minimum(jaw_RU,df['parking'])
1014
- df['jaw_LD'] = df['parking'] if df['gap_L'] is None else np.minimum(jaw_LD,df['parking'])
1015
- df['jaw_RD'] = -df['parking'] if df['gap_R'] is None else -np.minimum(jaw_RD,df['parking'])
1016
- # align crystals
1017
- opt = self._optics
1018
- df['align_angle'] = None
1019
- cry_mask = [c is not None for c in df.crystal]
1020
- df_cry = df[cry_mask]
1021
- if len(df_cry) > 0:
1022
- alfx = opt.loc[df_cry.s_align_front,'alfx'].astype(float).values
1023
- alfy = opt.loc[df_cry.s_align_front,'alfy'].astype(float).values
1024
- betx = opt.loc[df_cry.s_align_front,'betx'].astype(float).values
1025
- bety = opt.loc[df_cry.s_align_front,'bety'].astype(float).values
1026
- align_angle_x = -np.sqrt(self._emitx/self._beta_gamma_rel/betx)*alfx
1027
- align_angle_y = -np.sqrt(self._emity/self._beta_gamma_rel/bety)*alfy
1028
- align_angle = np.array([x if abs(ang) < 1e-6 else y
1029
- for x,y,ang in zip(align_angle_x,align_angle_y,df_cry.angle_L.values)])
1030
- df.loc[cry_mask, 'align_angle'] = align_angle*df_cry['gap_L']
1031
-
1032
-
1033
- # ---------------------------------------
1034
- # ------ Property setter functions ------
1035
- # ---------------------------------------
1036
-
1037
- def _set_property(self, prop, vals, single_default_allowed=False, limit_to=[]):
1038
- df = self._colldb
1039
- if not isinstance(limit_to, (list, tuple, set)):
1040
- limit_to = [limit_to]
1041
- if isinstance(vals, dict):
1042
- for name, val in vals.items():
1043
- if name not in self.name:
1044
- raise ValueError(f"Collimator {name} not found in CollimatorDatabase!")
1045
- if limit_to!=[] and val not in limit_to:
1046
- raise ValueError(f"Cannot set {prop} to {val}. Choose from {limit_to}!")
1047
- df.loc[name, prop] = val
1048
- elif isinstance(vals, pd.Series) or isinstance(vals, list) or isinstance(vals, np.ndarray):
1049
- if len(vals) != len(self.name):
1050
- raise ValueError(f"The variable '{prop}' has a different length than the number of "
1051
- + "collimators in the CollimatorDatabase. Use a dictionary instead.")
1052
- if limit_to!=[] and np.any([val not in limit_to for val in vals]):
1053
- raise ValueError(f"Cannot set {prop} to {vals}. Choose from {limit_to}!")
1054
- df[prop] = vals
632
+ def __getitem__(self, name):
633
+ if name in self._family_dict:
634
+ return self._family_dict[name]
635
+ elif name in self._collimator_dict:
636
+ return self._collimator_dict[name]
1055
637
  else:
1056
- if single_default_allowed:
1057
- if limit_to!=[] and vals not in limit_to:
1058
- raise ValueError(f"Cannot set {prop} to {vals}. Choose from {limit_to}!")
1059
- df[prop] = vals
1060
- else:
1061
- raise ValueError(f"Variable '{prop}' needs to be a pandas Series, dict, numpy array, or list!")
1062
-
1063
-
1064
- def _set_property_LR(self, prop, vals):
1065
- df = self._colldb
1066
- correct_format = False
1067
- # The variable vals is a Series or a list
1068
- if isinstance(vals, pd.Series) or isinstance(vals, list) or isinstance(vals, np.ndarray):
1069
- correct_format = True
1070
- if len(vals) != len(self.name):
1071
- raise ValueError(f"The variable '{prop}' has a different length than the number of "
1072
- + "collimators in the CollimatorDatabase. Use a dictionary instead.")
1073
- # Some of the vals are list (e.g. two different values for both gaps): loop over vals as dict
1074
- if any(hasattr(val, '__iter__') for val in vals):
1075
- vals = dict(zip(self.name, vals))
1076
- # All gaps are single values: use pandas-style assignment
1077
- else:
1078
- df[prop + "_L"] = vals
1079
- df[prop + "_R"] = vals
1080
-
1081
- # The variable vals is a dictionary
1082
- if isinstance(vals, dict):
1083
- correct_format = True
1084
- for name, val in vals.items():
1085
- if name not in self.name:
1086
- raise ValueError(f"Collimator {name} not found in CollimatorDatabase!")
1087
- if hasattr(val, '__iter__'):
1088
- if isinstance(val, str):
1089
- raise ValueError(f"The '{prop}' setting has to be a number!")
1090
- elif len(val) == 2:
1091
- val_L = val[0]
1092
- val_R = val[1]
1093
- elif len(val) == 1:
1094
- val_L = val[0]
1095
- val_R = val[0]
1096
- else:
1097
- raise ValueError(f"The '{prop}' setting must have one or two values (for the left and the right jaw)!")
1098
- else:
1099
- val_L = val
1100
- val_R = val
1101
- df.loc[name, prop + "_L"] = val_L
1102
- df.loc[name, prop + "_R"] = val_R
1103
-
1104
- if not correct_format:
1105
- raise ValueError("Variable '{prop}' needs to be a pandas Series, dict, numpy array, or list!")
1106
-
1107
- df[prop + "_L"] = df[prop + "_L"].astype('object', copy=False)
1108
- df[prop + "_R"] = df[prop + "_R"].astype('object', copy=False)
1109
- # Check if collimator active
1110
- # Check if gap is list (assymetric jaws)
638
+ raise ValueError(f"Family nor collimator `{name}` found in CollimatorDatabase!")
639
+