rowan-python 3.2.2__tar.gz → 3.2.4__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 (278) hide show
  1. {rowan_python-3.2.2 → rowan_python-3.2.4}/PKG-INFO +2 -2
  2. rowan_python-3.2.4/examples/mixmd_pocket_detection.py +41 -0
  3. {rowan_python-3.2.2 → rowan_python-3.2.4}/pyproject.toml +2 -2
  4. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/__init__.py +7 -1
  5. rowan_python-3.2.4/rowan/spectra.py +68 -0
  6. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/user.py +1 -3
  7. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/utils.py +63 -14
  8. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/__init__.py +8 -1
  9. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/_molecular_dynamics.py +27 -2
  10. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/conformer_search.py +62 -10
  11. rowan_python-3.2.4/rowan/workflows/pocket_detection.py +253 -0
  12. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/protein_md.py +7 -1
  13. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/protein_preparation.py +4 -0
  14. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/relative_binding_free_energy_perturbation.py +84 -6
  15. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/SKILL.md +1 -1
  16. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/conformer_search.md +19 -0
  17. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/pocket_detection.md +9 -4
  18. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/protein_md.md +43 -1
  19. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/protein_preparation.md +1 -0
  20. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/relative_binding_free_energy_perturbation.md +2 -1
  21. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_conformer_search.py +20 -0
  22. rowan_python-3.2.4/tests/test_download_presigned_files.py +68 -0
  23. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_md_workflow_updates.py +65 -0
  24. rowan_python-3.2.4/tests/test_pocket_detection.py +141 -0
  25. rowan_python-3.2.4/tests/test_rbfe_submission.py +80 -0
  26. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_rbfe_trajectory_download.py +24 -0
  27. rowan_python-3.2.4/tests/test_user.py +22 -0
  28. {rowan_python-3.2.2 → rowan_python-3.2.4}/uv.lock +83 -78
  29. rowan_python-3.2.2/rowan/workflows/pocket_detection.py +0 -118
  30. {rowan_python-3.2.2 → rowan_python-3.2.4}/.claude-plugin/marketplace.json +0 -0
  31. {rowan_python-3.2.2 → rowan_python-3.2.4}/.codex-plugin/plugin.json +0 -0
  32. {rowan_python-3.2.2 → rowan_python-3.2.4}/.editorconfig +0 -0
  33. {rowan_python-3.2.2 → rowan_python-3.2.4}/.envrc +0 -0
  34. {rowan_python-3.2.2 → rowan_python-3.2.4}/.github/workflows/build-and-deploy-docs.yml +0 -0
  35. {rowan_python-3.2.2 → rowan_python-3.2.4}/.github/workflows/publish-skill.yml +0 -0
  36. {rowan_python-3.2.2 → rowan_python-3.2.4}/.github/workflows/python-publish.yml +0 -0
  37. {rowan_python-3.2.2 → rowan_python-3.2.4}/.github/workflows/test.yml +0 -0
  38. {rowan_python-3.2.2 → rowan_python-3.2.4}/.gitignore +0 -0
  39. {rowan_python-3.2.2 → rowan_python-3.2.4}/.python-version +0 -0
  40. {rowan_python-3.2.2 → rowan_python-3.2.4}/.rumdl.toml +0 -0
  41. {rowan_python-3.2.2 → rowan_python-3.2.4}/LICENSE +0 -0
  42. {rowan_python-3.2.2 → rowan_python-3.2.4}/README.md +0 -0
  43. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/api-keys.md +0 -0
  44. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/calculation.md +0 -0
  45. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/folder.md +0 -0
  46. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/molecule.md +0 -0
  47. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/project.md +0 -0
  48. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/protein.md +0 -0
  49. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/user.md +0 -0
  50. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/webhooks.md +0 -0
  51. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/api/workflow.md +0 -0
  52. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/images/RowanLogoLarge.png +0 -0
  53. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/images/RowanSquareLogo.png +0 -0
  54. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/images/favicon.svg +0 -0
  55. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/index.md +0 -0
  56. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/stylesheets/colors.css +0 -0
  57. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/admet.md +0 -0
  58. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/analogue-docking.md +0 -0
  59. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/basic-calculation.md +0 -0
  60. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/batch-docking.md +0 -0
  61. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/binding-affinity.md +0 -0
  62. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/bond-dissociation-energy.md +0 -0
  63. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/conformer-search-settings.md +0 -0
  64. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/conformer-search.md +0 -0
  65. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/covalent-inhibitor-scan.md +0 -0
  66. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/descriptors.md +0 -0
  67. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/docking.md +0 -0
  68. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/double-ended-ts-search.md +0 -0
  69. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/electronic-properties.md +0 -0
  70. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/fukui.md +0 -0
  71. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/hydrogen-bond-donor-acceptor-strength.md +0 -0
  72. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/interaction-energy-decomposition.md +0 -0
  73. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/ion-mobility.md +0 -0
  74. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/irc.md +0 -0
  75. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/logp.md +0 -0
  76. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/macropka.md +0 -0
  77. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/membrane-permeability.md +0 -0
  78. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/msa.md +0 -0
  79. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/multistage-optimization.md +0 -0
  80. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/nmr.md +0 -0
  81. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/pka.md +0 -0
  82. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/pocket-detection.md +0 -0
  83. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/pose-analysis-md.md +0 -0
  84. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/protein-binder-design.md +0 -0
  85. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/protein-cofolding.md +0 -0
  86. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/protein-md.md +0 -0
  87. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/protein-preparation.md +0 -0
  88. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/rbfe-graph.md +0 -0
  89. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/redox-potential.md +0 -0
  90. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/relative-binding-free-energy-perturbation.md +0 -0
  91. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/scan.md +0 -0
  92. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/settings.md +0 -0
  93. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/solubility.md +0 -0
  94. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/solvent-dependent-conformers.md +0 -0
  95. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/spin-states.md +0 -0
  96. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/strain.md +0 -0
  97. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/tautomer-search.md +0 -0
  98. {rowan_python-3.2.2 → rowan_python-3.2.4}/docs/workflows/types.md +0 -0
  99. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/PROTAC_solubility.py +0 -0
  100. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/admet.py +0 -0
  101. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/analogue_docking.py +0 -0
  102. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/aqueous_solubility.py +0 -0
  103. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/basic_calculation.py +0 -0
  104. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/basic_calculation_from_json.py +0 -0
  105. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/basic_calculation_with_constraint.py +0 -0
  106. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/basic_calculation_with_solvent.py +0 -0
  107. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/batch_docking.py +0 -0
  108. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/batch_solubility.py +0 -0
  109. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/bde.py +0 -0
  110. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/binding_affinity.py +0 -0
  111. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/boltz_paired_msa.py +0 -0
  112. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/boltz_single_msa.py +0 -0
  113. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/chai_paired_msa.py +0 -0
  114. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/chai_single_msa.py +0 -0
  115. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/cofolding_screen.py +0 -0
  116. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/colabfold_paired_msa.py +0 -0
  117. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/colabfold_single_msa.py +0 -0
  118. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/conformer_dependent_redox.py +0 -0
  119. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/conformers.py +0 -0
  120. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/conformers_screen.py +0 -0
  121. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/covalent_docking.py +0 -0
  122. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/covalent_inhibitor_scan.py +0 -0
  123. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/data/1iep_receptorH.pdb +0 -0
  124. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/data/Al_FCC.xyz +0 -0
  125. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/data/citalopram_1iep.xyz +0 -0
  126. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/data/ibuprofen_conformers.sdf +0 -0
  127. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/data/tyk2_ligands.sdf +0 -0
  128. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/data/tyk2_structure.pdb +0 -0
  129. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/data/workflow_example.json +0 -0
  130. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/dcd_download.py +0 -0
  131. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/descriptors.py +0 -0
  132. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/docking.py +0 -0
  133. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/docking_screen.py +0 -0
  134. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/double_ended_ts_search.py +0 -0
  135. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/electronic_properties.py +0 -0
  136. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/estimate_workflow.py +0 -0
  137. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/fukui_index.py +0 -0
  138. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/hydrogen_bond_basicity.py +0 -0
  139. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/induced_fit_docking.py +0 -0
  140. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/interaction_energy_decomposition.py +0 -0
  141. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/ion_mobility.py +0 -0
  142. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/irc.py +0 -0
  143. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/logp.py +0 -0
  144. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/macropka.py +0 -0
  145. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/membrane_permeability.py +0 -0
  146. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/multistage_optimization.py +0 -0
  147. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/nmr.py +0 -0
  148. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/optimization.py +0 -0
  149. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/periodic_dft.py +0 -0
  150. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/phenol_pka.py +0 -0
  151. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/pka.py +0 -0
  152. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/pocket_detection.py +0 -0
  153. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/pose_analysis_md.py +0 -0
  154. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/project_scoped_api_key.py +0 -0
  155. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_binder_design.py +0 -0
  156. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_cofolding.py +0 -0
  157. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_cofolding_modified_inputs.py +0 -0
  158. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_cofolding_with_constraints.py +0 -0
  159. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_cofolding_with_templates.py +0 -0
  160. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_file_download.py +0 -0
  161. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_md.py +0 -0
  162. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/protein_preparation.py +0 -0
  163. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/rbfe_graph.py +0 -0
  164. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/rbfe_resubmit.py +0 -0
  165. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/redox_potential.py +0 -0
  166. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/relative_binding_free_energy_perturbation.py +0 -0
  167. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/resubmit_with_perturbations.py +0 -0
  168. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/retrieve_workflow.py +0 -0
  169. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/scan.py +0 -0
  170. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/solvent_dependent_conformers.py +0 -0
  171. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/spin_states.py +0 -0
  172. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/strain.py +0 -0
  173. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/tautomer.py +0 -0
  174. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/template.py +0 -0
  175. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/temporary_workflow_sharing.py +0 -0
  176. {rowan_python-3.2.2 → rowan_python-3.2.4}/examples/webhook.py +0 -0
  177. {rowan_python-3.2.2 → rowan_python-3.2.4}/mkdocs.yml +0 -0
  178. {rowan_python-3.2.2 → rowan_python-3.2.4}/prek.toml +0 -0
  179. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/api_keys.py +0 -0
  180. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/calculation.py +0 -0
  181. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/config.py +0 -0
  182. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/constants.py +0 -0
  183. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/folder.py +0 -0
  184. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/molecule.py +0 -0
  185. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/project.py +0 -0
  186. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/protein.py +0 -0
  187. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/py.typed +0 -0
  188. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/types.py +0 -0
  189. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/admet.py +0 -0
  190. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/analogue_docking.py +0 -0
  191. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/base.py +0 -0
  192. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/basic_calculation.py +0 -0
  193. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/batch_docking.py +0 -0
  194. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/bde.py +0 -0
  195. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/binding_affinity.py +0 -0
  196. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/constants.py +0 -0
  197. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/covalent_inhibitor_scan.py +0 -0
  198. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/descriptors.py +0 -0
  199. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/docking.py +0 -0
  200. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/double_ended_ts_search.py +0 -0
  201. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/electronic_properties.py +0 -0
  202. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/fukui.py +0 -0
  203. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/hydrogen_bond_donor_acceptor_strength.py +0 -0
  204. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/interaction_energy_decomposition.py +0 -0
  205. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/ion_mobility.py +0 -0
  206. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/irc.py +0 -0
  207. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/logp.py +0 -0
  208. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/macropka.py +0 -0
  209. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/membrane_permeability.py +0 -0
  210. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/msa.py +0 -0
  211. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/multistage_optimization.py +0 -0
  212. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/nmr.py +0 -0
  213. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/pka.py +0 -0
  214. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/pose_analysis_md.py +0 -0
  215. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/protein_binder_design.py +0 -0
  216. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/protein_cofolding.py +0 -0
  217. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/rbfe_graph.py +0 -0
  218. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/redox_potential.py +0 -0
  219. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/scan.py +0 -0
  220. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/solubility.py +0 -0
  221. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/solvent_dependent_conformers.py +0 -0
  222. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/spin_states.py +0 -0
  223. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/strain.py +0 -0
  224. {rowan_python-3.2.2 → rowan_python-3.2.4}/rowan/workflows/tautomer_search.py +0 -0
  225. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/.claude-plugin/plugin.json +0 -0
  226. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/admet.md +0 -0
  227. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/analogue_docking.md +0 -0
  228. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/basic_calculation.md +0 -0
  229. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/batch_docking.md +0 -0
  230. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/bde.md +0 -0
  231. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/binding_affinity.md +0 -0
  232. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/covalent_inhibitor_scan.md +0 -0
  233. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/descriptors.md +0 -0
  234. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/docking.md +0 -0
  235. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/double_ended_ts_search.md +0 -0
  236. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/electronic_properties.md +0 -0
  237. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/folders_and_projects.md +0 -0
  238. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/fukui.md +0 -0
  239. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/hydrogen_bond_donor_acceptor_strength.md +0 -0
  240. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/interaction_energy_decomposition.md +0 -0
  241. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/ion_mobility.md +0 -0
  242. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/irc.md +0 -0
  243. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/logp.md +0 -0
  244. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/macropka.md +0 -0
  245. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/mcp_execution.md +0 -0
  246. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/membrane_permeability.md +0 -0
  247. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/msa.md +0 -0
  248. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/multistage_optimization.md +0 -0
  249. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/nmr.md +0 -0
  250. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/pka.md +0 -0
  251. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/pose_analysis_md.md +0 -0
  252. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/protein_binder_design.md +0 -0
  253. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/protein_cofolding.md +0 -0
  254. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/python_sdk.md +0 -0
  255. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/rbfe_graph.md +0 -0
  256. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/redox_potential.md +0 -0
  257. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/scan.md +0 -0
  258. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/solubility.md +0 -0
  259. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/solvent_dependent_conformers.md +0 -0
  260. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/spin_states.md +0 -0
  261. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/strain.md +0 -0
  262. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/tautomer_search.md +0 -0
  263. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/reference/webhooks.md +0 -0
  264. {rowan_python-3.2.2 → rowan_python-3.2.4}/skills/computational-chemistry-and-biology/scripts/check_env.py +0 -0
  265. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_binding_affinity.py +0 -0
  266. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_cofolding_workflow_updates.py +0 -0
  267. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_docking_workflow.py +0 -0
  268. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_docking_workflow_updates.py +0 -0
  269. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_macropka_nmr.py +0 -0
  270. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_mango_forcefields.py +0 -0
  271. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_plugin.py +0 -0
  272. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_project.py +0 -0
  273. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_protein.py +0 -0
  274. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_solvent_dependent_conformers.py +0 -0
  275. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_tautomer_search.py +0 -0
  276. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_utils.py +0 -0
  277. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_workflow_results.py +0 -0
  278. {rowan_python-3.2.2 → rowan_python-3.2.4}/tests/test_workflow_submission.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: rowan-python
