0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CryoSparcをCUIで完全自動化してみた

0
Last updated at Posted at 2026-01-10

CryoSparcとは

CryoSparcはクライオ電子顕微鏡(Cryo-EM)において、2d画像に投影された粒子から3d復元を行うツールです。
下図の流れに沿ってGUIベースでボタンをポチポチ押しながら操作します。

スクリーンショット 2026-01-09 16.59.51.png
CryoMAE(supple)より引用↑

今回の目的

高速で実験を回すために、CUIコマンドを叩くことにより自動で処理を行い、最終的な3d resolutionまで出力します。

手順

セットアップ

まず下記リンクから使用許可を申請します。

次に下記に従ってインストールします。

自動化スクリプト

cryosparc_masterをダウンロードしたパスに移動して、下記のpythonファイルを作成してください。
このコードは、mrcファイルとstarファイルの入力に対して、3d resolutionの計算まで自動で行い、csvファイルに結果を出力するものです。

run_all_pipeline.py

import sys
import argparse
import csv
import os
import time
import glob
import numpy as np
import subprocess
import shutil
import re
from cryosparc.tools import CryoSPARC

# ==========================================
# EMPIAR SIZE DICTIONARY (Height, Width)
# ==========================================
empiar_sizes = {
    "10389": (3838, 3710),
    "10081": (3710, 3838),
    "10289": (3710, 3838),
    "11057": (5760, 4092),
    "10444": (5760, 4092),
    "10576": (7420, 7676),
    "10816": (7676, 7420),
    "10526": (7676, 7420),
    "11051": (3838, 3710),
    "10760": (3838, 3710),
    "11183": (5760, 4092),
    "10671": (5760, 4092),
    "10291": (3710, 3838),
    "10669": (7676, 7420),
    "10077": (4096, 4096),
    "10061": (7676, 7420),
    "10028": (4096, 4096),
    "10096": (3838, 3710),
    "10737": (5760, 4092),
    "10387": (3710, 3838),
    "10532": (4096, 4096),
    "10240": (3838, 3710),
    "10005": (3710, 3710),
    "10017": (4096, 4096),
    "10075": (4096, 4096),
    "10184": (3838, 3710),
    "10059": (3838, 3710),
    "10406": (3838, 3710),
    "10590": (3710, 3838),
    "10093": (3838, 3710),
    "10345": (3838, 3710),
    "11056": (5760, 4092),
    "10852": (5760, 4092),
    "10947": (4096, 4096)
}

