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