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

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"など、ここで作成したプロジェクトをコマンド入力する。

必要なデータを準備
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に渡して聞くのが手っ取り早いです。