htpolynet 2.6.0__tar.gz → 2.6.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 (339) hide show
  1. {htpolynet-2.6.0 → htpolynet-2.6.2}/.github/workflows/docker.yml +28 -4
  2. {htpolynet-2.6.0 → htpolynet-2.6.2}/CHANGELOG.md +240 -0
  3. {htpolynet-2.6.0 → htpolynet-2.6.2}/PKG-INFO +1 -1
  4. {htpolynet-2.6.0 → htpolynet-2.6.2}/ROADMAP.md +316 -4
  5. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/results.rst +10 -1
  6. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/container-usage.rst +15 -1
  7. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/postcure-repair.rst +202 -11
  8. {htpolynet-2.6.0 → htpolynet-2.6.2}/pyproject.toml +1 -1
  9. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/runtime.py +1 -0
  10. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/cure/curecontroller.py +64 -0
  11. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/repair/cyanate_cap.py +185 -18
  12. htpolynet-2.6.2/tests/unit/test_cap_placement.py +349 -0
  13. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_completion_bias.py +112 -0
  14. htpolynet-2.6.0/tests/unit/test_cap_placement.py +0 -115
  15. {htpolynet-2.6.0 → htpolynet-2.6.2}/.claude/settings.json +0 -0
  16. {htpolynet-2.6.0 → htpolynet-2.6.2}/.claude/skills/htpolynet/SKILL.md +0 -0
  17. {htpolynet-2.6.0 → htpolynet-2.6.2}/.envrc +0 -0
  18. {htpolynet-2.6.0 → htpolynet-2.6.2}/.github/workflows/conda-forge-sync.yml +0 -0
  19. {htpolynet-2.6.0 → htpolynet-2.6.2}/.github/workflows/release.yaml +0 -0
  20. {htpolynet-2.6.0 → htpolynet-2.6.2}/.github/workflows/test.yml +0 -0
  21. {htpolynet-2.6.0 → htpolynet-2.6.2}/.gitignore +0 -0
  22. {htpolynet-2.6.0 → htpolynet-2.6.2}/.readthedocs.yaml +0 -0
  23. {htpolynet-2.6.0 → htpolynet-2.6.2}/CITATION.cff +0 -0
  24. {htpolynet-2.6.0 → htpolynet-2.6.2}/CLAUDE.md +0 -0
  25. {htpolynet-2.6.0 → htpolynet-2.6.2}/LICENSE +0 -0
  26. {htpolynet-2.6.0 → htpolynet-2.6.2}/MANIFEST.in +0 -0
  27. {htpolynet-2.6.0 → htpolynet-2.6.2}/README.md +0 -0
  28. {htpolynet-2.6.0 → htpolynet-2.6.2}/docker/Dockerfile +0 -0
  29. {htpolynet-2.6.0 → htpolynet-2.6.2}/docker/compose.yml +0 -0
  30. {htpolynet-2.6.0 → htpolynet-2.6.2}/docker/docker-entrypoint.sh +0 -0
  31. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/Makefile +0 -0
  32. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/README.rst +0 -0
  33. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/make.bat +0 -0
  34. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/requirements.txt +0 -0
  35. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/_static/.gitkeep +0 -0
  36. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/changelog.rst +0 -0
  37. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/conf.py +0 -0
  38. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/0-liquid-styrene/configuration.rst +0 -0
  39. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/0-liquid-styrene/index.rst +0 -0
  40. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/0-liquid-styrene/introduction.rst +0 -0
  41. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/0-liquid-styrene/monomer.rst +0 -0
  42. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/0-liquid-styrene/postsim.rst +0 -0
  43. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/0-liquid-styrene/results.rst +0 -0
  44. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/0-liquid-styrene/run.rst +0 -0
  45. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/configuration.rst +0 -0
  46. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/index.rst +0 -0
  47. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/introduction.rst +0 -0
  48. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/monomer.rst +0 -0
  49. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/STY.png +0 -0
  50. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/STYCC.png +0 -0
  51. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/buildtraces.png +0 -0
  52. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/cure_info.png +0 -0
  53. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/densification-density.png +0 -0
  54. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/final-box.png +0 -0
  55. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/reaction_network.png +0 -0
  56. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/sty-coloring.tcl +0 -0
  57. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/sty-cured.png +0 -0
  58. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/sty-detail.png +0 -0
  59. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/sty-liq.png +0 -0
  60. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/pics/styrene-polymerization.png +0 -0
  61. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/postsim.rst +0 -0
  62. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/reactions.rst +0 -0
  63. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/results.rst +0 -0
  64. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/1-polystyrene/run.rst +0 -0
  65. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/configuration.rst +0 -0
  66. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/index.rst +0 -0
  67. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/introduction.rst +0 -0
  68. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/BPA.png +0 -0
  69. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/GMA.png +0 -0
  70. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/HIE.png +0 -0
  71. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/buildtraces.png +0 -0
  72. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/cure_info.png +0 -0
  73. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/densification-density.png +0 -0
  74. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/four_dimers.eps +0 -0
  75. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/four_dimers.fig +0 -0
  76. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/four_dimers.png +0 -0
  77. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/gma-sty-coloring.tcl +0 -0
  78. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/gma-sty-cured.png +0 -0
  79. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/gma-sty-detail.png +0 -0
  80. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/gma-sty-liq.png +0 -0
  81. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/p1-traces.png +0 -0
  82. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/reaction_network.png +0 -0
  83. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/vesys.eps +0 -0
  84. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/vesys.fig +0 -0
  85. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/pics/vesys.png +0 -0
  86. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/postsim.rst +0 -0
  87. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/reactions.rst +0 -0
  88. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/results.rst +0 -0
  89. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/2-bisgma-styrene-thermoset/run.rst +0 -0
  90. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/configuration.rst +0 -0
  91. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/index.rst +0 -0
  92. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/introduction.rst +0 -0
  93. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/monomers.rst +0 -0
  94. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/DGE-epoxy.png +0 -0
  95. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/DGE-labelled.png +0 -0
  96. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/PAC-2d.png +0 -0
  97. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/PAC-labelled.png +0 -0
  98. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/buildtraces.png +0 -0
  99. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/cure_info.png +0 -0
  100. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/densification-density.png +0 -0
  101. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/dge-pac-coloring.tcl +0 -0
  102. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/dge-pac-cured.png +0 -0
  103. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/dge-pac-detail.png +0 -0
  104. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/dge-pac-liq.png +0 -0
  105. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/dgesys.eps +0 -0
  106. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/dgesys.fig +0 -0
  107. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/dgesys.png +0 -0
  108. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/equil-rho_v_ns.png +0 -0
  109. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/postsim-typical.png +0 -0
  110. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/prod-e.png +0 -0
  111. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/prod-equil-rho_v_ns.png +0 -0
  112. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/prod-rho_v_ns.png +0 -0
  113. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/prod-tg.png +0 -0
  114. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/r1.png +0 -0
  115. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/r2.png +0 -0
  116. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/r3.png +0 -0
  117. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/reaction_network.png +0 -0
  118. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/rho_v_ns.png +0 -0
  119. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/short-e.png +0 -0
  120. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/pics/short-tg.png +0 -0
  121. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/postsim.rst +0 -0
  122. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/reactions.rst +0 -0
  123. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/results.rst +0 -0
  124. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/3-pacm-dgeba-epoxy-thermoset/run.rst +0 -0
  125. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/configuration.rst +0 -0
  126. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/index.rst +0 -0
  127. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/introduction.rst +0 -0
  128. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/monomers.rst +0 -0
  129. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/buildtraces.png +0 -0
  130. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/cure_info.png +0 -0
  131. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/densification-density.png +0 -0
  132. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/dfa-fde-coloring.tcl +0 -0
  133. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/dfa-fde-cured.png +0 -0
  134. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/dfa-fde-detail.png +0 -0
  135. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/dfa-fde-liq.png +0 -0
  136. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/pics/reaction_network.png +0 -0
  137. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/postsim.rst +0 -0
  138. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/reactions.rst +0 -0
  139. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/results.rst +0 -0
  140. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/4-dfda-fde-epoxy-thermoset/run.rst +0 -0
  141. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/configuration.rst +0 -0
  142. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/index.rst +0 -0
  143. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/introduction.rst +0 -0
  144. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/monomers.rst +0 -0
  145. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/buildtraces.png +0 -0
  146. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/cure_info.png +0 -0
  147. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/densification-density.png +0 -0
  148. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/htpb-coloring.tcl +0 -0
  149. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/htpb-ipdi-cured.png +0 -0
  150. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/htpb-ipdi-detail.png +0 -0
  151. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/htpb-ipdi-liq.png +0 -0
  152. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/pics/reaction_network.png +0 -0
  153. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/postsim.rst +0 -0
  154. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/reactions.rst +0 -0
  155. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/results.rst +0 -0
  156. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/5-htpb-ipdi/run.rst +0 -0
  157. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/configuration.rst +0 -0
  158. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/index.rst +0 -0
  159. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/introduction.rst +0 -0
  160. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/monomers.rst +0 -0
  161. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/badcy-coloring.tcl +0 -0
  162. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/badcy-cured.png +0 -0
  163. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/badcy-detail.png +0 -0
  164. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/badcy-liq.png +0 -0
  165. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/buildtraces.png +0 -0
  166. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/cure_info.png +0 -0
  167. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/densification-density.png +0 -0
  168. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/pics/reaction_network.png +0 -0
  169. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/postsim.rst +0 -0
  170. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/reactions.rst +0 -0
  171. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/6-cyanate-ester/run.rst +0 -0
  172. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/example-tutorials/index.rst +0 -0
  173. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/htpolynetpackage.rst +0 -0
  174. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/index.rst +0 -0
  175. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/install.rst +0 -0
  176. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/references/index.rst +0 -0
  177. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/references/mol2-reference.pdf +0 -0
  178. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/references.bib +0 -0
  179. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/release-history.rst +0 -0
  180. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/CURE.odg +0 -0
  181. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/bond_filter.odg +0 -0
  182. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/building-a-system.rst +0 -0
  183. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/configs/configs-for-analyze.rst +0 -0
  184. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/configs/configs-for-postsim.rst +0 -0
  185. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/configs/configs-for-run.rst +0 -0
  186. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/configuration-files.rst +0 -0
  187. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/flow1.odg +0 -0
  188. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/flow1yaml.odg +0 -0
  189. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/hydrogenated.eps +0 -0
  190. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/hydrogenated.fig +0 -0
  191. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/index.rst +0 -0
  192. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/molecular-structure-inputs.rst +0 -0
  193. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/STY.png +0 -0
  194. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/STYCC.png +0 -0
  195. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/TypicalUsageFlow.png +0 -0
  196. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/bond_filter.png +0 -0
  197. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/chemdoodle-2dsketcher-emb.png +0 -0
  198. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/chemdoodle-2dsketcher-styrene.png +0 -0
  199. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/hydrogenated.png +0 -0
  200. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/ring_pierce/ring_pierce_cases.png +0 -0
  201. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/pics/ring_pierce/ring_pierce_linkcell.png +0 -0
  202. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/program-flow.rst +0 -0
  203. {htpolynet-2.6.0 → htpolynet-2.6.2}/docs/source/user-guide/usage.rst +0 -0
  204. {htpolynet-2.6.0 → htpolynet-2.6.2}/scripts/check-conda-sync.py +0 -0
  205. {htpolynet-2.6.0 → htpolynet-2.6.2}/scripts/release.sh +0 -0
  206. {htpolynet-2.6.0 → htpolynet-2.6.2}/scripts/render-detail.sh +0 -0
  207. {htpolynet-2.6.0 → htpolynet-2.6.2}/scripts/render-detail.tcl +0 -0
  208. {htpolynet-2.6.0 → htpolynet-2.6.2}/scripts/render-snapshot.sh +0 -0
  209. {htpolynet-2.6.0 → htpolynet-2.6.2}/scripts/run_all_examples.sh +0 -0
  210. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/__init__.py +0 -0
  211. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/analysis/__init__.py +0 -0
  212. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/analysis/analyze.py +0 -0
  213. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/analysis/plot.py +0 -0
  214. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/analysis/postsim.py +0 -0
  215. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/analysis/utils.py +0 -0
  216. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/cli.py +0 -0
  217. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/__init__.py +0 -0
  218. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/bondtemplate.py +0 -0
  219. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/configuration.py +0 -0
  220. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/coordinates.py +0 -0
  221. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/molecule.py +0 -0
  222. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/paramcache.py +0 -0
  223. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/projectfilesystem.py +0 -0
  224. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/topocoord.py +0 -0
  225. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/core/topology.py +0 -0
  226. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/cure/__init__.py +0 -0
  227. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/cure/chain.py +0 -0
  228. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/cure/expandreactions.py +0 -0
  229. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/cure/reaction.py +0 -0
  230. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/external/__init__.py +0 -0
  231. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/external/ambertools.py +0 -0
  232. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/external/command.py +0 -0
  233. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/external/gromacs.py +0 -0
  234. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/external/slurm.py +0 -0
  235. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/external/smiles_input.py +0 -0
  236. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/external/software.py +0 -0
  237. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/geometry/__init__.py +0 -0
  238. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/geometry/bondlist.py +0 -0
  239. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/geometry/lattice.py +0 -0
  240. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/geometry/linkcell.py +0 -0
  241. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/geometry/matrix4.py +0 -0
  242. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/geometry/ring.py +0 -0
  243. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/io/__init__.py +0 -0
  244. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/io/gro.py +0 -0
  245. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/io/mol2.py +0 -0
  246. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/io/pdb.py +0 -0
  247. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/repair/__init__.py +0 -0
  248. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/repair/topology_surgery.py +0 -0
  249. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/README.md +0 -0
  250. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/__init__.py +0 -0
  251. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/claude/SKILL.md +0 -0
  252. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/example_depot/0-liquid-styrene.yaml +0 -0
  253. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/example_depot/1-polystyrene.yaml +0 -0
  254. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/example_depot/2-bisgma-styrene-thermoset.yaml +0 -0
  255. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/example_depot/3-pacm-dgeba-epoxy-thermoset.yaml +0 -0
  256. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/example_depot/4-dfda-fde-epoxy-thermoset.yaml +0 -0
  257. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/example_depot/5-htpb-ipdi.yaml +0 -0
  258. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/example_depot/6-cyanate-ester.yaml +0 -0
  259. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/README.md +0 -0
  260. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/drag-min.mdp +0 -0
  261. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/drag-npt.mdp +0 -0
  262. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/drag-nvt.mdp +0 -0
  263. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/min.mdp +0 -0
  264. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/npt.mdp +0 -0
  265. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/nvt.mdp +0 -0
  266. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/relax-min.mdp +0 -0
  267. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/relax-npt.mdp +0 -0
  268. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/relax-nvt.mdp +0 -0
  269. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/single-molecule-min.mdp +0 -0
  270. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/mdp/single-molecule-nvt.mdp +0 -0
  271. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/inputs/DFA.pdb +0 -0
  272. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/inputs/DGE.mol2 +0 -0
  273. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/inputs/EMB.mol2 +0 -0
  274. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/inputs/FDE.pdb +0 -0
  275. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/inputs/GMA.mol2 +0 -0
  276. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/inputs/PAC.mol2 +0 -0
  277. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/inputs/STY.mol2 +0 -0
  278. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/make-monomers.sh +0 -0
  279. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/pics/DFA.png +0 -0
  280. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/pics/DGE.png +0 -0
  281. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/pics/EMB.png +0 -0
  282. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/pics/FDE.png +0 -0
  283. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/pics/GMA.png +0 -0
  284. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/pics/PAC.png +0 -0
  285. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/pics/STY.png +0 -0
  286. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/sample-inputs/DFA.pdb +0 -0
  287. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/sample-inputs/DGE.mol2 +0 -0
  288. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/sample-inputs/EMB.mol2 +0 -0
  289. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/sample-inputs/FDE.pdb +0 -0
  290. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/sample-inputs/GMA.mol2 +0 -0
  291. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/sample-inputs/PAC.mol2 +0 -0
  292. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/molecules/sample-inputs/STY.mol2 +0 -0
  293. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/tcl/readbonds.tcl +0 -0
  294. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/tcl/readgrx.tcl +0 -0
  295. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/resources/tcl/render.tcl +0 -0
  296. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/__init__.py +0 -0
  297. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/banner.py +0 -0
  298. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/checkpoint.py +0 -0
  299. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/dataframetools.py +0 -0
  300. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/inputcheck.py +0 -0
  301. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/logsetup.py +0 -0
  302. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/profiling.py +0 -0
  303. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/stringthings.py +0 -0
  304. {htpolynet-2.6.0 → htpolynet-2.6.2}/src/htpolynet/utils/vmd_viz.py +0 -0
  305. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/__init__.py +0 -0
  306. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/conftest.py +0 -0
  307. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/__init__.py +0 -0
  308. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/config1.gro +0 -0
  309. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/config1.top +0 -0
  310. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/config2.gro +0 -0
  311. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/config2.top +0 -0
  312. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/items31.edr +0 -0
  313. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/items43.edr +0 -0
  314. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/items45.edr +0 -0
  315. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/fixtures/short.mdp +0 -0
  316. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_bondtemplate.py +0 -0
  317. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_chain.py +0 -0
  318. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_configuration.py +0 -0
  319. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_dataframetools.py +0 -0
  320. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_gpu_usability.py +0 -0
  321. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_gromacs_get_energy_menu.py +0 -0
  322. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_gromacs_gmx_energy_trace.py +0 -0
  323. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_inputcheck.py +0 -0
  324. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_linkcell_pierce.py +0 -0
  325. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_paramcache.py +0 -0
  326. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_paramcache_ambertools.py +0 -0
  327. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_parameterize_react.py +0 -0
  328. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_plot_smoke.py +0 -0
  329. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_projectfilesystem.py +0 -0
  330. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_repair_conversion.py +0 -0
  331. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_resources.py +0 -0
  332. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_ring.py +0 -0
  333. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_ring_pierce_figs.py +0 -0
  334. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_setup_claude.py +0 -0
  335. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_slurm_script.py +0 -0
  336. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_smiles_input.py +0 -0
  337. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_software_provenance.py +0 -0
  338. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_topology/test.top +0 -0
  339. {htpolynet-2.6.0 → htpolynet-2.6.2}/tests/unit/test_topology.py +0 -0
