Files
dpb/backend/app/api/v1/module_bre/statistics/model.py
T
34047007@qq.com b95053c52c init: 初始化 dpb 桃育种系统代码库
前后端 + 后端 FastAPI 全量源码、部署脚本与文档。
2026-08-06 00:17:49 +08:00

446 lines
24 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""育种统计 数据模型(一期 2 个最基础:ABLUP·EBV + 配合力 GCA/SCA"""
from datetime import datetime
from sqlalchemy import (
JSON,
Boolean,
Date,
DateTime,
Float,
ForeignKey,
Index,
Integer,
Numeric,
String,
Text,
)
from sqlalchemy.orm import Mapped, mapped_column
from app.core.base_model import MappedBase, ModelMixin, UserMixin
class PredictionModel(ModelMixin, UserMixin, MappedBase):
"""育种值模型/批次元数据(§3.12)。"""
__tablename__ = "bre_prediction"
model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="模型名称")
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
method: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="方法(ABLUP/COMBINING)")
stage: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="测定阶段(juvenile幼龄/evaluation成株)")
accuracy: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="模型精度(批次PA=√均值可靠性)")
train_n: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="训练样本量")
heritability: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="遗传力 h²")
predict_date: Mapped[datetime | None] = mapped_column(Date, nullable=True, comment="预测日期")
data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本(输入快照版本)")
input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256(表型+系谱)")
engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本")
is_active: Mapped[bool | None] = mapped_column(Boolean, nullable=True, default=False, comment="当前生效版本(同性状最近批次,供版本回滚)")
note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_prediction_created_deleted", "created_time", "is_deleted"),
)
class PredictionValueModel(ModelMixin, UserMixin, MappedBase):
"""个体预测值(EBV 持久化,V1.1 建表)。"""
__tablename__ = "bre_prediction_value"
prediction_id: Mapped[int] = mapped_column(
Integer, ForeignKey("bre_prediction.id", ondelete="CASCADE"),
index=True, nullable=False, comment="关联模型"
)
germplasm_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_germplasm.id", ondelete="CASCADE"),
index=True, nullable=True, comment="种质(亲本级)"
)
tree_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_tree.id", ondelete="CASCADE"),
index=True, nullable=True, comment="单株(树级)"
)
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
predicted_value: Mapped[float | None] = mapped_column(Float, nullable=True, comment="预测值/EBV")
reliability: Mapped[float | None] = mapped_column(Float, nullable=True, comment="可靠性")
pa: Mapped[float | None] = mapped_column(Float, nullable=True, comment="预测准确度 PA=√可靠性")
rank: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="排名")
__table_args__ = (
Index("ix_bre_prediction_value_created_deleted", "created_time", "is_deleted"),
)
class CombiningAbilityModel(ModelMixin, UserMixin, MappedBase):
"""配合力分析结果(§3.12;GCA 按亲本、SCA 按组合)。"""
__tablename__ = "bre_combining_ability"
model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="模型名称")
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方法")
design_type: Mapped[str | None] = mapped_column(
String(32), nullable=True,
comment="分析采用交配设计(full_diallel/partial_diallel/line_tester/nciii,结果快照)",
)
gca_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="亲本一般配合力 {parent: gca}")
sca_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="组合特殊配合力 {combo: {p1,p2,sca}}")
anova_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="配合力方差分解(F_gca/p_gca)")
__table_args__ = (
Index("ix_bre_combining_ability_created_deleted", "created_time", "is_deleted"),
)
class SelectionIndexModel(ModelMixin, UserMixin, MappedBase):
"""选择指数 批次(加权 Z 综合;可选接入 ABLUP 批次 EBV 与 h² 加权,结果持久化)。"""
__tablename__ = "bre_selection_index"
model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="批次名称")
method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="SI_EBV/SI_PHENO")
weights_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: 用户权重}")
batch_refs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: ABLUP批次id}")
heritability_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: h²}")
top_n: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="返回前 N")
result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{traits, top:[{tree_id,index,detail}]}")
__table_args__ = (
Index("ix_bre_selection_index_created_deleted", "created_time", "is_deleted"),
)
class AnovaResultModel(ModelMixin, UserMixin, MappedBase):
"""单因素 ANOVA 结果(家系方差组分 + 广义遗传力 H²)。"""
__tablename__ = "bre_anova_result"
model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="批次名称")
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="ANOVA/H2")
result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="方差组分/H²/F/p")
__table_args__ = (
Index("ix_bre_anova_result_created_deleted", "created_time", "is_deleted"),
)
class CvResultModel(ModelMixin, UserMixin, MappedBase):
"""k-fold 交叉验证结果(外部验证预测准确度,区别于 PEV 可靠性)。"""
__tablename__ = "bre_cv_result"
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码")
method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="KFCV/ABLUP 或 KFCV/GXE")
k: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="折数")
n_total: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="总记录数")
n_individuals: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="加性个体数")
mean_pearson: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="有效折预测-观测 pearson 均值")
mean_rmse: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="有效折 RMSE 均值")
pooled_pearson: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="合并全部折 pearson")
pooled_rmse: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="合并全部折 RMSE")
cv_accuracy: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="预测准确度(=mean_pearson)")
h2: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="有效折遗传力均值")
folds_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="折明细快照")
data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本")
input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256")
engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本")
note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_cv_result_created_deleted", "created_time", "is_deleted"),
)
class CvFoldModel(ModelMixin, UserMixin, MappedBase):
"""k-fold CV 折明细。"""
__tablename__ = "bre_cv_fold"
cv_result_id: Mapped[int] = mapped_column(
Integer, ForeignKey("bre_cv_result.id", ondelete="CASCADE"),
index=True, nullable=False, comment="关联 CV 结果"
)
fold_idx: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="折号(1-based)")
n_train: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="训练记录数")
n_test: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="测试个体数")
n_eval: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="有效评估个体数")
pearson: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="折内预测-观测 pearson")
rmse: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="折内 RMSE")
error: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="折失败原因")
__table_args__ = (
Index("ix_bre_cv_fold_created_deleted", "created_time", "is_deleted"),
)
class StatisticsJobModel(ModelMixin, UserMixin, MappedBase):
"""统计异步任务(R 引擎;ABLUP/COMBINING 提交后异步执行并回写结果)。"""
__tablename__ = "bre_statistics_job"
job_type: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="ABLUP/COMBINING")
params_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="入参")
status: Mapped[str] = mapped_column(String(16), nullable=False, default="PENDING", comment="PENDING/RUNNING/SUCCESS/FAILED")
result_ref: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="结果主表 id")
error_msg: Mapped[str | None] = mapped_column(Text, nullable=True, comment="错误信息")
started_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
finished_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
__table_args__ = (
Index("ix_bre_statistics_job_created_deleted", "created_time", "is_deleted"),
)
class GeneticCorrResultModel(ModelMixin, UserMixin, MappedBase):
"""成对双性状 BLUP 遗传相关矩阵结果(MT-BLUP,§8.18)。
逐对 bivariate 估计 σ²a1/σ²a2/σ²a12(固定单性状方差、仅对遗传相关 ρ 作
1-D 剖面 REML golden-max),输出遗传相关矩阵 r_g 供 Smith-Hazel 指数
G 矩阵非对角替换 Calo 近似。
"""
__tablename__ = "bre_genetic_corr_result"
trait_ids_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: trait_id}")
matrix_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="遗传相关矩阵 {code: {code: r_g}}")
sigma_a_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="加性方差矩阵 {code: {code: σa}}")
heritability_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{code: h²}")
pairs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="逐对详情 {pair: {r_g, va1, va2, ve1, ve2, n_common, converged, warning}}")
n_common: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="成对共有树数(最小)")
data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本")
input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256(表型+系谱)")
engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本")
note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_genetic_corr_result_created_deleted", "created_time", "is_deleted"),
)
class TypeBResultModel(ModelMixin, UserMixin, MappedBase):
"""Type-B 多环境遗传相关结果(§8.27)。
同一性状在多个环境(site=研究点 / year=年份)的表型,以环境互为"性状"逐对
REML 双性状 BLUP 估计遗传相关 r_g(复用 mtblup.solve_bivariate);r_g 均值
即 Type-B 遗传相关,衡量基因型×环境互作强度与跨环境遗传稳定性。
"""
__tablename__ = "bre_type_b_result"
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码")
env_dim: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="环境维度(site/year)")
method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方法(reml/calocalo 无环境级EBV时回退reml)")
envs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{env_code: env_label}")
matrix_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="环境间遗传相关矩阵 {env: {env: r_g}}")
pairs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="逐对详情 {pair: {r_g, va1, va2, ve1, ve2, n_common, converged, warning}}")
n_common: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="成对共有树数(最小)")
data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本")
input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256")
engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本")
note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_type_b_result_created_deleted", "created_time", "is_deleted"),
)
class StabilityResultModel(ModelMixin, UserMixin, MappedBase):
"""AMMI / Finlay-Wilkinson 稳定性分析结果(§8.18)。
两因素(基因型×环境)均值表 → AMMI SVD(IPC1/IPC2/ASV/ecovalence) 与
Finlay-Wilkinson 回归斜率 b,输出稳定性排名。
"""
__tablename__ = "bre_stability_result"
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码")
env_dim: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="环境维度(site/year)")
methods: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="方法(ammi,finlay)")
detail_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="稳定性分析明细快照")
data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本")
input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256")
engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本")
note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_stability_result_created_deleted", "created_time", "is_deleted"),
)
class GwasResultModel(ModelMixin, UserMixin, MappedBase):
"""GWAS 关联分析批次结果(§8.22)。
GLM+PC 逐标记单标记回归(纯 numpy + fdist),输出显著标记集与 QTL 区间。
"""
__tablename__ = "bre_gwas_result"
dataset_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_genotyping_dataset.id", ondelete="CASCADE"),
index=True, nullable=True, comment="基因型数据集"
)
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码")
method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方法(gwas/ssgwas)")
n_individuals: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="样本数(表型∩基因型)")
n_markers: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="标记总数")
m_after_maf: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="MAF 过滤后标记数")
maf_min: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="MAF 过滤下限")
n_pc: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="群体结构主成分数")
sig_level: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="显著性水平")
threshold_bonf: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="Bonferroni 阈值")
n_sig_bonf: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="Bonferroni 显著标记数")
n_sig_fdr: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="FDR q<α 标记数")
n_qtl: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="QTL 区间数")
data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本")
input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256(表型+系谱+基因型)")
engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本")
remark: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_gwas_result_created_deleted", "created_time", "is_deleted"),
)
class GwasSnpModel(ModelMixin, UserMixin, MappedBase):
"""GWAS 逐标记关联结果(§8.22)。"""
__tablename__ = "bre_gwas_snp"
gwas_result_id: Mapped[int] = mapped_column(
Integer, ForeignKey("bre_gwas_result.id", ondelete="CASCADE"),
index=True, nullable=False, comment="关联 GWAS 批次"
)
marker_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_marker.id", ondelete="SET NULL"),
index=True, nullable=True, comment="标记"
)
marker_name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="标记名称")
chromosome: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="染色体")
position: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="物理位置(bp)")
maf: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="次要等位频率")
effect: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="加性效应")
se: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="效应标准误")
t_value: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="t 值")
p_value: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="p 值")
neg_log10p: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="log10(p)")
q_value: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="BH-FDR q 值")
sig_bonf: Mapped[bool | None] = mapped_column(Boolean, nullable=True, comment="Bonferroni 显著")
sig_fdr: Mapped[bool | None] = mapped_column(Boolean, nullable=True, comment="FDR 显著")
__table_args__ = (
Index("ix_bre_gwas_snp_created_deleted", "created_time", "is_deleted"),
)
class QtlModel(ModelMixin, UserMixin, MappedBase):
"""QTL 区间(§8.22)。
source=known 为人工录入已知 QTL(桃成熟期/果重等位点);source=gwas 为 GWAS
显著标记聚类自动定位(gwas_result_id 关联批次)。
"""
__tablename__ = "bre_qtl"
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="性状"
)
chromosome: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="染色体")
start_bp: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="区间起点(bp)")
end_bp: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="区间终点(bp)")
peak_marker_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_marker.id", ondelete="SET NULL"),
index=True, nullable=True, comment="峰标记"
)
peak_marker_name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="峰标记名称")
peak_p: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="峰标记 p 值")
n_markers: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="区间显著标记数")
effect: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="区间峰效应")
source: Mapped[str | None] = mapped_column(String(8), nullable=True, default="known", comment="来源(known/gwas)")
gwas_result_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_gwas_result.id", ondelete="CASCADE"),
index=True, nullable=True, comment="来源 GWAS 批次(source=gwas 时)"
)
remark: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_qtl_created_deleted", "created_time", "is_deleted"),
)
class MasPanelModel(ModelMixin, UserMixin, MappedBase):
"""MAS 标记辅助选择面板(§8.22)。
一组与目标性状关联的标记(QTL 峰标记),供决策预览按有利剂量命中童期幼苗。
"""
__tablename__ = "bre_mas_panel"
panel_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="面板名称")
trait_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"),
index=True, nullable=True, comment="目标性状"
)
n_markers: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="标记数")
remark: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注")
__table_args__ = (
Index("ix_bre_mas_panel_created_deleted", "created_time", "is_deleted"),
)
class MasPanelMarkerModel(ModelMixin, UserMixin, MappedBase):
"""MAS 面板标记(§8.22)。"""
__tablename__ = "bre_mas_panel_marker"
panel_id: Mapped[int] = mapped_column(
Integer, ForeignKey("bre_mas_panel.id", ondelete="CASCADE"),
index=True, nullable=False, comment="关联面板"
)
marker_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("bre_marker.id", ondelete="SET NULL"),
index=True, nullable=True, comment="标记"
)
favorable_dose: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="有利剂量(0/1/2)")
effect: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="效应(绝对值参考)")
direction: Mapped[str | None] = mapped_column(String(8), nullable=True, default="high", comment="方向(high=剂量≥favorable_dose命中 / low=剂量≤命中)")
mode: Mapped[str | None] = mapped_column(
String(16), nullable=True, default="additive",
comment="基因作用模式:additive加性(剂量≥fav)/dominance显性(剂量≥1高/≤1低)/recessive隐性(剂量=2高/0低)/allele等位存在(有利等位)/haplotype单倍型(同组全命中)")
favorable_allele: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="有利等位(allele/haplotype 模式用,SSR 等位索引)")
haplotype_group: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="单倍型组(haplotype 模式:同组标记全命中才计 1)")
__table_args__ = (
Index("ix_bre_mas_panel_marker_created_deleted", "created_time", "is_deleted"),
)