1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2021-12-27 10:22:45 -0600 (Mon, 27 Dec 2021) $ 4 * $Revision: 22278 $ 5 6 * 7 * Copyright (C) 2003-2005 The Jmol Development Team 8 * 9 * Contact: jmol-developers@lists.sf.net 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Lesser General Public 13 * License as published by the Free Software Foundation; either 14 * version 2.1 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public 22 * License along with this library; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 24 */ 25 26 package org.jmol.modelset; 27 28 import java.util.Enumeration; 29 import java.util.Hashtable; 30 import java.util.Iterator; 31 import java.util.Map; 32 import java.util.Properties; 33 34 import org.jmol.api.AtomIndexIterator; 35 import org.jmol.api.Interface; 36 import org.jmol.api.JmolModulationSet; 37 import org.jmol.api.SymmetryInterface; 38 import org.jmol.atomdata.AtomData; 39 import org.jmol.atomdata.RadiusData; 40 import org.jmol.bspt.Bspf; 41 import org.jmol.bspt.CubeIterator; 42 import org.jmol.c.PAL; 43 import org.jmol.c.STR; 44 import org.jmol.c.VDW; 45 import org.jmol.modelsetbio.BioModel; 46 import org.jmol.script.ScriptCompiler; 47 import org.jmol.script.T; 48 import org.jmol.shape.Shape; 49 import org.jmol.util.BSUtil; 50 import org.jmol.util.BoxInfo; 51 import org.jmol.util.Edge; 52 import org.jmol.util.Elements; 53 import org.jmol.util.Escape; 54 import org.jmol.util.JmolMolecule; 55 import org.jmol.util.Logger; 56 import org.jmol.util.Point3fi; 57 import org.jmol.util.Rectangle; 58 import org.jmol.util.SimpleUnitCell; 59 import org.jmol.util.Tensor; 60 import org.jmol.util.Vibration; 61 import org.jmol.viewer.JC; 62 import org.jmol.viewer.JmolAsyncException; 63 import org.jmol.viewer.ShapeManager; 64 import org.jmol.viewer.TransformManager; 65 import org.jmol.viewer.Viewer; 66 67 import javajs.util.A4; 68 import javajs.util.AU; 69 import javajs.util.BS; 70 import javajs.util.Lst; 71 import javajs.util.M3; 72 import javajs.util.M4; 73 import javajs.util.Measure; 74 import javajs.util.P3; 75 import javajs.util.P4; 76 import javajs.util.PT; 77 import javajs.util.Quat; 78 import javajs.util.SB; 79 import javajs.util.T3; 80 import javajs.util.V3; 81 82 83 /* 84 * A class always created using new ModelLoader(...) 85 * 86 * Merged with methods in Mmset and ModelManager 10/2007 Jmol 11.3.32 87 * 88 * ModelLoader simply pulls out all private classes that are 89 * necessary only for file loading (and structure recalculation). 90 * 91 * What is left here are all the methods that are 92 * necessary AFTER a model is loaded, when it is being 93 * accessed by Viewer, primarily. 94 * 95 * Please: 96 * 97 * 1) designate any methods used only here as private 98 * 2) designate any methods accessed only by ModelLoader as protected 99 * 3) designate any methods accessed within modelset as nothing 100 * 4) designate any methods accessed only by Viewer as public 101 * 102 * Bob Hanson, 5/2007, 10/2007 103 * 104 */ 105 public class ModelSet extends BondCollection { 106 107 public boolean haveBioModels; 108 109 protected BS bsSymmetry; 110 111 public String modelSetName; 112 113 public Model[] am; 114 /** 115 * model count 116 */ 117 public int mc; 118 119 public SymmetryInterface[] unitCells; 120 public boolean haveUnitCells; 121 122 protected final Atom[] closest; 123 124 protected int[] modelNumbers; // from adapter -- possibly PDB MODEL record; possibly modelFileNumber 125 public int[] modelFileNumbers; // file * 1000000 + modelInFile (1-based) 126 public String[] modelNumbersForAtomLabel, modelNames, frameTitles; 127 128 protected BS[] elementsPresent; 129 130 protected boolean isXYZ; 131 132 public Properties modelSetProperties; 133 public Map<String, Object> msInfo; 134 135 protected boolean someModelsHaveSymmetry; 136 protected boolean someModelsHaveAromaticBonds; 137 protected boolean someModelsHaveFractionalCoordinates; 138 139 //////////////////////////////////////////// 140 141 private boolean isBbcageDefault; 142 public BS bboxModels; 143 private BS bboxAtoms; 144 private final BoxInfo boxInfo; 145 getBoxInfo()146 public BoxInfo getBoxInfo() { 147 return boxInfo; 148 } 149 150 public Lst<StateScript> stateScripts; 151 /* 152 * stateScripts are connect commands that must be executed in sequence. 153 * 154 * What I fear is that in deleting models we must delete these connections, 155 * and in deleting atoms, the bitsets may not be retrieved properly. 156 * 157 * 158 */ 159 private int thisStateModel; 160 161 protected Lst<V3[]> vibrationSteps; 162 163 private BS selectedMolecules; 164 165 //private final static boolean MIX_BSPT_ORDER = false; 166 boolean showRebondTimes = true; 167 168 protected BS bsAll; 169 170 public ShapeManager sm; 171 172 private static float hbondMinRasmol = 2.5f; 173 174 public boolean proteinStructureTainted; 175 176 public Hashtable<String, BS> htPeaks; 177 178 private Quat[] vOrientations; 179 180 private final P3 ptTemp, ptTemp1, ptTemp2; 181 private final M3 matTemp, matInv; 182 private final M4 mat4, mat4t; 183 private final V3 vTemp; 184 185 //////////////////////////////////////////////////////////////// 186 187 /** 188 * 189 * @param vwr 190 * @param name 191 */ ModelSet(Viewer vwr, String name)192 public ModelSet(Viewer vwr, String name) { 193 this.vwr = vwr; 194 modelSetName = name; 195 196 selectedMolecules = new BS(); 197 stateScripts = new Lst<StateScript>(); 198 199 boxInfo = new BoxInfo(); 200 boxInfo.addBoundBoxPoint(P3.new3(-10, -10, -10)); 201 boxInfo.addBoundBoxPoint(P3.new3(10, 10, 10)); 202 203 am = new Model[1]; 204 modelNumbers = new int[1]; // from adapter -- possibly PDB MODEL record; possibly modelFileNumber 205 modelFileNumbers = new int[1]; // file * 1000000 + modelInFile (1-based) 206 modelNumbersForAtomLabel = new String[1]; 207 modelNames = new String[1]; 208 frameTitles = new String[1]; 209 210 closest = new Atom[1]; 211 212 ptTemp = new P3(); 213 ptTemp1 = new P3(); 214 ptTemp2 = new P3(); 215 matTemp = new M3(); 216 matInv = new M3(); 217 mat4 = new M4(); 218 mat4t = new M4(); 219 vTemp = new V3(); 220 221 setupBC(); 222 } 223 releaseModelSet()224 protected void releaseModelSet() { 225 am = null; 226 closest[0] = null; 227 /* 228 * Probably unnecessary, but here for general accounting. 229 * 230 * I added this when I was trying to track down a memory bug. 231 * I know that you don't have to do this, but I was concerned 232 * that somewhere in this mess was a reference to modelSet. 233 * As it turns out, it was in models[i] (which was not actually 234 * nulled but, rather, transferred to the new model set anyway). 235 * Quite amazing that that worked at all, really. Some models were 236 * referencing the old modelset, some the new. Yeiks! 237 * 238 * Bob Hanson 11/7/07 239 * 240 */ 241 am = null; 242 bsSymmetry = null; 243 bsAll = null; 244 unitCells = null; 245 releaseModelSetBC(); 246 } 247 248 //variables that will be reset when a new frame is instantiated 249 250 private boolean echoShapeActive = false; 251 getEchoStateActive()252 public boolean getEchoStateActive() { 253 return echoShapeActive; 254 } 255 setEchoStateActive(boolean TF)256 public void setEchoStateActive(boolean TF) { 257 echoShapeActive = TF; 258 } 259 260 protected String modelSetTypeName; 261 getModelSetTypeName()262 public String getModelSetTypeName() { 263 return modelSetTypeName; 264 } 265 266 /** 267 * 268 * @param modelNumber 269 * can be a PDB MODEL number or a simple index number, or a fffnnnnnn 270 * f.n number 271 * @param useModelNumber 272 * @param doSetTrajectory 273 * @return index 274 */ getModelNumberIndex(int modelNumber, boolean useModelNumber, boolean doSetTrajectory)275 public int getModelNumberIndex(int modelNumber, boolean useModelNumber, 276 boolean doSetTrajectory) { 277 if (useModelNumber) { 278 for (int i = 0; i < mc; i++) 279 if (modelNumbers[i] == modelNumber || modelNumber < 1000000 280 && modelNumbers[i] == 1000000 + modelNumber) 281 return i; 282 return -1; 283 } 284 if (modelNumber < 1000000) 285 return modelNumber; 286 //new decimal format: frame 1.2 1.3 1.4 287 for (int i = 0; i < mc; i++) 288 if (modelFileNumbers[i] == modelNumber) { 289 if (doSetTrajectory && isTrajectory(i)) 290 setTrajectory(i); 291 return i; 292 } 293 return -1; 294 } 295 getModelDataBaseName(BS bsAtoms)296 public String getModelDataBaseName(BS bsAtoms) { 297 for (int i = 0; i < mc; i++) { 298 if (bsAtoms.equals(am[i].bsAtoms)) 299 return (String) getInfo(i, "dbName"); 300 } 301 return null; 302 } 303 setTrajectory(int modelIndex)304 public void setTrajectory(int modelIndex) { 305 if (modelIndex >= 0 && isTrajectory(modelIndex) 306 && at[am[modelIndex].firstAtomIndex].mi != modelIndex) 307 trajectory.setModel(modelIndex); 308 } 309 getBitSetTrajectories()310 public BS getBitSetTrajectories() { 311 return (trajectory == null ? null : trajectory.getModelsSelected()); 312 } 313 setTrajectoryBs(BS bsModels)314 public void setTrajectoryBs(BS bsModels) { 315 if (trajectory != null) 316 for (int i = 0; i < mc; i++) 317 if (bsModels.get(i)) 318 setTrajectory(i); 319 } 320 morphTrajectories(int m1, int m2, float f)321 public void morphTrajectories(int m1, int m2, float f) { 322 if (m1 >= 0 && m2 >= 0 && isTrajectory(m1) && isTrajectory(m2)) 323 trajectory.morph(m1, m2, f); 324 } 325 326 public P3[] translations; 327 getTranslation(int iModel)328 public P3 getTranslation(int iModel) { 329 return (translations == null || iModel >= translations.length ? null 330 : translations[iModel]); 331 } 332 333 /** 334 * move atoms by vector pt; used for co-centering with FRAME ALIGN {atoms} 335 * TRUE 336 * 337 * @param iModel 338 * @param pt 339 */ translateModel(int iModel, T3 pt)340 public void translateModel(int iModel, T3 pt) { 341 if (pt == null) { 342 P3 t = getTranslation(iModel); 343 if (t == null) 344 return; 345 pt = P3.newP(t); 346 pt.scale(-1); 347 translateModel(iModel, pt); 348 translations[iModel] = null; 349 return; 350 } 351 if (translations == null || translations.length <= iModel) 352 translations = new P3[mc]; 353 if (translations[iModel] == null) 354 translations[iModel] = new P3(); 355 translations[iModel].add(pt); 356 BS bs = am[iModel].bsAtoms; 357 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) 358 at[i].add(pt); 359 } 360 getFrameOffsets(BS bsAtoms, boolean isFull)361 public P3[] getFrameOffsets(BS bsAtoms, boolean isFull) { 362 if (bsAtoms == null) { 363 if (isFull) 364 for (int i = mc; --i >= 0;) { 365 Model m = am[i]; 366 if (!m.isJmolDataFrame && !m.isTrajectory) 367 translateModel(m.modelIndex, null); 368 } 369 return null; 370 } 371 int i0 = bsAtoms.nextSetBit(0); 372 if (i0 < 0) 373 return null; 374 if (isFull) { 375 BS bs = BSUtil.copy(bsAtoms); 376 P3 pt = null; 377 P3 pdiff = new P3(); 378 for (int i = 0; i < mc; i++) { 379 Model m = am[i]; 380 if (!m.isJmolDataFrame && !m.isTrajectory) { 381 int j = bs.nextSetBit(0); 382 if (m.bsAtoms.get(j)) { 383 if (pt == null) { 384 pt = P3.newP(at[j]); 385 } else { 386 pdiff.sub2(pt, at[j]); 387 translateModel(i, pdiff); 388 } 389 } 390 } 391 bs.andNot(m.bsAtoms); 392 } 393 return null; 394 } 395 P3[] offsets = new P3[mc]; 396 for (int i = mc; --i >= 0;) 397 offsets[i] = new P3(); 398 int lastModel = 0; 399 int n = 0; 400 P3 offset = offsets[0]; 401 boolean asTrajectory = (trajectory != null && trajectory.steps.size() == mc); 402 int m1 = (asTrajectory ? mc : 1); 403 offsets[0].set(0, 0, 0); 404 for (int m = 0; m < m1; m++) { 405 if (asTrajectory) 406 setTrajectory(m); 407 for (int i = 0; i <= ac; i++) { 408 if (i == ac || at[i].mi != lastModel) { 409 if (n > 0) { 410 offset.scale(-1.0f / n); 411 if (lastModel != 0) 412 offset.sub(offsets[0]); 413 n = 0; 414 } 415 if (i == ac) 416 break; 417 lastModel = at[i].mi; 418 offset = offsets[lastModel]; 419 } 420 if (!bsAtoms.get(i)) 421 continue; 422 offset.add(at[i]); 423 n++; 424 } 425 } 426 return offsets; 427 } 428 429 /** 430 * general lookup for integer type -- from Eval 431 * 432 * @param tokType 433 * @param specInfo 434 * @return bitset; null only if we mess up with name 435 */ getAtoms(int tokType, Object specInfo)436 public BS getAtoms(int tokType, Object specInfo) { 437 switch (tokType) { 438 default: 439 return BSUtil.andNot(getAtomBitsMaybeDeleted(tokType, specInfo), 440 vwr.slm.bsDeleted); 441 case T.spec_model: 442 int modelNumber = ((Integer) specInfo).intValue(); 443 int modelIndex = getModelNumberIndex(modelNumber, true, true); 444 return (modelIndex < 0 && modelNumber > 0 ? new BS() : vwr 445 .getModelUndeletedAtomsBitSet(modelIndex)); 446 case T.polyhedra: 447 Object[] data = new Object[] { null, null, null }; 448 vwr.shm.getShapePropertyData(JC.SHAPE_POLYHEDRA, "getCenters", data); 449 return (data[1] == null ? new BS() : (BS) data[1]); 450 } 451 } 452 findNearestAtomIndex(int x, int y, BS bsNot, int min)453 public int findNearestAtomIndex(int x, int y, BS bsNot, int min) { 454 if (ac == 0) 455 return -1; 456 closest[0] = null; 457 if (g3d.isAntialiased()) { 458 x <<= 1; 459 y <<= 1; 460 } 461 findNearest2(x, y, closest, bsNot, min); 462 sm.findNearestShapeAtomIndex(x, y, closest, bsNot); 463 int closestIndex = (closest[0] == null ? -1 : closest[0].i); 464 closest[0] = null; 465 return closestIndex; 466 } 467 468 /* 469 private Map userProperties; 470 471 void putUserProperty(String name, Object property) { 472 if (userProperties == null) 473 userProperties = new Hashtable(); 474 if (property == null) 475 userProperties.remove(name); 476 else 477 userProperties.put(name, property); 478 } 479 */ 480 481 ///////// atom and shape selecting ///////// 482 calculatePointGroup(BS bsAtoms)483 public String calculatePointGroup(BS bsAtoms) { 484 return (String) calculatePointGroupForFirstModel(bsAtoms, false, 485 false, null, 0, 0, null, null, null); 486 } 487 488 @SuppressWarnings("unchecked") getPointGroupInfo(BS bsAtoms)489 public Map<String, Object> getPointGroupInfo(BS bsAtoms) { 490 return (Map<String, Object>) calculatePointGroupForFirstModel(bsAtoms, 491 false, true, null, 0, 0, null, null, null); 492 } 493 getPointGroupAsString(BS bsAtoms, String type, int index, float scale, P3[] pts, P3 center, String id)494 public String getPointGroupAsString(BS bsAtoms, String type, 495 int index, float scale, P3[] pts, P3 center, String id) { 496 return (String) calculatePointGroupForFirstModel(bsAtoms, true, 497 false, type, index, scale, pts, center, id); 498 } 499 500 private BoxInfo defaultBBox; 501 calculatePointGroupForFirstModel(BS bsAtoms, boolean doAll, boolean asInfo, String type, int index, float scale, T3[] pts, P3 center, String id)502 private Object calculatePointGroupForFirstModel(BS bsAtoms, boolean doAll, 503 boolean asInfo, String type, 504 int index, float scale, 505 T3[] pts, P3 center, String id) { 506 SymmetryInterface pointGroup = this.pointGroup; 507 SymmetryInterface symmetry = Interface.getSymmetry(vwr, "ms"); 508 BS bs = null; 509 boolean haveVibration = false; 510 boolean isPolyhedron = false; 511 boolean localEnvOnly = false; 512 boolean isPoints = (pts != null); 513 int modelIndex = vwr.am.cmi; 514 if (!isPoints) { 515 int iAtom = (bsAtoms == null ? -1 : bsAtoms.nextSetBit(0)); 516 if (modelIndex < 0 && iAtom >= 0) 517 modelIndex = at[iAtom].mi; 518 if (modelIndex < 0) { 519 modelIndex = vwr.getVisibleFramesBitSet().nextSetBit(0); 520 bsAtoms = null; 521 } 522 bs = vwr.getModelUndeletedAtomsBitSet(modelIndex); 523 localEnvOnly = (bsAtoms != null && bs.cardinality() != bsAtoms 524 .cardinality()); 525 if (bsAtoms != null) 526 bs.and(bsAtoms); 527 iAtom = bs.nextSetBit(0); 528 if (iAtom < 0) { 529 bs = vwr.getModelUndeletedAtomsBitSet(modelIndex); 530 iAtom = bs.nextSetBit(0); 531 } 532 Object obj = vwr.shm 533 .getShapePropertyIndex(JC.SHAPE_VECTORS, "mad", iAtom); 534 haveVibration = (obj != null && ((Integer) obj).intValue() != 0 || vwr.tm.vibrationOn); 535 isPolyhedron = (type != null && type.toUpperCase().indexOf(":POLY") >= 0); 536 if (isPolyhedron) { 537 Object[] data = new Object[] { Integer.valueOf(iAtom), null }; 538 vwr.shm.getShapePropertyData(JC.SHAPE_POLYHEDRA, "points", data); 539 pts = (T3[]) data[1]; 540 if (pts == null) 541 return null; 542 bs = null; 543 haveVibration = false; 544 pointGroup = null; 545 } else { 546 pts = at; 547 } 548 } 549 550 int tp; 551 if (type != null && (tp = type.indexOf(":")) >= 0) 552 type = type.substring(0, tp); 553 if (type != null && (tp = type.indexOf(".")) >= 0) { 554 index = PT.parseInt(type.substring(tp + 1)); 555 if (index < 0) 556 index = 0; 557 type = type.substring(0, tp); 558 } 559 pointGroup = symmetry.setPointGroup(pointGroup, center, pts, bs, 560 haveVibration, (isPoints ? 0 : vwr.getFloat(T.pointgroupdistancetolerance)), 561 vwr.getFloat(T.pointgrouplineartolerance), localEnvOnly); 562 if (!isPolyhedron && !isPoints) 563 this.pointGroup = pointGroup; 564 if (!doAll && !asInfo) 565 return pointGroup.getPointGroupName(); 566 Object ret = pointGroup.getPointGroupInfo(modelIndex, id, asInfo, type, 567 index, scale); 568 return (asInfo ? ret : (mc > 1 ? "frame " 569 + getModelNumberDotted(modelIndex) + "; " : "") 570 + ret); 571 } 572 getDefaultStructure(BS bsAtoms, BS bsModified)573 public String getDefaultStructure(BS bsAtoms, BS bsModified) { 574 return (haveBioModels ? bioModelset.getAllDefaultStructures(bsAtoms, 575 bsModified) : ""); 576 } 577 deleteModelBonds(int modelIndex)578 public void deleteModelBonds(int modelIndex) { 579 BS bsAtoms = getModelAtomBitSetIncludingDeleted(modelIndex, false); 580 makeConnections(0, Float.MAX_VALUE, Edge.BOND_ORDER_NULL, T.delete, bsAtoms, bsAtoms, null, false, false, 0); 581 } 582 583 ///// super-overloaded methods /////// 584 makeConnections(float minDistance, float maxDistance, int order, int connectOperation, BS bsA, BS bsB, BS bsBonds, boolean isBonds, boolean addGroup, float energy)585 public int[] makeConnections(float minDistance, float maxDistance, int order, 586 int connectOperation, BS bsA, BS bsB, 587 BS bsBonds, boolean isBonds, boolean addGroup, 588 float energy) { 589 if (connectOperation == T.auto && order != Edge.BOND_H_REGULAR) { 590 String stateScript = "connect "; 591 if (minDistance != JC.DEFAULT_MIN_CONNECT_DISTANCE) 592 stateScript += minDistance + " "; 593 if (maxDistance != JC.DEFAULT_MAX_CONNECT_DISTANCE) 594 stateScript += maxDistance + " "; 595 addStateScript(stateScript, (isBonds ? bsA : null), 596 (isBonds ? null : bsA), (isBonds ? null : bsB), " auto", false, true); 597 } 598 moleculeCount = 0; 599 return makeConnections2(minDistance, maxDistance, order, connectOperation, 600 bsA, bsB, bsBonds, isBonds, addGroup, energy); 601 } 602 603 @SuppressWarnings("unchecked") setPdbConectBonding(int baseAtomIndex, int baseModelIndex, BS bsExclude)604 public void setPdbConectBonding(int baseAtomIndex, int baseModelIndex, 605 BS bsExclude) { 606 short mad = vwr.getMadBond(); 607 for (int i = baseModelIndex; i < mc; i++) { 608 Lst<int[]> vConnect = (Lst<int[]>) getInfo(i, "PDB_CONECT_bonds"); 609 if (vConnect == null) 610 continue; 611 int nConnect = vConnect.size(); 612 setInfo(i, "initialBondCount", Integer.valueOf(nConnect)); 613 int[] atomInfo = (int[]) getInfo(i, "PDB_CONECT_firstAtom_count_max"); 614 int firstAtom = atomInfo[0] + baseAtomIndex; 615 int atomMax = firstAtom + atomInfo[1]; 616 int max = atomInfo[2]; 617 int[] serialMap = new int[max + 1]; 618 int iSerial; 619 for (int iAtom = firstAtom; iAtom < atomMax; iAtom++) 620 if ((iSerial = atomSerials[iAtom]) > 0) 621 serialMap[iSerial] = iAtom + 1; 622 for (int iConnect = 0; iConnect < nConnect; iConnect++) { 623 int[] pair = vConnect.get(iConnect); 624 int sourceSerial = pair[0]; 625 int targetSerial = pair[1]; 626 short order = (short) pair[2]; 627 if (sourceSerial < 0 || targetSerial < 0 || sourceSerial > max 628 || targetSerial > max) 629 continue; 630 int sourceIndex = serialMap[sourceSerial] - 1; 631 int targetIndex = serialMap[targetSerial] - 1; 632 if (sourceIndex < 0 || targetIndex < 0) 633 continue; 634 Atom atomA = at[sourceIndex]; 635 Atom atomB = at[targetIndex]; 636 if (bsExclude != null) { 637 if (atomA.isHetero()) 638 bsExclude.set(sourceIndex); 639 if (atomB.isHetero()) 640 bsExclude.set(targetIndex); 641 } 642 // don't connect differing altloc 643 if (atomA.altloc == atomB.altloc || atomA.altloc == '\0' 644 || atomB.altloc == '\0') 645 getOrAddBond(atomA, atomB, order, (order == Edge.BOND_H_REGULAR ? 1 646 : mad), null, 0, false); 647 } 648 } 649 } 650 deleteAllBonds()651 public void deleteAllBonds() { 652 moleculeCount = 0; 653 for (int i = stateScripts.size(); --i >= 0;) { 654 if (stateScripts.get(i).isConnect()) { 655 stateScripts.removeItemAt(i); 656 } 657 } 658 deleteAllBonds2(); 659 } 660 661 /* ****************************************************** 662 * 663 * methods for definining the state 664 * 665 ********************************************************/ 666 includeAllRelatedFrames(BS bsModels)667 private void includeAllRelatedFrames(BS bsModels) { 668 int baseModel = 0; 669 for (int i = 0; i < mc; i++) { 670 boolean isTraj = isTrajectory(i); 671 boolean isBase = (isTraj && bsModels 672 .get(baseModel = am[i].trajectoryBaseIndex)); 673 if (bsModels.get(i)) { 674 if (isTraj && !isBase) { 675 bsModels.set(baseModel); 676 includeAllRelatedFrames(bsModels); 677 return; 678 } 679 } else if (isTraj || isJmolDataFrameForModel(i) 680 && bsModels.get(am[i].dataSourceFrame)) { 681 bsModels.set(i); 682 } 683 } 684 } 685 deleteModels(BS bsModels)686 public BS deleteModels(BS bsModels) { 687 // full models are deleted for any model containing the specified atoms 688 includeAllRelatedFrames(bsModels); 689 690 int nModelsDeleted = bsModels.cardinality(); 691 if (nModelsDeleted == 0) 692 return null; 693 694 moleculeCount = 0; 695 if (msInfo != null) 696 msInfo.remove("models"); 697 698 // clear references to this frame if it is a dataFrame 699 700 for (int i = bsModels.nextSetBit(0); i >= 0; i = bsModels.nextSetBit(i + 1)) 701 clearDataFrameReference(i); 702 703 BS bsDeleted; 704 if (nModelsDeleted == mc) { 705 bsDeleted = getModelAtomBitSetIncludingDeleted(-1, true); 706 vwr.zap(true, false, false); 707 return bsDeleted; 708 } 709 710 // zero out reproducible arrays 711 712 validateBspf(false); 713 714 bsDeleted = new BS(); 715 // if atoms have been added to a not-last model, and that model is not one being deleted, 716 // then we can't (yet) delete the model AND shift any values. 717 boolean allOrderly = true; 718 boolean isOneOfSeveral = false; 719 BS files = new BS(); 720 for (int i = 0; i < mc; i++) { 721 Model m = am[i]; 722 allOrderly &= m.isOrderly;//isOrderly(m); 723 if (bsModels.get(i)) { // get a good count now 724 if (m.fileIndex >= 0) 725 files.set(m.fileIndex); 726 bsDeleted.or(getModelAtomBitSetIncludingDeleted(i, false)); 727 } else { 728 if (m.fileIndex >= 0 && files.get(m.fileIndex)) 729 isOneOfSeveral = true; 730 } 731 } 732 if (!allOrderly || isOneOfSeveral) { 733 vwr.deleteAtoms(bsDeleted, false); 734 return null; 735 } 736 // create a new models array, 737 // and pre-calculate Model.bsAtoms and Model.ac 738 Model[] newModels = new Model[mc - nModelsDeleted]; 739 Model[] oldModels = am; 740 for (int i = 0, mpt = 0; i < mc; i++) { 741 if (!bsModels.get(i)) { // get a good count now 742 Model m = am[i]; 743 // TODO this does not account for file numbers! 744 m.modelIndex = mpt; 745 newModels[mpt++] = m; 746 } 747 } 748 am = newModels; 749 int oldModelCount = mc; 750 // delete bonds 751 BS bsBonds = getBondsForSelectedAtoms(bsDeleted, true); 752 deleteBonds(bsBonds, true); 753 754 // main deletion cycle 755 756 for (int i = 0, mpt = 0; i < oldModelCount; i++) { 757 if (!bsModels.get(i)) { 758 mpt++; 759 continue; 760 } 761 Model old = oldModels[i]; 762 int nAtoms = old.act; 763 if (nAtoms == 0) 764 continue; 765 BS bsModelAtoms = old.bsAtoms; 766 int firstAtomIndex = old.firstAtomIndex; 767 768 // delete from symmetry set 769 BSUtil.deleteBits(bsSymmetry, bsModelAtoms); 770 771 // delete from stateScripts, model arrays and bitsets, 772 // atom arrays, and atom bitsets 773 deleteModel(mpt, bsModelAtoms, bsBonds); 774 775 deleteModelAtoms(firstAtomIndex, nAtoms, bsModelAtoms); 776 vwr.deleteModelAtoms(mpt, firstAtomIndex, nAtoms, bsModelAtoms); 777 778 779 // adjust all models after this one 780 for (int j = oldModelCount; --j > i;) 781 oldModels[j].fixIndices(mpt, nAtoms, bsModelAtoms); 782 783 // adjust all shapes 784 vwr.shm.deleteShapeAtoms(new Object[] { newModels, at, 785 new int[] { mpt, firstAtomIndex, nAtoms } }, bsModelAtoms); 786 mc--; 787 } 788 789 // set final values 790 //final deletions 791 haveBioModels = false; 792 for (int i = mc; --i >= 0;) 793 if (am[i].isBioModel) { 794 haveBioModels = true; 795 bioModelset.set(vwr, this); 796 } 797 validateBspf(false); 798 bsAll = null; 799 resetMolecules(); 800 isBbcageDefault = false; 801 calcBoundBoxDimensions(null, 1); 802 return bsDeleted; 803 } 804 resetMolecules()805 public void resetMolecules() { 806 bsAll = null; 807 molecules = null; 808 moleculeCount = 0; 809 resetChirality(); 810 } 811 resetChirality()812 private void resetChirality() { 813 if (haveChirality) { 814 int modelIndex = -1; 815 for (int i = ac; --i >= 0;) { 816 Atom a = at[i]; 817 if (a == null) 818 continue; 819 a.setCIPChirality(0); 820 if (a.mi != modelIndex && a.mi < am.length) 821 am[modelIndex = a.mi].hasChirality = false; 822 } 823 } 824 } 825 deleteModel(int modelIndex, BS bsModelAtoms, BS bsBonds)826 private void deleteModel(int modelIndex, BS bsModelAtoms, BS bsBonds) { 827 /* 828 * ModelCollection.modelSetAuxiliaryInfo["group3Lists", "group3Counts, "models"] 829 * ModelCollection.stateScripts ????? 830 */ 831 if (modelIndex < 0) { 832 return; 833 } 834 835 modelNumbers = (int[]) AU.deleteElements(modelNumbers, modelIndex, 1); 836 modelFileNumbers = (int[]) AU.deleteElements(modelFileNumbers, modelIndex, 837 1); 838 modelNumbersForAtomLabel = (String[]) AU.deleteElements( 839 modelNumbersForAtomLabel, modelIndex, 1); 840 modelNames = (String[]) AU.deleteElements(modelNames, modelIndex, 1); 841 frameTitles = (String[]) AU.deleteElements(frameTitles, modelIndex, 1); 842 thisStateModel = -1; 843 String[] group3Lists = (String[]) getInfoM("group3Lists"); 844 int[][] group3Counts = (int[][]) getInfoM("group3Counts"); 845 int ptm = modelIndex + 1; 846 if (group3Lists != null && group3Lists[ptm] != null) { 847 for (int i = group3Lists[ptm].length() / 6; --i >= 0;) 848 if (group3Counts[ptm][i] > 0) { 849 group3Counts[0][i] -= group3Counts[ptm][i]; 850 if (group3Counts[0][i] == 0) 851 group3Lists[0] = group3Lists[0].substring(0, i * 6) + ",[" 852 + group3Lists[0].substring(i * 6 + 2); 853 } 854 } 855 if (group3Lists != null) { 856 msInfo.put("group3Lists", AU.deleteElements(group3Lists, modelIndex, 1)); 857 msInfo 858 .put("group3Counts", AU.deleteElements(group3Counts, modelIndex, 1)); 859 } 860 861 //fix cellInfos array 862 if (unitCells != null) { 863 unitCells = (SymmetryInterface[]) AU.deleteElements(unitCells, 864 modelIndex, 1); 865 } 866 867 // correct stateScripts, particularly CONNECT scripts 868 for (int i = stateScripts.size(); --i >= 0;) { 869 if (!stateScripts.get(i).deleteAtoms(modelIndex, bsBonds, bsModelAtoms)) { 870 stateScripts.removeItemAt(i); 871 } 872 } 873 } 874 setAtomProperty(BS bs, int tok, int iValue, float fValue, String sValue, float[] values, String[] list)875 public void setAtomProperty(BS bs, int tok, int iValue, float fValue, 876 String sValue, float[] values, String[] list) { 877 switch (tok) { 878 case T.backbone: 879 case T.cartoon: 880 case T.meshRibbon: 881 case T.ribbon: 882 case T.rocket: 883 case T.strands: 884 case T.trace: 885 if (fValue > Shape.RADIUS_MAX) 886 fValue = Shape.RADIUS_MAX; 887 if (values != null) { 888 // convert to atom indices 889 float[] newValues = new float[ac]; 890 try { 891 for (int i = bs.nextSetBit(0), ii = 0; i >= 0; i = bs 892 .nextSetBit(i + 1)) 893 newValues[i] = values[ii++]; 894 } catch (Exception e) { 895 return; 896 } 897 values = newValues; 898 } 899 //$FALL-THROUGH$ 900 case T.halo: 901 case T.star: 902 RadiusData rd = null; 903 int mar = 0; 904 if (values == null) { 905 if (fValue > Atom.RADIUS_MAX) 906 fValue = Atom.RADIUS_GLOBAL; 907 if (fValue < 0) 908 fValue = 0; 909 mar = (int) Math.floor(fValue * 2000); 910 } else { 911 rd = new RadiusData(values, 0, null, null); 912 } 913 sm.setShapeSizeBs(JC.shapeTokenIndex(tok), mar, rd, bs); 914 return; 915 } 916 setAPm(bs, tok, iValue, fValue, sValue, values, list); 917 } 918 919 @SuppressWarnings("unchecked") getFileData(int modelIndex)920 public Object getFileData(int modelIndex) { 921 if (modelIndex < 0) 922 return ""; 923 Map<String, Object> fileData = (Map<String, Object>) getInfo(modelIndex, 924 "fileData"); 925 if (fileData != null) 926 return fileData; 927 if (!getInfoB(modelIndex, "isCIF")) 928 return getPDBHeader(modelIndex); 929 fileData = vwr.getCifData(modelIndex); 930 setInfo(modelIndex, "fileData", fileData); 931 return fileData; 932 } 933 934 /** 935 * these are hydrogens that are being added due to a load 2D command and are 936 * therefore not to be flagged as NEW 937 * 938 * @param vConnections 939 * @param pts 940 * @return BitSet of new atoms 941 */ addHydrogens(Lst<Atom> vConnections, P3[] pts)942 public BS addHydrogens(Lst<Atom> vConnections, P3[] pts) { 943 int modelIndex = mc - 1; 944 BS bs = new BS(); 945 if (isTrajectory(modelIndex) || am[modelIndex].getGroupCount() > 1) { 946 // can't add atoms to a trajectory or a system with multiple groups! 947 return bs; 948 } 949 growAtomArrays(ac + pts.length); 950 RadiusData rd = vwr.rd; 951 short mad = getDefaultMadFromOrder(1); 952 am[modelIndex].resetDSSR(false); 953 for (int i = 0, n = am[modelIndex].act + 1; i < vConnections.size(); i++, n++) { 954 Atom atom1 = vConnections.get(i); 955 // hmm. atom1.group will not be expanded, though... 956 // something like within(group,...) will not select these atoms! 957 Atom atom2 = addAtom(modelIndex, atom1.group, 1, "H" + n, null, n, 958 atom1.getSeqID(), n, pts[i], Float.NaN, null, 0, 0, 100, Float.NaN, 959 null, false, (byte) 0, null, Float.NaN); 960 961 atom2.setMadAtom(vwr, rd); 962 bs.set(atom2.i); 963 bondAtoms(atom1, atom2, Edge.BOND_COVALENT_SINGLE, mad, null, 0, false, 964 false); 965 } 966 // must reset the shapes to give them new atom counts and arrays 967 sm.loadDefaultShapes(this); 968 return bs; 969 } 970 971 /** 972 * initial transfer of model data from old to new model set. Note that all new 973 * models are added later, AFTER thfe old ones. This is very important, 974 * because all of the old atom numbers must map onto the same numbers in the 975 * new model set, or the state script will not run properly, among other 976 * problems. 977 * 978 * @param mergeModelSet 979 */ mergeModelArrays(ModelSet mergeModelSet)980 protected void mergeModelArrays(ModelSet mergeModelSet) { 981 at = mergeModelSet.at; 982 bo = mergeModelSet.bo; 983 stateScripts = mergeModelSet.stateScripts; 984 proteinStructureTainted = mergeModelSet.proteinStructureTainted; 985 thisStateModel = -1; 986 bsSymmetry = mergeModelSet.bsSymmetry; 987 modelFileNumbers = mergeModelSet.modelFileNumbers; // file * 1000000 + modelInFile (1-based) 988 modelNumbersForAtomLabel = mergeModelSet.modelNumbersForAtomLabel; 989 modelNames = mergeModelSet.modelNames; 990 modelNumbers = mergeModelSet.modelNumbers; 991 frameTitles = mergeModelSet.frameTitles; 992 haveChirality = mergeModelSet.haveChirality; 993 if (msInfo != null) 994 msInfo.remove("models"); 995 mergeAtomArrays(mergeModelSet); 996 } 997 getUnitCell(int modelIndex)998 public SymmetryInterface getUnitCell(int modelIndex) { 999 if (modelIndex < 0 || modelIndex >= mc) 1000 return null; 1001 if (am[modelIndex].simpleCage != null) 1002 return am[modelIndex].simpleCage; 1003 if (unitCells != null && modelIndex < unitCells.length 1004 && unitCells[modelIndex] != null && unitCells[modelIndex].haveUnitCell()) 1005 return unitCells[modelIndex]; 1006 if (getInfo(modelIndex, "unitCellParams") != null) { 1007 if (unitCells == null) 1008 unitCells = new SymmetryInterface[mc]; 1009 haveUnitCells = true; 1010 return unitCells[modelIndex] = vwr.getSymTemp().setSymmetryInfo(modelIndex, 1011 am[modelIndex].auxiliaryInfo, null); 1012 } 1013 return null; 1014 } 1015 setModelCage(int modelIndex, SymmetryInterface simpleCage)1016 public void setModelCage(int modelIndex, SymmetryInterface simpleCage) { 1017 if (modelIndex >= 0 && modelIndex < mc) { 1018 am[modelIndex].simpleCage = simpleCage; 1019 haveUnitCells = true; 1020 } 1021 } 1022 getModelName(int modelIndex)1023 public String getModelName(int modelIndex) { 1024 return mc < 1 ? "" : modelIndex >= 0 ? modelNames[modelIndex] 1025 : modelNumbersForAtomLabel[-1 - modelIndex]; 1026 } 1027 getModelTitle(int modelIndex)1028 public String getModelTitle(int modelIndex) { 1029 return (String) getInfo(modelIndex, "title"); 1030 } 1031 getModelFileName(int modelIndex)1032 public String getModelFileName(int modelIndex) { 1033 return (String) getInfo(modelIndex, "fileName"); 1034 } 1035 getModelFileType(int modelIndex)1036 public String getModelFileType(int modelIndex) { 1037 return (String) getInfo(modelIndex, "fileType"); 1038 } 1039 setFrameTitle(BS bsFrames, Object title)1040 public void setFrameTitle(BS bsFrames, Object title) { 1041 if (title instanceof String) { 1042 for (int i = bsFrames.nextSetBit(0); i >= 0; i = bsFrames 1043 .nextSetBit(i + 1)) 1044 frameTitles[i] = (String) title; 1045 } else { 1046 String[] list = (String[]) title; 1047 for (int i = bsFrames.nextSetBit(0), n = 0; i >= 0; i = bsFrames 1048 .nextSetBit(i + 1)) 1049 if (n < list.length) 1050 frameTitles[i] = list[n++]; 1051 } 1052 } 1053 getFrameTitle(int modelIndex)1054 public String getFrameTitle(int modelIndex) { 1055 return (modelIndex >= 0 && modelIndex < mc ? frameTitles[modelIndex] : ""); 1056 } 1057 getModelNumberForAtomLabel(int modelIndex)1058 public String getModelNumberForAtomLabel(int modelIndex) { 1059 return modelNumbersForAtomLabel[modelIndex]; 1060 } 1061 1062 /** 1063 * In versions earlier than 12.1.51, groups[] was a field of ModelCollection. 1064 * But this is not necessary, and it was wasting space. This method is only 1065 * called when polymers are recreated. 1066 * 1067 * @return full array of groups in modelSet 1068 */ getGroups()1069 public Group[] getGroups() { 1070 int n = 0; 1071 for (int i = 0; i < mc; i++) 1072 n += am[i].getGroupCount(); 1073 Group[] groups = new Group[n]; 1074 for (int i = 0, iGroup = 0; i < mc; i++) 1075 for (int j = 0; j < am[i].chainCount; j++) 1076 for (int k = 0; k < am[i].chains[j].groupCount; k++) { 1077 groups[iGroup] = am[i].chains[j].groups[k]; 1078 groups[iGroup].groupIndex = iGroup; 1079 iGroup++; 1080 } 1081 return groups; 1082 } 1083 1084 /** 1085 * deprecated due to multimodel issues, but required by an interface -- do NOT 1086 * remove. 1087 * 1088 * @return just the first unit cell 1089 * 1090 */ getUnitCellParams()1091 public float[] getUnitCellParams() { 1092 SymmetryInterface c = getUnitCell(0); 1093 return (c == null ? null : c.getUnitCellParams()); 1094 } 1095 setCrystallographicDefaults()1096 public boolean setCrystallographicDefaults() { 1097 return !haveBioModels && someModelsHaveSymmetry 1098 && someModelsHaveFractionalCoordinates; 1099 } 1100 getBoundBoxCenter(int modelIndex)1101 public P3 getBoundBoxCenter(int modelIndex) { 1102 return (isJmolDataFrameForModel(modelIndex) ? new P3() 1103 : (getDefaultBoundBox() == null ? boxInfo : defaultBBox) 1104 .getBoundBoxCenter()); 1105 } 1106 getBoundBoxCornerVector()1107 public V3 getBoundBoxCornerVector() { 1108 return boxInfo.getBoundBoxCornerVector(); 1109 } 1110 getBBoxVertices()1111 public Point3fi[] getBBoxVertices() { 1112 return boxInfo.getBoundBoxVertices(); 1113 } 1114 setBoundBox(T3 pt1, T3 pt2, boolean byCorner, float scale)1115 public void setBoundBox(T3 pt1, T3 pt2, boolean byCorner, float scale) { 1116 isBbcageDefault = false; 1117 bboxModels = null; 1118 bboxAtoms = null; 1119 boxInfo.setBoundBox(pt1, pt2, byCorner, scale); 1120 } 1121 getBoundBoxCommand(boolean withOptions)1122 public String getBoundBoxCommand(boolean withOptions) { 1123 if (!withOptions && bboxAtoms != null) 1124 return "boundbox " + Escape.eBS(bboxAtoms); 1125 ptTemp.setT(boxInfo.getBoundBoxCenter()); 1126 V3 bbVector = boxInfo.getBoundBoxCornerVector(); 1127 String s = (withOptions ? "boundbox " + Escape.eP(ptTemp) + " " 1128 + Escape.eP(bbVector) + "\n#or\n" : ""); 1129 ptTemp.sub(bbVector); 1130 s += "boundbox corners " + Escape.eP(ptTemp) + " "; 1131 ptTemp.scaleAdd2(2, bbVector, ptTemp); 1132 float v = Math.abs(8 * bbVector.x * bbVector.y * bbVector.z); 1133 s += Escape.eP(ptTemp) + " # volume = " + v; 1134 return s; 1135 } 1136 findAtomsInRectangle(Rectangle rect)1137 public BS findAtomsInRectangle(Rectangle rect) { 1138 BS bsModels = vwr.getVisibleFramesBitSet(); 1139 BS bs = new BS(); 1140 for (int i = ac; --i >= 0;) { 1141 Atom atom = at[i]; 1142 if (atom == null) 1143 continue; 1144 if (!bsModels.get(atom.mi)) 1145 i = am[atom.mi].firstAtomIndex; 1146 else if (atom.checkVisible() && rect.contains(atom.sX, atom.sY)) 1147 bs.set(i); 1148 } 1149 return bs; 1150 } 1151 getDefaultVdwType(int modelIndex)1152 public VDW getDefaultVdwType(int modelIndex) { 1153 return (!am[modelIndex].isBioModel ? VDW.AUTO_BABEL 1154 : am[modelIndex].hydrogenCount == 0 ? VDW.AUTO_JMOL : VDW.AUTO_BABEL); // RASMOL is too small 1155 } 1156 setRotationRadius(int modelIndex, float angstroms)1157 public boolean setRotationRadius(int modelIndex, float angstroms) { 1158 if (isJmolDataFrameForModel(modelIndex)) { 1159 am[modelIndex].defaultRotationRadius = angstroms; 1160 return false; 1161 } 1162 return true; 1163 } 1164 calcRotationRadius(int modelIndex, P3 center, boolean useBoundBox)1165 public float calcRotationRadius(int modelIndex, P3 center, boolean useBoundBox) { 1166 if (isJmolDataFrameForModel(modelIndex)) { 1167 float r = am[modelIndex].defaultRotationRadius; 1168 return (r == 0 ? 10 : r); 1169 } 1170 if (useBoundBox && getDefaultBoundBox() != null) 1171 return defaultBBox.getMaxDim() / 2 * 1.2f; 1172 float maxRadius = 0; 1173 for (int i = ac; --i >= 0;) { 1174 Atom atom = at[i]; 1175 if (atom == null) 1176 continue; 1177 if (isJmolDataFrameForAtom(atom)) { 1178 modelIndex = atom.mi; 1179 while (i >= 0 && at[i] != null && at[i].mi == modelIndex) 1180 i--; 1181 continue; 1182 } 1183 atom = at[i]; 1184 if (atom == null) 1185 continue; 1186 float distAtom = center.distance(atom); 1187 float outerVdw = distAtom + getRadiusVdwJmol(atom); 1188 if (outerVdw > maxRadius) 1189 maxRadius = outerVdw; 1190 } 1191 return (maxRadius == 0 ? 10 : maxRadius); 1192 } 1193 calcBoundBoxDimensions(BS bs, float scale)1194 public void calcBoundBoxDimensions(BS bs, float scale) { 1195 if (bs != null && bs.nextSetBit(0) < 0) 1196 bs = null; 1197 if (bs == null && isBbcageDefault || ac == 0) 1198 return; 1199 if (getDefaultBoundBox() == null) { 1200 bboxModels = getModelBS(bboxAtoms = BSUtil.copy(bs), false); 1201 if (calcAtomsMinMax(bs, boxInfo) == ac) 1202 isBbcageDefault = true; 1203 if (bs == null) { // from modelLoader or reset 1204 if (unitCells != null) 1205 calcUnitCellMinMax(); 1206 } 1207 } else { 1208 P3[] vertices = defaultBBox.getBoundBoxVertices(); 1209 boxInfo.reset(); 1210 for (int j = 0; j < 8; j++) 1211 boxInfo.addBoundBoxPoint(vertices[j]); 1212 } 1213 boxInfo.setBbcage(scale); 1214 } 1215 1216 /** 1217 * The default bounding box is created when the LOAD .... FILL BOUNDBOX or 1218 * FILL UNITCELL is use. 1219 * 1220 * @return default bounding box, possibly null 1221 */ getDefaultBoundBox()1222 private BoxInfo getDefaultBoundBox() { 1223 T3[] bbox = (T3[]) getInfoM("boundbox"); 1224 if (bbox == null) 1225 defaultBBox = null; 1226 else { 1227 if (defaultBBox == null) 1228 defaultBBox = new BoxInfo(); 1229 defaultBBox.setBoundBoxFromOABC(bbox); 1230 } 1231 return defaultBBox; 1232 } 1233 getBoxInfo(BS bs, float scale)1234 public BoxInfo getBoxInfo(BS bs, float scale) { 1235 if (bs == null) 1236 return boxInfo; 1237 BoxInfo bi = new BoxInfo(); 1238 calcAtomsMinMax(bs, bi); 1239 bi.setBbcage(scale); 1240 return bi; 1241 } 1242 calcAtomsMinMax(BS bs, BoxInfo boxInfo)1243 public int calcAtomsMinMax(BS bs, BoxInfo boxInfo) { 1244 boxInfo.reset(); 1245 int nAtoms = 0; 1246 boolean isAll = (bs == null); 1247 int i0 = (isAll ? ac - 1 : bs.nextSetBit(0)); 1248 for (int i = i0; i >= 0; i = (isAll ? i - 1 : bs.nextSetBit(i + 1))) { 1249 nAtoms++; 1250 Atom a = at[i]; 1251 if (a != null && !isJmolDataFrameForAtom(a)) 1252 boxInfo.addBoundBoxPoint(a); 1253 } 1254 return nAtoms; 1255 } 1256 calcUnitCellMinMax()1257 private void calcUnitCellMinMax() { 1258 P3 pt = new P3(); 1259 for (int i = 0; i < mc; i++) { 1260 if (!unitCells[i].getCoordinatesAreFractional()) 1261 continue; 1262 P3[] vertices = unitCells[i].getUnitCellVerticesNoOffset(); 1263 P3 offset = unitCells[i].getCartesianOffset(); 1264 for (int j = 0; j < 8; j++) { 1265 pt.add2(offset, vertices[j]); 1266 boxInfo.addBoundBoxPoint(pt); 1267 } 1268 } 1269 } 1270 calcRotationRadiusBs(BS bs)1271 public float calcRotationRadiusBs(BS bs) { 1272 // Eval getZoomFactor 1273 P3 center = getAtomSetCenter(bs); 1274 float maxRadius = 0; 1275 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 1276 Atom atom = at[i]; 1277 float distAtom = center.distance(atom); 1278 float outerVdw = distAtom + getRadiusVdwJmol(atom); 1279 if (outerVdw > maxRadius) 1280 maxRadius = outerVdw; 1281 } 1282 return (maxRadius == 0 ? 10 : maxRadius); 1283 } 1284 1285 /** 1286 * 1287 * @param vAtomSets 1288 * @param addCenters 1289 * @return array of two lists of points, centers first if desired 1290 */ 1291 getCenterAndPoints(Lst<Object[]> vAtomSets, boolean addCenters)1292 public P3[][] getCenterAndPoints(Lst<Object[]> vAtomSets, boolean addCenters) { 1293 BS bsAtoms1, bsAtoms2; 1294 int n = (addCenters ? 1 : 0); 1295 for (int ii = vAtomSets.size(); --ii >= 0;) { 1296 Object[] bss = vAtomSets.get(ii); 1297 bsAtoms1 = (BS) bss[0]; 1298 if (bss[1] instanceof BS) { 1299 bsAtoms2 = (BS) bss[1]; 1300 n += Math.min(bsAtoms1.cardinality(), bsAtoms2.cardinality()); 1301 } else { 1302 n += Math.min(bsAtoms1.cardinality(), ((P3[]) bss[1]).length); 1303 } 1304 } 1305 P3[][] points = new P3[2][n]; 1306 if (addCenters) { 1307 points[0][0] = new P3(); 1308 points[1][0] = new P3(); 1309 } 1310 for (int ii = vAtomSets.size(); --ii >= 0;) { 1311 Object[] bss = vAtomSets.get(ii); 1312 bsAtoms1 = (BS) bss[0]; 1313 if (bss[1] instanceof BS) { 1314 bsAtoms2 = (BS) bss[1]; 1315 for (int i = bsAtoms1.nextSetBit(0), j = bsAtoms2.nextSetBit(0); i >= 0 1316 && j >= 0; i = bsAtoms1.nextSetBit(i + 1), j = bsAtoms2 1317 .nextSetBit(j + 1)) { 1318 points[0][--n] = at[i]; 1319 points[1][n] = at[j]; 1320 if (addCenters) { 1321 points[0][0].add(at[i]); 1322 points[1][0].add(at[j]); 1323 } 1324 } 1325 } else { 1326 P3[] coords = (P3[]) bss[1]; 1327 for (int i = bsAtoms1.nextSetBit(0), j = 0; i >= 0 && j < coords.length; i = bsAtoms1 1328 .nextSetBit(i + 1), j++) { 1329 points[0][--n] = at[i]; 1330 points[1][n] = coords[j]; 1331 if (addCenters) { 1332 points[0][0].add(at[i]); 1333 points[1][0].add(coords[j]); 1334 } 1335 } 1336 } 1337 } 1338 if (addCenters) { 1339 points[0][0].scale(1f / (points[0].length - 1)); 1340 points[1][0].scale(1f / (points[1].length - 1)); 1341 } 1342 return points; 1343 } 1344 getAtomSetCenter(BS bs)1345 public P3 getAtomSetCenter(BS bs) { 1346 P3 ptCenter = new P3(); 1347 int nPoints = 0; 1348 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 1349 if (!isJmolDataFrameForAtom(at[i])) { 1350 nPoints++; 1351 ptCenter.add(at[i]); 1352 } 1353 } 1354 if (nPoints > 1) 1355 ptCenter.scale(1.0f / nPoints); 1356 return ptCenter; 1357 } 1358 getAverageAtomPoint()1359 public P3 getAverageAtomPoint() { 1360 // if (averageAtomPoint == null) 1361 // averageAtomPoint = getAtomSetCenter(vwr.getAllAtoms()); 1362 return getAtomSetCenter(vwr.bsA());//averageAtomPoint; 1363 } 1364 setAPm(BS bs, int tok, int iValue, float fValue, String sValue, float[] values, String[] list)1365 protected void setAPm(BS bs, int tok, int iValue, float fValue, 1366 String sValue, float[] values, String[] list) { 1367 setAPa(bs, tok, iValue, fValue, sValue, values, list); 1368 switch (tok) { 1369 case T.valence: 1370 case T.formalcharge: 1371 if (vwr.getBoolean(T.smartaromatic)) 1372 assignAromaticBondsBs(true, null); 1373 break; 1374 } 1375 } 1376 addStateScript(String script1, BS bsBonds, BS bsAtoms1, BS bsAtoms2, String script2, boolean addFrameNumber, boolean postDefinitions)1377 public StateScript addStateScript(String script1, BS bsBonds, BS bsAtoms1, 1378 BS bsAtoms2, String script2, 1379 boolean addFrameNumber, 1380 boolean postDefinitions) { 1381 int iModel = vwr.am.cmi; 1382 if (addFrameNumber) { 1383 if (thisStateModel != iModel) 1384 script1 = "frame " 1385 + (iModel < 0 ? "all #" + iModel : getModelNumberDotted(iModel)) 1386 + ";\n " + script1; 1387 thisStateModel = iModel; 1388 } else { 1389 thisStateModel = -1; 1390 } 1391 StateScript stateScript = new StateScript(thisStateModel, script1, bsBonds, 1392 bsAtoms1, bsAtoms2, script2, postDefinitions); 1393 if (stateScript.isValid()) { 1394 stateScripts.addLast(stateScript); 1395 } 1396 return stateScript; 1397 } 1398 freezeModels()1399 void freezeModels() { 1400 haveBioModels = false; 1401 for (int iModel = mc; --iModel >= 0;) 1402 haveBioModels |= am[iModel].freeze(); 1403 } 1404 getStructureList()1405 public Map<STR, float[]> getStructureList() { 1406 return vwr.getStructureList(); 1407 } 1408 getInfoM(String keyName)1409 public Object getInfoM(String keyName) { 1410 // the preferred method now 1411 return (msInfo == null ? null : msInfo.get(keyName)); 1412 } 1413 getMSInfoB(String keyName)1414 public boolean getMSInfoB(String keyName) { 1415 Object val = getInfoM(keyName); 1416 return (val instanceof Boolean && ((Boolean) val).booleanValue()); 1417 } 1418 1419 /** 1420 * could be the base model or one of the subframes 1421 * 1422 * @param modelIndex 1423 * @return is any part of a trajectory 1424 */ isTrajectory(int modelIndex)1425 public boolean isTrajectory(int modelIndex) { 1426 return am[modelIndex].isTrajectory; 1427 } 1428 isTrajectorySubFrame(int i)1429 public boolean isTrajectorySubFrame(int i) { 1430 return (am[i].trajectoryBaseIndex != i); 1431 } 1432 isTrajectoryMeasurement(int[] countPlusIndices)1433 public boolean isTrajectoryMeasurement(int[] countPlusIndices) { 1434 return (trajectory != null && trajectory.hasMeasure(countPlusIndices)); 1435 } 1436 1437 /** 1438 * Get the set of models associated with a set of atoms. 1439 * This must allow for appended models. 1440 * @param atomList 1441 * @param allTrajectories 1442 * @return bit set of models 1443 */ getModelBS(BS atomList, boolean allTrajectories)1444 public BS getModelBS(BS atomList, boolean allTrajectories) { 1445 BS bs = new BS(); 1446 int modelIndex = 0; 1447 boolean isAll = (atomList == null); 1448 allTrajectories &= (trajectory != null); 1449 int i0 = (isAll ? 0 : atomList.nextSetBit(0)); 1450 for (int i = i0; i >= 0 && i < ac; i = (isAll ? i + 1 : atomList 1451 .nextSetBit(i + 1))) { 1452 if (at[i] == null) 1453 continue; 1454 bs.set(modelIndex = at[i].mi); 1455 if (allTrajectories) 1456 trajectory.getModelBS(modelIndex, bs); 1457 Model m = am[modelIndex]; 1458 if (m.isOrderly) 1459 i = m.firstAtomIndex + m.act - 1; 1460 } 1461 // System.out.println("MS " + atomList + " " + bs); 1462 return bs; 1463 } 1464 1465 /** 1466 * only some models can be iterated through. models for which 1467 * trajectoryBaseIndexes[i] != i are trajectories only 1468 * 1469 * @param allowJmolData 1470 * @return bitset of models 1471 */ getIterativeModels(boolean allowJmolData)1472 public BS getIterativeModels(boolean allowJmolData) { 1473 BS bs = new BS(); 1474 for (int i = 0; i < mc; i++) { 1475 if (!allowJmolData && isJmolDataFrameForModel(i)) 1476 continue; 1477 if (!isTrajectorySubFrame(i)) 1478 bs.set(i); 1479 } 1480 return bs; 1481 } 1482 fillAtomData(AtomData atomData, int mode)1483 public void fillAtomData(AtomData atomData, int mode) { 1484 if ((mode & AtomData.MODE_FILL_MOLECULES) != 0) { 1485 getMolecules(); 1486 atomData.bsMolecules = new BS[molecules.length]; 1487 atomData.atomMolecule = new int[ac]; 1488 BS bs; 1489 for (int i = 0; i < molecules.length; i++) { 1490 bs = atomData.bsMolecules[i] = molecules[i].atomList; 1491 for (int iAtom = bs.nextSetBit(0); iAtom >= 0; iAtom = bs 1492 .nextSetBit(iAtom + 1)) 1493 atomData.atomMolecule[iAtom] = i; 1494 } 1495 } 1496 if ((mode & AtomData.MODE_GET_ATTACHED_HYDROGENS) != 0) { 1497 int[] nH = new int[1]; 1498 atomData.hAtomRadius = vwr.getVanderwaalsMar(1) / 1000f; 1499 atomData.hAtoms = calculateHydrogens(atomData.bsSelected, nH, null, AtomCollection.CALC_H_JUSTC); 1500 atomData.hydrogenAtomCount = nH[0]; 1501 return; 1502 } 1503 if (atomData.modelIndex < 0) 1504 atomData.firstAtomIndex = (atomData.bsSelected == null ? 0 : Math.max(0, 1505 atomData.bsSelected.nextSetBit(0))); 1506 else 1507 atomData.firstAtomIndex = am[atomData.modelIndex].firstAtomIndex; 1508 atomData.lastModelIndex = atomData.firstModelIndex = (ac == 0 ? 0 1509 : at[atomData.firstAtomIndex].mi); 1510 atomData.modelName = getModelNumberDotted(atomData.firstModelIndex); 1511 fillADa(atomData, mode); 1512 } 1513 getModelNumberDotted(int modelIndex)1514 public String getModelNumberDotted(int modelIndex) { 1515 return (mc < 1 || modelIndex >= mc || modelIndex < 0 ? "" : Escape 1516 .escapeModelFileNumber(modelFileNumbers[modelIndex])); 1517 } 1518 getModelNumber(int modelIndex)1519 public int getModelNumber(int modelIndex) { 1520 return modelNumbers[modelIndex == Integer.MAX_VALUE ? mc - 1 : modelIndex]; 1521 } 1522 getModelProperty(int modelIndex, String property)1523 public String getModelProperty(int modelIndex, String property) { 1524 Properties props = am[modelIndex].properties; 1525 return props == null ? null : props.getProperty(property); 1526 } 1527 getModelAuxiliaryInfo(int modelIndex)1528 public Map<String, Object> getModelAuxiliaryInfo(int modelIndex) { 1529 return (modelIndex < 0 ? null : am[modelIndex].auxiliaryInfo); 1530 } 1531 setInfo(int modelIndex, Object key, Object value)1532 public void setInfo(int modelIndex, Object key, Object value) { 1533 if (modelIndex >= 0 && modelIndex < mc) 1534 am[modelIndex].auxiliaryInfo.put((String) key, value); 1535 } 1536 getInfo(int modelIndex, String key)1537 public Object getInfo(int modelIndex, String key) { 1538 return (modelIndex < 0 ? null : am[modelIndex].auxiliaryInfo.get(key)); 1539 } 1540 getInfoB(int modelIndex, String keyName)1541 protected boolean getInfoB(int modelIndex, String keyName) { 1542 Map<String, Object> info = am[modelIndex].auxiliaryInfo; 1543 return (info != null && info.containsKey(keyName) && ((Boolean) info 1544 .get(keyName)).booleanValue()); 1545 } 1546 getInfoI(int modelIndex, String keyName)1547 protected int getInfoI(int modelIndex, String keyName) { 1548 Map<String, Object> info = am[modelIndex].auxiliaryInfo; 1549 if (info != null && info.containsKey(keyName)) { 1550 return ((Integer) info.get(keyName)).intValue(); 1551 } 1552 return Integer.MIN_VALUE; 1553 } 1554 getInsertionCountInModel(int modelIndex)1555 public int getInsertionCountInModel(int modelIndex) { 1556 return am[modelIndex].insertionCount; 1557 } 1558 modelFileNumberFromFloat(float fDotM)1559 public static int modelFileNumberFromFloat(float fDotM) { 1560 //only used in the case of select model = someVariable 1561 //2.1 and 2.10 will be ambiguous and reduce to 2.1 1562 1563 int file = (int) Math.floor(fDotM); 1564 int model = (int) Math.floor((fDotM - file + 0.00001) * 10000); 1565 while (model != 0 && model % 10 == 0) 1566 model /= 10; 1567 return file * 1000000 + model; 1568 } 1569 getChainCountInModelWater(int modelIndex, boolean countWater)1570 public int getChainCountInModelWater(int modelIndex, boolean countWater) { 1571 if (modelIndex < 0) { 1572 int chainCount = 0; 1573 for (int i = mc; --i >= 0;) 1574 chainCount += am[i].getChainCount(countWater); 1575 return chainCount; 1576 } 1577 return am[modelIndex].getChainCount(countWater); 1578 } 1579 getGroupCountInModel(int modelIndex)1580 public int getGroupCountInModel(int modelIndex) { 1581 if (modelIndex < 0) { 1582 int groupCount = 0; 1583 for (int i = mc; --i >= 0;) 1584 groupCount += am[i].getGroupCount(); 1585 return groupCount; 1586 } 1587 return am[modelIndex].getGroupCount(); 1588 } 1589 calcSelectedGroupsCount()1590 public void calcSelectedGroupsCount() { 1591 BS bsSelected = vwr.bsA(); 1592 for (int i = mc; --i >= 0;) 1593 am[i].calcSelectedGroupsCount(bsSelected); 1594 } 1595 isJmolDataFrameForModel(int modelIndex)1596 public boolean isJmolDataFrameForModel(int modelIndex) { 1597 return (modelIndex >= 0 && modelIndex < mc && am[modelIndex].isJmolDataFrame); 1598 } 1599 isJmolDataFrameForAtom(Atom atom)1600 private boolean isJmolDataFrameForAtom(Atom atom) { 1601 return am[atom.mi].isJmolDataFrame; 1602 } 1603 setJmolDataFrame(String type, int modelIndex, int modelDataIndex)1604 public void setJmolDataFrame(String type, int modelIndex, int modelDataIndex) { 1605 Model model = am[type == null ? am[modelDataIndex].dataSourceFrame 1606 : modelIndex]; 1607 if (type == null) { 1608 //leaving a data frame -- just set generic to this one if quaternion 1609 type = am[modelDataIndex].jmolFrameType; 1610 } 1611 if (modelIndex >= 0) { 1612 if (model.dataFrames == null) { 1613 model.dataFrames = new Hashtable<String, Integer>(); 1614 } 1615 am[modelDataIndex].dataSourceFrame = modelIndex; 1616 am[modelDataIndex].jmolFrameType = type; 1617 model.dataFrames.put(type, Integer.valueOf(modelDataIndex)); 1618 } 1619 if (type.startsWith("quaternion") && type.indexOf("deriv") < 0) { //generic quaternion 1620 type = type.substring(0, type.indexOf(" ")); 1621 model.dataFrames.put(type, Integer.valueOf(modelDataIndex)); 1622 } 1623 } 1624 getJmolDataFrameIndex(int modelIndex, String type)1625 public int getJmolDataFrameIndex(int modelIndex, String type) { 1626 if (am[modelIndex].dataFrames == null) { 1627 return -1; 1628 } 1629 Integer index = am[modelIndex].dataFrames.get(type); 1630 return (index == null ? -1 : index.intValue()); 1631 } 1632 clearDataFrameReference(int modelIndex)1633 protected void clearDataFrameReference(int modelIndex) { 1634 for (int i = 0; i < mc; i++) { 1635 Map<String, Integer> df = am[i].dataFrames; 1636 if (df == null) { 1637 continue; 1638 } 1639 Iterator<Integer> e = df.values().iterator(); 1640 while (e.hasNext()) { 1641 if ((e.next()).intValue() == modelIndex) { 1642 e.remove(); 1643 } 1644 } 1645 } 1646 } 1647 getJmolFrameType(int modelIndex)1648 public String getJmolFrameType(int modelIndex) { 1649 return (modelIndex >= 0 && modelIndex < mc ? am[modelIndex].jmolFrameType 1650 : "modelSet"); 1651 } 1652 getJmolDataSourceFrame(int modelIndex)1653 public int getJmolDataSourceFrame(int modelIndex) { 1654 return (modelIndex >= 0 && modelIndex < mc ? am[modelIndex].dataSourceFrame 1655 : -1); 1656 } 1657 saveModelOrientation(int modelIndex, Orientation orientation)1658 public void saveModelOrientation(int modelIndex, Orientation orientation) { 1659 am[modelIndex].orientation = orientation; 1660 } 1661 getModelOrientation(int modelIndex)1662 public Orientation getModelOrientation(int modelIndex) { 1663 return am[modelIndex].orientation; 1664 } 1665 1666 /* 1667 final static String[] pdbRecords = { "ATOM ", "HELIX ", "SHEET ", "TURN ", 1668 "MODEL ", "SCALE", "HETATM", "SEQRES", 1669 "DBREF ", }; 1670 */ 1671 getPDBHeader(int modelIndex)1672 public String getPDBHeader(int modelIndex) { 1673 return (am[modelIndex].isBioModel ? ((BioModel) am[modelIndex]) 1674 .getFullPDBHeader() : getFileHeader(modelIndex)); 1675 } 1676 getFileHeader(int modelIndex)1677 public String getFileHeader(int modelIndex) { 1678 if (modelIndex < 0) 1679 return ""; 1680 if (am[modelIndex].isBioModel) 1681 return getPDBHeader(modelIndex); 1682 String info = (String) getInfo(modelIndex, "fileHeader"); 1683 if (info == null) 1684 info = modelSetName; 1685 if (info != null) 1686 return info; 1687 return "no header information found"; 1688 } 1689 1690 ////////////// individual models //////////////// 1691 getAltLocCountInModel(int modelIndex)1692 public int getAltLocCountInModel(int modelIndex) { 1693 return am[modelIndex].altLocCount; 1694 } 1695 getAltLocIndexInModel(int modelIndex, char alternateLocationID)1696 public int getAltLocIndexInModel(int modelIndex, char alternateLocationID) { 1697 if (alternateLocationID == '\0') { 1698 return 0; 1699 } 1700 String altLocList = getAltLocListInModel(modelIndex); 1701 if (altLocList.length() == 0) { 1702 return 0; 1703 } 1704 return altLocList.indexOf(alternateLocationID) + 1; 1705 } 1706 getInsertionCodeIndexInModel(int modelIndex, char insertionCode)1707 public int getInsertionCodeIndexInModel(int modelIndex, char insertionCode) { 1708 if (insertionCode == '\0') 1709 return 0; 1710 String codeList = getInsertionListInModel(modelIndex); 1711 if (codeList.length() == 0) 1712 return 0; 1713 return codeList.indexOf(insertionCode) + 1; 1714 } 1715 getAltLocListInModel(int modelIndex)1716 public String getAltLocListInModel(int modelIndex) { 1717 String str = (String) getInfo(modelIndex, "altLocs"); 1718 return (str == null ? "" : str); 1719 } 1720 getInsertionListInModel(int modelIndex)1721 private String getInsertionListInModel(int modelIndex) { 1722 String str = (String) getInfo(modelIndex, "insertionCodes"); 1723 return (str == null ? "" : str); 1724 } 1725 getModelSymmetryCount(int modelIndex)1726 public int getModelSymmetryCount(int modelIndex) { 1727 return (am[modelIndex].biosymmetryCount > 0 ? am[modelIndex].biosymmetryCount 1728 : unitCells == null || unitCells[modelIndex] == null ? 0 1729 : unitCells[modelIndex].getSpaceGroupOperationCount()); 1730 } 1731 getModelCellRange(int modelIndex)1732 public int[] getModelCellRange(int modelIndex) { 1733 return (unitCells == null ? null : unitCells[modelIndex].getCellRange()); 1734 } 1735 getLastVibrationVector(int modelIndex, int tok)1736 public int getLastVibrationVector(int modelIndex, int tok) { 1737 if (vibrations != null && modelIndex < vwr.ms.mc) { 1738 Vibration v; 1739 int a1 = (modelIndex < 0 || isTrajectory(modelIndex) 1740 || modelIndex >= mc - 1 ? ac : am[modelIndex + 1].firstAtomIndex); 1741 int a0 = (modelIndex <= 0 ? 0 : am[modelIndex].firstAtomIndex); 1742 for (int i = a1; --i >= a0;) { 1743 if ((modelIndex < 0 || at[i].mi == modelIndex) 1744 && ((tok == T.modulation || tok == 0) 1745 && (v = (Vibration) getModulation(i)) != null || (tok == T.vibration || tok == 0) 1746 && (v = getVibration(i, false)) != null) && v.isNonzero()) 1747 return i; 1748 } 1749 } 1750 return -1; 1751 } 1752 getModulationList(BS bs, char type, P3 t456)1753 public Lst<Object> getModulationList(BS bs, char type, P3 t456) { 1754 Lst<Object> list = new Lst<Object>(); 1755 if (vibrations != null) 1756 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) 1757 if (vibrations[i] instanceof JmolModulationSet) 1758 list.addLast(((JmolModulationSet) vibrations[i]).getModulation(type, 1759 t456)); 1760 else 1761 list.addLast(Float.valueOf(type == 'O' ? Float.NaN : -1)); 1762 return list; 1763 } 1764 getElementsPresentBitSet(int modelIndex)1765 public BS getElementsPresentBitSet(int modelIndex) { 1766 if (modelIndex >= 0) 1767 return elementsPresent[modelIndex]; 1768 BS bs = new BS(); 1769 for (int i = 0; i < mc; i++) 1770 bs.or(elementsPresent[i]); 1771 return bs; 1772 } 1773 1774 ///////// molecules ///////// 1775 getMoleculeIndex(int atomIndex, boolean inModel)1776 public int getMoleculeIndex(int atomIndex, boolean inModel) { 1777 //ColorManager 1778 if (moleculeCount == 0) 1779 getMolecules(); 1780 for (int i = 0; i < moleculeCount; i++) { 1781 if (molecules[i].atomList.get(atomIndex)) 1782 return (inModel ? molecules[i].indexInModel : i); 1783 } 1784 return 0; 1785 } 1786 1787 /** 1788 * return cumulative sum of all atoms in molecules containing these atoms 1789 * 1790 * @param bs 1791 * @return bitset of atoms 1792 */ getMoleculeBitSet(BS bs)1793 public BS getMoleculeBitSet(BS bs) { 1794 if (moleculeCount == 0) 1795 getMolecules(); 1796 BS bsResult = BSUtil.copy(bs); 1797 BS bsInitial = BSUtil.copy(bs); 1798 int i = 0; 1799 BS bsTemp = new BS(); 1800 while ((i = bsInitial.length() - 1) >= 0) { 1801 bsTemp = getMoleculeBitSetForAtom(i); 1802 if (bsTemp == null) { 1803 // atom has been deleted 1804 bsInitial.clear(i); 1805 bsResult.clear(i); 1806 continue; 1807 } 1808 bsInitial.andNot(bsTemp); 1809 bsResult.or(bsTemp); 1810 } 1811 return bsResult; 1812 } 1813 getMoleculeBitSetForAtom(int atomIndex)1814 public BS getMoleculeBitSetForAtom(int atomIndex) { 1815 if (moleculeCount == 0) 1816 getMolecules(); 1817 for (int i = 0; i < moleculeCount; i++) 1818 if (molecules[i].atomList.get(atomIndex)) 1819 return molecules[i].atomList; 1820 return null; 1821 } 1822 getModelDipole(int modelIndex)1823 public V3 getModelDipole(int modelIndex) { 1824 if (modelIndex < 0) 1825 return null; 1826 V3 dipole = (V3) getInfo(modelIndex, "dipole"); 1827 if (dipole == null) 1828 dipole = (V3) getInfo(modelIndex, "DIPOLE_VEC"); 1829 return dipole; 1830 } 1831 calculateMolecularDipole(int modelIndex, BS bsAtoms)1832 public V3 calculateMolecularDipole(int modelIndex, BS bsAtoms) throws JmolAsyncException { 1833 if (bsAtoms != null) { 1834 int ia = bsAtoms.nextSetBit(0); 1835 if (ia < 0) 1836 return null; 1837 modelIndex = at[ia].mi; 1838 } 1839 if (modelIndex < 0) 1840 return null; 1841 int nPos = 0; 1842 int nNeg = 0; 1843 float cPos = 0; 1844 float cNeg = 0; 1845 V3 pos = new V3(); 1846 V3 neg = new V3(); 1847 if (bsAtoms == null) 1848 bsAtoms = getModelAtomBitSetIncludingDeleted(-1, false); 1849 vwr.getOrCalcPartialCharges(am[modelIndex].bsAtoms, null); 1850 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) { 1851 if (at[i].mi != modelIndex || at[i].isDeleted()) { 1852 continue; 1853 } 1854 float c = partialCharges[i]; 1855 if (c < 0) { 1856 nNeg++; 1857 cNeg += c; 1858 neg.scaleAdd2(c, at[i], neg); 1859 } else if (c > 0) { 1860 nPos++; 1861 cPos += c; 1862 pos.scaleAdd2(c, at[i], pos); 1863 } 1864 } 1865 if (Math.abs(cPos + cNeg) > 0.015) { // BH Jmol 14.22.2 was 0.01, but PubChem charges are only to 0.01 precision 1866 Logger.info("Dipole calculation requires balanced charges: " + cPos + " " 1867 + cNeg); 1868 return null; 1869 } 1870 if (nNeg == 0 || nPos == 0) 1871 return null; 1872 pos.add(neg); 1873 pos.scale(4.8f); //1e-10f * 1.6e-19f/ 3.336e-30f; 1874 // 1 Debye = 3.336e-30 Coulomb-meter; C_e = 1.6022e-19 C 1875 return pos; 1876 } 1877 getMoleculeCountInModel(int modelIndex)1878 public int getMoleculeCountInModel(int modelIndex) { 1879 //ColorManager 1880 //not implemented for pop-up menu -- will slow it down. 1881 int n = 0; 1882 if (moleculeCount == 0) 1883 getMolecules(); 1884 if (modelIndex < 0) 1885 return moleculeCount; 1886 for (int i = 0; i < mc; i++) { 1887 if (modelIndex == i) 1888 n += am[i].moleculeCount; 1889 } 1890 return n; 1891 } 1892 calcSelectedMoleculesCount()1893 public void calcSelectedMoleculesCount() { 1894 BS bsSelected = vwr.bsA(); 1895 if (moleculeCount == 0) 1896 getMolecules(); 1897 selectedMolecules.xor(selectedMolecules); 1898 //selectedMoleculeCount = 0; 1899 BS bsTemp = new BS(); 1900 for (int i = 0; i < moleculeCount; i++) { 1901 BSUtil.copy2(bsSelected, bsTemp); 1902 bsTemp.and(molecules[i].atomList); 1903 if (bsTemp.length() > 0) { 1904 selectedMolecules.set(i); 1905 //selectedMoleculeCount++; 1906 } 1907 } 1908 } 1909 1910 /** 1911 * deletes molecules based on: CENTROID -- molecular centroid is not in unit 1912 * cell CENTROID PACKED -- all molecule atoms are not in unit cell 1913 * 1914 * @param bs 1915 * @param minmax 1916 * fractional [xmin, ymin, zmin, xmax, ymax, zmax, 1=packed] 1917 */ setCentroid(BS bs, int[] minmax)1918 public void setCentroid(BS bs, int[] minmax) { 1919 BS bsDelete = getNotInCentroid(bs, minmax); 1920 if (bsDelete != null && bsDelete.nextSetBit(0) >= 0) 1921 vwr.deleteAtoms(bsDelete, false); 1922 } 1923 getNotInCentroid(BS bs, int[] minmax)1924 private BS getNotInCentroid(BS bs, int[] minmax) { 1925 int iAtom0 = bs.nextSetBit(0); 1926 if (iAtom0 < 0) 1927 return null; 1928 SymmetryInterface uc = getUnitCell(at[iAtom0].mi); 1929 return (uc == null ? null : uc.notInCentroid(this, bs, minmax)); 1930 } 1931 getMolecules()1932 public JmolMolecule[] getMolecules() { 1933 if (moleculeCount > 0) 1934 return molecules; 1935 if (molecules == null) 1936 molecules = new JmolMolecule[4]; 1937 moleculeCount = 0; 1938 Model m = null; 1939 BS[] bsModelAtoms = new BS[mc]; 1940 Lst<BS> biobranches = null; 1941 for (int i = 0; i < mc; i++) { 1942 // TODO: Trajectories? 1943 bsModelAtoms[i] = vwr.getModelUndeletedAtomsBitSet(i); 1944 m = am[i]; 1945 m.moleculeCount = 0; 1946 biobranches = (m.isBioModel ? ((BioModel) m) 1947 .getBioBranches(biobranches) : null); 1948 } 1949 // problem, as with 1gzx, is that this does not include non-protein cofactors that are 1950 // covalently bonded. So we indicate a set of "biobranches" in JmolMolecule.getMolecules 1951 molecules = JmolMolecule.getMolecules(at, bsModelAtoms, biobranches, null); 1952 moleculeCount = molecules.length; 1953 for (int i = moleculeCount; --i >= 0;) { 1954 m = am[molecules[i].modelIndex]; 1955 m.firstMoleculeIndex = i; 1956 m.moleculeCount++; 1957 } 1958 return molecules; 1959 } 1960 1961 //////////// iterators ////////// 1962 initializeBspf()1963 protected void initializeBspf() { 1964 if (bspf != null && bspf.isValid) 1965 return; 1966 if (showRebondTimes) 1967 Logger.startTimer("build bspf"); 1968 Bspf bspf = new Bspf(3); 1969 if (Logger.debugging) 1970 Logger.debug("sequential bspt order"); 1971 BS bsNew = BS.newN(mc); 1972 for (int i = ac; --i >= 0;) { 1973 // important that we go backward here, because we are going to 1974 // use System.arrayCopy to expand the array ONCE only 1975 Atom atom = at[i]; 1976 if (atom != null && !atom.isDeleted() && !isTrajectorySubFrame(atom.mi)) { 1977 bspf.addTuple(am[atom.mi].trajectoryBaseIndex, atom); 1978 bsNew.set(atom.mi); 1979 } 1980 } 1981 // } 1982 if (showRebondTimes) { 1983 Logger.checkTimer("build bspf", false); 1984 bspf.stats(); 1985 // bspf.dump(); 1986 } 1987 for (int i = bsNew.nextSetBit(0); i >= 0; i = bsNew.nextSetBit(i + 1)) 1988 bspf.validateModel(i, true); 1989 bspf.isValid = true; 1990 this.bspf = bspf; 1991 1992 } 1993 initializeBspt(int modelIndex)1994 protected void initializeBspt(int modelIndex) { 1995 initializeBspf(); 1996 if (bspf.isInitializedIndex(modelIndex)) 1997 return; 1998 bspf.initialize(modelIndex, at, 1999 vwr.getModelUndeletedAtomsBitSet(modelIndex)); 2000 } 2001 setIteratorForPoint(AtomIndexIterator iterator, int modelIndex, T3 pt, float distance)2002 public void setIteratorForPoint(AtomIndexIterator iterator, int modelIndex, 2003 T3 pt, float distance) { 2004 if (modelIndex < 0) { 2005 iterator.setCenter(pt, distance); 2006 return; 2007 } 2008 initializeBspt(modelIndex); 2009 iterator.setModel(this, modelIndex, am[modelIndex].firstAtomIndex, 2010 Integer.MAX_VALUE, pt, distance, null); 2011 } 2012 setIteratorForAtom(AtomIndexIterator iterator, int modelIndex, int atomIndex, float distance, RadiusData rd)2013 public void setIteratorForAtom(AtomIndexIterator iterator, int modelIndex, 2014 int atomIndex, float distance, RadiusData rd) { 2015 if (modelIndex < 0) 2016 modelIndex = at[atomIndex].mi; 2017 modelIndex = am[modelIndex].trajectoryBaseIndex; 2018 initializeBspt(modelIndex); 2019 iterator.setModel(this, modelIndex, am[modelIndex].firstAtomIndex, 2020 atomIndex, at[atomIndex], distance, rd); 2021 } 2022 2023 /** 2024 * @param bsSelected 2025 * @param isGreaterOnly 2026 * @param modelZeroBased 2027 * @param hemisphereOnly 2028 * @param isMultiModel 2029 * @return an iterator 2030 */ getSelectedAtomIterator(BS bsSelected, boolean isGreaterOnly, boolean modelZeroBased, boolean hemisphereOnly, boolean isMultiModel)2031 public AtomIndexIterator getSelectedAtomIterator(BS bsSelected, 2032 boolean isGreaterOnly, 2033 boolean modelZeroBased, 2034 boolean hemisphereOnly, 2035 boolean isMultiModel) { 2036 //EnvelopeCalculation, IsoSolventReader 2037 // This iterator returns only atoms OTHER than the atom specified 2038 // and with the specified restrictions. 2039 // Model zero-based means the index returned is within the model, 2040 // not the full atom set. broken in 12.0.RC6; repaired in 12.0.RC15 2041 2042 initializeBspf(); 2043 AtomIteratorWithinModel iter; 2044 if (isMultiModel) { 2045 BS bsModels = getModelBS(bsSelected, false); 2046 for (int i = bsModels.nextSetBit(0); i >= 0; i = bsModels 2047 .nextSetBit(i + 1)) 2048 initializeBspt(i); 2049 iter = new AtomIteratorWithinModelSet(bsModels); 2050 } else { 2051 iter = new AtomIteratorWithinModel(); 2052 } 2053 iter.initialize(bspf, bsSelected, isGreaterOnly, modelZeroBased, 2054 hemisphereOnly, vwr.isParallel()); 2055 return iter; 2056 } 2057 2058 ////////// bonds ///////// 2059 2060 @Override getBondCountInModel(int modelIndex)2061 public int getBondCountInModel(int modelIndex) { 2062 return (modelIndex < 0 ? bondCount : am[modelIndex].getBondCount()); 2063 } 2064 getAtomCountInModel(int modelIndex)2065 public int getAtomCountInModel(int modelIndex) { 2066 return (modelIndex < 0 ? ac : am[modelIndex].act); 2067 } 2068 2069 /** 2070 * note -- this method returns ALL atoms, including deleted. 2071 * 2072 * @param bsModels 2073 * @return bitset of atoms 2074 */ getModelAtomBitSetIncludingDeletedBs(BS bsModels)2075 public BS getModelAtomBitSetIncludingDeletedBs(BS bsModels) { 2076 BS bs = new BS(); 2077 if (bsModels == null && bsAll == null) 2078 bsAll = BSUtil.setAll(ac); 2079 if (bsModels == null) 2080 bs.or(bsAll); 2081 else 2082 for (int i = bsModels.nextSetBit(0); i >= 0; i = bsModels 2083 .nextSetBit(i + 1)) 2084 bs.or(getModelAtomBitSetIncludingDeleted(i, false)); 2085 return bs; 2086 } 2087 2088 /** 2089 * Note that this method returns all atoms, included deleted ones. If you 2090 * don't want deleted atoms, then use 2091 * vwr.getModelAtomBitSetUndeleted(modelIndex, TRUE) 2092 * 2093 * @param modelIndex 2094 * @param asCopy 2095 * MUST BE TRUE IF THE BITSET IS GOING TO BE MODIFIED! 2096 * @return either the actual bitset or a copy 2097 */ getModelAtomBitSetIncludingDeleted(int modelIndex, boolean asCopy)2098 public BS getModelAtomBitSetIncludingDeleted(int modelIndex, boolean asCopy) { 2099 BS bs = (modelIndex < 0 ? bsAll : am[modelIndex].bsAtoms); 2100 if (bs == null) 2101 bs = bsAll = BSUtil.setAll(ac); 2102 return (asCopy ? BSUtil.copy(bs) : bs); 2103 } 2104 getAtomBitsMaybeDeleted(int tokType, Object specInfo)2105 protected BS getAtomBitsMaybeDeleted(int tokType, Object specInfo) { 2106 BS bs; 2107 switch (tokType) { 2108 default: 2109 return getAtomBitsMDa(tokType, specInfo, bs = new BS()); 2110 case T.domains: 2111 case T.validation: 2112 case T.dssr: 2113 case T.rna3d: 2114 case T.basepair: 2115 case T.sequence: 2116 bs = new BS(); 2117 return (haveBioModels ? bioModelset.getAtomBitsStr(tokType, 2118 (String) specInfo, bs) : bs); 2119 case T.bonds: 2120 case T.isaromatic: 2121 return getAtomBitsMDb(tokType, specInfo); 2122 case T.boundbox: 2123 BoxInfo boxInfo = getBoxInfo((BS) specInfo, 1); 2124 bs = getAtomsWithin(boxInfo.getBoundBoxCornerVector().length() + 0.0001f, 2125 boxInfo.getBoundBoxCenter(), null, -1); 2126 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) 2127 if (!boxInfo.isWithin(at[i])) 2128 bs.clear(i); 2129 return bs; 2130 case T.cell: 2131 // select cell=555 (NO NOT an absolute quantity) 2132 // select cell=1505050 2133 // select cell=1500500500 2134 bs = new BS(); 2135 P3 pt = (P3) specInfo; 2136 boolean ignoreOffset = false;//!vwr.getBoolean(T.fractionalrelative); 2137 for (int i = ac; --i >= 0;) 2138 if (at[i] != null && isInLatticeCell(i, pt, ptTemp2, ignoreOffset)) 2139 bs.set(i); 2140 return bs; 2141 case T.centroid: 2142 // select centroid=555 -- like cell=555 but for whole molecules 2143 // if it is one full molecule, then return the EMPTY bitset 2144 bs = BSUtil.newBitSet2(0, ac); 2145 P3 pt1 = (P3) specInfo; 2146 int[] minmax = new int[] { (int) pt1.x - 1, (int) pt1.y - 1, (int) pt1.z - 1, 2147 (int) pt1.x, (int) pt1.y, (int) pt1.z, 0 }; 2148 for (int i = mc; --i >= 0;) { 2149 SymmetryInterface uc = getUnitCell(i); 2150 if (uc == null) { 2151 BSUtil.andNot(bs, am[i].bsAtoms); 2152 continue; 2153 } 2154 bs.andNot(uc.notInCentroid(this, am[i].bsAtoms, minmax)); 2155 } 2156 return bs; 2157 case T.molecule: 2158 return getMoleculeBitSet((BS) specInfo); 2159 case T.spec_seqcode_range: 2160 return getSelectCodeRange((int[]) specInfo); 2161 case T.specialposition: 2162 bs = BS.newN(ac); 2163 int modelIndex = -1; 2164 int nOps = 0; 2165 for (int i = ac; --i >= 0;) { 2166 Atom atom = at[i]; 2167 if (atom == null) 2168 continue; 2169 BS bsSym = atom.atomSymmetry; 2170 if (bsSym != null) { 2171 if (atom.mi != modelIndex) { 2172 modelIndex = atom.mi; 2173 if (getModelCellRange(modelIndex) == null) 2174 continue; 2175 nOps = getModelSymmetryCount(modelIndex); 2176 } 2177 // special positions are characterized by 2178 // multiple operator bits set in the first (overall) 2179 // block of nOpts bits. 2180 // only strictly true with load {nnn mmm 1} 2181 2182 int n = 0; 2183 for (int j = nOps; --j >= 0;) 2184 if (bsSym.get(j)) 2185 if (++n > 1) { 2186 bs.set(i); 2187 break; 2188 } 2189 } 2190 } 2191 return bs; 2192 case T.symmetry: 2193 return BSUtil.copy(bsSymmetry == null ? bsSymmetry = BS.newN(ac) 2194 : bsSymmetry); 2195 case T.unitcell: 2196 // select UNITCELL (a relative quantity) 2197 bs = new BS(); 2198 SymmetryInterface unitcell = vwr.getCurrentUnitCell(); 2199 if (unitcell == null) 2200 return bs; 2201 ptTemp1.set(1, 1, 1); 2202 for (int i = ac; --i >= 0;) 2203 if (at[i] != null && isInLatticeCell(i, ptTemp1, ptTemp2, false)) 2204 bs.set(i); 2205 return bs; 2206 } 2207 } 2208 getSelectCodeRange(int[] info)2209 private BS getSelectCodeRange(int[] info) { 2210 // could be a PDB format file that is all UNK 2211 BS bs = new BS(); 2212 int seqcodeA = info[0]; 2213 int seqcodeB = info[1]; 2214 int chainID = info[2]; 2215 boolean caseSensitive = vwr.getBoolean(T.chaincasesensitive); 2216 if (chainID >= 0 && chainID < 300 && !caseSensitive) 2217 chainID = chainToUpper(chainID); 2218 for (int iModel = mc; --iModel >= 0;) 2219 if (am[iModel].isBioModel) { 2220 BioModel m = (BioModel) am[iModel]; 2221 int id; 2222 for (int i = m.chainCount; --i >= 0;) { 2223 Chain chain = m.chains[i]; 2224 if (chainID == -1 || chainID == (id = chain.chainID) 2225 || !caseSensitive && id > 0 && id < 300 2226 && chainID == chainToUpper(id)) { 2227 Group[] groups = chain.groups; 2228 int n = chain.groupCount; 2229 for (int index = 0; index >= 0;) { 2230 index = selectSeqcodeRange(groups, n, index, seqcodeA, seqcodeB, 2231 bs); 2232 } 2233 } 2234 } 2235 } 2236 return bs; 2237 } 2238 selectSeqcodeRange(Group[] groups, int n, int index, int seqcodeA, int seqcodeB, BS bs)2239 private static int selectSeqcodeRange(Group[] groups, int n, int index, 2240 int seqcodeA, int seqcodeB, BS bs) { 2241 int seqcode, indexA, indexB, minDiff; 2242 boolean isInexact = false; 2243 for (indexA = index; indexA < n && groups[indexA].seqcode != seqcodeA; indexA++) { 2244 } 2245 if (indexA == n) { 2246 // didn't find A exactly -- go find the nearest that is GREATER than this value 2247 if (index > 0) 2248 return -1; 2249 isInexact = true; 2250 minDiff = Integer.MAX_VALUE; 2251 for (int i = n; --i >= 0;) 2252 if ((seqcode = groups[i].seqcode) > seqcodeA 2253 && (seqcode - seqcodeA) < minDiff) { 2254 indexA = i; 2255 minDiff = seqcode - seqcodeA; 2256 } 2257 if (minDiff == Integer.MAX_VALUE) 2258 return -1; 2259 } 2260 if (seqcodeB == Integer.MAX_VALUE) { 2261 indexB = n - 1; 2262 isInexact = true; 2263 } else { 2264 for (indexB = indexA; indexB < n && groups[indexB].seqcode != seqcodeB; indexB++) { 2265 } 2266 if (indexB == n) { 2267 // didn't find B exactly -- get the nearest that is LESS than this value 2268 if (index > 0) 2269 return -1; 2270 isInexact = true; 2271 minDiff = Integer.MAX_VALUE; 2272 for (int i = indexA; i < n; i++) 2273 if ((seqcode = groups[i].seqcode) < seqcodeB 2274 && (seqcodeB - seqcode) < minDiff) { 2275 indexB = i; 2276 minDiff = seqcodeB - seqcode; 2277 } 2278 if (minDiff == Integer.MAX_VALUE) 2279 return -1; 2280 } 2281 } 2282 for (int i = indexA; i <= indexB; ++i) 2283 groups[i].setAtomBits(bs); 2284 return (isInexact ? -1 : indexB + 1); 2285 } 2286 isInLatticeCell(int i, P3 cell, P3 ptTemp, boolean isAbsolute)2287 private boolean isInLatticeCell(int i, P3 cell, P3 ptTemp, boolean isAbsolute) { 2288 // this is the one method that allows for an absolute fractional cell business 2289 // but it is always called with isAbsolute FALSE. 2290 // so then it is determining values for select UNITCELL and the like. 2291 2292 int iModel = at[i].mi; 2293 SymmetryInterface uc = getUnitCell(iModel); 2294 ptTemp.setT(at[i]); 2295 return (uc != null && uc.checkUnitCell(uc, cell, ptTemp, isAbsolute)); 2296 } 2297 2298 /** 2299 * Get atoms within a specific distance of any atom in a specific set of atoms 2300 * either within all models or within just the model(s) of those atoms 2301 * 2302 * @param distance 2303 * @param bs 2304 * @param withinAllModels 2305 * @param rd 2306 * @return the set of atoms 2307 */ getAtomsWithinRadius(float distance, BS bs, boolean withinAllModels, RadiusData rd)2308 public BS getAtomsWithinRadius(float distance, BS bs, 2309 boolean withinAllModels, RadiusData rd) { 2310 BS bsResult = new BS(); 2311 BS bsCheck = getIterativeModels(false); 2312 bs = BSUtil.andNot(bs, vwr.slm.bsDeleted); 2313 AtomIndexIterator iter = getSelectedAtomIterator(null, false, false, false, 2314 false); 2315 if (withinAllModels) { 2316 boolean fixJavaFloat = !vwr.g.legacyJavaFloat; 2317 P3 ptTemp = new P3(); 2318 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) 2319 for (int iModel = mc; --iModel >= 0;) { 2320 if (!bsCheck.get(iModel)) 2321 continue; 2322 if (distance < 0) { 2323 getAtomsWithin(distance, 2324 at[i].getFractionalUnitCoordPt(fixJavaFloat, true, ptTemp), 2325 bsResult, -1); 2326 continue; 2327 } 2328 setIteratorForAtom(iter, iModel, i, distance, rd); 2329 iter.addAtoms(bsResult); 2330 } 2331 } else { 2332 bsResult.or(bs); 2333 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 2334 if (distance < 0) { 2335 getAtomsWithin(distance, at[i], bsResult, at[i].mi); 2336 continue; 2337 } 2338 setIteratorForAtom(iter, -1, i, distance, rd); 2339 iter.addAtoms(bsResult); 2340 } 2341 } 2342 iter.release(); 2343 return bsResult; 2344 } 2345 getAtomsWithin(float distance, T3 coord, BS bsResult, int modelIndex)2346 public BS getAtomsWithin(float distance, T3 coord, BS bsResult, int modelIndex) { 2347 2348 if (bsResult == null) 2349 bsResult = new BS(); 2350 2351 if (distance < 0) { // check all unitCell distances 2352 distance = -distance; 2353 for (int i = ac; --i >= 0;) { 2354 Atom atom = at[i]; 2355 if (atom == null || modelIndex >= 0 && atom.mi != modelIndex) 2356 continue; 2357 if (!bsResult.get(i) 2358 && atom.getFractionalUnitDistance(coord, ptTemp1, ptTemp2) <= distance) 2359 bsResult.set(atom.i); 2360 } 2361 return bsResult; 2362 } 2363 2364 BS bsCheck = getIterativeModels(true); 2365 AtomIndexIterator iter = getSelectedAtomIterator(null, false, false, false, 2366 false); 2367 for (int iModel = mc; --iModel >= 0;) { 2368 if (!bsCheck.get(iModel) || am[iModel].bsAtoms.isEmpty()) 2369 continue; 2370 setIteratorForAtom(iter, -1, am[iModel].firstAtomIndex, -1, null); 2371 iter.setCenter(coord, distance); 2372 iter.addAtoms(bsResult); 2373 } 2374 iter.release(); 2375 return bsResult; 2376 } 2377 2378 // ////////// Bonding methods //////////// 2379 deleteBonds(BS bsBonds, boolean isFullModel)2380 public void deleteBonds(BS bsBonds, boolean isFullModel) { 2381 if (!isFullModel) { 2382 BS bsA = new BS(); 2383 BS bsB = new BS(); 2384 for (int i = bsBonds.nextSetBit(0); i >= 0; i = bsBonds.nextSetBit(i + 1)) { 2385 Atom atom1 = bo[i].atom1; 2386 if (am[atom1.mi].isModelKit) 2387 continue; 2388 bsA.clearAll(); 2389 bsB.clearAll(); 2390 bsA.set(atom1.i); 2391 bsB.set(bo[i].getAtomIndex2()); 2392 addStateScript("connect ", null, bsA, bsB, "delete", false, true); 2393 } 2394 } 2395 dBb(bsBonds, isFullModel); 2396 } 2397 makeConnections2(float minD, float maxD, int order, int connectOperation, BS bsA, BS bsB, BS bsBonds, boolean isBonds, boolean addGroup, float energy)2398 public int[] makeConnections2(float minD, float maxD, int order, 2399 int connectOperation, BS bsA, BS bsB, 2400 BS bsBonds, boolean isBonds, boolean addGroup, 2401 float energy) { 2402 if (bsBonds == null) 2403 bsBonds = new BS(); 2404 2405 //System.out.println("MS makeConn2 " + bsA + " " + bsB + " " + order + " " + minD + " " + maxD + " " + connectOperation); 2406 2407 2408 boolean matchAny = (order == Edge.BOND_ORDER_ANY); 2409 boolean matchNull = (order == Edge.BOND_ORDER_NULL); 2410 boolean isAtrop = (order == Edge.TYPE_ATROPISOMER); 2411 if (matchNull) 2412 order = Edge.BOND_COVALENT_SINGLE; //default for setting 2413 boolean matchHbond = Edge.isOrderH(order); 2414 boolean identifyOnly = false; 2415 boolean idOrModifyOnly = false; 2416 boolean createOnly = false; 2417 boolean autoAromatize = false; 2418 switch (connectOperation) { 2419 case T.delete: 2420 return deleteConnections(minD, maxD, order, bsA, bsB, isBonds, matchNull); 2421 case T.legacyautobonding: 2422 case T.auto: 2423 if (order != Edge.BOND_AROMATIC) { 2424 if (isBonds) { 2425 BS bs = bsA; 2426 bsA = new BS(); 2427 bsB = new BS(); 2428 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 2429 bsA.set(bo[i].atom1.i); 2430 bsB.set(bo[i].atom2.i); 2431 } 2432 } 2433 return new int[] { 2434 matchHbond ? autoHbond(bsA, bsB, false) : autoBondBs4(bsA, bsB, 2435 null, bsBonds, vwr.getMadBond(), 2436 connectOperation == T.legacyautobonding), 0 }; 2437 } 2438 idOrModifyOnly = autoAromatize = true; 2439 break; 2440 case T.identify: 2441 identifyOnly = idOrModifyOnly = true; 2442 break; 2443 case T.modify: 2444 idOrModifyOnly = true; 2445 break; 2446 case T.create: 2447 createOnly = true; 2448 break; 2449 } 2450 boolean anyOrNoId = (!identifyOnly || matchAny); 2451 boolean notAnyAndNoId = (!identifyOnly && !matchAny); 2452 2453 defaultCovalentMad = vwr.getMadBond(); 2454 boolean minDIsFrac = (minD < 0); 2455 boolean maxDIsFrac = (maxD < 0); 2456 boolean isFractional = (minDIsFrac || maxDIsFrac); 2457 boolean checkDistance = (!isBonds 2458 || minD != JC.DEFAULT_MIN_CONNECT_DISTANCE || maxD != JC.DEFAULT_MAX_CONNECT_DISTANCE); 2459 if (checkDistance) { 2460 minD = fixD(minD, minDIsFrac); 2461 maxD = fixD(maxD, maxDIsFrac); 2462 } 2463 short mad = getDefaultMadFromOrder(order); 2464 int nNew = 0; 2465 int nModified = 0; 2466 Bond bondAB = null; 2467 Atom atomA = null; 2468 Atom atomB = null; 2469 char altloc = '\0'; 2470 short newOrder = (short) (order | Edge.BOND_NEW); 2471 boolean isAromatic = ((order & Edge.BOND_AROMATIC_MASK) != 0); 2472 try { 2473 for (int i = bsA.nextSetBit(0); i >= 0; i = bsA.nextSetBit(i + 1)) { 2474 if (isBonds) { 2475 bondAB = bo[i]; 2476 atomA = bondAB.atom1; 2477 atomB = bondAB.atom2; 2478 } else { 2479 atomA = at[i]; 2480 if (atomA.isDeleted()) 2481 continue; 2482 altloc = (isModulated(i) ? '\0' : atomA.altloc); 2483 } 2484 for (int j = (isBonds ? 0 : bsB.nextSetBit(0)); j >= 0; j = bsB 2485 .nextSetBit(j + 1)) { 2486 if (isBonds) { 2487 j = 2147483646; // Integer.MAX_VALUE - 1; one pass only 2488 } else { 2489 if (j == i) 2490 continue; 2491 atomB = at[j]; 2492 if (atomB == null || atomA.mi != atomB.mi || atomB.isDeleted()) 2493 continue; 2494 if (altloc != '\0' && altloc != atomB.altloc 2495 && atomB.altloc != '\0') 2496 continue; 2497 bondAB = atomA.getBond(atomB); 2498 } 2499 if ((bondAB == null ? idOrModifyOnly : createOnly) 2500 || checkDistance 2501 && !isInRange(atomA, atomB, minD, maxD, minDIsFrac, maxDIsFrac, 2502 isFractional) 2503 || isAromatic && !allowAromaticBond(bondAB) 2504 ) 2505 continue; 2506 if (bondAB == null) { 2507 bsBonds.set(bondAtoms(atomA, atomB, order, mad, bsBonds, energy, 2508 addGroup, true).index); 2509 nNew++; 2510 } else { 2511 if (notAnyAndNoId) { 2512 bondAB.setOrder(order); 2513 if (isAtrop) { 2514 haveAtropicBonds = true; 2515 bondAB.setAtropisomerOptions(bsA, bsB); 2516 } 2517 bsAromatic.clear(bondAB.index); 2518 } 2519 if (anyOrNoId || order == bondAB.order || newOrder == bondAB.order 2520 || matchHbond && bondAB.isHydrogen()) { 2521 bsBonds.set(bondAB.index); 2522 nModified++; 2523 } 2524 } 2525 } 2526 } 2527 } catch (Exception e) { 2528 // well, we tried -- probably ran over 2529 } 2530 if (autoAromatize) 2531 assignAromaticBondsBs(true, bsBonds); 2532 if (!identifyOnly) 2533 sm.setShapeSizeBs(JC.SHAPE_STICKS, Integer.MIN_VALUE, null, bsBonds); 2534 return new int[] { nNew, nModified }; 2535 } 2536 autoBondBs4(BS bsA, BS bsB, BS bsExclude, BS bsBonds, short mad, boolean preJmol11_9_24)2537 public int autoBondBs4(BS bsA, BS bsB, BS bsExclude, BS bsBonds, short mad, 2538 boolean preJmol11_9_24) { 2539 // unfortunately, 11.9.24 changed the order with which atoms were processed 2540 // for autobonding. This means that state script prior to that that use 2541 // select BOND will be misread by later version. 2542 // In addition, prior to Jmol 14.2.6, the difference between double (JavaScript) and 2543 // float (Java) was not accounted for. However, this would only affect 2544 // very borderline cases -- where we are just at the edge of the bond tolerance. 2545 // Is it worth it to fix? This is the question. 2546 if (preJmol11_9_24) 2547 return autoBond_Pre_11_9_24(bsA, bsB, bsExclude, bsBonds, mad); 2548 if (ac == 0) 2549 return 0; 2550 if (mad == 0) 2551 mad = 1; 2552 if (maxBondingRadius == PT.FLOAT_MIN_SAFE) 2553 findMaxRadii(); 2554 float bondTolerance = vwr.getFloat(T.bondtolerance); 2555 float minBondDistance = vwr.getFloat(T.minbonddistance); 2556 float minBondDistance2 = minBondDistance * minBondDistance; 2557 int nNew = 0; 2558 if (showRebondTimes)// && Logger.debugging) 2559 Logger.startTimer("autobond"); 2560 int lastModelIndex = -1; 2561 boolean isAll = (bsA == null); 2562 BS bsCheck; 2563 int i0; 2564 if (isAll) { 2565 i0 = 0; 2566 bsCheck = null; 2567 } else { 2568 if (bsA.equals(bsB)) { 2569 bsCheck = bsA; 2570 } else { 2571 bsCheck = BSUtil.copy(bsA); 2572 bsCheck.or(bsB); 2573 } 2574 i0 = bsCheck.nextSetBit(0); 2575 } 2576 AtomIndexIterator iter = getSelectedAtomIterator(null, false, false, true, 2577 false); 2578 boolean useOccupation = false; 2579 for (int i = i0; i >= 0 && i < ac; i = (isAll ? i + 1 : bsCheck 2580 .nextSetBit(i + 1))) { 2581 boolean isAtomInSetA = (isAll || bsA.get(i)); 2582 boolean isAtomInSetB = (isAll || bsB.get(i)); 2583 Atom atom = at[i]; 2584 if (atom == null || atom.isDeleted()) 2585 continue; 2586 int modelIndex = atom.mi; 2587 // no connections allowed in a data frame 2588 if (modelIndex != lastModelIndex) { 2589 lastModelIndex = modelIndex; 2590 if (isJmolDataFrameForModel(modelIndex)) { 2591 // ok here -- all data frames are orderly 2592 i = am[modelIndex].firstAtomIndex + am[modelIndex].act - 1; 2593 continue; 2594 } 2595 useOccupation = getInfoB(modelIndex, "autoBondUsingOccupation"); // JANA reader 2596 } 2597 // Covalent bonds 2598 float myBondingRadius = atom.getBondingRadius(); 2599 if (myBondingRadius == 0) 2600 continue; 2601 float myFormalCharge = atom.getFormalCharge(); 2602 boolean useCharge = (myFormalCharge != 0); 2603 if (useCharge) 2604 myFormalCharge = Math.signum(myFormalCharge); 2605 boolean isFirstExcluded = (bsExclude != null && bsExclude.get(i)); 2606 float searchRadius = myBondingRadius + maxBondingRadius + bondTolerance; 2607 setIteratorForAtom(iter, -1, i, searchRadius, null); 2608 while (iter.hasNext()) { 2609 Atom atomNear = at[iter.next()]; 2610 if (atomNear.isDeleted()) 2611 continue; 2612 int j = atomNear.i; 2613 boolean isNearInSetA = (isAll || bsA.get(j)); 2614 boolean isNearInSetB = (isAll || bsB.get(j)); 2615 // BOTH must be excluded in order to ignore bonding 2616 if (!isNearInSetA && !isNearInSetB 2617 || !(isAtomInSetA && isNearInSetB || isAtomInSetB && isNearInSetA) 2618 || isFirstExcluded && bsExclude.get(j) || useOccupation 2619 && occupancies != null 2620 && (occupancies[i] < 50) != (occupancies[j] < 50) 2621 || useCharge && (Math.signum(atomNear.getFormalCharge()) == myFormalCharge) 2622 ) 2623 continue; 2624 int order = (isBondable(myBondingRadius, atomNear.getBondingRadius(), 2625 iter.foundDistance2(), minBondDistance2, bondTolerance) ? 1 : 0); 2626 if (order > 0 && autoBondCheck(atom, atomNear, order, mad, bsBonds)) 2627 nNew++; 2628 } 2629 iter.release(); 2630 } 2631 if (showRebondTimes) 2632 Logger.checkTimer("autoBond", false); 2633 return nNew; 2634 } 2635 isBondable(float bondingRadiusA, float bondingRadiusB, float distance2, float minBondDistance2, float bondTolerance)2636 public boolean isBondable(float bondingRadiusA, float bondingRadiusB, 2637 float distance2, float minBondDistance2, 2638 float bondTolerance) { 2639 if (bondingRadiusA == 0 || bondingRadiusB == 0 2640 || distance2 < minBondDistance2) 2641 return false; 2642 float maxAcceptable = bondingRadiusA + bondingRadiusB + bondTolerance; 2643 float maxAcceptable2 = maxAcceptable * maxAcceptable; 2644 return (distance2 <= maxAcceptable2); 2645 } 2646 2647 private boolean maxBondWarned; 2648 autoBondCheck(Atom atomA, Atom atomB, int order, short mad, BS bsBonds)2649 private boolean autoBondCheck(Atom atomA, Atom atomB, int order, short mad, 2650 BS bsBonds) { 2651 if (atomA.getCurrentBondCount() > JC.MAXIMUM_AUTO_BOND_COUNT 2652 || atomB.getCurrentBondCount() > JC.MAXIMUM_AUTO_BOND_COUNT) { 2653 if (!maxBondWarned) 2654 Logger.warn("maximum auto bond count reached"); 2655 maxBondWarned = true; 2656 return false; 2657 } 2658 int formalChargeA = atomA.getFormalCharge(); 2659 if (formalChargeA != 0) { 2660 int formalChargeB = atomB.getFormalCharge(); 2661 if ((formalChargeA < 0 && formalChargeB < 0) 2662 || (formalChargeA > 0 && formalChargeB > 0)) 2663 return false; 2664 } 2665 // don't connect differing altloc unless there are modulations 2666 if (atomA.altloc != atomB.altloc && atomA.altloc != '\0' 2667 && atomB.altloc != '\0' && getModulation(atomA.i) == null) 2668 return false; 2669 getOrAddBond(atomA, atomB, order, mad, bsBonds, 0, false); 2670 return true; 2671 } 2672 autoBond_Pre_11_9_24(BS bsA, BS bsB, BS bsExclude, BS bsBonds, short mad)2673 private int autoBond_Pre_11_9_24(BS bsA, BS bsB, BS bsExclude, BS bsBonds, 2674 short mad) { 2675 if (ac == 0) 2676 return 0; 2677 if (mad == 0) 2678 mad = 1; 2679 // null values for bitsets means "all" 2680 if (maxBondingRadius == PT.FLOAT_MIN_SAFE) 2681 findMaxRadii(); 2682 float bondTolerance = vwr.getFloat(T.bondtolerance); 2683 float minBondDistance = vwr.getFloat(T.minbonddistance); 2684 float minBondDistance2 = minBondDistance * minBondDistance; 2685 int nNew = 0; 2686 initializeBspf(); 2687 /* 2688 * miguel 2006 04 02 2689 * note that the way that these loops + iterators are constructed, 2690 * everything assumes that all possible pairs of atoms are going to 2691 * be looked at. 2692 * for example, the hemisphere iterator will only look at atom indexes 2693 * that are >= (or <= ?) the specified atom. 2694 * if we are going to allow arbitrary sets bsA and bsB, then this will 2695 * not work. 2696 * so, for now I will do it the ugly way. 2697 * maybe enhance/improve in the future. 2698 */ 2699 int lastModelIndex = -1; 2700 for (int i = ac; --i >= 0;) { 2701 Atom atom = at[i]; 2702 if (atom == null) 2703 continue; 2704 boolean isAtomInSetA = (bsA == null || bsA.get(i)); 2705 boolean isAtomInSetB = (bsB == null || bsB.get(i)); 2706 if (!isAtomInSetA && !isAtomInSetB) 2707 //|| bsExclude != null && bsExclude.get(i)) 2708 continue; 2709 if (atom.isDeleted()) 2710 continue; 2711 int modelIndex = atom.mi; 2712 //no connections allowed in a data frame 2713 if (modelIndex != lastModelIndex) { 2714 lastModelIndex = modelIndex; 2715 if (isJmolDataFrameForModel(modelIndex)) { 2716 for (; --i >= 0;) 2717 if (at[i] == null || at[i].mi != modelIndex) 2718 break; 2719 i++; 2720 continue; 2721 } 2722 } 2723 // Covalent bonds 2724 float myBondingRadius = atom.getBondingRadius(); 2725 if (myBondingRadius == 0) 2726 continue; 2727 float searchRadius = myBondingRadius + maxBondingRadius + bondTolerance; 2728 initializeBspt(modelIndex); 2729 CubeIterator iter = bspf.getCubeIterator(modelIndex); 2730 iter.initialize(atom, searchRadius, true); 2731 while (iter.hasMoreElements()) { 2732 Atom atomNear = (Atom) iter.nextElement(); 2733 if (atomNear == atom || atomNear.isDeleted()) 2734 continue; 2735 int atomIndexNear = atomNear.i; 2736 boolean isNearInSetA = (bsA == null || bsA.get(atomIndexNear)); 2737 boolean isNearInSetB = (bsB == null || bsB.get(atomIndexNear)); 2738 if (!isNearInSetA && !isNearInSetB || bsExclude != null 2739 && bsExclude.get(atomIndexNear) && bsExclude.get(i) //this line forces BOTH to be excluded in order to ignore bonding 2740 ) 2741 continue; 2742 if (!(isAtomInSetA && isNearInSetB || isAtomInSetB && isNearInSetA)) 2743 continue; 2744 int order = (isBondable(myBondingRadius, atomNear.getBondingRadius(), 2745 iter.foundDistance2(), minBondDistance2, bondTolerance) ? 1 : 0); 2746 if (order > 0) { 2747 if (autoBondCheck(atom, atomNear, order, mad, bsBonds)) 2748 nNew++; 2749 } 2750 } 2751 iter.release(); 2752 } 2753 return nNew; 2754 } 2755 2756 /** 2757 * a generalized formation of HBONDS, carried out in relation to calculate 2758 * HBONDS {atomsFrom} {atomsTo}. The calculation can create pseudo-H bonds for 2759 * files that do not contain H atoms. 2760 * 2761 * @param bsA 2762 * "from" set (must contain H if that is desired) 2763 * @param bsB 2764 * "to" set 2765 * @param onlyIfHaveCalculated 2766 * @return negative number of pseudo-hbonds or number of actual hbonds formed 2767 */ autoHbond(BS bsA, BS bsB, boolean onlyIfHaveCalculated)2768 public int autoHbond(BS bsA, BS bsB, boolean onlyIfHaveCalculated) { 2769 if (onlyIfHaveCalculated) { 2770 BS bsModels = getModelBS(bsA, false); 2771 for (int i = bsModels.nextSetBit(0); i >= 0 2772 && onlyIfHaveCalculated; i = bsModels.nextSetBit(i + 1)) 2773 onlyIfHaveCalculated = !am[i].hasRasmolHBonds; 2774 if (onlyIfHaveCalculated) 2775 return 0; 2776 } 2777 boolean haveHAtoms = false; 2778 for (int i = bsA.nextSetBit(0); i >= 0; i = bsA.nextSetBit(i + 1)) 2779 if (at[i].getElementNumber() == 1) { 2780 haveHAtoms = true; 2781 break; 2782 } 2783 BS bsHBonds = new BS(); 2784 boolean useRasMol = vwr.getBoolean(T.hbondsrasmol); 2785 if (bsB == null || useRasMol && !haveHAtoms) { 2786 Logger.info((bsB == null ? "DSSP/DSSR " : "RasMol") 2787 + " pseudo-hbond calculation"); 2788 calcRasmolHydrogenBonds(bsA, bsB, null, false, Integer.MAX_VALUE, false, 2789 bsHBonds); 2790 return -bsHBonds.cardinality(); 2791 } 2792 Logger.info(haveHAtoms ? "Standard Hbond calculation" 2793 : "Jmol pseudo-hbond calculation"); 2794 BS bsCO = null; 2795 if (!haveHAtoms) { 2796 bsCO = new BS(); 2797 for (int i = bsA.nextSetBit(0); i >= 0; i = bsA.nextSetBit(i + 1)) { 2798 int atomID = at[i].atomID; 2799 switch (atomID) { 2800 case JC.ATOMID_TERMINATING_OXT: 2801 case JC.ATOMID_CARBONYL_OXYGEN: 2802 case JC.ATOMID_CARBONYL_OD1: 2803 case JC.ATOMID_CARBONYL_OD2: 2804 case JC.ATOMID_CARBONYL_OE1: 2805 case JC.ATOMID_CARBONYL_OE2: 2806 bsCO.set(i); 2807 break; 2808 } 2809 } 2810 } 2811 float dmax; 2812 float min2; 2813 if (haveHAtoms) { 2814 // no set maximumn for this anymore -- default is 2.5A 2815 dmax = vwr.getFloat(T.hbondhxdistancemaximum); 2816 min2 = 1f; 2817 } else { 2818 dmax = vwr.getFloat(T.hbondnodistancemaximum); 2819 // default 3.25 for pseudo; user can make longer or shorter 2820 min2 = hbondMinRasmol * hbondMinRasmol; 2821 } 2822 float max2 = dmax * dmax; 2823 float minAttachedAngle = (float) (vwr.getFloat(T.hbondsangleminimum) 2824 * Math.PI / 180); 2825 int nNew = 0; 2826 float d2 = 0; 2827 V3 v1 = new V3(); 2828 V3 v2 = new V3(); 2829 if (showRebondTimes && Logger.debugging) 2830 Logger.startTimer("hbond"); 2831 P3 C = null; 2832 P3 D = null; 2833 AtomIndexIterator iter = getSelectedAtomIterator(bsB, false, false, false, 2834 false); 2835 for (int i = bsA.nextSetBit(0); i >= 0; i = bsA.nextSetBit(i + 1)) { 2836 Atom atom = at[i]; 2837 int elementNumber = atom.getElementNumber(); 2838 boolean isH = (elementNumber == 1); 2839 // If this is an H atom, then skip if we don't have H atoms in set A 2840 // If this is NOT an H atom, then skip if we have hydrogen atoms or this is not N or O 2841 if (isH ? !haveHAtoms 2842 : haveHAtoms || elementNumber != 7 && elementNumber != 8) 2843 continue; 2844 2845 boolean firstIsCO; 2846 if (isH) { 2847 firstIsCO = false; 2848 Bond[] b = atom.bonds; 2849 if (b == null) 2850 continue; 2851 // must have OH or NH 2852 boolean isOK = false; 2853 for (int j = 0; !isOK && j < b.length; j++) { 2854 Atom a2 = b[j].getOtherAtom(atom); 2855 int element = a2.getElementNumber(); 2856 isOK = (element == 7 || element == 8); 2857 } 2858 if (!isOK) 2859 continue; 2860 } else { 2861 // check if the first atom is C=O 2862 firstIsCO = bsCO.get(i); 2863 } 2864 setIteratorForAtom(iter, -1, atom.i, dmax, null); 2865 while (iter.hasNext()) { 2866 Atom atomNear = at[iter.next()]; 2867 int elementNumberNear = atomNear.getElementNumber(); 2868 if (atomNear == atom 2869 || (isH ? elementNumberNear == 1 : elementNumberNear != 7 && elementNumberNear != 8) 2870 || (d2 = iter.foundDistance2()) < min2 || d2 > max2 2871 || firstIsCO && bsCO.get(atomNear.i) 2872 || atom.isBonded(atomNear)) { 2873 continue; 2874 } 2875 if (minAttachedAngle > 0) { 2876 v1.sub2(atom, atomNear); 2877 if ((D = checkMinAttachedAngle(atom, minAttachedAngle, v1, v2, 2878 haveHAtoms)) == null) 2879 continue; 2880 v1.scale(-1); 2881 if ((C = checkMinAttachedAngle(atomNear, minAttachedAngle, v1, v2, 2882 haveHAtoms)) == null) 2883 continue; 2884 } 2885 float energy = 0; 2886 short bo; 2887 if (isH && !Float.isNaN(C.x) && !Float.isNaN(D.x)) { 2888 bo = Edge.BOND_H_CALC; 2889 // (+) H .......... A (-) 2890 // | | 2891 // | | 2892 // (-) D C (+) 2893 // 2894 // AH args[0], CH args[1], CD args[2], DA args[3] 2895 // 2896 energy = HBond.getEnergy((float) Math.sqrt(d2), C.distance(atom), 2897 C.distance(D), atomNear.distance(D)) / 1000f; 2898 } else { 2899 bo = Edge.BOND_H_REGULAR; 2900 } 2901 bsHBonds.set(addHBond(atom, atomNear, bo, energy)); 2902 nNew++; 2903 } 2904 } 2905 iter.release(); 2906 sm.setShapeSizeBs(JC.SHAPE_STICKS, Integer.MIN_VALUE, null, bsHBonds); 2907 if (showRebondTimes) 2908 Logger.checkTimer("hbond", false); 2909 return (haveHAtoms ? nNew : -nNew); 2910 } 2911 checkMinAttachedAngle(Atom atom1, float minAngle, V3 v1, V3 v2, boolean haveHAtoms)2912 private static P3 checkMinAttachedAngle(Atom atom1, float minAngle, V3 v1, 2913 V3 v2, boolean haveHAtoms) { 2914 Bond[] bonds = atom1.bonds; 2915 boolean ignore = true; 2916 Atom X = null; 2917 if (bonds != null && bonds.length > 0) { 2918 float dMin = Float.MAX_VALUE; 2919 for (int i = bonds.length; --i >= 0;) 2920 if (bonds[i].isCovalent()) { 2921 ignore = false; 2922 Atom atomA = bonds[i].getOtherAtom(atom1); 2923 if (!haveHAtoms && atomA.getElementNumber() == 1) 2924 continue; 2925 v2.sub2(atom1, atomA); 2926 float d = v2.angle(v1); 2927 if (d < minAngle) 2928 return null; 2929 if (d < dMin) { 2930 X = atomA; 2931 dMin = d; 2932 } 2933 } 2934 } 2935 return (ignore ? P3.new3(Float.NaN, 0, 0) : X); 2936 } 2937 2938 //////////// state definition /////////// 2939 setStructureIndexes()2940 public void setStructureIndexes() { 2941 int id; 2942 int idnew = 0; 2943 int lastid = -1; 2944 int imodel = -1; 2945 int lastmodel = -1; 2946 for (int i = 0; i < ac; i++) { 2947 if (at[i] == null) 2948 continue; 2949 if ((imodel = at[i].mi) != lastmodel) { 2950 idnew = 0; 2951 lastmodel = imodel; 2952 lastid = -1; 2953 } 2954 if ((id = at[i].group.getStrucNo()) != lastid && id != 0) { 2955 at[i].group.setStrucNo(++idnew); 2956 lastid = idnew; 2957 } 2958 } 2959 } 2960 getModelInfoAsString()2961 public String getModelInfoAsString() { 2962 SB sb = new SB().append("<models count=\""); 2963 sb.appendI(mc).append("\" modelSetHasVibrationVectors=\"") 2964 .append(modelSetHasVibrationVectors() + "\">\n<properties>"); 2965 if (modelSetProperties != null) { 2966 Enumeration<?> e = modelSetProperties.propertyNames(); 2967 while (e.hasMoreElements()) { 2968 String propertyName = (String) e.nextElement(); 2969 sb.append("\n <property name=\"").append(propertyName) 2970 .append("\" value=") 2971 .append(PT.esc(modelSetProperties.getProperty(propertyName))) 2972 .append(" />"); 2973 } 2974 sb.append("\n</properties>"); 2975 } 2976 for (int i = 0; i < mc; ++i) { 2977 sb.append("\n<model index=\"").appendI(i).append("\" n=\"") 2978 .append(getModelNumberDotted(i)).append("\" id=") 2979 .append(PT.esc("" + getInfo(i, "modelID"))); 2980 int ib = vwr.getJDXBaseModelIndex(i); 2981 if (ib != i) 2982 sb.append(" baseModelId=").append( 2983 PT.esc((String) getInfo(ib, "jdxModelID"))); 2984 sb.append(" name=").append(PT.esc(getModelName(i))).append(" title=") 2985 .append(PT.esc(getModelTitle(i))).append(" hasVibrationVectors=\"") 2986 .appendB(vwr.modelHasVibrationVectors(i)).append("\" />"); 2987 } 2988 sb.append("\n</models>"); 2989 return sb.toString(); 2990 } 2991 getSymmetryInfoAsString()2992 public String getSymmetryInfoAsString() { 2993 SB sb = new SB().append("Symmetry Information:"); 2994 for (int i = 0; i < mc; ++i) { 2995 sb.append("\nmodel #").append(getModelNumberDotted(i)).append("; name=") 2996 .append(getModelName(i)).append("\n"); 2997 SymmetryInterface unitCell = getUnitCell(i); 2998 sb.append(unitCell == null ? "no symmetry information" : unitCell 2999 .getSymmetryInfoStr()); 3000 } 3001 return sb.toString(); 3002 } 3003 createModels(int n)3004 public void createModels(int n) { 3005 int newModelCount = mc + n; 3006 Model[] newModels = (Model[]) AU.arrayCopyObject(am, newModelCount); 3007 validateBspf(false); 3008 modelNumbers = AU.arrayCopyI(modelNumbers, newModelCount); 3009 modelFileNumbers = AU.arrayCopyI(modelFileNumbers, newModelCount); 3010 modelNumbersForAtomLabel = AU.arrayCopyS(modelNumbersForAtomLabel, 3011 newModelCount); 3012 modelNames = AU.arrayCopyS(modelNames, newModelCount); 3013 frameTitles = AU.arrayCopyS(frameTitles, newModelCount); 3014 int f = modelFileNumbers[mc - 1] / 1000000 + 1; 3015 for (int i = mc, pt = 0; i < newModelCount; i++) { 3016 modelNumbers[i] = i + mc; 3017 modelFileNumbers[i] = f * 1000000 + (++pt); 3018 modelNumbersForAtomLabel[i] = modelNames[i] = f + "." + pt; 3019 } 3020 thisStateModel = -1; 3021 String[] group3Lists = (String[]) getInfoM("group3Lists"); 3022 if (group3Lists != null) { 3023 int[][] group3Counts = (int[][]) getInfoM("group3Counts"); 3024 group3Lists = AU.arrayCopyS(group3Lists, newModelCount); 3025 group3Counts = AU.arrayCopyII(group3Counts, newModelCount); 3026 msInfo.put("group3Lists", group3Lists); 3027 msInfo.put("group3Counts", group3Counts); 3028 } 3029 unitCells = (SymmetryInterface[]) AU.arrayCopyObject(unitCells, 3030 newModelCount); 3031 for (int i = mc; i < newModelCount; i++) { 3032 newModels[i] = new Model().set(this, i, -1, null, null, null); 3033 newModels[i].loadState = " model create #" + i + ";"; 3034 } 3035 am = newModels; 3036 mc = newModelCount; 3037 } 3038 deleteAtoms(BS bs)3039 public void deleteAtoms(BS bs) { 3040 //averageAtomPoint = null; 3041 if (bs == null) 3042 return; 3043 BS bsBonds = new BS(); 3044 boolean doNull = Viewer.nullDeletedAtoms; 3045 for (int i = bs.nextSetBit(0); i >= 0 && i < ac; i = bs.nextSetBit(i + 1)) { 3046 at[i].delete(bsBonds); 3047 if (doNull) 3048 at[i] = null; 3049 } 3050 for (int i = 0; i < mc; i++) { 3051 Model m = am[i]; 3052 m.resetDSSR(false); 3053 m.bsAtomsDeleted.or(bs); 3054 m.bsAtomsDeleted.and(m.bsAtoms); 3055 bs = BSUtil.andNot(m.bsAtoms, m.bsAtomsDeleted); 3056 m.firstAtomIndex = bs.nextSetBit(0); 3057 m.act = bs.cardinality(); 3058 m.isOrderly = (m.act == m.bsAtoms.length()); 3059 } 3060 deleteBonds(bsBonds, false); 3061 validateBspf(false); 3062 } 3063 clearDB(int atomIndex)3064 public void clearDB(int atomIndex) { 3065 getModelAuxiliaryInfo(at[atomIndex].mi).remove("dbName"); 3066 } 3067 3068 3069 // atom addition // 3070 adjustAtomArrays(int[] map, int i0, int ac)3071 public void adjustAtomArrays(int[] map, int i0, int ac) { 3072 // from ModelLoader, after hydrogen atom addition 3073 this.ac = ac; 3074 for (int i = i0; i < ac; i++) { 3075 at[i] = at[map[i]]; 3076 at[i].i = i; 3077 Model m = am[at[i].mi]; 3078 if (m.firstAtomIndex == map[i]) 3079 m.firstAtomIndex = i; 3080 m.bsAtoms.set(i); 3081 } 3082 if (vibrations != null) 3083 for (int i = i0; i < ac; i++) 3084 vibrations[i] = vibrations[map[i]]; 3085 if (atomTensorList != null) { 3086 for (int i = i0; i < ac; i++) { 3087 Object[] list = atomTensorList[i] = atomTensorList[map[i]]; 3088 if (list != null) 3089 for (int j = list.length; --j >= 0;) { 3090 Tensor t = (Tensor) list[j]; 3091 if (t != null) { 3092 t.atomIndex1 = i; 3093 } 3094 } 3095 } 3096 } 3097 if (atomNames != null) 3098 for (int i = i0; i < ac; i++) 3099 atomNames[i] = atomNames[map[i]]; 3100 if (atomTypes != null) 3101 for (int i = i0; i < ac; i++) 3102 atomTypes[i] = atomTypes[map[i]]; 3103 3104 if (atomResnos != null) 3105 for (int i = i0; i < ac; i++) 3106 atomResnos[i] = atomResnos[map[i]]; 3107 if (atomSerials != null) 3108 for (int i = i0; i < ac; i++) 3109 atomSerials[i] = atomSerials[map[i]]; 3110 if (atomSeqIDs != null) 3111 for (int i = i0; i < ac; i++) 3112 atomSeqIDs[i] = atomSeqIDs[map[i]]; 3113 3114 if (bfactor100s != null) 3115 for (int i = i0; i < ac; i++) 3116 bfactor100s[i] = bfactor100s[map[i]]; 3117 3118 if (occupancies != null) 3119 for (int i = i0; i < ac; i++) 3120 occupancies[i] = occupancies[map[i]]; 3121 if (partialCharges != null) 3122 for (int i = i0; i < ac; i++) 3123 partialCharges[i] = partialCharges[map[i]]; 3124 } 3125 growAtomArrays(int newLength)3126 protected void growAtomArrays(int newLength) { 3127 at = (Atom[]) AU.arrayCopyObject(at, newLength); 3128 if (vibrations != null) 3129 vibrations = (Vibration[]) AU.arrayCopyObject(vibrations, newLength); 3130 if (occupancies != null) 3131 occupancies = AU.arrayCopyF(occupancies, newLength); 3132 if (bfactor100s != null) 3133 bfactor100s = AU.arrayCopyShort(bfactor100s, newLength); 3134 if (partialCharges != null) 3135 partialCharges = AU.arrayCopyF(partialCharges, newLength); 3136 if (atomTensorList != null) 3137 atomTensorList = (Object[][]) AU.arrayCopyObject(atomTensorList, 3138 newLength); 3139 if (atomNames != null) 3140 atomNames = AU.arrayCopyS(atomNames, newLength); 3141 if (atomTypes != null) 3142 atomTypes = AU.arrayCopyS(atomTypes, newLength); 3143 if (atomResnos != null) 3144 atomResnos = AU.arrayCopyI(atomResnos, newLength); 3145 if (atomSerials != null) 3146 atomSerials = AU.arrayCopyI(atomSerials, newLength); 3147 if (atomSeqIDs != null) 3148 atomSeqIDs = AU.arrayCopyI(atomSeqIDs, newLength); 3149 } 3150 addAtom(int modelIndex, Group group, int atomicAndIsotopeNumber, String atomName, String atomType, int atomSerial, int atomSeqID, int atomSite, P3 xyz, float radius, V3 vib, int formalCharge, float partialCharge, float occupancy, float bfactor, Lst<Object> tensors, boolean isHetero, byte specialAtomID, BS atomSymmetry, float bondRadius)3151 public Atom addAtom(int modelIndex, Group group, int atomicAndIsotopeNumber, 3152 String atomName, String atomType, int atomSerial, 3153 int atomSeqID, int atomSite, P3 xyz, float radius, 3154 V3 vib, int formalCharge, float partialCharge, 3155 float occupancy, float bfactor, Lst<Object> tensors, 3156 boolean isHetero, byte specialAtomID, BS atomSymmetry, float bondRadius) { 3157 Atom atom = new Atom().setAtom(modelIndex, ac, xyz, radius, atomSymmetry, 3158 atomSite, (short) atomicAndIsotopeNumber, formalCharge, isHetero); 3159 am[modelIndex].act++; 3160 am[modelIndex].bsAtoms.set(ac); 3161 if (Elements.isElement(atomicAndIsotopeNumber, 1)) 3162 am[modelIndex].hydrogenCount++; 3163 if (ac >= at.length) 3164 growAtomArrays(ac + 100); // only due to added hydrogens 3165 3166 at[ac] = atom; 3167 setBFactor(ac, bfactor, false); 3168 setOccupancy(ac, occupancy, false); 3169 setPartialCharge(ac, partialCharge, false); 3170 if (tensors != null) 3171 setAtomTensors(ac, tensors); 3172 atom.group = group; 3173 atom.colixAtom = vwr.cm.getColixAtomPalette(atom, PAL.CPK.id); 3174 if (atomName != null) { 3175 if (atomType != null) { 3176 if (atomTypes == null) 3177 atomTypes = new String[at.length]; 3178 atomTypes[ac] = atomType; 3179 } 3180 atom.atomID = specialAtomID; 3181 if (specialAtomID == 0) { 3182 if (atomNames == null) 3183 atomNames = new String[at.length]; 3184 atomNames[ac] = atomName.intern(); 3185 } 3186 } 3187 if (atomSerial != Integer.MIN_VALUE) { 3188 if (atomSerials == null) 3189 atomSerials = new int[at.length]; 3190 atomSerials[ac] = atomSerial; 3191 } 3192 if (atomSeqID != 0) { 3193 if (atomSeqIDs == null) 3194 atomSeqIDs = new int[at.length]; 3195 atomSeqIDs[ac] = atomSeqID; 3196 } 3197 if (vib != null) 3198 setVibrationVector(ac, vib); 3199 if (!Float.isNaN(bondRadius)) 3200 setBondingRadius(ac, bondRadius); 3201 ac++; 3202 return atom; 3203 } 3204 getInlineData(int modelIndex)3205 public String getInlineData(int modelIndex) { 3206 SB data = null; 3207 if (modelIndex >= 0) 3208 data = am[modelIndex].loadScript; 3209 else 3210 for (modelIndex = mc; --modelIndex >= 0;) 3211 if ((data = am[modelIndex].loadScript).length() > 0) 3212 break; 3213 int pt = data.lastIndexOf("data \""); 3214 if (pt < 0) { // load inline ... 3215 String s = PT.getQuotedStringAt(data.toString(), 0); 3216 return ScriptCompiler.unescapeString(s, 0, s.length()); 3217 } 3218 pt = data.indexOf2("\"", pt + 7); 3219 int pt2 = data.lastIndexOf("end \""); 3220 if (pt2 < pt || pt < 0) 3221 return null; 3222 return data.substring2(pt + 2, pt2); 3223 } 3224 isAtomPDB(int i)3225 public boolean isAtomPDB(int i) { 3226 return i >= 0 && am[at[i].mi].isBioModel; 3227 } 3228 3229 /** 3230 * Ensure the atom index is >= 0 and that the 3231 * atom's model is the last model. 3232 * 3233 * @param i 3234 * @return true if that is the case 3235 */ isAtomInLastModel(int i)3236 public boolean isAtomInLastModel(int i) { 3237 return i >= 0 && at[i].mi == mc - 1; 3238 } 3239 haveModelKit()3240 public boolean haveModelKit() { 3241 for (int i = 0; i < mc; i++) 3242 if (am[i].isModelKit) 3243 return true; 3244 return false; 3245 } 3246 getModelKitStateBitset(BS bs, BS bsDeleted)3247 public BS getModelKitStateBitset(BS bs, BS bsDeleted) { 3248 // task here is to remove bits from bs that are deleted atoms in 3249 // models that are model kits. 3250 3251 BS bs1 = BSUtil.copy(bsDeleted); 3252 for (int i = 0; i < mc; i++) 3253 if (!am[i].isModelKit) 3254 bs1.andNot(am[i].bsAtoms); 3255 return BSUtil.deleteBits(bs, bs1); 3256 } 3257 3258 /** 3259 * 3260 * @param iFirst 3261 * 0 from ModelLoader.freeze; -1 from Viewer.assignAtom 3262 * @param baseAtomIndex 3263 * @param mergeSet 3264 */ setAtomNamesAndNumbers(int iFirst, int baseAtomIndex, AtomCollection mergeSet)3265 public void setAtomNamesAndNumbers(int iFirst, int baseAtomIndex, 3266 AtomCollection mergeSet) { 3267 // first, validate that all atomSerials are NaN 3268 if (baseAtomIndex < 0) 3269 iFirst = am[at[iFirst].mi].firstAtomIndex; 3270 if (atomSerials == null) 3271 atomSerials = new int[ac]; 3272 if (atomNames == null) 3273 atomNames = new String[ac]; 3274 // now, we'll assign 1-based atom numbers within each model 3275 boolean isZeroBased = isXYZ && vwr.getBoolean(T.zerobasedxyzrasmol); 3276 int lastModelIndex = Integer.MAX_VALUE; 3277 int atomNo = 1; 3278 for (int i = iFirst; i < ac; ++i) { 3279 Atom atom = at[i]; 3280 if (atom == null) 3281 continue; 3282 if (atom.mi != lastModelIndex) { 3283 lastModelIndex = atom.mi; 3284 atomNo = (isZeroBased ? 0 : 1); 3285 } 3286 // 1) do not change numbers assigned by adapter 3287 // 2) do not change the number already assigned when merging 3288 // 3) restart numbering with new atoms, not a continuation of old 3289 int ano = atomSerials[i]; 3290 3291 if (i >= -baseAtomIndex) { 3292 if (ano == 0 || baseAtomIndex < 0) 3293 atomSerials[i] = (i < baseAtomIndex ? mergeSet.atomSerials[i] 3294 : atomNo); 3295 if (atomNames[i] == null || baseAtomIndex < 0) 3296 atomNames[i] = (atom.getElementSymbol() + atomSerials[i]).intern(); 3297 } else if (ano > atomNo) { 3298 atomNo = ano; 3299 } 3300 if (!am[lastModelIndex].isModelKit || atom.getElementNumber() > 0 3301 && !atom.isDeleted()) 3302 atomNo++; 3303 } 3304 } 3305 setUnitCellOffset(SymmetryInterface unitCell, T3 pt, int ijk)3306 public void setUnitCellOffset(SymmetryInterface unitCell, T3 pt, int ijk) { 3307 // for (int i = modelIndex; i < modelCount; i++) { 3308 // if (i < 0 || modelIndex >= 0 && i != modelIndex 3309 // && models[i].trajectoryBaseIndex != modelIndex) 3310 // continue; 3311 // unitCell = getUnitCell(i); 3312 if (unitCell == null) 3313 return; 3314 if (pt == null) 3315 unitCell.setOffset(ijk); 3316 else 3317 unitCell.setOffsetPt(pt); 3318 // } 3319 } 3320 connect(float[][] connections)3321 public void connect(float[][] connections) { 3322 // array of [index1 index2 order diameter energy] 3323 resetMolecules(); 3324 BS bsDelete = new BS(); 3325 for (int i = 0; i < connections.length; i++) { 3326 float[] f = connections[i]; 3327 if (f == null || f.length < 2) 3328 continue; 3329 int index1 = (int) f[0]; 3330 boolean addGroup = (index1 < 0); 3331 if (addGroup) 3332 index1 = -1 - index1; 3333 int index2 = (int) f[1]; 3334 if (index2 < 0 || index1 >= ac || index2 >= ac) 3335 continue; 3336 int order = (f.length > 2 ? (int) f[2] : Edge.BOND_COVALENT_SINGLE); 3337 if (order < 0) 3338 order &= 0xFFFF; // 12.0.1 was saving struts as negative numbers 3339 short mad = (f.length > 3 ? (short) (1000f * connections[i][3]) 3340 : getDefaultMadFromOrder(order)); 3341 if (order == 0 || mad == 0 && order != Edge.BOND_STRUT 3342 && !Edge.isOrderH(order)) { 3343 Bond b = at[index1].getBond(at[index2]); 3344 if (b != null) 3345 bsDelete.set(b.index); 3346 continue; 3347 } 3348 float energy = (f.length > 4 ? f[4] : 0); 3349 bondAtoms(at[index1], at[index2], order, mad, null, energy, addGroup, 3350 true); 3351 } 3352 if (bsDelete.nextSetBit(0) >= 0) 3353 deleteBonds(bsDelete, false); 3354 } 3355 setFrameDelayMs(long millis, BS bsModels)3356 public void setFrameDelayMs(long millis, BS bsModels) { 3357 for (int i = bsModels.nextSetBit(0); i >= 0; i = bsModels.nextSetBit(i + 1)) 3358 am[am[i].trajectoryBaseIndex].frameDelay = millis; 3359 } 3360 getFrameDelayMs(int i)3361 public long getFrameDelayMs(int i) { 3362 return (i < am.length && i >= 0 ? am[am[i].trajectoryBaseIndex].frameDelay 3363 : 0); 3364 } 3365 getModelIndexFromId(String id)3366 public int getModelIndexFromId(String id) { 3367 boolean haveFile = (id.indexOf("#") >= 0); 3368 boolean isBaseModel = id.toLowerCase().endsWith(".basemodel"); 3369 if (isBaseModel) 3370 id = id.substring(0, id.length() - 10); 3371 int errCode = -1; 3372 String fname = null; 3373 for (int i = 0; i < mc; i++) { 3374 String mid = (String) getInfo(i, "modelID"); 3375 String mnum = (id.startsWith("~") ? "~" + getModelNumberDotted(i) : null); 3376 if (mnum == null && mid == null && (mid = getModelTitle(i)) == null) 3377 continue; 3378 if (haveFile) { 3379 fname = getModelFileName(i); 3380 if (fname.endsWith("#molfile")) { 3381 mid = fname; 3382 } else { 3383 fname += "#"; 3384 mid = fname + mid; 3385 } 3386 } 3387 if (id.equalsIgnoreCase(mid) || id.equalsIgnoreCase(mnum)) 3388 return (isBaseModel ? vwr.getJDXBaseModelIndex(i) : i); 3389 if (fname != null && id.startsWith(fname)) 3390 errCode = -2; 3391 } 3392 return (fname == null && !haveFile ? -2 : errCode); 3393 } 3394 3395 /** 3396 * Retrieve the main modelset info Hashtable (or a new non-null Hashtable) 3397 * with an up-to-date "models" key. 3398 * 3399 * @param bsModels 3400 * @return Map 3401 */ getAuxiliaryInfo(BS bsModels)3402 public Map<String, Object> getAuxiliaryInfo(BS bsModels) { 3403 Map<String, Object> info = msInfo; 3404 if (info == null) 3405 info = new Hashtable<String, Object>(); 3406 if (bsModels != null || !info.containsKey("models")) { 3407 Lst<Map<String, Object>> minfo = new Lst<Map<String, Object>>(); 3408 for (int i = 0; i < mc; ++i) 3409 if (bsModels == null || bsModels.get(i)) { 3410 Map<String, Object> m = getModelAuxiliaryInfo(i); 3411 m.put("modelIndex", Integer.valueOf(i)); 3412 minfo.addLast(m); 3413 } 3414 info.put("models", minfo); 3415 } 3416 return info; 3417 } 3418 getDihedralMap(int[] alist)3419 public int[][] getDihedralMap(int[] alist) { 3420 Lst<int[]> list = new Lst<int[]>(); 3421 int n = alist.length; 3422 Atom ai = null, aj = null, ak = null, al = null; 3423 for (int i = n - 1; --i >= 0;) 3424 for (int j = n; --j > i;) { 3425 ai = at[alist[i]]; 3426 aj = at[alist[j]]; 3427 if (ai.isBonded(aj)) { 3428 for (int k = n; --k >= 0;) 3429 if (k != i && k != j && (ak = at[alist[k]]).isBonded(ai)) 3430 for (int l = n; --l >= 0;) 3431 if (l != i && l != j && l != k 3432 && (al = at[alist[l]]).isBonded(aj)) { 3433 int[] a = new int[4]; 3434 a[0] = ak.i; 3435 a[1] = ai.i; 3436 a[2] = aj.i; 3437 a[3] = al.i; 3438 list.addLast(a); 3439 } 3440 } 3441 } 3442 n = list.size(); 3443 int[][] ilist = AU.newInt2(n); 3444 for (int i = n; --i >= 0;) 3445 ilist[n - i - 1] = list.get(i); 3446 return ilist; 3447 } 3448 3449 /** 3450 * Sets the modulation for all atoms in bs. 3451 * 3452 * @param bs 3453 * @param isOn 3454 * @param qtOffset 3455 * multiples of q or just t. 3456 * @param isQ 3457 * true if multiples of q. 3458 * 3459 * 3460 */ setModulation(BS bs, boolean isOn, P3 qtOffset, boolean isQ)3461 public void setModulation(BS bs, boolean isOn, P3 qtOffset, boolean isQ) { 3462 if (bsModulated == null) { 3463 if (isOn) 3464 bsModulated = new BS(); 3465 else if (bs == null) 3466 return; 3467 } 3468 if (bs == null) 3469 bs = getModelAtomBitSetIncludingDeleted(-1, false); 3470 float scale = vwr.getFloat(T.modulation); 3471 boolean haveMods = false; 3472 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 3473 JmolModulationSet ms = getModulation(i); 3474 if (ms == null) 3475 continue; 3476 ms.setModTQ(at[i], isOn, qtOffset, isQ, scale); 3477 if (bsModulated != null) 3478 bsModulated.setBitTo(i, isOn); 3479 haveMods = true; 3480 } 3481 if (!haveMods) 3482 bsModulated = null; 3483 } 3484 3485 /** 3486 * 3487 * @param type 3488 * volume, best, x, y, z, unitcell 3489 * @param bsAtoms 3490 * @return quaternion for best rotation or, for volume, string with volume 3491 * \t{dx dy dz} 3492 */ getBoundBoxOrientation(int type, BS bsAtoms)3493 public Object getBoundBoxOrientation(int type, BS bsAtoms) { 3494 float dx = 0, dy = 0, dz = 0; 3495 Quat q = null, qBest = null; 3496 int j0 = bsAtoms.nextSetBit(0); 3497 float vMin = 0; 3498 if (j0 >= 0) { 3499 int n = (vOrientations == null ? 0 : vOrientations.length); 3500 if (n == 0) { 3501 V3[] av = new V3[15 * 15 * 15]; 3502 n = 0; 3503 P4 p4 = new P4(); 3504 for (int i = -7; i <= 7; i++) 3505 for (int j = -7; j <= 7; j++) 3506 for (int k = 0; k <= 14; k++, n++) 3507 if ((av[n] = V3.new3(i / 7f, j / 7f, k / 14f)).length() > 1) 3508 --n; 3509 vOrientations = new Quat[n]; 3510 for (int i = n; --i >= 0;) { 3511 float cos = (float) Math.sqrt(1 - av[i].lengthSquared()); 3512 if (Float.isNaN(cos)) 3513 cos = 0; 3514 p4.set4(av[i].x, av[i].y, av[i].z, cos); 3515 vOrientations[i] = Quat.newP4(p4); 3516 } 3517 } 3518 P3 pt = new P3(); 3519 vMin = Float.MAX_VALUE; 3520 BoxInfo bBest = null; 3521 float v; 3522 BoxInfo b = new BoxInfo(); 3523 b.setMargin(type == T.volume ? 0 : 0.1f); 3524 for (int i = 0; i < n; i++) { 3525 q = vOrientations[i]; 3526 b.reset(); 3527 for (int j = j0; j >= 0; j = bsAtoms.nextSetBit(j + 1)) 3528 b.addBoundBoxPoint(q.transform2(at[j], pt)); 3529 switch (type) { 3530 default: 3531 case T.volume: 3532 case T.best: 3533 case T.unitcell: 3534 v = (b.bbCorner1.x - b.bbCorner0.x) * (b.bbCorner1.y - b.bbCorner0.y) 3535 * (b.bbCorner1.z - b.bbCorner0.z); 3536 break; 3537 case T.x: 3538 v = b.bbCorner1.x - b.bbCorner0.x; 3539 break; 3540 case T.y: 3541 v = b.bbCorner1.y - b.bbCorner0.y; 3542 break; 3543 case T.z: 3544 v = b.bbCorner1.z - b.bbCorner0.z; 3545 break; 3546 } 3547 if (v < vMin) { 3548 qBest = q; 3549 bBest = b; 3550 b = new BoxInfo(); 3551 b.setMargin(0.1f); 3552 vMin = v; 3553 } 3554 } 3555 switch (type) { 3556 default: 3557 return qBest; 3558 case T.unitcell: 3559 P3[] pts = bBest.getBoundBoxVertices(); 3560 pts = new P3[] {pts[0], pts[BoxInfo.X], pts[BoxInfo.Y], pts[BoxInfo.Z]}; 3561 qBest = qBest.inv(); 3562 for (int i = 0; i < 4; i++) { 3563 qBest.transform2(pts[i], pts[i]); 3564 if (i > 0) 3565 pts[i].sub(pts[0]); 3566 } 3567 return pts; 3568 case T.volume: 3569 case T.best: 3570 // we want dz < dy < dx 3571 q = Quat.newQ(qBest); 3572 dx = bBest.bbCorner1.x - bBest.bbCorner0.x; 3573 dy = bBest.bbCorner1.y - bBest.bbCorner0.y; 3574 dz = bBest.bbCorner1.z - bBest.bbCorner0.z; 3575 if (dx < dy) { 3576 pt.set(0, 0, 1); 3577 q = Quat.newVA(pt, 90).mulQ(q); 3578 float f = dx; 3579 dx = dy; 3580 dy = f; 3581 } 3582 if (dy < dz) { 3583 if (dz > dx) { 3584 // is dy < dx < dz 3585 pt.set(0, 1, 0); 3586 q = Quat.newVA(pt, 90).mulQ(q); 3587 float f = dx; 3588 dx = dz; 3589 dz = f; 3590 } 3591 // is dy < dz < dx 3592 pt.set(1, 0, 0); 3593 q = Quat.newVA(pt, 90).mulQ(q); 3594 float f = dy; 3595 dy = dz; 3596 dz = f; 3597 } 3598 break; 3599 } 3600 } 3601 return (type == T.volume ? vMin + "\t{" + dx + " " + dy + " " + dz + "}\t" + bsAtoms 3602 : type == T.unitcell ? null : q == null || q.getTheta() == 0 ? new Quat() : q); 3603 } 3604 getUnitCellForAtom(int index)3605 public SymmetryInterface getUnitCellForAtom(int index) { 3606 if (index < 0 || index > ac) 3607 return null; 3608 if (bsModulated != null) { 3609 JmolModulationSet ms = getModulation(index); 3610 SymmetryInterface uc = (ms == null ? null : ms.getSubSystemUnitCell()); 3611 if (uc != null) 3612 return uc; // subsystems 3613 } 3614 return getUnitCell(at[index].mi); 3615 } 3616 clearCache()3617 public void clearCache() { 3618 for (int i = mc; --i >= 0;) 3619 am[i].resetDSSR(false); 3620 } 3621 getSymMatrices(int modelIndex)3622 public M4[] getSymMatrices(int modelIndex) { 3623 int n = getModelSymmetryCount(modelIndex); 3624 if (n == 0) 3625 return null; 3626 M4[] ops = new M4[n]; 3627 SymmetryInterface unitcell = am[modelIndex].biosymmetry; 3628 if (unitcell == null) 3629 unitcell = getUnitCell(modelIndex); 3630 for (int i = n; --i >= 0;) 3631 ops[i] = unitcell.getSpaceGroupOperation(i); 3632 return ops; 3633 } 3634 getBsBranches(float[] dihedralList)3635 public BS[] getBsBranches(float[] dihedralList) { 3636 int n = dihedralList.length / 6; 3637 BS[] bsBranches = new BS[n]; 3638 Map<String, Boolean> map = new Hashtable<String, Boolean>(); 3639 for (int i = 0, pt = 0; i < n; i++, pt += 6) { 3640 float dv = dihedralList[pt + 5] - dihedralList[pt + 4]; 3641 if (Math.abs(dv) < 1f) 3642 continue; 3643 int i0 = (int) dihedralList[pt + 1]; 3644 int i1 = (int) dihedralList[pt + 2]; 3645 String s = "" + i0 + "_" + i1; 3646 if (map.containsKey(s)) 3647 continue; 3648 map.put(s, Boolean.TRUE); 3649 BS bs = vwr.getBranchBitSet(i1, i0, true); 3650 Bond[] bonds = at[i0].bonds; 3651 Atom a0 = at[i0]; 3652 for (int j = 0; j < bonds.length; j++) { 3653 Bond b = bonds[j]; 3654 if (!b.isCovalent()) 3655 continue; 3656 int i2 = b.getOtherAtom(a0).i; 3657 if (i2 == i1) 3658 continue; 3659 if (bs.get(i2)) { 3660 bs = null; 3661 break; 3662 } 3663 } 3664 bsBranches[i] = bs; 3665 } 3666 return bsBranches; 3667 } 3668 recalculatePositionDependentQuantities(BS bs, M4 mat)3669 public void recalculatePositionDependentQuantities(BS bs, M4 mat) { 3670 if ((vwr.shm.getShape(JC.SHAPE_POLYHEDRA) != null)) 3671 vwr.shm.getShapePropertyData(JC.SHAPE_POLYHEDRA, "move", new Object[] { 3672 bs, mat }); 3673 if (haveStraightness) 3674 calculateStraightnessAll(); 3675 recalculateLeadMidpointsAndWingVectors(-1); 3676 BS bsModels = getModelBS(bs, false); 3677 for (int i = bsModels.nextSetBit(0); i >= 0; i = bsModels.nextSetBit(i + 1)) { 3678 sm.notifyAtomPositionsChanged(i, bs, mat); 3679 if (mat != null) { 3680 Model m = am[i]; 3681 if (m.isContainedIn(bs)) { 3682 if (m.mat4 == null) 3683 m.mat4 = M4.newM4(null); 3684 m.mat4.mul2(mat, m.mat4); 3685 } 3686 } 3687 } 3688 //averageAtomPoint = null; 3689 /* but we would need to somehow indicate this in the state 3690 if (ellipsoids != null) 3691 for (int i = bs.nextSetBit(0); i >= 0 && i < ellipsoids.length; i = bs.nextSetBit(i + 1)) 3692 ellipsoids[i].rotate(mat); 3693 if (vibrationVectors != null) 3694 for (int i = bs.nextSetBit(0); i >= 0 && i < vibrationVectors.length; i = bs.nextSetBit(i + 1)) 3695 if (vibrationVectors[i] != null) 3696 mat.transform(vibrationVectors[i]); 3697 */ 3698 } 3699 moveAtoms(M4 m4, M3 mNew, M3 rotation, V3 translation, BS bs, P3 center, boolean isInternal, boolean translationOnly)3700 public void moveAtoms(M4 m4, M3 mNew, M3 rotation, V3 translation, BS bs, 3701 P3 center, boolean isInternal, boolean translationOnly) { 3702 if (m4 != null) { 3703 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 3704 m4.rotTrans(at[i]); 3705 taintAtom(i, TAINT_COORD); 3706 } 3707 mat4.setM4(m4); 3708 translation = null; 3709 } else if (!translationOnly) { 3710 if (mNew == null) { 3711 matTemp.setM3(rotation); 3712 } else { 3713 // screen frame? 3714 // must do inv(currentRot) * mNew * currentRot 3715 ptTemp.set(0, 0, 0); 3716 matInv.setM3(rotation); 3717 matInv.invert(); 3718 matTemp.mul2(mNew, rotation); 3719 matTemp.mul2(matInv, matTemp); 3720 } 3721 if (isInternal) { 3722 // adjust rotation to be around center of this set of atoms 3723 vTemp.setT(center); 3724 mat4.setIdentity(); 3725 mat4.setTranslation(vTemp); 3726 mat4t.setToM3(matTemp); 3727 mat4.mul(mat4t); 3728 mat4t.setIdentity(); 3729 vTemp.scale(-1); 3730 mat4t.setTranslation(vTemp); 3731 mat4.mul(mat4t); 3732 } else { 3733 mat4.setToM3(matTemp); 3734 } 3735 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 3736 if (isInternal) { 3737 mat4.rotTrans(at[i]); 3738 } else { 3739 ptTemp.add(at[i]); 3740 mat4.rotTrans(at[i]); 3741 ptTemp.sub(at[i]); 3742 } 3743 taintAtom(i, TAINT_COORD); 3744 } 3745 if (!isInternal) { 3746 ptTemp.scale(1f / bs.cardinality()); 3747 if (translation == null) 3748 translation = new V3(); 3749 translation.add(ptTemp); 3750 } 3751 } 3752 if (translation != null) { 3753 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 3754 at[i].add(translation); 3755 taintAtom(i, TAINT_COORD); 3756 } 3757 if (!translationOnly) { 3758 mat4t.setIdentity(); 3759 mat4t.setTranslation(translation); 3760 mat4.mul2(mat4t, mat4); 3761 } 3762 } 3763 recalculatePositionDependentQuantities(bs, mat4); 3764 } 3765 setDihedrals(float[] dihedralList, BS[] bsBranches, float f)3766 public void setDihedrals(float[] dihedralList, BS[] bsBranches, float f) { 3767 int n = dihedralList.length / 6; 3768 if (f > 1) 3769 f = 1; 3770 for (int j = 0, pt = 0; j < n; j++, pt += 6) { 3771 BS bs = bsBranches[j]; 3772 if (bs == null || bs.isEmpty()) 3773 continue; 3774 Atom a1 = at[(int) dihedralList[pt + 1]]; 3775 V3 v = V3.newVsub(at[(int) dihedralList[pt + 2]], a1); 3776 float angle = (dihedralList[pt + 5] - dihedralList[pt + 4]) * f; 3777 A4 aa = A4.newVA(v, (float) (-angle / TransformManager.degreesPerRadian)); 3778 matTemp.setAA(aa); 3779 ptTemp.setT(a1); 3780 for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { 3781 at[i].sub(ptTemp); 3782 matTemp.rotate(at[i]); 3783 at[i].add(ptTemp); 3784 taintAtom(i, TAINT_COORD); 3785 } 3786 } 3787 } 3788 setAtomCoordsRelative(T3 offset, BS bs)3789 public void setAtomCoordsRelative(T3 offset, BS bs) { 3790 setAtomsCoordRelative(bs, offset.x, offset.y, offset.z); 3791 mat4.setIdentity(); 3792 vTemp.setT(offset); 3793 mat4.setTranslation(vTemp); 3794 recalculatePositionDependentQuantities(bs, mat4); 3795 } 3796 setAtomCoords(BS bs, int tokType, Object xyzValues)3797 public void setAtomCoords(BS bs, int tokType, Object xyzValues) { 3798 setAtomCoord2(bs, tokType, xyzValues); 3799 switch (tokType) { 3800 case T.vibx: 3801 case T.viby: 3802 case T.vibz: 3803 case T.vibxyz: 3804 break; 3805 default: 3806 recalculatePositionDependentQuantities(bs, null); 3807 } 3808 } 3809 3810 /** 3811 * Carries out a stereochemical inversion through a point, across a plane, or at a chirality center. 3812 * 3813 * @param pt point to invert around if not null 3814 * @param plane plane to invert across if not null 3815 * @param iAtom atom to switch two groups on if >= 0 3816 * @param bsAtoms atoms to switch for the atom option 3817 */ invertSelected(P3 pt, P4 plane, int iAtom, BS bsAtoms)3818 public void invertSelected(P3 pt, P4 plane, int iAtom, BS bsAtoms) { 3819 resetChirality(); 3820 if (pt != null) { 3821 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) { 3822 float x = (pt.x - at[i].x) * 2; 3823 float y = (pt.y - at[i].y) * 2; 3824 float z = (pt.z - at[i].z) * 2; 3825 setAtomCoordRelative(i, x, y, z); 3826 } 3827 return; 3828 } 3829 if (plane != null) { 3830 // ax + by + cz + d = 0 3831 V3 norm = V3.new3(plane.x, plane.y, plane.z); 3832 norm.normalize(); 3833 float d = (float) Math.sqrt(plane.x * plane.x + plane.y * plane.y 3834 + plane.z * plane.z); 3835 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) { 3836 float twoD = -Measure.distanceToPlaneD(plane, d, at[i]) * 2; 3837 float x = norm.x * twoD; 3838 float y = norm.y * twoD; 3839 float z = norm.z * twoD; 3840 setAtomCoordRelative(i, x, y, z); 3841 } 3842 return; 3843 } 3844 if (iAtom >= 0) { 3845 Atom thisAtom = at[iAtom]; 3846 // stereochemical inversion at iAtom 3847 Bond[] bonds = thisAtom.bonds; 3848 if (bonds == null) 3849 return; 3850 BS bsToMove = new BS(); 3851 Lst<P3> vNot = new Lst<P3>(); 3852 BS bsModel = vwr.getModelUndeletedAtomsBitSet(thisAtom.mi); 3853 for (int i = 0; i < bonds.length; i++) { 3854 Atom a = bonds[i].getOtherAtom(thisAtom); 3855 if (bsAtoms.get(a.i)) { 3856 bsToMove.or(JmolMolecule.getBranchBitSet(at, a.i, bsModel, null, 3857 iAtom, true, true)); 3858 } else { 3859 vNot.addLast(a); 3860 } 3861 } 3862 if (vNot.size() == 0) 3863 return; 3864 pt = Measure.getCenterAndPoints(vNot)[0]; 3865 V3 v = V3.newVsub(thisAtom, pt); 3866 Quat q = Quat.newVA(v, 180); 3867 moveAtoms(null, null, q.getMatrix(), null, bsToMove, thisAtom, true, false); 3868 } 3869 } 3870 getCellWeights(BS bsAtoms)3871 public float[] getCellWeights(BS bsAtoms) { 3872 float[] wts = null; 3873 int i = bsAtoms.nextSetBit(0); 3874 int iModel = -1; 3875 if (i >= 0 && getUnitCell(iModel = at[i].mi) != null) { 3876 P3 pt = new P3(); 3877 BS bs = getModelAtomBitSetIncludingDeleted(iModel, true); 3878 bs.and(bsAtoms); 3879 wts = new float[bsAtoms.cardinality()]; 3880 for (int p = 0; i >= 0; i = bsAtoms.nextSetBit(i + 1)) 3881 wts[p++] = SimpleUnitCell.getCellWeight(at[i].getFractionalUnitCoordPt( 3882 true, false, pt)); 3883 } 3884 return wts; 3885 } 3886 getAtomGroupQuaternions(BS bsAtoms, int nMax, char qtype)3887 public Quat[] getAtomGroupQuaternions(BS bsAtoms, int nMax, char qtype) { 3888 // run through list, getting quaternions. For simple groups, 3889 // go ahead and take first three atoms 3890 // for PDB files, do not include NON-protein groups. 3891 int n = 0; 3892 Lst<Quat> v = new Lst<Quat>(); 3893 bsAtoms = BSUtil.copy(bsAtoms); 3894 BS bsDone = new BS(); 3895 for (int i = bsAtoms.nextSetBit(0); i >= 0 && n < nMax; i = bsAtoms 3896 .nextSetBit(i + 1)) { 3897 Group g = at[i].group; 3898 g.setAtomBits(bsDone); 3899 bsAtoms.andNot(bsDone); 3900 Quat q = g.getQuaternion(qtype); 3901 if (q == null) { 3902 if (!am[at[i].mi].isBioModel) 3903 q = g.getQuaternionFrame(at); // non-PDB just use first three atoms 3904 if (q == null) 3905 continue; 3906 } 3907 n++; 3908 v.addLast(q); 3909 } 3910 return v.toArray(new Quat[v.size()]); 3911 } 3912 getConformation(int modelIndex, int conformationIndex, boolean doSet, BS bsSelected)3913 public BS getConformation(int modelIndex, int conformationIndex, 3914 boolean doSet, BS bsSelected) { 3915 BS bs = new BS(); 3916 if (conformationIndex >= 0) 3917 for (int i = mc; --i >= 0;) { 3918 if (i != modelIndex && modelIndex >= 0) 3919 continue; 3920 Model m = am[i]; 3921 BS bsAtoms = vwr.getModelUndeletedAtomsBitSet(modelIndex); 3922 if (bsSelected != null) 3923 bsAtoms.and(bsSelected); 3924 if (bsAtoms.nextSetBit(0) < 0) 3925 continue; 3926 if (conformationIndex >= m.altLocCount) { 3927 if (conformationIndex == 0) 3928 bs.or(bsAtoms); 3929 continue; 3930 } 3931 if (am[i].isBioModel 3932 && ((BioModel) am[i]).getConformation(conformationIndex, doSet, 3933 bsAtoms, bs)) 3934 continue; 3935 int nAltLocs = getAltLocCountInModel(i); 3936 String altLocs = getAltLocListInModel(i); 3937 BS bsTemp = new BS(); 3938 for (int c = nAltLocs; --c >= 0;) 3939 if (c != conformationIndex) 3940 bsAtoms.andNot(getAtomBitsMDa(T.spec_alternate, 3941 altLocs.substring(c, c + 1), bsTemp)); 3942 if (bsAtoms.nextSetBit(0) >= 0) 3943 bs.or(bsAtoms); 3944 } 3945 return bs; 3946 } 3947 3948 ///// bio-only methods ///// 3949 getSequenceBits(String specInfo, BS bsAtoms, BS bsResult)3950 public BS getSequenceBits(String specInfo, BS bsAtoms, BS bsResult) { 3951 return (haveBioModels ? bioModelset.getAllSequenceBits(specInfo, bsAtoms, bsResult) 3952 : bsResult); 3953 } 3954 getBioPolymerCountInModel(int modelIndex)3955 public int getBioPolymerCountInModel(int modelIndex) { 3956 return (haveBioModels ? bioModelset.getBioPolymerCountInModel(modelIndex) 3957 : 0); 3958 } 3959 getPolymerPointsAndVectors(BS bs, Lst<P3[]> vList, boolean isTraceAlpha, float sheetSmoothing)3960 public void getPolymerPointsAndVectors(BS bs, Lst<P3[]> vList, 3961 boolean isTraceAlpha, 3962 float sheetSmoothing) { 3963 if (haveBioModels) 3964 bioModelset.getAllPolymerPointsAndVectors(bs, vList, isTraceAlpha, 3965 sheetSmoothing); 3966 } 3967 recalculateLeadMidpointsAndWingVectors(int modelIndex)3968 public void recalculateLeadMidpointsAndWingVectors(int modelIndex) { 3969 if (haveBioModels) 3970 bioModelset.recalculatePoints(modelIndex); 3971 } 3972 3973 /** 3974 * These are not actual hydrogen bonds. They are N-O bonds in proteins and 3975 * nucleic acids The method is called by AminoPolymer and NucleicPolymer 3976 * methods, which are indirectly called by ModelCollection.autoHbond 3977 * 3978 * @param bsA 3979 * @param bsB 3980 * @param vHBonds 3981 * vector of bonds to fill; if null, creates the HBonds 3982 * @param nucleicOnly 3983 * @param nMax 3984 * @param dsspIgnoreHydrogens 3985 * @param bsHBonds 3986 */ 3987 calcRasmolHydrogenBonds(BS bsA, BS bsB, Lst<Bond> vHBonds, boolean nucleicOnly, int nMax, boolean dsspIgnoreHydrogens, BS bsHBonds)3988 public void calcRasmolHydrogenBonds(BS bsA, BS bsB, Lst<Bond> vHBonds, 3989 boolean nucleicOnly, int nMax, 3990 boolean dsspIgnoreHydrogens, BS bsHBonds) { 3991 if (haveBioModels) 3992 bioModelset.calcAllRasmolHydrogenBonds(bsA, bsB, vHBonds, nucleicOnly, 3993 nMax, dsspIgnoreHydrogens, bsHBonds, 2); // DSSP version 2 here 3994 } 3995 calculateStraightnessAll()3996 public void calculateStraightnessAll() { 3997 if (haveBioModels && !haveStraightness) 3998 bioModelset.calculateStraightnessAll(); 3999 } 4000 4001 /** 4002 * see comments in org.jmol.modelsetbio.AlphaPolymer.java 4003 * 4004 * Struts are calculated for atoms in bs1 connecting to atoms in bs2. The two 4005 * bitsets may overlap. 4006 * 4007 * @param bs1 4008 * @param bs2 4009 * @return number of struts found 4010 */ calculateStruts(BS bs1, BS bs2)4011 public int calculateStruts(BS bs1, BS bs2) { 4012 return (haveBioModels ? bioModelset.calculateStruts(bs1, bs2) : 0); 4013 } 4014 getGroupsWithin(int nResidues, BS bs)4015 public BS getGroupsWithin(int nResidues, BS bs) { 4016 return (haveBioModels ? bioModelset.getGroupsWithinAll(nResidues, bs) 4017 : new BS()); 4018 } 4019 getProteinStructureState(BS bsAtoms, int mode)4020 public String getProteinStructureState(BS bsAtoms, int mode) { 4021 return (haveBioModels ? bioModelset.getFullProteinStructureState(bsAtoms, 4022 mode) : ""); 4023 } 4024 calculateStructures(BS bsAtoms, boolean asDSSP, boolean doReport, boolean dsspIgnoreHydrogen, boolean setStructure, int version)4025 public String calculateStructures(BS bsAtoms, boolean asDSSP, 4026 boolean doReport, 4027 boolean dsspIgnoreHydrogen, 4028 boolean setStructure, int version) { 4029 return (haveBioModels ? bioModelset.calculateAllStuctures(bsAtoms, asDSSP, 4030 doReport, dsspIgnoreHydrogen, setStructure, version) : ""); 4031 } 4032 4033 /** 4034 * allows rebuilding of PDB structures; also accessed by ModelManager from 4035 * Eval 4036 * 4037 * @param alreadyDefined 4038 * set to skip calculation 4039 * @param asDSSP 4040 * @param doReport 4041 * @param dsspIgnoreHydrogen 4042 * @param setStructure 4043 * @param includeAlpha 4044 * @param version TODO 4045 * @return report 4046 * 4047 */ calculateStructuresAllExcept(BS alreadyDefined, boolean asDSSP, boolean doReport, boolean dsspIgnoreHydrogen, boolean setStructure, boolean includeAlpha, int version)4048 public String calculateStructuresAllExcept(BS alreadyDefined, boolean asDSSP, 4049 boolean doReport, 4050 boolean dsspIgnoreHydrogen, 4051 boolean setStructure, 4052 boolean includeAlpha, int version) { 4053 freezeModels(); 4054 return (haveBioModels ? bioModelset.calculateAllStructuresExcept( 4055 alreadyDefined, asDSSP, doReport, dsspIgnoreHydrogen, setStructure, 4056 includeAlpha, version) : ""); 4057 } 4058 recalculatePolymers(BS bsModelsExcluded)4059 public void recalculatePolymers(BS bsModelsExcluded) { 4060 bioModelset.recalculateAllPolymers(bsModelsExcluded, getGroups()); 4061 } 4062 calculatePolymers(Group[] groups, int groupCount, int baseGroupIndex, BS modelsExcluded)4063 protected void calculatePolymers(Group[] groups, int groupCount, 4064 int baseGroupIndex, BS modelsExcluded) { 4065 if (bioModelset != null) // not using haveBioModels because not frozen yet 4066 bioModelset.calculateAllPolymers(groups, groupCount, baseGroupIndex, 4067 modelsExcluded); 4068 } 4069 calcSelectedMonomersCount()4070 public void calcSelectedMonomersCount() { 4071 if (haveBioModels) 4072 bioModelset.calcSelectedMonomersCount(); 4073 } 4074 setProteinType(BS bs, STR type)4075 public void setProteinType(BS bs, STR type) { 4076 if (haveBioModels) 4077 bioModelset.setAllProteinType(bs, type); 4078 } 4079 setStructureList(Map<STR, float[]> structureList)4080 public void setStructureList(Map<STR, float[]> structureList) { 4081 if (haveBioModels) 4082 bioModelset.setAllStructureList(structureList); 4083 } 4084 setConformation(BS bsAtoms)4085 public BS setConformation(BS bsAtoms) { 4086 if (haveBioModels) 4087 bioModelset.setAllConformation(bsAtoms); 4088 return bsAtoms; 4089 } 4090 4091 @SuppressWarnings("unchecked") getHeteroList(int modelIndex)4092 public Map<String, String> getHeteroList(int modelIndex) { 4093 Object o = (haveBioModels ? bioModelset.getAllHeteroList(modelIndex) : null); 4094 return (Map<String, String>) (o == null ? getInfoM("hetNames") : o); 4095 } 4096 getUnitCellPointsWithin(float distance, BS bs, P3 pt, boolean asMap)4097 public Object getUnitCellPointsWithin(float distance, BS bs, P3 pt, 4098 boolean asMap) { 4099 Lst<P3> lst = new Lst<P3>(); 4100 Map<String, Object> map = null; 4101 Lst<Integer> lstI = null; 4102 if (asMap) { 4103 map = new Hashtable<String, Object>(); 4104 lstI = new Lst<Integer>(); 4105 map.put("atoms", lstI); 4106 map.put("points", lst); 4107 } 4108 int iAtom = (bs == null ? -1 : bs.nextSetBit(0)); 4109 bs = vwr 4110 .getModelUndeletedAtomsBitSet(iAtom < 0 ? vwr.am.cmi : at[iAtom].mi); 4111 if (iAtom < 0) 4112 iAtom = bs.nextSetBit(0); 4113 if (iAtom >= 0) { 4114 SymmetryInterface unitCell = getUnitCellForAtom(iAtom); 4115 if (unitCell != null) { 4116 AtomIndexIterator iter = unitCell.getIterator(vwr, at[iAtom], at, bs, 4117 distance); 4118 if (pt != null) 4119 iter.setCenter(pt, distance); 4120 while (iter.hasNext()) { 4121 iAtom = iter.next(); 4122 pt = iter.getPosition(); 4123 lst.addLast(pt); 4124 if (asMap) { 4125 lstI.addLast(Integer.valueOf(iAtom)); 4126 } 4127 } 4128 } 4129 } 4130 return (asMap ? map : lst); 4131 } 4132 calculateDssrProperty(String dataType)4133 public void calculateDssrProperty(String dataType) { 4134 if (dataType == null) 4135 return; 4136 if (dssrData == null || dssrData.length < ac) 4137 dssrData = new float[ac]; 4138 for (int i = 0; i < ac; i++) 4139 dssrData[i] = Float.NaN; 4140 for (int i = mc; --i >= 0;) 4141 if (am[i].isBioModel) 4142 ((BioModel) am[i]).getAtomicDSSRData(dssrData, dataType); 4143 } 4144 getAtomicDSSRData(int i)4145 public float getAtomicDSSRData(int i) { 4146 return (dssrData == null || dssrData.length <= i ? Float.NaN : dssrData[i]); 4147 } 4148 4149 /** 4150 * Determine the Cahn-Ingold-Prelog R/S chirality of an atom 4151 * 4152 * @param atom 4153 * @return [0:none, 1:R, 2:S] 4154 */ getAtomCIPChiralityCode(Atom atom)4155 public int getAtomCIPChiralityCode(Atom atom) { 4156 haveChirality = true; 4157 Model m = am[atom.mi]; 4158 if (!m.hasChirality) { 4159 calculateChiralityForAtoms(m.bsAtoms, false); 4160 m.hasChirality = true; 4161 } 4162 return atom.getCIPChiralityCode(); 4163 } 4164 calculateChiralityForAtoms(BS bsAtoms, boolean withReturn)4165 public String calculateChiralityForAtoms(BS bsAtoms, boolean withReturn) { 4166 haveChirality = true; 4167 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) 4168 at[i].setCIPChirality(0); 4169 Interface.getSymmetry(vwr, "ms").calculateCIPChiralityForAtoms(vwr, bsAtoms); 4170 if (!withReturn) 4171 return null; 4172 String s = ""; 4173 for (int i = bsAtoms.nextSetBit(0); i >= 0; i = bsAtoms.nextSetBit(i + 1)) 4174 s += at[i].getCIPChirality(false); 4175 return s; 4176 } 4177 4178 } 4179 4180