001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.nbio.structure.xtal; 022 023import org.biojava.nbio.structure.jama.EigenvalueDecomposition; 024import org.biojava.nbio.structure.jama.Matrix; 025import org.biojava.nbio.structure.xtal.io.TransfAlgebraicAdapter; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029import javax.vecmath.AxisAngle4d; 030import javax.vecmath.Matrix3d; 031import javax.vecmath.Matrix4d; 032import javax.vecmath.Vector3d; 033import javax.xml.bind.JAXBContext; 034import javax.xml.bind.JAXBException; 035import javax.xml.bind.Marshaller; 036import javax.xml.bind.annotation.XmlAccessType; 037import javax.xml.bind.annotation.XmlAccessorType; 038import javax.xml.bind.annotation.XmlRootElement; 039import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 040import java.io.ByteArrayOutputStream; 041import java.io.PrintStream; 042import java.io.Serializable; 043import java.util.ArrayList; 044import java.util.List; 045import java.util.regex.Matcher; 046import java.util.regex.Pattern; 047 048 049/** 050 * A crystallographic space group. We store the standard numeric identifier, 051 * the international short symbol and the transformations corresponding to 052 * each space group (as Matrix4ds and in algebraic notation). 053 * The information for all (protein crystallography) space groups can be 054 * parsed from the XML file in the resource directory. 055 * 056 * See: http://en.wikipedia.org/wiki/Space_group 057 * 058 * @author duarte_j 059 * @see SymoplibParser 060 */ 061@XmlRootElement(name = "SpaceGroup", namespace ="http://www.biojava.org") 062@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER) 063public class SpaceGroup implements Serializable { 064 065 private static final long serialVersionUID = 1L; 066 private static final Logger logger = LoggerFactory.getLogger(SpaceGroup.class); 067 068 069 private static final Pattern splitPat1 = Pattern.compile("((?:[+-]?[XYZ])+)([+-][0-9/.]+)"); 070 private static final Pattern splitPat2 = Pattern.compile("([+-]?[0-9/.]+)((?:[+-][XYZ])+)"); 071 private static final Pattern coordPat = Pattern.compile("(?:([+-])?([XYZ]))+?"); // the last +? is for ungreedy matching 072 private static final Pattern transCoefPat = Pattern.compile("([-+]?[0-9.]+)(?:/([0-9.]+))?"); 073 074 private static final Pattern nonEnantPat = Pattern.compile("[-abcmnd]"); 075 076 protected static final double DELTA=0.0000001; 077 078 private int id; 079 private int multiplicity; 080 private int primitiveMultiplicity; 081 private String shortSymbol; 082 private String altShortSymbol; 083 private List<Matrix4d> transformations; 084 private List<String> transfAlgebraic; 085 private Vector3d[] cellTranslations; // in space groups I, C, F or H there are pure cell translations corresponding to recenterings 086 087 private AxisAngle4d[] axisAngles; 088 089 private int[] axisTypes; // indices of array are transformIds 090 091 private BravaisLattice bravLattice; 092 093 @SuppressWarnings("unused") 094 private SpaceGroup(){ 095 // required by JAXB 096 097 } 098 099 public SpaceGroup(int id, int multiplicity, int primitiveMultiplicity, String shortSymbol, String altShortSymbol, BravaisLattice bravLattice) { 100 this.id = id; 101 this.multiplicity = multiplicity; 102 this.primitiveMultiplicity = primitiveMultiplicity; 103 this.shortSymbol = shortSymbol; 104 this.altShortSymbol = altShortSymbol; 105 transformations = new ArrayList<Matrix4d>(multiplicity); 106 transfAlgebraic = new ArrayList<String>(multiplicity); 107 cellTranslations = new Vector3d[multiplicity/primitiveMultiplicity]; 108 this.bravLattice = bravLattice; 109 } 110 111 /** 112 * Get the space group for the given international short name, using 113 * the PDB format, e.g. 'P 21 21 21' or 'C 1 c 1' 114 * @param shortName 115 * @return the SpaceGroup or null if the shortName is not valid 116 * @see SymoplibParser#getSpaceGroup(String) 117 */ 118 public static SpaceGroup parseSpaceGroup(String shortName) { 119 return SymoplibParser.getSpaceGroup(shortName); 120 } 121 122 public void addTransformation(String transfAlgebraic) { 123 this.transfAlgebraic.add(transfAlgebraic); 124 this.transformations.add(getMatrixFromAlgebraic(transfAlgebraic)); 125 } 126 127 protected void initializeCellTranslations() { 128 if ( cellTranslations != null && cellTranslations.length >0) { 129 // we already initialized this 130 return; 131 } 132 cellTranslations = new Vector3d[multiplicity/primitiveMultiplicity]; 133 cellTranslations[0] = new Vector3d(0,0,0); 134 135 if ( transformations == null){ 136 logger.warn("transformations == null" + this.toXML()); 137 } 138 139 if (multiplicity==primitiveMultiplicity) { 140 return; 141 } 142 int fold = multiplicity/primitiveMultiplicity; 143 144 145 146 for (int n=1;n<fold;n++) { 147 if ( transformations.size() < (n* primitiveMultiplicity)){ 148 logger.warn("WARNING number of transformations < " +(n*primitiveMultiplicity)); 149 logger.warn(this.toXML()); 150 } 151 Matrix4d t = transformations.get(n*primitiveMultiplicity); 152 cellTranslations[n] = new Vector3d(t.m03,t.m13,t.m23); 153 } 154 } 155 156 public int getMultiplicity() { 157 return multiplicity; 158 } 159 160 public int getPrimitiveMultiplicity() { 161 return primitiveMultiplicity; 162 } 163 164 public Vector3d[] getCellTranslations() { 165 return cellTranslations; 166 } 167 168 public Vector3d getCellTranslation(int i) { 169 return cellTranslations[i]; 170 } 171 172 public static Matrix4d getMatrixFromAlgebraic(String transfAlgebraic) { 173 String[] parts = transfAlgebraic.toUpperCase().split(","); 174 double[] xCoef = convertAlgebraicStrToCoefficients(parts[0].trim()); 175 double[] yCoef = convertAlgebraicStrToCoefficients(parts[1].trim()); 176 double[] zCoef = convertAlgebraicStrToCoefficients(parts[2].trim()); 177 178 Matrix4d mat = new Matrix4d(); 179 mat.setIdentity(); 180 mat.setRotation(new Matrix3d(xCoef[0],xCoef[1],xCoef[2],yCoef[0],yCoef[1],yCoef[2],zCoef[0],zCoef[1],zCoef[2])); 181 mat.setTranslation(new Vector3d(xCoef[3],yCoef[3],zCoef[3])); 182 return mat; 183 //return new Matrix4d(xCoef[0],xCoef[1],xCoef[2],xCoef[3], 184 // yCoef[0],yCoef[1],yCoef[2],yCoef[3], 185 // zCoef[0],zCoef[1],zCoef[2],zCoef[3], 186 // 0,0,0,1); 187 } 188 189 private static double[] convertAlgebraicStrToCoefficients(String algString) { 190 String letters = null; 191 String noLetters = null; 192 Matcher m = splitPat1.matcher(algString); 193 if (m.matches()) { 194 letters = m.group(1); 195 noLetters = m.group(2); 196 } else { 197 m = splitPat2.matcher(algString); 198 if (m.matches()) { 199 letters = m.group(2); 200 noLetters = m.group(1); 201 } else { 202 letters = algString; 203 } 204 } 205 double[] coefficients = new double[4]; 206 m = coordPat.matcher(letters); 207 while(m.find()){ 208 String sign = ""; 209 if (m.group(1)!=null) { 210 sign = m.group(1); 211 } 212 double s = 1.0; 213 if (sign.equals("-")){ 214 s = -1.0; 215 } 216 String coord = m.group(2); 217 if (coord.equals("X")) { 218 coefficients[0] = s; 219 } else if (coord.equals("Y")) { 220 coefficients[1] = s; 221 } else if (coord.equals("Z")) { 222 coefficients[2] = s; 223 } 224 } 225 if (noLetters!=null) { 226 m = transCoefPat.matcher(noLetters); 227 if (m.matches()) { 228 double num = Double.parseDouble(m.group(1)); 229 double den = 1; 230 if (m.group(2)!=null) { 231 den = Double.parseDouble(m.group(2)); 232 } 233 coefficients[3] = num/den; 234 } 235 } else { 236 coefficients[3]=0; 237 } 238 return coefficients; 239 } 240 241 /** 242 * Gets the standard numeric identifier for the space group. 243 * See for example http://en.wikipedia.org/wiki/Space_group 244 * or the IUCr crystallographic tables 245 * @return 246 */ 247 public int getId() { 248 return id; 249 } 250 251 /** 252 * Gets the international short name (as used in PDB), 253 * e.g. "P 21 21 21" or "C 1 c 1" 254 * @return 255 */ 256 public String getShortSymbol() { 257 return shortSymbol; 258 } 259 260 /** 261 * Gets the alternative international short name (as sometimes used in PDB), 262 * e.g. "I 1 2 1" instead of "I 2" 263 * @return 264 */ 265 public String getAltShortSymbol() { 266 return altShortSymbol; 267 } 268 269 /** 270 * Gets all transformations except for the identity in crystal axes basis. 271 * @return 272 */ 273 public List<Matrix4d> getTransformations() { 274 List<Matrix4d> transfs = new ArrayList<Matrix4d>(); 275 for (int i=1;i<this.transformations.size();i++){ 276 transfs.add(transformations.get(i)); 277 } 278 return transfs; 279 } 280 281 private void calcRotAxesAndAngles() { 282 283 axisAngles = new AxisAngle4d[multiplicity]; 284 285 // identity operator (transformId==0) 286 axisAngles[0] = new AxisAngle4d(new Vector3d(0,0,0), 0.0); 287 288 for (int i=1;i<this.transformations.size();i++){ 289 Matrix3d r = new Matrix3d(transformations.get(i).m00,transformations.get(i).m01,transformations.get(i).m02, 290 transformations.get(i).m10,transformations.get(i).m11,transformations.get(i).m12, 291 transformations.get(i).m20,transformations.get(i).m21,transformations.get(i).m22); 292 293 axisAngles[i] = getRotAxisAndAngle(r); 294 295 } 296 } 297 298 /** 299 * Calculates the axis fold type (1, 2, 3, 4, 5, 6 for rotations or -1, -2, -3, -4, -6 improper rotations) 300 * from the trace of the rotation matrix, see for instance 301 * http://www.crystallography.fr/mathcryst/pdf/Gargnano/Aroyo_Gargnano_1.pdf 302 */ 303 private void calcAxisFoldTypes() { 304 axisTypes = new int[multiplicity]; 305 306 for (int i=0;i<this.transformations.size();i++){ 307 308 axisTypes[i] = getRotAxisType(transformations.get(i)); 309 310 } 311 } 312 313 public AxisAngle4d getRotAxisAngle(int transformId) { 314 if (this.axisAngles == null) calcRotAxesAndAngles(); 315 return this.axisAngles[transformId]; 316 } 317 318 /** 319 * Returns true if both given transform ids belong to the same crystallographic axis (a, b or c) 320 * For two non-rotation transformations (i.e. identity operators) it returns true 321 * @param tId1 322 * @param tId2 323 * @return 324 */ 325 public boolean areInSameAxis(int tId1, int tId2) { 326 if (tId1==tId2) return true; 327 328 if (axisAngles== null) calcRotAxesAndAngles(); 329 330 if (getAxisFoldType(tId1)==1 && getAxisFoldType(tId2)==1) return true; 331 332 // we can't deal yet with improper rotations: we return false whenever either of them is improper 333 if (getAxisFoldType(tId1)<0 || getAxisFoldType(tId2)<0) return false; 334 335 Vector3d axis1 = new Vector3d(axisAngles[tId1].x, axisAngles[tId1].y, axisAngles[tId1].z); 336 Vector3d axis2 = new Vector3d(axisAngles[tId2].x, axisAngles[tId2].y, axisAngles[tId2].z); 337 338 // TODO revise: we might need to consider that the 2 are in same direction but opposite senses 339 // the method is not used at the moment anyway 340 if (deltaComp(axis1.angle(axis2), 0.0, DELTA)) return true; 341 342 return false; 343 } 344 345 /** 346 * Given a transformId returns the type of axis of rotation: 1 (no rotation), 2, 3, 4 or 6 -fold 347 * and for improper rotations: -1, -2, -3, -4 and -6 348 * 349 * @param transformId 350 * @return 351 */ 352 public int getAxisFoldType(int transformId) { 353 if (axisTypes== null) calcAxisFoldTypes(); 354 return axisTypes[transformId]; 355 } 356 357 /** 358 * Gets a transformation by index expressed in crystal axes basis. 359 * Index 0 corresponds always to the identity transformation. 360 * Beware the returned Matrix4d is not a copy but it stays linked 361 * to the one stored in this SpaceGroup object 362 * @param i 363 * @return 364 */ 365 public Matrix4d getTransformation(int i) { 366 return transformations.get(i); 367 } 368 369 /** 370 * Gets a transformation algebraic string given its index. 371 * Index 0 corresponds always to the identity transformation. 372 * @param i 373 * @return 374 */ 375 public String getTransfAlgebraic(int i) { 376 return transfAlgebraic.get(i); 377 } 378 379 @Override 380 public boolean equals(Object o) { 381 if (! (o instanceof SpaceGroup)) { 382 return false; 383 } 384 SpaceGroup other = (SpaceGroup) o; 385 if (other.getId()==this.getId()) { 386 return true; 387 } 388 return false; 389 } 390 391 /** 392 * Gets the number of symmetry operators corresponding to this SpaceGroup (counting 393 * the identity operator) 394 * @return 395 */ 396 public int getNumOperators() { 397 return this.transformations.size(); 398 } 399 400 public static String getAlgebraicFromMatrix(Matrix4d m) { 401 String x = formatAlg(m.m00,m.m01,m.m02,m.m03); 402 String y = formatAlg(m.m10,m.m11,m.m12,m.m13); 403 String z = formatAlg(m.m20,m.m21,m.m22,m.m23); 404 String alg = x+","+y+","+z; 405 return alg; 406 } 407 408 private static String formatAlg(double xcoef, double ycoef, double zcoef, double trans) { 409 boolean[] leading = {false,false,false}; 410 if (xcoef!=0) { 411 leading[0] = true; 412 } else if (ycoef!=0) { 413 leading[1] = true; 414 } else if (zcoef!=0) { 415 leading[2] = true; 416 } 417 String x = deltaComp(xcoef,0,DELTA)?"":formatCoef(xcoef,leading[0])+"X"; 418 String y = deltaComp(ycoef,0,DELTA)?"":formatCoef(ycoef,leading[1])+"Y"; 419 String z = deltaComp(zcoef,0,DELTA)?"":formatCoef(zcoef, leading[2])+"Z"; 420 String t = deltaComp(trans,0,DELTA)?"":formatTransCoef(trans); 421 return x+y+z+t; 422 423 } 424 425 private static String formatCoef(double c, boolean leading) { 426 if (leading) { 427 return (deltaComp(Math.abs(c),1,DELTA)?(c>0?"":"-"):String.format("%4.2f",c)); 428 } else { 429 return (deltaComp(Math.abs(c),1,DELTA)?(c>0?"+":"-"):String.format("%+4.2f",c)); 430 } 431 } 432 433 private static String formatTransCoef(double c) { 434 if (Math.abs((Math.rint(c)-c))<DELTA) { // this is an integer 435 return String.format("%+d",(int)Math.rint(c)); 436 } else { // it is a fraction 437 int num,den; 438 int floor = (int)Math.floor(c); 439 double decPart = c - floor; 440 if (deltaComp(decPart,0.3333333,DELTA)) { 441 num=1;den=3; 442 } else if (deltaComp(decPart,0.6666667,DELTA)) { 443 num=2;den=3; 444 } else if (deltaComp(decPart,0.2500000,DELTA)) { 445 num=1;den=4; 446 } else if (deltaComp(decPart,0.5000000,DELTA)) { 447 num=1;den=2; 448 } else if (deltaComp(decPart,0.7500000,DELTA)) { 449 num=3;den=4; 450 } else if (deltaComp(decPart,0.1666667,DELTA)) { 451 num=1;den=6; 452 } else if (deltaComp(decPart,0.8333333,DELTA)) { 453 num=5;den=6; 454 } else { 455 num=0;den=0; // this in an error 456 } 457 num = floor*den+num; 458 return String.format("%+d/%d", num,den); 459 //return String.format("%+4.2f",c); 460 } 461 } 462 463 protected static boolean deltaComp(double d1, double d2, double delta) { 464 return Math.abs(d1-d2)<delta; 465 } 466 467 public BravaisLattice getBravLattice() { 468 return bravLattice; 469 } 470 471 public boolean isEnantiomorphic() { 472 Matcher m = nonEnantPat.matcher(shortSymbol); 473 if (m.find()) { 474 return false; 475 } 476 return true; 477 } 478 479 /** 480 * Given a rotation matrix calculates the rotation axis and angle for it. 481 * The angle is calculated from the trace, the axis from the eigenvalue 482 * decomposition. 483 * If given matrix is improper rotation or identity matrix then 484 * axis (0,0,0) and angle 0 are returned. 485 * @param m 486 * @return 487 * @throws IllegalArgumentException if given matrix is not a rotation matrix (determinant not 1 or -1) 488 */ 489 public static AxisAngle4d getRotAxisAndAngle(Matrix3d m) { 490 double determinant = m.determinant(); 491 492 if (!(Math.abs(determinant)-1.0<DELTA)) throw new IllegalArgumentException("Given matrix is not a rotation matrix"); 493 494 AxisAngle4d axisAndAngle = new AxisAngle4d(new Vector3d(0,0,0),0); 495 496 double[] d = {m.m00,m.m10,m.m20, 497 m.m01,m.m11,m.m21, 498 m.m02,m.m12,m.m22}; 499 500 Matrix r = new Matrix(d,3); 501 502 if (!deltaComp(r.det(), 1.0, DELTA)) { 503 // improper rotation: we return axis 0,0,0 and angle 0 504 return axisAndAngle; 505 } 506 507 EigenvalueDecomposition evd = new EigenvalueDecomposition(r); 508 509 Matrix eval = evd.getD(); 510 if (deltaComp(eval.get(0, 0),1.0,DELTA) && deltaComp(eval.get(1, 1),1.0,DELTA) && deltaComp(eval.get(2, 2),1.0,DELTA)) { 511 // the rotation is an identity: we return axis 0,0,0 and angle 0 512 return axisAndAngle; 513 } 514 int indexOfEv1; 515 for (indexOfEv1=0;indexOfEv1<3;indexOfEv1++) { 516 if (deltaComp(eval.get(indexOfEv1, indexOfEv1),1,DELTA)) break; 517 } 518 Matrix evec = evd.getV(); 519 axisAndAngle.set(new Vector3d(evec.get(0,indexOfEv1), evec.get(1, indexOfEv1), evec.get(2, indexOfEv1)), 520 Math.acos((eval.trace()-1.0)/2.0)); 521 522 return axisAndAngle; 523 } 524 525 /** 526 * Given a transformation matrix containing a rotation returns the type of rotation: 527 * 1 for identity, 2 for 2-fold rotation, 3 for 3-fold rotation, 4 for 4-fold rotation, 528 * 6 for 6-fold rotation, 529 * -1 for inversions, -2 for mirror planes, -3 for 3-fold improper rotation, 530 * -4 for 4-fold improper rotation and -6 for 6-fold improper rotation 531 * @param m 532 * @return 533 */ 534 public static int getRotAxisType(Matrix4d m) { 535 int axisType = 0; 536 537 Matrix3d rot = new Matrix3d(m.m00,m.m01,m.m02, 538 m.m10,m.m11,m.m12, 539 m.m20,m.m21,m.m22); 540 541 double determinant = rot.determinant(); 542 543 if (!deltaComp(determinant,1.0,DELTA) && !deltaComp(determinant, -1.0, DELTA)) { 544 throw new IllegalArgumentException("Given matrix does not seem to be a rotation matrix."); 545 } 546 547 int trace = (int)(rot.m00+rot.m11+rot.m22); 548 if (determinant>0) { 549 switch (trace) { 550 case 3: 551 axisType=1; 552 break; 553 case -1: 554 axisType=2; 555 break; 556 case 0: 557 axisType=3; 558 break; 559 case 1: 560 axisType=4; 561 break; 562 case 2: 563 axisType=6; 564 break; 565 default: 566 throw new RuntimeException("Trace of transform does not correspond to one of the expected types. This is most likely a bug"); 567 } 568 } else { 569 switch (trace) { 570 case -3: 571 axisType=-1; 572 break; 573 case 1: 574 axisType=-2; 575 break; 576 case 0: 577 axisType=-3; 578 break; 579 case -1: 580 axisType=-4; 581 break; 582 case -2: 583 axisType=-6; 584 break; 585 default: 586 throw new RuntimeException("Trace of transform does not correspond to one of the expected types. This is most likely a bug"); 587 } 588 } 589 return axisType; 590 } 591 592 @Override 593 public String toString() { 594 return getShortSymbol(); 595 } 596 597 public String toXML(){ 598 599 600 JAXBContext jaxbContextStringSortedSet = null; 601 602 try { 603 jaxbContextStringSortedSet= JAXBContext.newInstance(SpaceGroup.class); 604 } catch (JAXBException e){ 605 logger.error("Error converting to XML",e); 606 return null; 607 } 608 609 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 610 PrintStream ps = new PrintStream(baos); 611 612 613 try { 614 615 Marshaller m = jaxbContextStringSortedSet.createMarshaller(); 616 617 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 618 619 m.marshal( this, ps); 620 621 622 } catch (JAXBException e){ 623 logger.error("Error converting to XML",e); 624 } 625 626 return baos.toString(); 627 } 628 629 //@XmlElementWrapper(name="transfAlgebraicList", namespace="http://www.biojava.org") 630 //@XmlElement 631 @XmlJavaTypeAdapter(TransfAlgebraicAdapter.class) 632 public List<String> getTransfAlgebraic() { 633 return transfAlgebraic; 634 } 635 636 public void setTransfAlgebraic(List<String> transfAlgebraic) { 637 //System.out.println("setting transfAlgebraic " + transfAlgebraic); 638 if ( transformations == null || transformations.size() == 0) 639 transformations = new ArrayList<Matrix4d>(transfAlgebraic.size()); 640 641 if ( this.transfAlgebraic == null || this.transfAlgebraic.size() == 0) 642 this.transfAlgebraic = new ArrayList<String>(transfAlgebraic.size()); 643 644 for ( String transf : transfAlgebraic){ 645 addTransformation(transf); 646 } 647 } 648 649 650 public int[] getAxisTypes() { 651 return axisTypes; 652 } 653 654 public void setAxisTypes(int[] axisTypes) { 655 this.axisTypes = axisTypes; 656 } 657 658 public static long getSerialversionuid() { 659 return serialVersionUID; 660 } 661 662 public static Pattern getSplitpat1() { 663 return splitPat1; 664 } 665 666 public static Pattern getSplitpat2() { 667 return splitPat2; 668 } 669 670 public static Pattern getCoordpat() { 671 return coordPat; 672 } 673 674 public static Pattern getTranscoefpat() { 675 return transCoefPat; 676 } 677 678 public static Pattern getNonenantpat() { 679 return nonEnantPat; 680 } 681 682 public static double getDelta() { 683 return DELTA; 684 } 685 686 public void setId(int id) { 687 this.id = id; 688 } 689 690 public void setMultiplicity(int multiplicity) { 691 692 this.multiplicity = multiplicity; 693 } 694 695 public void setPrimitiveMultiplicity(int primitiveMultiplicity) { 696 this.primitiveMultiplicity = primitiveMultiplicity; 697 } 698 699 public void setShortSymbol(String shortSymbol) { 700 this.shortSymbol = shortSymbol; 701 } 702 703 public void setAltShortSymbol(String altShortSymbol) { 704 this.altShortSymbol = altShortSymbol; 705 } 706 707 708 public void setBravLattice(BravaisLattice bravLattice) { 709 this.bravLattice = bravLattice; 710 } 711 712} 713