# ==========================================
# Helper Functions
# ==========================================
def preprocess_star_file(star_file_path, original_star_resolution):
    """
    STARファイルを読み込み、座標変換 (Swap/Flip) とスケーリングを行い、
    新しいSTARファイルとして保存する。
    """
    print(f"Preprocessing STAR file: {star_file_path}")

    # 1. EMPIAR ID取得 (パスから5桁の数字を検索)
    match = re.search(r'(\d{5})', star_file_path)
    if not match:
        # パスに見つからない場合、ファイル名でトライ
        match = re.search(r'(\d{5})', os.path.basename(star_file_path))

    if match:
        empiar_id = match.group(1)
        print(f"  Detected EMPIAR ID: {empiar_id}")
    else:
        raise ValueError(f"Could not extract EMPIAR ID (5 digits) from path: {star_file_path}")

    # 2. サイズ取得
    original_dims = empiar_sizes.get(empiar_id)
    if not original_dims:
        raise ValueError(f"Unknown EMPIAR ID in dictionary: {empiar_id}")

    orig_w, orig_h = original_dims
    print(f"  Target Original Size (W, H): ({orig_w}, {orig_h})")
    print(f"  Input Star Resolution: {original_star_resolution}")

    # 3. STARファイル読み込み & 解析
    with open(star_file_path, 'r') as f:
        lines = f.readlines()

    # ヘッダー情報の解析
    x_col_idx = -1
    y_col_idx = -1
    header_end_idx = 0
    in_loop = False

    # RELION STAR形式のカラム特定 (_rlnCoordinateX #1 等)
    for i, line in enumerate(lines):
        stripped = line.strip()
        if stripped.startswith("loop_"):
            in_loop = True
            continue

        if in_loop and stripped.startswith("_rlnCoordinateX"):
            # カラム番号を取得 (#1 -> index 0)
            parts = stripped.split()
            if len(parts) >= 2 and parts[1].startswith("#"):
                x_col_idx = int(parts[1].replace("#", "")) - 1
            else:
                pass

        if in_loop and stripped.startswith("_rlnCoordinateY"):
            parts = stripped.split()
            if len(parts) >= 2 and parts[1].startswith("#"):
                y_col_idx = int(parts[1].replace("#", "")) - 1

        # データ行の開始判定 (数値で始まる行)
        if in_loop and len(stripped) > 0 and stripped[0].isdigit() or (stripped.startswith("-") and len(stripped)>1 and stripped[1].isdigit()):
            header_end_idx = i
            break

    if x_col_idx == -1 or y_col_idx == -1:
        # カラム名が見つからなかった場合、単純な行カウンタでの推定等のフォールバックが必要だが、一旦エラーに
        raise ValueError("Could not find _rlnCoordinateX/Y headers in STAR file.")

    # 4. データ変換処理
    processed_lines = lines[:header_end_idx] # ヘッダー部分はそのままコピー
    data_lines = lines[header_end_idx:]

    converted_count = 0

    # スケール係数の計算
    scale_x = orig_w / original_star_resolution
    scale_y = orig_h / original_star_resolution

    for line in data_lines:
        parts = line.split()
        if len(parts) <= max(x_col_idx, y_col_idx):
            continue # 空行などをスキップ

        try:
            x_old = float(parts[x_col_idx])
            y_old = float(parts[y_col_idx])

            # =========================
            # MRCがJPGと上下逆のため、Y反転は不要
            # =========================
            # y_flipped = original_star_resolution - y_old

            x_final = x_old * scale_x
            y_final = y_old * scale_y

            parts[x_col_idx] = f"{x_final:.6f}"
            parts[y_col_idx] = f"{y_final:.6f}"

            # 行を再構成 (スペース区切りで結合)
            new_line = "  ".join(parts) + "\n"
            processed_lines.append(new_line)
            converted_count += 1

        except ValueError:
            # 数値変換エラー時は行をそのまま出力(またはスキップ)
            processed_lines.append(line)

    # 5. 保存
    base, ext = os.path.splitext(star_file_path)
    new_star_path = f"{base}_preprocessed{ext}"

    with open(new_star_path, 'w') as f:
        f.writelines(processed_lines)

    print(f"  Saved to: {new_star_path}")

    return new_star_path


def get_resolution_from_meta(job):
    try:
        progress = job.doc.get('progress', [])
        if progress and len(progress) > 0:
            last_iter = progress[-1]
            if 'gsfsc' in last_iter:
                return float(last_iter['gsfsc'])

        results_list = job.doc.get('output_result_groups', [])
        for group in results_list:
            meta = group.get('summary', {})
            if not meta: meta = group.get('meta', {})
            if 'res_gsfsc_tight' in meta: return float(meta['res_gsfsc_tight'])
            if 'res_gsfsc_0143' in meta: return float(meta['res_gsfsc_0143'])

        print("Warning: Resolution key not found in progress log or meta.")
        return 0.0
    except Exception as e:
        print(f"Could not fetch resolution: {e}")
        return 0.0

def save_resolution_to_csv(job_uid, resolution, star_file_path, filename="resolutions.csv"):
    try:
        file_exists = os.path.isfile(filename)
        with open(filename, mode='a', newline='') as f:
            writer = csv.writer(f)
            if not file_exists:
                writer.writerow(["Job_UID", "Resolution_Angstrom", "Star_File", "Timestamp"])
            import datetime
            now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            writer.writerow([job_uid, f"{resolution:.2f}", star_file_path, now])
        print(f"Saved resolution to {filename}")
    except Exception as e:
        print(f"Failed to save CSV: {e}")

