code wiki / (root) / nx_peptide_chain.nx

nx_peptide_chain.nx source

↩ module page · 147 lines · 5660 B

1// nx_peptide_chain.nx -- CHEMISTRY SUITE / MULTI-CHAIN PEPTIDE rung. Closes 2// the last gap the peptide lane declared: an assembly of SEVERAL chains held 3// together by disulfide bridges. Insulin is the case that matters -- two 4// chains, three bridges, and one of the most counterfeited biologics there 5// is -- and nothing before this could weigh it. 6// 7// WHY IT IS NOT JUST "ADD THE CHAINS UP". Two things break that: 8// 1. Every chain carries its OWN terminal water, so an N-chain assembly 9// has N waters, not one. Treating insulin as a single 51-residue 10// sequence is short by a whole water (18.011 Da). 11// 2. Bridges are owned by the ASSEMBLY, not by any chain. An inter-chain 12// disulfide belongs to neither A nor B. So pca_add_chain REFUSES a 13// builder that already carries its own bridges -- otherwise the same 14// -2.016 Da gets subtracted twice and the answer looks plausible. 15// 16// INTRA AND INTER ARE TRACKED SEPARATELY, because they mean different 17// things. Both cost the same mass, but only INTER-chain bridges hold the 18// assembly together: linking N chains needs at least N-1 of them. 19// pca_is_covalently_linked enforces exactly that, so a "two-chain" molecule 20// with only intra-chain bridges is correctly reported as two separate 21// peptides that happen to be in the same tube. 22// 23// THE CYSTEINE BUDGET IS A REAL CONSTRAINT, NOT A FORMALITY. Each bridge 24// consumes two cysteines, and a claim of more bridges than the sequences 25// can supply produces a mass that looks entirely reasonable. Insulin is 26// the perfect witness: 6 cysteines, 3 bridges, ZERO left over. 27// 28// Grounding (cited; researcher-groundable): 29// published_monoisotopic_mass_human_insulin_5803_6375 (the anchor) 30// human_insulin_a_b_chain_sequences_and_disulfide_map 31// disulfide_bond_two_hydrogen_loss (via nx_peptide_ext) 32// 33// genealogy_id: peptide_chemistry + nishi_chem_suite 34 35import "nx_syscalls.nx" 36import "nx_peptide.nx" 37import "nx_peptide_ext.nx" 38 39// ===== The assembly =================================================== 40 41struct NxPepAssembly { 42 mass_sum_q4: i64, // sum of finished chain masses, each with its water 43 n_chains: i64, 44 n_cys: i64, 45 n_ss_intra: i64, 46 n_ss_inter: i64, 47 valid: i64, 48} 49 50func nx_pep_assembly_new() -> *NxPepAssembly { 51 let a: *NxPepAssembly = (sys_mmap(64)) as *NxPepAssembly 52 a.mass_sum_q4 = 0 53 a.n_chains = 0 54 a.n_cys = 0 55 a.n_ss_intra = 0 56 a.n_ss_inter = 0 57 a.valid = 1 58 return a 59} 60 61// Cysteines in a standard sequence -- the bridge budget's supply side. 62func pca_count_cys(seq: *u8) -> i64 { 63 return pep_count_aa(seq, PEP_C) 64} 65 66// Add a finished chain. REFUSES a builder that carries its own bridges: 67// those belong to the assembly, and accepting them here would subtract the 68// same mass twice. 69func pca_add_chain(a: *NxPepAssembly, b: *NxPepBuild, n_cys: i64) -> i64 { 70 if b.n_ss != 0 { a.valid = 0; return 0 } 71 let m: i64 = pex_mass_q4(b) 72 if m == PEP_INVALID { a.valid = 0; return 0 } 73 a.mass_sum_q4 = a.mass_sum_q4 + m 74 a.n_chains = a.n_chains + 1 75 a.n_cys = a.n_cys + n_cys 76 return a.valid 77} 78 79// Convenience for a plain standard-residue chain: builds it, counts its own 80// cysteines, and adds it. 81func pca_add_chain_seq(a: *NxPepAssembly, seq: *u8) -> i64 { 82 let b: *NxPepBuild = nx_pep_build_new() 83 pex_add_seq(b, seq) 84 let nc: i64 = pca_count_cys(seq) 85 return pca_add_chain(a, b, nc) 86} 87 88func pca_add_intra_disulfide(a: *NxPepAssembly) -> i64 { a.n_ss_intra = a.n_ss_intra + 1; return 0 } 89func pca_add_inter_disulfide(a: *NxPepAssembly) -> i64 { a.n_ss_inter = a.n_ss_inter + 1; return 0 } 90 91func pca_total_ss(a: *NxPepAssembly) -> i64 { 92 return a.n_ss_intra + a.n_ss_inter 93} 94 95// ===== Structural validity ============================================ 96 97// Cysteines left unpaired. NEGATIVE means the assembly claims more bridges 98// than its sequences can supply -- chemically impossible. 99func pca_free_cys(a: *NxPepAssembly) -> i64 { 100 let used: i64 = pca_total_ss(a) * 2 101 return a.n_cys - used 102} 103 104func pca_bridges_possible(a: *NxPepAssembly) -> i64 { 105 let free: i64 = pca_free_cys(a) 106 if free < 0 { return 0 } 107 return 1 108} 109 110// N chains need at least N-1 INTER-chain bridges to be one molecule. 111func pca_is_covalently_linked(a: *NxPepAssembly) -> i64 { 112 if a.n_chains <= 0 { return 0 } 113 if a.n_chains == 1 { return 1 } 114 let need: i64 = a.n_chains - 1 115 if a.n_ss_inter >= need { return 1 } 116 return 0 117} 118 119// ===== Mass =========================================================== 120// 121// Sum of the chains (each already carrying its own water and terminal 122// modifications), less two hydrogens per bridge. REFUSES if the cysteine 123// budget is exceeded, because that mass would look perfectly reasonable. 124 125func pca_mass_q4(a: *NxPepAssembly) -> i64 { 126 if a.valid != 1 { return PEP_INVALID } 127 if a.n_chains <= 0 { return PEP_INVALID } 128 let ok: i64 = pca_bridges_possible(a) 129 if ok != 1 { return PEP_INVALID } 130 let ss: i64 = pca_total_ss(a) * PEX_SS_DELTA_Q4 131 return a.mass_sum_q4 + ss 132} 133 134// Reduced mass: every bridge broken, chains still summed. What a reducing 135// agent gives you, and the difference from pca_mass_q4 is a direct readout 136// of how many bridges were really there. 137func pca_mass_reduced_q4(a: *NxPepAssembly) -> i64 { 138 if a.valid != 1 { return PEP_INVALID } 139 if a.n_chains <= 0 { return PEP_INVALID } 140 return a.mass_sum_q4 141} 142 143func pca_mz_q4(a: *NxPepAssembly, z: i64) -> i64 { 144 let m: i64 = pca_mass_q4(a) 145 if m == PEP_INVALID { return PEP_INVALID } 146 return pep_mz_q4(m, z) 147}