3
- Version: 3.2.2
3
+ Version: 3.2.4
4
4
  Summary: Rowan Python Library
5
5
  Project-URL: Homepage, https://github.com/rowansci/rowan-client
6
6
  Project-URL: Bug Tracker, https://github.com/rowansci/rowan-client/issues
@@ -12,7 +12,7 @@ Requires-Dist: httpx
12
12
  Requires-Dist: nest-asyncio
13
13
  Requires-Dist: rdkit
14
14
  Requires-Dist: setuptools
15
- Requires-Dist: stjames>=0.0.281
15
+ Requires-Dist: stjames>=0.0.293
16
16
  Description-Content-Type: text/markdown
17
17
 
18
18
  # Rowan Python Library
@@ -0,0 +1,41 @@
1
+ """Detect protein binding pockets with mixed-solvent molecular dynamics."""
2
+
3
+ import rowan
4
+
5
+ # Set your API key or use the ROWAN_API_KEY environment variable
6
+ # rowan.api_key = "rowan-sk..."
7
+ folder = rowan.get_folder("examples")
8
+
9
+ protein = rowan.create_protein_from_pdb_id("1OTP", name="thymidine phosphorylase")
10
+ preparation_workflow = rowan.submit_protein_preparation_workflow(
11
+ protein=protein.uuid,
12
+ name="Prepare thymidine phosphorylase",
13
+ folder=folder,
14
+ )
15
+ prepared_protein_uuid = preparation_workflow.result().prepared_protein_uuid
16
+ if prepared_protein_uuid is None:
17
+ raise ValueError("Protein preparation returned no prepared protein")
18
+
19
+ # Runs three independent replicas, each with 5 ns equilibration and 15 ns production.
20
+ workflow = rowan.submit_pocket_detection_workflow(
21
+ protein=prepared_protein_uuid,
22
+ settings=rowan.MixMDSettings(probe=rowan.Solvent.ACETONITRILE),
23
+ name="MixMD pocket detection on thymidine phosphorylase",
24
+ folder=folder,
25
+ )
26
+ print(f"View workflow privately at: https://labs.rowansci.com/pocket-detection/{workflow.uuid}")
27
+ result = workflow.result()
28
+
29
+ for message in result.messages:
30
+ print(message)
31
+
32
+ print(f"Detected {len(result.pockets)} pocket(s):")
33
+ for i, pocket in enumerate(result.pockets):
34
+ print(f" Pocket {i}: score={pocket.score}, enriched-region volume={pocket.volume} ų")
35
+ print(f" center={pocket.pocket_center}, sides={pocket.pocket_sides}")
36
+ print(f" residues={pocket.residue_numbers}")
37
+
38
+ # Pocket coordinates refer to this reference structure.
39
+ reference_protein = result.get_reference_protein()
40
+ if reference_protein is not None:
41
+ print(f"Reference protein: {reference_protein.uuid}")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rowan-python"
3
- version = "3.2.2"
3
+ version = "3.2.4"
4
4
  description = "Rowan Python Library"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -12,7 +12,7 @@ authors = [
12
12
  ]