def find_latest_completed_job(project, workspace_id, job_type, title_filter=None):
    jobs = project.find_jobs()
    candidates = []
    for job in jobs:
        if job.workspace_uid != workspace_id:
            continue
        if job.doc.get('job_type') != job_type:
            continue
        if job.status != 'completed':
            continue
        if title_filter and title_filter not in job.doc.get('title', ''):
            continue
        candidates.append(job)

    if not candidates:
        return None
    candidates.sort(key=lambda j: int(j.uid[1:]))
    return candidates[-1]

def create_project_via_cli(user_id, title):
    cryosparcm_cmd = shutil.which("cryosparcm")
    if not cryosparcm_cmd:
        if os.path.exists("./cryosparcm"):
            cryosparcm_cmd = "./cryosparcm"
        else:
            possible_path = "/mnt/ssd1/riku/cryosparc_master/cryosparcm"
            if os.path.exists(possible_path):
                cryosparcm_cmd = possible_path
            else:
                raise Exception("Could not find 'cryosparcm' command. Please check PATH.")

    print(f"Creating project '{title}' via CLI ({cryosparcm_cmd})...")
    safe_title = title.replace("'", "")
    cli_arg = f"create_project('{user_id}', '{safe_title}')"
    cmd = [cryosparcm_cmd, "cli", cli_arg]

    res = subprocess.run(cmd, capture_output=True, text=True)
    if res.returncode != 0:
        raise Exception(f"CLI create_project failed: {res.stderr}")

    new_pid = res.stdout.strip().replace("'", "").replace('"', "")
    return new_pid

def rename_star_file(input_path):
    base, ext = os.path.splitext(input_path)
    output_path = f"{base}_renamed{ext}"

    print(f"Checking/ Renaming STAR file: {input_path}")

    with open(input_path, 'r') as f:
        content = f.read()

    if "_pred.mrc" in content:
        print("  [Fix] Found '_pred.mrc'. Replacing with '.mrc'...")
        new_content = content.replace("_pred.mrc", ".mrc")

        with open(output_path, 'w') as f:
            f.write(new_content)
        return output_path
    else:
        return input_path

# ==========================================
# Main Workflow
# ==========================================

