1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2006-10-20 07:48:25 -0500 (Fri, 20 Oct 2006) $ 4 * $Revision: 5991 $ 5 * 6 * Copyright (C) 2003-2005 Miguel, Jmol Development, www.jmol.org 7 * 8 * Contact: jmol-developers@lists.sf.net 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 23 */ 24 package org.jmol.adapter.readers.cif; 25 26 import java.util.Hashtable; 27 import java.util.Map; 28 29 import javajs.util.Lst; 30 import javajs.util.M4; 31 import javajs.util.P3; 32 import javajs.util.PT; 33 import javajs.util.SB; 34 35 import org.jmol.adapter.smarter.Atom; 36 import org.jmol.adapter.smarter.Structure; 37 import org.jmol.api.JmolAdapter; 38 import org.jmol.c.STR; 39 import javajs.util.BS; 40 import org.jmol.util.BSUtil; 41 import org.jmol.util.Logger; 42 import org.jmol.util.SimpleUnitCell; 43 44 45 /** 46 * 47 * mmCIF files are recognized prior to class creation. 48 * Required fields include one of: 49 * 50 * _entry.id 51 * _database_PDB_ 52 * _pdbx_ 53 * _chem_comp.pdbx_type 54 * _audit_author.name 55 * _atom_site. 56 * 57 * 58 * @author Bob Hanson (hansonr@stolaf.edu) 59 * 60 */ 61 public class MMCifReader extends CifReader { 62 63 protected boolean isBiomolecule; 64 private boolean byChain, bySymop; 65 private Map<String, P3> chainAtomMap; 66 private Map<String, int[]> chainAtomCounts; 67 68 protected Lst<Map<String, Object>> vBiomolecules; 69 private Map<String, M4> htBiomts; 70 protected Map<String, Map<String, Object>> htSites; 71 protected Map<String, String> htHetero; 72 private Map<String, Lst<Object[]>> htBondMap; 73 private Map<String, BS> assemblyIdAtoms; 74 75 private int thisChain = -1; 76 private int modelIndex = 0; 77 78 private P3 chainSum; 79 private int[] chainAtomCount; 80 81 private boolean isLigandBondBug; 82 // Jmol-14.3.3_2014.07.27 broke mmCIF bond reading for ligands 83 // Jmol-14.3.9_2014.11.11 fixes this. 84 85 M4 mident; 86 87 @Override initSubclass()88 protected void initSubclass() { 89 setIsPDB(); 90 mident = M4.newM4(null); 91 isMMCIF = true; 92 if (isDSSP1) 93 asc.setInfo("isDSSP1",Boolean.TRUE); 94 if (htParams.containsKey("isMutate")) 95 asc.setInfo("isMutate",Boolean.TRUE); 96 doSetBonds = checkFilterKey("ADDBONDS"); 97 byChain = checkFilterKey("BYCHAIN"); 98 if (checkFilterKey("BIOMOLECULE")) // PDB format 99 filter = PT.rep(filter, "BIOMOLECULE", "ASSEMBLY"); 100 isBiomolecule = checkFilterKey("ASSEMBLY"); 101 if (isBiomolecule) { 102 filter = filter.replace(':', ' '); // no chain selection for biomolecules 103 bySymop = checkFilterKey("BYSYMOP"); 104 } 105 isCourseGrained = byChain || bySymop; 106 if (isCourseGrained) { 107 chainAtomMap = new Hashtable<String, P3>(); 108 chainAtomCounts = new Hashtable<String, int[]>(); 109 } 110 // When this reader was split off from CifReader, a bug was introduced 111 // into the Resolver that made it so that ligand files were read by 112 // CifReader and not MMCifReader. This caused CHEM_COMP_BOND records to be 113 // skipped and so in the case of pdbAddHydrogen no hydrogens added. 114 isLigandBondBug = (stateScriptVersionInt >= 140204 && stateScriptVersionInt <= 140208 115 || stateScriptVersionInt >= 140304 && stateScriptVersionInt <= 140308); 116 117 } 118 119 @Override processSubclassEntry()120 protected void processSubclassEntry() throws Exception { 121 if (key0.startsWith(FAMILY_ASSEM_CAT) 122 || key0.startsWith(FAMILY_STRUCTCONN_CAT) 123 || key0.startsWith(FAMILY_SEQUENCEDIF_CAT) 124 || key0.startsWith(FAMILY_STRUCTCONF_CAT) 125 || key0.startsWith(FAMILY_SHEET_CAT) 126 127 // || key0.startsWith(FAMILY_PDBX_NONPOLY_CAT) 128 ) 129 processSubclassLoopBlock(); 130 else if (key.equals("_rna3d")) { 131 addedData = data; 132 addedDataKey = key; 133 } else if (key.equals("_dssr")) { 134 dssr = vwr.parseJSONMap(reader.readLine()); 135 reader.readLine(); // sometimes there is a null character here 136 } 137 } 138 139 @Override processSubclassLoopBlock()140 protected boolean processSubclassLoopBlock() throws Exception { 141 if (key0.startsWith(FAMILY_NCS_CAT)) 142 return processStructOperListBlock(true); 143 if (key0.startsWith(FAMILY_OPER_CAT)) 144 return processStructOperListBlock(false); 145 if (key0.startsWith(FAMILY_ASSEM_CAT)) 146 return processAssemblyGenBlock(); 147 if (key0.startsWith(FAMILY_SEQUENCEDIF_CAT)) 148 return processSequence(); 149 150 if (isCourseGrained) 151 return false; 152 153 if (key0.startsWith(FAMILY_STRUCSITE_CAT)) 154 return processStructSiteBlock(); 155 if (key0.startsWith(FAMILY_CHEMCOMP_CAT)) 156 return processChemCompLoopBlock(); 157 // if (key0.startsWith(FAMILY_PDBX_NONPOLY_CAT)) 158 // return processNonpolyLoopBlock(); 159 if (key0.startsWith(FAMILY_STRUCTCONF_CAT)) 160 return processStructConfLoopBlock(); 161 if (key0.startsWith(FAMILY_SHEET_CAT)) 162 return processStructSheetRangeLoopBlock(); 163 164 // alas -- saved states must not read ligand bonding 165 // the problem was that these files were not recognized as mmCIF 166 // files by the resolver when this MMCifReader was created. 167 168 if (isLigandBondBug) 169 return false; 170 if (key0.startsWith(FAMILY_COMPBOND_CAT)) 171 return processCompBondLoopBlock(); 172 if (key0.startsWith(FAMILY_STRUCTCONN_CAT)) 173 return processStructConnLoopBlock(); 174 175 return false; 176 177 } 178 179 private boolean requiresSorting; 180 181 /** 182 * issue here is that mmCIF assembly atoms can be in different blocks by chain: 183 * Model1:Chain1 Model2:Chain1 Model1:Chain2 Model2:Chain2 ... and so assigned 184 * to too many atom sets. 185 * 186 */ sortAssemblyModels()187 protected void sortAssemblyModels() { 188 int natoms = asc.ac; 189 int lastSet = -1; 190 Atom[] atoms = asc.atoms; 191 Atom[] newAtoms = new Atom[natoms]; 192 String[] ids = PT.split("," + modelStrings + ",", ",,"); 193 BS bsAtomsNew = (asc.bsAtoms == null ? null : BS.newN(asc.bsAtoms.size())); 194 for (int im = 1, n = 0; im < ids.length; im++) { 195 String sModel = ids[im]; 196 int modelIndex = -1; 197 for (int is = 0; is < asc.atomSetCount; is++) { 198 int ia0 = asc.getAtomSetAtomIndex(is); 199 int ia1 = ia0 + asc.getAtomSetAtomCount(is); 200 String am = "" + modelMap.get("_" + is); 201 if (am.equals(sModel)) { 202 if (modelIndex < 0 && (modelIndex = is) > lastSet) 203 lastSet = is; 204 for (int i = ia0; i < ia1; i++) { 205 if (bsAtomsNew == null || asc.bsAtoms.get(i)) { 206 if (bsAtomsNew != null) 207 bsAtomsNew.set(n); 208 atoms[i].atomSetIndex = modelIndex; 209 newAtoms[n++] = atoms[i]; 210 } 211 } 212 } 213 } 214 215 } 216 asc.atoms = newAtoms; 217 asc.bsAtoms = bsAtomsNew; 218 if (++lastSet < asc.atomSetCount) 219 asc.atomSetCount = lastSet; 220 } 221 222 223 @Override finalizeSubclass()224 protected boolean finalizeSubclass() throws Exception { 225 if (byChain && !isBiomolecule) 226 for (String id : chainAtomMap.keySet()) 227 createParticle(id); 228 boolean haveBiomolecule = (isBiomolecule && vBiomolecules != null && vBiomolecules.size() > 0); 229 if (!isCourseGrained && asc.ac == nAtoms) { 230 asc.removeCurrentAtomSet(); 231 } else { 232 if ((dssr != null || validation != null || addedData != null) && !isCourseGrained && !requiresSorting) { 233 MMCifValidationParser vs = ((MMCifValidationParser) getInterface("org.jmol.adapter.readers.cif.MMCifValidationParser")) 234 .set(this); 235 String note = null; 236 if (addedData == null) { 237 if (validation != null || dssr != null) 238 note = vs.finalizeValidations(vwr, modelMap); 239 } else if (addedDataKey.equals("_rna3d")) { 240 note = vs.finalizeRna3d(modelMap); 241 } 242 if (note != null) 243 appendLoadNote(note); 244 } 245 setHetero(); 246 if (doSetBonds) 247 setBonds(); 248 } 249 if (asc.ac == 0 && !isCourseGrained) 250 return false; 251 String spaceGroup = sgName; 252 if (htSites != null) 253 addSites(htSites); 254 255 if (haveBiomolecule) { 256 asc.setCurrentModelInfo("biomolecules", vBiomolecules); 257 setBiomolecules(); 258 if (thisBiomolecule != null) { 259 if (iHaveFractionalCoordinates) 260 fractionalizeCoordinates(false); 261 asc.getXSymmetry().applySymmetryBio(thisBiomolecule, 262 applySymmetryToBonds, filter); 263 asc.xtalSymmetry = null; 264 } 265 doCheckUnitCell &= iHaveUnitCell && doApplySymmetry; 266 if (doCheckUnitCell) { 267 ignoreFileSpaceGroupName = true; 268 sgName = spaceGroup; 269 fractionalizeCoordinates(true); 270 asc.setCurrentModelInfo("biosymmetry", null); 271 asc.setCurrentModelInfo("biosymmetryCount", null); 272 asc.checkSpecial = false; 273 if (byChain) 274 return true; 275 } 276 } 277 if (latticeCells != null && latticeCells[0] != 0) 278 addJmolScript("unitcell;axes on;axes unitcell;"); 279 if (requiresSorting) 280 sortAssemblyModels(); 281 return true; 282 } 283 284 //////////////////////////////////////////////////////////////// 285 // assembly data 286 //////////////////////////////////////////////////////////////// 287 288 @Override checkSubclassSymmetry()289 protected boolean checkSubclassSymmetry() { 290 asc.checkSpecial = false; 291 int modelIndex = asc.iSet; 292 asc.setCurrentModelInfo( 293 "PDB_CONECT_firstAtom_count_max", 294 new int[] { asc.getAtomSetAtomIndex(modelIndex), 295 asc.getAtomSetAtomCount(modelIndex), maxSerial }); 296 return false; 297 } 298 299 /** 300 * Note that setting bonds from _struct_conn is only done if we have updated 301 * CIF files, which include _chem_comp_bond. 302 */ setBonds()303 private void setBonds() { 304 if (htBondMap == null) 305 return; 306 BS bsAtoms = asc.bsAtoms; 307 if (bsAtoms == null) 308 bsAtoms = BSUtil.newBitSet2(0, asc.ac); 309 Atom[] atoms = asc.atoms; 310 float seqid = -1; 311 String comp = null; 312 Map<Object, Integer> map = null; 313 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) { 314 Atom a = atoms[i]; 315 float pt = (a.vib == null ? a.sequenceNumber : a.vib.x); 316 if (pt != seqid) { 317 seqid = pt; 318 if (comp != null) 319 processBonds(htBondMap.get(comp), map, false); 320 map = new Hashtable<Object, Integer>(); 321 comp = atoms[i].group3; 322 if (!htBondMap.containsKey(comp)) { 323 comp = null; 324 continue; 325 } 326 } 327 if (comp == null) 328 continue; 329 map.put(a.atomName, Integer.valueOf(a.index)); 330 } 331 if (comp != null) 332 processBonds(htBondMap.get(comp), map, false); 333 if (structConnMap != null) { 334 map = new Hashtable<Object, Integer>(); 335 seqid = -1; 336 comp = null; 337 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) { 338 Atom a = atoms[i]; 339 float pt = (a.vib == null ? a.sequenceNumber : a.vib.x); 340 if (pt != seqid) { 341 seqid = pt; 342 String ckey = a.chainID + a.group3 + seqid; 343 if (structConnList.indexOf(ckey) < 0) { 344 comp = null; 345 continue; 346 } 347 comp = ckey; 348 } 349 if (comp == null) 350 continue; 351 map.put(comp + a.atomName + a.altLoc, Integer.valueOf(a.index)); 352 } 353 processBonds(structConnMap, map, true); 354 } 355 appendLoadNote(asc.bondCount + " bonds added"); 356 } 357 processBonds(Lst<Object[]> cmap, Map<Object, Integer> map, boolean isStructConn)358 private void processBonds(Lst<Object[]> cmap, Map<Object, Integer> map, boolean isStructConn) { 359 Integer i1, i2; 360 for (int i = 0, n = cmap.size(); i < n; i++) { 361 Object[] o = cmap.get(i); 362 if ((i1 = map.get(o[0])) == null || (i2 = map.get(o[1])) == null) 363 continue; 364 if (debugging) 365 Logger.debug((isStructConn ? "_struct_conn" : "_comp_bond") + " adding bond " + i1 + " " + i2 + " order=" + o[2]); 366 asc.addNewBondWithOrder(i1.intValue(), i2.intValue(), ((Integer) o[2]).intValue()); 367 } 368 } 369 370 final private static byte OPER_ID = 12; 371 final private static byte OPER_XYZ = 13; 372 373 final private static String FAMILY_NCS_CAT = "_struct_ncs_oper."; 374 final private static String FAMILY_NCS = "_struct_ncs_oper"; 375 final private static String[] ncsoperFields = { 376 "*_matrix[1][1]", 377 "*_matrix[1][2]", 378 "*_matrix[1][3]", 379 "*_vector[1]", 380 "*_matrix[2][1]", 381 "*_matrix[2][2]", 382 "*_matrix[2][3]", 383 "*_vector[2]", 384 "*_matrix[3][1]", 385 "*_matrix[3][2]", 386 "*_matrix[3][3]", 387 "*_vector[3]", 388 "*_id", 389 "*_symmetry_operation" 390 }; 391 392 final private static String FAMILY_OPER_CAT = "_pdbx_struct_oper_list."; 393 final private static String FAMILY_OPER = "_pdbx_struct_oper_list"; 394 final private static String[] operFields = { 395 "*_matrix[1][1]", 396 "*_matrix[1][2]", 397 "*_matrix[1][3]", 398 "*_vector[1]", 399 "*_matrix[2][1]", 400 "*_matrix[2][2]", 401 "*_matrix[2][3]", 402 "*_vector[2]", 403 "*_matrix[3][1]", 404 "*_matrix[3][2]", 405 "*_matrix[3][3]", 406 "*_vector[3]", 407 "*_id", 408 "*_symmetry_operation" 409 }; 410 411 final private static byte ASSEM_ID = 0; 412 final private static byte ASSEM_OPERS = 1; 413 final private static byte ASSEM_LIST = 2; 414 415 final private static String FAMILY_ASSEM_CAT = "_pdbx_struct_assembly_gen."; 416 417 final private static String[] assemblyFields = { 418 "_pdbx_struct_assembly_gen_assembly_id", 419 "_pdbx_struct_assembly_gen_oper_expression", 420 "_pdbx_struct_assembly_gen_asym_id_list" 421 }; 422 423 /* 424 _pdbx_struct_assembly_gen.assembly_id 1 425 _pdbx_struct_assembly_gen.oper_expression 1,2,3,4 426 _pdbx_struct_assembly_gen.asym_id_list A,B,C 427 # 428 loop_ 429 _pdbx_struct_oper_list.id 430 _pdbx_struct_oper_list.type 431 _pdbx_struct_oper_list.name 432 _pdbx_struct_oper_list.symmetry_operation 433 _pdbx_struct_oper_list.matrix[1][1] 434 _pdbx_struct_oper_list.matrix[1][2] 435 _pdbx_struct_oper_list.matrix[1][3] 436 _pdbx_struct_oper_list.vector[1] 437 _pdbx_struct_oper_list.matrix[2][1] 438 _pdbx_struct_oper_list.matrix[2][2] 439 _pdbx_struct_oper_list.matrix[2][3] 440 _pdbx_struct_oper_list.vector[2] 441 _pdbx_struct_oper_list.matrix[3][1] 442 _pdbx_struct_oper_list.matrix[3][2] 443 _pdbx_struct_oper_list.matrix[3][3] 444 _pdbx_struct_oper_list.vector[3] 445 1 'identity operation' 1_555 x,y,z 1.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 446 1.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000 0.0000000000 447 2 'crystal symmetry operation' 15_556 y,x,-z+1 0.0000000000 1.0000000000 0.0000000000 0.0000000000 1.0000000000 448 0.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 -1.0000000000 52.5900000000 449 3 'crystal symmetry operation' 10_665 -x+1,-y+1,z -1.0000000000 0.0000000000 0.0000000000 68.7500000000 0.0000000000 450 -1.0000000000 0.0000000000 68.7500000000 0.0000000000 0.0000000000 1.0000000000 0.0000000000 451 4 'crystal symmetry operation' 8_666 -y+1,-x+1,-z+1 0.0000000000 -1.0000000000 0.0000000000 68.7500000000 -1.0000000000 452 0.0000000000 0.0000000000 68.7500000000 0.0000000000 0.0000000000 -1.0000000000 52.5900000000 453 # 454 455 */ 456 457 final private static String FAMILY_SEQUENCEDIF_CAT = "_struct_ref_seq_dif."; 458 final private static byte STRUCT_REF_G3 = 0; 459 final private static byte STRUCT_REF_G1 = 1; 460 final private static String[] structRefFields = { 461 "_struct_ref_seq_dif_mon_id", 462 "_struct_ref_seq_dif_db_mon_id" 463 }; 464 465 /** 466 * get canonical 1-letter DNA/RNA sequence code from 3-letter code. For example, "2MG" --> "G" 467 * @return true 468 * @throws Exception 469 */ processSequence()470 private boolean processSequence() throws Exception { 471 parseLoopParameters(structRefFields); 472 String g1, g3; 473 while (cifParser.getData()) { 474 if (isNull(g1 = getField(STRUCT_REF_G1).toLowerCase()) 475 || g1.length() != 1 || isNull(g3 = getField(STRUCT_REF_G3))) 476 continue; 477 if (htGroup1 == null) 478 asc.setInfo("htGroup1", htGroup1 = new Hashtable<String, String>()); 479 htGroup1.put(g3, g1); 480 } 481 return true; 482 } 483 processAssemblyGenBlock()484 private boolean processAssemblyGenBlock() throws Exception { 485 parseLoopParameters(assemblyFields); 486 while (cifParser.getData()) { 487 String[] assem = new String[3]; 488 int count = 0; 489 int p; 490 int n = cifParser.getColumnCount(); 491 for (int i = 0; i < n; ++i) { 492 switch (p = fieldProperty(i)) { 493 case ASSEM_ID: 494 case ASSEM_OPERS: 495 case ASSEM_LIST: 496 count++; 497 assem[p] = field; 498 break; 499 } 500 } 501 if (count == 3) 502 addAssembly(assem); 503 } 504 return true; 505 } 506 507 @SuppressWarnings("unchecked") addAssembly(String[] assem)508 protected void addAssembly(String[] assem) throws Exception { 509 String id = assem[ASSEM_ID]; 510 String list = assem[ASSEM_LIST]; 511 String operators = assem[ASSEM_OPERS]; 512 String name = "biomolecule " + id; 513 Logger.info(name + " operators " + operators 514 + " ASYM_IDs " + list); 515 appendLoadNote("found " + name + ": " + list); 516 if (vBiomolecules == null) 517 vBiomolecules = new Lst<Map<String, Object>>(); 518 Map<String, Object> info = null; 519 for (int i = vBiomolecules.size(); --i >= 0;) 520 if (vBiomolecules.get(i).get("name").equals(name)) { 521 info = vBiomolecules.get(i); 522 break; 523 } 524 if (info == null) { 525 info = new Hashtable<String, Object>(); 526 info.put("name", name); 527 int iMolecule = parseIntStr(id); 528 info.put("molecule", 529 iMolecule == Integer.MIN_VALUE ? id : Integer.valueOf(iMolecule)); 530 info.put("biomts", new Lst<M4>()); 531 info.put("chains", new Lst<String>()); 532 info.put("assemblies", new Lst<String>()); 533 info.put("operators", new Lst<String>()); 534 vBiomolecules.addLast(info); 535 } 536 ((Lst<String>) info.get("assemblies")).addLast("$" + list.replace(',', '$')); 537 ((Lst<String>) info.get("operators")).addLast(decodeAssemblyOperators(operators)); 538 checkFilterAssembly(id, info); 539 } 540 checkFilterAssembly(String id, Map<String, Object> info)541 protected void checkFilterAssembly(String id, Map<String, Object> info) { 542 if (checkFilterKey("ASSEMBLY " + id + ";") || checkFilterKey("ASSEMBLY=" + id + ";")) 543 thisBiomolecule = info; 544 } 545 decodeAssemblyOperators(String ops)546 private String decodeAssemblyOperators(String ops) { 547 548 // Identifies the operation of collection of operations 549 // from category PDBX_STRUCT_OPER_LIST. 550 // 551 // Operation expressions may have the forms: 552 // 553 // (1) the single operation 1 554 // (1,2,5) the operations 1, 2, 5 555 // (1-4) the operations 1,2,3 and 4 556 // (1,2)(3,4) the combinations of operations 557 // 3 and 4 followed by 1 and 2 (i.e. 558 // the cartesian product of parenthetical 559 // groups applied from right to left) 560 int pt = ops.indexOf(")("); 561 if (pt >= 0) 562 return crossBinary(decodeAssemblyOperators(ops.substring(0, pt + 1)), 563 decodeAssemblyOperators(ops.substring(pt + 1))); 564 if (ops.startsWith("(")) { 565 if (ops.indexOf("-") >= 0) 566 ops = BS.unescape( 567 "({" + ops.substring(1, ops.length() - 1).replace('-', ':').replace(',', ' ') + "})") 568 .toJSON(); 569 ops = PT.rep(ops, " ", ""); 570 ops = ops.substring(1, ops.length() - 1); 571 } 572 return ops; 573 } 574 crossBinary(String ops1, String ops2)575 private String crossBinary(String ops1, String ops2) { 576 SB sb = new SB(); 577 String[] opsLeft = PT.split(ops1, ","); 578 String[] opsRight = PT.split(ops2, ","); 579 for (int i = 0; i < opsLeft.length; i++) 580 for (int j = 0; j < opsRight.length; j++) 581 sb.append(",").append(opsLeft[i]).append("|").append(opsRight[j]); 582 return sb.toString().substring(1); 583 } 584 processStructOperListBlock(boolean isNCS)585 private boolean processStructOperListBlock(boolean isNCS) throws Exception { 586 parseLoopParametersFor((isNCS ? FAMILY_NCS : FAMILY_OPER), isNCS ? ncsoperFields : operFields); 587 float[] m = new float[16]; 588 m[15] = 1; 589 while (cifParser.getData()) { 590 int count = 0; 591 String id = null; 592 String xyz = null; 593 int n = cifParser.getColumnCount(); 594 for (int i = 0; i < n; ++i) { 595 int p = fieldProperty(i); 596 switch (p) { 597 case NONE: 598 break; 599 case OPER_ID: 600 id = field; 601 break; 602 case OPER_XYZ: 603 xyz = field; 604 break; 605 default: 606 m[p] = parseFloatStr(field); 607 ++count; 608 } 609 } 610 if (id != null && (count == 12 || xyz != null && symmetry != null)) { 611 Logger.info((isNCS ? "noncrystallographic symmetry operator " : "assembly operator ") + id + " " + xyz); 612 M4 m4 = new M4(); 613 if (count != 12) { 614 symmetry.getMatrixFromString(xyz, m, false, 0); 615 m[3] *= symmetry.getUnitCellInfoType(SimpleUnitCell.INFO_A) / 12; 616 m[7] *= symmetry.getUnitCellInfoType(SimpleUnitCell.INFO_B) / 12; 617 m[11] *= symmetry.getUnitCellInfoType(SimpleUnitCell.INFO_C) / 12; 618 } 619 m4.setA(m); 620 addMatrix(id, m4, isNCS); 621 } 622 } 623 return true; 624 } 625 addMatrix(String id, M4 m4, boolean isNCS)626 protected void addMatrix(String id, M4 m4, boolean isNCS) { 627 if (isNCS) { 628 if (m4.equals(mident)) 629 return; 630 m4.m33 = 0; // flag for normalization 631 if (lstNCS == null) 632 lstNCS = new Lst<M4>(); 633 lstNCS.addLast(m4); 634 } else { 635 if (htBiomts == null) 636 htBiomts = new Hashtable<String, M4>(); 637 htBiomts.put(id, m4); 638 } 639 } 640 641 //////////////////////////////////////////////////////////////// 642 // HETATM identity 643 //////////////////////////////////////////////////////////////// 644 645 final private static byte CHEM_COMP_ID = 0; 646 final private static byte CHEM_COMP_NAME = 1; 647 648 final private static String FAMILY_CHEMCOMP_CAT = "_chem_comp."; 649 650 final private static String[] chemCompFields = { 651 "_chem_comp_id", 652 "_chem_comp_name" 653 }; 654 655 /** 656 * 657 * a general name definition field. Not all hetero 658 * 659 * @return true if successful; false to skip 660 * 661 * @throws Exception 662 */ processChemCompLoopBlock()663 private boolean processChemCompLoopBlock() throws Exception { 664 parseLoopParameters(chemCompFields); 665 String groupName, hetName; 666 while (cifParser.getData()) 667 if (!isNull(groupName = getField(CHEM_COMP_ID)) 668 && !isNull(hetName = getField(CHEM_COMP_NAME))) 669 addHetero(groupName, hetName, true, true); 670 return true; 671 } 672 673 // final private static byte NONPOLY_NAME = 0; 674 // final private static byte NONPOLY_COMP_ID = 1; 675 // 676 // private static final String FAMILY_PDBX_NONPOLY_CAT = "_pdbx_entity_nonpoly."; 677 // 678 // final private static String[] nonpolyFields = { 679 // "_pdbx_entity_nonpoly_name", 680 // "_pdbx_entity_nonpoly_comp_id", }; 681 // 682 // 683 // /** 684 // * 685 // * a HETERO name definition field. Maybe not all hetero? nonpoly? 686 // * 687 // * @return true if successful; false to skip 688 // * 689 // * @throws Exception 690 // */ 691 // private boolean processNonpolyLoopBlock() throws Exception { 692 // parseLoopParameters(nonpolyFields); 693 // String groupName, hetName; 694 // while (parser.getData()) { 695 // if (isNull(groupName = getField(NONPOLY_COMP_ID)) 696 // || isNull(hetName = getField(NONPOLY_NAME))) 697 // return false; 698 // addHetero(groupName, hetName, true); 699 // } 700 // return true; 701 // } 702 addHetero(String groupName, String hetName, boolean doCheck, boolean addNote)703 protected void addHetero(String groupName, String hetName, boolean doCheck, boolean addNote) { 704 if (doCheck && !vwr.getJBR().isHetero(groupName)) 705 return; 706 if (htHetero == null) 707 htHetero = new Hashtable<String, String>(); 708 if (doCheck && htHetero.containsKey(groupName)) 709 return; 710 htHetero.put(groupName, hetName); 711 if (addNote) 712 appendLoadNote(groupName + " = " + hetName); 713 } 714 715 //////////////////////////////////////////////////////////////// 716 // helix and turn structure data 717 //////////////////////////////////////////////////////////////// 718 719 final private static byte CONF_TYPE_ID = 0; 720 final private static byte BEG_ASYM_ID = 1; 721 final private static byte BEG_SEQ_ID = 2; 722 final private static byte BEG_INS_CODE = 3; 723 final private static byte END_ASYM_ID = 4; 724 final private static byte END_SEQ_ID = 5; 725 final private static byte END_INS_CODE = 6; 726 final private static byte STRUCT_ID = 7; 727 final private static byte SERIAL_NO = 8; 728 final private static byte HELIX_CLASS = 9; 729 730 final private static String FAMILY_STRUCTCONF_CAT = "_struct_conf."; 731 732 final private static String FAMILY_STRUCTCONF = "_struct_conf"; 733 final private static String[] structConfFields = { 734 "*_conf_type_id", 735 "*_beg_auth_asym_id", 736 "*_beg_auth_seq_id", 737 "*_pdbx_beg_pdb_ins_code", 738 "*_end_auth_asym_id", 739 "*_end_auth_seq_id", 740 "*_pdbx_end_pdb_ins_code", 741 "*_id", 742 "*_pdbx_pdb_helix_id", 743 "*_pdbx_pdb_helix_class" }; 744 745 /** 746 * identifies ranges for HELIX and TURN 747 * 748 * @return true if successful; false to skip 749 * @throws Exception 750 */ processStructConfLoopBlock()751 private boolean processStructConfLoopBlock() throws Exception { 752 if (ignoreStructure) { 753 cifParser.skipLoop(false); 754 return false; 755 } 756 parseLoopParametersFor(FAMILY_STRUCTCONF, structConfFields); 757 if (!checkAllFieldsPresent(structConfFields, -1, true)) { 758 cifParser.skipLoop(true); 759 return false; 760 } 761 while (cifParser.getData()) { 762 Structure structure = new Structure(-1, STR.HELIX, STR.HELIX, null, 0, 0, null); 763 764 String type = getField(CONF_TYPE_ID); 765 if (type.startsWith("TURN")) 766 structure.structureType = structure.substructureType = STR.TURN; 767 else if (!type.startsWith("HELX")) 768 structure.structureType = structure.substructureType = STR.NONE; 769 else 770 structure.substructureType = Structure.getHelixType(parseIntStr(getField(HELIX_CLASS))); 771 structure.serialID = parseIntStr(getField(SERIAL_NO)); 772 structure.structureID = getField(STRUCT_ID); 773 774 addStructure(structure); 775 } 776 return true; 777 } 778 779 //////////////////////////////////////////////////////////////// 780 // sheet structure data 781 //////////////////////////////////////////////////////////////// 782 addStructure(Structure structure)783 private void addStructure(Structure structure) { 784 structure.startChainID = vwr.getChainID(structure.startChainStr = getField(BEG_ASYM_ID), true); 785 structure.startSequenceNumber = parseIntStr(getField(BEG_SEQ_ID)); 786 structure.startInsertionCode = getField(BEG_INS_CODE).charAt(0); 787 structure.endChainID = vwr.getChainID(structure.endChainStr = getField(END_ASYM_ID), true); 788 structure.endSequenceNumber = parseIntStr(getField(END_SEQ_ID)); 789 structure.endInsertionCode = getField(END_INS_CODE).charAt(0); 790 asc.addStructure(structure); 791 } 792 793 final private static byte SHEET_ID = 0; 794 final private static byte STRAND_ID = 7; 795 796 final private static String FAMILY_SHEET_CAT = "_struct_sheet_range."; 797 798 final private static String FAMILY_SHEET = "_struct_sheet_range"; 799 final private static String[] structSheetRangeFields = { 800 "*_sheet_id", 801 "*_beg_auth_asym_id", 802 "*_beg_auth_seq_id", 803 "*_pdbx_beg_pdb_ins_code", 804 "*_end_auth_asym_id", 805 "*_end_auth_seq_id", 806 "*_pdbx_end_pdb_ins_code", 807 "*_id" 808 }; 809 810 /** 811 * 812 * identifies sheet ranges 813 * 814 * @return true if successful; false to skip 815 * 816 * @throws Exception 817 */ processStructSheetRangeLoopBlock()818 private boolean processStructSheetRangeLoopBlock() throws Exception { 819 if (ignoreStructure) { 820 cifParser.skipLoop(false); 821 return false; 822 } 823 parseLoopParametersFor(FAMILY_SHEET, structSheetRangeFields); 824 if (!checkAllFieldsPresent(structSheetRangeFields, -1, true)) { 825 cifParser.skipLoop(true); 826 return false; 827 } 828 while (cifParser.getData()) 829 addStructure(new Structure(-1, STR.SHEET, STR.SHEET, getField(SHEET_ID), 830 parseIntStr(getField(STRAND_ID)), 1, null)); 831 return true; 832 } 833 834 final private static byte SITE_ID = 0; 835 final private static byte SITE_COMP_ID = 1; 836 final private static byte SITE_ASYM_ID = 2; 837 final private static byte SITE_SEQ_ID = 3; 838 final private static byte SITE_INS_CODE = 4; //??? 839 840 final private static String FAMILY_STRUCSITE_CAT = "_struct_site_gen."; 841 842 final private static String FAMILY_STRUCSITE = "_struct_site_gen"; 843 final private static String[] structSiteFields = { 844 "*_site_id", 845 "*_auth_comp_id", 846 "*_auth_asym_id", 847 "*_auth_seq_id", 848 "*_label_alt_id", //should be an insertion code, not an alt ID? 849 }; 850 851 // loop_ 852 // _struct_site_gen.id 853 // _struct_site_gen.site_id 854 // _struct_site_gen.pdbx_num_res 855 // _struct_site_gen.label_comp_id 856 // _struct_site_gen.label_asym_id 857 // _struct_site_gen.label_seq_id 858 // _struct_site_gen.auth_comp_id 859 // _struct_site_gen.auth_asym_id 860 // _struct_site_gen.auth_seq_id 861 // _struct_site_gen.label_atom_id 862 // _struct_site_gen.label_alt_id 863 // _struct_site_gen.symmetry 864 // _struct_site_gen.details 865 // 1 CAT 5 GLN A 92 GLN A 92 . . ? ? 866 // 2 CAT 5 GLU A 58 GLU A 58 . . ? ? 867 // 3 CAT 5 HIS A 40 HIS A 40 . . ? ? 868 // 4 CAT 5 TYR A 38 TYR A 38 . . ? ? 869 // 5 CAT 5 PHE A 100 PHE A 100 . . ? ? 870 // # 871 872 /** 873 * 874 * identifies structure sites 875 * 876 * @return true if successful; false to skip 877 * 878 * @throws Exception 879 */ processStructSiteBlock()880 private boolean processStructSiteBlock() throws Exception { 881 parseLoopParametersFor(FAMILY_STRUCSITE, structSiteFields); 882 Map<String, Object> htSite = null; 883 htSites = new Hashtable<String, Map<String, Object>>(); 884 String seqNum, resID; 885 while (cifParser.getData()) { 886 if (isNull(seqNum = getField(SITE_SEQ_ID)) 887 || isNull(resID = getField(SITE_COMP_ID))) 888 continue; 889 String siteID = getField(SITE_ID); 890 htSite = htSites.get(siteID); 891 if (htSite == null) { 892 htSite = new Hashtable<String, Object>(); 893 htSite.put("groups", ""); 894 htSites.put(siteID, htSite); 895 } 896 String insCode = getField(SITE_INS_CODE); 897 String chainID = getField(SITE_ASYM_ID); 898 String group = "[" + resID + "]" + seqNum 899 + (isNull(insCode) ? "" : "^" + insCode) 900 + (isNull(chainID) ? "" : ":" + chainID); 901 String groups = (String) htSite.get("groups"); 902 groups += (groups.length() == 0 ? "" : ",") + group; 903 htSite.put("groups", groups); 904 } 905 return true; 906 } 907 setBiomolecules()908 private void setBiomolecules() { 909 if (assemblyIdAtoms == null && chainAtomCounts == null) 910 return; 911 BS bsAll = new BS(); 912 for (int i = vBiomolecules.size(); --i >= 0;) { 913 Map<String, Object> biomolecule = vBiomolecules.get(i); 914 setBiomolecule(biomolecule, (biomolecule == thisBiomolecule ? bsAll : null)); 915 } 916 if (isBiomolecule && bsAll.cardinality() < asc.ac) { 917 if (asc.bsAtoms != null) 918 asc.bsAtoms.and(bsAll); 919 else if (!isCourseGrained) 920 asc.bsAtoms = bsAll; 921 } 922 } 923 924 @SuppressWarnings("unchecked") setBiomolecule(Map<String, Object> biomolecule, BS bsAll)925 private int setBiomolecule(Map<String, Object> biomolecule, BS bsAll) { 926 Lst<String> biomtchains = (Lst<String>) biomolecule.get("chains"); 927 Lst<M4> biomts = (Lst<M4>) biomolecule.get("biomts"); 928 Lst<String> operators = (Lst<String>) biomolecule.get("operators"); 929 Lst<String> assemblies = (Lst<String>) biomolecule.get("assemblies"); 930 P3 sum = new P3(); 931 int count = 0; 932 BS bsAtoms = new BS(); 933 int nAtomsTotal = 0; 934 boolean isBioCourse = (isBiomolecule && isCourseGrained); 935 for (int i = operators.size(); --i >= 0;) { 936 String[] ops = PT.split(operators.get(i), ","); 937 String[] ids = PT.split(assemblies.get(i), "$"); 938 String chainlist = ""; 939 int nAtoms = 0; 940 for (int j = 1; j < ids.length; j++) { 941 String id = ids[j]; 942 chainlist += ":" + id + ";"; 943 if (assemblyIdAtoms != null) { 944 biomolecule.put("asemblyIdAtoms", assemblyIdAtoms); 945 BS bs = assemblyIdAtoms.get(id); 946 if (bs != null) { 947 bsAtoms.or(bs); 948 if (bsAll != null) 949 bsAll.or(bs); 950 nAtoms += bs.cardinality(); 951 } 952 } else if (isBioCourse) { 953 P3 asum = chainAtomMap.get(id); 954 if (asum != null) { 955 if (bySymop) { 956 sum.add(asum); 957 count += chainAtomCounts.get(id)[0]; 958 } else { 959 createParticle(id); 960 nAtoms++; 961 } 962 } 963 } 964 } 965 if (!isBiomolecule) 966 continue; 967 for (int j = 0; j < ops.length; j++) { 968 M4 m = getOpMatrix(ops[j]); 969 if (m == null) 970 return 0; 971 if (m.equals(mident)) { 972 biomts.add(0, mident); 973 biomtchains.add(0, chainlist); 974 } else { 975 biomts.addLast(m); 976 biomtchains.addLast(chainlist); 977 } 978 } 979 if (bySymop && bsAll != null) { 980 nAtoms = 1; 981 Atom a1 = new Atom(); 982 a1.setT(sum); 983 a1.scale(1f / count); 984 a1.radius = 16; 985 asc.addAtom(a1); 986 } 987 nAtoms *= ops.length; 988 nAtomsTotal += nAtoms; 989 } 990 biomolecule.put("atomCount", Integer.valueOf(nAtomsTotal)); 991 return nAtomsTotal; 992 993 } 994 createParticle(String id)995 private void createParticle(String id) { 996 P3 asum = chainAtomMap.get(id); 997 int c = chainAtomCounts.get(id)[0]; 998 Atom a = new Atom(); 999 a.setT(asum); 1000 a.scale(1f / c); 1001 a.elementSymbol = "Pt"; 1002 setChainID(a, id); 1003 a.radius = 16; 1004 asc.addAtom(a); 1005 } 1006 getOpMatrix(String ops)1007 private M4 getOpMatrix(String ops) { 1008 if (htBiomts == null) 1009 return M4.newM4(null); 1010 int pt = ops.indexOf("|"); 1011 if (pt >= 0) { 1012 M4 m = M4.newM4(htBiomts.get(ops.substring(0, pt))); 1013 m.mul(htBiomts.get(ops.substring(pt + 1))); 1014 return m; 1015 } 1016 return htBiomts.get(ops); 1017 } 1018 1019 //////////////////////////////////////////////////////////////// 1020 // bond data 1021 //////////////////////////////////////////////////////////////// 1022 1023 // _STRUCT_CONN is only processed in the presence of _CHEM_CONN (2015 updated cif from EBI) 1024 1025 final private static byte STRUCT_CONN_ASYM1 = 0; 1026 final private static byte STRUCT_CONN_SEQ1 = 1; 1027 final private static byte STRUCT_CONN_COMP1 = 2; 1028 final private static byte STRUCT_CONN_ATOM1 = 3; 1029 final private static byte STRUCT_CONN_ALT1 = 4; 1030 final private static byte STRUCT_CONN_SYMM1 = 5; 1031 final private static byte STRUCT_CONN_ASYM2 = 6; 1032 final private static byte STRUCT_CONN_SEQ2 = 7; 1033 final private static byte STRUCT_CONN_COMP2 = 8; 1034 final private static byte STRUCT_CONN_ATOM2 = 9; 1035 final private static byte STRUCT_CONN_ALT2 = 10; 1036 final private static byte STRUCT_CONN_SYMM2 = 11; 1037 final private static byte STRUCT_CONN_TYPE = 12; 1038 final private static byte STRUCT_CONN_ORDER = 13; 1039 1040 1041 final private static String FAMILY_STRUCTCONN_CAT = "_struct_conn."; 1042 1043 final private static String FAMILY_STRUCTCONN = "_struct_conn"; 1044 final private static String[] structConnFields = { 1045 "*_ptnr1_auth_asym_id", 1046 "*_ptnr1_auth_seq_id", 1047 "*_ptnr1_auth_comp_id", 1048 "*_ptnr1_label_atom_id", 1049 "*_pdbx_ptnr1_label_alt_id", 1050 "*_ptnr1_symmetry", 1051 "*_ptnr2_auth_asym_id", 1052 "*_ptnr2_auth_seq_id", 1053 "*_ptnr2_auth_comp_id", 1054 "*_ptnr2_label_atom_id", 1055 "*_pdbx_ptnr2_label_alt_id", 1056 "*_ptnr2_symmetry", 1057 "*_conn_type_id", 1058 "*_pdbx_value_order" 1059 }; 1060 1061 //Allowed Value Details 1062 //covale covalent bond 1063 //covale_base covalent modification of a nucleotide base 1064 //covale_phosphate covalent modification of a nucleotide phosphate 1065 //covale_sugar covalent modification of a nucleotide sugar 1066 //disulf disulfide bridge 1067 //metalc metal coordination 1068 // 1069 //// not used: 1070 //hydrog hydrogen bond 1071 //mismat mismatched base pairs 1072 //modres covalent residue modification 1073 //saltbr ionic interaction 1074 1075 private Lst<Object[]> structConnMap; 1076 private String structConnList = ""; 1077 private boolean doSetBonds; 1078 processStructConnLoopBlock()1079 private boolean processStructConnLoopBlock() throws Exception { 1080 parseLoopParametersFor(FAMILY_STRUCTCONN, structConnFields); 1081 while (cifParser.getData()) { 1082 String sym1 = getField(STRUCT_CONN_SYMM1); 1083 String sym2 = getField(STRUCT_CONN_SYMM2); 1084 if (!sym1.equals(sym2) || !isNull(sym1) && !sym1.equals("1_555")) 1085 continue; 1086 String type = getField(STRUCT_CONN_TYPE); 1087 if (!type.startsWith("covale") && !type.equals("disulf") 1088 && !type.equals("metalc")) 1089 continue; 1090 if (htBondMap == null) 1091 htBondMap = new Hashtable<String, Lst<Object[]>>(); 1092 String key1 = vwr.getChainID(getField(STRUCT_CONN_ASYM1), true) + getField(STRUCT_CONN_COMP1) 1093 + parseFloatStr(getField(STRUCT_CONN_SEQ1)) 1094 + getField(STRUCT_CONN_ATOM1) + getField(STRUCT_CONN_ALT1); 1095 String key2 = vwr.getChainID(getField(STRUCT_CONN_ASYM2), true) + getField(STRUCT_CONN_COMP2) 1096 + parseFloatStr(getField(STRUCT_CONN_SEQ2)) 1097 + getField(STRUCT_CONN_ATOM2) + getField(STRUCT_CONN_ALT2); 1098 int order = getBondOrder(getField(STRUCT_CONN_ORDER)); 1099 if (structConnMap == null) 1100 structConnMap = new Lst<Object[]>(); 1101 structConnMap 1102 .addLast(new Object[] { key1, key2, Integer.valueOf(order) }); 1103 if (structConnList.indexOf(key1) < 0) 1104 structConnList += key1; 1105 if (structConnList.indexOf(key2) < 0) 1106 structConnList += key2; 1107 } 1108 return true; 1109 } 1110 1111 final private static byte CHEM_COMP_BOND_ID = 0; 1112 final private static byte CHEM_COMP_BOND_ATOM_ID_1 = 1; 1113 final private static byte CHEM_COMP_BOND_ATOM_ID_2 = 2; 1114 final private static byte CHEM_COMP_BOND_VALUE_ORDER = 3; 1115 final private static byte CHEM_COMP_BOND_AROMATIC_FLAG = 4; 1116 1117 final private static String FAMILY_COMPBOND_CAT = "_chem_comp_bond."; 1118 1119 final private static String FAMILY_COMPBOND = "_chem_comp_bond"; 1120 final private static String[] chemCompBondFields = { 1121 "*_comp_id", 1122 "*_atom_id_1", 1123 "*_atom_id_2", 1124 "*_value_order", 1125 "*_pdbx_aromatic_flag" 1126 }; 1127 processCompBondLoopBlock()1128 private boolean processCompBondLoopBlock() throws Exception { 1129 doSetBonds = true; 1130 parseLoopParametersFor(FAMILY_COMPBOND, chemCompBondFields); 1131 while (cifParser.getData()) { 1132 String comp = getField(CHEM_COMP_BOND_ID); 1133 String atom1 = getField(CHEM_COMP_BOND_ATOM_ID_1); 1134 String atom2 = getField(CHEM_COMP_BOND_ATOM_ID_2); 1135 int order = getBondOrder(getField(CHEM_COMP_BOND_VALUE_ORDER)); 1136 if ((getField(CHEM_COMP_BOND_AROMATIC_FLAG).charAt(0) == 'Y')) 1137 switch (order) { 1138 case JmolAdapter.ORDER_COVALENT_SINGLE: 1139 order = JmolAdapter.ORDER_AROMATIC_SINGLE; 1140 break; 1141 case JmolAdapter.ORDER_COVALENT_DOUBLE: 1142 order = JmolAdapter.ORDER_AROMATIC_DOUBLE; 1143 break; 1144 } 1145 if (isLigand) { 1146 asc.addNewBondWithOrderA(asc.getAtomFromName(atom1), 1147 asc.getAtomFromName(atom2), order); 1148 } else if (haveHAtoms || htHetero != null && htHetero.containsKey(comp)) { 1149 if (htBondMap == null) 1150 htBondMap = new Hashtable<String, Lst<Object[]>>(); 1151 Lst<Object[]> cmap = htBondMap.get(comp); 1152 if (cmap == null) 1153 htBondMap.put(comp, cmap = new Lst<Object[]>()); 1154 cmap.addLast(new Object[] { atom1, atom2, 1155 Integer.valueOf(haveHAtoms ? order : 1) }); 1156 } 1157 } 1158 return true; 1159 } 1160 1161 @Override processSubclassAtom(Atom atom, String assemblyId, String strChain)1162 public boolean processSubclassAtom(Atom atom, String assemblyId, String strChain) { 1163 if (isBiomolecule) { 1164 if (isCourseGrained) { 1165 P3 sum = chainAtomMap.get(assemblyId); 1166 if (sum == null) { 1167 chainAtomMap.put(assemblyId, sum = new P3()); 1168 chainAtomCounts.put(assemblyId, new int[1]); 1169 } 1170 chainAtomCounts.get(assemblyId)[0]++; 1171 sum.add(atom); 1172 return false; 1173 } 1174 } else if (byChain) { 1175 if (thisChain != atom.chainID) { 1176 thisChain = atom.chainID; 1177 chainSum = chainAtomMap.get(strChain); 1178 if (chainSum == null) { 1179 chainAtomMap.put(strChain, chainSum = new P3()); 1180 chainAtomCounts.put(strChain, chainAtomCount = new int[1]); 1181 } 1182 } 1183 chainSum.add(atom); 1184 chainAtomCount[0]++; 1185 return false; 1186 } 1187 if (assemblyId != null) { 1188 if (assemblyIdAtoms == null) 1189 assemblyIdAtoms = new Hashtable<String, BS>(); 1190 BS bs = assemblyIdAtoms.get(assemblyId); 1191 if (bs == null) 1192 assemblyIdAtoms.put(assemblyId, bs = new BS()); 1193 bs.set(ac); 1194 } 1195 return true; 1196 } 1197 1198 private String modelStrings = ""; 1199 1200 protected boolean done; 1201 1202 @Override checkPDBModelField(int modelField, int currentModelNo)1203 protected int checkPDBModelField(int modelField, int currentModelNo) throws Exception { 1204 // the model field value is only used if 1205 // it is indicated AFTER the file name in the load command, 1206 // not if we have a MODEL keyword before the file name. 1207 1208 fieldProperty(modelField); 1209 int modelNo = parseIntStr(field); 1210 return (modelNo == currentModelNo ? modelNo : incrementModel(modelNo)); 1211 } 1212 incrementModel(int modelNo)1213 protected int incrementModel(int modelNo) throws Exception { 1214 boolean isAssembly = (thisDataSetName != null && thisDataSetName.indexOf("-assembly-") >= 0); 1215 if (isAssembly) { 1216 // Files such as http://www.ebi.ac.uk/pdbe/static/entry/download/2lev-assembly-1.cif.gz 1217 // may require sorting if there are multiple models, since the models are by chain, not by model. 1218 1219 useFileModelNumbers = true; 1220 String key = "," + modelNo + ","; 1221 if (modelStrings.indexOf(key) >= 0) { 1222 requiresSorting = true; 1223 } else { 1224 modelStrings += key; 1225 } 1226 } 1227 if (iHaveDesiredModel && asc.atomSetCount > 0 && !isAssembly) { 1228 done = true; 1229 if (cifParser != null) { 1230 cifParser.skipLoop(false); 1231 // but only this atom loop 1232 skipping = false; 1233 } 1234 continuing = true; 1235 return Integer.MIN_VALUE; 1236 } 1237 int modelNumberToUse = (useFileModelNumbers ? modelNo : ++modelIndex); 1238 setHetero(); 1239 newModel(modelNumberToUse); 1240 if (!skipping) { 1241 nextAtomSet(); 1242 if (modelMap == null || asc.ac == 0) 1243 modelMap = new Hashtable<String, Integer>(); 1244 modelMap.put("" + modelNo, Integer.valueOf(Math.max(0, asc.iSet))); 1245 modelMap 1246 .put("_" + Math.max(0, asc.iSet), Integer.valueOf(modelNo)); 1247 } 1248 return modelNo; 1249 } 1250 setHetero()1251 private void setHetero() { 1252 if (htHetero != null) { 1253 asc.setCurrentModelInfo("hetNames", htHetero); 1254 asc.setInfo("hetNames", htHetero); 1255 } 1256 } 1257 1258 } 1259