Releases: cameronabrams/pestifer
Releases · cameronabrams/pestifer
Release v2.6.1
- bugfix: large membrane-embedding builds aborted at the end of the
make_membrane_systemembed step with a VMD segmentation fault (signal 11), even though the embedded, solvated, and neutralized system had already been written correctly. The clash-removal steps inbilayer_embed.tclbuiltatomselect "index <list>"selections directly from the per-atom index lists returned bymeasure contacts; on a large solvated system those lists run to ~10^5 atoms, and VMD's atom-selection parse tree has one node per index whose destructor (atomparser_node::~atomparser_node) is recursive — so freeing such a selection recurses ~10^5 frames deep and overflows the stack during interpreter teardown at VMD exit (confirmed via core dump:VMDApp::~VMDApp→DeleteInterpProc→AtomSel::~AtomSel→ParseTree::~ParseTree→ hundreds of thousands of nested~atomparser_nodeframes). The crash was purely in at-exit teardown but returned signal 11 and aborted the whole build, and it reproduced on VMD 1.9.3, 2.0.0, and 2.0.1a1 (it is a long-standing VMD bug, not version-specific). The clashing atoms are now mapped to(segname, resid)by reading directly from the parent whole-molecule (all) selection's attribute lists, so no largeindexselection — and no large parse tree — is ever constructed - bugfix: the same clash-removal loops invoked
delatom $seg $resid(which deletes an entire residue) once per contacting atom rather than once per residue, so a lipid or water with several atoms near the protein was deleted on the first call and then re-deleted on every subsequent atom — emitting tens of thousands ofno residue ... of segment ...messages on a large embed. Each clashing residue is now deduplicated and deleted exactly once - enhancement:
embed_proteinno longer appends a spurious trailingregenerate angles dihedralsto the embed psfgen script. It calledwritescript(regenerate=True, writepsf=False, writepdb=False), which emitted aregeneratewith no followingwritepsf/writepdbto consume it — pure wasted work regenerating angles and dihedrals for the ~2M-atom post-autoionize context. Thebilayer_embedscript already regenerates before each structure it writes, soembed_proteinnow usesregenerate=False(matching the sibling quilt call site)
Release v2.6.0
- new feature: NAMD runs under SLURM can now span multiple nodes, controlled by a new
namd.cpu-parallel-launcheroption (auto|numactl|srun|mpirun|charmrun, defaultauto). Previously the SLURM CPU launch path always usednumactl --interleave=all namd3 +p N, which runs a single node-local process and cannot use more than one node; on a multi-node allocation with an MPI NAMD build this failed immediately with the Charm++ "to use multiple processors ... charmrun +pN namd3 / build the mpi-linux-x86_64-smp version" error.autokeeps the single-nodenumactllaunch for one-node allocations and switches tosrun namd3whenSLURM_NNODES > 1;mpirunlaunches via the MPI runtime's own process manager (mpirun -np N namd3, e.g. Intel MPI Hydra);charmrunuses charmrun's++mpiexeclauncher for Charm++ net-layer builds. A companionnamd.srun-mpi-typeoption emitssrun --mpi=<plugin>(e.g.pmi2/pmix) for MPI runtimes — notably Intel MPI — whose ranks would otherwise each initialize as an independent 1-PE job and collide on the output DCD withCouldn't open DCD file ...: File exists - bugfix: multi-node NAMD launches no longer stage parameter files to node-local scratch.
_stage_params_to_local_scratchcopied the parameter files to$TMPDIRand rewrote the NAMD config'sparametersline to that absolute path, which is only valid when every PE runs on one node; under a multi-nodesrun/mpirunlaunch the files existed only on the launch node, so ranks on the other nodes died withUNABLE TO OPEN CHARMM PARAMETER FILE. Staging is now gated on a single-node launch, and multi-node runs read the parameter files from the shared filesystem (as they already do forstructure/coordinates) - bugfix: the NAMD log parser no longer aborts the whole build on a single malformed line. Live NAMD stdout from a multi-rank run (e.g.
srun/mpirunacross nodes) can interleave output from different PEs, producing a garbledENERGY:record with a token like0LINE;process_energy_linethen raisedValueErroronfloat()and killed the run even though the simulation itself was fine.process_linenow catchesValueError/IndexError/KeyErrorfrom a single line processor, logs it at debug level, and continues without appending a partial record - bugfix: subcontroller tasks now inherit the parent run's NAMD settings.
Config.taskless_subconfigbuilt the subcontroller configuration from schema defaults only, so MD runs launched insidemake_membrane_system(which uses a subcontroller for the membrane-relaxation stages) ignored user overrides such asnamd.cpu-parallel-launcherand reverted to the default — reintroducing the multi-node launch failure for the relaxation stages even when the top-level tasks were correctly configured. The subconfig now inherits the progenitor's user settings (NAMD launcher, paths, force field, psfgen options) and resets only the task list - bugfix:
terminate/packagebuilds that run no MD step (e.g.continuation→psfgen→terminate) produced a consolidated minimal.prmwith an empty NONBONDED section (nonbonded=0) and only partial bonded terms, so the packaged production run failed withDIDN'T FIND vdW PARAMETER FOR ATOM TYPE ...(the first such type encountered, e.g.NH3). The standard CHARMM.prmparameter files are staged by NAMD/MD tasks, so a build with no MD step had registered only topology.strstream files for consolidation;generate_minimal_paramsnow always stages and includes the standard parameter set (via the NAMD scripter'sfetch_standard_charmm_parameters) before consolidating, and warns loudly if a consolidated file still has no nonbonded parameters - bugfix: corrected a Tcl variable-dereference typo (
set $box_min_z/set $box_max_zinstead ofset box_min_z/set box_max_z) in the bilayer-embed water-gap padding, which created a garbage-named variable and left the box bound unchanged when the water gap above or below the protein was under 3 Å - dependency: dropped the
gputilruntime dependency (and thesetuptoolsshim it required to providedistutilson Python 3.12+). Local NVIDIA GPU enumeration now queriesnvidia-smi --query-gpu=indexdirectly via a small helper, with the same behavior as before (enumerates physical GPUs, returns an empty list whennvidia-smiis absent or fails)
Release v2.5.2
- bugfix: a plain
pip install pestifer(without the optionalligand-paramgenextra) crashed on every CLI invocation withModuleNotFoundError: No module named 'dimorphite_dl'; the optionalrdkitanddimorphite_dldependencies were imported at module load time incharmmff.ligand_paramgen.protonationandcharmmff.ligand_paramgen.mol2_writer, and sincesubcommands/__init__.pyeagerly imports themake-ligand-mol2subcommand at startup, those imports ran for every command. The imports are now lazy (deferred into the functions that use them) and raise a clearpip install pestifer[ligand-paramgen]hint when actually needed - bugfix: the
dependenciesarray inpyproject.tomlwas missing its closing]
Release v2.5.1
- bugfix:
PSFContents.remove_ignored_residuescrashed withTypeError: 'PSFAtom' object is not subscriptablebecause it wrongly indexed the result ofBaseObjList.get()with[0];get()returns the matched object directly when there is exactly one match (which is always the case for an atom-by-serial lookup), so the trailing[0]was indexing into the atom itself - bugfix:
AsymmetricUnitextendedignored_residuestwice with the samemore_ignored_residueslist (a copy-paste duplicate around the interveninggrafts.assign_residuescall), causingPSFContents.remove_ignored_residuesto be called for the same residues twice and crash on the second pass whenself.atoms.get()returnedNone(atoms already removed) andself.atoms.remove(None)invokedPSFAtom.__eq__againstNone.serial - bugfix: continuation+psfgen builds that inserted protein residues at glycosylation sites (e.g. extending the HIV-1 gp41 ectodomain from MPER residue 685 through TM residue 710 on a pre-built glycoprotein) emitted glycan-link patches against the protein segment (
patch 14ba A:1222 A:1223) instead of the glycan segment (patch 14ba AG01:1222 AG01:1223), causing psfgen to abort withno residue X of segment A/MOLECULE DESTROYED BY FATAL ERROR; two related issues were fixed: (a)Link._from_psflinkpatchpopulatedchainID1/chainID2from the psfgen segname but leftsegname1/segname2unset, so whenchainID1was later remapped from the segname (AG01) to the biological chainID (A) so the lookup against PDB-derived residues could succeed, the writer atPsfgenScripter.write_link(which prefersL.segname1overL.residue1.chainID) had nothing but the biological chainID to fall back on; (b)ResidueList.renumber, when renaming a glycan residue whose resid collided with a newly inserted protein residue (glycan A:686 → A:1324 after inserting protein A:686), only propagated the resid update to links keyed by biological chainID and skipped links from PSF REMARKS whosechainID1/chainID2carried the psfgen segname, so those stale links became orphans and the orphan cleanup atLinkList.assign_residuesremoved the entire glycan tree from the residue list — leaving segment AG01 with only the renumbered root and stripping the patches' target residues;renumbernow also keys itsmapper_by_chainby segname when segname differs from chainID
Release v2.5.0
- new feature:
pestifer make-ligand-mol2subcommand that, given a 4-letter RCSB PDB code or a path to a local.pdbfile, generates a CGenFF-ready Tripos mol2 file for every HETATM ligand whose resname is not already defined in the loaded CHARMM topologies; for each unknown ligand it fetches the SMILES from the RCSB Chemical Component Dictionary (preferring the OpenEye canonical-stereo descriptor), builds an RDKitMolwhose heavy atoms are in PDB order and carry the original PDB atom names, protonates at the target pH (default 7.4) via Dimorphite-DL, places explicit Hs in 3D, and writes the mol2 via Open Babel with--title <RESNAME>so the CGenFF binary/web tool registers the resultingRESIunder the correct residue name (rather than the leaked tempfile path); per-ligand failures are surfaced in a summary table without aborting the run, and--smiles RESNAME=...overrides the RCSB lookup when a custom tautomer or charge state is needed - new feature: new
pestifer.charmmff.ligand_paramgensubpackage exposes the building blocks reused bymake-ligand-mol2as a library:fetch_ligand_smiles(comp_id)(RCSB lookup with LRU caching and HTTP-error →RCSBLookupErrormapping),protonate_ligand(residue, smiles, ph)(RDKit + Dimorphite-DL pipeline that preserves PDB heavy-atom order and stamps each heavy atom with the original PDB name on the_pdb_nameproperty),write_mol2(mol, resname, outpath)(PDB-block-via-obabel writer that propagates_pdb_nameand assigns sequentialH1,H2, ... names to hydrogens), andgenerate_ligand_mol2s(parsed, charmmff_content, outdir, ph, smiles_overrides)(the orchestrator the subcommand calls, which the build workflow will also call for unknown ligands) - new feature: well-known per-user toppar cache at
~/.pestifer/toppar/; when this directory exists, pestifer automatically prepends it tocharmmff.user_custom.searchpathso.strfiles dropped there are picked up by every build without requiring auser_customblock in YAML; any project-local searchpath entry is loaded after the cache and overrides it (last-loaded wins) with a warning naming both files; designed as the default destination for.strfiles produced by runningmake-ligand-mol2output through the CGenFF binary or web tool - enhancement:
charmmff.user_custom.searchpathentries now expand~/(the user's home directory) and shell environment-variable references like$HOME/fooor${SCRATCH}/charmmbefore the directory check; previously those were taken literally and silently failed - behavior change:
CHARMMFFContent.add_custom_directoryno longer asserts on duplicate-basename clashes between searchpath entries; instead, the later-loaded file wins and a warning is emitted naming both paths (the assertion previously crashed pestifer when, e.g., the user's project happened to contain a.strfile with the same basename as one in the cache); same-resname clashes across differently-named files in the searchpath also emit a warning and follow last-loaded-wins semantics, so a project-local override of a cached parameterization is surfaced without silently merging - new optional dep:
[project.optional-dependencies]table inpyproject.tomldeclares anligand-paramgenextra (pip install 'pestifer[ligand-paramgen]') that pulls inrdkitanddimorphite_dl; theobabelbinary remains a runtime-PATH dependency, documented alongside the new subcommand - test:
tests/unit/test_charmmff/test_charmmffcontent.py::TestCharmmffContent.setUpClasswas picking the CHARMMFF version directory bymtimerather than by parsed month-year (the productionResourceManager.charmmff_version_dirs()orders semantically); when thefeb26andjul24directories were extracted out of release order,mtimeselectedjul24and the test's hard-coded counts (calibrated againstfeb26) failed by ~1400 residues; setUpClass now delegates toResourceManager.charmmff_version_dirs()so the test always exercises the same CHARMMFF release that production code uses - test: new
tests/unit/test_charmmff/ligand_paramgen/package covers the ligand-paramgen building blocks (29 tests): protonation invariants on five SMILES across a pH=7.4 charge range, RCSB descriptor-priority selection underunittest.mockofrequests.get, mol2 title/atom-name round-trip via the realobabelbinary, and orchestrator-level altloc dedup and known-resname filtering using realHetatmobjects;test_charmmffcontent.pygains threeTestAddCustomDirectorycases (tilde expansion, duplicate-basename warning + last-wins, duplicate-RESI warning + last-wins) that build a stubCHARMMFFContentvia__new__to avoid paying the full tarball-load cost - doc: new
docs/source/subs/make-ligand-mol2.rstcovers the subcommand with examples (PDB code, local file, SMILES override, pH override) and outlines the CGenFF round-trip workflow (web tool →~/.pestifer/toppar/); linked from the subcommand toctree inusage.rst; thecharmmff.user_customschema docstring gains "Per-user toppar cache" and tilde-expansion sections
Release v2.4.13
- behavior change:
make_membrane_systemno longer silently turns on NAMD's on-the-flypressureProfilecalculation during NPT/NPAT bilayer-relaxation stages on CPU NAMD; pressure profile calculation is now opt-in via a new top-levelmake_membrane_system.compute_pressure_profileblock (enabled: falsedefault, plusslabs/freqknobs that map topressureProfileSlabs/pressureProfileFreq); previously, any NPT/NPAT stage whoseother_parametersdid not explicitly mentionpressureProfilehad it auto-injected asonon CPU builds, surprising GPU users (theprocessor-typeguard correctly skipped injection on GPU but the opt-out default was hostile and unintuitive); themdplottask'sprofiles=['pressure']list, which was unconditionally requested byequilibrate_bilayer, is now likewise gated on the new flag so no spurious pressure-profile plotting is attempted when the data is not produced - new feature:
make_membrane_systemnow hard-errors withPestiferBuildErrorifcompute_pressure_profile.enabled: trueis set under GPU NAMD (processor-type: gpu), or if any explicitother_parameters.pressureProfilesetting in a stage is truthy on GPU; CUDA-enabled NAMD does not supportpressureProfile, and the previous silent-strip behavior masked user misconfiguration; the error message names the offending stage's ensemble and points at the two ways to fix the conflict (disable the flag, or use a CPU NAMD build) - doc: ex16 and ex17 example YAMLs (membrane-embedded HIV-1 gp41 MPER-TM trimer builds) now carry a header comment explaining that their post-equilibration NPAT stage and packaged production run use
pressureProfile, so they must be run with a CPU NAMD build; the comment names the specificother_parametersblocks to strip if a user wants to run them on GPU
Release v2.4.12
- bugfix:
PackmolLogParserfailed on logs produced bypackmol21.x because the new release reorganized its header in three breaking ways: thePeriodic boundary condition activated:line became multi-line with indentedMinimum coordinates:andMaximum coordinates:rows, thePBC Reference box:line was removed entirely (its information now carried by the min/max rows), and the per-typeMaximum number of GENCAN loops for type:lines were dropped in favor of the aggregatefor all molecule packing:value alone; the parser now auto-detects the PBC format by checking whether numeric tokens trail the activation line and reconstructs bothpbc_boxsize(max-min) andpbc_reference_box(concatenated min+max) so downstream consumers see the same metadata schema; logs from packmol 20.15.1 continue to parse correctly via the legacy code path - bugfix:
PackmolLogParserinitialized each structure'scurrent_gencan_loopscounter only inside the per-typeMaximum number of GENCAN loops for type:block, so aKeyErrorwas raised on the first GENCAN report for any structure whose type lacked that header line (always the case in packmol 21.x); the counter is now initialized to 0 at structure-creation time - bugfix:
PackmolLogParser.finalize()crashed with'Axes' object is not subscriptablefor single-structure packs becauseplt.subplots(1, 1)returns a bareAxesrather than a 1-element array;squeeze=Falseplusax.flatten()makes the indexing uniform
Release v2.4.11
- new feature: integrated the VMD
ssrestraintsplugin into themdtask as a peer ofconstraintsandcolvar_specs; when a top-levelssrestraintssub-dict appears under anmdtask, pestifer invokes the plugin against the current state's PSF/PDB to emit a NAMDextraBondsfile and wiresextraBonds=on/extraBondsFile=<basename>.extrabondsinto the generated NAMD config; the schema entry exposes all 13 plugin options (selection text, force constants for protein/NA,namode,ideal, H-bond restraint sub-options) with defaults that mirror the plugin's own; the generated extraBonds file participates in the artifact pipeline via a newNAMDExtraBondsFileArtifact - enhancement:
packmolis now version-validated at config-load time; pestifer probes the resolved binary by sending it an empty stdin and parses the version banner, refusing any version below 20.15.1 (the first release with thepbckeyword); when the resolved binary lives inside a conda environment, the error message hints at the AmberTools/packmol-memgenshadow problem and recommends installing a standalone packmol outside the conda env;paths.packmolmay be set to an absolute path in user YAMLs to bypassPATHresolution entirely; ex16 and ex17 example YAMLs now demonstrate this pattern - enhancement: the
PackmolScripterpost-run log scan now flags lines containingERROR,Could not open file, orCould not findand forces a non-zero return code so callers raise; older packmol could exit 0 while still failing internally, and this surfaces those failures - bugfix:
[package vcompare [vmdinfo version] X.Y]returns unreliable results on VMD builds whose version banner has trailing tags or non-numeric components; replaced the comparison in bothpestifer/resources/tcl/macros.tcland the macro generator inpestifer/core/labels.pywith[lindex [split [vmdinfo version] .] 0] < MAJOR, an integer-major-version gate that is robust across builds - doc: explain that the
mdplotsubcommand and task emit per-quantity CSV files alongside plots; explain thatdensityis a pestifer-computed timeseries column derived from the cell volume, not a NAMD output; updated themdplot2.4.x enhancement docs (time-on-x-axis, automatic unit selection) - test: corrected
_ARCHIVE_PREFIXintest_desolvate.pyto match the schema default ('artifacts') so the test reflects whatterminateactually produces by default; relaxed the per-binary path assertions intest_config_help_examplesfrom strict equality toendswith()so legitimate per-examplepaths.packmoloverrides (such as the absolute paths added to ex16/ex17) do not break the smoke test
Release v2.4.10
- enhancement: GPU mode is now auto-detected by comparing
paths.namd3andpaths.namd3gpu; if the two paths differ andnamd3gpuis found in PATH, pestifer switches to GPU mode automatically — nonamd.processor-typesetting required;processor-typeis retained in the schema for backward compatibility but is ignored;paths.namd3gpudefaults tonamd3(CPU mode when identical); workstation users with separate CPU and GPU-resident NAMD3 builds simply setpaths.namd3gputo the GPU binary name/path; the--gpuCLI flag now correctly propagates GPU mode to both the config and the live NAMD scripter - bugfix: GPU-resident NAMD3 config parameter renamed from
GPUResidenttoCUDASOAintegrateto match current NAMD3 release notes;outputEnergies: 500added to thegpu-residentschema section (NAMD recommends 500–1000 for GPU-resident mode);writescriptnow suppresses any param key that appears ingpu-resident(case-insensitive) so each parameter appears exactly once in the generated config file - enhancement: multi-GPU GPU-resident launches now include
+pmepes Kto assign fewer PEs to the PME device and reduce load imbalance; K is computed as total PEs minus 8×(N−1) for N GPUs, matching the NAMD3 recommended work distribution examples
Release v2.4.9
- enhancement:
mdplottimeseries plots now use simulation time on the bottom x-axis instead of raw timestep index; units are auto-selected by magnitude (ps when total duration < 1000 ps, ns otherwise); the integer timestep index is shown on the top spine via a secondary x-axis;NAMDLogParser.finalize()adds adt_fsconstant column to the energy dataframe so that chained runs with different timestep sizes are handled correctly — simulation time is computed in the plot task ascumsum(dt_fs × ΔTS / 1000)across the concatenated dataframe, which correctly accumulates time across run segments regardless of whether the timestep changes between segments - enhancement:
mdplottimeseries y-axis unit labels now default to the correct physical units for known NAMD output columns (kcal/mol for energy terms, K for temperature, bar for pressure, ų for volume) rather than*; energy quantities whose maximum absolute value exceeds 1000 kcal/mol are automatically scaled by 1/1000 and labeled1000 kcal/molto avoid unwieldy tick magnitudes