def run_full_pipeline(
    project_id,
    workspace_id,
    micrographs_path,
    star_file_path,
    box_size,
    min_class_size,
    email,
    password,
    license_id,
    host="localhost",
    port=39000,
    psize_A=1.3,
    accel_kv=300,
    cs_mm=2.7,
    total_dose_e_per_A2=50.0,
    gpu_ids=None,
    worker_hostname=None,
    resume=False,
    project_title=None,
    output_csv_file_name="resolutions.csv"
):
    # ==========================================
    # 0. Pre-check & Fixes
    # ==========================================

    if "_pred.mrc" in micrographs_path:
        print(f"Notice: Replacing '_pred.mrc' with '.mrc' in micrographs wildcard path.")
        micrographs_path = micrographs_path.replace("_pred.mrc", ".mrc")

    if not os.path.isfile(star_file_path):
        print(f"\n[ERROR] Star file not found at: {star_file_path}")
        sys.exit(1)

    # 3. Star file content fix (Creating a renamed version)
    fixed_star_path = rename_star_file(star_file_path)

    # GPU設定
    gpu_kwargs = {"lane": "default"}
    if gpu_ids is not None and len(gpu_ids) > 0 and worker_hostname is not None:
        gpu_kwargs["gpus"] = gpu_ids
        gpu_kwargs["hostname"] = worker_hostname
        print(f"--> GPUs: {gpu_ids} on {worker_hostname}")

    # --- 接続 ---
    cs = CryoSPARC(license=license_id, email=email, password=password, host=host, base_port=port)
    if not cs.test_connection():
        print("Error: Connection failed.")
        sys.exit(1)

    try:
        user_id = cs.cli.get_user_id(email)
        print(f"User ID: {user_id}")
    except Exception as e:
        print(f"Error getting user_id for {email}: {e}")
        sys.exit(1)

    # ==========================================
    # Project & Workspace: Get or Create
    # ==========================================

    project_doc = None
    try:
        project_doc = cs.cli.get_project(project_id)
    except Exception:
        pass

    if project_doc:
        print(f"Found existing project: {project_id}")
        project = cs.find_project(project_id)
    else:
        raise Exception(f"Project {project_id} not found.")

    workspace_doc = None
    try:
        workspace_doc = cs.cli.get_workspace(project_id, workspace_id)
    except Exception:
        pass

    if workspace_doc:
        print(f"Found existing workspace: {workspace_id}")
        workspace = project.find_workspace(workspace_id)
    else:
        raise Exception(f"Workspace {workspace_id} not found in {project_id}.")

    print(f"=== Pipeline Start in {project_id} - {workspace_id} (Resume: {resume}) ===")

    # ---------------------------------------------------------
    # Phase 1: Import & Extract
    # ---------------------------------------------------------

    # 1. Import Micrographs
    print("\n[1/8] Checking Import Micrographs...")
    job_mic = None
    if resume:
        job_mic = find_latest_completed_job(project, workspace_id, "import_micrographs")

    if job_mic:
        print(f"  [Resume] Found completed job {job_mic.uid}. Skipping.")
    else:
        mic_params = {
            "blob_paths": micrographs_path,
            "psize_A": psize_A, "accel_kv": accel_kv, "cs_mm": cs_mm, "total_dose_e_per_A2": total_dose_e_per_A2
        }
        job_mic = project.create_job(workspace_id, "import_micrographs", params=mic_params)
        job_mic.queue()
        job_mic.wait_for_done()
        if job_mic.status != "completed": sys.exit(f"Job {job_mic.uid} failed.")

    # 2. Patch CTF Estimation
    print("\n[2/8] Checking Patch CTF Estimation...")
    job_ctf = None
    if resume:
        job_ctf = find_latest_completed_job(project, workspace_id, "patch_ctf_estimation_multi")

    if job_ctf:
         print(f"  [Resume] Found completed job {job_ctf.uid}. Skipping.")
    else:
        job_ctf = project.create_job(workspace_id, "patch_ctf_estimation_multi")
        job_ctf.connect("exposures", job_mic.uid, "imported_micrographs")
        job_ctf.queue(**gpu_kwargs)
        job_ctf.wait_for_done()
        if job_ctf.status != "completed": sys.exit(f"Job {job_ctf.uid} failed.")

    # 3. Import Particles
    print("\n[3/8] Checking Import Particles...")
    job_part = None
    if resume:
        job_part = find_latest_completed_job(project, workspace_id, "import_particles")

    if job_part:
        print(f"  [Resume] Found completed job {job_part.uid}. Skipping.")
    else:
        # 修正: ここで fixed_star_path を使う
        particle_params = {
            "particle_meta_path": fixed_star_path,
            "ignore_pose": True, "ignore_blob": True, "remove_leading_uid": True
        }
        job_part = project.create_job(workspace_id, "import_particles", params=particle_params)
        job_part.connect("micrographs", job_mic.uid, "imported_micrographs")
        job_part.queue(lane="default")
        job_part.wait_for_done()
        if job_part.status != "completed": sys.exit(f"Job {job_part.uid} failed.")

    # 4. Extract Particles
    print("\n[4/8] Checking Extraction...")
    job_extract = None
    if resume:
        job_extract = find_latest_completed_job(project, workspace_id, "extract_micrographs_multi")

    if job_extract:
        print(f"  [Resume] Found completed job {job_extract.uid}. Skipping.")
    else:
        extract_params = {"box_size_pix": box_size}
        job_extract = project.create_job(workspace_id, "extract_micrographs_multi", params=extract_params)
        job_extract.connect("particles", job_part.uid, "imported_particles")
        job_extract.connect("micrographs", job_ctf.uid, "exposures")
        job_extract.queue(**gpu_kwargs)
        job_extract.wait_for_done()
        if job_extract.status != "completed": sys.exit(f"Job {job_extract.uid} failed.")

    # ---------------------------------------------------------
    # Phase 2: Processing (2D -> Abinit -> Refine)
    # ---------------------------------------------------------

    # 5. 2D Classification
    print("\n[5/8] Checking 2D Classification...")
    job_2d = None
    if resume:
        job_2d = find_latest_completed_job(project, workspace_id, "class_2D")

    if job_2d:
        print(f"  [Resume] Found completed job {job_2d.uid}. Skipping.")
    else:
        job_2d = project.create_job(workspace_id, "class_2D")
        job_2d.connect("particles", job_extract.uid, "particles")
        job_2d.set_param("class2D_K", 50)
        job_2d.set_param("class2D_num_full_iter", 20)
        job_2d.queue(**gpu_kwargs)
        job_2d.wait_for_done()
        if job_2d.status != "completed": sys.exit(f"Job {job_2d.uid} failed.")

    # 6. Filter Particles
    # 6. Filter Particles
    print(f"\n[6/8] Checking Filter Particles (Min Size {min_class_size})...")
    job_filter = None
    filter_title = f"Auto Filter (Min Size {min_class_size})"
    if resume:
        job_filter = find_latest_completed_job(project, workspace_id, "import_particles", title_filter=filter_title)

    if job_filter:
        print(f"  [Resume] Found completed job {job_filter.uid}. Skipping.")
    else:
        print("  Running Filtering Logic...")
        particles_2d = job_2d.load_output("particles")
        class_ids = particles_2d["alignments2D/class"]
        unique_ids, counts = np.unique(class_ids, return_counts=True)

        # Filter logic: Keep classes with count > min_class_size
        keep_mask = counts > min_class_size
        keep_ids = unique_ids[keep_mask]
        drop_ids = unique_ids[~keep_mask]

        print(f"  Dropping {len(drop_ids)} classes (Count <= {min_class_size}).")

        if len(keep_ids) == 0:
            sys.exit("Error: All classes dropped. Threshold too high?")

        final_particles = particles_2d.query({"alignments2D/class": keep_ids})

        job_filter = project.create_external_job(workspace_id, title=filter_title)
        job_filter.add_output(type="particle", name="particles", slots=["blob", "ctf", "alignments2D"], alloc=final_particles)
        job_filter.save_output("particles", final_particles)
        job_filter.stop()

    # 7. Ab-Initio
    print("\n[7/8] Checking Ab-Initio Reconstruction...")
    job_abinit = None
    if resume:
        job_abinit = find_latest_completed_job(project, workspace_id, "homo_abinit")

    if job_abinit:
        print(f"  [Resume] Found completed job {job_abinit.uid}. Skipping.")
    else:
        job_abinit = project.create_job(workspace_id, "homo_abinit")
        job_abinit.connect("particles", job_filter.uid, "particles")
        job_abinit.set_param("abinit_K", 1)
        job_abinit.queue(**gpu_kwargs)
        job_abinit.wait_for_done()
        if job_abinit.status != "completed": sys.exit(f"Job {job_abinit.uid} failed.")

    # 8. Homogeneous Refinement
    print("\n[8/8] Checking Homogeneous Refinement...")
    job_refine = None
    if resume:
        job_refine = find_latest_completed_job(project, workspace_id, "homo_refine")

    if job_refine:
        print(f"  [Resume] Found completed job {job_refine.uid}. Skipping.")
    else:
        job_refine = project.create_job(workspace_id, "homo_refine")
        job_refine.connect("particles", job_abinit.uid, "particles_all_classes")
        job_refine.connect("volume", job_abinit.uid, "volume_class_0")
        job_refine.queue(**gpu_kwargs)
        job_refine.wait_for_done()
        if job_refine.status != "completed": sys.exit(f"Job {job_refine.uid} failed.")

    # Result
    res = get_resolution_from_meta(job_refine)
    save_resolution_to_csv(job_refine.uid, res, star_file_path, output_csv_file_name)
    print(f"Pipeline Completed! Est Res: {res:.2f} A")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Full CryoSPARC Pipeline: Import -> Extract -> Refine")

    parser.add_argument("--project", "-p", required=True, help="Project ID (e.g. P1)")
    parser.add_argument("--workspace", "-w", required=True, help="Workspace ID (e.g. W1)")
    parser.add_argument("--micrographs", "-m", required=True, help="Micrographs path wildcard")
    parser.add_argument("--star", "-s", required=True, help="Particle star file path")
    parser.add_argument("--project_title", help="Title for the new project if created", default=None)
    parser.add_argument("--resume", "-r", action="store_true", help="Resume from the latest completed jobs in the workspace")
    parser.add_argument("--email", required=True)
    parser.add_argument("--password", required=True)
    parser.add_argument("--license", required=True)
    parser.add_argument("--host", default="localhost")
    parser.add_argument("--port", type=int, default=39000)
    parser.add_argument("--box_size", "-b", type=int, default=256)
    parser.add_argument("--min_class_size", type=int, default=50, help="Minimum particle count to keep a class")
    parser.add_argument("--psize_A", type=float, default=1.3)
    parser.add_argument("--accel_kv", type=float, default=300)
    parser.add_argument("--cs_mm", type=float, default=2.7)
    parser.add_argument("--total_dose_e_per_A2", type=float, default=50.0)
    parser.add_argument("--gpus", default=None, help="Comma-separated GPU IDs (e.g. '0,1')")
    parser.add_argument("--worker", default="dlboxiv", help="Worker hostname")

    # resize GT
    parser.add_argument("--preprocess_star", action='store_true', help="Enable STAR file preprocessing")
    parser.add_argument("--original_star_resolution", type=int, default=1024, help="Original star file resolution for flipping/scaling")

    # output csv
    parser.add_argument("--output_csv_file_name", type=str, default="resolutions.csv", help="Output CSV file name")

    args = parser.parse_args()

    # ==========================================
    # Pre-process: Preprocess STAR File
    # ==========================================
    final_star_path = args.star

    if args.preprocess_star:
        print("\n=== Pre-process: Preprocessing STAR File ===")
        if not args.original_star_resolution:
            print("[Error] --original_star_resolution is required when --preprocess_star is used.")
            sys.exit(1)

        try:
            final_star_path = preprocess_star_file(args.star, args.original_star_resolution)
            print(f"--> Pipeline will use preprocessed STAR: {final_star_path}")
        except Exception as e:
            print(f"[Error] STAR preprocessing failed: {e}")
            sys.exit(1)

    # Parse GPU list
    gpu_list = None
    if args.gpus:
        try:
            gpu_list = [int(g.strip()) for g in args.gpus.split(",")]
        except ValueError:
            sys.exit("Error: Invalid format for --gpus.")

    # Run Pipeline
    run_full_pipeline(
        project_id=args.project,
        workspace_id=args.workspace,
        micrographs_path=args.micrographs, # 元のmicrographsパスを使用(リサイズしない)
        star_file_path=final_star_path,    # 変換後のSTARファイルを使用
        box_size=args.box_size,
        min_class_size=args.min_class_size,
        email=args.email,
        password=args.password,
        license_id=args.license,
        host=args.host,
        port=args.port,
        psize_A=args.psize_A,
        accel_kv=args.accel_kv,
        cs_mm=args.cs_mm,
        total_dose_e_per_A2=args.total_dose_e_per_A2,
        gpu_ids=gpu_list,
        worker_hostname=args.worker,
        resume=args.resume,
        project_title=args.project_title,
        output_csv_file_name=args.output_csv_file_name
    )

