| import { base64ToArray } from "../utilities"; |
| import { Matrix4 } from "../WebGL"; |
| import { ParserOptionsSpec } from "./ParserOptionsSpec"; |
| import { computeSecondaryStructure } from "./utils/computeSecondaryStructure"; |
| import { processSymmetries } from "./utils/processSymmetries"; |
| |
| export interface MMTFobj { |
| decode(data: Uint8Array | ArrayBuffer): any; |
| decodeMsgpack(data: Uint8Array | ArrayBuffer): any; |
| } |
| declare var MMTF: MMTFobj; |
| |
| var fromCharCode = function (charCodeArray: any) { |
| return String.fromCharCode.apply(null, charCodeArray).replace(/\0/g, ''); |
| }; |
| |
| var convertSS = function (val: number | boolean) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if (val == 0 || val == 2 || val == 4) return 'h'; |
| if (val == 3) return 's'; |
| return 'c'; |
| }; |
| |
| let mmtfHETATMtypes = new Set([ |
| "D-SACCHARIDE", |
| "D-SACCHARIDE 1,4 AND 1,4 LINKING", |
| "D-SACCHARIDE 1,4 AND 1,6 LINKING", |
| "L-SACCHARIDE", |
| "L-SACCHARIDE 1,4 AND 1,4 LINKING", |
| "L-SACCHARIDE 1,4 AND 1,6 LINKING", |
| "NON-POLYMER", |
| "OTHER", |
| "PEPTIDE-LIKE", |
| "SACCHARIDE"]); |
| |
| |
| |
| |
| |
| |
| export function MMTFparser(bindata: any, options: ParserOptionsSpec) { |
| |
| var noH = !options.keepH; |
| var selAltLoc = options.altLoc ? options.altLoc : 'A'; |
| var ignoreStruct = !!options.noSecondaryStructure; |
| var computeStruct = !options.noComputeSecondaryStructure; |
| |
| var noAssembly = !options.doAssembly; |
| var assemblyIndex = options.assemblyIndex ? options.assemblyIndex : 0; |
| |
| if (typeof (bindata) == "string") { |
| |
| bindata = base64ToArray(bindata); |
| } else { |
| bindata = new Uint8Array(bindata); |
| } |
| |
| var mmtfData = MMTF.decode(bindata); |
| |
| var atoms: any[][] & Record<string, any> = [[]]; |
| var modelData: any[] = atoms.modelData = []; |
| |
| |
| var chainIndex = 0; |
| var groupIndex = 0; |
| var atomIndex = 0; |
| |
| |
| var secStructList = mmtfData.secStructList; |
| var bFactorList = mmtfData.bFactorList; |
| var altLocList = mmtfData.altLocList; |
| var occupancyList = mmtfData.occupancyList; |
| var bondAtomList = mmtfData.bondAtomList; |
| var bondOrderList = mmtfData.bondOrderList; |
| |
| var numModels = mmtfData.numModels; |
| if (numModels == 0) return atoms; |
| if (!options.multimodel) numModels = 1; |
| |
| var i: number, j: number, k: number, kl: number, m: number, n: number; |
| |
| |
| |
| var symmetries: Matrix4[] = []; |
| if (!noAssembly && mmtfData.bioAssemblyList && mmtfData.bioAssemblyList.length > 0) { |
| var transforms = mmtfData.bioAssemblyList[assemblyIndex].transformList; |
| for (i = 0, n = transforms.length; i < n; i++) { |
| var matrix = new Matrix4(transforms[i].matrix); |
| matrix.transpose(); |
| symmetries.push(matrix); |
| } |
| } |
| var unitCell = null as Record<string, number> | null; |
| |
| if (mmtfData.unitCell) { |
| var u = mmtfData.unitCell; |
| unitCell = { 'a': u[0], 'b': u[1], 'c': u[2], 'alpha': u[3], 'beta': u[4], 'gamma': u[5] }; |
| } |
| |
| let chainIsPolymer: boolean[] = []; |
| mmtfData.entityList.forEach((entity: { chainIndexList: any[]; type: string; }) => { |
| entity.chainIndexList.forEach(ch => { |
| chainIsPolymer[ch] = entity.type == "polymer"; |
| }); |
| }); |
| var bondAtomListStart = 0; |
| |
| for (m = 0; m < numModels; m++) { |
| var modelChainCount = mmtfData.chainsPerModel[m]; |
| var matoms = atoms[atoms.length - 1]; |
| var serialToIndex: number[] = []; |
| |
| modelData.push({ symmetries: symmetries, cryst: unitCell }); |
| for (i = 0; i < modelChainCount; ++i) { |
| |
| var chainGroupCount = mmtfData.groupsPerChain[chainIndex]; |
| var chainId = fromCharCode( |
| mmtfData.chainIdList.subarray(chainIndex * 4, chainIndex * 4 + 4) |
| ); |
| if (mmtfData.chainNameList) { |
| chainId = fromCharCode( |
| mmtfData.chainNameList.subarray(chainIndex * 4, chainIndex * 4 + 4) |
| ); |
| } |
| |
| var startGroup = groupIndex; |
| var prevSS = ''; |
| for (j = 0; j < chainGroupCount; ++j) { |
| |
| var groupData = mmtfData.groupList[mmtfData.groupTypeList[groupIndex]]; |
| var groupAtomCount = groupData.atomNameList.length; |
| var secStruct = 0; |
| var secStructBegin = false; |
| var secStructEnd = false; |
| |
| if (secStructList) { |
| secStruct = secStructList[groupIndex]; |
| var sscode = convertSS(secStruct); |
| if (groupIndex == 0 || sscode != prevSS) { |
| secStructBegin = true; |
| } |
| prevSS = sscode; |
| var nextgroup = groupIndex + 1; |
| if (nextgroup >= secStructList.length || convertSS(secStructList[nextgroup] != sscode)) { |
| secStructEnd = true; |
| } |
| } |
| var groupId = mmtfData.groupIdList[groupIndex]; |
| var groupName = groupData.groupName; |
| let groupType = groupData.chemCompType; |
| var startAtom = atomIndex; |
| |
| |
| let isHETATM = mmtfHETATMtypes.has(groupType) || !chainIsPolymer[chainIndex]; |
| |
| for (k = 0; k < groupAtomCount; ++k) { |
| |
| var element = groupData.elementList[k]; |
| if (noH && element == 'H') { |
| atomIndex += 1; |
| continue; |
| } |
| |
| var bFactor = ''; |
| if (bFactorList) { |
| bFactor = bFactorList[atomIndex]; |
| } |
| var altLoc = ''; |
| if (altLocList && altLocList[atomIndex]) { |
| altLoc = String.fromCharCode(altLocList[atomIndex]); |
| } |
| var occupancy = ''; |
| if (occupancyList) { |
| occupancy = occupancyList[atomIndex]; |
| } |
| |
| if (altLoc != '' && altLoc != selAltLoc && selAltLoc != '*') { |
| atomIndex += 1; |
| continue; |
| } |
| |
| var atomId = mmtfData.atomIdList[atomIndex]; |
| var atomName = groupData.atomNameList[k]; |
| var atomCharge = 0; |
| if (groupData.atomChargeList) atomCharge = groupData.atomChargeList[k]; |
| var xCoord = mmtfData.xCoordList[atomIndex]; |
| var yCoord = mmtfData.yCoordList[atomIndex]; |
| var zCoord = mmtfData.zCoordList[atomIndex]; |
| |
| serialToIndex[atomIndex] = matoms.length; |
| matoms.push({ |
| 'resn': groupName, |
| 'x': xCoord, |
| 'y': yCoord, |
| 'z': zCoord, |
| 'elem': element, |
| 'hetflag': isHETATM, |
| 'chain': chainId, |
| 'resi': groupId, |
| 'icode': altLoc, |
| 'rescode': groupId + (altLoc != ' ' ? "^" + altLoc : ""), |
| |
| |
| |
| 'serial': atomId, |
| 'altLoc': altLoc, |
| 'index': atomIndex, |
| 'atom': atomName, |
| 'bonds': [], |
| 'ss': convertSS(secStruct), |
| 'ssbegin': secStructBegin, |
| 'ssend': secStructEnd, |
| 'bondOrder': [], |
| 'properties': { charge: atomCharge, occupancy: occupancy }, |
| 'b': bFactor, |
| }); |
| |
| atomIndex += 1; |
| } |
| |
| |
| var groupBondAtomList = groupData.bondAtomList; |
| for (k = 0, kl = groupData.bondOrderList.length; k < kl; ++k) { |
| var atomIndex1 = startAtom + groupBondAtomList[k * 2]; |
| var atomIndex2 = startAtom + groupBondAtomList[k * 2 + 1]; |
| var bondOrder = groupData.bondOrderList[k]; |
| |
| |
| var i1 = serialToIndex[atomIndex1]; |
| var i2 = serialToIndex[atomIndex2]; |
| var a1 = matoms[i1]; |
| var a2 = matoms[i2]; |
| if (a1 && a2) { |
| a1.bonds.push(i2); |
| a1.bondOrder.push(bondOrder); |
| a2.bonds.push(i1); |
| a2.bondOrder.push(bondOrder); |
| } |
| } |
| |
| groupIndex += 1; |
| } |
| |
| |
| groupIndex = startGroup; |
| for (j = 0; j < chainGroupCount; ++j) { |
| |
| groupIndex += 1; |
| |
| } |
| |
| chainIndex += 1; |
| } |
| |
| |
| |
| if (bondAtomList) { |
| for (let k = bondAtomListStart, kl = bondAtomList.length; k < kl; k += 2) { |
| let atomIndex1 = bondAtomList[k]; |
| let atomIndex2 = bondAtomList[k + 1]; |
| let bondOrder = bondOrderList ? bondOrderList[k / 2] : 1; |
| |
| if (atomIndex1 >= atomIndex) { |
| bondAtomListStart = k; |
| break; |
| } |
| |
| let i1 = serialToIndex[atomIndex1]; |
| let i2 = serialToIndex[atomIndex2]; |
| let a1 = matoms[i1]; |
| let a2 = matoms[i2]; |
| if (a1 && a2) { |
| a1.bonds.push(i2); |
| a1.bondOrder.push(bondOrder); |
| a2.bonds.push(i1); |
| a2.bondOrder.push(bondOrder); |
| } |
| } |
| } |
| |
| if (options.multimodel) { |
| if (!options.onemol) atoms.push([]); |
| } |
| } |
| |
| if (!noAssembly) { |
| for (let n = 0; n < atoms.length; n++) { |
| processSymmetries(modelData[n].symmetries, atoms[n], options, modelData[n].cryst); |
| } |
| } |
| |
| if (computeStruct && !ignoreStruct) { |
| computeSecondaryStructure(atoms as any, options.hbondCutoff); |
| } |
| |
| return atoms; |
| }; |