mdprep 0.3.0__tar.gz → 0.5.0__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 (395) hide show
  1. {mdprep-0.3.0 → mdprep-0.5.0}/AGENTS.md +3 -2
  2. mdprep-0.5.0/CHANGELOG.md +497 -0
  3. mdprep-0.5.0/CONTRIBUTING.md +114 -0
  4. {mdprep-0.3.0 → mdprep-0.5.0}/PKG-INFO +58 -24
  5. {mdprep-0.3.0 → mdprep-0.5.0}/README.md +57 -23
  6. {mdprep-0.3.0 → mdprep-0.5.0}/docs/README.md +4 -0
  7. mdprep-0.5.0/docs/enzyme_families.md +78 -0
  8. {mdprep-0.3.0 → mdprep-0.5.0}/docs/guided_manifests.md +66 -3
  9. mdprep-0.5.0/docs/heterogens.md +152 -0
  10. {mdprep-0.3.0 → mdprep-0.5.0}/docs/ligands.md +42 -3
  11. {mdprep-0.3.0 → mdprep-0.5.0}/docs/manifest_reference.md +83 -6
  12. {mdprep-0.3.0 → mdprep-0.5.0}/docs/metals.md +262 -6
  13. {mdprep-0.3.0 → mdprep-0.5.0}/docs/molecular_dynamics.md +33 -0
  14. mdprep-0.5.0/docs/oligomers.md +169 -0
  15. mdprep-0.5.0/docs/predicted_structures.md +171 -0
  16. {mdprep-0.3.0 → mdprep-0.5.0}/docs/tleap_and_validation.md +13 -0
  17. {mdprep-0.3.0 → mdprep-0.5.0}/docs/troubleshooting.md +76 -1
  18. mdprep-0.5.0/examples/17_syrb2_bound_water_mcpb.yaml +216 -0
  19. mdprep-0.5.0/examples/18_syrb2_dimer_shared_mcpb.yaml +345 -0
  20. mdprep-0.5.0/examples/19_cyp119_heme_mcpb.yaml +228 -0
  21. mdprep-0.5.0/examples/20_upo_5oxu_heme_glycans.yaml +352 -0
  22. mdprep-0.5.0/examples/21_prna_fad_halogenase.yaml +85 -0
  23. {mdprep-0.3.0 → mdprep-0.5.0}/examples/README.md +26 -5
  24. {mdprep-0.3.0 → mdprep-0.5.0}/examples/colab_smoke_test.ipynb +1 -1
  25. mdprep-0.5.0/examples/mdprep_colab.ipynb +910 -0
  26. mdprep-0.5.0/examples/mdprep_colab_run.ipynb +30 -0
  27. {mdprep-0.3.0 → mdprep-0.5.0}/examples/mdprep_interactive_colab.ipynb +2 -2
  28. {mdprep-0.3.0 → mdprep-0.5.0}/pyproject.toml +2 -1
  29. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/__init__.py +1 -1
  30. mdprep-0.5.0/src/mdprep/analysis/__init__.py +6 -0
  31. mdprep-0.5.0/src/mdprep/analysis/charges.py +209 -0
  32. mdprep-0.5.0/src/mdprep/analysis/dcd.py +112 -0
  33. mdprep-0.5.0/src/mdprep/analysis/equilibration.py +90 -0
  34. mdprep-0.5.0/src/mdprep/analysis/metal_site.py +78 -0
  35. mdprep-0.5.0/src/mdprep/analysis/prmtop.py +236 -0
  36. mdprep-0.5.0/src/mdprep/analysis/trajectory.py +365 -0
  37. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/cli.py +235 -9
  38. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/config/decisions.py +1621 -302
  39. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/config/models.py +375 -3
  40. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/builder.py +21 -2
  41. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/report.py +15 -0
  42. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/residues.py +28 -0
  43. mdprep-0.5.0/src/mdprep/ligands/cofactors.py +214 -0
  44. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ligands/hydrogenate.py +53 -0
  45. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ligands/workflow.py +106 -9
  46. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/md/roe_brooks.py +139 -6
  47. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/coordination.py +11 -4
  48. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/gxtb_hessian.py +184 -5
  49. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/mcpb.py +565 -14
  50. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/pyscf_mcpb.py +10 -0
  51. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/report.py +25 -0
  52. mdprep-0.5.0/src/mdprep/metals/through_metal.py +135 -0
  53. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/workflow.py +31 -11
  54. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/histidine_qmmm.py +19 -2
  55. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/histidine_xtb.py +18 -1
  56. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/temporary_hydrogenation.py +10 -4
  57. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/selection.py +27 -0
  58. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/reports/structure_report.py +20 -0
  59. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/classify.py +39 -1
  60. mdprep-0.5.0/src/mdprep/structure/closest_xray.py +301 -0
  61. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/completeness.py +14 -4
  62. mdprep-0.5.0/src/mdprep/structure/coordination.py +70 -0
  63. mdprep-0.5.0/src/mdprep/structure/heterogens.py +475 -0
  64. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/inspect.py +8 -0
  65. mdprep-0.5.0/src/mdprep/structure/links.py +308 -0
  66. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/mmcif.py +18 -4
  67. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/models.py +13 -1
  68. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/normalize.py +66 -2
  69. mdprep-0.5.0/src/mdprep/structure/oligomer.py +713 -0
  70. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/pdb.py +26 -0
  71. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/pdb_fields.py +188 -14
  72. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/repair.py +199 -6
  73. mdprep-0.5.0/src/mdprep/structure/waters.py +868 -0
  74. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/writer.py +47 -2
  75. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/validation/topology.py +2 -2
  76. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/doctor.py +55 -0
  77. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/runtime.py +144 -5
  78. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/wizard.py +39 -3
  79. mdprep-0.5.0/tests/browser/example_button.mjs +72 -0
  80. {mdprep-0.3.0 → mdprep-0.5.0}/tests/browser/student_flow.mjs +7 -0
  81. mdprep-0.5.0/tests/data/cofactors/fad_2ar8.pdb +55 -0
  82. mdprep-0.5.0/tests/data/cofactors/fmn_4ttb.pdb +33 -0
  83. mdprep-0.5.0/tests/data/cofactors/hem_2qfk.pdb +46 -0
  84. mdprep-0.5.0/tests/data/cofactors/nad_2jhf.pdb +46 -0
  85. mdprep-0.5.0/tests/data/cofactors/nai_4plz.pdb +46 -0
  86. mdprep-0.5.0/tests/data/cofactors/nap_4lbs.pdb +50 -0
  87. mdprep-0.5.0/tests/data/cofactors/ndp_1kmv.pdb +50 -0
  88. mdprep-0.5.0/tests/data/cofactors/sah_8pb4.pdb +28 -0
  89. mdprep-0.5.0/tests/data/cofactors/sam_7rwg.pdb +29 -0
  90. mdprep-0.5.0/tests/data/heterogens/covalent_intermediate_1zrn.pdb +64 -0
  91. mdprep-0.5.0/tests/data/heterogens/pyroglutamate_1cpo.pdb +89 -0
  92. mdprep-0.5.0/tests/data/heterogens/selenomethionine_1rqr.pdb +58 -0
  93. mdprep-0.5.0/tests/data/heterogens/vanadate_1idq.pdb +39 -0
  94. mdprep-0.5.0/tests/data/metals/dhp_2qfk_small_model.xyz +93 -0
  95. mdprep-0.5.0/tests/test_analysis.py +435 -0
  96. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_besd_halogenase_case.py +65 -2
  97. mdprep-0.5.0/tests/test_closest_xray.py +256 -0
  98. mdprep-0.5.0/tests/test_colab_official_notebook.py +195 -0
  99. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_colab_smoke_notebook.py +1 -1
  100. mdprep-0.5.0/tests/test_crystal_ions.py +214 -0
  101. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_doctor.py +21 -0
  102. mdprep-0.5.0/tests/test_external_dcd_openmm.py +42 -0
  103. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_gxtb_hessian.py +43 -0
  104. mdprep-0.5.0/tests/test_external_halogenase_families.py +130 -0
  105. mdprep-0.5.0/tests/test_external_heme_mcpb.py +98 -0
  106. mdprep-0.5.0/tests/test_external_modified_residues.py +154 -0
  107. mdprep-0.5.0/tests/test_external_oligomer_mcpb.py +112 -0
  108. mdprep-0.5.0/tests/test_external_water_transplant.py +61 -0
  109. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_gxtb_hessian.py +173 -0
  110. mdprep-0.5.0/tests/test_heterogen_groups.py +649 -0
  111. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_histidine_qmmm.py +48 -14
  112. mdprep-0.5.0/tests/test_known_cofactors.py +113 -0
  113. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_leap_builder.py +23 -0
  114. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_ligand_hydrogenation.py +43 -0
  115. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_manifest_decisions.py +72 -19
  116. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_manifest_wizard.py +7 -3
  117. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_mcpb_parameter_comparison.py +47 -0
  118. mdprep-0.5.0/tests/test_metal_bound_water.py +212 -0
  119. mdprep-0.5.0/tests/test_metal_cofactors.py +405 -0
  120. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_metals.py +1 -0
  121. mdprep-0.5.0/tests/test_oligomers.py +923 -0
  122. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_packaging_metadata.py +1 -1
  123. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_pdb_writer.py +58 -0
  124. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_qm_region_spin_state.py +20 -36
  125. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_refinement_selection.py +95 -0
  126. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_roe_brooks.py +26 -0
  127. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_runtime_requirements.py +133 -1
  128. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_runtime_requirements_cover_every_option.py +23 -1
  129. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_structure_completeness.py +111 -4
  130. mdprep-0.5.0/tests/test_structure_links.py +219 -0
  131. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_structure_repair_inputs.py +32 -0
  132. mdprep-0.5.0/tests/test_syrb2_bound_water_case.py +98 -0
  133. mdprep-0.5.0/tests/test_through_metal.py +100 -0
  134. mdprep-0.5.0/tests/test_water_transplant.py +382 -0
  135. mdprep-0.5.0/tests/test_web_builder_bound_water_case.py +134 -0
  136. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_web_builder_browser.py +3 -3
  137. mdprep-0.5.0/tests/test_web_builder_example_button.py +62 -0
  138. mdprep-0.5.0/tests/test_web_builder_flavin_case.py +120 -0
  139. mdprep-0.5.0/tests/test_web_builder_heme_case.py +119 -0
  140. mdprep-0.5.0/tests/test_web_builder_oligomer_case.py +165 -0
  141. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_web_builder_reference_case.py +10 -9
  142. mdprep-0.5.0/tests/test_web_builder_upo_case.py +104 -0
  143. {mdprep-0.3.0 → mdprep-0.5.0}/web/README.md +18 -0
  144. {mdprep-0.3.0 → mdprep-0.5.0}/web/app.js +149 -39
  145. {mdprep-0.3.0 → mdprep-0.5.0}/web/index.html +35 -8
  146. {mdprep-0.3.0 → mdprep-0.5.0}/web/style.css +43 -0
  147. mdprep-0.3.0/CHANGELOG.md +0 -219
  148. mdprep-0.3.0/CONTRIBUTING.md +0 -58
  149. mdprep-0.3.0/examples/mdprep_colab_run.ipynb +0 -277
  150. mdprep-0.3.0/tests/test_colab_run_notebook.py +0 -125
  151. {mdprep-0.3.0 → mdprep-0.5.0}/.gitignore +0 -0
  152. {mdprep-0.3.0 → mdprep-0.5.0}/CITATION.cff +0 -0
  153. {mdprep-0.3.0 → mdprep-0.5.0}/LICENSE +0 -0
  154. {mdprep-0.3.0 → mdprep-0.5.0}/docs/developer_notes.md +0 -0
  155. {mdprep-0.3.0 → mdprep-0.5.0}/docs/installation.md +0 -0
  156. {mdprep-0.3.0 → mdprep-0.5.0}/docs/mcpb_xtb_benchmark.md +0 -0
  157. {mdprep-0.3.0 → mdprep-0.5.0}/docs/protonation.md +0 -0
  158. {mdprep-0.3.0 → mdprep-0.5.0}/docs/qmmesp_pyscf.md +0 -0
  159. {mdprep-0.3.0 → mdprep-0.5.0}/docs/qmmm_refinement.md +0 -0
  160. {mdprep-0.3.0 → mdprep-0.5.0}/docs/quickstart.md +0 -0
  161. {mdprep-0.3.0 → mdprep-0.5.0}/environment-dev.yml +0 -0
  162. {mdprep-0.3.0 → mdprep-0.5.0}/environment-minimal.yml +0 -0
  163. {mdprep-0.3.0 → mdprep-0.5.0}/environment.yml +0 -0
  164. {mdprep-0.3.0 → mdprep-0.5.0}/examples/00_basic_protein.yaml +0 -0
  165. {mdprep-0.3.0 → mdprep-0.5.0}/examples/01_protein_only_ff19sb.yaml +0 -0
  166. {mdprep-0.3.0 → mdprep-0.5.0}/examples/02_manual_catalytic_protonation.yaml +0 -0
  167. {mdprep-0.3.0 → mdprep-0.5.0}/examples/03_multi_ligand_am1bcc.yaml +0 -0
  168. {mdprep-0.3.0 → mdprep-0.5.0}/examples/04_qmmesp_pyscf_ligand.yaml +0 -0
  169. {mdprep-0.3.0 → mdprep-0.5.0}/examples/05_histidine_gxtb_sp.yaml +0 -0
  170. {mdprep-0.3.0 → mdprep-0.5.0}/examples/06_disulfide_manual.yaml +0 -0
  171. {mdprep-0.3.0 → mdprep-0.5.0}/examples/07_gas_resp_pyscf_ligand.yaml +0 -0
  172. {mdprep-0.3.0 → mdprep-0.5.0}/examples/08_nonbonded_zinc_1264.yaml +0 -0
  173. {mdprep-0.3.0 → mdprep-0.5.0}/examples/09_bonded_zinc_mcpb_prepare.yaml +0 -0
  174. {mdprep-0.3.0 → mdprep-0.5.0}/examples/10_qmmm_refinement_ash.yaml +0 -0
  175. {mdprep-0.3.0 → mdprep-0.5.0}/examples/11_qmmm_metal_gfn2_mcpb.yaml +0 -0
  176. {mdprep-0.3.0 → mdprep-0.5.0}/examples/12_qmmm_metal_mace_polar1_mcpb.yaml +0 -0
  177. {mdprep-0.3.0 → mdprep-0.5.0}/examples/13_qmmm_refinement_gxtb_mechanical.yaml +0 -0
  178. {mdprep-0.3.0 → mdprep-0.5.0}/examples/14_qmmm_refinement_mace_polar1_mechanical.yaml +0 -0
  179. {mdprep-0.3.0 → mdprep-0.5.0}/examples/15_roe_brooks_openmm.yaml +0 -0
  180. {mdprep-0.3.0 → mdprep-0.5.0}/examples/16_besd_halogenase_gfn2_mcpb.yaml +0 -0
  181. {mdprep-0.3.0 → mdprep-0.5.0}/examples/colab/mdprep_colab_pipeline.py +0 -0
  182. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/_selftest_data/basic_protein.yaml +0 -0
  183. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/_selftest_data/ligand_sub.mol2 +0 -0
  184. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ambertools/__init__.py +0 -0
  185. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ambertools/antechamber.py +0 -0
  186. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ambertools/commands.py +0 -0
  187. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ambertools/mol2.py +0 -0
  188. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ambertools/parmchk2.py +0 -0
  189. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ambertools/resp.py +0 -0
  190. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/charges/__init__.py +0 -0
  191. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/charges/esp_grid.py +0 -0
  192. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/config/__init__.py +0 -0
  193. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/config/loader.py +0 -0
  194. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/external/__init__.py +0 -0
  195. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/external/discovery.py +0 -0
  196. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/external/runner.py +0 -0
  197. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/__init__.py +0 -0
  198. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/forcefields.py +0 -0
  199. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/ions.py +0 -0
  200. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/log_parser.py +0 -0
  201. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/leap/runner.py +0 -0
  202. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ligands/__init__.py +0 -0
  203. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ligands/extract.py +0 -0
  204. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ligands/identity.py +0 -0
  205. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ligands/pyscf_charges.py +0 -0
  206. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/ligands/report.py +0 -0
  207. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/md/__init__.py +0 -0
  208. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/md/imaging.py +0 -0
  209. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/__init__.py +0 -0
  210. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/c4.py +0 -0
  211. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/hydrogenate.py +0 -0
  212. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/mace_polar1_hessian.py +0 -0
  213. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/mace_polar1_worker.py +0 -0
  214. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/mcpb_compat.py +0 -0
  215. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/nonbonded.py +0 -0
  216. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/metals/parameter_comparison.py +0 -0
  217. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/__init__.py +0 -0
  218. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/apply.py +0 -0
  219. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/disulfide_states.py +0 -0
  220. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/histidine_geometry.py +0 -0
  221. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/overrides.py +0 -0
  222. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/pka_rules.py +0 -0
  223. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/propka.py +0 -0
  224. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/propka_parser.py +0 -0
  225. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/report.py +0 -0
  226. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/states.py +0 -0
  227. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/xtb_parser.py +0 -0
  228. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/protonation/xtb_runner.py +0 -0
  229. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/qm/__init__.py +0 -0
  230. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/qm/point_charges.py +0 -0
  231. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/qm/pyscf_esp.py +0 -0
  232. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/qm/pyscf_runner.py +0 -0
  233. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/qm/xtb_esp.py +0 -0
  234. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/__init__.py +0 -0
  235. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/ash.py +0 -0
  236. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/coordinates.py +0 -0
  237. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/mapping.py +0 -0
  238. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/openmm_minimizer.py +0 -0
  239. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/report.py +0 -0
  240. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/refinement/workflow.py +0 -0
  241. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/reports/__init__.py +0 -0
  242. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/__init__.py +0 -0
  243. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/disulfides.py +0 -0
  244. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/reader.py +0 -0
  245. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/rename.py +0 -0
  246. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/structure/selectors.py +0 -0
  247. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/validation/__init__.py +0 -0
  248. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/validation/openmm_check.py +0 -0
  249. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/validation/parmed_check.py +0 -0
  250. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/__init__.py +0 -0
  251. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/init.py +0 -0
  252. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/inspect.py +0 -0
  253. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/prepare.py +0 -0
  254. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/selftest.py +0 -0
  255. {mdprep-0.3.0 → mdprep-0.5.0}/src/mdprep/workflows/validate.py +0 -0
  256. {mdprep-0.3.0 → mdprep-0.5.0}/tests/__init__.py +0 -0
  257. {mdprep-0.3.0 → mdprep-0.5.0}/tests/besd_structure.py +0 -0
  258. {mdprep-0.3.0 → mdprep-0.5.0}/tests/browser/launch.mjs +0 -0
  259. {mdprep-0.3.0 → mdprep-0.5.0}/tests/browser/smoke.mjs +0 -0
  260. {mdprep-0.3.0 → mdprep-0.5.0}/tests/conftest.py +0 -0
  261. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/amber/README.md +0 -0
  262. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/amber/ace_ala_gly_nme.inpcrd +0 -0
  263. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/amber/ace_ala_gly_nme.prmtop +0 -0
  264. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/boltz_far_donor.cif +0 -0
  265. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/boltz_model.cif +0 -0
  266. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/boltz_smiles_ligands.cif +0 -0
  267. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/boltz_wide_names.cif +0 -0
  268. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_cof.frcmod +0 -0
  269. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_cof.good.mol2 +0 -0
  270. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.atom_count_mismatch.mol2 +0 -0
  271. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.bad_charge.mol2 +0 -0
  272. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.frcmod +0 -0
  273. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.good.mol2 +0 -0
  274. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.pdb +0 -0
  275. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.renamed.mol2 +0 -0
  276. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.shifted_coords.mol2 +0 -0
  277. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/ligands/ligand_sub.small_residual.mol2 +0 -0
  278. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/propka_sample.pka +0 -0
  279. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_altloc.pdb +0 -0
  280. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_atom_record_ligand_blank_chain.pdb +0 -0
  281. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_blank_chain.pdb +0 -0
  282. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_cyx_disulfide.pdb +0 -0
  283. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_disulfide.pdb +0 -0
  284. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_histidine_ring.pdb +0 -0
  285. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_histidine_ring_hydrogenated.pdb +0 -0
  286. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_histidine_water_oxygen.pdb +0 -0
  287. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_histidine_zinc.pdb +0 -0
  288. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_insertion_code.pdb +0 -0
  289. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_two_ligands.pdb +0 -0
  290. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_with_hydrogenated_free_lysine.pdb +0 -0
  291. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_with_hydrogens.pdb +0 -0
  292. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_with_waters.pdb +0 -0
  293. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/protein_zinc_aqua.pdb +0 -0
  294. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/xtb_hid_stdout.txt +0 -0
  295. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/xtb_hie_stdout.txt +0 -0
  296. {mdprep-0.3.0 → mdprep-0.5.0}/tests/data/zinc_only.pdb +0 -0
  297. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_altloc.py +0 -0
  298. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_amber_resp.py +0 -0
  299. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_ambertools_commands.py +0 -0
  300. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_browser_planning_path.py +0 -0
  301. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_build_residues_is_defined_once.py +0 -0
  302. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_classify.py +0 -0
  303. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_cli.py +0 -0
  304. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_colab_wizard_notebook.py +0 -0
  305. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_config_examples.py +0 -0
  306. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_config_validation.py +0 -0
  307. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_coordinating_ions.py +0 -0
  308. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_disulfide_assignment.py +0 -0
  309. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_disulfide_leap_mapping.py +0 -0
  310. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_disulfides.py +0 -0
  311. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_esp_grid.py +0 -0
  312. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_amber_resp.py +0 -0
  313. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_ambertools.py +0 -0
  314. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_mace_polar1.py +0 -0
  315. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_md_restraint_frame.py +0 -0
  316. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_md_snapshot_box.py +0 -0
  317. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_metals.py +0 -0
  318. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_propka_xtb.py +0 -0
  319. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_pyscf.py +0 -0
  320. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_structure_repair.py +0 -0
  321. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_tleap.py +0 -0
  322. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_external_xtb_embedding.py +0 -0
  323. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_histidine_cluster_metal.py +0 -0
  324. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_histidine_geometry.py +0 -0
  325. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_import.py +0 -0
  326. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_init_cli.py +0 -0
  327. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_init_ligand_placeholders.py +0 -0
  328. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_inspect_cli.py +0 -0
  329. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_ions.py +0 -0
  330. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_leap_forcefields.py +0 -0
  331. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_leap_input_pdb.py +0 -0
  332. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_leap_ligand_residue_names.py +0 -0
  333. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_leap_log_parser.py +0 -0
  334. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_ligand_extraction.py +0 -0
  335. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_ligand_mol2_validation.py +0 -0
  336. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_ligand_workflow_mocked.py +0 -0
  337. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_mace_polar1_hessian.py +0 -0
  338. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_manifest_paths.py +0 -0
  339. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_manual_protonation.py +0 -0
  340. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_mcpb_compat.py +0 -0
  341. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_mcpb_pyscf_fixed_geometry.py +0 -0
  342. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_md_config.py +0 -0
  343. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_md_imaging.py +0 -0
  344. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_metal_hydrogenation_preservation.py +0 -0
  345. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_mmcif.py +0 -0
  346. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_mol2_parser.py +0 -0
  347. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_mol2_validation.py +0 -0
  348. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_no_openbabel.py +0 -0
  349. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_pdb_large_serials.py +0 -0
  350. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_pdb_parser.py +0 -0
  351. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_pdb_roundtrip_property.py +0 -0
  352. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_pka_rules.py +0 -0
  353. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_point_charges.py +0 -0
  354. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_prediction_pdb_quirks.py +0 -0
  355. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_prepare_ligands_stage.py +0 -0
  356. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_prepare_protonation_stage.py +0 -0
  357. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_prepare_pyscf_ligands_stage.py +0 -0
  358. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_prepare_refinement_stage.py +0 -0
  359. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_prepare_structure_stage.py +0 -0
  360. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_prepare_tleap_stage.py +0 -0
  361. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_propka_parser.py +0 -0
  362. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_protonation_propka_workflow.py +0 -0
  363. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_protonation_reuse_refined.py +0 -0
  364. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_protonation_states.py +0 -0
  365. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_protonation_xtb_workflow.py +0 -0
  366. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_pyscf_esp_mocked.py +0 -0
  367. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_pyscf_runner_config.py +0 -0
  368. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_qmmesp_correctness.py +0 -0
  369. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_qmmesp_final_mol2_usage.py +0 -0
  370. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_qmmesp_no_environment_fit.py +0 -0
  371. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_readme_example.py +0 -0
  372. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_refinement_ash.py +0 -0
  373. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_refinement_config.py +0 -0
  374. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_refinement_coordinates.py +0 -0
  375. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_refinement_openmm.py +0 -0
  376. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_refinement_platform.py +0 -0
  377. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_refinement_report.py +0 -0
  378. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_remove_hydrogens.py +0 -0
  379. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_residue_rename.py +0 -0
  380. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_roe_brooks_restraints.py +0 -0
  381. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_selectors.py +0 -0
  382. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_selftest_installed.py +0 -0
  383. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_structure_normalize.py +0 -0
  384. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_temporary_hydrogenation_hold_back.py +0 -0
  385. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_tleap_workflow_mocked.py +0 -0
  386. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_validation_helpers.py +0 -0
  387. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_validation_topology.py +0 -0
  388. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_web_bundle_zip.py +0 -0
  389. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_xtb_command_builder.py +0 -0
  390. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_xtb_esp.py +0 -0
  391. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_xtb_parser.py +0 -0
  392. {mdprep-0.3.0 → mdprep-0.5.0}/tests/test_xtb_water_hydrogens.py +0 -0
  393. {mdprep-0.3.0 → mdprep-0.5.0}/web/.gitignore +0 -0
  394. {mdprep-0.3.0 → mdprep-0.5.0}/web/build.py +0 -0
  395. {mdprep-0.3.0 → mdprep-0.5.0}/web/zip.js +0 -0