実行手順

cryosparcを起動

cryosparcm restart

GUIでprojectを作る(初回のみ)

右上のNew Projectボタンから作成する。
以降のステップで"P1"など、ここで作成したプロジェクトをコマンド入力する。
スクリーンショット 2026-01-09 22.17.09.png

必要なデータを準備

cryopppのmrcファイルとstarファイル
https://github.com/BioinfoMachineLearning/cryoppp

粒子ごとの物理パラメータ(CryoPPP paperのsupple table1)
https://pmc.ncbi.nlm.nih.gov/articles/instance/9980126/bin/media-1.xlsx

# 10081のパラメータ例
PSIZE_A=1.3
ACCEL_KV=300
CS_MM=2.7
TOTAL_DOSE_E_PER_A2=50.0

bashファイルを作成して実行

#!/bin/bash

# ========================================================
# CryoSPARC Full Pipeline Runner
# ========================================================

# プロジェクト設定
PROJECT_ID="P1"
WORKSPACE_ID="W1"

# 入力データ設定
MICROGRAPHS_PATH="path/to/*.mrc"
STAR_FILE_PATH="path/to/particle_coordinate.star"

# パラメータ
BOX_SIZE=256
MIN_CLASS_SIZE=20  # 2d classificationで20個以下のクラスは除外
ORIGINAL_STAR_RESOLUTION=1024  # 保存したstarファイルの画像サイズ

