From 5edfb1a6f90a9f1fb498be1ec8a85c26085d94ee Mon Sep 17 00:00:00 2001 From: David Koes Date: Fri, 5 Jul 2024 21:52:29 -0400 Subject: [PATCH] Checkpoint mmtf replacement. Still several regressions. --- src/parsers/BCIF.ts | 181 +++++++++++++++++++++---------------- src/utilities.ts | 21 +++-- tests/auto/tests/test60.js | 2 +- tests/auto/tests/test94.js | 2 +- 4 files changed, 114 insertions(+), 92 deletions(-) diff --git a/src/parsers/BCIF.ts b/src/parsers/BCIF.ts index d2b4a9058..85475c4fd 100644 --- a/src/parsers/BCIF.ts +++ b/src/parsers/BCIF.ts @@ -21,7 +21,7 @@ declare var MMTF: MMTFobj; */ export function BCIF(bindata: any, options: ParserOptionsSpec) { - //var noH = !options.keepH; // suppress hydrogens by default + var noH = !options.keepH; // suppress hydrogens by default //var selAltLoc = options.altLoc ? options.altLoc : 'A'; //default alternate location to select if present var computeStruct = !options.noComputeSecondaryStructure; //var assemblyIndex = options.assemblyIndex ? options.assemblyIndex : 0; @@ -77,50 +77,87 @@ export function BCIF(bindata: any, options: ParserOptionsSpec) { //helices let sslookup = {}; //chain to residue range let sshelix = cats.struct_conf; - let htypes = sshelix.getField('conf_type_id'); - let hchain = sshelix.getField('beg_label_asym_id'); - let hstart = sshelix.getField('beg_label_seq_id'); - let hend = sshelix.getField('end_label_seq_id'); - - for (let i = 0; i < htypes.length; i++) { - if (htypes[i].startsWith('H')) { - let ch = hchain[i]; - let startResi = hstart[i]; - let endResi = hend[i]; + if (sshelix) { + let htypes = sshelix.getField('conf_type_id'); + let hchain = sshelix.getField('beg_label_asym_id'); + let hstart = sshelix.getField('beg_label_seq_id'); + let hend = sshelix.getField('end_label_seq_id'); + + for (let i = 0; i < htypes.length; i++) { + if (htypes[i].startsWith('H')) { + let ch = hchain[i]; + let startResi = hstart[i]; + let endResi = hend[i]; + if (!(ch in sslookup)) { + sslookup[ch] = {}; + } + sslookup[ch][startResi] = "h1"; + for (let res = startResi + 1; res < endResi; res++) { + sslookup[ch][res] = "h"; + } + sslookup[ch][endResi] = "h2"; + } + } + } + //sheets + let sssheet = cats.struct_sheet_range; + if (sssheet) { + let sids = sssheet.getField('id'); + let schain = sssheet.getField('beg_label_asym_id'); + let sstart = sssheet.getField('beg_label_seq_id'); + let send = sssheet.getField('end_label_seq_id'); + + for (let i = 0; i < sids.length; i++) { + let ch = schain[i]; + let startResi = sstart[i]; + let endResi = send[i]; if (!(ch in sslookup)) { sslookup[ch] = {}; } - sslookup[ch][startResi] = "h1"; + sslookup[ch][startResi] = "s1"; for (let res = startResi + 1; res < endResi; res++) { - sslookup[ch][res] = "h"; + sslookup[ch][res] = "s"; } - sslookup[ch][endResi] = "h2"; - } - } + sslookup[ch][endResi] = "s2"; - //sheets - let sssheet = cats.struct_sheet_range; - let sids = sssheet.getField('id'); - let schain = sssheet.getField('beg_label_asym_id'); - let sstart = sssheet.getField('beg_label_seq_id'); - let send = sssheet.getField('end_label_seq_id'); - - for (let i = 0; i < sids.length; i++) { - let ch = schain[i]; - let startResi = sstart[i]; - let endResi = send[i]; - if (!(ch in sslookup)) { - sslookup[ch] = {}; - } - sslookup[ch][startResi] = "s1"; - for (let res = startResi + 1; res < endResi; res++) { - sslookup[ch][res] = "s"; } - sslookup[ch][endResi] = "s2"; - } + //symmetry operations + let structops = cats.pdbx_struct_oper_list; + let opids = structops.getField('id'); + if (opids && !noAssembly) { + let matrix11 = structops.getField('matrix[1][1]'); + let matrix12 = structops.getField('matrix[1][2]'); + let matrix13 = structops.getField('matrix[1][3]'); + let matrix21 = structops.getField('matrix[2][1]'); + let matrix22 = structops.getField('matrix[2][2]'); + let matrix23 = structops.getField('matrix[2][3]'); + let matrix31 = structops.getField('matrix[3][1]'); + let matrix32 = structops.getField('matrix[3][2]'); + let matrix33 = structops.getField('matrix[3][3]'); + let vector1 = structops.getField('vector[1]'); + let vector2 = structops.getField('vector[2]'); + let vector3 = structops.getField('vector[3]'); + for (let i = 0; i < opids.length; i++) { + const matrix = new Matrix4( + matrix11[i], + matrix12[i], + matrix13[i], + vector1[i], + matrix21[i], + matrix22[i], + matrix23[i], + vector2[i], + matrix31[i], + matrix32[i], + matrix33[i], + vector3[i] + ); + modelData[modelData.length - 1].symmetries.push(matrix); + } + } //atom info let asites = cats.atom_site; @@ -141,13 +178,27 @@ export function BCIF(bindata: any, options: ParserOptionsSpec) { let bfactors = asites.getField("B_iso_or_equiv"); let serials = asites.getField('id'); let icodes = asites.getField('label_alt_id'); + let modelnums = asites.getField('pdbx_PDB_model_num'); + let curmodel = modelnums ? modelnums[0] : 0; for (let i = 0; i < atomCount; i++) { - if ( - group_pdb !== undefined && + if (group_pdb !== undefined && group_pdb[i] === "TER" ) continue; + + if (modelnums && modelnums[i] != curmodel) { + curmodel = modelnums[i]; + if (options.multimodel) { + if (!options.onemol) { + atoms.push([]); + modelData.push(modelData[modelData.length-1]); + } + } else { + break; //first model only + } + } + const atom: AtomSpec = {}; atom.x = cartn_x[i]; atom.y = cartn_y[i]; @@ -159,16 +210,16 @@ export function BCIF(bindata: any, options: ParserOptionsSpec) { ? label_asym_id[i] : undefined; atom.lchain = label_asym_id - ? label_asym_id[i] - : undefined; + ? label_asym_id[i] + : undefined; atom.resi = auth_seq_id ? auth_seq_id[i] : label_seq_id ? label_seq_id[i] : undefined; atom.lresi = label_seq_id - ? label_seq_id[i] - : undefined; + ? label_seq_id[i] + : undefined; atom.resn = auth_comp_id ? auth_comp_id[i].trim() : label_comp_id @@ -193,6 +244,10 @@ export function BCIF(bindata: any, options: ParserOptionsSpec) { atom.elem = elem[0].toUpperCase() + elem.substring(1, 2).toLowerCase(); if (bfactors) atom.b = bfactors[i]; + if(noH && atom.elem == 'H') { + continue; + } + atom.bonds = []; atom.ss = "c"; atom.serial = serials[i]; @@ -203,43 +258,6 @@ export function BCIF(bindata: any, options: ParserOptionsSpec) { } - - //symmetry operations - let structops = cats.pdbx_struct_oper_list; - let opids = structops.getField('id'); - if (opids && !noAssembly) { - let matrix11 = structops.getField('matrix[1][1]'); - let matrix12 = structops.getField('matrix[1][2]'); - let matrix13 = structops.getField('matrix[1][3]'); - let matrix21 = structops.getField('matrix[2][1]'); - let matrix22 = structops.getField('matrix[2][2]'); - let matrix23 = structops.getField('matrix[2][3]'); - let matrix31 = structops.getField('matrix[3][1]'); - let matrix32 = structops.getField('matrix[3][2]'); - let matrix33 = structops.getField('matrix[3][3]'); - let vector1 = structops.getField('vector[1]'); - let vector2 = structops.getField('vector[2]'); - let vector3 = structops.getField('vector[3]'); - - for (let i = 0; i < opids.length; i++) { - const matrix = new Matrix4( - matrix11[i], - matrix12[i], - matrix13[i], - vector1[i], - matrix21[i], - matrix22[i], - matrix23[i], - vector2[i], - matrix31[i], - matrix32[i], - matrix33[i], - vector3[i] - ); - modelData[modelData.length - 1].symmetries.push(matrix); - } - } - // Assign secondary structures from pdb file if (!isEmpty(sslookup)) { let matoms = atoms[atoms.length - 1]; @@ -257,8 +275,11 @@ export function BCIF(bindata: any, options: ParserOptionsSpec) { } } - if (options.multimodel) { - if (!options.onemol) atoms.push([]); + if (options.multimodel && m < numModels - 1) { + if (!options.onemol) { + atoms.push([]); + modelData.push({ symmetries: [] }); + } } } diff --git a/src/utilities.ts b/src/utilities.ts index 740b0a4de..2627653d2 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -405,7 +405,6 @@ export function getbin(uri, callback?, request?, postdata?) { export function download(query, viewer, options, callback?) { var type = ""; var pdbUri = ""; - var mmtfUri = ""; var uri = ""; var promise = null; var m = viewer.addModel(); @@ -420,10 +419,13 @@ export function download(query, viewer, options, callback?) { query = 'url:' + query; } } - if (query.substring(0, 5) === 'mmtf:') { - pdbUri = options && options.pdbUri ? options.pdbUri : "https://mmtf.rcsb.org/v1.0/full/"; + if (query.substring(0,5) == 'mmtf:') { + console.log('WARNING: MMTF now deprecated. Reverting to bcif.'); + query = 'bcif:' + query.slice(5); + } + if (query.substring(0, 5) === 'bcif:') { query = query.substring(5).toUpperCase(); - uri = pdbUri + query; + uri = "https://models.rcsb.org/" + query + '.bcif.gz'; if (options && typeof options.noComputeSecondaryStructure === 'undefined') { //when fetch directly from pdb, trust structure annotations options.noComputeSecondaryStructure = true; @@ -431,7 +433,7 @@ export function download(query, viewer, options, callback?) { promise = new Promise(function (resolve) { getbin(uri) .then(function (ret) { - m.addMolData(ret, 'mmtf', options); + m.addMolData(ret, 'bcif.gz', options); viewer.zoomTo(); viewer.render(); resolve(m); @@ -440,7 +442,7 @@ export function download(query, viewer, options, callback?) { } else { if (query.substring(0, 4) === 'pdb:') { - type = 'mmtf'; + type = 'pdb'; if (options && options.format) { type = options.format; //can override and require pdb } @@ -454,9 +456,8 @@ export function download(query, viewer, options, callback?) { alert("Wrong PDB ID"); return; } - if (type == 'mmtf') { - mmtfUri = options && options.mmtfUri ? options.mmtfUri : 'https://mmtf.rcsb.org/v1.0/full/'; - uri = mmtfUri + query.toUpperCase(); + if (type == 'bcif') { + uri = 'https://models.rcsb.org/' + query.toUpperCase() + '.bcif.gz'; } else { pdbUri = options && options.pdbUri ? options.pdbUri : "https://files.rcsb.org/view/"; @@ -482,7 +483,7 @@ export function download(query, viewer, options, callback?) { viewer.render(); }; promise = new Promise(function (resolve) { - if (type == 'mmtf') { //binary data + if (type == 'bcif') { //binary data getbin(uri) .then(function (ret) { handler(ret); diff --git a/tests/auto/tests/test60.js b/tests/auto/tests/test60.js index 3229607ad..57d903b96 100644 --- a/tests/auto/tests/test60.js +++ b/tests/auto/tests/test60.js @@ -1,6 +1,6 @@ - $3Dmol.download('pdb:1pfl',viewer,{},function(m) { + $3Dmol.download('bcif:1pfl',viewer,{},function(m) { m.setStyle({'cartoon':{colorscheme:'ssPyMol'}}); viewer.zoomTo(); viewer.render(); diff --git a/tests/auto/tests/test94.js b/tests/auto/tests/test94.js index 2aecbb648..f3b419a64 100644 --- a/tests/auto/tests/test94.js +++ b/tests/auto/tests/test94.js @@ -1,5 +1,5 @@ - $3Dmol.download("pdb:2V0E",viewer,{multimodel:true, frames:true}) + $3Dmol.download("bcif:2V0E",viewer,{multimodel:true, frames:true}) .then(function(m1){ $3Dmol.download("mmtf:4HHB",viewer,{multimodel:true, frames:true}) .then(function(m2){