diff --git a/cockpit/public/fma_body.mesh.nodes.json b/cockpit/public/fma_body.mesh.nodes.json new file mode 100644 index 000000000..bd77977f4 --- /dev/null +++ b/cockpit/public/fma_body.mesh.nodes.json @@ -0,0 +1 @@ +{"nodes":[{"row":0,"fma":"FMA10014","name":"ninth thoracic vertebra","tissue":"bone"},{"row":1,"fma":"FMA10037","name":"tenth thoracic vertebra","tissue":"bone"},{"row":2,"fma":"FMA10059","name":"eleventh thoracic vertebra","tissue":"bone"},{"row":3,"fma":"FMA10081","name":"twelfth thoracic vertebra","tissue":"bone"},{"row":4,"fma":"FMA10419","name":"pancreatic duct","tissue":"organ"},{"row":7,"fma":"FMA10429","name":"wall of abdomen proper","tissue":"other"},{"row":9,"fma":"FMA10446","name":"intervertebral disk","tissue":"bone"},{"row":10,"fma":"FMA10458","name":"intervertebral disk of first thoracic vertebra","tissue":"bone"},{"row":11,"fma":"FMA10552","name":"left dorsal scapular artery","tissue":"vessel"},{"row":12,"fma":"FMA10660","name":"right deep cervical artery","tissue":"vessel"},{"row":13,"fma":"FMA10680","name":"left inferior thyroid artery","tissue":"vessel"},{"row":14,"fma":"FMA10681","name":"left suprascapular artery","tissue":"vessel"},{"row":15,"fma":"FMA10682","name":"left transverse cervical artery","tissue":"vessel"},{"row":16,"fma":"FMA10683","name":"left superficial cervical artery","tissue":"vessel"},{"row":17,"fma":"FMA10692","name":"right musculophrenic artery","tissue":"vessel"},{"row":18,"fma":"FMA10697","name":"right inferior thyroid artery","tissue":"vessel"},{"row":19,"fma":"FMA10698","name":"right suprascapular artery","tissue":"vessel"},{"row":20,"fma":"FMA10699","name":"right transverse cervical artery","tissue":"vessel"},{"row":21,"fma":"FMA10700","name":"right superficial cervical artery","tissue":"vessel"},{"row":22,"fma":"FMA10951","name":"inferior vena cava","tissue":"vessel"},{"row":23,"fma":"FMA11338","name":"ileocecal junction","tissue":"other"},{"row":38,"fma":"FMA13072","name":"first lumbar vertebra","tissue":"bone"},{"row":39,"fma":"FMA13073","name":"second lumbar vertebra","tissue":"bone"},{"row":40,"fma":"FMA13074","name":"third lumbar vertebra","tissue":"bone"},{"row":41,"fma":"FMA13075","name":"fourth lumbar vertebra","tissue":"bone"},{"row":42,"fma":"FMA13076","name":"fifth lumbar vertebra","tissue":"bone"},{"row":43,"fma":"FMA13279","name":"left anterior segmental artery","tissue":"vessel"},{"row":46,"fma":"FMA13323","name":"left clavicle","tissue":"bone"},{"row":47,"fma":"FMA13325","name":"right cephalic vein","tissue":"vessel"},{"row":48,"fma":"FMA13326","name":"left cephalic vein","tissue":"vessel"},{"row":49,"fma":"FMA13336","name":"right external oblique","tissue":"muscle"},{"row":50,"fma":"FMA13337","name":"left external oblique","tissue":"muscle"},{"row":53,"fma":"FMA13365","name":"caudate lobe of liver","tissue":"organ"},{"row":56,"fma":"FMA13375","name":"right pectoralis minor","tissue":"muscle"},{"row":57,"fma":"FMA13376","name":"left pectoralis minor","tissue":"muscle"},{"row":58,"fma":"FMA13381","name":"right rhomboid major","tissue":"muscle"},{"row":59,"fma":"FMA13382","name":"left rhomboid major","tissue":"muscle"},{"row":60,"fma":"FMA13383","name":"right rhomboid minor","tissue":"muscle"},{"row":61,"fma":"FMA13384","name":"left rhomboid minor","tissue":"muscle"},{"row":63,"fma":"FMA13396","name":"left scapula","tissue":"bone"},{"row":64,"fma":"FMA13398","name":"right serratus anterior","tissue":"muscle"},{"row":65,"fma":"FMA13399","name":"left serratus anterior","tissue":"muscle"},{"row":66,"fma":"FMA13411","name":"left subclavius","tissue":"muscle"},{"row":67,"fma":"FMA13412","name":"right subclavius","tissue":"muscle"},{"row":69,"fma":"FMA13495","name":"intervertebral disk of second thoracic vertebra","tissue":"bone"},{"row":70,"fma":"FMA13500","name":"intervertebral disk of third thoracic vertebra","tissue":"bone"},{"row":71,"fma":"FMA13501","name":"intervertebral disk of fourth thoracic vertebra","tissue":"bone"},{"row":72,"fma":"FMA13502","name":"intervertebral disk of fifth thoracic vertebra","tissue":"bone"},{"row":73,"fma":"FMA13503","name":"intervertebral disk of sixth thoracic vertebra","tissue":"bone"},{"row":74,"fma":"FMA13504","name":"intervertebral disk of seventh thoracic vertebra","tissue":"bone"},{"row":75,"fma":"FMA13505","name":"intervertebral disk of eighth thoracic vertebra","tissue":"bone"},{"row":76,"fma":"FMA13506","name":"intervertebral disk of ninth thoracic vertebra","tissue":"bone"},{"row":77,"fma":"FMA13507","name":"intervertebral disk of tenth thoracic vertebra","tissue":"bone"},{"row":78,"fma":"FMA13508","name":"intervertebral disk of eleventh thoracic vertebra","tissue":"bone"},{"row":79,"fma":"FMA13889","name":"pituitary gland","tissue":"organ"},{"row":80,"fma":"FMA13896","name":"intervertebral disk of third cervical vertebra","tissue":"bone"},{"row":81,"fma":"FMA13897","name":"intervertebral disk of fourth cervical vertebra","tissue":"bone"},{"row":82,"fma":"FMA13898","name":"intervertebral disk of fifth cervical vertebra","tissue":"bone"},{"row":83,"fma":"FMA13899","name":"intervertebral disk of sixth cervical vertebra","tissue":"bone"},{"row":84,"fma":"FMA13900","name":"intervertebral disk of seventh cervical vertebra","tissue":"bone"},{"row":85,"fma":"FMA14338","name":"right hepatic vein","tissue":"vessel"},{"row":86,"fma":"FMA14339","name":"left hepatic vein","tissue":"vessel"},{"row":87,"fma":"FMA14341","name":"right testicular vein","tissue":"vessel"},{"row":88,"fma":"FMA14343","name":"right suprarenal vein","tissue":"vessel"},{"row":89,"fma":"FMA14345","name":"left testicular vein","tissue":"vessel"},{"row":90,"fma":"FMA14349","name":"left suprarenal vein","tissue":"vessel"},{"row":91,"fma":"FMA14539","name":"cystic duct","tissue":"organ"},{"row":93,"fma":"FMA14542","name":"appendix","tissue":"organ"},{"row":94,"fma":"FMA14544","name":"rectum","tissue":"organ"},{"row":95,"fma":"FMA14545","name":"ascending colon","tissue":"organ"},{"row":96,"fma":"FMA14546","name":"transverse colon","tissue":"organ"},{"row":97,"fma":"FMA14547","name":"descending colon","tissue":"organ"},{"row":103,"fma":"FMA14643","name":"mesentery of small intestine","tissue":"organ"},{"row":104,"fma":"FMA14647","name":"transverse mesocolon","tissue":"organ"},{"row":106,"fma":"FMA14668","name":"common hepatic duct","tissue":"organ"},{"row":107,"fma":"FMA14669","name":"right hepatic duct","tissue":"organ"},{"row":108,"fma":"FMA14670","name":"left hepatic duct","tissue":"organ"},{"row":110,"fma":"FMA14746","name":"right inferior phrenic artery","tissue":"vessel"},{"row":111,"fma":"FMA14747","name":"left inferior phrenic artery","tissue":"vessel"},{"row":112,"fma":"FMA14749","name":"superior mesenteric artery","tissue":"vessel"},{"row":113,"fma":"FMA14750","name":"inferior mesenteric artery","tissue":"vessel"},{"row":114,"fma":"FMA14752","name":"right renal artery","tissue":"vessel"},{"row":115,"fma":"FMA14753","name":"left renal artery","tissue":"vessel"},{"row":116,"fma":"FMA14755","name":"right middle suprarenal artery","tissue":"vessel"},{"row":117,"fma":"FMA14756","name":"left middle suprarenal artery","tissue":"vessel"},{"row":118,"fma":"FMA14759","name":"right testicular artery","tissue":"vessel"},{"row":119,"fma":"FMA14760","name":"left testicular artery","tissue":"vessel"},{"row":121,"fma":"FMA14765","name":"right common iliac artery","tissue":"vessel"},{"row":122,"fma":"FMA14766","name":"left common iliac artery","tissue":"vessel"},{"row":123,"fma":"FMA14768","name":"left gastric artery","tissue":"vessel"},{"row":124,"fma":"FMA14771","name":"common hepatic artery","tissue":"vessel"},{"row":125,"fma":"FMA14772","name":"hepatic artery proper","tissue":"vessel"},{"row":126,"fma":"FMA14773","name":"splenic artery","tissue":"vessel"},{"row":128,"fma":"FMA14776","name":"right gastric artery","tissue":"vessel"},{"row":131,"fma":"FMA14805","name":"inferior pancreaticoduodenal artery","tissue":"vessel"},{"row":132,"fma":"FMA14809","name":"ileal artery","tissue":"vessel"},{"row":133,"fma":"FMA14810","name":"middle colic artery","tissue":"vessel"},{"row":134,"fma":"FMA14811","name":"right colic artery","tissue":"vessel"},{"row":135,"fma":"FMA14812","name":"celiac trunk","tissue":"vessel"},{"row":136,"fma":"FMA14815","name":"ileocolic artery","tissue":"vessel"},{"row":137,"fma":"FMA14816","name":"anterior cecal artery","tissue":"vessel"},{"row":138,"fma":"FMA14817","name":"posterior cecal artery","tissue":"vessel"},{"row":139,"fma":"FMA14818","name":"appendicular artery","tissue":"vessel"},{"row":140,"fma":"FMA14819","name":"ileal branch of inferior branch of ileocolic artery","tissue":"vessel"},{"row":141,"fma":"FMA14820","name":"ascending branch of inferior branch of ileocolic artery","tissue":"vessel"},{"row":143,"fma":"FMA14824","name":"marginal colic artery","tissue":"vessel"},{"row":144,"fma":"FMA14826","name":"left colic artery","tissue":"vessel"},{"row":145,"fma":"FMA14830","name":"sigmoid artery","tissue":"vessel"},{"row":146,"fma":"FMA14831","name":"marginal artery of colon","tissue":"vessel"},{"row":147,"fma":"FMA14832","name":"superior rectal artery","tissue":"vessel"},{"row":148,"fma":"FMA14964","name":"proximal part of ileum","tissue":"organ"},{"row":149,"fma":"FMA14965","name":"middle part of ileum","tissue":"organ"},{"row":150,"fma":"FMA14966","name":"distal part of ileum","tissue":"organ"},{"row":152,"fma":"FMA15042","name":"taenia mesocolica","tissue":"muscle"},{"row":153,"fma":"FMA15043","name":"taenia omentalis","tissue":"muscle"},{"row":154,"fma":"FMA15044","name":"taenia libera","tissue":"muscle"},{"row":155,"fma":"FMA15414","name":"right portal vein","tissue":"vessel"},{"row":156,"fma":"FMA15415","name":"left portal vein","tissue":"vessel"},{"row":158,"fma":"FMA15420","name":"anterior superior segmental branch of right portal vein","tissue":"vessel"},{"row":159,"fma":"FMA15421","name":"anterior inferior segmental branch of right portal vein","tissue":"vessel"},{"row":161,"fma":"FMA15423","name":"posterior superior segmental branch of right portal vein","tissue":"vessel"},{"row":162,"fma":"FMA15424","name":"posterior inferior segmental branch of right portal vein","tissue":"vessel"},{"row":163,"fma":"FMA15425","name":"caudate lobe branch of left portal vein","tissue":"vessel"},{"row":165,"fma":"FMA15428","name":"medial superior segmental branch of left portal vein","tissue":"vessel"},{"row":166,"fma":"FMA15429","name":"medial inferior segmental branch of left portal vein","tissue":"vessel"},{"row":168,"fma":"FMA15431","name":"lateral superior segmental branch of left portal vein","tissue":"vessel"},{"row":169,"fma":"FMA15432","name":"lateral inferior segmental branch of left portal vein","tissue":"vessel"},{"row":170,"fma":"FMA15571","name":"right ureter","tissue":"organ"},{"row":171,"fma":"FMA15572","name":"left ureter","tissue":"organ"},{"row":172,"fma":"FMA15629","name":"right adrenal gland","tissue":"organ"},{"row":173,"fma":"FMA15630","name":"left adrenal gland","tissue":"organ"},{"row":174,"fma":"FMA15739","name":"hepatovenous segment ii","tissue":"vessel"},{"row":175,"fma":"FMA15741","name":"hepatovenous segment iii","tissue":"vessel"},{"row":176,"fma":"FMA15742","name":"hepatovenous segment iv","tissue":"vessel"},{"row":177,"fma":"FMA15743","name":"hepatovenous segment v","tissue":"vessel"},{"row":178,"fma":"FMA15744","name":"hepatovenous segment vi","tissue":"vessel"},{"row":179,"fma":"FMA15745","name":"hepatovenous segment vii","tissue":"vessel"},{"row":180,"fma":"FMA15746","name":"hepatovenous segment viii","tissue":"vessel"},{"row":185,"fma":"FMA15800","name":"anterior inferior segmental tributary of middle hepatic vein","tissue":"vessel"},{"row":188,"fma":"FMA15900","name":"urinary bladder","tissue":"organ"},{"row":189,"fma":"FMA16033","name":"intervertebral disk of first lumbar vertebra","tissue":"bone"},{"row":190,"fma":"FMA16034","name":"intervertebral disk of second lumbar vertebra","tissue":"bone"},{"row":191,"fma":"FMA16035","name":"intervertebral disk of third lumbar vertebra","tissue":"bone"},{"row":192,"fma":"FMA16036","name":"intervertebral disk of fourth lumbar vertebra","tissue":"bone"},{"row":193,"fma":"FMA16037","name":"intervertebral disk of fifth lumbar vertebra","tissue":"bone"},{"row":194,"fma":"FMA16202","name":"sacrum","tissue":"bone"},{"row":196,"fma":"FMA16549","name":"mesoappendix","tissue":"organ"},{"row":203,"fma":"FMA16981","name":"proximal part of jejunum","tissue":"organ"},{"row":204,"fma":"FMA16982","name":"middle part of jejunum","tissue":"organ"},{"row":205,"fma":"FMA16983","name":"distal part of jejunum","tissue":"organ"},{"row":208,"fma":"FMA18806","name":"right external iliac artery","tissue":"vessel"},{"row":209,"fma":"FMA18807","name":"left external iliac artery","tissue":"vessel"},{"row":210,"fma":"FMA18809","name":"right internal iliac artery","tissue":"vessel"},{"row":211,"fma":"FMA18810","name":"left internal iliac artery","tissue":"vessel"},{"row":212,"fma":"FMA18885","name":"right external iliac vein","tissue":"vessel"},{"row":213,"fma":"FMA18886","name":"left external iliac vein","tissue":"vessel"},{"row":214,"fma":"FMA18887","name":"right internal iliac vein","tissue":"vessel"},{"row":215,"fma":"FMA18888","name":"left internal iliac vein","tissue":"vessel"},{"row":216,"fma":"FMA19667","name":"urethra","tissue":"organ"},{"row":220,"fma":"FMA20226","name":"right side of bony pelvis","tissue":"other"},{"row":221,"fma":"FMA20227","name":"left side of bony pelvis","tissue":"other"},{"row":224,"fma":"FMA20688","name":"right inferior epigastric artery","tissue":"vessel"},{"row":225,"fma":"FMA20689","name":"left inferior epigastric artery","tissue":"vessel"},{"row":226,"fma":"FMA20735","name":"right superficial epigastric artery","tissue":"vessel"},{"row":227,"fma":"FMA20736","name":"left superficial epigastric artery","tissue":"vessel"},{"row":230,"fma":"FMA20801","name":"right lateral circumflex femoral artery","tissue":"vessel"},{"row":231,"fma":"FMA20802","name":"left lateral circumflex femoral artery","tissue":"vessel"},{"row":232,"fma":"FMA21387","name":"right common iliac vein","tissue":"vessel"},{"row":233,"fma":"FMA21388","name":"left common iliac vein","tissue":"vessel"},{"row":234,"fma":"FMA21930","name":"external anal sphincter","tissue":"muscle"},{"row":235,"fma":"FMA22324","name":"right obturator internus","tissue":"muscle"},{"row":236,"fma":"FMA22325","name":"left obturator internus","tissue":"muscle"},{"row":237,"fma":"FMA22340","name":"right piriformis","tissue":"muscle"},{"row":238,"fma":"FMA22341","name":"left piriformis","tissue":"muscle"},{"row":239,"fma":"FMA22342","name":"right psoas major","tissue":"bone"},{"row":240,"fma":"FMA22343","name":"left psoas major","tissue":"bone"},{"row":241,"fma":"FMA22507","name":"right descending genicular artery","tissue":"vessel"},{"row":242,"fma":"FMA22508","name":"left descending genicular artery","tissue":"vessel"},{"row":246,"fma":"FMA22676","name":"left lateral thoracic artery","tissue":"vessel"},{"row":248,"fma":"FMA22679","name":"left subscapular artery","tissue":"vessel"},{"row":250,"fma":"FMA22683","name":"left anterior circumflex humeral artery","tissue":"vessel"},{"row":252,"fma":"FMA22687","name":"left posterior circumflex humeral artery","tissue":"vessel"},{"row":253,"fma":"FMA22691","name":"right brachial artery","tissue":"vessel"},{"row":254,"fma":"FMA22692","name":"left brachial artery","tissue":"vessel"},{"row":256,"fma":"FMA22697","name":"left deep brachial artery","tissue":"vessel"},{"row":258,"fma":"FMA22708","name":"left superior ulnar collateral artery","tissue":"vessel"},{"row":260,"fma":"FMA22713","name":"left inferior ulnar collateral artery","tissue":"vessel"},{"row":262,"fma":"FMA22734","name":"left radial artery","tissue":"vessel"},{"row":263,"fma":"FMA22764","name":"right radial recurrent artery","tissue":"vessel"},{"row":264,"fma":"FMA22766","name":"left radial recurrent artery","tissue":"vessel"},{"row":265,"fma":"FMA22772","name":"dorsal carpal branch of right radial artery","tissue":"vessel"},{"row":266,"fma":"FMA22773","name":"dorsal carpal branch of left radial artery","tissue":"vessel"},{"row":268,"fma":"FMA22798","name":"left ulnar artery","tissue":"vessel"},{"row":269,"fma":"FMA22801","name":"right anterior ulnar recurrent artery","tissue":"vessel"},{"row":270,"fma":"FMA22802","name":"left anterior ulnar recurrent artery","tissue":"vessel"},{"row":271,"fma":"FMA22804","name":"right posterior ulnar recurrent artery","tissue":"vessel"},{"row":272,"fma":"FMA22805","name":"left posterior ulnar recurrent artery","tissue":"vessel"},{"row":273,"fma":"FMA22807","name":"right common interosseous artery","tissue":"bone"},{"row":274,"fma":"FMA22808","name":"left common interosseous artery","tissue":"bone"},{"row":275,"fma":"FMA22812","name":"right anterior interosseous artery","tissue":"bone"},{"row":276,"fma":"FMA22813","name":"left anterior interosseous artery","tissue":"bone"},{"row":277,"fma":"FMA22821","name":"right dorsal carpal branch of ulnar artery","tissue":"vessel"},{"row":278,"fma":"FMA22822","name":"left dorsal carpal branch of ulnar artery","tissue":"vessel"},{"row":280,"fma":"FMA22909","name":"right basilic vein","tissue":"vessel"},{"row":281,"fma":"FMA22910","name":"left basilic vein","tissue":"vessel"},{"row":282,"fma":"FMA22935","name":"right medial brachial vein","tissue":"vessel"},{"row":283,"fma":"FMA23063","name":"pectoral branch of right thoraco-acromial artery","tissue":"vessel"},{"row":284,"fma":"FMA23064","name":"pectoral branch of left thoraco-acromial artery","tissue":"vessel"},{"row":285,"fma":"FMA23068","name":"acromial branch of right thoraco-acromial artery","tissue":"vessel"},{"row":286,"fma":"FMA23069","name":"acromial branch of left thoraco-acromial artery","tissue":"vessel"},{"row":287,"fma":"FMA23072","name":"deltoid branch of right thoraco-acromial artery","tissue":"vessel"},{"row":288,"fma":"FMA23073","name":"deltoid branch of left thoraco-acromial artery","tissue":"vessel"},{"row":289,"fma":"FMA230986","name":"middle phalanx of right little toe","tissue":"bone"},{"row":290,"fma":"FMA230988","name":"middle phalanx of left little toe","tissue":"bone"},{"row":291,"fma":"FMA23130","name":"right humerus","tissue":"bone"},{"row":292,"fma":"FMA23131","name":"left humerus","tissue":"bone"},{"row":294,"fma":"FMA23180","name":"right circumflex scapular artery","tissue":"vessel"},{"row":295,"fma":"FMA23181","name":"left circumflex scapular artery","tissue":"vessel"},{"row":298,"fma":"FMA23464","name":"right radius","tissue":"bone"},{"row":299,"fma":"FMA23465","name":"left radius","tissue":"bone"},{"row":300,"fma":"FMA23467","name":"right ulna","tissue":"bone"},{"row":301,"fma":"FMA23468","name":"left ulna","tissue":"bone"},{"row":302,"fma":"FMA23725","name":"right trapezoid","tissue":"bone"},{"row":305,"fma":"FMA23938","name":"middle phalanx of left index finger","tissue":"bone"},{"row":306,"fma":"FMA23940","name":"middle phalanx of left middle finger","tissue":"bone"},{"row":307,"fma":"FMA23942","name":"middle phalanx of left ring finger","tissue":"bone"},{"row":308,"fma":"FMA23944","name":"middle phalanx of left little finger","tissue":"bone"},{"row":309,"fma":"FMA23951","name":"distal phalanx of left thumb","tissue":"bone"},{"row":310,"fma":"FMA23953","name":"distal phalanx of left index finger","tissue":"bone"},{"row":311,"fma":"FMA23955","name":"distal phalanx of left middle finger","tissue":"bone"},{"row":312,"fma":"FMA23957","name":"distal phalanx of left ring finger","tissue":"bone"},{"row":313,"fma":"FMA23959","name":"distal phalanx of left little finger","tissue":"bone"},{"row":328,"fma":"FMA242625","name":"right prefrontal cortex","tissue":"other"},{"row":332,"fma":"FMA24435","name":"right scaphoid","tissue":"bone"},{"row":333,"fma":"FMA24436","name":"left scaphoid","tissue":"bone"},{"row":334,"fma":"FMA24437","name":"right lunate","tissue":"bone"},{"row":335,"fma":"FMA24438","name":"left lunate","tissue":"bone"},{"row":336,"fma":"FMA24439","name":"right triquetral","tissue":"bone"},{"row":337,"fma":"FMA24440","name":"left triquetral","tissue":"bone"},{"row":338,"fma":"FMA24441","name":"right pisiform","tissue":"bone"},{"row":339,"fma":"FMA24442","name":"left pisiform","tissue":"bone"},{"row":340,"fma":"FMA24443","name":"right trapezium","tissue":"bone"},{"row":341,"fma":"FMA24444","name":"left trapezium","tissue":"bone"},{"row":342,"fma":"FMA24445","name":"left trapezoid","tissue":"bone"},{"row":343,"fma":"FMA24446","name":"right capitate","tissue":"bone"},{"row":344,"fma":"FMA24447","name":"left capitate","tissue":"bone"},{"row":345,"fma":"FMA24448","name":"right hamate","tissue":"bone"},{"row":346,"fma":"FMA24449","name":"left hamate","tissue":"bone"},{"row":347,"fma":"FMA24450","name":"proximal phalanx of right thumb","tissue":"bone"},{"row":348,"fma":"FMA24451","name":"proximal phalanx of right index finger","tissue":"bone"},{"row":349,"fma":"FMA24452","name":"proximal phalanx of right middle finger","tissue":"bone"},{"row":350,"fma":"FMA24453","name":"proximal phalanx of right ring finger","tissue":"bone"},{"row":351,"fma":"FMA24454","name":"proximal phalanx of right little finger","tissue":"bone"},{"row":352,"fma":"FMA24455","name":"middle phalanx of right index finger","tissue":"bone"},{"row":353,"fma":"FMA24456","name":"middle phalanx of right middle finger","tissue":"bone"},{"row":354,"fma":"FMA24457","name":"middle phalanx of right ring finger","tissue":"bone"},{"row":355,"fma":"FMA24458","name":"middle phalanx of right little finger","tissue":"bone"},{"row":356,"fma":"FMA24459","name":"distal phalanx of right thumb","tissue":"bone"},{"row":357,"fma":"FMA24460","name":"distal phalanx of right index finger","tissue":"bone"},{"row":358,"fma":"FMA24461","name":"distal phalanx of right middle finger","tissue":"bone"},{"row":359,"fma":"FMA24462","name":"distal phalanx of right ring finger","tissue":"bone"},{"row":360,"fma":"FMA24463","name":"distal phalanx of right little finger","tissue":"bone"},{"row":361,"fma":"FMA24464","name":"right first metacarpal bone","tissue":"bone"},{"row":362,"fma":"FMA24465","name":"left first metacarpal bone","tissue":"bone"},{"row":363,"fma":"FMA24466","name":"right second metacarpal bone","tissue":"bone"},{"row":364,"fma":"FMA24467","name":"left second metacarpal bone","tissue":"bone"},{"row":365,"fma":"FMA24468","name":"right third metacarpal bone","tissue":"bone"},{"row":366,"fma":"FMA24469","name":"left third metacarpal bone","tissue":"bone"},{"row":367,"fma":"FMA24470","name":"right fourth metacarpal bone","tissue":"bone"},{"row":368,"fma":"FMA24471","name":"left fourth metacarpal bone","tissue":"bone"},{"row":369,"fma":"FMA24472","name":"right fifth metacarpal bone","tissue":"bone"},{"row":370,"fma":"FMA24473","name":"left fifth metacarpal bone","tissue":"bone"},{"row":371,"fma":"FMA24474","name":"right femur","tissue":"bone"},{"row":372,"fma":"FMA24475","name":"left femur","tissue":"bone"},{"row":373,"fma":"FMA24477","name":"right tibia","tissue":"bone"},{"row":374,"fma":"FMA24478","name":"left tibia","tissue":"bone"},{"row":375,"fma":"FMA24480","name":"right fibula","tissue":"bone"},{"row":376,"fma":"FMA24481","name":"left fibula","tissue":"bone"},{"row":377,"fma":"FMA24482","name":"right talus","tissue":"bone"},{"row":378,"fma":"FMA24483","name":"left talus","tissue":"bone"},{"row":379,"fma":"FMA24486","name":"right patella","tissue":"bone"},{"row":380,"fma":"FMA24487","name":"left patella","tissue":"bone"},{"row":381,"fma":"FMA24497","name":"right calcaneus","tissue":"bone"},{"row":382,"fma":"FMA24498","name":"left calcaneus","tissue":"bone"},{"row":383,"fma":"FMA24500","name":"navicular bone of right foot","tissue":"bone"},{"row":384,"fma":"FMA24501","name":"navicular bone of left foot","tissue":"bone"},{"row":385,"fma":"FMA24507","name":"right first metatarsal bone","tissue":"bone"},{"row":386,"fma":"FMA24508","name":"left first metatarsal bone","tissue":"bone"},{"row":387,"fma":"FMA24509","name":"right second metatarsal bone","tissue":"bone"},{"row":388,"fma":"FMA24510","name":"left second metatarsal bone","tissue":"bone"},{"row":389,"fma":"FMA24511","name":"right third metatarsal bone","tissue":"bone"},{"row":390,"fma":"FMA24512","name":"left third metatarsal bone","tissue":"bone"},{"row":391,"fma":"FMA24513","name":"right fourth metatarsal bone","tissue":"bone"},{"row":392,"fma":"FMA24514","name":"left fourth metatarsal bone","tissue":"bone"},{"row":393,"fma":"FMA24515","name":"right fifth metatarsal bone","tissue":"bone"},{"row":394,"fma":"FMA24516","name":"left fifth metatarsal bone","tissue":"bone"},{"row":395,"fma":"FMA24521","name":"right medial cuneiform bone","tissue":"bone"},{"row":396,"fma":"FMA24522","name":"left medial cuneiform bone","tissue":"bone"},{"row":397,"fma":"FMA24523","name":"right intermediate cuneiform bone","tissue":"bone"},{"row":398,"fma":"FMA24524","name":"left intermediate cuneiform bone","tissue":"bone"},{"row":399,"fma":"FMA24525","name":"right lateral cuneiform bone","tissue":"bone"},{"row":400,"fma":"FMA24526","name":"left lateral cuneiform bone","tissue":"bone"},{"row":401,"fma":"FMA24528","name":"right cuboid bone","tissue":"bone"},{"row":402,"fma":"FMA24529","name":"left cuboid bone","tissue":"bone"},{"row":422,"fma":"FMA25058","name":"intervertebral disk of axis","tissue":"bone"},{"row":427,"fma":"FMA25572","name":"right bony pectoral girdle","tissue":"other"},{"row":432,"fma":"FMA259248","name":"content of abdomen","tissue":"other"},{"row":433,"fma":"FMA260124","name":"right orbital content","tissue":"other"},{"row":434,"fma":"FMA260127","name":"left orbital content","tissue":"other"},{"row":437,"fma":"FMA260791","name":"white matter of right cerebral hemisphere","tissue":"other"},{"row":438,"fma":"FMA260794","name":"white matter of left cerebral hemisphere","tissue":"other"},{"row":472,"fma":"FMA32540","name":"right levator scapulae","tissue":"muscle"},{"row":473,"fma":"FMA32541","name":"left levator scapulae","tissue":"muscle"},{"row":474,"fma":"FMA32634","name":"proximal phalanx of right second toe","tissue":"bone"},{"row":475,"fma":"FMA32635","name":"proximal phalanx of left second toe","tissue":"bone"},{"row":476,"fma":"FMA32636","name":"proximal phalanx of right third toe","tissue":"bone"},{"row":477,"fma":"FMA32637","name":"proximal phalanx of left third toe","tissue":"bone"},{"row":478,"fma":"FMA32638","name":"proximal phalanx of right fourth toe","tissue":"bone"},{"row":479,"fma":"FMA32639","name":"proximal phalanx of left fourth toe","tissue":"bone"},{"row":480,"fma":"FMA32640","name":"proximal phalanx of right little toe","tissue":"bone"},{"row":481,"fma":"FMA32641","name":"proximal phalanx of left little toe","tissue":"bone"},{"row":482,"fma":"FMA32642","name":"middle phalanx of right second toe","tissue":"bone"},{"row":483,"fma":"FMA32643","name":"middle phalanx of left second toe","tissue":"bone"},{"row":484,"fma":"FMA32644","name":"middle phalanx of right third toe","tissue":"bone"},{"row":485,"fma":"FMA32645","name":"middle phalanx of left third toe","tissue":"bone"},{"row":486,"fma":"FMA32646","name":"middle phalanx of right fourth toe","tissue":"bone"},{"row":487,"fma":"FMA32647","name":"middle phalanx of left fourth toe","tissue":"bone"},{"row":488,"fma":"FMA32650","name":"distal phalanx of right big toe","tissue":"bone"},{"row":489,"fma":"FMA32651","name":"distal phalanx of left big toe","tissue":"bone"},{"row":490,"fma":"FMA32652","name":"distal phalanx of right second toe","tissue":"bone"},{"row":491,"fma":"FMA32653","name":"distal phalanx of left second toe","tissue":"bone"},{"row":492,"fma":"FMA32654","name":"distal phalanx of right third toe","tissue":"bone"},{"row":493,"fma":"FMA32655","name":"distal phalanx of left third toe","tissue":"bone"},{"row":494,"fma":"FMA32656","name":"distal phalanx of right fourth toe","tissue":"bone"},{"row":495,"fma":"FMA32657","name":"distal phalanx of left fourth toe","tissue":"bone"},{"row":496,"fma":"FMA32658","name":"distal phalanx of right little toe","tissue":"bone"},{"row":497,"fma":"FMA32659","name":"distal phalanx of left little toe","tissue":"bone"},{"row":504,"fma":"FMA3736","name":"ascending aorta","tissue":"vessel"},{"row":505,"fma":"FMA37666","name":"left coracobrachialis","tissue":"muscle"},{"row":506,"fma":"FMA37669","name":"left brachialis","tissue":"muscle"},{"row":507,"fma":"FMA3768","name":"arch of aorta","tissue":"vessel"},{"row":508,"fma":"FMA37705","name":"right anconeus","tissue":"muscle"},{"row":509,"fma":"FMA37706","name":"left anconeus","tissue":"muscle"},{"row":510,"fma":"FMA3784","name":"descending aorta","tissue":"vessel"},{"row":532,"fma":"FMA3988","name":"right superior epigastric artery","tissue":"vessel"},{"row":533,"fma":"FMA3992","name":"right thyrocervical trunk","tissue":"vessel"},{"row":534,"fma":"FMA40120","name":"flexor retinaculum of right wrist","tissue":"organ"},{"row":535,"fma":"FMA40121","name":"flexor retinaculum of left wrist","tissue":"organ"},{"row":536,"fma":"FMA4057","name":"right dorsal scapular artery","tissue":"vessel"},{"row":539,"fma":"FMA4066","name":"left vertebral artery","tissue":"bone"},{"row":540,"fma":"FMA4068","name":"left internal thoracic artery","tissue":"vessel"},{"row":541,"fma":"FMA4077","name":"left musculophrenic artery","tissue":"vessel"},{"row":542,"fma":"FMA4083","name":"left superior epigastric artery","tissue":"vessel"},{"row":543,"fma":"FMA4084","name":"left thyrocervical trunk","tissue":"vessel"},{"row":544,"fma":"FMA4086","name":"left costocervical trunk","tissue":"vessel"},{"row":545,"fma":"FMA4088","name":"left superior intercostal artery","tissue":"vessel"},{"row":546,"fma":"FMA4134","name":"left deep cervical artery","tissue":"vessel"},{"row":547,"fma":"FMA4149","name":"esophageal artery","tissue":"vessel"},{"row":548,"fma":"FMA43253","name":"proximal phalanx of right big toe","tissue":"bone"},{"row":549,"fma":"FMA43254","name":"proximal phalanx of left big toe","tissue":"bone"},{"row":551,"fma":"FMA43896","name":"right anterior tibial artery","tissue":"vessel"},{"row":552,"fma":"FMA43897","name":"left anterior tibial artery","tissue":"vessel"},{"row":553,"fma":"FMA43898","name":"right posterior tibial artery","tissue":"vessel"},{"row":554,"fma":"FMA43899","name":"left posterior tibial artery","tissue":"vessel"},{"row":555,"fma":"FMA43916","name":"right dorsalis pedis artery","tissue":"vessel"},{"row":556,"fma":"FMA43917","name":"left dorsalis pedis artery","tissue":"vessel"},{"row":557,"fma":"FMA43929","name":"right medial plantar artery","tissue":"vessel"},{"row":558,"fma":"FMA43930","name":"left medial plantar artery","tissue":"vessel"},{"row":559,"fma":"FMA43931","name":"right lateral plantar artery","tissue":"vessel"},{"row":560,"fma":"FMA43932","name":"left lateral plantar artery","tissue":"vessel"},{"row":561,"fma":"FMA43937","name":"right superficial medial plantar artery","tissue":"vessel"},{"row":562,"fma":"FMA43938","name":"left superficial medial plantar artery","tissue":"vessel"},{"row":563,"fma":"FMA43943","name":"right plantar arch","tissue":"vessel"},{"row":564,"fma":"FMA43944","name":"left plantar arch","tissue":"vessel"},{"row":565,"fma":"FMA43956","name":"plantar metatarsal artery","tissue":"vessel"},{"row":574,"fma":"FMA45874","name":"abdominal part of right pectoralis major","tissue":"muscle"},{"row":575,"fma":"FMA45875","name":"abdominal part of left pectoralis major","tissue":"muscle"},{"row":576,"fma":"FMA4634","name":"right subcostal artery","tissue":"vessel"},{"row":579,"fma":"FMA4654","name":"left subcostal artery","tissue":"vessel"},{"row":581,"fma":"FMA46728","name":"right levator veli palatini","tissue":"muscle"},{"row":582,"fma":"FMA46729","name":"left levator veli palatini","tissue":"muscle"},{"row":583,"fma":"FMA46731","name":"right tensor veli palatini","tissue":"muscle"},{"row":584,"fma":"FMA46732","name":"left tensor veli palatini","tissue":"muscle"},{"row":585,"fma":"FMA46733","name":"uvular muscle","tissue":"muscle"},{"row":586,"fma":"FMA4694","name":"left subclavian artery","tissue":"vessel"},{"row":589,"fma":"FMA4708","name":"left marginal vein","tissue":"vessel"},{"row":590,"fma":"FMA4712","name":"posterior vein of left ventricle","tissue":"vessel"},{"row":591,"fma":"FMA4713","name":"middle cardiac vein","tissue":"vessel"},{"row":595,"fma":"FMA4720","name":"superior vena cava","tissue":"vessel"},{"row":596,"fma":"FMA4751","name":"right brachiocephalic vein","tissue":"vessel"},{"row":597,"fma":"FMA4754","name":"right internal jugular vein","tissue":"vessel"},{"row":598,"fma":"FMA4755","name":"right subclavian vein","tissue":"vessel"},{"row":599,"fma":"FMA4758","name":"right internal thoracic vein","tissue":"vessel"},{"row":600,"fma":"FMA4761","name":"left brachiocephalic vein","tissue":"vessel"},{"row":601,"fma":"FMA4797","name":"left superior intercostal vein","tissue":"vessel"},{"row":602,"fma":"FMA4838","name":"azygos vein","tissue":"vessel"},{"row":603,"fma":"FMA49044","name":"right superior rectus","tissue":"muscle"},{"row":604,"fma":"FMA49045","name":"left superior rectus","tissue":"muscle"},{"row":605,"fma":"FMA49046","name":"right inferior rectus","tissue":"muscle"},{"row":606,"fma":"FMA49047","name":"left inferior rectus","tissue":"muscle"},{"row":607,"fma":"FMA49048","name":"right levator palpebrae superioris","tissue":"muscle"},{"row":608,"fma":"FMA49049","name":"left levator palpebrae superioris","tissue":"muscle"},{"row":609,"fma":"FMA49050","name":"right inferior oblique","tissue":"muscle"},{"row":610,"fma":"FMA49051","name":"left inferior oblique","tissue":"muscle"},{"row":611,"fma":"FMA49052","name":"right superior oblique","tissue":"muscle"},{"row":612,"fma":"FMA49053","name":"left superior oblique","tissue":"muscle"},{"row":613,"fma":"FMA49054","name":"right lateral rectus","tissue":"muscle"},{"row":614,"fma":"FMA49055","name":"left lateral rectus","tissue":"muscle"},{"row":615,"fma":"FMA49056","name":"right medial rectus","tissue":"muscle"},{"row":616,"fma":"FMA49057","name":"left medial rectus","tissue":"muscle"},{"row":623,"fma":"FMA4944","name":"hemiazygos vein","tissue":"vessel"},{"row":624,"fma":"FMA49869","name":"right ophthalmic artery","tissue":"vessel"},{"row":627,"fma":"FMA49911","name":"right inferior pulmonary vein","tissue":"vessel"},{"row":628,"fma":"FMA49913","name":"left inferior pulmonary vein","tissue":"vessel"},{"row":629,"fma":"FMA49914","name":"right superior pulmonary vein","tissue":"vessel"},{"row":630,"fma":"FMA49916","name":"left superior pulmonary vein","tissue":"vessel"},{"row":631,"fma":"FMA50029","name":"right anterior cerebral artery","tissue":"vessel"},{"row":641,"fma":"FMA50085","name":"right posterior communicating artery","tissue":"vessel"},{"row":642,"fma":"FMA50086","name":"left posterior communicating artery","tissue":"vessel"},{"row":643,"fma":"FMA50088","name":"right anterior choroidal artery","tissue":"vessel"},{"row":645,"fma":"FMA50169","name":"anterior communicating artery","tissue":"vessel"},{"row":647,"fma":"FMA50366","name":"sphenoid part of right middle cerebral artery","tissue":"vessel"},{"row":648,"fma":"FMA50377","name":"anterolateral central branch of right middle cerebral artery","tissue":"vessel"},{"row":649,"fma":"FMA5039","name":"right costocervical trunk","tissue":"vessel"},{"row":650,"fma":"FMA5042","name":"right superior intercostal artery","tissue":"vessel"},{"row":652,"fma":"FMA50519","name":"right posterior inferior cerebellar artery","tissue":"vessel"},{"row":653,"fma":"FMA50520","name":"left posterior inferior cerebellar artery","tissue":"vessel"},{"row":654,"fma":"FMA50532","name":"right anterior spinal artery","tissue":"vessel"},{"row":655,"fma":"FMA50542","name":"basilar artery","tissue":"vessel"},{"row":656,"fma":"FMA50544","name":"anterior inferior cerebellar artery","tissue":"vessel"},{"row":659,"fma":"FMA50566","name":"medial branch of right pontine artery","tissue":"vessel"},{"row":660,"fma":"FMA50567","name":"medial branch of left pontine artery","tissue":"vessel"},{"row":661,"fma":"FMA50568","name":"lateral branch of right pontine artery","tissue":"vessel"},{"row":662,"fma":"FMA50569","name":"lateral branch of left pontine artery","tissue":"vessel"},{"row":663,"fma":"FMA50574","name":"right superior cerebellar artery","tissue":"vessel"},{"row":664,"fma":"FMA50575","name":"left superior cerebellar artery","tissue":"vessel"},{"row":667,"fma":"FMA50639","name":"precommunicating part of right posterior cerebral artery","tissue":"vessel"},{"row":668,"fma":"FMA50640","name":"precommunicating part of left posterior cerebral artery","tissue":"vessel"},{"row":669,"fma":"FMA50643","name":"right lateral occipital artery","tissue":"vessel"},{"row":670,"fma":"FMA50644","name":"left lateral occipital artery","tissue":"vessel"},{"row":671,"fma":"FMA50645","name":"right medial occipital artery","tissue":"vessel"},{"row":672,"fma":"FMA50646","name":"left medial occipital artery","tissue":"vessel"},{"row":675,"fma":"FMA50664","name":"right thalamoperforating artery","tissue":"vessel"},{"row":676,"fma":"FMA50665","name":"left thalamoperforating artery","tissue":"vessel"},{"row":677,"fma":"FMA50670","name":"right thalamogeniculate artery","tissue":"vessel"},{"row":678,"fma":"FMA50671","name":"left thalamogeniculate artery","tissue":"vessel"},{"row":679,"fma":"FMA50672","name":"right posterior medial choroidal artery","tissue":"vessel"},{"row":680,"fma":"FMA50673","name":"left posterior medial choroidal artery","tissue":"vessel"},{"row":681,"fma":"FMA50678","name":"anterior temporal branch of right lateral occipital artery","tissue":"vessel"},{"row":682,"fma":"FMA50679","name":"anterior temporal branch of left lateral occipital artery","tissue":"vessel"},{"row":683,"fma":"FMA50680","name":"middle temporal branch of right lateral occipital artery","tissue":"vessel"},{"row":684,"fma":"FMA50681","name":"middle temporal branch of left lateral occipital artery","tissue":"vessel"},{"row":685,"fma":"FMA50684","name":"right splenial artery","tissue":"vessel"},{"row":686,"fma":"FMA50685","name":"left splenial artery","tissue":"vessel"},{"row":687,"fma":"FMA50735","name":"hepatic portal vein","tissue":"vessel"},{"row":688,"fma":"FMA50737","name":"celiac artery","tissue":"vessel"},{"row":690,"fma":"FMA50872","name":"right pulmonary artery","tissue":"vessel"},{"row":691,"fma":"FMA50873","name":"left pulmonary artery","tissue":"vessel"},{"row":694,"fma":"FMA52734","name":"frontal bone","tissue":"bone"},{"row":695,"fma":"FMA52735","name":"occipital bone","tissue":"bone"},{"row":696,"fma":"FMA52736","name":"sphenoid bone","tissue":"bone"},{"row":697,"fma":"FMA52738","name":"right temporal bone","tissue":"bone"},{"row":698,"fma":"FMA52739","name":"left temporal bone","tissue":"bone"},{"row":699,"fma":"FMA52740","name":"ethmoid","tissue":"bone"},{"row":700,"fma":"FMA52748","name":"mandible","tissue":"bone"},{"row":701,"fma":"FMA52749","name":"hyoid bone","tissue":"bone"},{"row":703,"fma":"FMA52789","name":"left parietal bone","tissue":"bone"},{"row":705,"fma":"FMA52892","name":"right zygomatic bone","tissue":"bone"},{"row":706,"fma":"FMA52893","name":"left zygomatic bone","tissue":"bone"},{"row":711,"fma":"FMA53645","name":"right lacrimal bone","tissue":"bone"},{"row":712,"fma":"FMA53646","name":"left lacrimal bone","tissue":"bone"},{"row":715,"fma":"FMA53649","name":"right maxilla","tissue":"bone"},{"row":716,"fma":"FMA53650","name":"left maxilla","tissue":"bone"},{"row":717,"fma":"FMA53655","name":"right palatine bone","tissue":"bone"},{"row":718,"fma":"FMA53656","name":"left palatine bone","tissue":"bone"},{"row":719,"fma":"FMA53672","name":"neurocranium","tissue":"other"},{"row":721,"fma":"FMA54319","name":"pubic hair","tissue":"skin"},{"row":723,"fma":"FMA54397","name":"upper jaw","tissue":"other"},{"row":724,"fma":"FMA54398","name":"lower jaw","tissue":"other"},{"row":732,"fma":"FMA54640","name":"tongue","tissue":"other"},{"row":770,"fma":"FMA58776","name":"right iliotibial tract","tissue":"organ"},{"row":771,"fma":"FMA58777","name":"left iliotibial tract","tissue":"organ"},{"row":776,"fma":"FMA59089","name":"tarsal plate of right lower eyelid","tissue":"organ"},{"row":777,"fma":"FMA59090","name":"tarsal plate of left lower eyelid","tissue":"organ"},{"row":778,"fma":"FMA59091","name":"tarsal plate of right upper eyelid","tissue":"organ"},{"row":779,"fma":"FMA59092","name":"tarsal plate of left upper eyelid","tissue":"organ"},{"row":787,"fma":"FMA59505","name":"right major alar cartilage","tissue":"cartilage"},{"row":788,"fma":"FMA59506","name":"left major alar cartilage","tissue":"cartilage"},{"row":789,"fma":"FMA59512","name":"right lateral nasal cartilage","tissue":"cartilage"},{"row":790,"fma":"FMA59513","name":"left lateral nasal cartilage","tissue":"cartilage"},{"row":795,"fma":"FMA59541","name":"right lacrimal lake","tissue":"organ"},{"row":796,"fma":"FMA59542","name":"left lacrimal lake","tissue":"organ"},{"row":797,"fma":"FMA59545","name":"right lacrimal sac","tissue":"organ"},{"row":798,"fma":"FMA59546","name":"left lacrimal sac","tissue":"organ"},{"row":799,"fma":"FMA59555","name":"right nasolacrimal duct","tissue":"organ"},{"row":800,"fma":"FMA59556","name":"left nasolacrimal duct","tissue":"organ"},{"row":801,"fma":"FMA59582","name":"right lacrimal canaliculus","tissue":"organ"},{"row":802,"fma":"FMA59583","name":"left lacrimal canaliculus","tissue":"organ"},{"row":805,"fma":"FMA59655","name":"osseous skeleton of external nose","tissue":"other"},{"row":806,"fma":"FMA59656","name":"osseous skeleton of internal nose","tissue":"other"},{"row":807,"fma":"FMA59665","name":"septum of internal nose","tissue":"other"},{"row":810,"fma":"FMA59672","name":"left lateral wall of internal nose","tissue":"other"},{"row":817,"fma":"FMA59802","name":"right submandibular gland","tissue":"organ"},{"row":818,"fma":"FMA59803","name":"left submandibular gland","tissue":"organ"},{"row":821,"fma":"FMA59838","name":"cartilaginous part of nasal septum","tissue":"other"},{"row":849,"fma":"FMA61472","name":"right pectoral part of chest","tissue":"other"},{"row":859,"fma":"FMA61993","name":"midbrain","tissue":"organ"},{"row":862,"fma":"FMA62003","name":"metencephalon","tissue":"other"},{"row":863,"fma":"FMA62004","name":"medulla oblongata","tissue":"organ"},{"row":864,"fma":"FMA62008","name":"hypothalamus","tissue":"organ"},{"row":867,"fma":"FMA62032","name":"habenula","tissue":"other"},{"row":868,"fma":"FMA62033","name":"pineal body","tissue":"organ"},{"row":869,"fma":"FMA62327","name":"tuber cinereum","tissue":"other"},{"row":870,"fma":"FMA63103","name":"pancreatic duct tree","tissue":"organ"},{"row":871,"fma":"FMA63120","name":"parenchyma of pancreas","tissue":"organ"},{"row":872,"fma":"FMA65470","name":"proximal phalanx of left thumb","tissue":"bone"},{"row":873,"fma":"FMA66321","name":"right thoracodorsal artery","tissue":"vessel"},{"row":874,"fma":"FMA66322","name":"left thoracodorsal artery","tissue":"vessel"},{"row":875,"fma":"FMA66358","name":"trunk of superior mesenteric artery","tissue":"vessel"},{"row":876,"fma":"FMA66363","name":"trunk of right renal artery","tissue":"vessel"},{"row":877,"fma":"FMA66364","name":"trunk of left renal artery","tissue":"vessel"},{"row":878,"fma":"FMA66563","name":"trunk of right thoraco-acromial artery","tissue":"vessel"},{"row":879,"fma":"FMA66564","name":"trunk of left thoraco-acromial artery","tissue":"vessel"},{"row":880,"fma":"FMA66791","name":"proximal phalanx of left little finger","tissue":"bone"},{"row":883,"fma":"FMA67943","name":"pons","tissue":"other"},{"row":892,"fma":"FMA68068","name":"inferior phrenic vein","tissue":"vessel"},{"row":896,"fma":"FMA68197","name":"right upper lobar artery","tissue":"vessel"},{"row":900,"fma":"FMA68211","name":"right apical segmental bronchial tree","tissue":"organ"},{"row":901,"fma":"FMA68212","name":"right anterior segmental bronchial tree","tissue":"organ"},{"row":902,"fma":"FMA68213","name":"right posterior segmental bronchial tree","tissue":"organ"},{"row":903,"fma":"FMA68214","name":"medial segmental bronchial tree","tissue":"organ"},{"row":904,"fma":"FMA68215","name":"lateral segmental bronchial tree","tissue":"organ"},{"row":905,"fma":"FMA68216","name":"right superior segmental bronchial tree","tissue":"organ"},{"row":906,"fma":"FMA68218","name":"right medial basal segmental bronchial tree","tissue":"organ"},{"row":907,"fma":"FMA68220","name":"right lateral basal segmental bronchial tree","tissue":"organ"},{"row":908,"fma":"FMA68221","name":"right posterior basal segmental bronchial tree","tissue":"organ"},{"row":909,"fma":"FMA68222","name":"left anterior segmental bronchial tree","tissue":"organ"},{"row":910,"fma":"FMA68223","name":"left apical segmental bronchial tree","tissue":"organ"},{"row":911,"fma":"FMA68225","name":"left posterior segmental bronchial tree","tissue":"organ"},{"row":912,"fma":"FMA68226","name":"superior lingular bronchial tree","tissue":"organ"},{"row":913,"fma":"FMA68227","name":"inferior lingular bronchial tree","tissue":"organ"},{"row":914,"fma":"FMA68228","name":"left superior segmental bronchial tree","tissue":"organ"},{"row":915,"fma":"FMA68230","name":"left medial basal segmental bronchial tree","tissue":"organ"},{"row":916,"fma":"FMA68231","name":"left anterior basal segmental bronchial tree","tissue":"organ"},{"row":917,"fma":"FMA68232","name":"left lateral basal segmental bronchial tree","tissue":"organ"},{"row":918,"fma":"FMA68233","name":"left posterior basal segmental bronchial tree","tissue":"organ"},{"row":922,"fma":"FMA68321","name":"right anterior basal segmental bronchial tree","tissue":"organ"},{"row":923,"fma":"FMA68418","name":"right main bronchus proper","tissue":"organ"},{"row":926,"fma":"FMA68662","name":"apical part of right apical segmental artery","tissue":"vessel"},{"row":927,"fma":"FMA68665","name":"anterior part of right apical segmental artery","tissue":"vessel"},{"row":928,"fma":"FMA68670","name":"apical part of right posterior segmental artery","tissue":"vessel"},{"row":929,"fma":"FMA68673","name":"posterior part of right posterior segmental artery","tissue":"vessel"},{"row":930,"fma":"FMA68677","name":"posterior branch of right anterior segmental artery","tissue":"vessel"},{"row":931,"fma":"FMA68683","name":"anterior branch of right anterior segmental artery","tissue":"vessel"},{"row":932,"fma":"FMA68690","name":"posterior branch of lateral segmental artery","tissue":"vessel"},{"row":933,"fma":"FMA68691","name":"anterior branch of lateral segmental artery","tissue":"vessel"},{"row":934,"fma":"FMA68693","name":"superior branch of medial segmental artery","tissue":"vessel"},{"row":935,"fma":"FMA68694","name":"inferior branch of medial segmental artery","tissue":"vessel"},{"row":936,"fma":"FMA68706","name":"medial branch of right superior segmental artery","tissue":"vessel"},{"row":937,"fma":"FMA68709","name":"superior branch of right superior segmental artery","tissue":"vessel"},{"row":938,"fma":"FMA68712","name":"lateral branch of right superior segmental artery","tissue":"vessel"},{"row":939,"fma":"FMA68723","name":"basal branch of right anterior basal segmental artery","tissue":"vessel"},{"row":940,"fma":"FMA68725","name":"lateral branch of right anterior basal segmental artery","tissue":"vessel"},{"row":941,"fma":"FMA68728","name":"lateral branch of right lateral basal segmental artery","tissue":"vessel"},{"row":942,"fma":"FMA68735","name":"accessory subsuperior branch of right posterior basal segmental artery","tissue":"vessel"},{"row":943,"fma":"FMA68738","name":"laterobasal branch of right posterior basal segmental artery","tissue":"vessel"},{"row":944,"fma":"FMA68741","name":"mediobasal branch of right posterior basal segmental artery","tissue":"vessel"},{"row":948,"fma":"FMA68880","name":"trunk of right apical segmental vein","tissue":"vessel"},{"row":949,"fma":"FMA68921","name":"anterior part of right apical segmental vein","tissue":"vessel"},{"row":950,"fma":"FMA68926","name":"superior part of right anterior segmental vein","tissue":"vessel"},{"row":951,"fma":"FMA68928","name":"inferior part of right anterior segmental vein","tissue":"vessel"},{"row":952,"fma":"FMA68944","name":"posterior part of lateral segmental vein","tissue":"vessel"},{"row":953,"fma":"FMA68945","name":"anterior part of lateral segmental vein","tissue":"vessel"},{"row":954,"fma":"FMA68982","name":"superior part of medial segmental vein","tissue":"vessel"},{"row":955,"fma":"FMA68983","name":"inferior part of medial segmental vein","tissue":"vessel"},{"row":956,"fma":"FMA69265","name":"right inferior suprarenal artery","tissue":"vessel"},{"row":957,"fma":"FMA69266","name":"left inferior suprarenal artery","tissue":"vessel"},{"row":958,"fma":"FMA69490","name":"right lateral tarsal artery","tissue":"vessel"},{"row":959,"fma":"FMA69491","name":"left lateral tarsal artery","tissue":"vessel"},{"row":960,"fma":"FMA69494","name":"right arcuate artery","tissue":"vessel"},{"row":961,"fma":"FMA69495","name":"left arcuate artery","tissue":"vessel"},{"row":962,"fma":"FMA69517","name":"distal perforating artery","tissue":"vessel"},{"row":965,"fma":"FMA70249","name":"right femoral artery","tissue":"vessel"},{"row":966,"fma":"FMA70250","name":"left femoral artery","tissue":"vessel"},{"row":972,"fma":"FMA70442","name":"anterior superior segmental hepatic artery","tissue":"vessel"},{"row":973,"fma":"FMA70443","name":"anterior inferior segmental hepatic artery","tissue":"vessel"},{"row":975,"fma":"FMA70445","name":"posterior superior segmental hepatic artery","tissue":"vessel"},{"row":976,"fma":"FMA70446","name":"posterior inferior segmental hepatic artery","tissue":"vessel"},{"row":977,"fma":"FMA70447","name":"caudate lobe branch of right hepatic artery","tissue":"vessel"},{"row":979,"fma":"FMA70449","name":"medial superior segmental hepatic artery","tissue":"vessel"},{"row":980,"fma":"FMA70450","name":"medial inferior segmental hepatic artery","tissue":"vessel"},{"row":982,"fma":"FMA70452","name":"lateral superior segmental hepatic artery","tissue":"vessel"},{"row":983,"fma":"FMA70453","name":"lateral inferior segmental hepatic artery","tissue":"vessel"},{"row":984,"fma":"FMA70455","name":"caudate lobe branch of left hepatic artery","tissue":"vessel"},{"row":985,"fma":"FMA70456","name":"trunk of right hepatic artery","tissue":"vessel"},{"row":986,"fma":"FMA70457","name":"trunk of left hepatic artery","tissue":"vessel"},{"row":987,"fma":"FMA70492","name":"ureteric segment of right renal artery","tissue":"vessel"},{"row":988,"fma":"FMA70493","name":"ureteric segment of left renal artery","tissue":"vessel"},{"row":989,"fma":"FMA7088","name":"heart","tissue":"other"},{"row":991,"fma":"FMA7097","name":"left atrium","tissue":"other"},{"row":993,"fma":"FMA7101","name":"left ventricle","tissue":"other"},{"row":997,"fma":"FMA71194","name":"right lobe of thymus","tissue":"organ"},{"row":998,"fma":"FMA71195","name":"left lobe of thymus","tissue":"organ"},{"row":1000,"fma":"FMA7131","name":"esophagus","tissue":"organ"},{"row":1001,"fma":"FMA7148","name":"stomach","tissue":"organ"},{"row":1010,"fma":"FMA7163","name":"skin","tissue":"skin"},{"row":1012,"fma":"FMA7166","name":"left side of heart","tissue":"other"},{"row":1023,"fma":"FMA71867","name":"anterior superior tributary of right hepatic biliary tree","tissue":"organ"},{"row":1024,"fma":"FMA71868","name":"anterior inferior tributary of right hepatic biliary tree","tissue":"organ"},{"row":1025,"fma":"FMA71869","name":"posterior superior tributary of right hepatic biliary tree","tissue":"organ"},{"row":1027,"fma":"FMA71870","name":"posterior inferior tributary of right hepatic biliary tree","tissue":"organ"},{"row":1029,"fma":"FMA71885","name":"medial superior tributary of left hepatic biliary tree","tissue":"organ"},{"row":1030,"fma":"FMA71886","name":"medial inferior tributary of left hepatic biliary tree","tissue":"organ"},{"row":1031,"fma":"FMA71887","name":"lateral superior tributary of left hepatic biliary tree","tissue":"organ"},{"row":1032,"fma":"FMA71888","name":"lateral inferior tributary of left hepatic biliary tree","tissue":"organ"},{"row":1033,"fma":"FMA71889","name":"caudate lobe tributary of left hepatic biliary tree","tissue":"organ"},{"row":1035,"fma":"FMA71904","name":"pre-hepatic portal vein","tissue":"vessel"},{"row":1036,"fma":"FMA71908","name":"proximal phalanx of left middle finger","tissue":"bone"},{"row":1037,"fma":"FMA71915","name":"proximal phalanx of left index finger","tissue":"bone"},{"row":1038,"fma":"FMA71916","name":"proximal phalanx of left ring finger","tissue":"bone"},{"row":1040,"fma":"FMA7198","name":"pancreas","tissue":"organ"},{"row":1043,"fma":"FMA7202","name":"gallbladder","tissue":"organ"},{"row":1044,"fma":"FMA7204","name":"right kidney","tissue":"organ"},{"row":1045,"fma":"FMA7205","name":"left kidney","tissue":"organ"},{"row":1046,"fma":"FMA7206","name":"duodenum","tissue":"organ"},{"row":1048,"fma":"FMA72063","name":"set of cervical vertebrae","tissue":"other"},{"row":1060,"fma":"FMA7242","name":"anterior leaflet of mitral valve","tissue":"organ"},{"row":1066,"fma":"FMA7252","name":"right posterior cusp of aortic valve","tissue":"organ"},{"row":1067,"fma":"FMA7253","name":"anterior cusp of aortic valve","tissue":"organ"},{"row":1068,"fma":"FMA7254","name":"left posterior cusp of aortic valve","tissue":"organ"},{"row":1070,"fma":"FMA7260","name":"anterior papillary muscle of right ventricle","tissue":"muscle"},{"row":1071,"fma":"FMA7261","name":"posterior papillary muscle of right ventricle","tissue":"muscle"},{"row":1072,"fma":"FMA7262","name":"septal papillary muscle of right ventricle","tissue":"muscle"},{"row":1076,"fma":"FMA72654","name":"left superior frontal gyrus","tissue":"organ"},{"row":1078,"fma":"FMA72656","name":"left middle frontal gyrus","tissue":"organ"},{"row":1080,"fma":"FMA72658","name":"left inferior frontal gyrus","tissue":"organ"},{"row":1081,"fma":"FMA72661","name":"right precentral gyrus","tissue":"organ"},{"row":1082,"fma":"FMA72662","name":"left precentral gyrus","tissue":"organ"},{"row":1083,"fma":"FMA72665","name":"right postcentral gyrus","tissue":"organ"},{"row":1084,"fma":"FMA72666","name":"left postcentral gyrus","tissue":"organ"},{"row":1085,"fma":"FMA72667","name":"right supramarginal gyrus","tissue":"organ"},{"row":1086,"fma":"FMA72668","name":"left supramarginal gyrus","tissue":"organ"},{"row":1087,"fma":"FMA72669","name":"right angular gyrus","tissue":"organ"},{"row":1088,"fma":"FMA72670","name":"left angular gyrus","tissue":"organ"},{"row":1089,"fma":"FMA72671","name":"right superior parietal lobule","tissue":"organ"},{"row":1090,"fma":"FMA72672","name":"left superior parietal lobule","tissue":"organ"},{"row":1091,"fma":"FMA72685","name":"right middle temporal gyrus","tissue":"organ"},{"row":1092,"fma":"FMA72686","name":"left middle temporal gyrus","tissue":"organ"},{"row":1093,"fma":"FMA72687","name":"right inferior temporal gyrus","tissue":"organ"},{"row":1094,"fma":"FMA72688","name":"left inferior temporal gyrus","tissue":"organ"},{"row":1095,"fma":"FMA72689","name":"right fusiform gyrus","tissue":"organ"},{"row":1096,"fma":"FMA72690","name":"left fusiform gyrus","tissue":"organ"},{"row":1097,"fma":"FMA72705","name":"right parahippocampal gyrus","tissue":"organ"},{"row":1098,"fma":"FMA72706","name":"left parahippocampal gyrus","tissue":"organ"},{"row":1099,"fma":"FMA72713","name":"right hippocampus","tissue":"organ"},{"row":1100,"fma":"FMA72714","name":"left hippocampus","tissue":"organ"},{"row":1101,"fma":"FMA72717","name":"right cingulate gyrus","tissue":"organ"},{"row":1102,"fma":"FMA72718","name":"left cingulate gyrus","tissue":"organ"},{"row":1103,"fma":"FMA72906","name":"right internal capsule","tissue":"other"},{"row":1104,"fma":"FMA72907","name":"left internal capsule","tissue":"other"},{"row":1113,"fma":"FMA72975","name":"right occipital lobe","tissue":"organ"},{"row":1114,"fma":"FMA72976","name":"left occipital lobe","tissue":"organ"},{"row":1115,"fma":"FMA72977","name":"right insula","tissue":"organ"},{"row":1116,"fma":"FMA72978","name":"left insula","tissue":"organ"},{"row":1131,"fma":"FMA73422","name":"right superior colliculus","tissue":"organ"},{"row":1132,"fma":"FMA73423","name":"left superior colliculus","tissue":"organ"},{"row":1133,"fma":"FMA73434","name":"right inferior colliculus","tissue":"organ"},{"row":1134,"fma":"FMA73435","name":"left inferior colliculus","tissue":"organ"},{"row":1138,"fma":"FMA7362","name":"right posterior basal bronchopulmonary segment","tissue":"other"},{"row":1139,"fma":"FMA7363","name":"right lateral basal bronchopulmonary segment","tissue":"other"},{"row":1140,"fma":"FMA7364","name":"right anterior basal bronchopulmonary segment","tissue":"other"},{"row":1141,"fma":"FMA7365","name":"right medial basal bronchopulmonary segment","tissue":"other"},{"row":1142,"fma":"FMA7366","name":"right superior bronchopulmonary segment","tissue":"other"},{"row":1151,"fma":"FMA7376","name":"left superior bronchopulmonary segment","tissue":"other"},{"row":1153,"fma":"FMA7378","name":"left anterior basal bronchopulmonary segment","tissue":"other"},{"row":1154,"fma":"FMA7379","name":"left lateral basal bronchopulmonary segment","tissue":"other"},{"row":1155,"fma":"FMA7380","name":"left posterior basal bronchopulmonary segment","tissue":"other"},{"row":1160,"fma":"FMA7394","name":"trachea","tissue":"organ"},{"row":1169,"fma":"FMA7486","name":"manubrium","tissue":"bone"},{"row":1170,"fma":"FMA7487","name":"body of sternum","tissue":"organ"},{"row":1171,"fma":"FMA7488","name":"xiphoid process","tissue":"organ"},{"row":1176,"fma":"FMA76574","name":"trunk of gastroduodenal artery","tissue":"vessel"},{"row":1177,"fma":"FMA77380","name":"right popliteal artery","tissue":"vessel"},{"row":1178,"fma":"FMA77381","name":"left popliteal artery","tissue":"vessel"},{"row":1179,"fma":"FMA78121","name":"superior phrenic vein","tissue":"vessel"},{"row":1181,"fma":"FMA78449","name":"right lateral ventricle","tissue":"organ"},{"row":1182,"fma":"FMA78450","name":"left lateral ventricle","tissue":"organ"},{"row":1183,"fma":"FMA78454","name":"third ventricle","tissue":"organ"},{"row":1184,"fma":"FMA78467","name":"cerebral aqueduct","tissue":"organ"},{"row":1185,"fma":"FMA78469","name":"fourth ventricle","tissue":"organ"},{"row":1186,"fma":"FMA78497","name":"central canal of spinal cord","tissue":"organ"},{"row":1187,"fma":"FMA7857","name":"right first rib","tissue":"bone"},{"row":1188,"fma":"FMA7875","name":"right first costal cartilage","tissue":"cartilage"},{"row":1189,"fma":"FMA7882","name":"right second rib","tissue":"bone"},{"row":1190,"fma":"FMA7886","name":"right second costal cartilage","tissue":"cartilage"},{"row":1194,"fma":"FMA7909","name":"right third rib","tissue":"bone"},{"row":1195,"fma":"FMA7913","name":"right third costal cartilage","tissue":"cartilage"},{"row":1200,"fma":"FMA79274","name":"content of superior mediastinum","tissue":"other"},{"row":1203,"fma":"FMA79277","name":"content of posterior mediastinum","tissue":"other"},{"row":1205,"fma":"FMA7957","name":"right fourth rib","tissue":"bone"},{"row":1206,"fma":"FMA7976","name":"right fourth costal cartilage","tissue":"cartilage"},{"row":1207,"fma":"FMA7987","name":"left first rib","tissue":"bone"},{"row":1209,"fma":"FMA79979","name":"sternocostal part of right pectoralis major","tissue":"muscle"},{"row":1210,"fma":"FMA79980","name":"sternocostal part of left pectoralis major","tissue":"muscle"},{"row":1211,"fma":"FMA8005","name":"left first costal cartilage","tissue":"cartilage"},{"row":1212,"fma":"FMA8012","name":"left second rib","tissue":"bone"},{"row":1213,"fma":"FMA8031","name":"left second costal cartilage","tissue":"cartilage"},{"row":1214,"fma":"FMA8039","name":"left third rib","tissue":"bone"},{"row":1215,"fma":"FMA8058","name":"left third costal cartilage","tissue":"cartilage"},{"row":1216,"fma":"FMA8066","name":"right fifth rib","tissue":"bone"},{"row":1217,"fma":"FMA8070","name":"right fifth costal cartilage","tissue":"cartilage"},{"row":1218,"fma":"FMA8093","name":"left fifth rib","tissue":"bone"},{"row":1219,"fma":"FMA8112","name":"left fifth costal cartilage","tissue":"cartilage"},{"row":1220,"fma":"FMA8148","name":"left fourth rib","tissue":"bone"},{"row":1221,"fma":"FMA8167","name":"left fourth costal cartilage","tissue":"cartilage"},{"row":1222,"fma":"FMA8175","name":"right sixth rib","tissue":"bone"},{"row":1223,"fma":"FMA8194","name":"right sixth costal cartilage","tissue":"cartilage"},{"row":1224,"fma":"FMA8202","name":"left sixth rib","tissue":"bone"},{"row":1225,"fma":"FMA8221","name":"left sixth costal cartilage","tissue":"cartilage"},{"row":1226,"fma":"FMA8229","name":"right seventh rib","tissue":"bone"},{"row":1227,"fma":"FMA8248","name":"right seventh costal cartilage","tissue":"cartilage"},{"row":1228,"fma":"FMA8256","name":"left seventh rib","tissue":"bone"},{"row":1231,"fma":"FMA82695","name":"trunk of right portal vein","tissue":"vessel"},{"row":1232,"fma":"FMA82697","name":"trunk of left portal vein","tissue":"vessel"},{"row":1233,"fma":"FMA82706","name":"caudate lobe branch of right portal vein","tissue":"vessel"},{"row":1234,"fma":"FMA8275","name":"left seventh costal cartilage","tissue":"cartilage"},{"row":1235,"fma":"FMA8283","name":"right eighth rib","tissue":"bone"},{"row":1236,"fma":"FMA8310","name":"left eighth rib","tissue":"bone"},{"row":1239,"fma":"FMA8364","name":"right ninth rib","tissue":"bone"},{"row":1241,"fma":"FMA8391","name":"left ninth rib","tissue":"bone"},{"row":1242,"fma":"FMA8445","name":"right tenth rib","tissue":"bone"},{"row":1243,"fma":"FMA8472","name":"left tenth rib","tissue":"bone"},{"row":1254,"fma":"FMA8531","name":"right eleventh rib","tissue":"bone"},{"row":1255,"fma":"FMA8532","name":"left eleventh rib","tissue":"bone"},{"row":1256,"fma":"FMA8533","name":"right twelfth rib","tissue":"bone"},{"row":1257,"fma":"FMA8534","name":"left twelfth rib","tissue":"bone"},{"row":1258,"fma":"FMA86056","name":"myocardial zone 4","tissue":"other"},{"row":1261,"fma":"FMA8612","name":"pulmonary trunk","tissue":"vessel"},{"row":1264,"fma":"FMA8620","name":"right anterior segmental artery","tissue":"vessel"},{"row":1269,"fma":"FMA8634","name":"left apical segmental artery","tissue":"vessel"},{"row":1270,"fma":"FMA8635","name":"left posterior segmental artery","tissue":"vessel"},{"row":1271,"fma":"FMA8639","name":"superior lingular artery","tissue":"vessel"},{"row":1272,"fma":"FMA8640","name":"inferior lingular artery","tissue":"vessel"},{"row":1274,"fma":"FMA8644","name":"left medial basal segmental artery","tissue":"vessel"},{"row":1275,"fma":"FMA8645","name":"left anterior basal segmental artery","tissue":"vessel"},{"row":1283,"fma":"FMA8662","name":"right anterior segmental vein","tissue":"vessel"},{"row":1284,"fma":"FMA8663","name":"right posterior segmental vein","tissue":"vessel"},{"row":1288,"fma":"FMA8667","name":"left anterior segmental vein","tissue":"vessel"},{"row":1289,"fma":"FMA8668","name":"superior lingular vein","tissue":"vessel"},{"row":1290,"fma":"FMA8669","name":"inferior lingular vein","tissue":"vessel"},{"row":1300,"fma":"FMA8681","name":"apical part of right apical segmental vein","tissue":"vessel"},{"row":1304,"fma":"FMA87217","name":"descending thoracic aorta","tissue":"vessel"},{"row":1310,"fma":"FMA9165","name":"first thoracic vertebra","tissue":"bone"},{"row":1311,"fma":"FMA9187","name":"second thoracic vertebra","tissue":"bone"},{"row":1312,"fma":"FMA9209","name":"third thoracic vertebra","tissue":"bone"},{"row":1313,"fma":"FMA9248","name":"fourth thoracic vertebra","tissue":"bone"},{"row":1316,"fma":"FMA9352","name":"papillary muscle of left ventricle","tissue":"other"},{"row":1320,"fma":"FMA9437","name":"left apical segmental vein","tissue":"vessel"},{"row":1321,"fma":"FMA9438","name":"left posterior segmental vein","tissue":"vessel"},{"row":1322,"fma":"FMA9450","name":"left lateral basal segmental vein","tissue":"vessel"},{"row":1330,"fma":"FMA9531","name":"wall of left atrium","tissue":"organ"},{"row":1349,"fma":"FMA9600","name":"prostate","tissue":"organ"},{"row":1355,"fma":"FMA9761","name":"right transversus thoracis","tissue":"muscle"},{"row":1356,"fma":"FMA9762","name":"left transversus thoracis","tissue":"muscle"},{"row":1364,"fma":"FMA9922","name":"fifth thoracic vertebra","tissue":"bone"},{"row":1365,"fma":"FMA9945","name":"sixth thoracic vertebra","tissue":"bone"},{"row":1366,"fma":"FMA9968","name":"seventh thoracic vertebra","tissue":"bone"},{"row":1367,"fma":"FMA9991","name":"eighth thoracic vertebra","tissue":"bone"}]} \ No newline at end of file diff --git a/cockpit/src/FmaBody.tsx b/cockpit/src/FmaBody.tsx index 878867638..80a392bf9 100644 --- a/cockpit/src/FmaBody.tsx +++ b/cockpit/src/FmaBody.tsx @@ -1,22 +1,22 @@ // /fma-body — MY full-body FMA viewer (additive to the other session's /torso*). // -// Renders cockpit/public/fma_body.mesh (baked by `fma`'s cockpit_bake) — the same SPM1 -// indexed triangle surface the cockpit already decodes, but the per-vertex `opacity` -// byte carries a clean LAYER id (1 skin · 2 muscle · 3 organ · 4 skeleton · 5 vessel · -// 6 nerve · 7 connective · 8 other). So the viewer can TOGGLE each layer with a button, -// and switch the whole body between SOLID and TRANSPARENT. Color is the converged -// `tissue` byte (is_a); geometry is real BodyParts3D, vertex-cluster decimated. -// -// This does not touch /torso, /torso-live, /torso-splat, /torso-map (#57/#58). +// Renders cockpit/public/fma_body.mesh (baked by `fma`'s cockpit_bake) — the SPM1 wire +// the cockpit decodes, with the per-vertex `opacity` byte = a LAYER id (1 skin · 2 muscle · +// 3 organ · 4 skeleton · 5 vessel · 6 nerve · 7 connective · 8 other). Layers toggle via +// buttons; solid↔transparent switches; a SEARCH BAR zooms the camera to any organ +// (centroids from the per-vertex node_row + fma_body.mesh.nodes.json), and a CLINICAL NARS +// panel posts {organ, condition, medication, labs} to the real q2 NARS engine +// (POST /api/clinical/reason → lance_graph_planner TruthValue::deduction) and shows the +// inferred risk chains. The reasoning is a DEMO over a small rule KB — NOT medical advice. // +// Does not touch /torso, /torso-live, /torso-splat, /torso-map (#57/#58). // Geometry/data: BodyParts3D, (c) The Database Center for Life Science, CC-BY 4.0. -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; const PAGE_BG = 0x0a0e17; -// layer id (opacity byte) → label + swatch. id 0 unused; index = id. const LAYERS: { id: number; name: string; color: string }[] = [ { id: 1, name: 'skin', color: '#dba88a' }, { id: 2, name: 'muscle', color: '#bd5c57' }, @@ -28,19 +28,27 @@ const LAYERS: { id: number; name: string; color: string }[] = [ { id: 8, name: 'other', color: '#9696a0' }, ]; +// clickable demo scenarios for the NARS panel (mock dataset). +const SCENARIOS = [ + { label: 'Cirrhotic liver · acetaminophen', organ: 'liver', condition: 'cirrhosis', medication: 'acetaminophen', labs: [{ name: 'inr', flag: 'high' }, { name: 'bilirubin', flag: 'high' }] }, + { label: 'Cirrhosis · warfarin', organ: 'liver', condition: 'cirrhosis', medication: 'warfarin', labs: [{ name: 'inr', flag: 'high' }, { name: 'platelets', flag: 'low' }] }, + { label: 'CKD kidney · ibuprofen', organ: 'kidney', condition: 'ckd', medication: 'ibuprofen', labs: [{ name: 'creatinine', flag: 'high' }, { name: 'egfr', flag: 'low' }] }, + { label: 'Heart failure · NSAID', organ: 'heart', condition: 'heart_failure', medication: 'ibuprofen', labs: [{ name: 'creatinine', flag: 'high' }] }, +]; + interface Mesh { vertCount: number; triCount: number; - positions: Float32Array; + positions: Float32Array; // decoded (-x,z,y) — world space normals: Float32Array; colors: Uint8Array; - layer: Float32Array; // per-vertex layer id (from the opacity byte) + layer: Float32Array; + nodeRow: Uint16Array; index: Uint32Array; } -// SPM1 (little-endian): header 40 B | vert 21 B [pos 3f|normal 3i8|rgb 3u8|opacity u8| -// node_row u16] | index 12 B. Orientation (x,y,z)->(-x,z,y): proper rotation (det +1), -// head-up in three.js Y-up — identical to TorsoMesh so both viewers agree. +interface NodeInfo { row: number; fma: string; name: string; tissue: string } + function decodeSpm1(buf: ArrayBuffer): Mesh { const dv = new DataView(buf); const magic = String.fromCharCode(dv.getUint8(0), dv.getUint8(1), dv.getUint8(2), dv.getUint8(3)); @@ -52,17 +60,19 @@ function decodeSpm1(buf: ArrayBuffer): Mesh { const normals = new Float32Array(vertCount * 3); const colors = new Uint8Array(vertCount * 3); const layer = new Float32Array(vertCount); + const nodeRow = new Uint16Array(vertCount); for (let i = 0; i < vertCount; i++) { const b = voff + i * 21; const x = dv.getFloat32(b, true), y = dv.getFloat32(b + 4, true), z = dv.getFloat32(b + 8, true); - positions[i * 3] = -x; positions[i * 3 + 1] = z; positions[i * 3 + 2] = y; + positions[i * 3] = -x; positions[i * 3 + 1] = z; positions[i * 3 + 2] = y; // (-x,z,y) head-up normals[i * 3] = -dv.getInt8(b + 12) / 127; normals[i * 3 + 1] = dv.getInt8(b + 14) / 127; normals[i * 3 + 2] = dv.getInt8(b + 13) / 127; colors[i * 3] = dv.getUint8(b + 15); colors[i * 3 + 1] = dv.getUint8(b + 16); colors[i * 3 + 2] = dv.getUint8(b + 17); - layer[i] = dv.getUint8(b + 18); // opacity byte = LAYER id + layer[i] = dv.getUint8(b + 18); + nodeRow[i] = dv.getUint16(b + 19, true); } const ioff = voff + vertCount * 21; const index = new Uint32Array(triCount * 3); @@ -72,11 +82,9 @@ function decodeSpm1(buf: ArrayBuffer): Mesh { index[t * 3 + 1] = dv.getUint32(b + 4, true); index[t * 3 + 2] = dv.getUint32(b + 8, true); } - return { vertCount, triCount, positions, normals, colors, layer, index }; + return { vertCount, triCount, positions, normals, colors, layer, nodeRow, index }; } -// Per-layer visibility via uEnabled[9] (indexed by the vertex layer id) + a global alpha -// for the solid↔transparent switch. Phong smooth shade, two-sided. const VERT = ` attribute vec3 aNormal; attribute vec3 aColor; @@ -85,9 +93,7 @@ varying vec3 vNormal; varying vec3 vColor; varying float vLayer; void main() { - vNormal = aNormal; - vColor = aColor; - vLayer = aLayer; + vNormal = aNormal; vColor = aColor; vLayer = aLayer; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`; const FRAG = ` @@ -99,9 +105,9 @@ varying vec3 vColor; varying float vLayer; void main() { int li = int(vLayer + 0.5); - if (li < 0 || li > 8 || uEnabled[li] < 0.5) discard; // layer toggled off + if (li < 0 || li > 8 || uEnabled[li] < 0.5) discard; vec3 n = normalize(vNormal); - if (!gl_FrontFacing) n = -n; // two-sided + if (!gl_FrontFacing) n = -n; const vec3 L = vec3(-0.401, 0.783, 0.476); float ndl = max(dot(n, L), 0.0); float hemi = 0.34 + 0.20 * (n.y * 0.5 + 0.5); @@ -111,15 +117,15 @@ void main() { }`; interface RenderState { - enabled: Float32Array; // length 9, indexed by layer id + enabled: Float32Array; alpha: number; transparent: boolean; + focus: { t: [number, number, number]; d: number } | null; // zoom target } function mount(container: HTMLDivElement, mesh: Mesh, st: RenderState, onStats: (s: { fps: number }) => void): () => void { let w = container.clientWidth || window.innerWidth; let h = container.clientHeight || window.innerHeight; - const scene = new THREE.Scene(); scene.background = new THREE.Color(PAGE_BG); const camera = new THREE.PerspectiveCamera(45, w / h, 0.01, 100); @@ -143,23 +149,18 @@ function mount(container: HTMLDivElement, mesh: Mesh, st: RenderState, onStats: transparent: st.transparent, depthWrite: !st.transparent, }); - const obj = new THREE.Mesh(geom, mat); - scene.add(obj); + scene.add(new THREE.Mesh(geom, mat)); const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.08; controls.autoRotate = true; - controls.autoRotateSpeed = 0.6; - controls.target.set(0, 0, 0); - controls.minDistance = 0.6; + controls.autoRotateSpeed = 0.5; + controls.minDistance = 0.3; controls.maxDistance = 12; - let raf = 0; - let ema = 16.6; - let last = performance.now(); - let sinceStat = 0; - let wasTransparent = st.transparent; + let raf = 0, ema = 16.6, last = performance.now(), sinceStat = 0, wasT = st.transparent; + const tmp = new THREE.Vector3(); const tick = () => { raf = requestAnimationFrame(tick); const now = performance.now(); @@ -169,38 +170,28 @@ function mount(container: HTMLDivElement, mesh: Mesh, st: RenderState, onStats: if (renderer.getPixelRatio() !== pr) renderer.setPixelRatio(pr); mat.uniforms.uEnabled.value = st.enabled; mat.uniforms.uAlpha.value = st.alpha; - if (st.transparent !== wasTransparent) { - mat.transparent = st.transparent; - mat.depthWrite = !st.transparent; - mat.needsUpdate = true; - wasTransparent = st.transparent; + if (st.transparent !== wasT) { mat.transparent = st.transparent; mat.depthWrite = !st.transparent; mat.needsUpdate = true; wasT = st.transparent; } + if (st.focus) { + tmp.set(st.focus.t[0], st.focus.t[1], st.focus.t[2]); + controls.target.lerp(tmp, 0.12); + const dir = camera.position.clone().sub(controls.target).normalize(); + camera.position.lerp(tmp.clone().add(dir.multiplyScalar(st.focus.d)), 0.12); } controls.update(); renderer.render(scene, camera); - if (++sinceStat >= 20) { - sinceStat = 0; - onStats({ fps: Math.round(1000 / Math.max(ema, 1)) }); - } + if (++sinceStat >= 20) { sinceStat = 0; onStats({ fps: Math.round(1000 / Math.max(ema, 1)) }); } }; tick(); const onResize = () => { w = container.clientWidth || window.innerWidth; h = container.clientHeight || window.innerHeight; - camera.aspect = w / h; - camera.updateProjectionMatrix(); - renderer.setSize(w, h); + camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setSize(w, h); }; const ro = new ResizeObserver(onResize); ro.observe(container); - return () => { - cancelAnimationFrame(raf); - ro.disconnect(); - controls.dispose(); - geom.dispose(); - mat.dispose(); - renderer.dispose(); + cancelAnimationFrame(raf); ro.disconnect(); controls.dispose(); geom.dispose(); mat.dispose(); renderer.dispose(); if (renderer.domElement.parentNode === container) container.removeChild(renderer.domElement); }; } @@ -208,15 +199,32 @@ function mount(container: HTMLDivElement, mesh: Mesh, st: RenderState, onStats: export function FmaBody() { const ref = useRef(null); const [mesh, setMesh] = useState(null); + const [nodes, setNodes] = useState([]); const [error, setError] = useState(null); const [stats, setStats] = useState<{ fps: number } | null>(null); - // skin off by default (so the anatomy shows); everything else on. const [on, setOn] = useState>({ 1: false, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true }); const [transparent, setTransparent] = useState(false); - // shared, mutation-friendly render state (read every frame by the GL loop). - const stRef = useRef({ enabled: new Float32Array([0, 0, 1, 1, 1, 1, 1, 1, 1]), alpha: 1, transparent: false }); + const [query, setQuery] = useState(''); + const [selected, setSelected] = useState(null); + const [reason, setReason] = useState<{ summary: string[]; inferences: { source: string; target: string; truth_f: number; truth_c: number; inference_type: string; via: string[] }[]; disclaimer: string } | null>(null); + const [busy, setBusy] = useState(false); + const stRef = useRef({ enabled: new Float32Array([0, 0, 1, 1, 1, 1, 1, 1, 1]), alpha: 1, transparent: false, focus: null }); + + // per-node centroid in decoded world space (group vertices by node_row). + const rowCentroid = useMemo(() => { + const m = new Map(); + if (!mesh) return m; + const sum = new Map(); + for (let i = 0; i < mesh.vertCount; i++) { + const r = mesh.nodeRow[i]; + const a = sum.get(r) ?? [0, 0, 0, 0]; + a[0] += mesh.positions[i * 3]; a[1] += mesh.positions[i * 3 + 1]; a[2] += mesh.positions[i * 3 + 2]; a[3]++; + sum.set(r, a); + } + for (const [r, a] of sum) if (a[3]) m.set(r, [a[0] / a[3], a[1] / a[3], a[2] / a[3]]); + return m; + }, [mesh]); - // push React state → the GL render state each change. useEffect(() => { const e = new Float32Array(9); for (let i = 1; i <= 8; i++) e[i] = on[i] ? 1 : 0; @@ -227,10 +235,10 @@ export function FmaBody() { useEffect(() => { let cancelled = false; - fetch('/fma_body.mesh') - .then((r) => { if (!r.ok) throw new Error(`HTTP ${r.status} fetching fma_body.mesh`); return r.arrayBuffer(); }) - .then((buf) => { if (!cancelled) setMesh(decodeSpm1(buf)); }) - .catch((e) => { if (!cancelled) setError(String(e)); }); + fetch('/fma_body.mesh').then((r) => { if (!r.ok) throw new Error(`HTTP ${r.status} fetching fma_body.mesh`); return r.arrayBuffer(); }) + .then((buf) => { if (!cancelled) setMesh(decodeSpm1(buf)); }).catch((e) => { if (!cancelled) setError(String(e)); }); + fetch('/fma_body.mesh.nodes.json').then((r) => (r.ok ? r.json() : { nodes: [] })) + .then((d) => { if (!cancelled) setNodes(d.nodes ?? []); }).catch(() => {}); return () => { cancelled = true; }; }, []); @@ -240,29 +248,94 @@ export function FmaBody() { return mount(container, mesh, stRef.current, setStats); }, [mesh]); + const matches = useMemo(() => { + const q = query.trim().toLowerCase(); + if (!q) return []; + return nodes.filter((n) => n.name.toLowerCase().includes(q)).slice(0, 12); + }, [query, nodes]); + + function pick(n: NodeInfo) { + setSelected(n); + setReason(null); + const c = rowCentroid.get(n.row); + if (c) stRef.current.focus = { t: c, d: 0.9 }; + } + + async function runReason(sc: { organ: string; condition: string; medication: string; labs: { name: string; flag: string }[] }) { + setBusy(true); + setReason(null); + try { + const r = await fetch('/api/clinical/reason', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(sc) }); + if (!r.ok) throw new Error(`HTTP ${r.status}`); + setReason(await r.json()); + } catch (e) { + setReason({ summary: [`reasoning endpoint unavailable (${e}) — needs the cockpit-server backend deployed`], inferences: [], disclaimer: 'NARS demo — not medical advice.' }); + } finally { + setBusy(false); + } + } + const btn = (active: boolean): React.CSSProperties => ({ - padding: '5px 11px', - borderRadius: 6, - border: `1px solid ${active ? '#5a7fa8' : '#2a3242'}`, - background: active ? '#16202e' : '#0e1219', - color: active ? '#cdd9e5' : '#6a7686', - font: '12px ui-monospace, monospace', - cursor: 'pointer', + padding: '5px 11px', borderRadius: 6, border: `1px solid ${active ? '#5a7fa8' : '#2a3242'}`, + background: active ? '#16202e' : '#0e1219', color: active ? '#cdd9e5' : '#6a7686', + font: '12px ui-monospace, monospace', cursor: 'pointer', }); return (
-
-
FMA body · (place:tissue) layers
-
- {mesh ? `${mesh.triCount.toLocaleString()} triangles · drag to orbit` : error ? '' : 'loading fma_body.mesh…'} -
- {stats &&
{stats.fps} fps · solid surface, layer-gated by the converged key
} + {/* search + reasoning panel (left) */} +
+
FMA body · (place:tissue) layers
+ setQuery(e.target.value)} + placeholder={`search ${nodes.length} organs/parts — e.g. "liver"`} + style={{ width: '100%', boxSizing: 'border-box', padding: '7px 9px', borderRadius: 6, border: '1px solid #2a3242', background: '#0e1219', color: '#cdd9e5', font: '13px ui-monospace, monospace' }} + /> + {matches.length > 0 && ( +
+ {matches.map((n) => ( +
{ pick(n); setQuery(''); }} style={{ padding: '6px 9px', cursor: 'pointer', display: 'flex', justifyContent: 'space-between', borderBottom: '1px solid #141b24' }}> + {n.name}{n.tissue} +
+ ))} +
+ )} + + {selected && ( +
+
{selected.name} · {selected.tissue}
+
NARS clinical reasoning (demo) — pick a scenario:
+
+ {SCENARIOS.map((s) => ( + + ))} +
+ {busy &&
reasoning…
} + {reason && ( +
+ {reason.summary.map((s, i) => ( +
▸ {s}
+ ))} + {reason.inferences.filter((x) => x.inference_type === 'Deduction').slice(0, 6).map((x, i) => ( +
+ {x.source} → {x.target} f={x.truth_f.toFixed(2)} c={x.truth_c.toFixed(2)} +
+ ))} +
{reason.disclaimer}
+
+ )} +
+
+ )} + {stats && !selected &&
{stats.fps} fps · search zooms to the organ; layers gated by the converged key
}
- {/* layer toggles + solid/transparent */} + {/* layer toggles + solid/transparent (right) */}
{LAYERS.map((l) => ( @@ -272,26 +345,16 @@ export function FmaBody() { ))}
- +
- {error && ( -
- {error} -
- bake: cargo run -p fma --bin cockpit_bake -- <parts> <element_parts> <converged.tsv> cockpit/public/fma_body.mesh -
-
- )} - + {error &&
{error}
}
- BodyParts3D, (c) The Database Center for Life Science, licensed under CC Attribution 4.0 International + BodyParts3D, (c) The Database Center for Life Science, CC Attribution 4.0 International · clinical reasoning is a NARS demo, not medical advice
); diff --git a/crates/cockpit-server/src/clinical.rs b/crates/cockpit-server/src/clinical.rs new file mode 100644 index 000000000..c316cb3b1 --- /dev/null +++ b/crates/cockpit-server/src/clinical.rs @@ -0,0 +1,323 @@ +//! Clinical NARS reasoning — the FMA `/fma-body` viewer's "reason about this organ" +//! panel, backed by the REAL q2 NARS (`lance_graph_planner::nars::truth::TruthValue:: +//! deduction`, the same canonical algebra `graph_engine::nars_deduction` uses). +//! +//! A scenario {organ, condition, medication, labs} is compiled into a small clinical +//! graph of `(subject --rel--> object, NarsTruth)` statements drawn from a hand-authored +//! rule KB (condition→effects, drug→properties, (effect×property)→risk, lab→effect). NARS +//! 2-hop deduction `A→B, B→C ⊢ A→C` then chains e.g. `acetaminophen → hepatically_metabolized +//! → drug_accumulation_toxicity ⊢ acetaminophen → drug_accumulation_toxicity` with a derived +//! truth value. Returns the inferences (frequency/confidence) + a plain-language summary. +//! +//! DEMO ONLY — a NARS reasoning illustration over a tiny rule set, NOT medical advice. The +//! frontend shows that disclaimer in-view. + +use lance_graph_contract::exploration::NarsTruth; +use lance_graph_planner::nars::truth::TruthValue; +use serde::Serialize; + +/// One clinical statement: `subject --relation--> object` carrying a NARS truth value. +#[derive(Clone)] +struct Stmt { + s: String, + rel: String, + o: String, + truth: NarsTruth, +} + +/// A derived (or asserted) clinical inference, wire-serialized with `truth_f`/`truth_c` +/// to match the cockpit's existing NARS JSON convention (see graph_engine). +#[derive(Clone)] +pub struct CliInference { + s: String, + rel: String, + o: String, + kind: &'static str, // "Asserted" | "Deduction" + truth: NarsTruth, + via: Vec, +} + +impl Serialize for CliInference { + fn serialize(&self, ser: S) -> Result { + use serde::ser::SerializeStruct; + let mut st = ser.serialize_struct("CliInference", 7)?; + st.serialize_field("source", &self.s)?; + st.serialize_field("relation", &self.rel)?; + st.serialize_field("target", &self.o)?; + st.serialize_field("inference_type", &self.kind)?; + st.serialize_field("truth_f", &self.truth.frequency)?; + st.serialize_field("truth_c", &self.truth.confidence)?; + st.serialize_field("via", &self.via)?; + st.end() + } +} + +/// Canonical NARS deduction `A→B, B→C ⊢ A→C` via the planner's `TruthValue::deduction` +/// (`f = f1·f2, c = f1·f2·c1·c2`) — identical bridge to `graph_engine::nars_deduction`. +fn nars_deduction(ab: &NarsTruth, bc: &NarsTruth) -> NarsTruth { + let r = TruthValue::new(ab.frequency, ab.confidence) + .deduction(&TruthValue::new(bc.frequency, bc.confidence)); + NarsTruth::new(r.frequency, r.confidence) +} + +fn norm(s: &str) -> String { + s.trim().to_lowercase().replace([' ', '-'], "_") +} + +// ── the rule KB (compact clinical demo) ─────────────────────────────────────────────── +// condition → physiological effects it induces. +fn condition_effects(cond: &str) -> &'static [(&'static str, f32, f32)] { + match cond { + "cirrhosis" => &[ + ("impaired_hepatic_clearance", 0.9, 0.85), + ("coagulopathy", 0.75, 0.8), + ("portal_hypertension", 0.7, 0.75), + ], + "hepatitis" => &[ + ("hepatic_inflammation", 0.85, 0.8), + ("impaired_hepatic_clearance", 0.6, 0.7), + ], + "ckd" | "renal_failure" | "chronic_kidney_disease" => { + &[("impaired_renal_clearance", 0.9, 0.85)] + } + "heart_failure" => &[ + ("renal_hypoperfusion", 0.7, 0.75), + ("fluid_overload", 0.8, 0.8), + ], + _ => &[], + } +} +// medication → pharmacologic properties. +fn drug_properties(drug: &str) -> &'static [(&'static str, f32, f32)] { + match drug { + "acetaminophen" | "paracetamol" => &[ + ("hepatically_metabolized", 0.95, 0.9), + ("hepatotoxic_in_overdose", 0.7, 0.8), + ], + "ibuprofen" | "naproxen" | "nsaid" => &[ + ("renally_cleared", 0.8, 0.85), + ("gi_bleed_propensity", 0.65, 0.75), + ("nephrotoxic", 0.6, 0.7), + ], + "warfarin" => &[ + ("hepatically_metabolized", 0.9, 0.85), + ("anticoagulant", 0.95, 0.9), + ], + "metformin" => &[ + ("renally_cleared", 0.9, 0.9), + ("lactic_acidosis_if_accumulated", 0.6, 0.75), + ], + _ => &[], + } +} +// (active effect × drug property) → the risk it produces. property→risk is the edge NARS +// chains through (drug → property → risk). +fn risk_rule(effect: &str, property: &str) -> Option<(&'static str, f32, f32)> { + match (effect, property) { + ("impaired_hepatic_clearance", "hepatically_metabolized") => { + Some(("drug_accumulation_toxicity", 0.85, 0.8)) + } + ("impaired_renal_clearance", "renally_cleared") => { + Some(("drug_accumulation_toxicity", 0.85, 0.8)) + } + ("coagulopathy", "anticoagulant") => Some(("major_bleeding_risk", 0.9, 0.85)), + ("coagulopathy", "gi_bleed_propensity") => Some(("gi_hemorrhage_risk", 0.85, 0.8)), + ("portal_hypertension", "gi_bleed_propensity") => Some(("variceal_bleed_risk", 0.8, 0.8)), + ("renal_hypoperfusion", "nephrotoxic") => Some(("acute_kidney_injury_risk", 0.85, 0.8)), + ("impaired_renal_clearance", "lactic_acidosis_if_accumulated") => { + Some(("lactic_acidosis_risk", 0.8, 0.8)) + } + _ => None, + } +} +// lab (name, abnormal flag) → the effect it asserts/reinforces. +fn lab_effect(name: &str, flag: &str) -> Option<(&'static str, f32, f32)> { + match (name, flag) { + ("inr", "high") => Some(("coagulopathy", 0.85, 0.85)), + ("bilirubin", "high") => Some(("impaired_hepatic_clearance", 0.8, 0.8)), + ("albumin", "low") => Some(("hepatic_synthetic_dysfunction", 0.7, 0.75)), + ("creatinine", "high") => Some(("impaired_renal_clearance", 0.88, 0.85)), + ("egfr", "low") => Some(("impaired_renal_clearance", 0.88, 0.85)), + ("platelets", "low") => Some(("coagulopathy", 0.6, 0.7)), + _ => None, + } +} + +#[derive(serde::Deserialize)] +pub struct LabValue { + pub name: String, + #[serde(default)] + pub flag: String, // "high" | "low" | "normal" +} + +#[derive(serde::Deserialize)] +pub struct ClinicalScenario { + #[serde(default)] + pub organ: String, + #[serde(default)] + pub condition: String, + #[serde(default)] + pub medication: String, + #[serde(default)] + pub labs: Vec, +} + +/// Compile the scenario → clinical statements, run 2-hop NARS deduction, return inferences. +fn reason(sc: &ClinicalScenario) -> (Vec, Vec) { + let (organ, cond, drug) = (norm(&sc.organ), norm(&sc.condition), norm(&sc.medication)); + let mut stmts: Vec = Vec::new(); + let mut effects: Vec = Vec::new(); + let push = |v: &mut Vec, s: &str, rel: &str, o: &str, f: f32, c: f32| { + v.push(Stmt { + s: s.into(), + rel: rel.into(), + o: o.into(), + truth: NarsTruth::new(f, c), + }); + }; + + // organ --has--> condition + if !organ.is_empty() && !cond.is_empty() { + push(&mut stmts, &organ, "has", &cond, 1.0, 0.9); + } + // condition --induces--> effect + for &(e, f, c) in condition_effects(&cond) { + push(&mut stmts, &cond, "induces", e, f, c); + effects.push(e.to_string()); + } + // lab --indicates--> effect (reinforces / asserts) + for lab in &sc.labs { + let (ln, lf) = (norm(&lab.name), norm(&lab.flag)); + if let Some((e, f, c)) = lab_effect(&ln, &lf) { + push(&mut stmts, &format!("{ln}_{lf}"), "indicates", e, f, c); + if !effects.contains(&e.to_string()) { + effects.push(e.to_string()); + } + } + } + // medication --is--> property ; property --confers--> risk (only for ACTIVE effects) + for &(p, f, c) in drug_properties(&drug) { + if !drug.is_empty() { + push(&mut stmts, &drug, "is", p, f, c); + } + for e in &effects { + if let Some((risk, rf, rc)) = risk_rule(e, p) { + push(&mut stmts, p, "confers", risk, rf, rc); + } + } + } + + // assert + deduce + let mut out: Vec = stmts + .iter() + .map(|s| CliInference { + s: s.s.clone(), + rel: s.rel.clone(), + o: s.o.clone(), + kind: "Asserted", + truth: s.truth, + via: vec![], + }) + .collect(); + + // 2-hop deduction A→B, B→C ⊢ A→C + let existing: std::collections::HashSet<(String, String)> = + stmts.iter().map(|s| (s.s.clone(), s.o.clone())).collect(); + for ab in &stmts { + for bc in &stmts { + if ab.o == bc.s && ab.s != bc.o && !existing.contains(&(ab.s.clone(), bc.o.clone())) { + let t = nars_deduction(&ab.truth, &bc.truth); + if t.confidence >= 0.1 { + out.push(CliInference { + s: ab.s.clone(), + rel: bc.rel.clone(), + o: bc.o.clone(), + kind: "Deduction", + truth: t, + via: vec![ab.o.clone()], + }); + } + } + } + } + + // plain-language summary: strongest derived risks (expectation = c·(f−0.5)+0.5). + let mut derived: Vec<&CliInference> = out + .iter() + .filter(|i| i.kind == "Deduction" && (i.o.contains("risk") || i.o.contains("toxicity"))) + .collect(); + derived.sort_by(|a, b| { + let ex = |i: &CliInference| i.truth.confidence * (i.truth.frequency - 0.5) + 0.5; + ex(b) + .partial_cmp(&ex(a)) + .unwrap_or(std::cmp::Ordering::Equal) + }); + let mut summary: Vec = derived + .iter() + .take(4) + .map(|i| { + let pretty = |s: &str| s.replace('_', " "); + format!( + "{} → {} (f={:.2}, c={:.2}, via {})", + pretty(&i.s), + pretty(&i.o), + i.truth.frequency, + i.truth.confidence, + i.via.join(", ") + ) + }) + .collect(); + if summary.is_empty() { + summary.push("No risk chain derived from the rule KB for this scenario.".into()); + } + (out, summary) +} + +/// `POST /api/clinical/reason` — body `{organ, condition, medication, labs:[{name,flag}]}`. +pub async fn clinical_reason_handler( + axum::Json(sc): axum::Json, +) -> axum::Json { + let (inferences, summary) = reason(&sc); + let asserted = inferences.iter().filter(|i| i.kind == "Asserted").count(); + let derived = inferences.len() - asserted; + axum::Json(serde_json::json!({ + "organ": sc.organ, + "condition": sc.condition, + "medication": sc.medication, + "asserted": asserted, + "derived": derived, + "inferences": inferences, + "summary": summary, + "engine": "lance_graph_planner::nars::truth::TruthValue::deduction (f=f1·f2, c=f1·f2·c1·c2)", + "disclaimer": "NARS reasoning DEMO over a small rule KB — not medical advice.", + })) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn cirrhosis_acetaminophen_chains_to_accumulation() { + let sc = ClinicalScenario { + organ: "liver".into(), + condition: "cirrhosis".into(), + medication: "acetaminophen".into(), + labs: vec![LabValue { + name: "inr".into(), + flag: "high".into(), + }], + }; + let (inf, summary) = reason(&sc); + // deduction must surface acetaminophen → drug_accumulation_toxicity via hepatically_metabolized + assert!( + inf.iter().any(|i| i.s == "acetaminophen" + && i.o == "drug_accumulation_toxicity" + && i.kind == "Deduction"), + "expected acetaminophen→drug_accumulation_toxicity; got {:?}", + inf.iter() + .map(|i| format!("{}→{}", i.s, i.o)) + .collect::>() + ); + assert!(!summary.is_empty()); + } +} diff --git a/crates/cockpit-server/src/main.rs b/crates/cockpit-server/src/main.rs index c2584ca1b..f461c2082 100644 --- a/crates/cockpit-server/src/main.rs +++ b/crates/cockpit-server/src/main.rs @@ -29,6 +29,7 @@ use tower_http::cors::CorsLayer; mod openai; mod graph_engine; +mod clinical; mod osint_gotham; mod scene_player; mod shader_stream; @@ -168,6 +169,8 @@ async fn main() { .route("/api/graph/snapshot", get(graph_engine::graph_snapshot_handler)) .route("/api/graph/infer", post(graph_engine::nars_infer_handler)) .route("/api/graph/health", get(graph_engine::graph_health_handler)) + // Clinical NARS reasoning for the /fma-body organ panel (real TruthValue::deduction) + .route("/api/clinical/reason", post(clinical::clinical_reason_handler)) // OSINT domain (classid 0x0700): the harvest as a CANON family-basin graph // (round→anchor basins, GUID-v2 tail), displayed via the OGAR ClassView. .route("/api/graph/osint", get(osint_gotham::osint_graph_handler)) diff --git a/fma/docs/OGAR_CONSUMER_INTEGRATION.md b/fma/docs/OGAR_CONSUMER_INTEGRATION.md new file mode 100644 index 000000000..d536f6601 --- /dev/null +++ b/fma/docs/OGAR_CONSUMER_INTEGRATION.md @@ -0,0 +1,379 @@ +# OGAR Consumer Integration — adopting the canonical NodeGuid / guid-shaped representation + +> What a consumer does to adopt OGAR's canonical node representation, and the +> new powers it unlocks for data representation and AST. Grounded in shipped +> code: `canonical_node.rs` is the canonical home; q2's `osint-bake` + `cockpit-server` +> already consume the contract; this crate's v3 `converge` mints the canonical +> key dep-free. Speculative items are tagged **CONJECTURE**; everything else is +> a fact about code that exists today. + +## 0. The one-sentence claim + +A node is `4096 bit = 512 byte = key(16) | edges(16) | value(480)`, and **the +16-byte key IS the address** — `classid · HEEL · HIP · TWIG · family · identity`, +little-endian, self-describing at sight. A consumer adopts OGAR by replacing its +bespoke ids with this key. The payoff: every consumer inherits prefix routing, +key-only scans, zero-copy Lance I/O, and compression-without-losing-addressability +**for free**, because they all become readings of one shared 16-byte key. + +Reference impl (the source of truth, all line numbers below are this file): +`/home/user/lance-graph/crates/lance-graph-contract/src/canonical_node.rs`. + +--- + +## 1. The canonical surface consumers adopt + +Everything a consumer needs is in `lance_graph_contract::canonical_node`. Five +types, one registry: + +### 1.1 `NodeGuid` — the 16-byte key + +```text + 0..4 classid (u32) 8 hex — prefix-routable; default 0x0000_0000 + 4..6 HEEL (u16) ┐ + 6..8 HIP (u16) ├ 3 cascade tiers (HHTL path) + 8..10 TWIG (u16) ┘ + 10..13 family (u24) ┐ trailing 6 bytes = basin-local key + 13..16 identity (u24) ┘ (a single masked load after the trie binds the prefix) +``` + +- `NodeGuid::new(classid, heel, hip, twig, family, identity)` — const fn, + little-endian, panics (incl. const-eval) if `family`/`identity` exceed 24 bits + (the silent-truncation footgun guard). +- `NodeGuid::local(identity)` — the bootstrap address: classid=0, family=0, only + identity discriminates. +- Accessors: `.classid() .heel() .hip() .twig() .family() .identity()`, + `.decode() -> GuidParts` (all six groups in one read), `.local_key() -> u64` + (trailing 6 bytes — the only discriminator once the prefix is trie-resolved), + `.read_mode() -> ReadMode`, `.as_bytes() -> &[u8; 16]`. +- `Display` renders the canonical `{:08x}-{:04x}-{:04x}-{:04x}-{:06x}{:06x}` + (8-4-4-4-12 hex). The dash-groups ARE the semantic delimiters. +- Dispatch guards: `.is_default_class() .is_unbasined() .is_bootstrap_address()`. + +### 1.2 `NodeRow` — the 512-byte SoA row + +`#[repr(C, align(64))]`, `key: NodeGuid (0..16) | edges: EdgeBlock (16..32) | value: [u8; 480] (32..512)`. +Compile-asserted at 512 B. A `&[NodeRow]` is *already* a row-strided LE column +packet — no serialization needed. + +### 1.3 `EdgeBlock` — 12 in-family + 4 out-of-family + +`#[repr(C, align(16))]`, one byte per slot. Canonical, **not mandatory**: always +reserved (zeroed when unused), never shrunk. A class opting out of edges is +resolved via `classid → ClassView`, never a stride change. Read flavor is an +*interpretation* selected by `EdgeCodecFlavor` (`CoarseOnly` / `CoarseResidue` / +`Pq32x4`) — none changes `NODE_ROW_STRIDE`. + +### 1.4 Value tenants via `ValueSchema` presets + +The 480-byte value slab is carved by named `ValueTenant`s (stable, append-only +positions): `Meta · Qualia · MaterializedEdges · Fingerprint · HelixResidue · +TurbovecResidue · Energy · Plasticity · EntityType`. A class picks a **preset**: + +| `ValueSchema` | tenants | bytes | +|---|---|---| +| `Bootstrap` (default) | none — key + edges only | 0 | +| `Cognitive` | Meta, Qualia, Fingerprint, Energy, Plasticity, EntityType | 58 | +| `Compressed` | Fingerprint, HelixResidue, TurbovecResidue, EntityType | 56 | +| `Full` | every tenant | 112 | + +Every preset carves *within* the reserved 480 B, so the choice never changes the +512-byte stride. `ValueTenant::value_offset()` / `byte_len()` let a transcode +write into the slab without hardcoding the carve. + +### 1.5 `classid → ReadMode` registry + +`classid_read_mode(classid) -> ReadMode { value_schema, edge_codec }` — resolved +through one `LazyLock` map (`BUILTIN_READ_MODES`). `NodeGuid::read_mode()` is the +carrier-method form. **Both a consumer transcoding a row AND OGAR minting the same +class read the identical schema** — single-sourced LE interpretation. Any classid +not in the map falls through to `ReadMode::DEFAULT` (the key's own zero-fallback +ladder). NB: `DEFAULT.value_schema` is temporarily `Full` (a 2026-06-15 POC default, +guarded by the test `read_mode_default_is_full_poc`); it flips back to `Bootstrap` +when the POC ends. + +### 1.6 The lever: the zero-fallback ladder (incremental adoption) + +``` +classid == 0x0000_0000 → default class, no prefix routing (dormant) +family == 0x00_0000 → default basin, no neighborhood grouping (dormant) +⇒ while both are zero, identity (24 bit) ALONE discriminates — the bootstrap address. +``` + +This is what makes adoption **incremental and reversible**. A consumer can switch +to `NodeGuid::local(id)` today, keep its flat id-space (16.7M identities per +default basin), and ship. Later it mints a non-zero `classid` (to turn on prefix +routing) and/or a non-zero `family` (to turn on basins) — **with ZERO +`ENVELOPE_LAYOUT_VERSION` change**, because `classid` (4 B) and `family` (3 B) +keep fixed offsets that were reserved, never reclaimed. There is no flag day: a +zero tier means "not consulted", never "compacted away" (RESERVE, DON'T RECLAIM). + +--- + +## 2. Per-consumer upgrade path + +### 2.1 lance-graph (canonical home — already there) + +`canonical_node.rs` IS the contract. `NodeRowPacket<'a>` implements `SoaEnvelope` +with a zero-copy `as_le_bytes()` (the pointer of the byte view equals the slice's +pointer — asserted in tests). Lance's columnar I/O writes those LE bytes directly +from the in-place backing store. Nothing to adopt; this is the surface everyone +else imports. + +What's left here: extend `BUILTIN_READ_MODES` as real classes mint (today it +holds only the default), and flip the POC `Full` default back to `Bootstrap` (one +revert, two sites — `ReadMode::DEFAULT` + `ClassView::value_schema`). + +### 2.2 q2 `osint-bake` / `cockpit-server` (already consume the contract) + +- **`crates/osint-bake/src/bin/fma.rs`** mints node keys via + `NodeGuid::new_v2(CLASSID_FMA, HEEL, HIP, TWIG, LEAF, family, identity)` — a + **7-group** layout (it threads a distinct `LEAF` tier between TWIG and family, + and reads it back with `.leaf()` / `.family_v2()`). It emits the cockpit's + `OSO1` wire buffer (`node.key.as_bytes()` → 16 bytes per node) and the `/fma` + dual-membership proof. + + **Blocker, file as an issue (do NOT silently reimplement — §5):** + `NodeGuid::new_v2`, `.leaf()`, and `.family_v2()` **do not exist** in the + current `canonical_node.rs` (which ships the 6-group + `NodeGuid::new(classid, heel, hip, twig, family, identity)` with `.heel/.hip/.twig` + but no `.leaf`/`.family_v2`/`.new_v2`). q2 pins this exact path + (`../lance-graph/crates/lance-graph-contract`, root `Cargo.toml:214` & + `:377`), so `osint-bake` is written against an **in-flight v2 NodeGuid API + that has not landed in `canonical_node.rs`**. This is precisely the + `I-LEGACY-API-FEATURE-GATED` situation: two readings of "the canonical key" + (6-group locked vs 7-group LEAF-bearing) under one name. Resolution is upstream + in lance-graph — either land the 7-group `new_v2` (LEAF reclaims part of the + TWIG/family span, version-gated) or migrate `fma.rs` onto the 6-group `new`. + Until then, `osint-bake`'s `fma` bin is the canary for that decision; treat the + divergence as the gating item, not a thing to route around. + +- **`crates/cockpit-server/src/graph_engine.rs`** already uses + `lance_graph_contract::exploration::NarsTruth` (frequency, confidence) for edge + truth and `lance_graph_contract::nars::InferenceType` for inference labels, + bridging NARS deduction to `lance_graph_planner::nars::truth::TruthValue::deduction`. + Truth/inference types are canonical here. What's left: the snapshot's + `GraphNode { id: String, ... }` is still a stringly-typed property-graph node — + the natural next step is to carry a `NodeGuid` per node (its id) and route the + cockpit's render/select by `classid` prefix (the same prefix the `/fma` + skeleton button uses), instead of by string id. + +### 2.3 fma (v3 `converge` already mints the canonical key, dep-free) + +`/home/user/q2/fma/src/bin/converge.rs` is a **standalone crate** (self-isolated +`[workspace]`, only dep `png`) that deliberately does NOT link the contract. It +reimplements the canonical 16-byte layout byte-for-byte: + +- `node_guid_bytes(classid, heel, hip, twig, family, identity)` builds the exact + `to_le_bytes` layout of `NodeGuid::new` (header comment asserts byte-identity to + `lance_graph_contract::canonical_node::NodeGuid::new`, OGAR canon 2026-06-13). +- `guid_display` renders the same `8-4-4-4-12` hex as `NodeGuid`'s `Display`. +- It realizes the **two ontological axes in one key**: each 8:8 HHTL tier is + `(place : tissue)` — high byte = PLACE (Morton spatial cell for skeletal nodes + classid `0x0A02`, or `part_of` sibling-rank for soft tissue `0x0A01`); low byte + = TISSUE (`is_a` taxonomy sibling-rank). The high-byte chain prefix-routes the + body, the low-byte chain prefix-routes the type taxonomy — **both hierarchies, + one key**. `family` (u24) is the `(part_of:is_a)` level-3 ontological basin. + `connected_to` lands in the EdgeBlock shape: `part_of` siblings = in-family + (≤12), `is_a` parent = out-of-family (≤4). +- Identity is the golden-stride mint (`GOLDEN_RATIO × EULER_GAMMA`), with a + linear-probe collision guard against a `HashSet<[u8;16]>`. + +This is the model for any consumer that must stay free of the lance/datafusion +closure: **own the 16-byte layout as bytes, keep it byte-identical to `NodeGuid`, +and you are on the canon without taking the dependency.** When fma later wants the +typed surface, it swaps `node_guid_bytes(...)` → `NodeGuid::new(...).as_bytes()` +with no on-disk change (the bytes are already canonical). + +### 2.4 Generic consumer — the 5-step recipe + +Applies to medcare-rs, woa-rs, arcgis, a `ruff`/`ty` AST, any graph/record store: + +1. **Replace bespoke ids with `NodeGuid`.** Start at the bottom of the ladder: + `NodeGuid::local(next_identity)` (classid=0, family=0). Your old flat id-space + keeps working; nothing else changes yet. (Or, if you can't take the dep, mint + the 16 bytes directly — see §2.3 fma.) +2. **Map your two ontological axes onto the key.** OGAR's recurring shape is two + orthogonal hierarchies: + - **subsumption / `is_a` / kind-of** → the **low-byte chain** of the HHTL tiers + (and/or `classid` for the coarse class). "What it is." + - **parthood / `part_of` / contained-in** → the **high-byte chain** of the HHTL + tiers (and `family` for the basin). "Where it sits." + Each tier byte is a stable **sibling-rank** under its parent (1-based; + `converge.rs` and `osint-bake/fma.rs` both do exactly this), so the cascade IS + the path — no edge lookup to place a node. +3. **Lateral relations → `EdgeBlock`.** The non-tree edges (your "connects-to", + "references", "calls") go in the 12 in-family + 4 out-of-family byte slots — + each byte a palette/centroid index or a local adjacency handle. Reserve the + block even if you don't fill it. +4. **Payload → value tenants via a `ValueSchema` preset.** Pick `Bootstrap` (no + payload), `Cognitive` (hot lifecycle columns), `Compressed` (codec residues), + or `Full`. Write fields at `ValueTenant::value_offset()`. Need a tenant that + doesn't exist? That's a Core gap — extend the Core (§5), don't bolt state onto + an adapter. +5. **Inherit the powers for free.** Once your data wears the key, key-only routing + (§3) and SoA scans (§3) work without any further code — they are properties of + the 16-byte key, not of your consumer. + +The recipe is monotonic with the ladder: you can stop after step 1 and still +ship; steps 2–4 light up routing/basins/payload incrementally; step 5 costs +nothing. + +--- + +## 3. New superpowers for DATA representation + +### 3.1 Prefix-routed subtree selection — O(1) candidate filter + +The key prerenders nodes with **zero value decode**: classid → the class template, +HEEL/HIP/TWIG → the cascade position, family → the neighborhood, identity → the +instance. "Draw the skeleton subtree" is `classid == 0x0A02` — a 4-byte compare, +no value touched. Because the codebooks are built as a 4-level 4-ary hierarchy +(256 = 4⁴), a tier byte's nibbles are a centroid's ancestry, so `is_ancestor_of` +is centroid-tree containment and a prefix match is a reachability test that +replaces a graph walk. **CONJECTURE** (hierarchical-4⁴-vs-flat-256 fidelity is a +named-but-unrun test in the OGAR canon): treat the centroid-tree containment claim +as conjecture until that probe is green; the *byte-prefix* routing itself is +shipped and exact. + +### 3.2 Key-only SoA scan — ~30× less memory, measured + +`/home/user/q2/fma/src/bin/soa_scan.rs` lays out `NodeRow` columnar — a contiguous +16-byte **key column** and a contiguous 480-byte **value column** — and compares: + +- **key-only** (prefix-route / render-select): stream 16 B/row, compare classid. +- **value** (decode the slab): stream 480 B/row, sum the bytes. + +The key-only scan touches **16 B/row vs 480 B/row → ~30× less memory**, and stays +flat as N grows (measured at 64K / 256K / 1M synthetic rows, best-of-5). The doc's +own summary line: *"key-only touches 16 B/row vs 480 B/row (30× less); routing / +render-select needs NO value decode."* This is the same prefix routing the +`/fma`-body skeleton button does, measured at scale. + +> Note on the "~90×" figure: the **memory-traffic** ratio is 480/16 = 30×. A +> larger wall-clock speedup (the work-per-byte gap: a 4-byte compare vs a +> 480-iteration sum) is what `soa_scan` prints as the `speedup` column; cite the +> 30× memory ratio as the load-bearing number and let the binary report the +> wall-clock multiple for the host it runs on. + +### 3.3 Zero-copy Lance columnar I/O + +`NodeRowPacket` implements `SoaEnvelope`; `as_le_bytes()` is the slice reinterpreted +as `&[u8]` (zero-copy, pointer-identical — test `single_row_packet_verifies_and_byte_view_is_zero_copy`). +Lance writes those LE bytes from the in-place backing store. Nothing serializes +between "row in memory" and "row in Lance" — the envelope is zero-copy from +creation to tombstone. + +### 3.4 Compression without losing addressability + +The key is **never compressed**; the value can be anything Lance wants — columnar +encodings, dictionary, PQ. So the store keeps a transparent view and a stable +address regardless of how aggressively the 480-byte value is squeezed. Compression +never costs addressability, because addressing lives entirely in the 16 bytes that +are never touched by the value codec. The `EdgeCodecFlavor` / `ValueSchema` choices +are *interpretations of reserved bytes* — `is_layout_preserving()` is `const true` +for all of them, so a compression/codec change is never an `ENVELOPE_LAYOUT_VERSION` +bump. + +--- + +## 4. New superpowers for AST (core-first transcode) + +The same key that addresses data addresses **code**. An AST node becomes a +canonical GUID, and a program becomes a `&[NodeRow]`. + +### 4.1 Guid-shaped AST + +Each AST node = one `NodeGuid`. `classid` = the node kind (a function, a class, a +call, an `if`); HEEL/HIP/TWIG = its position in the program's containment cascade +(module → class → method → block); family = its basin; identity = the node's stable +id. The program is a columnar `&[NodeRow]` — the same SoA the data path uses. + +### 4.2 classid-keyed thin adapters (the core-first inversion) + +Per the OGAR Core-First doctrine: a generated layer (codegen'd Rust, AST adapters) +is only ever as clean as the Core it targets, so the **OGAR Core is shaped first, +deliberately** and adapters are emitted *thin and classid-keyed, assuming the +Core*: + +- **identity = `classid`** (the node kind routes to its template), +- **state = SoA value tenants** (the node's payload, never carried by the adapter), +- **relations = `EdgeBlock`** (lateral edges between AST nodes), +- **composition / inheritance = `classid → ClassView`** (method resolution), +- **invocation = `UnifiedStep`** (the canonical bridge). + +A C++→Rust transcode (e.g. Tesseract) emits one thin adapter per leaf method, each +keyed by `classid`. **Never** build a parallel object model; **never** let an +adapter carry its own state (a Core gap → extend the Core, §5); **never** force an +intrusive/stateful method into the adapter mold (route it to a raw-pointer +hand-port — the Frankenstein-flattening guard). This holds for mechanical / +data-shaped leaf methods only and is **CONJECTURE** until the +`PROBE-OGAR-ADAPTER-UNICHARSET` byte-parity probe is green. + +### 4.3 The SPO harvest IS the ClassView method-resolution manifest + +A `ruff_cpp_spo`-style SPO harvest (`has_function` / `inherits_from` / +`virtually_overrides`) over the C++ source is not a separate artifact from the +codegen — it is the **ClassView method-resolution manifest**. `classid → ClassView` +answers "which method body runs for this node" by reading the harvested +`inherits_from` / `virtually_overrides` chain. The harvest and the codegen are two +halves of one system. + +### 4.4 Prefix-routed program structure + key-only code scans + +Everything §3 gives data, AST gets too: + +- **Subsumption / parthood as prefix matches.** "All methods of class C" = a + HEEL/HIP prefix scan; "is node A inside scope B" = a prefix containment test — + no tree walk. +- **Key-only scans over code.** "Find every virtual override" / "every node of + kind K" = a 16-byte key-column scan (§3.2), 30× cheaper than materializing each + node's payload. Refactoring queries, call-graph slices, and visibility checks + become column scans over keys. +- **Method resolution via `classid → ClassView`** is an O(1) registry read, not a + graph traversal. + +--- + +## 5. Migration safety + +The whole design is engineered so adoption never needs a flag day. + +- **Zero-fallback ladder ⇒ start dormant.** `NodeGuid::local(id)` (classid=0, + family=0) is a drop-in for a flat id-space. Routing and basins stay *off* until + you mint non-zero tiers. Every consumer can ship at the bottom of the ladder and + climb later. +- **RESERVE, DON'T RECLAIM ⇒ no layout churn.** `classid` (4 B) and `family` (3 B) + hold fixed offsets that were reserved from day one. Minting a non-zero value + later wakes routing/basin binding with **ZERO `ENVELOPE_LAYOUT_VERSION` bump**. + Likewise every `ValueSchema` preset and `EdgeCodecFlavor` is layout-preserving + (`is_layout_preserving() == true` by const assertion) — a payload/codec change + is never a stride change. +- **`I-LEGACY-API-FEATURE-GATED` ⇒ no silent dual-semantics.** Any v1→v2 accessor + (e.g. the 6-group `NodeGuid::new` vs the in-flight 7-group `new_v2` that + `osint-bake/fma.rs` calls — §2.2) MUST transparently route through the canonical + mapping OR be feature-gated to a documented no-op with a migration pointer. The + same function name must never silently produce different semantics under + different features, and a layout reclaim must be paired with a version gate on + any serialization path. Field-isolation matrix tests are mandatory whenever a + layout reclaims previously-used bits. +- **Approval gate for upstream Core changes.** If a consumer needs a `ValueTenant`, + a `ClassView` capability, or a `NodeGuid` shape that doesn't exist (e.g. the + LEAF-bearing `new_v2`), **file an issue against lance-graph and surface it** — + do NOT reimplement it consumer-side. A Core gap is resolved by extending the + deliberate Core, never by hacking an adapter or forking the layout. The + `osint-bake` `new_v2` divergence in §2.2 is the live worked example of this gate. + +### Adoption checklist (per consumer) + +- [ ] Import `lance_graph_contract::canonical_node` (or commit to byte-identical + local minting, fma-style — §2.3). +- [ ] Replace primary ids with `NodeGuid` (`::local(id)` to start; classid=0, + family=0). +- [ ] Map subsumption → low-byte/`classid`, parthood → high-byte/`family` (§2.4 step 2). +- [ ] Move lateral relations into `EdgeBlock` (12+4). +- [ ] Choose a `ValueSchema` preset; write payload at `ValueTenant::value_offset()`. +- [ ] Lay rows out columnar (`Vec` or split key/value columns) → inherit + key-only scan + zero-copy Lance I/O. +- [ ] File an issue for any missing tenant / ClassView capability / NodeGuid shape + instead of reimplementing it (the §2.2 `new_v2` gate). diff --git a/fma/docs/V3_SOA_WIRING.md b/fma/docs/V3_SOA_WIRING.md new file mode 100644 index 000000000..7a885f26a --- /dev/null +++ b/fma/docs/V3_SOA_WIRING.md @@ -0,0 +1,359 @@ +# V3 SoA Wiring — `(part_of:is_a)` canonical-NodeGuid addressing + +> What this documents: the **v3** FMA addressing that landed with `converge.rs` + +> `graph.rs` + `soa_scan.rs` (q2 PR #59, merged). It wires the OGAR canonical +> 16-byte `NodeGuid` / 512-byte `NodeRow` SoA from +> `lance_graph_contract::canonical_node` into a real, rendered, measured pipeline, +> and packs **two hierarchies into one key**: `part_of` (where, mereology) in the +> high byte of each HHTL tier, `is_a` (what, taxonomy) in the low byte. +> +> Everything below is grounded in source. Byte offsets come from +> `canonical_node.rs`; mint logic from `src/bin/converge.rs`; prefix-render from +> `src/bin/graph.rs`; measured throughput from `src/bin/soa_scan.rs`. Speculative +> extrapolations are marked **CONJECTURE**. + +--- + +## 1. The canonical `NodeGuid` + `NodeRow` SoA + +### 1.1 The 16-byte key (byte offsets are the contract) + +`lance_graph_contract::canonical_node::NodeGuid` is `#[repr(C, align(16))]` +around `[u8; 16]`, little-endian throughout, with a `const _: () = +assert!(size_of::() == 16)` lock. The six canonical groups: + +```text + byte range field width role + ────────── ───── ───── ──── + 0..4 classid u32 prefix-routable class id; default 0x0000_0000 + 4..6 HEEL u16 ┐ + 6..8 HIP u16 ├ 3 HHTL cascade tiers (the path) + 8..10 TWIG u16 ┘ + 10..13 family u24 ┐ trailing 6 bytes = basin-local key + 13..16 identity u24 ┘ (one masked load once the prefix is bound) +``` + +`Display` renders the canonical self-describing `8-4-4-4-12` hex form, dash-groups +== semantic delimiters (OGAR P0): + +```text +classid -HEEL-HIP -TWIG-family·identity +deadbeef-1111-2222-3333-0000ab0000cd (NodeGuid::new(0xDEAD_BEEF, 0x1111, 0x2222, 0x3333, 0xAB, 0xCD)) +``` + +The trailing 6 bytes `[10..16)` (`family ++ identity`) are contiguous and form +`local_key()` — a single masked `u64` load that is the **only** discriminator once +an HHTL radix walk has bound `classid·HEEL·HIP·TWIG`. `decode()` reads the whole +key in one shot into `GuidParts { classid, heel, hip, twig, family, identity }` — +the "read the GUID as a GUID" surface, six fields in canon print order, nothing +invented or dropped. + +### 1.2 The 512-byte row + +`NodeRow` is `#[repr(C, align(64))]`, locked at 512 bytes +(`assert!(size_of::() == 512)`): + +```text + byte range field bytes what + ────────── ───── ───── ──── + 0..16 key 16 NodeGuid (the address) + 16..32 edges 16 EdgeBlock: 12 in-family + 4 out-of-family + 32..512 value 480 deferred value slab (Lance-compressible) +``` + +`NODE_ROW_COLUMNS` describes the three top-level slots as columns (key @ 0 / 16 B, +edges @ 16 / 16 B, value @ 32 / 480 B; Σ = 512 = `NODE_ROW_STRIDE`), and +`NodeRowPacket` is a **zero-copy** `SoaEnvelope` over `&[NodeRow]`: because +`NodeRow` is `repr(C)` with the locked layout, a `&[NodeRow]` *is already* a +row-strided LE byte packet at stride 512. `as_le_bytes()` is a `from_raw_parts` +re-view with no allocation and no translation — Lance's columnar I/O reads the +in-place backing store directly. (The `single_row_packet_verifies_and_byte_view_is_zero_copy` +test asserts `as_le_bytes().as_ptr() == rows.as_ptr()`.) + +The value slab is itself class-carved but not surfaced as its own envelope column: +`ValueTenant` (Meta / Qualia / MaterializedEdges / Fingerprint / HelixResidue / +TurbovecResidue / Energy / Plasticity / EntityType) gives a stable, contiguous, +compile-asserted byte carve; `ValueSchema` presets (Bootstrap / Cognitive / +Compressed / Full) pick which tenants materialize. Every preset and every +`EdgeCodecFlavor` is **layout-preserving** — `is_layout_preserving()` is `const +true` for all of them, so adopting a schema never bumps `ENVELOPE_LAYOUT_VERSION`. +This is the canon's value-side analog of "which XSD parses this document": +`classid → ReadMode { value_schema, edge_codec }` via the `BUILTIN_READ_MODES` +`LazyLock` registry, with any unconfigured classid falling through to +`ReadMode::DEFAULT`. + +### 1.3 The zero-fallback ladder + +Monotonic — a zero tier means "not consulted", **never** "compacted away" +("RESERVE, DON'T RECLAIM"): + +- `classid == 0x0000_0000` → default class, no prefix routing (dormant). +- `family == 0x00_0000` → default basin, no neighborhood grouping (dormant). +- ⇒ while both are zero, `identity` (24 bits, 16.7 M slots) **alone** discriminates + — the bootstrap address. `is_bootstrap_address()` guards exactly this state, and + `debug_assert_identity_unique()` enforces identity uniqueness while the family is + still a no-op. Minting a non-zero `family` later *wakes* basin binding with zero + layout change (the `classid(4B)` and `family(3B)` offsets are fixed). + +`NodeGuid::new` `assert!`s that `family <= 0x00FF_FFFF` and `identity <= +0x00FF_FFFF` — the silent-truncation footgun (two distinct u32 inputs collapsing to +the same stored 24-bit key) is a panic, including at const-eval. + +--- + +## 2. The `(part_of:is_a)` tile = `(place:tissue)` + +The v3 insight (`converge.rs`): **each HHTL tier is an 8:8 split**, packing two +orthogonal hierarchies into one `u16`. + +```text + tier (u16): ┌────────── high byte ──────────┬────────── low byte ──────────┐ + │ PLACE — WHERE it sits │ TISSUE — WHAT it is │ + │ part_of (mereology) │ is_a (taxonomy) │ + └─────────────────────────────────┴───────────────────────────────┘ + HEEL = (place₀ : tissue₀) HIP = (place₁ : tissue₁) TWIG = (place₂ : tissue₂) +``` + +The packer is literally `fn tier(hi: u8, lo: u8) -> u16 { ((hi as u16) << 8) | lo +as u16 }`. The **high-byte chain** (HEEL.hi → HIP.hi → TWIG.hi) prefix-routes the +*body*; the **low-byte chain** (HEEL.lo → HIP.lo → TWIG.lo) prefix-routes the *type +taxonomy*. Both hierarchies, one key, cascading HEEL → HIP → TWIG (coarse → fine). +`family` (u24 @ `[10..13)`) carries the level-3 basin as the same split: `((po_rank3 +as u32) << 8) | ia_rank3` — `(part_of:is_a)` one level deeper. + +### 2.1 classid dispatches the `place` mode (OGAR `HhtlMode`) + +`converge.rs` classifies each FMA node into `ConceptDomain::Anatomy` (`0x0A`): + +- `classid 0x0000_0A02` — **skeleton** (bone / cartilage / vertebra / rib / femur / + skull, via `is_skeletal()`). +- `classid 0x0000_0A01` — **soft tissue** (everything else). + +The `place` bytes are then dispatched on classid: + +- **Located** (skeleton `0x0A02` *with a centroid*): `place` is the **Morton + spatial cell** of the bone's mesh centroid. `morton3()` interleaves the three + quantized 8-bit axes into a 24-bit Z-order code; the three octets of that code + become the high bytes of HEEL/HIP/TWIG respectively (`(m>>16)&0xFF`, + `(m>>8)&0xFF`, `m&0xFF`). The exact anatomical anchor **is** the key — spatially + near bones share leading high-byte groups. +- **Cascade** (soft tissue `0x0A01`, or any node lacking a centroid): `place` is the + **`part_of` sibling-rank** at each level (`lvl(&po_ranks, 0..2)`) — ontological + place, inheriting position from the `part_of` basin's skeleton anchor. + +`tissue` (the low byte) is the **`is_a` sibling-rank** at each level +(`lvl(&ia_ranks, 0..2)`) in **both** modes. Sibling-rank comes from +`Tree::rank_of` — the IRI-sorted child index under the node's parent (stable, +`(k.min(254)) + 1`, 0 = root), so siblings get adjacent ranks and the tier prefixes +stay monotone with the hierarchy. + +`identity` (@ `[13..16)`) is the **golden-stride mint**: `golden_id24(k)` from +`GOLDEN_RATIO × EULER_GAMMA` (stride-4 / offset-20, the helix `CurveRuler` +generator), with a linear-probe `(identity + 1) & 0x00FF_FFFF` on the rare +collision against the `used` set. + +### 2.2 Worked examples (real `converge` output) + +Located skeleton — **thoracic vertebrae T9/T10/T11**, `classid 0x0A02`, mode +Located: + +```text + FMA10014 00000a02-ce01-fe02-7b02-… ↔ T10,T11,T12,… shared Morton HEEL ce = same spatial octant + FMA10059 00000a02-ce01-d602-eb02-… ↔ T9,T10,T12,… HIP/TWIG descend as the centroid descends (z 1164→1107) +``` + +Both vertebrae share `classid 0x0A02` and the **same HEEL high byte `ce`** — they +sit in the same spatial octant of the body, so their addresses agree on the coarsest +spatial group. HIP and TWIG diverge as the centroid descends. The low bytes (`01`, +`02`) are the `is_a` ranks (the bone taxonomy position). + +Cascade soft tissue — **aortic segments**, `classid 0x0A01`, mode Cascade: + +```text + FMA3736 ascending aorta 00000a01-0901-0702-0e02-… ↔ arch, descending part_of siblings = the connected segments +``` + +The ascending aorta, the arch, and the descending aorta are `part_of` siblings of +the same aorta; they share the leading `part_of` high-byte groups (`09`, `07`, `0e` +…) and are connected to each other (§3). The `connected_to` column lists exactly the +sibling segments that physically continue the vessel. + +The upshot, made visible in `graph.rs`: a single key prefix `00000a01-0901-0702` +selects "one `part_of`/`is_a` subtree" of triangles; `00000a02` selects the whole +skeleton. **The address is the query.** + +--- + +## 3. `connected_to` = the EdgeBlock + +`converge.rs` fills the canonical 16-byte `EdgeBlock` (12 in-family + 4 +out-of-family) with the **anatomical adjacency graph**: + +- **in-family** (≤ 12 slots) = **`part_of` siblings** (`Tree::siblings` — the + co-parts under the same `part_of` parent). For the aorta these are the aortic + segments; for the heart, the chambers — *the sub-parts that physically connect*. + v3 emits one `in_family:part_of_sibling` edge row per sibling (capped at 12, the + in-family slot count). +- **out-of-family** (≤ 4 slots) = the **`is_a` parent** (the type link), emitted as + `out_family:is_a_parent`. + +This is the canon's "a class opting out of edges is resolved via `classid → +ClassView`, never a stride change" used positively: anatomy populates the reserved +block with mereological adjacency, so "70K nodes connecting via relationships" is +carried in the same 512-byte row as the address — the relationships **are** the +key's neighbors. The edge byte (one per slot) is a palette/centroid index under the +default `EdgeCodecFlavor::CoarseOnly`; the manifest's human-readable `connected_to` +column carries the sibling FMA ids for inspection. + +--- + +## 4. The SoA superpower: key-only scan, zero value decode + +This is the OGAR canon's "**the key prerenders nodes with zero value decode**", +measured. `soa_scan.rs` lays the 512-byte `NodeRow` out **columnar** (struct-of- +arrays): a contiguous 16-byte key column (`Vec<[u8; 16]>`) and a contiguous 480-byte +value column (`Vec<[u8; 480]>`), separate allocations. Two scans over 1 M synthetic +rows (seeded by the FMA distribution: ~25 % skeleton classid, the rest soft tissue): + +- **key-only (prefix-route / render-select):** read only the key column; decode + `classid` from bytes `[0..4)`; count the skeleton subtree (`== 0x0000_0A02`). This + is exactly the work the `/fma-body` skeleton button and `graph 00000a02` do. +- **value (decode the slab):** read the whole value column; sum all 480 bytes per + row — the work a value/tenant materialization does. + +Measured (real numbers from `soa_scan`, the q2 PR #59 run): + +| scan | throughput | bandwidth | scales with N | +| -------------------------- | ----------------- | --------- | ------------- | +| key-only (route) | **~1.5 G rows/s** | ~24 GB/s | **flat** | +| value (decode 480 B slab) | ~17 M rows/s | ~8 GB/s | flat | +| **speedup** | **89–130×** | — | | + +(The README summarizes this as "~90× at 1M".) The key-only scan touches **16 B/row +vs 480 B/row — 30× less memory** — and the realized speedup (89–130×) exceeds the +raw byte ratio because the 16-byte key column is cache-resident and streams at near +memory bandwidth while the 480-byte value column is RAM-bound. Crucially the ratio +is **flat as N grows** (64 K → 256 K → 1 M): routing/render-select is a property of +the key column's size, not the dataset's. + +Why this falls out of the layout, not a trick: + +- The discriminator a router needs — `classid` (and HEEL/HIP/TWIG for finer routing) + — lives in the first 16 bytes, never in the value. +- Lance is free to compress the 480-byte value arbitrarily (columnar, dictionary, + PQ); the key is never compressed and never needs the value decoded to be useful — + **compression never costs addressability** (canon §"the GUID is the key of + key-value"). +- A prefix match on the key column is a `starts_with` over 16-byte rows; the + zero-fallback ladder means even an all-default node is addressable by `identity` + alone. + +`graph.rs` is the same routing at render time, not at scan time: it reads the +converged manifest, and a `sel` that is all-hex-or-dash is treated as a GUID prefix — +`guid.starts_with(&sel)` selects which meshes' triangles to rasterize. `graph … +00000a02` renders ~922 K skeleton triangles; `graph all` / `tissues` / `vessel` +render the whole body / inner tissues / vascular tree. The address selects the +geometry; the prefix is the query — and it never decodes a value slab to decide. + +--- + +## 5. Implications for GUID-shaped ASTs / rails-shaped programs + +The v3 wiring demonstrates a general substrate property on anatomy; the same +machinery applies to **code**. An AST node and an anatomical part are both +"something with a parent (`part_of` / enclosing scope), a type (`is_a` / node kind), +siblings (co-parts / sibling statements), and an identity". The canonical `NodeGuid` +is anatomy-agnostic — `converge.rs` is one *consumer* of a contract that says nothing +about bones. The OGAR canon (`core-first-transcode-doctrine`) already frames code +this way: identity = `classid`, state = SoA value tenants, relations = `EdgeBlock`, +composition/inheritance = `classid → ClassView`, invocation = `UnifiedStep`. + +### 5.1 Each AST node addressed by a canonical GUID + +Grounded in the canon's stated structure: a transcoded program's AST node becomes a +`NodeRow` whose `classid` is the node kind (the C++/Tesseract `classid` the OGAR +`ruff_cpp_spo` harvest already assigns), whose HHTL tiers are the node's position in +the program tree, whose `family`/`identity` discriminate within a basin, and whose +`EdgeBlock` carries its structural neighbors. The OGAR canon states this directly: +"the key prerenders nodes — in any way — with zero value decode … a +renderer/router/planner can lay out, group, route, and skeleton-render nodes from +keys alone". An AST is exactly such a thing to lay out and route. + +### 5.2 The `(place:tissue)` tile maps to `(scope:kind)` — **CONJECTURE** + +**CONJECTURE.** The v3 8:8 tier — `(part_of:is_a)` = `(where:what)` — has a direct +code analog: `(enclosing-scope-rank : node-kind-rank)`. The high-byte chain would +prefix-route *structural containment* (module → class → function → block, the +program's `part_of`), the low-byte chain would prefix-route *syntactic kind* (the +`is_a` of `Expr`/`Stmt`/`Decl`/…). Two program hierarchies in one key, exactly as +anatomy packs mereology + taxonomy. This is a transfer of the *mechanism* v3 ships, +not something v3 itself implements for code; the FMA pipeline is the existence proof +that the tile carries two independent prefix-routable hierarchies losslessly. + +### 5.3 Subsumption / parthood become prefix matches + +Grounded: in v3, "is this part inside the aorta subtree?" and "is this bone in that +spatial octant?" are both `guid.starts_with(prefix)` (the `graph.rs` selector). The +same operation answers, for code, "is this node inside that function body?" (a +`part_of`/scope prefix) and "is this an expression?" (an `is_a`/kind prefix) — **if** +the AST is minted with the §5.2 tile (CONJECTURE). The canon's hierarchical-prefix +rule ("`is_ancestor_of` = centroid-tree containment", longest-prefix-wins) is the +general statement; v3 is the anatomy instance. + +### 5.4 Key-only scans over code + +Grounded by §4's measurement (the substrate is content-blind): a 1 M-node program +AST laid out as a `NodeRow` SoA would route the same way the FMA skeleton does — +"select every `FunctionDecl`" is a `classid`-prefix scan over the 16-byte key column +at ~1.5 G rows/s, never decoding the value slab (which would hold the node's +spans/attributes/fingerprint). "Find every node under this module" is an HHTL-prefix +scan. The flat-as-N property means whole-program structural queries stay +cache-resident regardless of program size. (CONJECTURE that real programs hit the +same constant; the *layout* guarantee — key column is 16 B/row independent of value +size — is not a conjecture.) + +### 5.5 OGAR Active-Record / "rails-shaped" programs off the guid-addressed AST + +**CONJECTURE (framing), grounded in the OGAR canon.** OGAR = *Open Graph of Active +Record*. A "rails-shaped" program is one whose objects are rows in this key-value +store keyed by the canonical GUID: identity is the key, state lives in the value +tenants, relations are the `EdgeBlock`, and method resolution is `classid → +ClassView` (the canon's stated mapping). The v3 anatomy graph is structurally that +object graph — `connected_to` is the relation column, `tissue`/`place` are +addressable attributes, and the renderer is a *consumer* that reads only what it +needs from the key. An Active-Record program over a guid-addressed AST would behave +the same: a "find" is a prefix scan (§5.4), a "belongs_to"/"has_many" traversal is an +`EdgeBlock` read (§3), a "type-of" dispatch is a `classid → ClassView` lookup. The +load-bearing claim is the canon's: AGI/program behavior is the runtime behavior of +the SoA under dispatch, *not* a new layer wrapped around it. + +### 5.6 classid-keyed adapters (core-first transcode) + +Grounded in the OGAR doctrine: the transcode of a C++ method becomes a **thin, +classid-keyed adapter that ASSUMES the Core** — it reads inputs from the value +tenants, writes outputs back to value tenants, defers composition to `ClassView`, and +carries **no state of its own**. v3 is a small validation of the Core-first stance: +`converge.rs` did not invent a parallel node model — it emits bytes *byte-identical* +to `NodeGuid::new` (the header asserts this), treating the canonical node as the Core +and the anatomy mint as an adapter over it. The doctrine's guard applies unchanged to +code: a method that needs state the value tenants can't carry, or a dispatch the +`ClassView` can't express, is a **Core gap → extend the Core deliberately**, never +hack the adapter; intrusive/stateful methods route to hand-port. (Per the canon, this +holds for mechanical/data-shaped leaf methods and remains CONJECTURE until +`PROBE-OGAR-ADAPTER-UNICHARSET` runs byte-parity green.) + +--- + +## Source map + +| Claim | Source | +| ------------------------------------------------ | ----------------------------------------------------------------- | +| 16 B key layout, offsets, zero-fallback ladder | `lance-graph/crates/lance-graph-contract/src/canonical_node.rs` | +| 512 B `NodeRow`, columns, zero-copy envelope | same — `NodeRow`, `NODE_ROW_COLUMNS`, `NodeRowPacket` | +| value tenants / schemas / `classid → ReadMode` | same — `ValueTenant`, `ValueSchema`, `classid_read_mode` | +| `(place:tissue)` 8:8 tier, Located/Cascade, mint | `q2/fma/src/bin/converge.rs` | +| `connected_to` EdgeBlock from `part_of` siblings | `q2/fma/src/bin/converge.rs` (`siblings`, edge emit) | +| prefix-routed render (`graph 00000a02`) | `q2/fma/src/bin/graph.rs` | +| key-only vs value scan, 89–130×, flat | `q2/fma/src/bin/soa_scan.rs` | +| three coexisting v1/v2/v3 addressings | `q2/fma/README.md` | +| GUID-is-key, key-prerenders, classid adapters | `OGAR/CLAUDE.md`, `core-first-transcode-doctrine` | diff --git a/fma/src/bin/cockpit_bake.rs b/fma/src/bin/cockpit_bake.rs index 705314139..50559d4e8 100644 --- a/fma/src/bin/cockpit_bake.rs +++ b/fma/src/bin/cockpit_bake.rs @@ -125,10 +125,11 @@ fn main() { let out_path = a.get(4).cloned().unwrap_or_else(|| "cockpit/public/fma_body.mesh".into()); let cell_mm: f32 = a.get(5).and_then(|s| s.parse().ok()).unwrap_or(3.6); - // converged key: FMA → (tissue, part_of depth, row). + // converged key: FMA → (tissue, part_of depth, row, name). let mut fma_tissue: HashMap = HashMap::new(); let mut fma_depth: HashMap = HashMap::new(); let mut fma_row: HashMap = HashMap::new(); + let mut fma_name: HashMap = HashMap::new(); for (i, line) in std::fs::read_to_string(&conv_path).unwrap_or_default().lines().enumerate() { if i == 0 { continue; @@ -138,6 +139,8 @@ fn main() { fma_row.insert(f[0].into(), (fma_tissue.len() & 0xFFFF) as u16); fma_tissue.insert(f[0].into(), f[4].into()); fma_depth.insert(f[0].into(), f[6].matches(" / ").count()); + // name = the deepest segment of the part_of distinguished name. + fma_name.insert(f[0].into(), f[6].rsplit(" / ").next().unwrap_or(f[0]).trim().to_string()); } } let mut fj_fma: HashMap> = HashMap::new(); @@ -255,8 +258,8 @@ fn main() { buf.extend_from_slice(&v.to_le_bytes()); } for i in 0..pos.len() { - for k in 0..3 { - buf.extend_from_slice(&pos[i][k].to_le_bytes()); + for c in pos[i] { + buf.extend_from_slice(&c.to_le_bytes()); } buf.push(qi8(nrm[i][0]) as u8); buf.push(qi8(nrm[i][1]) as u8); @@ -287,6 +290,24 @@ fn main() { ); File::create(&manifest_path).unwrap().write_all(manifest.as_bytes()).unwrap(); - eprintln!("[cockpit_bake] {} verts, {} tris -> {out_path} ({} MB) + manifest", pos.len(), tris.len(), buf.len() / 1_000_000); + // search index: row → {fma, name, tissue} for the nodes present in the mesh. Drives the + // /fma-body search bar; per-node centroids are computed client-side from `node_row`. + let used: std::collections::HashSet = row.iter().copied().collect(); + let mut node_entries: Vec<(u16, &String, &String, &String)> = fma_row + .iter() + .filter(|(_, r)| used.contains(r)) + .filter_map(|(fma, r)| Some((*r, fma, fma_name.get(fma)?, fma_tissue.get(fma)?))) + .collect(); + node_entries.sort_by_key(|&(r, ..)| r); + let esc = |s: &str| s.replace('\\', "\\\\").replace('"', "\\\""); + let nodes_json: String = node_entries + .iter() + .map(|(r, fma, name, tissue)| format!("{{\"row\":{r},\"fma\":\"{}\",\"name\":\"{}\",\"tissue\":\"{}\"}}", esc(fma), esc(name), esc(tissue))) + .collect::>() + .join(","); + let nodes_path = format!("{out_path}.nodes.json"); + File::create(&nodes_path).unwrap().write_all(format!("{{\"nodes\":[{nodes_json}]}}").as_bytes()).unwrap(); + + eprintln!("[cockpit_bake] {} verts, {} tris -> {out_path} ({} MB) + manifest + {} search nodes", pos.len(), tris.len(), buf.len() / 1_000_000, node_entries.len()); eprintln!("[cockpit_bake] opacity byte = LAYER id; layers: {layers:?}"); }