13
13
  dependencies = [
14
14
  "httpx",
15
- "stjames>=0.0.281",
15
+ "stjames>=0.0.293",
16
16
  "setuptools",
17
17
  "rdkit",
18
18
  "nest-asyncio",
@@ -15,6 +15,7 @@ from stjames import (
15
15
  Constraint,
16
16
  ConstraintType,
17
17
  ConformerClusteringSettings,
18
+ ConformerProperties,
18
19
  ConformerGenSettingsUnion,
19
20
  Correction,
20
21
  DNASequence,
@@ -27,7 +28,9 @@ from stjames import (
27
28
  iMTDSettings,
28
29
  InducedFitSettings,
29
30
  KMeansClusteringSettings,
31
+ MDRestraints,
30
32
  Method,
33
+ MixMDSettings,
31
34
  Mode,
32
35
  MSAFormat,
33
36
  MultiStageOptSettings,
@@ -38,9 +41,11 @@ from stjames import (
38
41
  OptimizationSettings,
39
42
  PBCDFTSettings,
40
43
  PeriodicCell,
44
+ PocketeerSettings,
41
45
  ProteinSequence,
42
46
  ProteinForceField,
43
47
  ResidueModification,
48
+ RestraintType,
44
49
  RNASequence,
45
50
  ScanSettings,
46
51
  Settings,
@@ -67,7 +72,7 @@ from stjames.engine_compatibility import (
67
72
  METHOD_ENGINES,
68
73
  get_supported_corrections,
69
74
  )
70
- from stjames.pdb import ResidueRef
75
+ from stjames.pdb import ResidueAtomRef, ResidueRef
71
76
  from stjames.optimization.band_method import NEBSettings
72
77
  from stjames.optimization.interpolation import Interpolation
73
78
  from stjames.optimization.string_method import FSMSettings, StringMethodSettings
@@ -83,5 +88,6 @@ from .types import ProteinUUID, RdkitMol, SMILES, StJamesMolecule, StructureInpu
83
88
  from .workflows import *
84
89
  from .project import *
85
90
  from .protein import *
91
+ from .spectra import HARTREE_TO_EV, broaden_spectrum
86
92
  from .user import *
87
93
  from .utils import *
@@ -0,0 +1,68 @@
1
+ """Broaden stick spectra into continuous line shapes."""
2
+
3
+ import math
4
+ from collections.abc import Sequence
5
+ from typing import Literal
6
+
7
+ HARTREE_TO_EV = 27.211386245988
8
+
9
+ _GAUSSIAN_FWHM_TO_SIGMA = 1 / (2 * math.sqrt(2 * math.log(2)))
10
+
11
+
12
+ def broaden_spectrum(
13
+ positions: Sequence[float],
14
+ intensities: Sequence[float],
15
+ grid: Sequence[float],
16
+ fwhm: float,
17
+ lineshape: Literal["gaussian", "lorentzian"] = "gaussian",
18
+ ) -> list[float]:
19
+ """Sum line shapes centered on each stick, each with area equal to its intensity.
20
+
21
+ Use it on the stick spectra of `ConformerSearchResult.ensemble_properties`, for
22
+ example excitation energies with oscillator or rotatory strengths for UV-vis or ECD,
23
+ or vibrational frequencies with IR intensities. `grid` and `fwhm` share the units of
24
+ `positions`; convert excitation energies from Hartree with `HARTREE_TO_EV` first to
25
+ broaden in eV.
26
+
27
+ Args:
28
+ positions: line positions
29
+ intensities: line intensities, parallel to `positions`
30
+ grid: points at which to evaluate the spectrum
31
+ fwhm: full width at half maximum of each line
32
+ lineshape: line shape of each stick
33
+
34
+ Returns:
35
+ spectrum at each point of `grid`
36
+
37
+ Raises:
38
+ ValueError: `fwhm` is not positive or `intensities` differs in length from `positions`
39
+
40
+ >>> [round(y, 4) for y in broaden_spectrum([0.0], [1.0], [0.0, 0.5], fwhm=1.0)]
41
+ [0.9394, 0.4697]
42
+ >>> [round(y, 4) for y in broaden_spectrum([0.0], [2.0], [0.0], 1.0, "lorentzian")]
43
+ [1.2732]
44
+ """
45
+ if fwhm <= 0:
46
+ raise ValueError(f"fwhm must be positive, got {fwhm}")
47
+ if len(positions) != len(intensities):
48
+ raise ValueError(
49
+ f"positions ({len(positions)}) and intensities ({len(intensities)}) "
50
+ "must have the same length"
51
+ )
52
+
53
+ if lineshape == "gaussian":
54
+ sigma = fwhm * _GAUSSIAN_FWHM_TO_SIGMA
55
+ norm = 1 / (sigma * math.sqrt(2 * math.pi))
56
+
57
+ def shape(dx: float) -> float:
58
+ return norm * math.exp(-0.5 * (dx / sigma) ** 2)
59
+
60
+ else:
61
+ gamma = fwhm / 2
62
+
63
+ def shape(dx: float) -> float:
64
+ return gamma / (math.pi * (dx**2 + gamma**2))
65
+
66
+ return [
67
+ sum(i * shape(x - p) for p, i in zip(positions, intensities, strict=True)) for x in grid
68
+ ]
@@ -60,7 +60,6 @@ class User(BaseModel):
60
60
  email: email of the user
61
61
  firstname: first name of the user
62
62
  lastname: last name of the user
63
- weekly_credits: weekly credits of the user
64
63
  credits: credits of the user
65
64
  billing_name: billing name of the user
66
65
  billing_address: billing address of the user
@@ -79,7 +78,6 @@ class User(BaseModel):
79
78
  email: str
80
79
  firstname: str | None = None
81
80
  lastname: str | None = None
82
- weekly_credits: float | None = None
83
81
  credits: float | None = None
84
82
  billing_name: str | None = None
85
83
  billing_address: str | dict | None = None
@@ -124,7 +122,7 @@ class User(BaseModel):
124
122
  Returns:
125
123
  string showing available credits
126
124
  """
127
- individual_credits = f"Weekly Credits: {self.weekly_credits}\nCredits: {self.credits}"
125
+ individual_credits = f"Credits: {self.credits}"
128
126
  if self.organization is not None:
129
127
  return (
130
128
  individual_credits
@@ -4,7 +4,7 @@ from contextvars import ContextVar
4
4
  from dataclasses import dataclass
5
5
  from pathlib import Path
6
6
  from tempfile import NamedTemporaryFile
7
- from typing import Any, Generator, Literal
7
+ from typing import Any, Callable, ContextManager, Generator, Literal
8
8
 
9
9
  import httpx
10
10
  import stjames
@@ -167,24 +167,14 @@ def api_client() -> Generator[httpx.Client, None, None]:
167
167
  yield client
168
168
 
169
169
 
170
- def download_file(
171
- path: Path,
172
- method: Literal["GET", "POST"],
173
- url: str,
174
- *,
175
- params: dict[str, Any] | None = None,
176
- json: Any = None,
177
- ) -> Path:
178
- """Stream an authenticated API response into one local file atomically."""
170
+ def _stream_to_file(path: Path, stream: Callable[[], ContextManager[httpx.Response]]) -> Path:
171
+ """Write a streamed response into one local file atomically."""
179
172
  path.parent.mkdir(parents=True, exist_ok=True)
180
173
  temporary_path: Path | None = None
181
174
  try:
182
175
  with NamedTemporaryFile(dir=path.parent, prefix=f".{path.name}.", delete=False) as output:
183
176
  temporary_path = Path(output.name)
184
- with (
185
- api_client() as client,
186
- client.stream(method, url, params=params, json=json) as response,
187
- ):
177
+ with stream() as response:
188
178
  response.raise_for_status()
189
179
  for chunk in response.iter_bytes():
190
180
  output.write(chunk)
@@ -196,6 +186,65 @@ def download_file(
196
186
  return path
197
187
 
198
188
 
189
+ def download_file(
190
+ path: Path,
191
+ method: Literal["GET", "POST"],
192
+ url: str,
193
+ *,
194
+ params: dict[str, Any] | None = None,
195
+ json: Any = None,
196
+ ) -> Path:
197
+ """Stream an authenticated API response into one local file atomically."""
198
+
199
+ @contextmanager
200
+ def stream() -> Generator[httpx.Response, None, None]:
201
+ with (
202
+ api_client() as client,
203
+ client.stream(method, url, params=params, json=json) as response,
204
+ ):
205
+ yield response
206
+
207
+ return _stream_to_file(path, stream)
208
+
209
+
210
+ def download_presigned_files(
211
+ directory: Path,
212
+ url: str,
213
+ *,
214
+ params: dict[str, Any] | None = None,
215
+ json: Any = None,
216
+ ) -> list[Path]:
217
+ """Fetch presigned download links from the API and stream each file into `directory`.
218
+
219
+ Links are short-lived, so an expired one is refreshed once before giving up.
220
+ """
221
+
222
+ def fetch_links() -> list[dict[str, str]]:
223
+ with api_client() as client:
224
+ return client.post(url, params=params, json=json).json()
225
+
226
+ def download(link: dict[str, str]) -> Path:
227
+ # Plain client: the API key must never be sent to S3.
228
+ @contextmanager
229
+ def stream() -> Generator[httpx.Response, None, None]:
230
+ with httpx.Client(timeout=httpx.Timeout(120, read=None)) as client:
231
+ with client.stream("GET", link["url"]) as response:
232
+ yield response
233
+
234
+ return _stream_to_file(directory / Path(link["filename"]).name, stream)
235
+
236
+ links = fetch_links()
237
+ paths = []
238
+ for i, link in enumerate(links):
239
+ try:
240
+ paths.append(download(link))
241
+ except httpx.HTTPStatusError as error:
242
+ if error.response.status_code != 403:
243
+ raise
244
+ paths.append(download(fetch_links()[i]))
245
+ return paths
246
+
247
+
199
248
  ATOMIC_NUMBER_TO_ATOMIC_SYMBOL = {
200
249
  "1": "H",
201
250
  "2": "He",
@@ -102,7 +102,14 @@ from .multistage_optimization import (
102
102
  )
103
103
  from .nmr import NMRCoupling, NMRPeak, NMRResult, submit_nmr_workflow
104
104
  from .pka import pKaMicrostate, pKaResult, submit_pka_workflow
105
- from .pocket_detection import Pocket, PocketDetectionResult, submit_pocket_detection_workflow
105
+ from .pocket_detection import (
106
+ MixMDPocketDiagnostics,
107
+ MixMDReplicaDiagnostics,
108
+ MixMDResults,
109
+ Pocket,
110
+ PocketDetectionResult,
111
+ submit_pocket_detection_workflow,
112
+ )
106
113
  from .pose_analysis_md import PoseAnalysisMDResult, submit_pose_analysis_md_workflow
107
114
  from .protein_binder_design import (
108
115
  ProteinBinder,
@@ -8,7 +8,7 @@ from typing import Literal, Protocol
8
8
  from stjames.pdb import PDB
9
9
 
10
10
  from rowan.protein import Protein, retrieve_protein
11
- from rowan.utils import api_client, download_file
11
+ from rowan.utils import api_client, download_file, download_presigned_files
12
12
 
13
13
  from .base import WorkflowResult
14
14
 
@@ -222,7 +222,9 @@ class _MolecularDynamicsResult(WorkflowResult):
222
222
  name: str | None = None,
223
223
  path: Path | str | None = None,
224
224
  ) -> Path:
225
- """Download DCD trajectory files for selected replicates.
225
+ """Download DCD trajectory files for selected replicates as one `.tar.gz` archive.
226
+
227
+ Long trajectories can time out; use `download_trajectory_files` for those.
226
228
 
227
229
  Args:
228
230
  replicates: zero-based replicate indices
@@ -244,6 +246,29 @@ class _MolecularDynamicsResult(WorkflowResult):
244
246
  json=replicates,
245
247
  )
246
248
 
249
+ def download_trajectory_files(
250
+ self,
251
+ replicates: list[int],
252
+ path: Path | str | None = None,
253
+ ) -> list[Path]:
254
+ """Download each selected replicate's DCD file directly from storage.
255
+
256
+ Args:
257
+ replicates: zero-based replicate indices
258
+ path: output directory; defaults to the current directory
259
+
260
+ Returns:
261
+ paths to the downloaded `.dcd` files, one per replicate
262
+
263
+ Raises:
264
+ httpx.HTTPStatusError: API or storage request fails
265
+ """
266
+ return download_presigned_files(
267
+ Path(path) if path is not None else Path.cwd(),
268
+ f"/trajectory/{self.workflow_uuid}/trajectory_dcd_urls",
269
+ json=replicates,
270
+ )
271
+
247
272
  def _trajectory(self, replicate: int) -> _MolecularDynamicsTrajectory:
248
273
  """Return one trajectory with a consistent bounds error."""
249
274
  trajectories = self.trajectories
@@ -31,6 +31,8 @@ from .base import (
31
31
  )
32
32
  from .constants import to_relative_kcal
33
33
 
34
+ ConformerProperties = stjames.ConformerProperties
35
+
34
36
 
35
37
  @register_result("conformer_search")
36
38
  class ConformerSearchResult(WorkflowResult):
@@ -72,22 +74,59 @@ class ConformerSearchResult(WorkflowResult):
72
74
  return to_relative_kcal(energies) if relative else energies
73
75
 
74
76
  @property
75
- def radii_of_gyration(self) -> list[float]:
76
- """Radius of gyration for each conformer (A)."""
77
+ def radii_of_gyration(self) -> list[float | None]:
78
+ """Radius of gyration for each conformer (A), None where it failed."""
77
79
  return [p.radius_of_gyration for p in self._workflow.conformer_properties]
78
80
 
79
81
  @property
80
- def sasa(self) -> list[float]:
81
- """Solvent accessible surface area for each conformer (A^2)."""
82
+ def sasa(self) -> list[float | None]:
83
+ """Solvent accessible surface area for each conformer (A^2), None where it failed."""
82
84
  return [p.solvent_accessible_surface_area for p in self._workflow.conformer_properties]
83
85
 
84
86
  @property
85
- def polar_sasa(self) -> list[float]:
86
- """Polar solvent accessible surface area for each conformer (A^2)."""
87
+ def polar_sasa(self) -> list[float | None]:
88
+ """Polar solvent accessible surface area for each conformer (A^2), None where it failed."""
87
89
  return [
88
90
  p.polar_solvent_accessible_surface_area for p in self._workflow.conformer_properties
89
91
  ]
90
92
 
93
+ @property
94
+ def dipoles(self) -> list[float | None]:
95
+ """Dipole moment magnitude about the center of mass for each conformer (Debye).
96
+
97
+ None where the method reports no dipole.
98
+ """
99
+ return [p.dipole for p in self._workflow.conformer_properties]
100
+
101
+ @property
102
+ def ensemble_properties(self) -> ConformerProperties | None:
103
+ """Ensemble properties weighted by `boltzmann_weights`.
104
+
105
+ Each property is averaged over the conformers that have it: SASA, polar SASA, Rg,
106
+ the root-mean-square dipole (Debye), and per-atom Mulliken charges. When the run
107
+ computed them, it also holds stick spectra with every conformer's lines, each
108
+ intensity scaled by its conformer's population: `excitation_energies` (Hartree) with
109
+ `oscillator_strengths` (UV-vis) and `rotatory_strengths` (ECD), and
110
+ `vibrational_frequencies` (cm^-1) with `ir_intensities` (km/mol). Pass them to
111
+ `rowan.broaden_spectrum` for the spectrum. Rotatory strengths are omitted when the
112
+ conformers differ in stereochemistry, since mixing enantiomers cancels the ECD signal.
113
+ """
114
+ return self._workflow.ensemble_properties
115
+
116
+ @property
117
+ def boltzmann_weights(self) -> list[float]:
118
+ """Population of each conformer at the weighting temperature (sum to 1.0).
119
+
120
+ From free energies when every conformer has frequencies, else from ground-state
121
+ energies. Empty for workflows run before weights were reported.
122
+ """
123
+ return list(self._workflow.boltzmann_weights)
124
+
125
+ @property
126
+ def weighting_temperature(self) -> float:
127
+ """Temperature of `boltzmann_weights` and `ensemble_properties` (K)."""
128
+ return self._workflow.weighting_temperature
129
+
91
130
  def get_conformers(self, n: int | None = None) -> list[Molecule]:
92
131
  """Fetch conformer molecules.
93
132
 
@@ -156,6 +195,7 @@ def _mso_for_final_method(
156
195
  final_method: Method,
157
196
  solvent: SolventInput = None,
158
197
  transition_state: bool = False,
198
+ frequencies: bool = False,
159
199
  ) -> MultiStageOptSettings:
160
200
  """Build optimization settings for the final method.
161
201
 
@@ -163,9 +203,9 @@ def _mso_for_final_method(
163
203
  without a named preset.
164
204
 
165
205
  `solvent` and `transition_state` are merged into each stage's `Settings`
166
- when supplied; the named preset itself is independent of them (mirrors how
167
- tinbergen's form keeps the preset dropdown separate from the solvent / TS
168
- toggles).
206
+ when supplied, and `frequencies` runs on the optimization stage; the named
207
+ preset itself is independent of them (mirrors how tinbergen's form keeps the
208
+ preset dropdown separate from the solvent / TS toggles).
169
209
  """
170
210
  opt_method, sp_method = _FINAL_METHOD_TO_MSO_RECIPE.get(final_method, (final_method, None))
171
211
 
@@ -196,6 +236,7 @@ def _mso_for_final_method(
196
236
  return MultiStageOptSettings(
197
237
  optimization_settings=[opt_stage],
198
238
  singlepoint_settings=sp_stage,
239
+ frequencies=frequencies,
199
240
  )
200
241
 
201
242
 
@@ -224,6 +265,8 @@ def submit_conformer_search_workflow(
224
265
  final_method: Method | str = "aimnet2_wb97md3",
225
266
  solvent: SolventInput = None,
226
267
  transition_state: bool = False,
268
+ frequencies: bool = False,
269
+ weighting_temperature: float = 298.15,
227
270
  multistage_opt_settings: MultiStageOptSettings | None = None,
228
271
  conformer_clustering_settings: ConformerClusteringSettings | None = None,
229
272
  initial_conformers: Sequence[StructureInput] | None = None,
@@ -264,6 +307,11 @@ def submit_conformer_search_workflow(
264
307
  `multistage_opt_settings` is provided
265
308
  transition_state: whether to optimize the transition state. Ignored
266
309
  if `multistage_opt_settings` is provided
310
+ frequencies: compute vibrational frequencies of each conformer at the optimization
311
+ level, for the ensemble IR spectrum. Ignored if `multistage_opt_settings` is
312
+ provided; set its `frequencies` instead
313
+ weighting_temperature: temperature for the conformer populations, in Kelvin. With
314
+ frequencies, populations use free energies at this temperature
267
315
  multistage_opt_settings: optimization stages and singlepoint settings
268
316
  for ranking conformers. When provided, takes precedence over
269
317
  `final_method` / `solvent` / `transition_state`. When omitted, an MSO is
@@ -359,7 +407,10 @@ def submit_conformer_search_workflow(
359
407
  if isinstance(final_method, str):
360
408
  final_method = Method(final_method)
361
409
  multistage_opt_settings = _mso_for_final_method(
362
- final_method, solvent=solvent, transition_state=transition_state
410
+ final_method,
411
+ solvent=solvent,
412
+ transition_state=transition_state,
413
+ frequencies=frequencies,
363
414
  )
364
415
  multistage_opt_settings = _release_ts_optimization_constraints(multistage_opt_settings)
365
416
 
@@ -370,6 +421,7 @@ def submit_conformer_search_workflow(
370
421
  multistage_opt_settings=multistage_opt_settings,
371
422
  conf_gen_settings=conf_gen_settings,
372
423
  conformer_clustering_settings=conformer_clustering_settings,
424
+ weighting_temperature=weighting_temperature,
373
425
  )
374
426
 
375
427
  workflow_data = workflow.model_dump(serialize_as_any=True, mode="json")