adaptive.cr
adaptive-cr 0.3.0
MinKNOWのRead Untilを使う、Crystal製のプログラム可能なadaptive samplingツールです。Dorado Basecall Serverで累積信号をbasecallし、minimap2で並列マッピングし、Crystalの任意の判定コードで Continue / Accept / Reject を返します。BEDは不要です。プロジェクト名は暫定名です。Moleflow本体とは独立しています。
通信・信号管理・並列実行・マッピング・判定・操作・監査ログはCrystalです。Doradoとの接続は、公式Pythonクライアントを使う常駐アダプターを正式な方式として採用します。ワーカーごとに一度起動し、ADC信号をバイナリで渡します。DoradoのCLI dorado basecaller とは別製品の Dorado Basecall Server を利用します。
Linux x86_64 / Crystal 1.22.0でビルド・テスト済み。公式クライアント7.13.6の入力構築を検証し、Moleflowと本物のgRPC・minimap2による結合試験を実施しました。GPU付きDorado実サーバーと実機MinKNOWによる検証は未実施です。 付属テストのbasecallerは固定配列を返す明示的なfixtureであり、精度やGPU処理能力の証明には使えません。
ビルド
Crystal 1.22.0以上、Python 3.11以上(検証は3.12)と、Cコンパイラ・make・pkg-config・libnghttp2・OpenSSL・zlib・libyamlの開発パッケージ、POD5用のC++20コンパイラ・curl・tar・unzip・patchを用意します。Debian/Ubuntuでの依存ライブラリ導入とmiseを使った環境構築の例:
sudo apt-get install build-essential pkg-config libnghttp2-dev libssl-dev zlib1g-dev libyaml-dev curl unzip patch
mise install
mise exec -- shards install
mise exec -- python -m venv .venv
. .venv/bin/activate
python3 -m pip install -r requirements.txt
mise exec -- scripts/build.sh
mise exec -- scripts/test.sh
依存ライブラリはShardsで外部から取得します。shard.lockは検証したコミットを固定し、最新版に更新する場合は mise exec -- shards update を実行します。minimap2はShardsのインストール時にネイティブソースを取得・ビルドします。POD5ネイティブライブラリは scripts/build.sh が未導入時に取得・構築します。初回のセットアップにはネット接続が必要です。Pythonパッケージ・Doradoサーバー・GPUドライバは同梱していません。
まずオフラインで動かす
プロジェクトのルートで実行します。設定内の相対パスも現在の作業ディレクトリ基準です。
bin/adaptive --validate
bin/adaptive --replay=examples/replay.jsonl
例の参照は独立に生成した人工配列 host と virus です。結果は Reject, Accept, Reject。最後のRejectはvirusの採用数上限1に達したためです。実際の研究用参照ではありません。
POD5から実信号の診断入力を作る(0.3.0)
sh scripts/pod5.sh real.pod5 diagnostic --samples=20000
bin/adaptive -c run.json --check-signal=diagnostic/prefix.i16 --signal-metadata=diagnostic/prefix.json
--read-id=UUID で対象を指定できます。省略時は100 samples以上の最初のreadです。 指定したprefix長と実際の長さの小さい方を出力します。ADCを再校正せず、元のoffset、 scale、sample rate、start sampleを保持します。read.jsonにはUUID・channel・長さを 記録します。既存ディレクトリは上書きせず、失敗時は新規作成した出力を削除します。
この抽出はpod5.crを使うCrystal処理です。Doradoとの接続には引き続きPythonが必要です。 --replay は従来通り配列JSONLによるpolicy再生であり、POD5のライブ再生ではありません。 Moleflowで信号を配信する場合は、Moleflowの scripts/pod5.sh prepare を使ってください。
現在のpod5.cr APIではprefix抽出にも1 read全体の展開が必要です。このツールは展開前に 1,000万samplesを超えるreadを拒否します(ADC配列だけで最大約20 MB、RSS上限ではありません)。 出力prefixは100〜250,000 samplesです。巨大readの部分展開には未対応です。
DoradoとMinKNOWにつなぐ
- ONTのDorado Basecall Serverを導入し、付属READMEに従ってサーバーと対象化学条件のモデルを起動します。接続先、モデル設定名、クライアントとの互換性は実際のサーバー環境に合わせてください。
- 下の例を
run.jsonに保存し、参照、MinKNOWの position serviceのポート、CA証明書、モデル設定名を実環境に変更します。Managerの9501をそのままpositionポートとして使わないでください。 - サーバー接続と実信号basecallの確認、観測モードを経て、排出を行う際に
observeをfalseにします。詳しい導入・検証・停止・障害対応は 運用手順 にあります。
{
"host": "127.0.0.1",
"port": 10001,
"tls": true,
"ca_file": "/data/rpc-certs/minknow/ca.crt",
"first_channel": 1,
"last_channel": 512,
"reference": "/absolute/path/reference.mmi",
"dorado_address": "ipc:///tmp/.guppy/5555",
"dorado_model": "dna_r10.4.1_e8.2_400bps_5khz_fast",
"python": ".venv/bin/python",
"workers": 4,
"policy": "contig",
"targets": ["target_contig"],
"quota": 0,
"observe": true,
"log": "run-001.jsonl"
}
bin/adaptive -c run.json --validate
bin/adaptive -c run.json --check-backend
bin/adaptive -c run.json
--check-backendは公式クライアントの接続までを確認し、Python・NumPy・クライアントの実バージョンをJSONで返します。信号のbasecallや実機制御までを検証するコマンドではありません。実信号を使う --check-signal は下記を参照してください。ライブ入力はraw int16 ADCです。チャンネル別offset・range/digitisation・sample rateをMinKNOWから取得し、公式クライアントへ渡します。
bin/adaptive -c run.json --check-signal=/data/prefix.i16 --signal-metadata=/data/prefix.json
prefix.i16 は実測信号のlittle-endian int16 ADC列(100〜250000 samples)、prefix.json はその信号の offset, scale, sample_rate, start_sample を持つJSONです。scale = range / digitisation。実際の値を使用してください。このコマンドはMinKNOWへ接続せず、Doradoから得た配列をJSONへ出力します。空配列しか返らなければ診断失敗です。
PythonクライアントのバージョンはDorado Basecall Serverと完全一致させます。付属の requirements.txt は7.13.6向けです。モデル名もflow cell・kit・sample rateに適合するものを選び、例の5 kHz設定を無条件に流用しないでください。
認証が必要な環境では MINKNOW_AUTH_TOKEN または PROTOCOL_TOKEN を環境変数に設定します。クライアント証明書を使う場合は MINKNOW_API_CLIENT_CERTIFICATE_CHAIN / MINKNOW_API_CLIENT_KEY にパスを設定します。ログや設定例にトークンを記録しません。ローカルトークンの自動探索は無効です。実機の認証方式と接続権限は環境ごとに確認が必要です。
ログは既存ファイルを上書きしません。実行ごとに新しいパスを指定してください。SIGINT/SIGTERMで停止できます。
任意の判定を書く
Adaptive::Policyを継承し、以下のメソッドを実装します。
class MyPolicy < Adaptive::Policy
def decide(read : Adaptive::Evidence,
experiment : Adaptive::Experiment,
memory : Hash(String, String)) : Adaptive::Decision
# read.sequences: Doradoのsplitを維持した配列一覧
# read.hits: split番号とminimap2の座標・strand・MAPQ・CIGARなど
# read.samples / channel / read_id
# experiment.confirmed / reserved: グループ別採用操作数
# memory: このリード世代だけの状態
Adaptive::Decision.new(Adaptive::Choice::Continue, "more_signal_needed")
end
end
examples/custom.crが独自実行ファイルの入口、examples/junction_policy.crが接合候補を採用する実装例です。
crystal build examples/custom.cr --release -o bin/adaptive-junction
bin/adaptive-junction -c run.json --replay=examples/replay.jsonl
この例は同じsplit内でhost/virusへのMAPQ・アラインメント長・クエリ座標の隣接を調べ、接合候補を100本まで採用します。構造変異の確定判定器ではありません。向き、反復配列、既知ブレークポイントなどは目的に応じて判定へ追加します。独自バイナリでは policy を custom にするとログでも区別できます。通常バイナリに custom を指定すると起動エラーになります。
判定は一つのcoordinator上で実行し、採用枠の予約と一体化しています。共有状態の競合を避けるため、ここでは重い計算やネットワーク待機を行わないでください。重い特徴量抽出は src/adaptive/pool.cr の並列ワーカー側へ追加し、Evidenceを拡張します。任意コードは信頼されたコンパイル時プラグインであり、サンドボックス化や実行時間の強制制限はありません。
標準判定と設定
| 設定 | 既定値 / 動作 |
|---|---|
policy |
contig。他に motif, all。customは独自バイナリ専用 |
targets |
contig名の配列。いずれかへのMAPQ閾値以上のhitで採用 |
mapq / min_bases |
20 / 300。短配列・contig判定で高信頼hitがない場合はContinue |
motif |
A/C/G/T文字列。順方向・逆相補鎖を検索。split間は連結しない |
quota |
0は無制限。正数は対象contigまたはmotifグループ別の採用操作数上限 |
background_fraction / seed |
0.0 / 42。非対象を再現可能なread-IDハッシュで一部採用 |
min_samples / step_samples / max_samples |
2500 / 2000 / 20000。累積prefixを再basecallする |
deadline_ms |
2000。アプリが最初のchunkを受信してからの判定期限 |
bridge_timeout_ms |
3000。bridgeのI/O待機上限とサーバー結果待機の設定 |
bridge_startup_timeout_ms |
60000。Python起動・接続・モデル初回読み込みの待機上限。リードの判定期限とは別 |
ack_timeout_ms |
3000。操作応答待ち上限。超過で実行を停止し、操作を再送しない |
max_buffer_bytes |
268435456。保存prefixと実行待ち/実行中signalコピーの合計量制限 |
workers |
4。Crystalのparallel execution contextのスレッド数。各ワーカーに常駐Pythonクライアント1個 |
observe |
true。判定を記録するが、MinKNOWへ採用/排出操作を送らない |
motif判定は「現在までに読めたprefix内にmotifがあるか」を判定します。閾値以上のprefixで不在ならRejectになるため、分子後半のmotifを保証して探索する戦略ではありません。目的に応じてContinue条件を変更してください。
Acceptは stop_further_data で当該リードの信号配信を止め、分子の測定は続けます。Rejectは0.1秒の unblock。Continueは次の信号を待ちます。quotaのconfirmedは 操作成功の確認数 であり、完全長リード取得数やcoverageではありません。観測モードとreplayでは仮想的に採用数を増やします。
障害時と実装上の範囲
- 信号欠落・重複、容量不足、判定期限、basecaller障害、判断不能のサンプル上限では分子を残します。期限超過結果や前のリード世代の結果から排出しません。
- 複数チャネルが同時にquotaを満たしても、操作送信前に枠を予約します。失敗応答では枠を戻し、応答不明の操作は成功扱いしません。終了時に未確認操作数も記録します。
- 接続切断・不正な信号形式・監査ログ障害・操作応答タイムアウトでは実行を停止します。再接続後に古い状態を持ち越す自動復帰は実装していません。
- 正常停止・異常終了とも
endイベントへ終了理由と未確認操作を記録します。ログ自体の障害では記録できない場合があり、stderrと終了コードも確認します。終了時は待機jobを破棄し、実行中処理を回収します。PythonはEOFで切断し、250 msで終了しなければ強制終了します。 - minimap2は
map-ont、CIGARあり。参照indexを共有し、呼び出しごとに独立したthread bufferを使います。multipart indexはMAPQの扱いが不適切になるため拒否します。大きな参照では十分な-Iで単一partのindexを事前作成してください。 - 期限はハードリアルタイム保証ではありません。初回chunk以前の装置側遅延、OSスケジューラ遅延、既に実行中のminimap2 C関数の強制中断は対象外です。期限超過後の結果は適用しません。
- メモリ設定はアプリ内signal量の上限です。gRPCバッファ、minimap2 index/作業領域、Python、GC、独自policyの状態を含むRSS上限ではありません。
- リードごとの機械学習スコア、オンラインcoverage、外部DB連動はpolicy/workerの拡張として実装できますが、この版に学習済みモデルや完全長coverage集計は含みません。変更塩基・品質スコアは現在のEvidenceへ渡していません。
検証
scripts/test.sh
# Moleflowを別途ビルドしてある場合。実gRPC・minimap2、fixture basecallerでの結合試験:
scripts/test.sh /absolute/path/moleflow/bin/moleflow
docs/validation-v0.3.0.md、docs/integration-v0.3.0.jsonlに今回の実行結果、docs/research.mdに調査根拠、docs/bugs.mdに修正事項を記録しています。長時間の負荷・GPU性能・実データでの選択精度は未測定です。
scripts/package.sh でアプリケーションのソースと実行ファイルをまとめられます。外部ライブラリは含まれず、展開後に shards install が必要です。出力先は既定で dist/、環境変数 ADAPTIVE_DIST_DIR で変更できます。配布物は実機検証前の研究用リリースです。
adaptive.cr
- 0
- 0
- 1
- 0
- 7
- 11 minutes ago
- October 30, 2026
Mozilla Public License 2.0
Fri, 30 Oct 2026 06:14:46 GMT