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