# GPU設定 (例: "0,1" や "2")
GPUS="1,2"
WORKER_HOST="dlboxiv"

# 認証情報
EMAIL="aaaa"
PASSWORD="bbbb"
LICENSE="cccc"

# 10081用
PSIZE_A=1.3
ACCEL_KV=300
CS_MM=2.7
TOTAL_DOSE_E_PER_A2=50.0

# # 10093用
# PSIZE_A=1.2156
# ACCEL_KV=300
# CS_MM=2.7
# TOTAL_DOSE_E_PER_A2=54

# # 10345用
# PSIZE_A=1.345
# ACCEL_KV=300
# CS_MM=2.7
# TOTAL_DOSE_E_PER_A2=70

# # 10532用
# PSIZE_A=1.03
# ACCEL_KV=300
# CS_MM=2.7
# TOTAL_DOSE_E_PER_A2=40

# ========================================================
# 実行コマンド
# ========================================================

# --resumeでlatest jobから再開できる
python CUI_AUTOMATION/run_all_pipeline.py \
  --project "$PROJECT_ID" \
  --workspace "$WORKSPACE_ID" \
  --micrographs "$MICROGRAPHS_PATH" \
  --star "$STAR_FILE_PATH" \
  --box_size $BOX_SIZE \
  --min_class_size $MIN_CLASS_SIZE \
  --gpus "$GPUS" \
  --worker "$WORKER_HOST" \
  --email "$EMAIL" \
  --password "$PASSWORD" \
  --license "$LICENSE" \
  --psize_A "$PSIZE_A" \
  --accel_kv "$ACCEL_KV" \
  --cs_mm "$CS_MM" \
  --total_dose_e_per_A2 "$TOTAL_DOSE_E_PER_A2" \
  --preprocess_star \
  --original_star_resolution "$ORIGINAL_STAR_RESOLUTION" \
  --output_csv_file_name "resolutions_anomaly_${EMPIAR_ID}.csv"

