1 /* $RCSfile$ 2 * $Author: hansonr $ 3 * $Date: 2007-03-30 11:40:16 -0500 (Fri, 30 Mar 2007) $ 4 * $Revision: 7273 $ 5 * 6 * Copyright (C) 2007 Miguel, Bob, Jmol Development 7 * 8 * Contact: hansonr@stolaf.edu 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 23 */ 24 package org.jmol.jvxl.readers; 25 26 import java.util.Date; 27 28 import javajs.util.AU; 29 import javajs.util.M4; 30 import javajs.util.P3; 31 import javajs.util.P3i; 32 import javajs.util.SB; 33 import javajs.util.T3; 34 import javajs.util.V3; 35 36 import org.jmol.atomdata.AtomData; 37 import org.jmol.atomdata.RadiusData; 38 import org.jmol.atomdata.RadiusData.EnumType; 39 import org.jmol.c.VDW; 40 import javajs.util.BS; 41 import org.jmol.jvxl.data.JvxlCoder; 42 import org.jmol.jvxl.data.MeshData; 43 import org.jmol.util.BSUtil; 44 import org.jmol.util.ContactPair; 45 import org.jmol.util.Logger; 46 47 abstract class AtomDataReader extends VolumeDataReader { 48 49 protected float maxDistance; 50 protected ContactPair contactPair; 51 AtomDataReader()52 AtomDataReader() { 53 } 54 initADR(SurfaceGenerator sg)55 protected void initADR(SurfaceGenerator sg) { 56 initVDR(sg); 57 precalculateVoxelData = true; 58 } 59 60 protected String fileName; 61 protected String fileDotModel; 62 protected int modelIndex; 63 64 protected AtomData atomData = new AtomData(); 65 66 protected P3[] atomXyzTruncated; 67 protected float[] atomRadius; 68 protected float[] atomProp; 69 protected int[] atomNo; 70 protected int[] atomIndex; 71 protected int[] myIndex; 72 protected int ac; 73 protected int myAtomCount; 74 protected int nearbyAtomCount; 75 protected int firstNearbyAtom; 76 protected BS bsMySelected = new BS(); 77 protected BS bsMyIgnored = new BS(); 78 protected BS bsNearby; 79 80 protected boolean doAddHydrogens; 81 protected boolean havePlane; 82 protected boolean doUseIterator; 83 protected float theProperty; 84 protected boolean haveOneProperty; 85 private float minPtsPerAng; 86 87 /** 88 * @param isMapData 89 */ 90 @Override setup(boolean isMapData)91 protected void setup(boolean isMapData) { 92 setup2(); 93 } 94 setup2()95 protected void setup2() { 96 //CANNOT BE IN HERE IF atomDataServer is not valid 97 contactPair = params.contactPair; 98 doAddHydrogens = (sg.atomDataServer != null && params.addHydrogens); //Jvxl cannot do this on its own 99 modelIndex = params.modelIndex; 100 if (params.bsIgnore != null) 101 bsMyIgnored = params.bsIgnore; 102 if (params.volumeData != null) { 103 setVolumeDataV(params.volumeData); 104 setBBox(volumeData.volumetricOrigin, 0); 105 ptV.setT(volumeData.volumetricOrigin); 106 for (int i = 0; i < 3; i++) 107 ptV.scaleAdd2(volumeData.voxelCounts[i] - 1, 108 volumeData.volumetricVectors[i], ptV); 109 setBBox(ptV, 0); 110 } 111 havePlane = (params.thePlane != null); 112 if (havePlane) 113 volumeData.setPlaneParameters(params.thePlane); 114 } 115 markPlaneVoxels(P3 p, float r)116 protected void markPlaneVoxels(P3 p, float r) { 117 for (int i = 0, pt = thisX * yzCount, pt1 = pt + yzCount; pt < pt1; pt++, i++) { 118 volumeData.getPoint(pt, ptV); 119 thisPlane[i] = ptV.distance(p) - r; 120 } 121 } 122 setVolumeForPlane()123 protected void setVolumeForPlane() { 124 if (useOriginStepsPoints) { 125 xyzMin = P3.newP(params.origin); 126 xyzMax = P3.newP(params.origin); 127 xyzMax.add3((params.points.x - 1) * params.steps.x, (params.points.y - 1) 128 * params.steps.y, (params.points.z - 1) * params.steps.z); 129 } else if (params.boundingBox == null) { 130 getAtoms(params.bsSelected, false, true, false, false, false, false, 131 params.mep_marginAngstroms, params.modelInvRotation); 132 if (xyzMin == null) { 133 xyzMin = P3.new3(-10, -10, -10); 134 xyzMax = P3.new3(10, 10, 10); 135 } 136 } else { 137 xyzMin = P3.newP(params.boundingBox[0]); 138 xyzMax = P3.newP(params.boundingBox[1]); 139 } 140 setRanges(params.plane_ptsPerAngstrom, params.plane_gridMax, 0); 141 } 142 143 /** 144 * 145 * @param bsSelected 146 * @param doAddHydrogens 147 * @param getRadii 148 * @param getMolecules 149 * @param getAllModels 150 * @param addNearbyAtoms 151 * @param getAtomMinMax 152 * @param marginAtoms 153 * @param modelInvRotation 154 */ getAtoms(BS bsSelected, boolean doAddHydrogens, boolean getRadii, boolean getMolecules, boolean getAllModels, boolean addNearbyAtoms, boolean getAtomMinMax, float marginAtoms, M4 modelInvRotation)155 protected void getAtoms(BS bsSelected, boolean doAddHydrogens, 156 boolean getRadii, boolean getMolecules, 157 boolean getAllModels, boolean addNearbyAtoms, 158 boolean getAtomMinMax, float marginAtoms, M4 modelInvRotation) { 159 if (addNearbyAtoms) 160 getRadii = true; 161 // set atomRadiusData to 100% if it has not been set already 162 // if it hasn't already been set. 163 if (getRadii) { 164 if (params.atomRadiusData == null) 165 params.atomRadiusData = new RadiusData(null, 1, EnumType.FACTOR, 166 VDW.AUTO); 167 atomData.radiusData = params.atomRadiusData; 168 atomData.radiusData.valueExtended = params.solventExtendedAtomRadius; 169 if (doAddHydrogens) 170 atomData.radiusData.vdwType = VDW.NOJMOL; 171 } 172 atomData.modelIndex = modelIndex; // -1 here means fill ALL atoms; any other 173 // means "this model only" 174 atomData.bsSelected = bsSelected; 175 atomData.bsIgnored = bsMyIgnored; 176 sg.fillAtomData(atomData, AtomData.MODE_FILL_COORDS 177 | (getAllModels ? AtomData.MODE_FILL_MULTIMODEL : 0) 178 | (getMolecules ? AtomData.MODE_FILL_MOLECULES : 0) 179 | (getRadii ? AtomData.MODE_FILL_RADII : 0)); 180 if (doUseIterator) 181 atomData.bsSelected = null; 182 ac = atomData.ac; 183 modelIndex = atomData.firstModelIndex; 184 if (modelInvRotation != null) 185 atomData.transformXYZ(modelInvRotation, bsSelected); 186 boolean needRadius = false; 187 for (int i = 0; i < ac; i++) { 188 if ((bsSelected == null || bsSelected.get(i)) && (!bsMyIgnored.get(i))) { 189 if (havePlane 190 && Math.abs(volumeData.distancePointToPlane(atomData.xyz[i])) > 2 * (atomData.atomRadius[i] = getWorkingRadius( 191 i, marginAtoms))) 192 continue; 193 bsMySelected.set(i); 194 needRadius = !havePlane; 195 } 196 if (getRadii && (addNearbyAtoms || needRadius)) 197 atomData.atomRadius[i] = getWorkingRadius(i, marginAtoms); 198 } 199 200 float rH = (getRadii && doAddHydrogens ? getWorkingRadius(-1, marginAtoms) 201 : 0); 202 myAtomCount = BSUtil.cardinalityOf(bsMySelected); 203 BS atomSet = BSUtil.copy(bsMySelected); 204 int nH = 0; 205 atomProp = null; 206 theProperty = Float.MAX_VALUE; 207 haveOneProperty = false; 208 float[] props = params.theProperty; 209 if (myAtomCount > 0) { 210 P3[] hAtoms = null; 211 if (doAddHydrogens) { 212 atomData.bsSelected = atomSet; 213 sg.atomDataServer.fillAtomData(atomData, 214 AtomData.MODE_GET_ATTACHED_HYDROGENS); 215 hAtoms = new P3[nH = atomData.hydrogenAtomCount]; 216 for (int i = 0; i < atomData.hAtoms.length; i++) 217 if (atomData.hAtoms[i] != null) 218 for (int j = atomData.hAtoms[i].length; --j >= 0;) 219 hAtoms[--nH] = atomData.hAtoms[i][j]; 220 nH = hAtoms.length; 221 Logger.info(nH + " attached hydrogens added"); 222 } 223 int n = nH + myAtomCount; 224 if (getRadii) 225 atomRadius = new float[n]; 226 atomXyzTruncated = new P3[n]; 227 if (params.theProperty != null) 228 atomProp = new float[n]; 229 atomNo = new int[n]; 230 atomIndex = new int[n]; 231 myIndex = new int[ac]; 232 233 for (int i = 0; i < nH; i++) { 234 if (getRadii) 235 atomRadius[i] = rH; 236 atomXyzTruncated[i] = hAtoms[i]; 237 atomNo[i] = -1; 238 if (atomProp != null) 239 addAtomProp(i, Float.NaN); 240 // if (params.logMessages) 241 // Logger.debug("draw {" + hAtoms[i].x + " " + hAtoms[i].y + " " 242 // + hAtoms[i].z + "};"); 243 } 244 myAtomCount = nH; 245 for (int i = atomSet.nextSetBit(0); i >= 0; i = atomSet.nextSetBit(i + 1)) { 246 if (atomProp != null) 247 addAtomProp(myAtomCount, 248 (props != null && i < props.length ? props[i] : Float.NaN)); 249 atomXyzTruncated[myAtomCount] = atomData.xyz[i]; 250 atomNo[myAtomCount] = atomData.atomicNumber[i]; 251 atomIndex[myAtomCount] = i; 252 myIndex[i] = myAtomCount; 253 if (getRadii) 254 atomRadius[myAtomCount] = atomData.atomRadius[i]; 255 myAtomCount++; 256 } 257 } 258 firstNearbyAtom = myAtomCount; 259 if (!isQuiet) 260 Logger.info(myAtomCount + " atoms will be used in the surface calculation"); 261 262 if (myAtomCount == 0) { 263 setBBox(P3.new3(10, 10, 10), 0); 264 setBBox(P3.new3(-10, -10, -10), 0); 265 } 266 for (int i = 0; i < myAtomCount; i++) 267 setBBox(atomXyzTruncated[i], getRadii ? atomRadius[i] + 0.5f : 0); 268 if (!Float.isNaN(params.scale)) { 269 V3 v = V3.newVsub(xyzMax, xyzMin); 270 v.scale(0.5f); 271 xyzMin.add(v); 272 v.scale(params.scale); 273 xyzMax.add2(xyzMin, v); 274 xyzMin.sub(v); 275 } 276 277 // fragment idea 278 279 if (!addNearbyAtoms || myAtomCount == 0) 280 return; 281 P3 pt = new P3(); 282 283 bsNearby = new BS(); 284 for (int i = 0; i < ac; i++) { 285 if (atomSet.get(i) || bsMyIgnored.get(i)) 286 continue; 287 float rA = atomData.atomRadius[i]; 288 if (params.thePlane != null 289 && Math.abs(volumeData.distancePointToPlane(atomData.xyz[i])) > 2 * rA) 290 continue; 291 if (params.theProperty != null) 292 rA += maxDistance; 293 pt = atomData.xyz[i]; 294 if (pt.x + rA > xyzMin.x && pt.x - rA < xyzMax.x && pt.y + rA > xyzMin.y 295 && pt.y - rA < xyzMax.y && pt.z + rA > xyzMin.z 296 && pt.z - rA < xyzMax.z) { 297 bsNearby.set(i); 298 nearbyAtomCount++; 299 } 300 } 301 int nAtoms = myAtomCount; 302 if (nearbyAtomCount != 0) { 303 nAtoms += nearbyAtomCount; 304 atomRadius = AU.arrayCopyF(atomRadius, nAtoms); 305 atomXyzTruncated = (P3[]) AU.arrayCopyObject(atomXyzTruncated, nAtoms); 306 if (atomIndex != null) 307 atomIndex = AU.arrayCopyI(atomIndex, nAtoms); 308 309 if (props != null) 310 atomProp = AU.arrayCopyF(atomProp, nAtoms); 311 for (int i = bsNearby.nextSetBit(0); i >= 0; i = bsNearby 312 .nextSetBit(i + 1)) { 313 if (props != null) 314 addAtomProp(myAtomCount, props[i]); 315 myIndex[i] = myAtomCount; 316 atomIndex[myAtomCount] = i; 317 atomXyzTruncated[myAtomCount] = atomData.xyz[i]; 318 atomRadius[myAtomCount++] = atomData.atomRadius[i]; 319 } 320 } 321 322 if (getRadii) 323 setRadii(); 324 325 haveOneProperty = (!Float.isNaN(theProperty)); 326 } 327 328 /** 329 * solvent radius 330 */ 331 protected float sr; 332 /** 333 * atom radius + solvent radius 334 */ 335 protected float[] rs; 336 /** 337 * square of (atom radius + solvent radius) 338 */ 339 protected float[] rs2; 340 /** 341 * maximun (atom radius + solvent radius) 342 */ 343 protected float maxRS; 344 setRadii()345 protected void setRadii() { 346 if (rs != null) 347 return; 348 maxRS = 0; 349 rs = new float[myAtomCount]; 350 rs2 = new float[myAtomCount]; 351 for (int i = 0; i < myAtomCount; i++) { 352 float r = rs[i] = atomRadius[i] + sr; 353 if (r > maxRS) 354 maxRS = r; 355 rs2[i] = rs[i] * rs[i]; 356 } 357 } 358 addAtomProp(int i, float f)359 private void addAtomProp(int i, float f) { 360 atomProp[i] = f; 361 if (!Float.isNaN(theProperty)) 362 if (f != theProperty) 363 theProperty = (theProperty == Float.MAX_VALUE ? f : Float.NaN); 364 } 365 getWorkingRadius(int i, float marginAtoms)366 private float getWorkingRadius(int i, float marginAtoms) { 367 float r = (i < 0 ? atomData.hAtomRadius : atomData.atomRadius[i]); 368 return (Float.isNaN(marginAtoms) ? Math.max(r, 0.1f) : r + marginAtoms); 369 } 370 setHeader(String calcType, String line2)371 protected void setHeader(String calcType, String line2) { 372 jvxlFileHeaderBuffer = new SB(); 373 if (atomData.programInfo != null) 374 jvxlFileHeaderBuffer.append("#created by ").append(atomData.programInfo) 375 .append(" on ").append("" + new Date()).append("\n"); 376 jvxlFileHeaderBuffer.append(calcType).append("\n").append(line2) 377 .append("\n"); 378 } 379 setRanges(float ptsPerAngstrom, int maxGrid, float minPtsPerAng)380 protected void setRanges(float ptsPerAngstrom, int maxGrid, float minPtsPerAng) { 381 if (xyzMin == null) 382 return; 383 this.ptsPerAngstrom = ptsPerAngstrom; 384 this.maxGrid = maxGrid; 385 this.minPtsPerAng = minPtsPerAng; 386 setVolumeData(); 387 JvxlCoder.jvxlCreateHeader(volumeData, jvxlFileHeaderBuffer); 388 } 389 390 @Override setVolumeData()391 protected void setVolumeData() { 392 setVolumeDataADR(); 393 } 394 setVolumeDataADR()395 protected void setVolumeDataADR() { 396 if (!setVolumeDataParams()) { 397 setVoxelRange(0, xyzMin.x, xyzMax.x, ptsPerAngstrom, maxGrid, 398 minPtsPerAng); 399 setVoxelRange(1, xyzMin.y, xyzMax.y, ptsPerAngstrom, maxGrid, 400 minPtsPerAng); 401 setVoxelRange(2, xyzMin.z, xyzMax.z, ptsPerAngstrom, maxGrid, 402 minPtsPerAng); 403 } 404 } 405 setVertexSource()406 protected void setVertexSource() { 407 if (meshDataServer != null) 408 meshDataServer.fillMeshData(meshData, MeshData.MODE_GET_VERTICES, null); 409 if (params.vertexSource != null) { 410 params.vertexSource = AU.arrayCopyI(params.vertexSource, 411 meshData.vc); 412 for (int i = 0; i < meshData.vc; i++) 413 params.vertexSource[i] = Math.abs(params.vertexSource[i]) - 1; 414 } 415 } 416 resetPlane(float value)417 protected void resetPlane(float value) { 418 for (int i = 0; i < yzCount; i++) 419 thisPlane[i] = value; 420 } 421 resetVoxelData(float value)422 protected void resetVoxelData(float value) { 423 for (int x = 0; x < nPointsX; ++x) 424 for (int y = 0; y < nPointsY; ++y) 425 for (int z = 0; z < nPointsZ; ++z) 426 voxelData[x][y][z] = value; 427 } 428 429 protected float[] thisPlane; 430 protected BS thisAtomSet; 431 protected int thisX; 432 getVoxel(int i, int j, int k, int ipt)433 private float getVoxel(int i, int j, int k, int ipt) { 434 return (isProgressive ? thisPlane[ipt % yzCount] : voxelData[i][j][k]); 435 } 436 unsetVoxelData()437 protected void unsetVoxelData() { 438 unsetVoxelData2(); 439 } 440 unsetVoxelData2()441 protected void unsetVoxelData2() { 442 if (isProgressive) 443 for (int i = 0; i < yzCount; i++) { 444 if (thisPlane[i] == Float.MAX_VALUE) 445 thisPlane[i] = Float.NaN; 446 } 447 else 448 for (int x = 0; x < nPointsX; ++x) 449 for (int y = 0; y < nPointsY; ++y) 450 for (int z = 0; z < nPointsZ; ++z) 451 if (voxelData[x][y][z] == Float.MAX_VALUE) 452 voxelData[x][y][z] = Float.NaN; 453 } 454 455 protected float margin; 456 protected float vl0, vl1, vl2; 457 setGridLimitsForAtom(P3 ptA, float rA, P3i pt0, P3i pt1)458 protected void setGridLimitsForAtom(P3 ptA, float rA, P3i pt0, P3i pt1) { 459 rA += margin; // to span corner-to-corner possibility 460 volumeData.xyzToVoxelPt(ptA.x, ptA.y, ptA.z, pt0); 461 int x = (int) Math.floor(rA / volumeData.volumetricVectorLengths[0]); 462 int y = (int) Math.floor(rA / volumeData.volumetricVectorLengths[1]); 463 int z = (int) Math.floor(rA / volumeData.volumetricVectorLengths[2]); 464 pt1.set(pt0.x + x, pt0.y + y, pt0.z + z); 465 pt0.set(pt0.x - x, pt0.y - y, pt0.z - z); 466 pt0.x = Math.max(pt0.x - 1, 0); 467 pt0.y = Math.max(pt0.y - 1, 0); 468 pt0.z = Math.max(pt0.z - 1, 0); 469 pt1.x = Math.min(pt1.x + 1, nPointsX); 470 pt1.y = Math.min(pt1.y + 1, nPointsY); 471 pt1.z = Math.min(pt1.z + 1, nPointsZ); 472 } 473 474 // for isoSolventReader and isoIntersectReader 475 476 protected BS bsSurfaceVoxels; 477 protected BS validSpheres, noFaceSpheres; 478 protected int[] voxelSource; 479 getAtomMinMax(BS bs, BS[] bsAtomMinMax)480 protected void getAtomMinMax(BS bs, BS[] bsAtomMinMax) { 481 for (int i = 0; i < nPointsX; i++) 482 bsAtomMinMax[i] = new BS(); 483 for (int iAtom = myAtomCount; --iAtom >= 0;) { 484 if (bs != null && !bs.get(iAtom)) 485 continue; 486 setGridLimitsForAtom(atomXyzTruncated[iAtom], atomRadius[iAtom], pt0, pt1); 487 for (int i = pt0.x; i < pt1.x; i++) 488 bsAtomMinMax[i].set(iAtom); 489 //System.out.println("for atom " + iAtom + " " + ptA + " " + min + " " + max); 490 } 491 } 492 493 protected final P3 ptY0 = new P3(); 494 protected final P3 ptZ0 = new P3(); 495 protected final P3i pt0 = new P3i(); 496 protected final P3i pt1 = new P3i(); 497 protected final P3 ptV = new P3(); 498 markSphereVoxels(float r0, float distance)499 protected void markSphereVoxels(float r0, float distance) { 500 boolean isWithin = (distance != Float.MAX_VALUE && point != null); 501 T3 v0 = volumetricVectors[0]; 502 T3 v1 = volumetricVectors[1]; 503 T3 v2 = volumetricVectors[2]; 504 for (int iAtom = thisAtomSet.nextSetBit(0); iAtom >= 0; iAtom = thisAtomSet 505 .nextSetBit(iAtom + 1)) { 506 if (!havePlane && validSpheres != null && !validSpheres.get(iAtom)) 507 continue; 508 boolean isSurface = (noFaceSpheres != null && noFaceSpheres.get(iAtom)); 509 boolean isNearby = (iAtom >= firstNearbyAtom); 510 P3 ptA = atomXyzTruncated[iAtom]; 511 float rA = atomRadius[iAtom]; 512 if (isWithin && ptA.distance(point) > distance + rA + 0.5) 513 continue; 514 float rA0 = rA + r0; 515 setGridLimitsForAtom(ptA, rA0, pt0, pt1); 516 //pt1.y = nPointsY; 517 //pt1.z = nPointsZ; 518 if (isProgressive) { 519 pt0.x = thisX; 520 pt1.x = thisX + 1; 521 } 522 volumeData.voxelPtToXYZ(pt0.x, pt0.y, pt0.z, ptV); 523 for (int i = pt0.x; i < pt1.x; i++, ptV.add2(v0, ptY0)) { 524 ptY0.setT(ptV); 525 for (int j = pt0.y; j < pt1.y; j++, ptV.add2(v1, ptZ0)) { 526 ptZ0.setT(ptV); 527 for (int k = pt0.z; k < pt1.z; k++, ptV.add(v2)) { 528 float value = ptV.distance(ptA) - rA; 529 int ipt = volumeData.getPointIndex(i, j, k); 530 if ((r0 == 0 || value <= rA0) && value < getVoxel(i, j, k, ipt)) { 531 if (isNearby || isWithin && ptV.distance(point) > distance) 532 value = Float.NaN; 533 setVoxel(i, j, k, ipt, value); 534 if (!Float.isNaN(value)) { 535 if (voxelSource != null) 536 voxelSource[ipt] = iAtom + 1; 537 if (value < 0 && isSurface) 538 bsSurfaceVoxels.set(ipt); 539 } 540 } 541 } 542 } 543 } 544 } 545 } 546 setVoxel(int i, int j, int k, int ipt, float value)547 protected void setVoxel(int i, int j, int k, int ipt, float value) { 548 if (isProgressive) 549 thisPlane[ipt % yzCount] = value; 550 else 551 voxelData[i][j][k] = value; 552 } 553 554 } 555