@@ -65,8 +65,9 @@ Explicitly unsupported for v0.2:
65
65
  - covalent ligands
66
66
  - ORCA backend
67
67
  - Multiwfn dependency
68
- - multiple independent bonded MCPB sites
69
- - multi-chain MCPB protein inputs
68
+ - multiple independent bonded MCPB sites (copies of one site in an oligomer
69
+ share a single fit through `parameters_from`; see `docs/oligomers.md`)
70
+ - bonded MCPB sites bound by more than one protein chain
70
71
 
71
72
  ## Required Checks
72
73
 
@@ -0,0 +1,497 @@
1
+ # Changelog
2
+
3
+ ## 0.5.0 - 2026-10-23
4
+
5
+ ### Added
6
+
7
+ - The web builder's **Load SyrB2 (PDB 2FCT)** button: the workshop's worked
8
+ example, for a student with no structure of their own, fetched from RCSB as
9
+ a typed ID would be.
10
+ - `mdprep.workflows.runtime.full_toolchain_manifest()`: a manifest that calls
11
+ every program mdprep installs, for an environment built before the real
12
+ manifest exists.
13
+ - Hemes and other metals deposited inside a cofactor. The PDB writes heme b as
14
+ one residue, HEM, with its iron among its atoms; mdprep now moves the metal
15
+ into a residue of its own as any structure is read, named after the element
16
+ with the cofactor's chain and number, and the porphyrin left behind is a
17
+ ligand that coordinates it. A cytochrome P450 becomes an ordinary bonded
18
+ iron site: the four porphyrin nitrogens, the cysteine and the water. The
19
+ oxidation state is asked, not read off the assigned name. Heme b's SMILES
20
+ and net charge (-4, both propionates ionised) are proposed with the
21
+ assumption stated. See `docs/metals.md`.
22
+ - `examples/19_cyp119_heme_mcpb.yaml` and the vendored 1IO7 deposition:
23
+ CYP119 at rest, low-spin Fe(III).
24
+ - `mcpb.pyscf.xtb.electronic_temperature_kelvin`: Fermi smearing for the xTB
25
+ Hessian and the GFN2 ESP of the large model. An open-shell heme's SCF does
26
+ not converge at xTB's own 300 K; the builder sets 1000 K for a site whose
27
+ donors include a heme, and an SCF failure without it names the setting.
28
+ - A residue still holding several metal atoms (an iron-sulfur cluster) and
29
+ heme c, a covalent ligand, are refused with the reason before any question
30
+ is asked.
31
+ - Heterogens that are not ligands. mdprep reads the bonds a deposition
32
+ declares (PDB LINK, mmCIF `_struct_conn`) and its modified residues (MODRES,
33
+ `_pdbx_struct_mod_residue`), and sorts the heterogens before asking about
34
+ ligands: modified residues in a chain, glycans, other heterogens bonded to
35
+ the protein, and crystallisation additives. Each group is one question with
36
+ every member listed. Glycans and additives are proposed for removal, a
37
+ selenomethionine for replacement by methionine; anything else is asked
38
+ without a proposal, and keeping what cannot be built stops at the question.
39
+ See `docs/heterogens.md`.
40
+ - `structure.remove_residues`: residues left out on purpose, each with its
41
+ reason, applied before anything else looks at the structure and reported.
42
+ - `structure.repair.replace_modified_residues`: modified residues replaced by
43
+ their standard parents through PDBFixer, exactly the ones listed.
44
+ - A metal that is not inside a cofactor can be removed on its model question
45
+ (a nickel from a His-tag purification). Magnesium and calcium are proposed
46
+ nonbonded.
47
+ - The SMILES and net charge of FAD, FMN, SAM, SAH, NAD+, NADH, NADP+ and NADPH
48
+ are proposed, at pH 7, with the protonation stated; each is tested against
49
+ a deposited cofactor.
50
+ - `examples/20_upo_5oxu_heme_glycans.yaml` (an unspecific peroxygenase:
51
+ heme-thiolate, magnesium, N-glycans, additives) and
52
+ `examples/21_prna_fad_halogenase.yaml` (a flavin-dependent halogenase),
53
+ with their depositions. `docs/enzyme_families.md` lists what mdprep does
54
+ with each family of halogenating and dehalogenating enzymes.
55
+ - Refused when the structure is loaded, with the reason: a cofactor bonded to
56
+ the protein that holds a metal (myeloperoxidase's heme), an oxoanion such as
57
+ vanadate, a modified residue with no standard parent, and a declared bond
58
+ between protein residues that is neither a peptide bond nor a disulfide.
59
+
60
+ ### Changed
61
+
62
+ - The spin is asked once, for the QM region. The per-metal multiplicity
63
+ question is gone; the QM region's answer is also the bonded site's
64
+ `ions[].multiplicity` and MCPB model spins.
65
+ - Crystallisation additives are no longer offered one by one as ligands
66
+ unless their removal is declined.
67
+ - The official Colab notebook takes its structure only from the builder's
68
+ bundle. Its predicted-model section (closest X-ray structure, crystal
69
+ waters), the SyrB2 example and the upload of an earlier run's results are
70
+ gone; `mdprep closest-xray` and `mdprep transplant-waters` still bring
71
+ waters across on the command line. It installs every program mdprep runs
72
+ first, before there is a bundle, so the install runs while the builder's
73
+ questions are answered; the MD follows the preparation directly, and the
74
+ investigation of both comes after. Sections, old to new: C to A, D to C,
75
+ F to D, G to F, H to G, I to H, J to I; B and E1-E8 keep their letters.
76
+
77
+ - The protonation of a titratable side chain on a metal is asked right after
78
+ the coordination shell is confirmed, before the spin and the model charge.
79
+ - Proposals carry their own explanation, shown by the builder and the
80
+ `mdprep init --interactive` wizard alike.
81
+
82
+ ### Fixed
83
+
84
+ - A metal-bound cysteine stated as CYM stopped the protonation stage: OpenMM
85
+ calls the thiolate's hydrogen variant CYX. Every cysteine donor -- a zinc
86
+ finger's, a heme's -- reached this.
87
+ - The proposed model charge read a donor's charge from its residue name, so a
88
+ cysteine stated as CYM counted as neutral and an aspartate stated as ASH as
89
+ -1. It now counts the state given, and proposes nothing until it is given.
90
+ - The builder named a residue once per highlighted atom.
91
+ - The ligand bond-order check measured conjugated single bonds against
92
+ saturated lengths, so every amide, amino-heterocycle and flavin looked like
93
+ a wrong tautomer and a SMILES for FAD, NAD or SAM could not be applied.
94
+ - A heme on both a bonded iron and a nonbonded magnesium, as in a
95
+ peroxygenase, was refused for taking its charges from the magnesium's
96
+ non-existent fit.
97
+ - QM/MM refinement stopped on a nonbonded metal or a crystal ion next to the
98
+ QM region; both are MM environment with known parameters.
99
+ - A lysine PropKa made neutral lost a hydrogen's charge in the embedding of
100
+ the xTB histidine comparison: OpenMM names its amine hydrogens HZ1 and HZ2,
101
+ ff14SB's LYN HZ2 and HZ3. The histidines around it were compared beside a
102
+ lysine at -0.39 e, and the report asked for the lysine to be declared as a
103
+ ligand. PrnA's Lys79 reached this: its four histidines keep their states,
104
+ but their HID-HIE gaps moved by 1 to 3 kcal/mol, enough to flip a closer
105
+ call.
106
+ - A vanadate was split into a vanadium and four unbonded oxygens.
107
+ - Replacing a modified residue stopped the run unless
108
+ `structure.repair.add_missing_heavy_atoms` was set: PDBFixer keeps a blank
109
+ insertion code as a space, so the replaced residue's own new atoms counted
110
+ as unrequested. Any replacement in a structure missing nothing else reached
111
+ this, 1CPO's pyroglutamate among them. A chain's terminal OXT, which the
112
+ planner never asks about, stopped such a run too; it is left to tleap.
113
+ - A pyroglutamate replaced by glutamine kept its lactam's CD 1.5 A from its
114
+ own backbone nitrogen. A replaced side chain bonded to its own backbone is
115
+ rebuilt beyond CB from the parent's template, listed under
116
+ `side_chain_rebuilt`, with a warning naming its closest contact.
117
+ - The g-xTB Hessian of a high-spin heme site could fail to converge, or
118
+ converge in whichever of two states the thread count led it to: on 2QFK's
119
+ aquo Fe(III), 27 kcal/mol apart, with Fe-N force constants up to 1.7 times
120
+ different. `mcpb.pyscf.xtb.scf_annealing_kelvin` converges the SCF straight
121
+ and from each hotter temperature listed, single-threaded, and takes the
122
+ Hessian from the lowest; the builder sets it, with `max_scf_iterations:
123
+ 3000`, for every heme site. Examples 19 and 20 carry both. 2QFK itself now
124
+ stops every time at the same place, a negative His-Fe-N angle constant,
125
+ instead of passing or failing by the thread count. See `docs/metals.md`.
126
+ - A Seminario term MCPB.py found negative and wrote as zero was reported only
127
+ as a 0.0 in the frcmod; the error now names it, its atoms and its value.
128
+ - The bond-order check read a porphyrin bond by bond, so 2QFK's heme, refined
129
+ with one pyrrole's beta-beta bond at single-bond length, was refused as a
130
+ wrong tautomer of heme b. A porphyrin's core is skipped like a carboxylate;
131
+ a chlorin's reduced ring is still checked.
132
+
133
+ ## 0.4.0 - 2026-10-20
134
+
135
+ ### Added
136
+
137
+ - Dimers, trimers and tetramers. Every protein chain can be prepared in one
138
+ system, and when the chains are copies of one protein the builder asks
139
+ whether every copy should get the same parameters. If so it asks about the
140
+ first copy only and gives each answer to the matching residue of the others,
141
+ matched by sequence and by position rather than by residue number, which
142
+ copies often do not share (2FCT numbers its two alpha-ketoglutarates 897 and
143
+ 898). A ligand is parameterised once; a bonded metal site is fitted once with
144
+ MCPB.py, and each copy's residues take the fit's templates and its metal the
145
+ fit's bonds. A copy whose site differs -- 6NIE's chains B and C bind
146
+ alpha-ketoglutarate through the other carboxylate oxygen -- is reported and
147
+ asked about on its own. See `docs/oligomers.md`.
148
+ - `parameters_from` on ligands and metal sites: a block built with another
149
+ block's parameters, checked by `config-check` to repeat its settings and, for
150
+ a bonded site, to list its residues in the reference's order.
151
+ - `examples/18_syrb2_dimer_shared_mcpb.yaml`: both copies of SyrB2, one fit.
152
+ - `mdprep.analysis.charges.metal_sites`: each metal site's charge on its own,
153
+ which the official notebook now shows one table per site.
154
+ - The web builder lists which chains are copies of one protein, shows the
155
+ chain and copy questions with each chain in its own colour, and names
156
+ residues with their chain.
157
+ - Refusals the answers already make certain are given at the question that
158
+ causes them, in the web builder and in `mdprep init --interactive`: a second
159
+ bonded metal site needing a fit of its own, or a cofactor whose charges were
160
+ to come from a site made nonbonded. Every `DecisionError` names the question
161
+ to go back to (`decision_id`), and the page goes there.
162
+
163
+ - The official Colab notebook, `examples/mdprep_colab.ipynb`: takes a bundle
164
+ from the web builder (or runs the SyrB2 example), prepares and equilibrates
165
+ the system, and shows every step -- the structure after each stage, the
166
+ protonation states, the charge on every atom in tables and in 3D, the metal
167
+ site's MCPB force constants, how temperature, density and volume
168
+ equilibrated, the structure after each Roe-Brooks step, and the trajectory
169
+ with its RMSD, RMSF and metal-site distances. The web builder links to it.
170
+ - `mdprep closest-xray`: the X-ray structures closest to a predicted model,
171
+ from the RCSB sequence search, with resolution, waters and bound ligands;
172
+ those holding the model's metal come first.
173
+ - `mdprep transplant-waters`: a reference structure's crystal waters on a
174
+ predicted model. PyMOL pairs the residues (by sequence, or by structure for a
175
+ distant homologue); each model chain takes its best reference chain; a water
176
+ bound to a metal moves with it onto the model's metal; clashing and bulk
177
+ waters are dropped; a reference of another fold is refused. Every decision
178
+ is in a JSON report.
179
+ - `mdprep.analysis`: reads a prmtop, inpcrd and OpenMM DCD with numpy alone,
180
+ and provides charge tables, the metal site's force constants, imaged and
181
+ superposed trajectories, RMSD, RMSF and distances, and the equilibration and
182
+ production logs.
183
+ - `equilibration.csv` in every Roe-Brooks run: every stage on one time axis,
184
+ with temperature, density, box volume and energies every 0.5 ps.
185
+ - `docs/predicted_structures.md`: from a Boltz or AlphaFold3 prediction to a
186
+ model with its crystal waters, with the worked SyrB2 example.
187
+ - `examples/17_syrb2_bound_water_mcpb.yaml` and the vendored 2FCT deposition.
188
+ - When a structure with a metal has no waters at all, the metal question says
189
+ so and points to `mdprep transplant-waters`.
190
+
191
+ - Waters bound to a bonded metal site, as the resting iron of an
192
+ alpha-ketoglutarate enzyme carries (SyrB2, PDB 2FCT). The decision engine
193
+ proposes the water as a donor; mdprep writes the TIP3P template MCPB.py
194
+ requires, supplies the H-O-H angle rigid TIP3P lacks, and counts the water as
195
+ neutral in the QM/MM refinement.
196
+ - `structure.keep_crystal_ions` and its question: free monatomic ions resolved
197
+ in the crystal (Cl-, Na+, Br-, ...) are kept or removed as a group, and
198
+ listed in the structure report either way.
199
+
200
+ ### Changed
201
+
202
+ - **Free crystal ions are kept by default.** A free monatomic ion in the input
203
+ used to count as an unknown heterogen, so a manifest with
204
+ `structure.remove_unknown_heterogens: true` dropped it. It is now governed by
205
+ `structure.keep_crystal_ions`, which defaults to `true`, so the same manifest
206
+ builds with the ion in place: 2FCT's free chloride, for one. Add
207
+ `keep_crystal_ions: false` to keep the old result. Every ion kept or removed
208
+ is listed in `reports/structure_report.md`.
209
+ - Two bonded metal sites are refused by `mdprep config-check`, where 0.3.0
210
+ refused them only once a run had started.
211
+
212
+ ### Fixed
213
+
214
+ - CUDA did not start on Colab's T4 GPUs (OpenCL did):
215
+ - conda-forge installed a CUDA runtime newer than the GPU driver, whose
216
+ kernels the driver refused (`CUDA_ERROR_UNSUPPORTED_PTX_VERSION`);
217
+ - the setup the notebook and the web builder run now caps `cuda-version`
218
+ at the driver's version, and rerunning section C repairs an existing
219
+ environment;
220
+ - `mdprep doctor` starts a CUDA system to check;
221
+ - a CUDA failure in the MD says what to do, and `auto` says which
222
+ platform it passed over.
223
+ - The official notebook drew the final structure (E3) from tleap's PDB, which
224
+ has no elements, so the viewer read hydrogens such as HG21 as mercury and
225
+ bonded them to everything near. It is now drawn from the topology, as E8
226
+ and H are. Each protein molecule is now its own chain in every view, so no
227
+ cartoon runs from one copy of a dimer into the next or across a missing
228
+ loop. A chloride on the iron, one atom with no bond to draw, now shows as a
229
+ sphere.
230
+ - Keeping one chain of a predicted oligomer kept every ligand chain too, so the
231
+ other copy's iron and cofactor floated in the box. A chain holding only
232
+ heterogens now goes with the protein chain it sits against.
233
+ - The spin of the QM region was asked of any structure with two metals, even
234
+ when neither turned out bonded; it is now asked once a bonded site is
235
+ confirmed, whichever site that is.
236
+ - `DecisionPlan.applicable` counted an answer whose own question was no longer
237
+ reachable -- a shell confirmed before the site was switched to nonbonded.
238
+ - The ligand coordinate check after tleap could not tell two copies of one
239
+ cofactor apart, since tleap renumbers residues; it now takes the copy nearest
240
+ the ligand it checks.
241
+ - The web builder and the wizard told a student to add a SMILES to a ligand
242
+ without hydrogens after asking for it and being given it.
243
+ - `mdprep init --interactive` re-asked a rejected answer without saying why.
244
+
245
+ - A residue name mdprep assigned (a predicted iron called `LIG1` read as `FE`)
246
+ lost that record when the structure was written and read back, and `FE` read
247
+ cold is the CCD code for Fe(III): the planner then proposed +3 for an Fe(II)
248
+ site. mdprep's PDB writer records assigned names in a remark its reader
249
+ honours.
250
+ - The model-charge proposal ignored an oxidation state accepted as proposed,
251
+ so a student added the terms up by hand.
252
+ - The old Colab run notebook ran the MD twice: `mdprep prepare` already runs it
253
+ when the manifest enables it. It now points to the official notebook, which
254
+ stops `prepare` before the MD.
255
+ - A free crystal chloride was offered as a ligand and then refused as a
256
+ reserved residue name, telling the user to rename it. tleap builds it from
257
+ its ion library like any counterion; it is no longer a ligand candidate, and
258
+ a histidine xTB cluster that contains one counts its charge.
259
+ - A topology with a water and a halide on the same metal went to NaN in
260
+ heating: their 1-4 pair through the metal had a Coulomb attraction and no
261
+ repulsion. Those 1-4 terms are now switched off in the prmtop and listed in
262
+ the tleap report.
263
+ - tleap bonded the two ends of an unresolved loop into one peptide bond, 6.08 A
264
+ long in 2FCT. A TER is now written wherever C(i)-N(i+1) exceeds 2 A.
265
+ - The crystal-water and unknown-heterogen questions disappeared whenever any
266
+ water coordinated any metal -- in 6NIE, three waters on a surface iron of
267
+ chain B hid the question for all 847. Both are asked now, and the
268
+ crystal-water question names the bound waters that are kept regardless.
269
+ - A water bound to a metal was dropped with the other crystal waters when
270
+ those were removed: for a bonded site that left an MCPB bond to a residue
271
+ that no longer existed, and for a nonbonded one it stripped the ion's first
272
+ shell, though the question had said it would stay. The question and
273
+ normalisation now share one definition of a bound water
274
+ (`mdprep.structure.coordination`).
275
+ - Declining a ligand while keeping unknown heterogens, dropping crystal waters
276
+ with a bonded site, or choosing OPC with a water bound to a bonded metal now
277
+ fail in the builder with what to change, instead of later in Colab.
278
+ - The QM-region spin proposal ignored defaults the user had accepted without
279
+ typing them, so a bonded iron with the default model got no proposal.
280
+
281
+ ## 0.3.0 - 2026-10-19
282
+
283
+ ### Added
284
+
285
+ - `mdprep plan` and `mdprep init --interactive`: a structure-aware decision
286
+ engine that reduces a 250+ setting schema to the questions one structure
287
+ actually needs, and asks them. Chemistry-sensitive values have no default and
288
+ cannot be skipped.
289
+ - Each decision carries viewer hints (`focus`, `targets`, `target_resnames`) so
290
+ a 3D front end can frame exactly the residues a question is about.
291
+ - `mdprep inspect` reports free monatomic metal ions.
292
+ - A static web input builder (`web/`) that runs mdprep in the browser under
293
+ Pyodide, shows a 3D view framed on whatever each question is about, and
294
+ produces a validated manifest plus runnable Colab cells.
295
+ - `mdprep.workflows.runtime.conda_packages_for` derives the external toolchain a
296
+ given manifest needs, so a generated setup cell installs PropKa, xTB or PySCF
297
+ only when the run will actually invoke them.
298
+
299
+ - `mdprep doctor` checks that the external tools a given manifest will invoke
300
+ are installed, and names the one command that installs what is missing.
301
+ - mmCIF and ModelCIF input: a structure predicted by Boltz or AlphaFold is read
302
+ directly, with no conversion step and no loss of the chain and residue
303
+ identifiers the manifest selects on.
304
+ - Four-character residue names, hybrid-36 serial and residue numbers, and
305
+ residues whose name does not fit a PDB column, which a predicted structure
306
+ written to PDB reaches routinely. A name mdprep has to assign is recorded as
307
+ assigned, so nothing downstream reads chemistry into a name it invented.
308
+ - `metals[].coordinating_ions` declares a non-metal ion bound in a metal site,
309
+ such as a coordinating halide, which previously had nowhere to live: it is
310
+ not a metal, and antechamber cannot treat a single atom.
311
+ - The setup cell downloads the g-xTB build of xtb from the Grimme group's
312
+ releases and checks it against the published checksum, because conda-forge
313
+ carries only the GFN-only build.
314
+
315
+ - `structure.keep_chains` restricts a build to named chains, which a bonded
316
+ MCPB site requires and a multi-copy crystal structure needs.
317
+ - The decision engine proposes a metal coordination sphere from interatomic
318
+ distances, requires it to be confirmed, and generates the bonded MCPB block
319
+ with a GFN2 Seminario Hessian and GFN2 QM/MM refinement geometry.
320
+ - `examples/16_besd_halogenase_gfn2_mcpb.yaml`, the BesD halogenase reference
321
+ case.
322
+ - Detection of incomplete residues and chain breaks, asked about before any
323
+ expensive stage runs, and protection for waters coordinating a metal.
324
+ - `examples/mdprep_colab_run.ipynb`, a Colab notebook that runs a manifest and
325
+ installs only the toolchain that manifest needs.
326
+
327
+ - `metals[].coordinating_ions` declares a non-metal ion bound in a metal site,
328
+ such as a coordinating halide, which previously had nowhere to live: it is
329
+ not a metal and antechamber cannot treat a single atom.
330
+
331
+ ### Changed
332
+
333
+ - The refinement stage defaults to `backend: openmm`, a force-field hydrogen
334
+ relaxation, instead of GFN2 QM/MM. The stage only ever moved hydrogens, and
335
+ a force field settles them in seconds. `backend: ash` keeps the QM/MM route
336
+ and is required to relax heavy atoms. `movable_atoms` and
337
+ `post_refinement_protonation` default to match the hydrogen-only backend.
338
+ - Histidine HID/HIE selection stays with xTB: force-field energies of the two
339
+ tautomers are not comparable, because they are different residue templates
340
+ rather than one molecule with a proton moved.
341
+
342
+ - Dropped the unused `scipy` and `pandas` runtime dependencies.
343
+ - A ligand that coordinates a bonded metal site now defaults to taking its
344
+ charges from that site's MCPB fit instead of AM1-BCC.
345
+ - A metal site's Hessian defaults to g-xTB rather than GFN2. GFN2 has no
346
+ parameters for most transition metals, and said so only after the run had
347
+ got as far as the Hessian.
348
+ - **A ligand whose residue name an Amber force field already defines is now
349
+ refused, where it used to be renamed for the build.** `LYS` became `LY1`,
350
+ which satisfied tleap and moved the problem: the prepared system then
351
+ described a residue under a name the input never used, and every later
352
+ reader had to know about the substitution. A manifest that declares such a
353
+ ligand now fails, in the GUI before it asks anything and on the command line
354
+ before any quantum chemistry, and says which residue to rename. The web
355
+ builder offers to make the change in the input.
356
+ - **`refinement.total_qm_multiplicity` is now required whenever any component
357
+ of the QM region is open-shell**, where it used to be taken from the first
358
+ open-shell component found. For a lone high-spin Fe(II) that is the right
359
+ answer and it was right by accident: it holds only while the ion is the
360
+ single unpaired centre and nothing couples to it, which nothing in a
361
+ manifest can check. Existing manifests that leave it out of an open-shell
362
+ region will fail validation and need the value added.
363
+ - Preparing the same system the same way twice now yields the same atom count.
364
+ MD starting velocities stay random and the seed drawn for each run is
365
+ recorded, so a replicate can be repeated by putting that number back.
366
+
367
+ ### Fixed
368
+
369
+ - Per-step MD snapshots are written in the box the manifest asked for. They
370
+ carried the pre-NPT cell, because `PDBFile` takes CRYST1 from the topology
371
+ and the topology was the one loaded at the start, and they were wrapped into
372
+ the parallelepiped OpenMM spans rather than imaged about the solute -- so a
373
+ truncated octahedron came back as a sheared prism with the protein off to
374
+ one side and its water drawn 70 A away instead of 54 A.
375
+ - The ESP grid survives an xTB crash on its last point, and the fit uses the
376
+ grid that was actually evaluated rather than the one that was requested.
377
+ - A metal in a predicted structure is named after its element, so a site is
378
+ not identified by a name the prediction never meant as one.
379
+ - CONECT records that cover only part of a ligand are ignored rather than
380
+ treated as its whole connectivity.
381
+ - tleap writes its own atom types into the element column of the PDB it
382
+ outputs; the reader no longer believes them.
383
+ - The setup cell installs PDBFixer whenever a run will need it, not only when
384
+ structure repair happens to pull it in, and the resolver is checked against
385
+ every combination of options rather than the one that was reported.
386
+ - A titratable side chain coordinating a metal is asked about, from the same
387
+ contact list the bonds come from, instead of refusing the run later.
388
+ - Guessed force-field parameters (`ATTN, need revision`) and the OpenMM energy
389
+ check are both checked when the manifest asks for them.
390
+ - Many GUI fixes: the Finish button reports what went wrong instead of doing
391
+ nothing, re-uploading a structure cannot leave the bundle describing the
392
+ previous one, a file that parses to no atoms is rejected, Start over clears
393
+ the answers, Enter fetches a PDB id, and an entry that is mmCIF-only is
394
+ fetched as `.cif`.
395
+
396
+ ## 0.2.1 - 2026-10-01
397
+
398
+ ### Fixed
399
+
400
+ - A ligand whose residue name is one the Amber force fields already define is
401
+ now built under a name they do not. `tleap` resolves residues by name and
402
+ maps an amino-acid name to its terminal form first, so the BesD free-lysine
403
+ substrate was built from the `NLYS` protein template and the run died with
404
+ "Atom .R<NLYS 252>.A<OXT 25> does not have a type" for every one of its
405
+ ligand-named atoms; binding the ligand unit to `LYS` instead would have
406
+ pointed every lysine in the protein at the ligand's parameters. The leap
407
+ input PDB, a copy of the fitted mol2, the `tleap` script and the final
408
+ validation all use the new name, and every rename is reported.
409
+ - The temporary xTB hydrogen environment no longer hydrogenates a residue
410
+ twice. OpenMM matches the hydrogens a residue already has through the bonds
411
+ its residue templates define, so hydrogens mdprep placed from
412
+ `ligands[].smiles`, named after their parent heavy atom, were invisible to it
413
+ and it built a second complete set beside them: the BesD free-lysine
414
+ substrate came out carrying both HB2/HB3 and HB/HBA. Such a residue is now
415
+ passed through untouched and reported, unless a protonation state was decided
416
+ for it, in which case OpenMM still rebuilds it in that state.
417
+ - Amber ion atom types were built as `element + charge + "+"`, which produced
418
+ `Na1+` for every monovalent cation and could not express an anion at all.
419
+
420
+ - Roe--Brooks stage 2 no longer fails with "Particle coordinate is NaN" on
421
+ solvated systems. Free ions were positionally restrained because Amber names
422
+ them `Na+`/`Cl-`, which match no bare element symbol, and coordinates handed
423
+ between stages were wrapped into the periodic box while the restraint
424
+ references stayed unwrapped, placing every wrapped restrained particle a full
425
+ box length from its reference. Stage hand-off and XML restarts now stay in
426
+ the unwrapped frame; only the per-step PDBs and the trajectory are wrapped.
427
+ - Final-output validation no longer rejects its own PDB with "PDB atom serials
428
+ must be unique when present" above 99,999 atoms. Serials are decoded for the
429
+ column-12 overflow `tleap`/`ambpdb` write, for hybrid-36, and for `*****`; a
430
+ genuine wrap-around is renumbered in file order with a warning, and stays
431
+ fatal only when `CONECT` records make the connectivity ambiguous. The PDB
432
+ writer uses the same convention it reads, so structures of that size
433
+ round-trip unchanged.
434
+ - `mdprep inspect --json` no longer emits unparseable JSON on a narrow
435
+ terminal, where rich reflowed long strings to the console width.
436
+
437
+ ### Changed
438
+
439
+ - xTB histidine calculations pin `OMP_NUM_THREADS`, `MKL_NUM_THREADS` and
440
+ `OPENBLAS_NUM_THREADS` to the new `protonation.histidine.xtb.num_threads`
441
+ (default `1`), with `OMP_STACKSIZE` from `omp_stacksize` (default `1G`).
442
+ xTB otherwise opened one thread per hardware thread for every tautomer
443
+ cluster, spending large amounts of CPU time without reducing wall time.
444
+ - `mdprep inspect` also reports free monatomic metal ions.
445
+
446
+ ## 0.2.0 - 2026-08-17
447
+
448
+ ### Added
449
+
450
+ - Explicit nonbonded and bonded MCPB.py metal-center workflows, including
451
+ PySCF QMMESP/RESP charges and PySCF, GFN2-xTB, g-xTB, or MACE-POLAR-1
452
+ Hessian sources for Seminario parameters.
453
+ - Optional ASH active-site QM/MM refinement with explicit QM components,
454
+ coordinating residues, 4 A residue and 8 A water active regions, and
455
+ hydrogen-only relaxation.
456
+ - Manifest-driven Roe--Brooks OpenMM minimization, heating, density
457
+ equilibration, and production MD with accelerator-first/CPU-fallback
458
+ platform selection.
459
+ - User-controlled production step and reporting/checkpoint intervals.
460
+ - Manifest-directory-relative input paths and portable executable discovery.
461
+ - GAFF/GAFF2, ff14SB/ff19SB, TIP3P/OPC, AM1-BCC, gas RESP, and embedded
462
+ QMMESP examples covering the supported preparation combinations.
463
+
464
+ ### Fixed
465
+
466
+ - Roe--Brooks positional restraints are installed before Context creation and
467
+ their reference coordinates are converted explicitly from input units to nm.
468
+ - Constraint-compatible heating handoff, evolving NPT box propagation, and
469
+ production progress totals.
470
+ - MCPB/tLEaP residue-index and renamed-residue coordinate validation.
471
+
472
+ ## 0.1.0 - 2026-06-15
473
+
474
+ Initial usable release.
475
+
476
+ ### Added
477
+
478
+ - YAML manifest validation with pydantic.
479
+ - PDB inspection, residue/atom selector parsing, altloc handling, water and heterogen classification, histidine/titratable residue detection, and possible disulfide detection.
480
+ - `mdprep init` starter-manifest generation and safe structure normalization.
481
+ - Manual protonation overrides, input-state preservation, disulfide `CYX` assignment, and input-hydrogen removal.
482
+ - PropKa-based residue-state assignment and xTB/GFN2 or g-xTB HID/HIE histidine tautomer selection.
483
+ - Ligand extraction and AmberTools parameter generation for `am1bcc` and `user_mol2`.
484
+ - PySCF gas-phase RESP/ESP-like ligand charges.
485
+ - PySCF QMMESP-like environment-polarized ligand charges with explicit target-ligand-only fitting.
486
+ - Final `tleap` build, optional solvation, neutralization/salt handling, final Amber files, and validation reports.
487
+ - External tests that skip cleanly when optional executables or libraries are unavailable.
488
+
489
+ ### Unsupported In 0.1.0
490
+
491
+ - Noncanonical amino acids inside polymer chains.
492
+ - Covalent ligands.
493
+ - Bonded metal-center parameterization and MCPB-like workflows.
494
+ - ORCA and Multiwfn backends.
495
+ - mmCIF input.
496
+ - Automatic loop modeling.
497
+ - Production minimization or MD.
@@ -0,0 +1,114 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ mamba env create -f environment.yml
7
+ conda activate mdprep
8
+ pip install -e .
9
+ mdprep selftest --quick
10
+ ```
11
+
12
+ For packaging and lint tooling, use `environment-dev.yml` or install the
13
+ `dev` extra in a suitable environment.
14
+
15
+ ## Tests
16
+
17
+ Default tests must not require AmberTools, xTB, PropKa, PySCF, ParmEd, or
18
+ OpenMM:
19
+
20
+ ```bash
21
+ pytest -q
22
+ python -m mdprep.cli config-check examples/*.yaml
23
+ python -m mdprep.cli selftest --quick
24
+ ```
25
+
26
+ External tests must skip cleanly when optional tools are unavailable:
27
+
28
+ ```bash
29
+ pytest -q -m "external"
30
+ pytest -q -m "external or ambertools or tleap or propka or xtb or pyscf or qmmesp"
31
+ ```
32
+
33
+ ## Chemistry Rules
34
+
35
+ - The legacy molecule-conversion toolkit identified by the dedicated ban test
36
+ is intentionally prohibited.
37
+ - Do not add molecule-conversion fallbacks.
38
+ - User overrides always win.
39
+ - Do not silently guess catalytic chemistry, ligand charge, protonation, or
40
+ metal-center behavior.
41
+ - Every chemical decision and every residue rename must be reported.
42
+ - Unsupported chemistry must fail with a clear error.
43
+ - External commands must go through `mdprep.external.runner`.
44
+
45
+ ## QMMESP Rules
46
+
47
+ - MM point charges polarize only the selected target ligand QM density.
48
+ - The RESP/ESP fit is performed only on target ligand atoms.
49
+ - Environment point charges must not be fitted.
50
+ - Environment point charges must not be written to ligand mol2 files.
51
+ - The final Amber system must use final PySCF-fitted mol2 charges, not
52
+ provisional charges.
53
+
54
+ ## Adding Features
55
+
56
+ New user-facing features need docs, tests, examples when practical, and clear
57
+ failure behavior for unsupported chemistry. Keep changes local to the relevant
58
+ workflow stage and avoid broad rewrites unless there is a tested reason.
59
+
60
+ ## Releasing
61
+
62
+ Publishing is automatic and tokenless. `.github/workflows/release.yml` fires
63
+ on a `v*` tag and uploads to PyPI through Trusted Publishing, so no API token
64
+ exists to leak or rotate. PyPI is configured to trust this repository, this
65
+ workflow file by name, and the `pypi` environment; renaming either breaks
66
+ publishing until the publisher at
67
+ <https://pypi.org/manage/project/mdprep/settings/publishing/> is updated.
68
+
69
+ To cut a release:
70
+
71
+ 1. Bump the version in `pyproject.toml` and `src/mdprep/__init__.py`, and in
72
+ the README's first line. `tests/test_packaging_metadata.py` fails if the
73
+ first two disagree.
74
+ 2. Retitle the changelog's `## Unreleased` section to `## <version> - <date>`.
75
+ The workflow refuses a tag with no such heading.
76
+ 3. Update the `mdprep[md,qm]==` pin in `examples/*.ipynb` and the assertion in
77
+ `tests/test_colab_smoke_notebook.py`. The web builder installs from git
78
+ master and needs no bump.
79
+ 4. Execute the official notebook end to end (below) and fix whatever it
80
+ finds: it is what students run, and nothing else exercises it whole.
81
+ 5. Merge, then `git tag -a vX.Y.Z` and push the tag.
82
+
83
+ The workflow then refuses a tag that does not match the version in the tree,
84
+ builds, checks that the sdist carries the project and nothing that was lying
85
+ in the working tree, installs the wheel and runs `mdprep selftest --quick`
86
+ from it, publishes to PyPI, and attaches the same two files to the GitHub
87
+ release -- creating one from the changelog section if you have not written
88
+ one by hand.
89
+
90
+ Use semantic versioning against the *manifest*, not just the API: a change
91
+ that makes an existing manifest stop validating is breaking, whatever it did
92
+ to the Python surface.
93
+
94
+ ### Executing the official notebook outside Colab
95
+
96
+ `examples/mdprep_colab.ipynb` runs anywhere with a Linux GPU. Its upload and
97
+ installs are redirected by environment variables, so a Python with mdprep,
98
+ `py3Dmol`, `pandas`, `matplotlib` and `nbclient` can execute it against a
99
+ micromamba runtime built once:
100
+
101
+ ```bash
102
+ MDPREP_COLAB_PREFIX=/scratch/colab \
103
+ MDPREP_SKIP_KERNEL_INSTALL=1 \
104
+ MDPREP_SPEC=$PWD \
105
+ MDPREP_TEST_UPLOAD_BUNDLE=/path/to/mdprep-bundle.zip \
106
+ python -c "import nbformat; from nbclient import NotebookClient; \
107
+ nb = nbformat.read('examples/mdprep_colab.ipynb', 4); \
108
+ NotebookClient(nb, timeout=5400).execute(); nbformat.write(nb, 'executed.ipynb')"
109
+ ```
110
+
111
+ `MDPREP_COLAB_PREFIX` stands in for `/content` (micromamba goes in its `bin/`,
112
+ the environment in `mamba-root/`). The bundle is one the web builder
113
+ downloaded; its SyrB2 button gives one for 2FCT.
114
+