実行結果

実行の様子

=== Pipeline Start in P1 - W1 (Resume: False) ===

[1/8] Checking Import Micrographs...
  Creating new job...
  Waiting for Job J147...

[2/8] Checking Patch CTF Estimation...
  Creating new job...
  Waiting for Job J148...

[3/8] Checking Import Particles...
  Creating new job...
  Waiting for Job J149...

[4/8] Checking Extraction...
  Creating new job...
  Waiting for Job J150...

[5/8] Checking 2D Classification...
  Creating new job...
  Waiting for Job J151...

[6/8] Checking Filter Particles (Drop 3)...
  Running Filtering Logic...
  Dropping 3 classes. Counts: [np.int64(1), np.int64(1), np.int64(3)]
  Particles retained: 9143 / 9148
  Filter Job J152 created.

[7/8] Checking Ab-Initio Reconstruction...
  Creating new job...
  Waiting for Job J153...

[8/8] Checking Homogeneous Refinement...
  Creating new job...
  Waiting for Job J154...
Saved resolution to resolutions.csv
Pipeline Completed! Est Res: 8.86 A

csvファイルにログ(resolution, star_file pathなど)が保存される
resolutions.csv

Job_UID,Resolution_Angstrom,Star_File,Timestamp
J101,8.70,~/10081.star,2026-01-09 19:27:28

TIPS

  • mrcファイルの座標系とstarファイルの粒子の座標系が異なる場合があります。必ずGUIを確認し、粒子が正しく切り出されていることを確認すると良いです。
  • わからないことがあればCryosparcのドキュメントをgeminiに渡して聞くのが手っ取り早いです。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?