abmptools 2.2.0__tar.gz → 2.3.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.
- {abmptools-2.2.0/abmptools.egg-info → abmptools-2.3.0}/PKG-INFO +6 -3
- {abmptools-2.2.0 → abmptools-2.3.0}/README.md +5 -2
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/analyzer.py +166 -12
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/cli.py +17 -2
- abmptools-2.3.0/abmptools/hbond/diagram.py +150 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udfcharge/__init__.py +4 -0
- abmptools-2.3.0/abmptools/udfcharge/__main__.py +117 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udfcharge/core.py +186 -5
- {abmptools-2.2.0 → abmptools-2.3.0/abmptools.egg-info}/PKG-INFO +6 -3
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools.egg-info/SOURCES.txt +1 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/pyproject.toml +1 -1
- abmptools-2.2.0/abmptools/udfcharge/__main__.py +0 -63
- {abmptools-2.2.0 → abmptools-2.3.0}/LICENSE +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/NOTICE +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/abinit_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/addsolvfrag.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/ajf2config.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/ajfserial.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/density.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/mdp_protocol.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/molecule_prep.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/ndx_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/packing.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/parameterizer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/pubchem.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/system_model_adapter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/amorphous/trajectory_ingest.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/anlfmo.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/aij_assign.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/aij_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/calc_sett_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/dpm_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/monomer_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/notebook_ui.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/orchestrator.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/udf_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/dpd/udf_writer_udfm.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/_subprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/insane_runner.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/mdp_templates.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/pmf.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/pulling.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/system_packer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/topology_composer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/membrane/umbrella.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/_subprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/martinize_runner.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/mdp_templates.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/peptide_atomistic.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/system_packer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/top_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cg/peptide/water_box.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/convertcpf.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/core/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/core/system_model.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cpf2ifielist.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/cpfmanager.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/_subprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/atom_distance.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/cif_engine_ase.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/cif_engine_legacy.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/job_templates.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/legacy/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/crystal/postproc.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/f90/bin/readifiepiedalib.so +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/_subprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/analysis/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/analysis/aggregate_transition.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/analysis/contact_map.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/analysis/hbond.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/analysis/plots.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/analysis/sasa.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/analysis/secondary_structure.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/mdp_templates.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/ndx.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/packer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/peptide_atomistic.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/peptide_atomistic_openff.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/small_molecule.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/small_molecule_openff.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/topology.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/topology_openff.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/formulation/umbrella_release.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/auto_split.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/cap_attach.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/chain_splitter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/dpdgen_exporter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/exporter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/fcews_export.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/notebook_ui.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/orchestrator.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cg_segmenter/ring_detector.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/cut_apply.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/expand_to_system.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/grouping.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/headless_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/notebook_ui.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/pdb_loader.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/fragmenter/polymer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/generate_difie.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/generateajf.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/_subprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/analysis.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/grest_runner.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/inp_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/replica_temperatures.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/rest_selection.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/grest/system_builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/_subprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/analysis.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/gbsa_runner.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/inp_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/ligand_parameterize.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/pdb_splitter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/genesis/mmgbsa/system_builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/geomopt/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/geomopt/mace_optimizer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/geomopt/openff_openmm_minimizer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/geomopt/pyscf_optimizer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/getcharge.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/getifiepieda.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/default_template.udf +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/default_template_cognac101.udf +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/exporter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/gro_adapter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/gro_parser.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/mdp_parser.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/top_adapter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/top_exporter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/top_model.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/top_parser.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/trajectory_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/gro2udf/udf_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/bdf_reader.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/classifier.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/colorizer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/distance_dist.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/func_tags.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/functional_groups.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/hbond_detector.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/lifetime.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/notebook_ui.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/hbond/pair_type_stats.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/log2config.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/log2cpf.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/logmanager.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/bilayer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/lipid_info.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/mdp_us_protocol.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/parameterize_amber.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/parameterize_charmm.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/pmf.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/pulling.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/topology_sanity.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/membrane/umbrella.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/mol_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/molcalc.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/pdb2fmo.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/pdb_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/pdbmodify.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/readcif.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/setfmo.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/trajectory/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/trajectory/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/trajectory/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/trajectory/postprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2fmo.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/__main__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/exporter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/gromacs/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/gromacs/writers/__init__.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/gromacs/writers/_validator.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/gromacs/writers/gro_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/gromacs/writers/itp_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/gromacs/writers/mdp_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/gromacs/writers/top_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf2gro/udf_adapter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udf_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udfcreate.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udfcreate_v2.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools/udfrm_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools.egg-info/dependency_links.txt +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools.egg-info/entry_points.txt +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools.egg-info/requires.txt +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/abmptools.egg-info/top_level.txt +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/setup.cfg +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/setup.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_abinit_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_amorphous_models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_anlfmo.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_builder_integration.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_builder_mocked.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_builder_mocked.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_insane_runner.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_integration.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_mdp.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_packer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_pmf.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_pulling.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_topology_composer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_membrane_umbrella.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_atomistic.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_builder_mocked.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_integration.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_martinize_runner.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_mdp.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_packer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_subprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_topwriter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cg_peptide_water_box.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_charge_method.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cli_scripts.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_cpfmanager.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_atom_distance.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_cif_ase.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_cif_legacy.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_job_templates.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_numeric_regression.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_crystal_regression.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_density.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_analysis.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_mdp.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_ndx.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_packer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_peptide_atomistic.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_small_molecule.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_topology.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_formulation_umbrella_release.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_getifiepieda.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_analysis_mocked.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_builder_mocked.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_inp_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_integration.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_replica_temperatures.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_rest_selection.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_grest_system_builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_gro_adapter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_gro_parser.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_gro_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_interchange_adapter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_logmanager.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mdp_parser.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mdp_protocol.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mdp_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_membrane_charmm_translate.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_membrane_mixed_lipid.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_membrane_topology_sanity.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_analysis.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_builder_mocked.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_cli.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_forcefield_check.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_inp_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_integration.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_models.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_pdb_splitter.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mmgbsa_system_builder.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_mol_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_molcalc.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_ndx_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_parameterizer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_pdb_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_pubchem.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_pyscf_optimizer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_pyscf_parsers.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_read_ifie_hf_fallback.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_readcif.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_regression.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_setfmo.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_system_model.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_system_model_extensions.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_top_exporter_frames_override.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_top_model.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_top_parser.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_top_writer.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_trajectory_ingest.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_trajectory_postprocess.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_udf_io.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_udfcreate.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_udfcreate_v2.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_udfcreate_v2_byte_equivalence.py +0 -0
- {abmptools-2.2.0 → abmptools-2.3.0}/tests/test_udfrm_io.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: abmptools
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Pre/post-processing and analysis toolkit for ABINIT-MP Fragment Molecular Orbital calculations
|
|
5
5
|
Author-email: Koji Okuwaki <koujioku81@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -121,7 +121,7 @@ A Python toolkit for pre-processing, post-processing, and analysis of Fragment M
|
|
|
121
121
|
|
|
122
122
|
- **udf2gro**: Convert OCTA UDF files to GROMACS format (`.gro`, `.top`, `.mdp`, `.itp`)
|
|
123
123
|
- **gro2udf**: Convert GROMACS files to OCTA UDF format (supports `--from-top` mode)
|
|
124
|
-
- **udfcharge**: Transfer per-atom partial charges from a single-molecule UDF to
|
|
124
|
+
- **udfcharge**: Transfer per-atom partial charges from a single-molecule UDF to bulk molecules (`transfer`), or restore a neutralized UDF's charges to a target integer formal charge (`restore`)
|
|
125
125
|
|
|
126
126
|
### Geometry Optimization (`geomopt`)
|
|
127
127
|
|
|
@@ -314,7 +314,10 @@ python -m abmptools.udf2gro.cli -i system.udf -o output
|
|
|
314
314
|
python -m abmptools.gro2udf.cli -i system.gro -t system.top -o output.udf
|
|
315
315
|
|
|
316
316
|
# Transfer charges from a single-molecule UDF to all same-named molecules in a bulk UDF
|
|
317
|
-
python -m abmptools.udfcharge --template mol.udf --bulk bulk.udf --out bulk_charged.udf
|
|
317
|
+
python -m abmptools.udfcharge transfer --template mol.udf --bulk bulk.udf --out bulk_charged.udf
|
|
318
|
+
|
|
319
|
+
# Restore a neutralized UDF's charges to a target integer formal charge
|
|
320
|
+
python -m abmptools.udfcharge restore --udf mol.udf --formal-charge 12 --out mol_q+12.udf
|
|
318
321
|
|
|
319
322
|
# Build an amorphous mixture from SMILES (50 ketoprofen molecules, density 0.8 g/cm^3)
|
|
320
323
|
python -m abmptools.amorphous --smiles "OC(=O)C(C)c1cccc(C(=O)c2ccccc2)c1" \
|
|
@@ -37,7 +37,7 @@ A Python toolkit for pre-processing, post-processing, and analysis of Fragment M
|
|
|
37
37
|
|
|
38
38
|
- **udf2gro**: Convert OCTA UDF files to GROMACS format (`.gro`, `.top`, `.mdp`, `.itp`)
|
|
39
39
|
- **gro2udf**: Convert GROMACS files to OCTA UDF format (supports `--from-top` mode)
|
|
40
|
-
- **udfcharge**: Transfer per-atom partial charges from a single-molecule UDF to
|
|
40
|
+
- **udfcharge**: Transfer per-atom partial charges from a single-molecule UDF to bulk molecules (`transfer`), or restore a neutralized UDF's charges to a target integer formal charge (`restore`)
|
|
41
41
|
|
|
42
42
|
### Geometry Optimization (`geomopt`)
|
|
43
43
|
|
|
@@ -230,7 +230,10 @@ python -m abmptools.udf2gro.cli -i system.udf -o output
|
|
|
230
230
|
python -m abmptools.gro2udf.cli -i system.gro -t system.top -o output.udf
|
|
231
231
|
|
|
232
232
|
# Transfer charges from a single-molecule UDF to all same-named molecules in a bulk UDF
|
|
233
|
-
python -m abmptools.udfcharge --template mol.udf --bulk bulk.udf --out bulk_charged.udf
|
|
233
|
+
python -m abmptools.udfcharge transfer --template mol.udf --bulk bulk.udf --out bulk_charged.udf
|
|
234
|
+
|
|
235
|
+
# Restore a neutralized UDF's charges to a target integer formal charge
|
|
236
|
+
python -m abmptools.udfcharge restore --udf mol.udf --formal-charge 12 --out mol_q+12.udf
|
|
234
237
|
|
|
235
238
|
# Build an amorphous mixture from SMILES (50 ketoprofen molecules, density 0.8 g/cm^3)
|
|
236
239
|
python -m abmptools.amorphous --smiles "OC(=O)C(C)c1cccc(C(=O)c2ccccc2)c1" \
|
|
@@ -140,6 +140,12 @@ class AnalyzerConfig:
|
|
|
140
140
|
distance_d_max: float = 3.6 # Å, upper edge (Luzar-Chandler cutoff 3.5 + slack)
|
|
141
141
|
distance_bin_width: float = 0.05 # Å
|
|
142
142
|
angle_bin_width: float = 5.0 # deg, used for the 2-D (d, θ) heatmap
|
|
143
|
+
# Per-molecule 2D structure diagram marking the detected H-bond sites
|
|
144
|
+
# (red = donor, cyan = acceptor). Requires RDKit; skipped with a warning if
|
|
145
|
+
# unavailable or if bond-order perception fails. diagram_charge is the net
|
|
146
|
+
# molecular charge passed to DetermineBondOrders (0 = neutral).
|
|
147
|
+
do_diagram: bool = True
|
|
148
|
+
diagram_charge: int = 0
|
|
143
149
|
|
|
144
150
|
def get_criteria(self) -> HBondCriteria:
|
|
145
151
|
if self.criteria_mode == "luzar-chandler":
|
|
@@ -302,6 +308,36 @@ class Analyzer:
|
|
|
302
308
|
meta_by_type["ether_O"] = [(s.mol_index, s.acceptor_a) for s in sites]
|
|
303
309
|
return sites_by_type, meta_by_type
|
|
304
310
|
|
|
311
|
+
def _auto_groups(self) -> Tuple[List[str], List[str]]:
|
|
312
|
+
"""Auto-detect donor/acceptor group types present in the system.
|
|
313
|
+
|
|
314
|
+
Used by ``classify_mode='auto'``. Returns ``(donor_groups,
|
|
315
|
+
acceptor_groups)`` listing only the functional-group types actually
|
|
316
|
+
detected (carboxyl / amide / secondary-amide N-H / amine N-H /
|
|
317
|
+
hydroxyl). ``ether_O`` is NOT auto-listed because there is no reliable
|
|
318
|
+
ether detector yet (GAFF2 ``os``-tag only); pass ``--acceptor-groups
|
|
319
|
+
ether_O`` explicitly if needed.
|
|
320
|
+
"""
|
|
321
|
+
if self.traj is None:
|
|
322
|
+
self.load()
|
|
323
|
+
from .functional_groups import detect_hydroxyls
|
|
324
|
+
donors: List[str] = []
|
|
325
|
+
acceptors: List[str] = []
|
|
326
|
+
if self.carboxyls:
|
|
327
|
+
donors.append("carboxyl")
|
|
328
|
+
acceptors.append("carboxyl_O")
|
|
329
|
+
if any(g.from_amide for g in self.amine_donors):
|
|
330
|
+
donors.append("amide_donor")
|
|
331
|
+
if any(not g.from_amide for g in self.amine_donors):
|
|
332
|
+
donors.append("amine_donor")
|
|
333
|
+
hydroxyls = detect_hydroxyls(self.traj.molecules, mapping=self.mapping)
|
|
334
|
+
if hydroxyls:
|
|
335
|
+
donors.append("hydroxyl")
|
|
336
|
+
acceptors.append("hydroxyl_O")
|
|
337
|
+
if self.amides:
|
|
338
|
+
acceptors.append("amide_O")
|
|
339
|
+
return donors, acceptors
|
|
340
|
+
|
|
305
341
|
def run(self) -> List[FrameResult]:
|
|
306
342
|
if self.traj is None:
|
|
307
343
|
self.load()
|
|
@@ -309,12 +345,28 @@ class Analyzer:
|
|
|
309
345
|
end = c.record_end if c.record_end >= 0 else self.traj.n_records
|
|
310
346
|
criteria = c.get_criteria()
|
|
311
347
|
mode = (c.classify_mode or "imc").lower()
|
|
312
|
-
if mode not in {"imc", "generic"}:
|
|
348
|
+
if mode not in {"imc", "generic", "auto"}:
|
|
313
349
|
raise ValueError(
|
|
314
350
|
f"Unknown classify_mode={c.classify_mode!r}; "
|
|
315
|
-
"must be 'imc' or '
|
|
351
|
+
"must be 'imc', 'generic', or 'auto'"
|
|
316
352
|
)
|
|
317
353
|
|
|
354
|
+
if mode == "auto":
|
|
355
|
+
# Detect which functional-group donor/acceptor types are present and
|
|
356
|
+
# run them through the generic pair-stats path. Explicit
|
|
357
|
+
# --donor-groups / --acceptor-groups still override the auto picks.
|
|
358
|
+
auto_donors, auto_acceptors = self._auto_groups()
|
|
359
|
+
if c.donor_groups is None:
|
|
360
|
+
c.donor_groups = auto_donors
|
|
361
|
+
if c.acceptor_groups is None:
|
|
362
|
+
c.acceptor_groups = auto_acceptors
|
|
363
|
+
if c.verbose:
|
|
364
|
+
print(f" [auto] donor groups : {c.donor_groups or '(none detected)'}")
|
|
365
|
+
print(f" [auto] acceptor groups: {c.acceptor_groups or '(none detected)'}")
|
|
366
|
+
# Resolve to generic so run()/write_outputs use the generic path.
|
|
367
|
+
c.classify_mode = "generic"
|
|
368
|
+
mode = "generic"
|
|
369
|
+
|
|
318
370
|
donor_groups = c.donor_groups or (
|
|
319
371
|
["carboxyl"] if mode == "imc" else []
|
|
320
372
|
)
|
|
@@ -328,6 +380,9 @@ class Analyzer:
|
|
|
328
380
|
acceptor_sites_by_type, acceptor_meta_by_type = (
|
|
329
381
|
self._build_acceptor_sites_by_type(acceptor_groups)
|
|
330
382
|
)
|
|
383
|
+
# Stash detected sites so write_outputs() can render the 2D diagram.
|
|
384
|
+
self.donor_sites_by_type = donor_sites_by_type
|
|
385
|
+
self.acceptor_sites_by_type = acceptor_sites_by_type
|
|
331
386
|
|
|
332
387
|
# IMC mode keeps backward-compat names for hb_cc/hb_ca path
|
|
333
388
|
carb_donors = donor_sites_by_type.get("carboxyl", [])
|
|
@@ -654,17 +709,36 @@ class Analyzer:
|
|
|
654
709
|
import matplotlib.pyplot as plt
|
|
655
710
|
recs = [fr.record for fr in self.frame_results]
|
|
656
711
|
fig, ax = plt.subplots(figsize=(7, 4))
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
712
|
+
if mode == "imc":
|
|
713
|
+
ax.plot(recs, [fr.n_dual_mols for fr in self.frame_results],
|
|
714
|
+
"o-", color="red", label="dual COOH-COOH mols")
|
|
715
|
+
ax.plot(recs, [fr.n_chain_mols for fr in self.frame_results],
|
|
716
|
+
"D-", color="magenta", label="chain COOH-COOH mols")
|
|
717
|
+
ax.plot(recs, [fr.n_single_mols for fr in self.frame_results],
|
|
718
|
+
"s-", color="blue", label="single COOH-amide mols")
|
|
719
|
+
ax.plot(recs, [fr.n_free_mols for fr in self.frame_results],
|
|
720
|
+
"^-", color="gray", label="free mols")
|
|
721
|
+
ax.set_ylabel("number of molecules")
|
|
722
|
+
ax.set_title(f"H-bond classification ({c.criteria_mode})")
|
|
723
|
+
else:
|
|
724
|
+
# generic / auto: one line per donor→acceptor pair type
|
|
725
|
+
pair_types = sorted(
|
|
726
|
+
{pt for fr in self.frame_results
|
|
727
|
+
for pt in fr.hbonds_by_pair_type}
|
|
728
|
+
)
|
|
729
|
+
for pt in pair_types:
|
|
730
|
+
counts = [len(fr.hbonds_by_pair_type.get(pt, []))
|
|
731
|
+
for fr in self.frame_results]
|
|
732
|
+
ax.plot(recs, counts, "o-", markersize=3,
|
|
733
|
+
label=f"{pt[0]}→{pt[1]}")
|
|
734
|
+
if not pair_types:
|
|
735
|
+
ax.plot(recs, [0] * len(recs), "o-", color="gray",
|
|
736
|
+
label="(no H-bonds detected)")
|
|
737
|
+
ax.set_ylabel("number of H-bonds")
|
|
738
|
+
ax.set_title(
|
|
739
|
+
f"H-bond count per pair type ({c.criteria_mode})"
|
|
740
|
+
)
|
|
665
741
|
ax.set_xlabel("record")
|
|
666
|
-
ax.set_ylabel("number of molecules")
|
|
667
|
-
ax.set_title(f"H-bond classification ({c.criteria_mode})")
|
|
668
742
|
ax.legend()
|
|
669
743
|
ax.grid(True, alpha=0.3)
|
|
670
744
|
fig.tight_layout()
|
|
@@ -682,6 +756,86 @@ class Analyzer:
|
|
|
682
756
|
if c.compute_lifetime and len(self.frame_results) >= 2:
|
|
683
757
|
out_paths.update(self._write_lifetime_outputs())
|
|
684
758
|
|
|
759
|
+
# Per-molecule 2D structure diagram of the detected H-bond sites
|
|
760
|
+
if c.do_diagram:
|
|
761
|
+
out_paths.update(self._write_diagram_outputs())
|
|
762
|
+
|
|
763
|
+
return out_paths
|
|
764
|
+
|
|
765
|
+
def _write_diagram_outputs(self) -> Dict[str, str]:
|
|
766
|
+
"""Render a 2D structure diagram per molecular species, marking the
|
|
767
|
+
detected donor (red) / acceptor (cyan) atoms. Requires RDKit; skipped
|
|
768
|
+
with a warning if unavailable or if a molecule cannot be perceived."""
|
|
769
|
+
from . import diagram as _dg
|
|
770
|
+
c = self.config
|
|
771
|
+
out_paths: Dict[str, str] = {}
|
|
772
|
+
|
|
773
|
+
donor_by_type = getattr(self, "donor_sites_by_type", {}) or {}
|
|
774
|
+
acceptor_by_type = getattr(self, "acceptor_sites_by_type", {}) or {}
|
|
775
|
+
donors_per_mol: Dict[int, set] = {}
|
|
776
|
+
acceptors_per_mol: Dict[int, set] = {}
|
|
777
|
+
donor_types_per_mol: Dict[int, set] = {}
|
|
778
|
+
acceptor_types_per_mol: Dict[int, set] = {}
|
|
779
|
+
for dtype, sites in donor_by_type.items():
|
|
780
|
+
for s in sites:
|
|
781
|
+
donors_per_mol.setdefault(s.mol_index, set()).add(s.d_local)
|
|
782
|
+
donor_types_per_mol.setdefault(s.mol_index, set()).add(dtype)
|
|
783
|
+
for atype, sites in acceptor_by_type.items():
|
|
784
|
+
for s in sites:
|
|
785
|
+
acceptors_per_mol.setdefault(s.mol_index, set()).add(s.a_local)
|
|
786
|
+
acceptor_types_per_mol.setdefault(s.mol_index, set()).add(atype)
|
|
787
|
+
|
|
788
|
+
if not donors_per_mol and not acceptors_per_mol:
|
|
789
|
+
if c.verbose:
|
|
790
|
+
print(" (diagram skipped: no donor/acceptor atoms detected)")
|
|
791
|
+
return {}
|
|
792
|
+
|
|
793
|
+
rec0 = c.record_start
|
|
794
|
+
try:
|
|
795
|
+
frame = self.traj.get_frame(rec0)
|
|
796
|
+
except Exception:
|
|
797
|
+
frame = self.traj.get_frame(0)
|
|
798
|
+
|
|
799
|
+
# Group molecules into unique species by element signature (robust to
|
|
800
|
+
# per-atom-unique force-field type names).
|
|
801
|
+
species: Dict[tuple, int] = {}
|
|
802
|
+
for mi, topo in enumerate(self.traj.molecules):
|
|
803
|
+
sig = tuple(_dg.element_from_name(a.atom_name) for a in topo.atoms)
|
|
804
|
+
species.setdefault(sig, mi)
|
|
805
|
+
multi = len(species) > 1
|
|
806
|
+
n_done = 0
|
|
807
|
+
for sig, mi in species.items():
|
|
808
|
+
d_atoms = sorted(donors_per_mol.get(mi, set()))
|
|
809
|
+
a_atoms = sorted(acceptors_per_mol.get(mi, set()))
|
|
810
|
+
if not d_atoms and not a_atoms:
|
|
811
|
+
continue
|
|
812
|
+
topo = self.traj.molecules[mi]
|
|
813
|
+
coords = frame.positions[mi]
|
|
814
|
+
mol, reason = _dg.build_mol_from_topology(
|
|
815
|
+
topo, coords, charge=c.diagram_charge,
|
|
816
|
+
)
|
|
817
|
+
if mol is None:
|
|
818
|
+
print(f"Warning: diagram skipped for {topo.mol_name}: {reason}")
|
|
819
|
+
continue
|
|
820
|
+
dnames = ", ".join(sorted(donor_types_per_mol.get(mi, set()))) or "—"
|
|
821
|
+
anames = ", ".join(sorted(acceptor_types_per_mol.get(mi, set()))) or "—"
|
|
822
|
+
legend = (f"{topo.mol_name} red = donor ({dnames}) "
|
|
823
|
+
f"cyan = acceptor ({anames})")
|
|
824
|
+
suffix = f"_diagram_{topo.mol_name}" if multi else "_diagram"
|
|
825
|
+
png = f"{c.out_prefix}{suffix}.png"
|
|
826
|
+
svg = f"{c.out_prefix}{suffix}.svg"
|
|
827
|
+
try:
|
|
828
|
+
_dg.draw_hbond_diagram(mol, d_atoms, a_atoms, png, svg,
|
|
829
|
+
legend=legend)
|
|
830
|
+
except Exception as e: # noqa: BLE001
|
|
831
|
+
print(f"Warning: diagram render failed for {topo.mol_name}: {e}")
|
|
832
|
+
continue
|
|
833
|
+
key = f"diagram_{topo.mol_name}" if multi else "diagram"
|
|
834
|
+
out_paths[key] = png
|
|
835
|
+
out_paths[key + "_svg"] = svg
|
|
836
|
+
n_done += 1
|
|
837
|
+
if c.verbose and n_done:
|
|
838
|
+
print(f" diagram: {n_done} molecular species rendered")
|
|
685
839
|
return out_paths
|
|
686
840
|
|
|
687
841
|
def _write_distance_outputs(self) -> Dict[str, str]:
|
|
@@ -62,9 +62,11 @@ def main(argv=None) -> int:
|
|
|
62
62
|
help="Base molecule name for renamed groups (default: IMC)"
|
|
63
63
|
)
|
|
64
64
|
parser.add_argument(
|
|
65
|
-
"--classify-mode", choices=["imc", "generic"], default="imc",
|
|
65
|
+
"--classify-mode", choices=["imc", "generic", "auto"], default="imc",
|
|
66
66
|
help="imc: COOH-centric 4-species (dual/chain/single/free, IMC default). "
|
|
67
|
-
"generic: donor-type x acceptor-type pair stats (PVA/peptide/etc.)"
|
|
67
|
+
"generic: donor-type x acceptor-type pair stats (PVA/peptide/etc.). "
|
|
68
|
+
"auto: detect functional groups present and run generic with them "
|
|
69
|
+
"(no need to pass --donor-groups/--acceptor-groups; ether_O excluded)"
|
|
68
70
|
)
|
|
69
71
|
parser.add_argument(
|
|
70
72
|
"--no-element-fallback", action="store_true",
|
|
@@ -148,6 +150,17 @@ def main(argv=None) -> int:
|
|
|
148
150
|
"--no-distance-plots", action="store_true",
|
|
149
151
|
help="Skip d(D...A) distance distribution + (d, ∠) 2-D heatmap"
|
|
150
152
|
)
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
"--no-diagram", action="store_true",
|
|
155
|
+
help="Skip the per-molecule 2D structure diagram of the detected "
|
|
156
|
+
"H-bond sites (red=donor/cyan=acceptor). Requires RDKit; the "
|
|
157
|
+
"diagram is auto-generated by default when RDKit is available."
|
|
158
|
+
)
|
|
159
|
+
parser.add_argument(
|
|
160
|
+
"--diagram-charge", type=int, default=0,
|
|
161
|
+
help="Net molecular charge for diagram bond-order perception "
|
|
162
|
+
"(DetermineBondOrders), default 0 = neutral"
|
|
163
|
+
)
|
|
151
164
|
parser.add_argument(
|
|
152
165
|
"--distance-d-min", type=float, default=2.0,
|
|
153
166
|
help="d(D...A) histogram lower edge [Å] (default 2.0)"
|
|
@@ -213,6 +226,8 @@ def main(argv=None) -> int:
|
|
|
213
226
|
distance_d_max=args.distance_d_max,
|
|
214
227
|
distance_bin_width=args.distance_bin_width,
|
|
215
228
|
angle_bin_width=args.angle_bin_width,
|
|
229
|
+
do_diagram=not args.no_diagram,
|
|
230
|
+
diagram_charge=args.diagram_charge,
|
|
216
231
|
)
|
|
217
232
|
|
|
218
233
|
analyzer = Analyzer(config)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Per-molecule 2D structure diagrams marking the detected H-bond sites.
|
|
2
|
+
|
|
3
|
+
Builds an RDKit molecule from the COGNAC UDF topology (element from
|
|
4
|
+
``Atom_Name`` + connectivity + a single frame's 3D coordinates) and renders a
|
|
5
|
+
2D depiction with the **detected** donor / acceptor atoms highlighted
|
|
6
|
+
(red = donor, cyan = acceptor). One diagram is produced per unique molecular
|
|
7
|
+
species.
|
|
8
|
+
|
|
9
|
+
COGNAC UDFs (and OpenFF-interchange-exported ones in particular) usually carry
|
|
10
|
+
**no bond orders** (every ``order`` is 1.0), so aromaticity and C=O double
|
|
11
|
+
bonds are recovered from the 3D geometry via
|
|
12
|
+
``rdkit.Chem.rdDetermineBonds.DetermineBondOrders`` (assumes a neutral, closed
|
|
13
|
+
shell molecule by default — override with ``charge``).
|
|
14
|
+
|
|
15
|
+
RDKit is an optional dependency: if it is not importable, or the molecule
|
|
16
|
+
cannot be perceived (e.g. an ion with the wrong ``charge``), diagram generation
|
|
17
|
+
is skipped with a warning rather than aborting the analysis.
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Dict, List, Optional, Sequence, Tuple
|
|
22
|
+
|
|
23
|
+
# Two-letter elements first so "Cl"/"Br" are not truncated to "C"/"B".
|
|
24
|
+
_TWO_LETTER = ("Cl", "Br", "Si", "Na", "Mg", "Ca", "Fe", "Zn", "Li", "Se")
|
|
25
|
+
_ONE_LETTER = set("HCNOFPSKIBW")
|
|
26
|
+
|
|
27
|
+
DONOR_COLOR = (0.92, 0.30, 0.30) # red
|
|
28
|
+
ACCEPTOR_COLOR = (0.20, 0.75, 0.90) # cyan
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def element_from_name(name: str) -> str:
|
|
32
|
+
"""Best-effort element symbol from a UDF ``Atom_Name``.
|
|
33
|
+
|
|
34
|
+
Handles clean symbols (``"Cl"``, ``"O"``), element+index (``"C10"``,
|
|
35
|
+
``"HO"`` → ``H``), and is case-insensitive on the trailing letter so
|
|
36
|
+
``"CL"`` and ``"cl"`` both resolve to ``Cl``.
|
|
37
|
+
"""
|
|
38
|
+
s = "".join(ch for ch in (name or "") if ch.isalpha())
|
|
39
|
+
if not s:
|
|
40
|
+
return ""
|
|
41
|
+
cap = s[0].upper() + s[1:2].lower()
|
|
42
|
+
for two in _TWO_LETTER:
|
|
43
|
+
if cap.startswith(two):
|
|
44
|
+
return two
|
|
45
|
+
if s[0].upper() in _ONE_LETTER:
|
|
46
|
+
return s[0].upper()
|
|
47
|
+
return s[0].upper()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def build_mol_from_topology(topology, coords, charge: int = 0):
|
|
51
|
+
"""Build an RDKit ``Mol`` from a ``MoleculeTopology`` + 3D coordinates.
|
|
52
|
+
|
|
53
|
+
Returns ``(mol, None)`` on success or ``(None, reason)`` on failure.
|
|
54
|
+
``coords`` is an ``(n_atoms, 3)`` array-like (Å). Atom order is preserved,
|
|
55
|
+
so caller-supplied atom indices map 1:1 onto the returned molecule.
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
from rdkit import Chem
|
|
59
|
+
from rdkit.Chem import rdDetermineBonds
|
|
60
|
+
from rdkit.Geometry import Point3D
|
|
61
|
+
except ImportError:
|
|
62
|
+
return None, "rdkit not installed"
|
|
63
|
+
|
|
64
|
+
atoms = topology.atoms
|
|
65
|
+
if coords is None or len(coords) != len(atoms):
|
|
66
|
+
return None, "coordinate/atom count mismatch"
|
|
67
|
+
|
|
68
|
+
rw = Chem.RWMol()
|
|
69
|
+
for a in atoms:
|
|
70
|
+
sym = element_from_name(a.atom_name)
|
|
71
|
+
if not sym:
|
|
72
|
+
return None, f"could not resolve element for {a.atom_name!r}"
|
|
73
|
+
rw.AddAtom(Chem.Atom(sym))
|
|
74
|
+
for b in topology.bonds:
|
|
75
|
+
rw.AddBond(int(b.atom1), int(b.atom2), Chem.BondType.SINGLE)
|
|
76
|
+
mol = rw.GetMol()
|
|
77
|
+
|
|
78
|
+
conf = Chem.Conformer(mol.GetNumAtoms())
|
|
79
|
+
for i in range(mol.GetNumAtoms()):
|
|
80
|
+
x, y, z = coords[i]
|
|
81
|
+
conf.SetAtomPosition(i, Point3D(float(x), float(y), float(z)))
|
|
82
|
+
mol.AddConformer(conf, assignId=True)
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
# Perceive bond orders / aromaticity from geometry (bonds already set).
|
|
86
|
+
rdDetermineBonds.DetermineBondOrders(mol, charge=int(charge))
|
|
87
|
+
Chem.SanitizeMol(mol)
|
|
88
|
+
except Exception as e: # noqa: BLE001 - any perception failure → skip
|
|
89
|
+
return None, f"bond-order perception failed: {type(e).__name__}: {e}"
|
|
90
|
+
return mol, None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def draw_hbond_diagram(
|
|
94
|
+
mol,
|
|
95
|
+
donor_atoms: Sequence[int],
|
|
96
|
+
acceptor_atoms: Sequence[int],
|
|
97
|
+
png_path: str,
|
|
98
|
+
svg_path: Optional[str] = None,
|
|
99
|
+
legend: str = "",
|
|
100
|
+
donor_note: str = "donor",
|
|
101
|
+
acceptor_note: str = "acceptor",
|
|
102
|
+
) -> List[str]:
|
|
103
|
+
"""Render ``mol`` 2D with donor (red) / acceptor (cyan) atoms highlighted.
|
|
104
|
+
|
|
105
|
+
``donor_atoms`` / ``acceptor_atoms`` are atom indices into ``mol`` (the
|
|
106
|
+
heavy donor atom, e.g. amide N, and the acceptor atom, e.g. carbonyl O).
|
|
107
|
+
Non-polar H are removed for clarity; the highlighted heavy atoms are tracked
|
|
108
|
+
across H removal via an atom property. Returns the list of written paths.
|
|
109
|
+
"""
|
|
110
|
+
from rdkit import Chem
|
|
111
|
+
from rdkit.Chem import AllChem
|
|
112
|
+
from rdkit.Chem.Draw import rdMolDraw2D
|
|
113
|
+
|
|
114
|
+
work = Chem.Mol(mol)
|
|
115
|
+
for i in donor_atoms:
|
|
116
|
+
work.GetAtomWithIdx(int(i)).SetProp("_hb_role", "donor")
|
|
117
|
+
for i in acceptor_atoms:
|
|
118
|
+
work.GetAtomWithIdx(int(i)).SetProp("_hb_role", "acceptor")
|
|
119
|
+
|
|
120
|
+
heavy = Chem.RemoveHs(work)
|
|
121
|
+
AllChem.Compute2DCoords(heavy) # 2D depiction, not a projection of the 3D pose
|
|
122
|
+
|
|
123
|
+
hi_atoms: List[int] = []
|
|
124
|
+
atom_cols: Dict[int, Tuple[float, float, float]] = {}
|
|
125
|
+
for a in heavy.GetAtoms():
|
|
126
|
+
if not a.HasProp("_hb_role"):
|
|
127
|
+
continue
|
|
128
|
+
role = a.GetProp("_hb_role")
|
|
129
|
+
hi_atoms.append(a.GetIdx())
|
|
130
|
+
atom_cols[a.GetIdx()] = DONOR_COLOR if role == "donor" else ACCEPTOR_COLOR
|
|
131
|
+
a.SetProp("atomNote", donor_note if role == "donor" else acceptor_note)
|
|
132
|
+
|
|
133
|
+
written: List[str] = []
|
|
134
|
+
targets = [("png", png_path)] + ([("svg", svg_path)] if svg_path else [])
|
|
135
|
+
for kind, path in targets:
|
|
136
|
+
drawer = (rdMolDraw2D.MolDraw2DCairo if kind == "png"
|
|
137
|
+
else rdMolDraw2D.MolDraw2DSVG)(1100, 820)
|
|
138
|
+
op = drawer.drawOptions()
|
|
139
|
+
op.legendFontSize = 20
|
|
140
|
+
op.bondLineWidth = 2
|
|
141
|
+
rdMolDraw2D.PrepareAndDrawMolecule(
|
|
142
|
+
drawer, heavy, legend=legend,
|
|
143
|
+
highlightAtoms=hi_atoms, highlightAtomColors=atom_cols,
|
|
144
|
+
)
|
|
145
|
+
drawer.FinishDrawing()
|
|
146
|
+
data = drawer.GetDrawingText()
|
|
147
|
+
with open(path, "wb" if kind == "png" else "w") as f:
|
|
148
|
+
f.write(data)
|
|
149
|
+
written.append(path)
|
|
150
|
+
return written
|
|
@@ -14,8 +14,10 @@ from .core import (
|
|
|
14
14
|
POINT_CHARGE,
|
|
15
15
|
AssignResult,
|
|
16
16
|
MoleculeChargeTemplate,
|
|
17
|
+
RestoreResult,
|
|
17
18
|
assign_charges_to_bulk,
|
|
18
19
|
read_molecule_charges,
|
|
20
|
+
restore_formal_charge,
|
|
19
21
|
)
|
|
20
22
|
|
|
21
23
|
__all__ = [
|
|
@@ -23,6 +25,8 @@ __all__ = [
|
|
|
23
25
|
"POINT_CHARGE",
|
|
24
26
|
"AssignResult",
|
|
25
27
|
"MoleculeChargeTemplate",
|
|
28
|
+
"RestoreResult",
|
|
26
29
|
"assign_charges_to_bulk",
|
|
27
30
|
"read_molecule_charges",
|
|
31
|
+
"restore_formal_charge",
|
|
28
32
|
]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""CLI: OCTA/COGNAC UDF の per-atom 電荷操作。
|
|
2
|
+
|
|
3
|
+
# 単分子 UDF の電荷をバルク UDF の同名分子へ転写
|
|
4
|
+
python -m abmptools.udfcharge transfer --template mol.udf --bulk bulk.udf \
|
|
5
|
+
[--out bulk_charged.udf] [--mol-name NAME] [--mol-index I] \
|
|
6
|
+
[--no-verify-types] [--non-strict]
|
|
7
|
+
|
|
8
|
+
# 中和 (Σq≈0) された 1 分子 UDF の電荷を指定形式電荷に復元
|
|
9
|
+
python -m abmptools.udfcharge restore --udf mol.udf --formal-charge 12 \
|
|
10
|
+
[--out mol_q+12.udf] [--mol-index I] [--mol-name NAME]
|
|
11
|
+
|
|
12
|
+
後方互換: サブコマンド省略時は ``transfer`` として解釈する。
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import logging
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
from .core import (
|
|
22
|
+
assign_charges_to_bulk,
|
|
23
|
+
read_molecule_charges,
|
|
24
|
+
restore_formal_charge,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
_SUBCOMMANDS = {"transfer", "restore"}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _run_transfer(args) -> int:
|
|
31
|
+
tmpl = read_molecule_charges(
|
|
32
|
+
args.template, mol_name=args.mol_name, mol_index=args.mol_index,
|
|
33
|
+
)
|
|
34
|
+
res = assign_charges_to_bulk(
|
|
35
|
+
args.bulk, tmpl, args.out,
|
|
36
|
+
verify_atom_types=not args.no_verify_types,
|
|
37
|
+
strict=not args.non_strict,
|
|
38
|
+
)
|
|
39
|
+
print(f"template : {tmpl.mol_name} (n_atoms={tmpl.n_atoms}, "
|
|
40
|
+
f"net_charge={tmpl.net_charge:+.4f})")
|
|
41
|
+
print(f"assigned : {res.n_molecules_assigned}/{res.n_molecules_total} molecules")
|
|
42
|
+
if res.skipped_indices:
|
|
43
|
+
print(f"skipped : {res.skipped_indices}")
|
|
44
|
+
print(f"output : {res.out_path}")
|
|
45
|
+
return 0
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _run_restore(args) -> int:
|
|
49
|
+
res = restore_formal_charge(
|
|
50
|
+
args.udf, args.formal_charge, args.out,
|
|
51
|
+
mol_index=args.mol_index, mol_name=args.mol_name, mode=args.mode,
|
|
52
|
+
)
|
|
53
|
+
detail = (f"λ={res.lam:.8f}" if res.mode == "proportional"
|
|
54
|
+
else f"shift=S/N={res.shift:.8f}")
|
|
55
|
+
print(f"molecule : {res.mol_name} (n_atoms={res.n_atoms})")
|
|
56
|
+
print(f"mode : {res.mode}")
|
|
57
|
+
print(f"input total : {res.input_total:+.6f} (中和済み想定)")
|
|
58
|
+
print(f"formal charge: {res.formal_charge:+d} ({detail})")
|
|
59
|
+
print(f"output total : {res.output_total:+.6f}")
|
|
60
|
+
print(f"output : {res.out_path}")
|
|
61
|
+
return 0
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def main(argv=None) -> int:
|
|
65
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
66
|
+
# 後方互換: 旧フラット呼び出し (transfer の --template ...) を許容
|
|
67
|
+
if argv and argv[0] not in _SUBCOMMANDS and not argv[0].startswith("-"):
|
|
68
|
+
pass # 不明な位置引数 → そのまま argparse にエラーさせる
|
|
69
|
+
elif argv and argv[0].startswith("-") and "--template" in argv:
|
|
70
|
+
argv = ["transfer"] + argv
|
|
71
|
+
|
|
72
|
+
p = argparse.ArgumentParser(
|
|
73
|
+
prog="python -m abmptools.udfcharge",
|
|
74
|
+
description="OCTA/COGNAC UDF の per-atom 電荷操作 (転写 / 形式電荷復元)。",
|
|
75
|
+
)
|
|
76
|
+
sub = p.add_subparsers(dest="cmd")
|
|
77
|
+
|
|
78
|
+
pt = sub.add_parser("transfer",
|
|
79
|
+
help="単分子 UDF の電荷をバルク UDF の同名分子へ転写")
|
|
80
|
+
pt.add_argument("--template", required=True, help="電荷を持つ単分子 UDF")
|
|
81
|
+
pt.add_argument("--bulk", required=True, help="割り当て先のバルク UDF")
|
|
82
|
+
pt.add_argument("--out", default=None, help="出力 (省略時 <bulk>_charged.udf)")
|
|
83
|
+
pt.add_argument("--mol-name", default=None)
|
|
84
|
+
pt.add_argument("--mol-index", type=int, default=None)
|
|
85
|
+
pt.add_argument("--no-verify-types", action="store_true")
|
|
86
|
+
pt.add_argument("--non-strict", action="store_true")
|
|
87
|
+
pt.add_argument("-v", "--verbose", action="store_true")
|
|
88
|
+
pt.set_defaults(func=_run_transfer)
|
|
89
|
+
|
|
90
|
+
pr = sub.add_parser("restore",
|
|
91
|
+
help="中和済み 1 分子 UDF の電荷を指定形式電荷に復元")
|
|
92
|
+
pr.add_argument("--udf", required=True, help="中和 (Σq≈0) された 1 分子 UDF")
|
|
93
|
+
pr.add_argument("--formal-charge", type=int, required=True,
|
|
94
|
+
help="目標の形式電荷 (整数)")
|
|
95
|
+
pr.add_argument("--out", default=None, help="出力 (省略時 <udf>_q<±S>.udf)")
|
|
96
|
+
pr.add_argument("--mode", choices=["proportional", "uniform"],
|
|
97
|
+
default="proportional",
|
|
98
|
+
help="中和ルール: proportional (|q| 比例、 既定) / uniform (均等分配)")
|
|
99
|
+
pr.add_argument("--mol-name", default=None)
|
|
100
|
+
pr.add_argument("--mol-index", type=int, default=0)
|
|
101
|
+
pr.add_argument("-v", "--verbose", action="store_true")
|
|
102
|
+
pr.set_defaults(func=_run_restore)
|
|
103
|
+
|
|
104
|
+
args = p.parse_args(argv)
|
|
105
|
+
if not getattr(args, "cmd", None):
|
|
106
|
+
p.print_help()
|
|
107
|
+
return 2
|
|
108
|
+
|
|
109
|
+
logging.basicConfig(
|
|
110
|
+
level=logging.INFO if getattr(args, "verbose", False) else logging.WARNING,
|
|
111
|
+
format="%(levelname)s %(name)s: %(message)s",
|
|
112
|
+
)
|
|
113
|
+
return args.func(args)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
sys.exit(main())
|