--- name: coot-essential-api description: "API documentation to be loaded at startup - when starting a Coot session, immediately call get_function_descriptions() with the functions listed in this skill." --- # Coot Essential API Functions This document contains the core Coot API functions needed for typical validation and model-building workflows. Reading these function signatures at session start eliminates the need for searching. ## Setup & Configuration ```python coot.set_refinement_immediate_replacement(1) # CRITICAL: Call this before any refinement operations to make them synchronous # Without this, refinement results may not be available immediately coot.set_imol_refinement_map(imol_map) # CRITICAL: Call this to tell Coot which map to use for refinement. # Must be called once per session (or whenever the map changes). # Without this, refine_residues_py() will fail silently. # Example: coot.set_imol_refinement_map(1) ``` ## Molecule Management ```python coot.is_valid_model_molecule(imol) -> int # Returns 1 if valid model, 0 otherwise coot.is_valid_map_molecule(imol) -> int # Returns 1 if valid map, 0 otherwise coot.molecule_name(imol) -> str # Returns the molecule filename/description coot.n_chains(imol) -> int # Returns number of chains coot.coot_version() -> str # Returns Coot version string coot.load_tutorial_model_and_data() # Loads tutorial RNase structure + maps # Download structures and data from PDBe coot.network_get_accession_code_entity(pdb_accession_code, mode) # Downloads model and/or structure factors from PDBe # Parameters: # pdb_accession_code: str - PDB accession code (e.g., "4wa9") # mode: int - 0 for coordinates (.pdb or .cif), 1 for structure factors (.mtz) # Example - fetch both model and data: # coot.network_get_accession_code_entity("4wa9", 0) # Get coordinates # coot.network_get_accession_code_entity("4wa9", 1) # Get structure factors to make a map ``` ## Checkpoints - Model State Management When experimenting with the various model building tools available to address a particular model-building problem it is useful to create backup checkpoints. This allows you to return to a particular state, so that you can try alternative model-building parameters or functions, or combinations of functions. ```python coot.make_backup_checkpoint(imol, description_string) -> int # Creates a named checkpoint of the molecule's current state # Returns: checkpoint index for later restoration # # Parameters: # imol: Model molecule index # description_string: Human-readable description (e.g., "before rotamer fix") # # CRITICAL: Always checkpoint before experimental or risky operations # # Example: checkpoint_idx = coot.make_backup_checkpoint(0, "before rotamer fix") coot.auto_fit_best_rotamer(0, "A", 42, "", "", 1, 1, 0.01) # ... check if improvement worked ... if not improved: coot.restore_to_backup_checkpoint(0, checkpoint_idx) coot.restore_to_backup_checkpoint(imol, checkpoint_index) # Restores molecule to a previously saved checkpoint state # Parameters: # imol: Model molecule index # checkpoint_index: Index returned by make_backup_checkpoint() coot.compare_current_model_to_backup(imol, checkpoint_index) -> dict # Compares current model state to a checkpoint to see what changed # Parameters: # imol: Model molecule index # checkpoint_index: Index of checkpoint to compare against ``` ## Chain and Residue Information ```python # Requires: import coot_utils coot_utils.chain_ids(imol) -> list # Returns list of chain IDs, e.g., ['A', 'B'] # Direct C++ functions (preferred when possible) coot.chain_id_py(imol, chain_index) -> str # Get chain ID by index ``` ## Secondary Structure Information ```python coot.get_header_secondary_structure_info(imol) -> dict # Returns secondary structure from PDB header # Returns: {'helices': [...], 'strands': [...]} # # Each helix dict contains: # serNum, helixID, initChainID, initSeqNum, endChainID, endSeqNum, length, comment # # Each strand dict contains: # SheetID, strandNo, initChainID, initSeqNum, endChainID, endSeqNum # # Example - get beta barrel strands: ss = coot.get_header_secondary_structure_info(0) if 'strands' in ss: for strand in ss['strands']: print(f"Strand {strand['strandNo']}: {strand['initSeqNum']}-{strand['endSeqNum']}") ``` ## Navigation ```python coot.set_go_to_atom_chain_residue_atom_name(chain_id, resno, atom_name) -> int # Centers view on specified atom. Returns 1 on success. # Example: coot.set_go_to_atom_chain_residue_atom_name("A", 42, "CA") coot.closest_atom_simple_py() -> list # Returns: [imol, chain_id, resno, ins_code, atom_name, alt_conf] # Gets the atom closest to screen center across all displayed molecules coot.closest_atom_py(imol) -> list # Same as above but for specific molecule coot.active_atom_spec_py() -> list # Returns the currently "active" atom specification (or False if none found) # (found, (imol, atom_spec)) # found: Boolean indicating if an atom exists close to the center # molecule_number: Integer molecule ID # atom_spec: List [chain_id, resno, ins_code, atom_name, alt_conf] ``` ## Residue Inspection ```python coot.residue_info_py(imol, chain_id, resno, ins_code) -> list # Returns detailed atom information for a residue # # Parameters: # imol: Model molecule index # chain_id: Chain identifier (e.g., "A") # resno: Residue number # ins_code: Insertion code (use "" if none) # # Returns: List of atom entries, each containing: # [[atom_name, alt_conf], [occupancy, b_factor, element, ?], [x, y, z], atom_index] # # Example output for a complete CYS: # [[' N ', ''], [1.0, 12.5, ' N', ''], [x, y, z], 100], # [[' CA ', ''], [1.0, 11.2, ' C', ''], [x, y, z], 101], # [[' CB ', ''], [1.0, 14.3, ' C', ''], [x, y, z], 102], # [[' SG ', ''], [1.0, 18.1, ' S', ''], [x, y, z], 103], # Sulfur! # [[' C ', ''], [1.0, 10.8, ' C', ''], [x, y, z], 104], # [[' O ', ''], [1.0, 11.0, ' O', ''], [x, y, z], 105] # # NOTE: b_factor may be a list [b_iso, B11, B22, B33, B12, B13, B23] for anisotropic # Always handle safely: # def get_b(atom): b = atom[1][1]; return b[0] if isinstance(b, list) else b # Check for missing atoms in a residue atoms = coot.residue_info_py(0, "A", 72, "") atom_names = [a[0][0].strip() for a in atoms] print(f"Atoms present: {atom_names}") # Expected atoms for common residues expected_atoms = { 'CYS': ['N', 'CA', 'CB', 'SG', 'C', 'O'], 'ILE': ['N', 'CA', 'CB', 'CG1', 'CG2', 'CD1', 'C', 'O'], 'GLY': ['N', 'CA', 'C', 'O'], 'PHE': ['N', 'CA', 'CB', 'CG', 'CD1', 'CD2', 'CE1', 'CE2', 'CZ', 'C', 'O'], } # Find missing atoms res_type = coot.residue_name_py(0, "A", 72, "") if res_type in expected_atoms: missing = [a for a in expected_atoms[res_type] if a not in atom_names] if missing: print(f"WARNING: Missing atoms in {res_type}: {missing}") ``` ## Validation - Density Fit ```python coot.map_to_model_correlation_stats_per_residue_range_py( imol, # Model molecule number chain_id, # Chain identifier (e.g., "A") imol_map, # Map molecule number n_per_range, # Residues per window (use 1 for per-residue) exclude_NOC # 0=include all atoms, 1=exclude backbone N,O,C ) -> list # Returns: [[all_atom_stats], [sidechain_stats]] # Each stats list: [[residue_spec, [n_points, correlation]], ...] # residue_spec = [chain_id, resno, ins_code] # Example - find worst fitting residues: stats = coot.map_to_model_correlation_stats_per_residue_range_py(0, "A", 1, 1, 0) all_atom = stats[0] worst = sorted(all_atom, key=lambda x: x[1][1])[:5] # 5 worst by correlatio # Mainchain vs sidechain correlation for a single residue: coot.map_to_model_correlation_py(imol, residue_specs, neighb_specs, atom_mask_mode, imol_map) # atom_mask_mode: 0=all atoms, 1=mainchain only, 2=sidechain only # Use to distinguish backbone problems from sidechain problems before choosing a fix # Per-atom density probing — the most powerful backbone diagnostic: sigma = coot.map_sigma_py(imol_map) d = coot.density_at_point(imol_map, x, y, z) / sigma # value in sigma units # Backbone atom < 0.5σ = problem; carbonyl O near 0σ with good CA = pepflip needed ``` ## Validation - Geometry ```python coot.all_molecule_ramachandran_score_py(imol) -> list # Returns a list of exactly 6 elements (confirmed from C++ source): # [0]: overall score (float) # [1]: n_residues (int) # [2]: score_non_sec_str (float) # [3]: n_residues_non_sec_str (int) # [4]: n_zeros (int) # [5]: per-residue list (list of per-residue entries) # # Each per-residue entry: [[phi, psi], [chain_id, resno, ins_code], probability, [prev_resname, this_resname, next_resname]] # NOTE: rama_data[5] and rama_data[-1] are equivalent and both correct. # LOW probability = BAD (outlier). Outlier threshold: prob < 0.02 # # Example: # per_res = coot.all_molecule_ramachandran_score_py(imol)[5] # outliers = [r for r in per_res if r[2] < 0.02] # worst = min(per_res, key=lambda x: x[2]) coot.rotamer_graphs_py(imol) -> list # Returns: [[chain_id, resno, ins_code, score_percentage, resname], ...] # LOW score = BAD rotamer coot.molecule_atom_overlaps_py(imol, n_pairs) -> list # Returns worst n_pairs atom overlaps (use -1 for all) # Each overlap: { # 'atom-1-spec': [imol, chain, resno, ins, atom_name, alt], # 'atom-2-spec': [imol, chain, resno, ins, atom_name, alt], # 'overlap-volume': float # in ų, >5.0 is severe # } ``` ## Validation - Unmodeled Density ```python coot.find_blobs_py(imol_model, imol_map, sigma_cutoff) -> list # Finds unmodeled density blobs # Returns: [[position, score], ...] # position is a list or 3 floats, (for x, y, z) # Use sigma_cutoff=3.0 for difference maps, 1.0 for 2mFo-DFc # Higher score = larger/stronger blob ``` ## Validation - Hydrogen Bonds ```python coot.get_hydrogen_bonds_py(imol, selection_1, selection_2, mcdonald_and_thornton) -> list # Find hydrogen bonds between two atom selections. # selection_1, selection_2: MMDB selection strings (e.g. "//A/35", "//A") # Note: selection_1 and selection_2 can be the same, e.g. "//A" for intra-chain H-bonds # mcdonald_and_thornton: 0 if model has no H atoms, 1 if it does # Returns list of H-bond candidates, each a list of 12 elements: # [0] hydrogen atom (dict or None) # [1] donor atom (dict) # [2] acceptor atom (dict) # [3] donor neighbour atom (dict or None) # [4] acceptor neighbour atom (dict or None) # [5] angle_1 (float, degrees) # [6] angle_2 (float, degrees) # [7] angle_3 (float, degrees) # [8] distance (float, Å) # [9] ligand_atom_is_donor (bool) # [10] hydrogen_is_ligand_atom (bool) # [11] bond_has_hydrogen_flag (bool) # Atom dicts have keys: x, y, z, name, element, chain, residue_name, occ, b_iso, altLoc # # Example: hbonds = coot.get_hydrogen_bonds_py(0, "//A/35", "//A", 0) for hb in hbonds: donor = hb[1] acceptor = hb[2] dist = hb[8] d_str = donor['chain'] + " " + donor['residue_name'] + " " + donor['name'].strip() a_str = acceptor['chain'] + " " + acceptor['residue_name'] + " " + acceptor['name'].strip() print("H-bond: " + d_str + " -> " + a_str + " dist=" + str(dist)) ``` ## Refinement ```python coot.refine_residues_py(imol, residue_specs) -> list # Real-space refinement of specified residues # residue_specs = [["A", 42, ""], ["A", 43, ""], ...] # [chain, resno, ins_code] # Returns: ['', status, lights] where: # status: 0=converged, -2=GSL_CONTINUE (call again), 27=no progress # lights: list of [name, label, value] refinement statistics, or False # CRITICAL: if status == -2, call refine_residues_py() again (up to 3 times total) # Example robust call: # for _ in range(3): # result = coot.refine_residues_py(imol, specs) # if result and result[1] != -2: break # accepted = coot.accept_moving_atoms_py() # get traffic lights ``` ## Model Building - Rotamers ```python coot.auto_fit_best_rotamer( imol, # Model molecule chain_id, # Chain (e.g., "A") resno, # Residue number ins_code, # Insertion code (usually "") altloc, # Alt conf (usually "") imol_map, # Map for density scoring clash_flag, # 1=check clashes, 0=ignore lowest_probability # Minimum rotamer probability (e.g., 0.01) ) -> float # Returns new rotamer score, or -99.9 if residue has no rotamers (GLY, ALA) ``` ## Model Building - Backbone ```python coot.pepflip(imol, chain_id, resno, ins_code, altloc) # Flips the peptide bond at specified residue # Use for fixing cis/trans peptide issues or Ramachandran outliers # or other false minimum backbone conformations. # Follow with refinement of surrounding residues ``` --- ## CRITICAL: Always Render Validation Results as Interactive SVG Widgets **When presenting validation results, geometry analysis, per-atom density data, or any tabular data about multiple residues, ALWAYS render an interactive SVG widget using `visualize:show_widget`. Never just print a wall of text.** The user can click on each residue block to navigate directly to it in Coot or trigger a fix. This is far more useful than stdout and makes results immediately actionable. ### When to render a widget — trigger situations: - After running full validation (Ramachandran, rotamers, density fit, clashes, geometry) - After a per-atom backbone density probe scan - After any survey comparing multiple residues or chains - After a before/after fix comparison showing improvement - Any time there are more than ~5 residues worth of results to show ### Severity colour coding: - `c-red` — severe issues (Rama score < 0.001, rotamer 0%, corr < 0.3, omega > 20° off) - `c-amber` — moderate issues (Rama 0.001–0.01, rotamer < 5%, corr 0.3–0.65) - `c-gray` — informational / OK residues - `c-teal` — unmodelled density blobs / features to investigate - `c-green` — successfully fixed residues (before/after comparisons) ### onclick patterns — make them actionable, not just informational: ```python # Navigation onclick="sendPrompt('Go to A/41 GLU and show me the density')" # Investigation onclick="sendPrompt('Go to B/257 GLU and investigate — negative correlation')" # Fix requests onclick="sendPrompt('Fix the clash between A/2 CA and A/89 CZ')" onclick="sendPrompt('Try pepflip at B/262 and refine')" onclick="sendPrompt('Fix rotamer A/32 GLN — 0% score')" # Comparative onclick="sendPrompt('Go to A/260 ALA — worst Ramachandran in chain A')" ``` The onclick prompt should describe the *action to take*, not just what the residue is. A user clicking a red block should trigger the next useful step automatically. ### Minimal widget template for validation results: ```svg Ramachandran outliers A/41 GLU score 0.00004 phi=112° A/35 VAL score 0.006 ``` ### Geometry widget — always include ideal, actual, Z score: For bond/angle/omega distortions, display as rows with severity colour. Omega torsion outliers (|omega − 180°| > 15°) are the most sensitive backbone diagnostic and should always be highlighted — they identify misplaced backbone immediately. ```svg A/258→A/259 omega 60.0° (ideal 180°) +24.0σ distorted! ``` --- ## Typical Validation & Fix Workflow ```python # 1. Setup coot.set_refinement_immediate_replacement(1) # 2. Check what's loaded for i in range(10): if coot.is_valid_model_molecule(i): print(f"Model {i}: {coot.molecule_name(i)}") if coot.is_valid_map_molecule(i): print(f"Map {i}: {coot.molecule_name(i)}") # 3. Validate density fit stats = coot.map_to_model_correlation_stats_per_residue_range_py(0, "A", 1, 1, 0) worst = sorted(stats[0], key=lambda x: x[1][1])[:10] # 4. Check for clashes overlaps = coot.molecule_atom_overlaps_py(0, 30) severe = [o for o in overlaps if o['overlap-volume'] > 5.0] # 5. Fix bad rotamers coot.auto_fit_best_rotamer(0, "A", 89, "", "", 1, 1, 0.01) coot.refine_residues_py(0, [["A", 89, ""]]) # 6. Fix backbone issues coot.pepflip(0, "A", 41, "", "") coot.refine_residues_py(0, [["A", 40, ""], ["A", 41, ""], ["A", 42, ""]]) # 7. Re-validate overlaps_after = coot.molecule_atom_overlaps_py(0, 10) # 8. ALWAYS render results as an interactive SVG widget — see section above ``` ## Important Notes 1. **Always call `set_refinement_immediate_replacement(1)` first** - makes refinement synchronous 3. **Use `coot.*_py()` functions directly** - faster than `coot_utils` wrappers 4. **Import coot_utils only when needed** - for convenience functions like `chain_ids()` 5. **The `coot` module is auto-imported** - no import statement needed