@@ -50,14 +50,38 @@ jobs:
50
50
 
51
51
  - name: Compute tags
52
52
  id: tags
53
+ env:
54
+ REF_NAME: ${{ github.ref_name }}
55
+ REF_TYPE: ${{ github.ref_type }}
53
56
  run: |
57
+ repo="ghcr.io/cameronabrams/htpolynet"
58
+ prefix="${{ matrix.tag_prefix }}"
54
59
  if [ "${{ matrix.variant }}" = "cuda" ]; then
55
- moving="ghcr.io/cameronabrams/htpolynet:cuda"
60
+ moving="$repo:cuda"
56
61
  else
57
- moving="ghcr.io/cameronabrams/htpolynet:latest"
62
+ moving="$repo:latest"
58
63
  fi
59
- printf 'tags<<EOF\n%s\nghcr.io/cameronabrams/htpolynet:%s%s\nEOF\n' \
60
- "$moving" "${{ matrix.tag_prefix }}" "${{ github.sha }}" >> "$GITHUB_OUTPUT"
64
+ {
65
+ echo "tags<<EOF"
66
+ echo "$moving"
67
+ echo "$repo:${prefix}${{ github.sha }}"
68
+ # A release also gets a tag people can *guess*. Until now the only
69
+ # stable name was the commit sha, so `pull ...:v2.6.0` failed with
70
+ # `manifest unknown` -- which reads like the build failed rather than
71
+ # like the tag is named something else. Emit both spellings, the git
72
+ # tag as written and the bare version, because there is no way for a
73
+ # user to know which convention this registry chose. A `d*` tag is a
74
+ # Dockerfile-only rebuild, not a release, so it gets neither.
75
+ if [ "$REF_TYPE" = "tag" ]; then
76
+ case "$REF_NAME" in
77
+ v*)
78
+ echo "$repo:${prefix}${REF_NAME}"
79
+ echo "$repo:${prefix}${REF_NAME#v}"
80
+ ;;
81
+ esac
82
+ fi
83
+ echo "EOF"
84
+ } >> "$GITHUB_OUTPUT"
61
85
 
