{
  "schema": "aspen-flowsim-stream-information-schema/v1",
  "title": "流股信息写入契约",
  "language": "zh-CN",
  "source_evidence": {
    "source_drawing": "块文件/物料表.dwg",
    "table_orientation": "streams_as_columns_properties_as_rows",
    "value_publication": "forbidden",
    "note": "该契约只保留物料表字段、单位和写入规则；源图中的项目流股名称、组分和数值均不随接口发布。"
  },
  "source_table_geometry": {
    "cad_bounds": {
      "min_x": 9892.822484,
      "max_x": 10646.344884,
      "min_y": 4101.999925,
      "max_y": 4570.634725
    },
    "grid": {
      "column_count": 20,
      "row_count": 60,
      "column_boundaries_are_fixed": true,
      "row_boundaries_are_fixed": true,
      "all_cells_same_size": false
    },
    "columns": {
      "field_label_width": 38.336123,
      "unit_width": 27.674541,
      "stream_column_count": 18,
      "stream_column_nominal_width": 38.336123,
      "source_width_exception": {
        "stream_column_index": 5,
        "width": 35.79765
      }
    },
    "rows": {
      "height_range": [
        7.620635,
        8.029224
      ],
      "common_heights": [
        7.620635,
        7.785321,
        8.029223
      ],
      "note": "每一行的高度由源图横线坐标固定，但不同属性行的高度并不完全相同。"
    },
    "default_render_profile": "source_preserving",
    "render_rule": "需要复刻竞赛模板时使用 source_preserving 并保留全部边界坐标；仅在另建项目图框时才允许显式选择 normalized_profile。"
  },
  "read_endpoints": {
    "schema": "/api/v1/stream-schema.json",
    "empty_template": "/api/v1/stream-template.json",
    "cad_vector_template": "/api/v1/stream-table-template.json"
  },
  "planned_write": {
    "route": "PUT /api/v1/projects/{project_id}/streams",
    "storage": "projects/{project_id}/stream_results.json",
    "collection_key": "streams",
    "merge_key": "aspen_stream_id",
    "status": "contract_only",
    "note": "当前站点是静态只读服务，不接受项目数据上传。后续接入项目后端时，按本契约实现该写入路由。"
  },
  "xml_results_reader": {
    "accepted_root": "Plant",
    "stream_selector": "StreamMaterial",
    "component_selector": "ComponentsMain/COMPID",
    "unit_rule": "量纲值的 unit 必须从当前 StreamMaterial 字段的 XML unit 属性读取；本全局契约不得预置具体单位。",
    "dynamic_table_rule": "固定字段列与单位列；每条选中项目流股生成一列，组分行按当前 COMPID 数量生成。",
    "required_result_fields": [
      "TEMP_OUT",
      "PRES_OUT",
      "MASSFLMX",
      "MASSFLOW",
      "MASSFRAC"
    ],
    "optional_result_fields": [
      "VFRAC_OUT",
      "LFRAC",
      "SFRAC",
      "MASSVFRA",
      "MASSSFRA",
      "VOLFLMX",
      "HMX",
      "HMX_MASS",
      "SMX",
      "SMX_MASS",
      "RHOMX",
      "RHOMX_MASS",
      "HMX_FLOW",
      "MWMX",
      "SOURCE",
      "DESTINATION",
      "COMPTYPE"
    ]
  },
  "table_rules": [
    {
      "id": "stream_column",
      "requirement": "一条流股对应物料表中的一列；pfd.stream_no 必须与 PFD 图中的流股编号一致。"
    },
    {
      "id": "property_row",
      "requirement": "流股名称、来源/去向、相态、状态、流量、热力学量和组分是行字段，不以自由文本拼接为单元格。"
    },
    {
      "id": "quantity_unit",
      "requirement": "每个量纲数值必须写为 quantity 对象，包含 value 与 unit；value 为 null 代表未取得，绝不代表零。"
    },
    {
      "id": "component_dynamic",
      "requirement": "components 由当前 Aspen 项目的组分清单动态生成，不在全局设备库中固化任何项目组分。"
    },
    {
      "id": "topology_link",
      "requirement": "topology.source 与 topology.target 必须引用项目拓扑中的设备、边界或公用工程节点；流股标识不可只存在于物料表。"
    }
  ],
  "value_types": {
    "quantity": {
      "shape": {
        "value": "number | null",
        "unit": "string | null"
      },
      "examples_are_data": false
    },
    "fraction": {
      "shape": {
        "value": "number | null",
        "unit": "fraction"
      },
      "range": "0..1 when value is present"
    }
  },
  "stream_record": {
    "required": [
      "aspen_stream_id",
      "pfd",
      "topology"
    ],
    "fields": [
      {
        "path": "aspen_stream_id",
        "type": "string",
        "required": true,
        "description": "Aspen 流股原始 ID，也是增量写入的合并键。"
      },
      {
        "path": "pfd.stream_no",
        "type": "string | null",
        "required": true,
        "description": "PFD 图号和物料表列号。"
      },
      {
        "path": "pfd.label",
        "type": "string | null",
        "required": false,
        "description": "PFD 上显示的物流名称或简短标识。"
      },
      {
        "path": "pfd.show_on_pfd",
        "type": "boolean",
        "required": true,
        "description": "是否作为 PFD 主表中的有效流股。"
      },
      {
        "path": "topology.source / topology.target",
        "type": "string | null",
        "required": true,
        "description": "项目拓扑节点 ID；边界流股允许一端为空。"
      },
      {
        "path": "topology.stream_type",
        "type": "material | utility | energy",
        "required": true,
        "description": "物流、公用工程或能量流，供图层与表格过滤。"
      },
      {
        "path": "identity.description / identity.mixed_substream",
        "type": "string | null",
        "required": false,
        "description": "描述和 Aspen MIXED 子流股名称。"
      },
      {
        "path": "state.phase",
        "type": "string | null",
        "required": false,
        "description": "物料表相态字段。"
      },
      {
        "path": "state.temperature / state.pressure",
        "type": "quantity",
        "required": false,
        "description": "温度与压力；具体单位由当前项目结果写入 quantity.unit。"
      },
      {
        "path": "phase_fractions.molar.vapor / liquid / solid",
        "type": "fraction",
        "required": false,
        "description": "摩尔相分率。"
      },
      {
        "path": "phase_fractions.mass.vapor / liquid / solid",
        "type": "fraction",
        "required": false,
        "description": "质量相分率。"
      },
      {
        "path": "flows.mass_flow / flows.volumetric_flow",
        "type": "quantity",
        "required": false,
        "description": "物料表中的总质量流量与体积流量；具体单位由当前项目结果写入 quantity.unit。"
      },
      {
        "path": "thermodynamics.molar_enthalpy / mass_enthalpy / molar_entropy / mass_entropy / molar_density / mass_density / enthalpy_flow / average_molecular_weight",
        "type": "quantity",
        "required": false,
        "description": "物料表热力学行字段；具体单位由当前项目结果写入 quantity.unit。"
      },
      {
        "path": "quality.maximum_relative_error / economics.cost_flow",
        "type": "quantity",
        "required": false,
        "description": "计算精度和成本流字段；具体单位由当前项目结果写入 quantity.unit。"
      },
      {
        "path": "components[]",
        "type": "array",
        "required": false,
        "description": "按 Aspen 当前项目组分动态写入；每项包含 component_id、mass_flow、mass_fraction，可按导出能力追加 mole_fraction。"
      }
    ]
  },
  "write_order": [
    "读取 Aspen XML Results、Toolkit 或确认过的导出表。",
    "用 Aspen stream ID 连接项目拓扑，并映射 PFD 流股编号。",
    "把数值标准化为 quantity/fraction 对象，保留导出单位。",
    "校验唯一 stream ID、来源去向、单位和组分分率。",
    "写入项目级 stream_results.json，再由 CAD/PFD 表格渲染器读取。"
  ]
}