checkpoint: real-scale 数据链 + 统计引擎 + ABLUP 稀疏性能修复

init 后首次落盘,累计工作:
- 数据侧:simulate_breeding_data real-scale 3.5万树重建 + 分层观测
- 引擎侧:ABLUP 稀疏生产档 EM-REML(blup 1.6.0/1.7.0);性能倒挂修复——
  系谱闭包收口为 BFS 可达祖先 + N_EXACT 3000 对齐 N_SUBSAMPLE(选中 200~3000 树
  不再顶进数小时精确迹尾),A/B 数值等价实证 + 守卫探针
- 前端:观测过滤 + 表单/HTTP 工具链完善
- 文档:业务链/观测梳理 + 引擎实施记录 + 规划对照总表
- gitignore:排除 Temp/调试脚本/一次性验证输出
This commit is contained in:
34047007@qq.com
2026-08-07 08:03:10 +08:00
parent b95053c52c
commit e937fc930c
16 changed files with 2293 additions and 238 deletions
@@ -1349,15 +1349,11 @@
<el-select v-model="mabcBgPanels" multiple collapse-tags placeholder="背景恢复面板全基因组标记" style="min-width: 220px">
<el-option v-for="p in masPanels" :key="p.id" :label="p.panel_name" :value="p.id" />
</el-select>
<el-select v-model="mabcRpTree" placeholder="轮回亲本树" style="min-width: 170px">
<el-option v-for="t in treeOptions" :key="t.value" :label="t.label" :value="t.value" />
</el-select>
<el-select-v2 v-model="mabcRpTree" :options="treeOptions" placeholder="轮回亲本树" style="min-width: 170px" />
<el-button :loading="treeOptLoading" @click="loadTreeOptions">刷新树</el-button>
</div>
<div class="toolbar">
<el-select v-model="mabcCands" multiple collapse-tags placeholder="候选回交单株BC 分离群体" style="min-width: 300px">
<el-option v-for="t in treeOptions" :key="t.value" :label="t.label" :value="t.value" />
</el-select>
<el-select-v2 v-model="mabcCands" :options="treeOptions" multiple collapse-tags placeholder="候选回交单株BC 分离群体" style="min-width: 300px" />
<span style="color:#909399; font-size:12px">前景阈值</span>
<el-input-number v-model="mabcMinHits" :min="1" style="width: 90px" />
<span style="color:#909399; font-size:12px">当前世代</span>
@@ -2435,7 +2431,7 @@ async function loadAnova() {
}
async function loadTrialStudies() {
try {
const res: any = await TrialStudyAPI.getTrialStudyList({ page_no: 1, page_size: 200 } as any);
const res: any = await TrialStudyAPI.getTrialStudyList({ page_no: 1, page_size: 100 } as any);
trialStudies.value = (res?.data?.data?.items ?? []) as Array<{ id: number; study_name: string; block_count?: number }>;
} catch (e: any) {
msg.error(e?.message || '研究点列表加载失败');
@@ -306,7 +306,7 @@ function displayValue(trait: TraitTable): string {
async function loadTraits() {
if (traitsLoaded.value) return;
try {
const res = await TraitAPI.getTraitList({ page_no: 1, page_size: 500 });
const res = await TraitAPI.getTraitList({ page_no: 1, page_size: 100 });
if (res.data.code === ResultEnum.SUCCESS) {
const list = res.data.data.items ?? [];
for (const t of TRAIT_TABS) traitsByCategory[t] = [];
@@ -326,7 +326,7 @@ async function loadObservations(evaluationId: number) {
const res = await TraitObservationAPI.getTraitObservationList({
evaluation_id: evaluationId,
page_no: 1,
page_size: 500,
page_size: 100,
});
if (res.data.code === ResultEnum.SUCCESS) {
const list = res.data.data.items ?? [];
@@ -856,7 +856,7 @@ async function syncObservations(evaluationId: number) {
const existing = await TraitObservationAPI.getTraitObservationList({
evaluation_id: evaluationId,
page_no: 1,
page_size: 500,
page_size: 100,
});
const ids = (existing.data.data.items ?? []).map((o) => o.id).filter((x): x is number => x != null);
if (ids.length) await TraitObservationAPI.deleteTraitObservation(ids);