62
86
  - name: Build and push
63
87
  uses: docker/build-push-action@v6
@@ -7,6 +7,246 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.6.2] - 2026-08-31
11
+
12
+ ### Fixed
13
+
14
+ - **The too-few-iterations warning was silent on the failure it exists to
15
+ catch.** `check_iterations_vs_functionality` returned early whenever the
16
+ cure ran at least `f` iterations, so it fired only for the counting
17
+ impossibility `n < f`. But `n >= f` only makes completion *possible*. The
18
+ bonds a cure forms are not spread evenly across its iterations -- the
19
+ per-iteration count decays steeply, and it is the last iteration that has to
20
+ supply each crosslinker its final bond -- so a cure that runs exactly `f`
21
+ iterations and spends its last one on almost nothing arrives at the same
22
+ place as one that ran too few. A build did exactly that: three iterations
23
+ against a functionality of three, target bond conversion reached, last
24
+ iteration spent on 9 bonds, and **one complete crosslinker out of 240**,
25
+ with nothing in the log about it. The system it wrote is a monomer melt
26
+ that equilibrates and reports a sensible density.
27
+
28
+ The check now tests the outcome rather than the precondition, which needs no
29
+ new measurement: by the time it runs, how many crosslinkers reacted at all
30
+ of their sites is exactly known. It logs that count on every cure and warns
31
+ when the fraction falls below the crosslinker conversion an ideal randomly
32
+ branching network of the same functionality would show at its gel point --
33
+ 12.5 % for a trifunctional crosslinker. That figure is an idealization and
34
+ is used only to decide when to raise the volume; the count itself is exact
35
+ and is reported either way. The `n < f` case keeps its own message, because
36
+ there the cause is known exactly and worth naming.
37
+
38
+ The regression test suite had the bug written into it: a test asserted that
39
+ a run at exactly `f` iterations with no complete crosslinkers stays silent.
40
+
41
+ ### Changed
42
+
43
+ - **`min_clearance_nm` is documented as a placement outcome, not a tail
44
+ statistic.** 2.6.1's docs said `min_clearance_nm` and `n_below_target` were
45
+ the tail and were what `cap_min_clearance` should be calibrated against.
46
+ The first half is wrong for the same reason the median was: the direction
47
+ search exits at the first direction reaching the target, so whenever it
48
+ succeeds for every cap the worst-placed cap is one that only just cleared,
49
+ and the reported minimum is pinned to the threshold by construction. Across
50
+ 14 independent real boxes it came in at 0.1503 +/- 0.0006 nm against a
51
+ 0.150 nm target, and the single box that fell below it was the single box
52
+ with a non-zero `n_below_target`. The minimum therefore carries nothing
53
+ `n_below_target` does not already say. `blind_min_clearance_nm`, which
54
+ ranged 0.006-0.048 nm over the same boxes, is the real tail statistic, and
55
+ the `blind_*` fields are what to calibrate the target against.
56
+
57
+ - **The cube law is documented as an estimate over a measured band, not as a
58
+ floor.** The docs said crosslinker conversion sits at or above the cube of
59
+ bond conversion in the many-iteration limit. It does not, and the band over
60
+ which the cube is even a good estimate is narrower than that claim implied.
61
+
62
+ *Where it holds*: across 14 trifunctional runs at 1.7-2.7 `f` iterations and
63
+ bond conversions of 0.74-0.90, the crosslinker conversion sits +2.0 % from
64
+ the cube with a standard deviation of 2.9 %, and 3 of the 14 land *below*
65
+ it, to -3.7 %, against a replicate scatter of 0.8-1.8 % -- so the excursions
66
+ below are real and it is a two-sided estimate, good to about 3 %.
67
+
68
+ *Below that band*: on 12 further builds at bond conversions of 0.40-0.73 it
69
+ is neither mild nor two-sided. 11 of the 12 fall below the cube, by -19.9 %
70
+ on average, worsening monotonically as the bond conversion falls and
71
+ reaching -93.6 % at 0.40. Carrying +/- 3 % down to a bond conversion of 0.5
72
+ understates the error by an order of magnitude, in a predictable direction.
73
+
74
+ *Above it*: the four runs of the nine-iteration cohort all landed +0.6 % to
75
+ +3.5 % above the cube, which reads like a bound but cannot establish one --
76
+ four points cannot separate a bound from the upper tail of a two-sided
77
+ distribution, and the scatter measured at 1.7-2.7 `f` cannot be carried to
78
+ 3 `f` when regime dependence is exactly what is at issue. The docs say 3 `f`
79
+ is untested rather than either way.
80
+
81
+ *What sets the shortfall*: not the iteration count. Four runs that each took
82
+ exactly three iterations span 15x in ratio-to-cube (0.06, 0.63, 0.80, 0.94).
83
+ It is how the bonds were distributed across those iterations, and
84
+ specifically how many the last one formed, since that is the iteration which
85
+ has to supply each crosslinker its final bond -- per-iteration bond counts
86
+ decay steeply, so the average is not the operative number. The run at 0.06
87
+ spent its last iteration on 9 bonds against an average of 96; a run at the
88
+ same bond conversion five months earlier, under an older htpolynet, spent its
89
+ own last iteration on 10 and reached the same ratio to three digits.
90
+
91
+ *Which variable to read it against*: bond conversion, because that is what
92
+ the shortfall tracks -- r = +0.81, against +0.57 for the iteration count,
93
+ over 26 runs. The docs are explicit that this is not the mechanism. Within
94
+ a fixed iteration count the *average* bonds formed per iteration is exactly
95
+ proportional to the bond conversion, so no set of runs sharing an iteration
96
+ count can distinguish those two, and none here does.
97
+
98
+ - **The placement documentation now quotes real-box numbers instead of
99
+ synthetic ones.** `cap_min_clearance`'s "demanding default" was described
100
+ from a synthetic sweep that put the blind median at 0.143 nm and had about
101
+ half of caps needing a search. On real cured boxes at the same heavy-atom
102
+ density the blind median is 0.120 nm -- ~16 % tighter, in the direction the
103
+ sweep's own caveat predicted -- so the search runs for well over half of all
104
+ caps and 37 % of them would have been placed inside 0.10 nm blind. It
105
+ nonetheless reaches the target for all but 1 cap in 1955, so the default is
106
+ demanding and reachable at once. `n_preferred_out_of_angle` came in at 6 %,
107
+ which the docs now give as the scale for reading that field: the 90-150
108
+ degree window is not what is sending caps to the search.
109
+
110
+ ## [2.6.1] - 2026-08-27
111
+
112
+ ### Fixed
113
+
114
+ - **Cap-placement clearance was pinned at the O-C bond length and measured
115
+ nothing** (regression in 2.6.0). The neighbour set a transferred `-C#N` cap
116
+ was scored against excluded the cap atoms being moved and the hydrogens
117
+ about to be deleted, but not the bridge oxygen the cap bonds *to*. The cap
118
+ carbon sits at exactly `oc_len` = 0.136 nm from that oxygen in every
119
+ candidate direction, so the reported clearance was 0.136 nm whichever
120
+ direction was scored. Two independent acceptance builds on different
121
+ topologies both reported `min_clearance_nm` 0.136, median 0.136, and 71 of
122
+ 71 caps below the 0.150 nm target -- identical to three decimals, which is
123
+ what a constant looks like when it is being read as a distribution.
124
+
125
+ Consequences: the reported clearance carried no information about crowding;
126
+ the default target was unreachable by construction, so the "could not reach
127
+ clearance" warning fired on every cap in every run and
128
+ `n_direction_searched` was always 100 %; and the search, while not dead,
129
+ could only reject directions worse than 0.136 nm rather than pick the
130
+ clearest one. Placement was degraded, not disabled, and the repair
131
+ chemistry was never affected -- every conservation identity held through
132
+ 2.6.0.
133
+
134
+ Each cap now drops the atoms it is bonded *through* -- its attachment oxygen
135
+ and that oxygen's aryl carbon -- and nothing else. Every *other* cap's
136
+ oxygen is a real atom in the way, as is every cap already placed. Both
137
+ exclusions are for the same reason: a distance fixed by bond geometry is not
138
+ a measurement of how crowded the site is. The oxygen is the hard case, at
139
+ exactly 0.136 nm in every direction. The aryl carbon is the soft one, and
140
+ keeping it would have left `median_clearance_nm` saturated at the C-O-C
141
+ geometry -- so a healthy run would still have reported a constant, just a
142
+ larger one, which is the same defect one bond further out.
143
+
144
+ Keeping the cap off the ring it hangs from is now an explicit constraint
145
+ rather than a side effect of the metric: the direction search is restricted
146
+ to C-O-C angles between 90 and 150 degrees. That guards an end the aryl
147
+ carbon never did -- clearance alone is *maximized* by a linear ether, since
148
+ antiparallel puts the cap as far as possible from the rest of the molecule,
149
+ so a pure clearance search drifts toward a geometry no aryl ether adopts.
150
+ Bond lengths are still held fixed and open-space caps still land on the O-H
151
+ vector, so nothing moves for a cap that was already comfortable.
152
+
153
+ Because a systematically rejected preferred direction would reproduce the
154
+ exact symptom being fixed here -- everything searched, everything flagged,
155
+ for a reason unrelated to crowding -- repair now reports
156
+ `n_preferred_out_of_angle` separately from `n_direction_searched`.
157
+
158
+ The 2.6.0 calibration missed the original bug because it was done on a
159
+ jittered cubic lattice with no bonded attachment oxygen -- the fixture
160
+ lacked the one feature that defeats the fix. The regression test added here
161
+ supplies it, and asserts the pinning at 0.136 nm that the released code
162
+ produces.
163
+
164
+ - **Container releases now carry a version tag.** `docker.yml` pushed only
165
+ the moving tag (`:latest` / `:cuda`) and the commit sha, so
166
+ `docker pull ...:v2.6.0` -- the obvious thing to type, and what the release
167
+ notes imply -- failed with `manifest unknown`. That error reads like the
168
+ image failed to build rather than like the tag is named something else, and
169
+ it sent a user off to resolve the release through the GitHub tag API by
170
+ hand. A `v*` push now also tags `:v<version>` and `:<version>`, in both
171
+ spellings because nothing tells a user which convention a registry chose,
172
+ with the `cuda-` prefix for the CUDA variant. A `d*` tag is a
173
+ Dockerfile-only rebuild rather than a release and gets neither.
174
+
175
+ Releases before this one are unaffected and still have no version tag; the
176
+ container docs now say so and say how to resolve one to its commit sha.
177
+
178
+ ### Changed
179
+
180
+ - **The docs now say which placement fields measure the box and which measure
181
+ the search.** `repair-summary.yaml` carries nine numbers about cap
182
+ placement and they are not the same kind of thing, which is worth knowing
183
+ before treating any of them as physics. `min_clearance_nm` and
184
+ `n_below_target` describe the tail, and are what `cap_min_clearance` should
185
+ be calibrated against. `median_clearance_nm` is a placement *outcome*: the
186
+ direction search stops at the first direction that reaches the target, so
187
+ the number is pulled toward the threshold you set and partly reports it back
188
+ to you. `blind_min_clearance_nm` and `blind_median_clearance_nm` are the
189
+ crowding statistics -- one fixed direction, no search, no early exit -- and
190
+ are the ones to correlate across a series of runs.
191
+
192
+ `cap_min_clearance` is also now described honestly as a demanding default.
193
+ At the heavy-atom density of a cured thermoset it sits slightly above the
194
+ room a typical site has along the O-H vector, so the direction search runs
195
+ for roughly half of all caps. That is the intent -- the search exists for
196
+ the crowded half -- but a run reporting that most caps needed a search is
197
+ the default working, not a symptom.
198
+
199
+ - **The docs now bound the cube law by what has actually been measured.**
200
+ Crosslinker conversion goes as roughly the cube of bond conversion, but only
201
+ in the many-iteration limit, where proximity lifts real runs a couple of
202
+ percent *above* it -- the search is distance-ranked and a partly-bonded
203
+ crosslinker sits in a bridge-rich neighbourhood, so `completion_bias` gets a
204
+ weak version of itself for free. Below that limit the page now says two
205
+ things and no more than two. Under `f` iterations the crosslinker
206
+ conversion is *exactly zero*, which is a counting constraint and holds
207
+ unconditionally. At or above `f` it falls short of the cube by an amount
208
+ set by how the bonds were distributed across the iterations, not by how many
209
+ there were: two trifunctional runs at three iterations apiece came out at
210
+ 6 % and 50 % of the cube-law figure. An earlier draft of this page claimed
211
+ the iteration count decides where a run lands and that the
212
+ one-bond-per-residue rule accounts for the shortfall; the eightfold spread
213
+ refutes the first, and the rule is worth only about a fifth of the second.
214
+ The remaining mechanism is unidentified and the page now says so rather than
215
+ guessing.
216
+
217
+ ### Added
218
+
219
+ - **htpolynet warns when a cure ran too few iterations for its crosslinkers to
220
+ complete.** The bond downselection admits at most one bond per residue per
221
+ iteration, so a residue with `f` reactive sites cannot be fully reacted in
222
+ fewer than `f` iterations -- whatever bond conversion was reached. A cure
223
+ that hits its target in two iterations therefore leaves *every*
224
+ trifunctional crosslinker incomplete, and a system with no complete
225
+ crosslinker has no junctions: it is a monomer melt that equilibrates,
226
+ reports a sensible density, and looks in every other respect like a cured
227
+ network.
228
+
229
+ Nothing else surfaces this. The conversion the cure reports is a bond
230
+ conversion and is perfectly happy with it; only a `postcure_repair` stage
231
+ would notice, and only if one is configured. The warning also says that
232
+ `completion_bias` is not the fix -- it changes which residues react, not the
233
+ one-per-residue-per-iteration rule -- because it is the first thing a user
234
+ would reach for on seeing a low crosslinker conversion.
235
+
236
+ - **Repair now records what blind cap placement *would* have given, on the
237
+ real box.** The O-H direction is tried first anyway, so its clearance is
238
+ free to compute; logging it turns "blind placement was putting caps in
239
+ overlap" from a claim measured on a synthetic lattice into a number measured
240
+ on the system actually being built. Reported alongside the achieved
241
+ clearance and carried in `repair-summary.yaml` as `blind_min_clearance_nm`
242
+ `blind_median_clearance_nm`, and `n_blind_would_overlap`, with
243
+ `median_clearance_nm` alongside them -- a minimum says whether one build is
244
+ in danger, but correlating placement quality against outcomes across a
245
+ series of runs needs a statistic that is not an extreme value. This is what tells someone whether structures
246
+ built before v2.6.0 were shaped by overlap resolution rather than by
247
+ placement -- a question that could not be answered from those runs' own
248
+ output.
249
+
10
250
  ## [2.6.0] - 2026-08-26
