Hi Artie,
There were a couple of elusive and pernicious bugs in the ChimeraX C++ code that could cause crashes when Python ran garbage collection.  We fixed one a couple of months ago (so the fix isn't in the 1.7.1 release you are using) and fixed the other one today, so it will only be in the release candidate and daily builds starting tomorrow.  So I recommend getting tomorrow's 1.8 release candidate and seeing if that works better for you.
As an aside, it is generally better to report bugs using the Help→Report A Bug menu item, since that's includes extensive information about your system and ChimeraX's version and configuration, and since most bugs aren't of general interest to all users -- though this particular one may be somewhat of an exception.

--Eric

Eric Pettersen
UCSF Computer Graphics Lab
 

On Jun 7, 2024, at 12:42 PM, Artie Kushner via ChimeraX-users <chimerax-users@cgl.ucsf.edu> wrote:

Hi, I hope the summer is starting off really well for you.

tldr: I leave ChimeraX running movie/image generating commands from a python script in a tmux session and it segfaults on multiple machines.

I was wondering if someone has encountered this before or can lend advice as to why this happens. I'd like to produce some movies (or at least pictures) in bulk (around 2000 individual molecules). I preprocess each one (load locally or open, add some representation, and either start recording a movie or "save XXXX.png"). After about 8-10 successful movies or images are produced I get a ChimeraX segfault and the process dies.

This is quite perplexing to me because
  - I tried it on multiple machines:  Ubuntu 22.04, installed from the .deb and Arch, installed from aur distribution.
  - both with `--offscreen` and `--nogui` flags and without them ( in fact, following up some threads in the mailing list it seems like it's not possible to produce movies with --nogui, just pngs)
  - there seems to be no excessive memory or page cache issues, although i haven't profiled it. Only one core is occupied when rendering both mp4/png's.


Below I'm attaching a crash log from one of the machines (Ubuntu 22.04) and the description of my setup, which is a little awkward, but I don't think it's the cause since it produces some samples successfully before crashing. I hope i'm wrong.

Best regards and any tips are really appreciated! I was really looking forward to having some crisp images.

---------------------------------------------------------------------------------------

I start the process by calling a python script at the command line: ` chimerax --script "/home/student/dev/riboxyz/chimerax/ribrepr.py"  --nogui --offscreen` when i tried generated images. This was after I gave up on getting the movies, which i did by just opening a ChimeraX gui on our workstation and calling a "loop.py" after a load the commands from "ribrepr.py" file from the gui command line. I do both in a tmux session.

```loop.py
import os
from chimerax.core.commands import run
from concurrent.futures import ThreadPoolExecutor

DEST_DIR = "/home/rtviii/dev/riboxyz/chimerax/movies"

# This expands to ~1800 PDB ids: rcsb_id:= {4UG0, 7K00 and so on}
for rcsb_id in os.listdir('/home/rtviii/dev/RIBETL_DATA'):
    movie_dir = os.path.join(DEST_DIR, "{}.mp4".format(rcsb_id))
    print("Attempting to write ", movie_dir)
    if "{}.mp4".format(rcsb_id) in os.listdir(DEST_DIR):
        print("Skipping {}. Exists".format(rcsb_id))
        continue
    else:
        run(session,"ribmovie {}".format(rcsb_id))  # <---- ribmovie command corresponds to the `produce_and_save_movie` in ribrepr.py below

```

The  contents of the `ribrepr.py` are just to register a command for custom visualization of a given molecule + loop over molecules for image generation.

``` ribrepr.py
import enum
import json
import os
import sys
from chimerax.core.commands import register, CmdDesc
from chimerax.atomic import ResiduesArg, Chains, ChainArg, StructureArg
from chimerax.atomic import Structure, AtomicStructure, Chain
from chimerax.core.commands import run, runscript
from chimerax.core.commands import CmdDesc, register, StringArg

# https://mail.cgl.ucsf.edu/mailman/archives/list/chimera-users@cgl.ucsf.edu/thread/EOUA5K3CZU6DJYVPISR3GFWHCISR6WGV/

# just a data folder, it exists.
RIBETL_DATA = os.environ.get("RIBETL_DATA", "/home/rtviii/dev/RIBETL_DATA")

class PolymerClass(str, enum.Enum):
    tRNA = "tRNA"
    bS1m  = "bS1m"
    # ... another ~200 enum members, redacted for brevity

CHIMERAX_COLORS = [
    ["tan", "#d2b48c"],    ["sienna", "#a0522d"], #... more colors redacted for brevity
]

# helper function to map colors
def get_polymer_color(polymer_class:str):
    polyix      = list(map(lambda x: x.value, (PolymerClass)))
    class_index = polyix.index(polymer_class) % len(polyix)

    if polymer_class == None:
        return "gray"
    return CHIMERAX_COLORS[(class_index % len(CHIMERAX_COLORS))][1]

def ribosome_representation(session, structure: AtomicStructure):
    for _ in list(PolymerClass):
        print(_.name)

    from chimerax.core.commands import run
    from chimerax.core.colors import hex_color
    from chimerax.atomic import Residue, Atom, Chain

    # i get the PDB ID from the StructureArg
    rcsb_id = str(structure.name).upper().split('.')[0] # <-- the structure gets opened with the basename ex "(5AFI.cif)"
    run(session, "set bgColor white")
    run(session, "sym #1 assembly 1") # take only one assembly if multiple are available
    run(session, "hide #2")

    with open(os.path.join(RIBETL_DATA, rcsb_id, "{}.json".format(rcsb_id)), "r") as f:
        profile = json.load(f)  # load my annotations, just a json file
    
    #--------------------------------------------[ This whole bit just colors by chain annotation basically]
    polymers       = {}
    polymer_chains = [
        *profile["proteins"],
        *profile["rnas"],
        *profile["other_polymers"],
    ]
    [ polymers.update(x) for x in [{chain["auth_asym_id"]: chain} for chain in polymer_chains] ]

    c: Chain
    for c in structure.chains:
        aaid      = c.chain_id
        polyclass = None
        if len(polymers[aaid]["nomenclature"]) < 1:
            continue
        else:
            polyclass = polymers[aaid]["nomenclature"][0]
        if polymers[aaid]["entity_poly_polymer_type"] == "RNA":
            run(session, "surf /{}".format(aaid))
            run(session, "transp /{} 100".format(aaid))
            run(session, "color /{} gray".format(aaid))
        else:
            run(session, "show /{} cartoon".format(aaid, get_polymer_color(polyclass)))
            run(session, "color /{} {}".format(aaid, get_polymer_color(polyclass)))
    #--------------------------------------------[ This whole bit just colors by chain annotation basically]
    run(session, "graphics silhouettes true width 1")
    run(session, "light soft")




# # ! Didn't work out for now. This is how i tried to make movies. (Loop over every structure (loop.py above) and call this command). Chimerax segfaults when looped on this.

# def produce_and_save_movie(session, target:str):
#     print("GOT TARGET", target)
#     RCSB_ID = target
#     run(session, "open /home/rtviii/dev/RIBETL_DATA/{}/{}.cif".format(RCSB_ID, RCSB_ID))
#     run(session, "sym #1 assembly 1") # take only one assembly if multiple are available
#     run(session, "ribrep #2")
#     run(session, "movie record")
#     run(session, "turn y 2 180")
#     run(session, "wait 180")
#     run(session, "movie encode /home/rtviii/dev/riboxyz/chimerax/movies/{}.mp4".format(RCSB_ID))
#     run(session, "close all")


# # ! This is just to not download the mmcif files i have locally.
def register_ribetl_command(logger):
    def ribetl(session, rcsb_id:str):
        rcsb_id = rcsb_id.upper()
        run(session, "open /home/rtviii/dev/RIBETL_DATA/{}/{}.cif".format(rcsb_id, rcsb_id))
    desc = CmdDesc( required= [("rcsb_id", StringArg)], )
    register("ribetl", desc, ribetl, logger=logger)

# # ! Register the above repr  sequence as a command.
def register_ribrepr_command(logger):
    from chimerax.core.commands import CmdDesc, register
    from chimerax.atomic import AtomicStructureArg, Chain, Residue, Atom

    desc = CmdDesc(
        required           = [("structure", AtomicStructureArg)],
        required_arguments = ["structure"],
        synopsis           = "representation ",
    )
    register("ribrep", desc, ribosome_representation, logger=logger)


register_ribrepr_command(session.logger)
register_ribetl_command(session.logger)

# This loop expands into a list of ~1800 PDB : 5AFI, 4UG0 and so on.
for rcsb_id in os.listdir(RIBETL_DATA):
    run(session,"open {}".format(rcsb_id))
    run(session,"ribrep #1")
    run(session,"save /home/student/dev/riboxyz/chimerax/{}.png width 800 height 800 transparentBackgroun
d true".format(rcsb_id))
    run(session,"close all")

```

Let me know if i can elucidate this situation further with hardware specs or whatnot. I'm quite at loss as to how to proceed with this.


<crash.log>_______________________________________________
ChimeraX-users mailing list -- chimerax-users@cgl.ucsf.edu
To unsubscribe send an email to chimerax-users-leave@cgl.ucsf.edu
Archives: https://mail.cgl.ucsf.edu/mailman/archives/list/chimerax-users@cgl.ucsf.edu/