11
251
 
12
252
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: htpolynet
3
- Version: 2.6.0
3
+ Version: 2.6.2
4
4
  Summary: Automated MD System Builder for Amorphous Network Polymers
5
5
  Project-URL: Source, https://github.com/cameronabrams/htpolynet
6
6
  Project-URL: Documentation, https://htpolynet.readthedocs.io/
@@ -27,10 +27,17 @@ Rough ordering within each section is by value, not by effort.
27
27
  choice for runs that offload to a GPU anyway, so the penalty may be small
28
28
  for exactly the case the `:cuda` image serves.
29
29
 
30
- - **Publish a digest or version tag people can pin.** `:latest` moves
31
- every week via the scheduled rebuild, so a run recorded as "built with
32
- the container" is not reproducible. Per-commit tags already exist;
33
- what's missing is documenting that users should pin one.
30
+ - **Releases before v2.6.1 have no version tag in the registry.** From
31
+ v2.6.1 on, `docker.yml` pushes `:v<version>` and `:<version>` (and the
32
+ `cuda-` variants) alongside the commit sha, but the earlier releases were
33
+ pushed as `:latest` and a sha only. So `pull ...:v2.5.0` returns `manifest
34
+ unknown`, which reads like a failed build rather than a differently-named
35
+ tag. The docs now say how to resolve an old release to its sha, which is
36
+ the cheap half. Retagging the existing images would be better and is a
37
+ registry operation, not a code change: `docker buildx imagetools create -t
38
+ ghcr.io/cameronabrams/htpolynet:v2.5.0 ghcr.io/cameronabrams/htpolynet:<sha>`
39
+ for each past release, which needs a token with `write:packages`. Worth
40
+ doing if anyone reports hitting it a second time.
34
41
 
35
42
  - **The image's Gromacs and AmberTools are unpinned, so two images with
36
43
  identical htpolynet code can compute different numbers.** `docker/Dockerfile`
@@ -166,6 +173,311 @@ Coverage as of the last measurement: **38.8%** overall.
166
173
 
167
174
  ## Cure and repair
168
175
 
176
+ - **`cap_min_clearance` has never been calibrated against a working metric.**
177
+ The 0.150 nm default was chosen in 2.6.0 against a clearance that was pinned
178
+ at 0.136 nm by a bug, so it fired on 100 % of caps for a reason that had
179
+ nothing to do with crowding, and the 0.22 nm value rejected before it was
180
+ rejected on the same broken measurement. The metric is real as of the fix,
181
+ but the only two data points on a real box -- the accept260 builds on
182
+ picotte, `/ifs/groups/abramsGrp/cfa22/htpolynet/cyanate-bridge-series/accept260/{unbiased,biased}/`
183
+ -- were taken with the bug present and are uninformative. The geometry now
184
+ bounds the achievable clearance at 0.272 nm (cap carbon to the attachment
185
+ oxygen's aryl carbon, antiparallel), with the chemically sensible ~120
186
+ degree placement at 0.236 nm -- but the aryl carbon has since been excluded
187
+ from the metric precisely so it does not saturate, so that bound no longer
188
+ applies and there is no analytic ceiling to reason from at all. What is
189
+ unknown was the fire rate in a box at polymer density, and that has now been
190
+ measured (see the real-box block at the end of this entry). What is left is
191
+ the recalibration itself: set the default so it flags the tail rather than
192
+ the bulk, using `blind_min_clearance_nm`, `blind_median_clearance_nm` and
193
+ `n_below_target`. Do **not** calibrate against `min_clearance_nm` -- it
194
+ saturates at whatever target is set. A threshold that fires on everything is
195
+ not a threshold. The `n_preferred_out_of_angle` escape hatch is closed: it
196
+ came back at 6 %, so the 90--150 degree window is not biting real O-H
197
+ vectors and is not the thing to change.
198
+
199
+ One thing the synthetic sweep did settle, so nobody re-derives it: the
200
+ clipping the aryl-carbon exclusion removes is density-dependent, and at melt
201
+ density it was mild. Median clearance against random neighbourhoods at 5,
202
+ 15, 33 and 60 heavy atoms per nm^3 ran 0.316 / 0.230 / 0.193 / 0.177 nm with
203
+ the aryl carbon excluded and 0.233 / 0.222 / 0.191 / 0.174 nm with it in.
204
+ It pins hard at 0.233 nm -- the C-O-C geometry at 118 degrees -- only in
205
+ sparse surroundings, where the caps are comfortable anyway; by 33/nm^3 real
206
+ neighbours are usually closer than the geometric bound and the two agree to
207
+ about 2 %. So the median was censored from above rather than constant, and
208
+ the exclusion buys an uncensored statistic rather than rescuing a dead one.
209
+ Worth knowing before treating a change in that median as physics.
210
+
211
+ For the cyanate-ester system specifically, the study session measured the
212
+ box: heavy-atom count is conversion-independent at 7560 (14,040 atoms less
213
+ 6,480 H, and the cure removes only hydrogen), post-repair mass 100,192
214
+ g/mol, and measured densities of 1.171--1.198 g/cm^3 across the as-cured,
215
+ ladder-cold-end and monomer-melt states bracket **~53 heavy atoms per
216
+ nm^3**. Repair runs before the postcure anneal so the placement-time value
217
+ is not directly measured, but the spread between those three is smaller than
218
+ the uncertainty over which stage to attribute. That is inside the swept
219
+ range, so nothing here extrapolates. Rerunning the sweep at 53/nm^3 gives
220
+ median blind clearance 0.143 nm (p10 0.075, p90 0.212), median searched
221
+ clearance 0.179 nm, and about 45 % of caps keeping the O-H direction, with
222
+ the censored and uncensored medians differing by under 1 %. Three things
223
+ follow.
224
+
225
+ First, and this needs stating at commit granularity rather than as "the
226
+ clearance fix", because the two commits move the numbers by wildly different
227
+ amounts in the same release: 5a58d3d, dropping the attachment oxygen, turns
228
+ `median_clearance_nm` from the constant 0.136 into a distribution, so every
229
+ placement field moves enormously between the accept260 runs and whatever
230
+ comes next. That is the released bug being fixed and is expected. 82ddd3e,
231
+ dropping the aryl carbon, is the <1 % above. Read as one change, the large
232
+ shift becomes evidence about the aryl-carbon exclusion, which it is not.
233
+
234
+ Second, a `blind_median_clearance_nm` anywhere near 0.233 in a box believed
235
+ to be at this density is unambiguous evidence the box is wrong, since that
236
+ value is only legitimate in the sparse regime.
237
+
238
+ Third, the default sits *above* the blind median: 0.150 against 0.143, which
239
+ is the same fact as only ~45 % of caps keeping the O-H vector. So at melt
240
+ density roughly half of all cap sites cannot reach `cap_min_clearance` along
241
+ the preferred direction and the search is doing real work rather than
242
+ rubber-stamping. That makes 0.150 demanding but not absurd -- which is more
243
+ than it was when it was unreachable by construction -- and it suggests the
244
+ recalibration may move it *down* rather than up. Not the direction either
245
+ session guessed, and worth not being surprised by.
246
+
247
+ Independent check on the scale, by the study session: uncorrelated Poisson
248
+ at 53/nm^3 has a median nearest-neighbour distance of 0.1462 nm from a probe
249
+ point, dropping to 0.1236 when minimized over both atoms of a -C#N group at
250
+ 0.116 nm separation. The swept 0.143 sits inside [0.124, 0.146], near the
251
+ top, which is where the excluded hole around the attachment oxygen should
252
+ put it. Script at
253
+ `~/devtests/htpolynet/bridge-series/verify_blind_clearance_scale.py`.
254
+
255
+ A trap in that check, flagged by the study session and worth disarming
256
+ before someone rederives it: the disjoint-sphere floor,
257
+ `(ln 2 / (8/3 pi rho))^(1/3)`, evaluates to 0.116 nm at rho = 53, which is
258
+ also `cn_len`, the C-N bond length. That is arithmetic coincidence at this
259
+ one density and nothing else. The floor tracks number density -- 0.127 at
260
+ 40/nm^3, 0.116 at 53, 0.111 at 60, 0.101 at 80 -- while the bond length is
261
+ fixed. Anyone who writes down "the floor is the C-N bond length" has made a
262
+ claim that is invisible here and wrong everywhere else, and has attributed a
263
+ number-density result to cap geometry.
264
+
265
+ Two caveats on those figures. The sweep places uncorrelated Poisson points
266
+ with a hole around the oxygen, which is not a melt -- real packing is
267
+ correlated and has excluded volume between the neighbours too -- so it gives
268
+ a scale, not a prediction, and in particular its `n_below_target` of zero is
269
+ certainly optimistic. And replicate scatter in this system is topological
270
+ rather than numerical: the study session measures density sd rising from
271
+ 0.71 kg/m^3 at chi_OCN 0 to 3.25 at 0.746, a factor of 4.6, because at zero
272
+ conversion every build is the same molecular liquid. Cap sites are network
273
+ sites, so expect the scatter in `blind_median_clearance_nm` to grow with
274
+ conversion the same way, and size any series meant to calibrate the default
275
+ accordingly rather than assuming the high-conversion points are as tight as
276
+ the low ones.
277
+
278
+ **Measured on real boxes, 2026-08-27** (study session, job 22107390): 14
279
+ independent cured BPA-cyanate-ester boxes at v2.6.1, chi_bond 0.740--0.901,
280
+ 1955 caps, ~53 heavy atoms/nm^3 -- the first placement numbers taken without
281
+ the clearance bug present. `blind_median_clearance_nm` 0.1198 +/- 0.0061
282
+ against the synthetic sweep's 0.143: real boxes are ~16 % *tighter*, in the
283
+ direction the sweep's own caveat predicted, so the sweep's absolute values
284
+ should not be used to set the default. `blind_min_clearance_nm` 0.006--0.048.
285
+ 722 of 1955 caps (37 %) would have been placed inside 0.10 nm blind.
286
+ `n_preferred_out_of_angle` 109 (6 %). `n_below_target` 1 of 1955, against
287
+ the sweep's 0 that was flagged "certainly optimistic".
288
+
289
+ And a correction to this entry's own advice, which the numbers force:
290
+ `min_clearance_nm` is **not** a tail statistic and must not be calibrated
291
+ against. Across all 14 boxes it came in at 0.1503 +/- 0.0006 against a 0.150
292
+ target -- the target seen from above, not a measurement. The search exits at
293
+ the first direction reaching target, so whenever it succeeds for every cap
294
+ the worst-placed cap is one that only just cleared, and the minimum is
295
+ pinned to the threshold by construction. The one box below it (cb0773,
296
+ 0.1488) is the one box with `n_below_target` = 1. This is the searched-median
297
+ defect one statistic further along; it was missed because the median's
298
+ version of it was the one being written up. Docs corrected.
299
+
300
+ So the recalibration is unblocked and wants the `blind_*` columns. Note that
301
+ 0.150 sits well above the measured blind median of 0.120, not marginally
302
+ above 0.143 as the sweep suggested -- so the search runs for well over half
303
+ of all caps -- yet it succeeds for 1954 of 1955. Demanding and reachable at
304
+ once, which is a different situation from the one this entry was written
305
+ against, and it weakens the earlier guess that recalibration would move the
306
+ default down.
307
+
308
+ **The placement change is density-neutral at high conversion, 2026-08-28**
309
+ (study session; picotte 22107390 complete, 14/14, exit 0:0). v2.6.1 anchors
310
+ at chi_OCN 0.7438 give 1197.59 kg/m^3 (n = 2) against v2.3.0's 1197.94 +/-
311
+ 3.25 at 0.7458 (n = 8): offset -0.34 on a combined SE of 2.38, i.e. 0.1
312
+ sigma, bounding |offset| < 4.7 kg/m^3 at 2 sigma. So the net of 5a58d3d and
313
+ 82ddd3e does not move bulk density where it has been checked. Two limits.
314
+ The bound is small against the 21 kg/m^3 rise across the series, so the two
315
+ versions pool for curve shape -- but it is *not* small against the 3.0 kg/m^3
316
+ basin depth, so it licenses nothing about the basin. And it does not
317
+ calibrate `cap_min_clearance`: a placement change being invisible in bulk
318
+ density is a much weaker statement than the threshold being right, and this
319
+ item stays open exactly as written above.
320
+
321
+ - **The cap direction search stops at the first adequate direction, not the
322
+ best one.** `_choose_cap_placement` breaks out as soon as a direction
323
+ reaches `cap_min_clearance`, so a cap that could have had 0.25 nm of room
324
+ may be left with 0.15. Two consequences. The placement is worse than it
325
+ needs to be, for compute that is genuinely negligible -- the angle window
326
+ admits about 43 % of a 48-direction Fibonacci spiral, so a full scan is
327
+ ~21 vectorized distance evaluations against a neighbour list of order 100.
328
+ And `median_clearance_nm` is partly a readout of the threshold rather than
329
+ of the box, since the distribution is truncated from below at the target --
330
+ as is `min_clearance_nm`, which is pinned *at* the target rather than merely
331
+ pulled toward it, measured at 0.1503 +/- 0.0006 across 14 real boxes.
332
+ Removing the early exit would give both fields their meaning back.
333
+
334
+ Deliberately not changed for 2.6.1: taking the best direction moves every
335
+ cap that needed a search, and doing that on the same release as the
336
+ clearance fix means the next real build cannot attribute a change in the
337
+ numbers to either one. That precondition is now satisfied -- the 14-box
338
+ measurement of 2026-08-27 recorded above is the clean pre-change baseline,
339
+ so this is ready to do. Note that changing it invalidates the achieved
340
+ columns of anything built before it while leaving the `blind_*` columns
341
+ comparable, which is another reason those are the ones to correlate on.
342
+
343
+ - **The shortfall from the cube law between `f` and many iterations is
344
+ unexplained, and is now known to be narrow.** Below `f` iterations
345
+ crosslinker conversion is exactly zero, a counting constraint; the four runs
346
+ of the nine-iteration cohort land +0.6 to +3.5 % above the cube (attested at
347
+ nine for two of the four; the other two are the same cohort at the same
348
+ target with the count unrecorded). In between, measured ratios
349
+ to the cube law are 0.06 and 0.46--0.50 at three iterations and 0.86 at
350
+ four -- an eightfold spread at an *identical* iteration count, so the
351
+ iteration count does not determine it. The band above that is now measured
352
+ and shows no shortfall at all: 14 runs at `n`/`f` 1.67--2.67 sit at
353
+ 1.020 +/- 0.029 of the cube, with 3 of the 14 *below* it to -3.7 % against
354
+ replicate scatter of 0.8--1.8 %. So the unexplained region is only
355
+ `f` to about 1.7`f`, and across 1.7--2.7`f` the cube is a two-sided estimate
356
+ rather than the floor the docs used to call it -- corrected there.
357
+
358
+ What that does **not** settle is 3`f`, and the temptation to settle it by
359
+ arithmetic should be resisted: applying the 1.7--2.7`f` scatter to the
360
+ nine-iteration cohort gives P(below cube) = 0.245 and makes four-of-four
361
+ above a one-in-three outcome, but that presupposes the deviation is
362
+ regime-independent, which is the claim in question. The cohort on its own is
363
+ +2.64 % sd 1.39 % (n = 4), giving P = 0.03 -- an order of magnitude apart --
364
+ and at n = 4 the sd's 95 % CI is [0.79, 5.18], so the two cannot be
365
+ distinguished. 3`f` is untested, not disproved. Settling it wants more runs
366
+ at 3`f`, not a wider distribution borrowed from a lower one. Whatever
367
+ mechanism explains the shortfall has to switch off within a factor of two
368
+ of `f`.
369
+
370
+ The one-bond-per-residue-per-iteration rule was simulated against this and
371
+ moves the n=3 prediction only from 30.0 to 25.9 against 15 observed: a fifth
372
+ of the gap. The leading untested guess is spatial anti-correlation --
373
+ bonds forming preferentially on crosslinkers that already have room, leaving
374
+ the rest to compete. This matters because it is the regime where a user's
375
+ reported conversion is most wrong, and because a warning better than the
376
+ current `iterations < f` one needs a mechanism to threshold on. Widening
377
+ that warning to `n < 2f` was considered and rejected: no threshold on `n`
378
+ alone can work.
379
+
380
+ That conclusion survives a correction to its own evidence, and comes out
381
+ stronger. The 8x pair was **confounded**: conv40 r3 and conv50 r1 are both
382
+ n = 3 but sit at chi_bond 0.40 and 0.50, so they never isolated `n` either.
383
+ The new low-conversion builds split it -- at fixed chi_bond the residual
384
+ spread is 1.36x, not 8x, and the chi_bond 0.40 ratio-to-cube reproduces to
385
+ three digits across v2.3.0 and v2.6.1 five months apart. So at fixed `n` the
386
+ ratio moves 7--10x purely with chi_bond, which is a sharper refutation of an
387
+ `n` threshold than the confounded pair was. What does *not* survive is the
388
+ explanation: the "product of per-iteration bond fractions" account is
389
+ superseded by plain chi_bond, which is simpler and reproduces across
390
+ versions. Docs corrected.
391
+
392
+ **Reinstated 2026-08-29**, and worth recording because it was withdrawn and
393
+ reinstated inside two days. The "product of per-iteration bond fractions"
394
+ account was not superseded -- it was under-evidenced, and the iteration logs
395
+ now make it the best-evidenced thing in this entry. Bonds per iteration decay
396
+ steeply (bpa-fl0500: 156, 145, 59; bpa-cb0900: 162, 148, 128, 92, 46, 29, 17,
397
+ 26), so `720 x chi_bond / n` is an average no build actually realises. What
398
+ matters is the LAST iteration, the one that has to supply a triazine's third
399
+ bond: bpa-fl0400 spent 9 bonds there against an average of 96 and came in at
400
+ ratio 0.064, and conv40 r3 -- same conversion, v2.3.0, five months earlier --
401
+ spent 10 on its own last iteration and also came in at 0.064.
402
+
403
+ So chi_bond is a **proxy for the distribution, not a replacement for it**.
404
+ The algebra above still holds for *average* bonds-per-iteration, which is
405
+ exactly collinear with chi_bond at fixed n (r = 1.0000). The *last-iteration*
406
+ count is a third variable at r = 0.980 with chi_bond -- separable in
407
+ principle, not on four points. The withdrawal on 08-28 was made on the
408
+ strength of a correlation, which is the move this entry already warns about
409
+ one paragraph earlier.
410
+
411
+ **Measured below the band, 2026-08-28** (study session; picotte 22132281,
412
+ 12 BPA builds at v2.6.1, cures final, ladders still running): at bond
413
+ conversions of 0.40--0.73 the deviation from the cube is one-sided and
414
+ large -- 11 of 12 below, mean -19.9 %, worsening monotonically as bond
415
+ conversion falls, -93.6 % at 0.40. The single build inside the documented
416
+ band (0.7306, +1.5 %) agrees with it, so nothing here disturbs the
417
+ 1.7--2.7`f` scoping.
418
+
419
+ The open question this creates is which variable is doing the work. The
420
+ documented band is *both* 1.7--2.7`f` and bond conversion 0.74--0.90; this
421
+ array varies bond conversion and its iteration counts are not yet in hand
422
+ (they live in `diagnostics.log`, returned only when a task ends -- expected
423
+ early 2026-08-29). So the docs state the degradation against bond
424
+ conversion, which is what was measured, and do not attribute it to `n`/`f`.
425
+ **Resolved 2026-08-29**, counts returned with the array. Four builds sit at
426
+ exactly n = 3 spanning 15x in ratio-to-cube (0.064 / 0.633 / 0.795 / 0.937 at
427
+ chi_bond 0.40 / 0.50 / 0.55 / 0.58), monotone in chi_bond. So "iteration
428
+ count does not determine the shortfall" is established directly, on four
429
+ same-n runs, rather than inferred from the confounded pair. Over all 26
430
+ builds r(ratio, chi_bond) = +0.813 against r(ratio, n/f) = +0.567, with
431
+ r(chi_bond, n/f) = +0.905; counts run 3 to 8, n/f 1.00 to 2.67. Docs cite
432
+ the four-run evidence now.
433
+
434
+ - **A config-time version of that warning, before any compute is spent.**
435
+ Largely superseded by the completed-crosslinker check that shipped -- nothing
436
+ needs a proxy for a quantity that is exactly known by the time the cure
437
+ ends -- and worth keeping only for
438
+ what the post-hoc check cannot do: warn *before* a multi-hour build rather
439
+ than after it. That is a weaker claim on much worse evidence, so it is a
440
+ separate feature and not a substitute. The reasoning that motivated it:
441
+ chi_bond predicts the ratio-to-cube to within 1.36x, and unlike a bond
442
+ distribution -- which does not exist until the cure runs -- it is knowable
443
+ before the cure starts. So
444
+ htpolynet could warn at config time that a run will yield far less
445
+ crosslinker conversion than the cube law implies, which is the number a user
446
+ is actually reasoning with. The existing `iterations < f` warning fires only
447
+ after the fact and only in the exactly zero regime.
448
+
449
+ **Do not key it on `desired_conversion`, and do not key it on chi_bond
450
+ either.** chi_bond is a config-time proxy, not the governing quantity, and
451
+ the collinearity is not an accident of sampling that more builds would fix.
452
+ Within a fixed iteration count `bonds = 720 x chi_bond` for this system, so
453
+ bonds-per-iteration `= 720 x chi_bond / n` is *exactly* proportional to
454
+ chi_bond. No dataset at fixed `n` can separate them, however large. Breaking
455
+ the proportionality needs `max_conversion_per_iteration` or
456
+ `min_bonds_per_iteration` varied AT FIXED `desired_conversion` -- which is
457
+ a deliberate experiment nobody has run, not something a wider sweep of
458
+ conversions will deliver.
459
+
460
+ There is a further reason to keep it qualitative: the quantity that appears
461
+ to govern the shortfall is the number of bonds formed in the *last*
462
+ iteration, and that is not knowable at config time at all -- it is an
463
+ outcome of the cure, not a setting. Any config-time warning is necessarily
464
+ keyed on a proxy for it.
465
+
466
+ Those same two directives are also why `desired_conversion` is the wrong
467
+ key in ordinary use: they set bonds-per-iteration independently of it, which
468
+ is exactly what the warning at `cure/curecontroller.py:674` already tells a
469
+ user to do to spend more iterations at the same conversion, and what this
470
+ project plans in order to reach 9+ iterations. A threshold keyed on
471
+ `desired_conversion` alone would misfire on precisely the runs that took
472
+ htpolynet's own advice.
473
+
474
+ So keep it qualitative until something separates the two. A warning saying
475
+ "below about 0.7 the cube law overstates badly, and worsens as you go lower"
476
+ needs no attribution and could ship soon. One that quotes a number needs both
477
+ the separation and a sense of how much of the curve is BADCy-specific -- it
478
+ is one chemistry, one force field, one cure protocol, n = 1 per target apart
479
+ from a single duplicate.
480
+
169
481
  - **`completion_bias` biases the `B` side only, and that is a convention,
170
482
  not a law.** The new `CURE.controls.completion_bias` ranks bond candidates
171
483
  by how many bonds their `B`-side residue already carries, because
@@ -48,7 +48,16 @@ Diagnostic-log plots:
48
48
  cyanate — and the fraction of triazines that survive is what FTIR
49
49
  measures at 2270 cm\ :sup:`-1`. Under random placement that
50
50
  fraction is about the cube of the bond conversion, so a run at
51
- 0.90 leaves a cyanate conversion near 0.73. htpolynet reports
51
+ 0.90 leaves a cyanate conversion near 0.73 -- a little above it
52
+ here, since this cure takes nine iterations and the distance-ranked
53
+ search keeps re-finding crosslinkers that are partly bonded. The
54
+ cube is an estimate rather than a bound, and only near this run's
55
+ own bond conversion: at 0.74–0.90 real runs scatter a few percent
56
+ either side of it, but by 0.5 they fall short of it by tens of
57
+ percent, always on the same side. A cure that
58
+ reaches its target in two or three iterations lands far below it,
59
+ and in fewer than three it lands at exactly zero, because at most
60
+ one bond per residue forms per iteration. htpolynet reports
52
61
  both figures at the end of the repair stage and writes them to
53
62
  ``repair-summary.yaml``; see :ref:`what repair reports
54
63
  <postcure_repair_reporting>`. If what you want is a structure