1 package jspecview.source;
2 
3 import java.util.Hashtable;
4 import java.util.Map;
5 
6 import org.jmol.util.Logger;
7 
8 import javajs.util.DF;
9 import javajs.util.PT;
10 import jspecview.common.Annotation.AType;
11 import jspecview.common.Coordinate;
12 import jspecview.common.Integral;
13 import jspecview.common.Measurement;
14 import jspecview.common.Spectrum;
15 import jspecview.exception.JSVException;
16 
17 /**
18  * spectrum data AS READ FROM FILE
19  *
20  * @author Bob Hanson
21  *
22  */
23 public abstract class JDXDataObject extends JDXHeader {
24 
25   /**
26    * Error number that is returned when a min value is undefined
27    */
28   public static final double ERROR = Double.MAX_VALUE;
29 
30   public static final int REF_TYPE_UNSPECIFIED = -1;
31   public static final int REF_TYPE_STANDARD = 0;
32   public static final int REF_TYPE_BRUKER = 1;
33   public static final int REF_TYPE_VARIAN = 2;
34 
35   public String sourceID = "";
36   public boolean isSimulation;
37 
38   protected double blockID; // a random number generated in JDXFileReader
39 
40   private String filePath;
41   private String filePathForwardSlash;
42   private String inlineData;
43 
44   private double fileShiftRef = ERROR; // ##.Shift Reference
45   private int fileShiftRefType = REF_TYPE_UNSPECIFIED; // shiftRef = 0, bruker = 1, varian = 2
46   private int fileShiftRefDataPt = -1;
47 
48   private double minX = Double.NaN, minY = Double.NaN;
49   private double maxX = Double.NaN, maxY = Double.NaN;
50   private double deltaX = Double.NaN;
51 
52   /**
53    * array of x,y coordinates
54    */
55   public Coordinate[] xyCoords;
56   private boolean continuous;
57 
58   /**
59    * whether the x values were converted from HZ to PPM
60    */
61   private boolean isHZtoPPM = false;
62   private boolean xIncreases = true;
63 
64   // --Required JDX Parameters --
65 
66   /**
67    * JDXReader only
68    */
69   public double fileFirstX = ERROR;
70 
71   /**
72    * JDXReader only
73    */
74   public double fileLastX = ERROR;
75 
76 
77   /**
78    * JDXReader only
79    */
80   public int fileNPoints = -1;
81 
82   /**
83    * Also used in JDXExport
84    */
85   public double xFactor = ERROR;
86 
87   /**
88    * Also used in JDXExport
89    */
90   public double yFactor = ERROR;
91 
92   // --Optional Spectral Parameters
93 
94   public String nucleusX, nucleusY = "?";
95   public double freq2dX = Double.NaN;
96   public double freq2dY = Double.NaN;
97   public String y2DUnits = "";
98 
99   protected Spectrum parent;
100   protected String xUnits = "";
101   protected String yUnits = "";
102   protected String xLabel = null;
103   protected String yLabel = null;
104 
105   /**
106    * from JDXReader ##VARNAME
107    */
108   String varName = "";
109 
110 
111   /**
112    * for example, ^1H, ^13C
113    */
114   private String observedNucl = "";
115   private double observedFreq = ERROR;
116   private int numDim = 1;
117   private int nH;
118   private double y2D = Double.NaN;
119 
setInlineData(String data)120   public void setInlineData(String data) {
121     inlineData = data;
122 
123   }
124 
getInlineData()125   public String getInlineData() {
126     return inlineData;
127   }
128 
setFilePath(String filePath)129   public void setFilePath(String filePath) {
130   	if (filePath != null)
131   		filePathForwardSlash = (this.filePath = filePath.trim()).replace('\\','/');
132   }
133 
134   /**
135    * The path to the file
136    * @return path to file or [inline] (if loaded inline)
137    */
getFilePath()138   public String getFilePath() {
139     return filePath;
140   }
141 
getFilePathForwardSlash()142   public String getFilePathForwardSlash() {
143     return filePathForwardSlash;
144   }
145 
setBlockID(double id)146   public void setBlockID(double id) {
147     blockID = id;
148   }
149 
150   /**
151    * for JDXReader only
152    * @throws JSVException
153    */
checkJDXRequiredTokens()154   public void checkJDXRequiredTokens() throws JSVException {
155     String missingTag = (
156         fileFirstX == ERROR ? "##FIRSTX"
157         : fileLastX == ERROR ? "##LASTX"
158         : fileNPoints == -1 ? "##NPOINTS"
159         : xFactor == ERROR ? "##XFACTOR"
160         : yFactor == ERROR ? "##YFACTOR"
161                 : null);
162     if (missingTag != null)
163       throw new JSVException("Error Reading Data Set: " + missingTag + " not found");
164   }
165 
166   /**
167    * Sets the original xfactor, from JDXReader and XMLReader
168    *
169    * @param xFactor
170    *        the x factor
171    */
setXFactor(double xFactor)172   public void setXFactor(double xFactor) {
173     this.xFactor = xFactor;
174   }
175 
176   /**
177    * Returns the original x factor
178    *
179    * @return the original x factor
180    */
getXFactor()181   public double getXFactor() {
182     return xFactor;
183   }
184 
185   /**
186    * Sets the original y factor, from JDXReader and XMLReader
187    *
188    * @param yFactor
189    *        the y factor
190    */
setYFactor(double yFactor)191   public void setYFactor(double yFactor) {
192     this.yFactor = yFactor;
193   }
194 
195   /**
196    * Returns the original y factor
197    *
198    * @return the original y factor
199    */
getYFactor()200   public double getYFactor() {
201     return yFactor;
202   }
203 
204   /**
205    * From ##VARNAME
206    *
207    * @param name
208    */
setVarName(String name)209   public void setVarName(String name) {
210     varName = name;
211   }
212 
isImaginary()213   public boolean isImaginary() {
214     return varName.contains("IMAG");
215   }
216 
217   /**
218    * Sets the units for the x axis
219    *
220    * @param xUnits
221    *        the x units
222    */
setXUnits(String xUnits)223   public void setXUnits(String xUnits) {
224     this.xUnits = xUnits;
225   }
226 
227   /**
228    * Returns the units for x-axis when spectrum is displayed
229    *
230    * @return the units for x-axis when spectrum is displayed
231    */
getXUnits()232   public String getXUnits() {
233     return xUnits;
234   }
235 
236   /**
237    * Sets the units for the y axis
238    *
239    * @param yUnits
240    *        the y units
241    */
setYUnits(String yUnits)242   public void setYUnits(String yUnits) {
243   	if (yUnits.equals("PPM"))
244   		yUnits = "ARBITRARY UNITS"; // EPFL bug
245     this.yUnits = yUnits;
246   }
247 
248   /**
249    * Returns the units for y-axis when spectrum is displayed
250    *
251    * @return the units for y-axis when spectrum is displayed
252    */
getYUnits()253   public String getYUnits() {
254     return yUnits;
255   }
256 
setXLabel(String value)257   public void setXLabel(String value) {
258     xLabel = value;
259   }
260 
setYLabel(String value)261   public void setYLabel(String value) {
262     yLabel = value;
263   }
264 
265 
setObservedNucleus(String value)266 	public void setObservedNucleus(String value) {
267 		observedNucl = value;
268 		if (is1D())
269 			parent.nucleusX = nucleusX = fixNucleus(value);
270 	}
271 
272 	/**
273 	 * ^1H, ^13C, for example
274 	 *
275 	 * @return observedNucl
276 	 */
getObservedNucleus()277 	public String getObservedNucleus() {
278 	  return observedNucl;
279 	}
280 
281   /**
282    * Sets the Observed Frequency (for NMR Spectra)
283    *
284    * @param observedFreq
285    *        the observed frequency
286    */
setObservedFreq(double observedFreq)287   public void setObservedFreq(double observedFreq) {
288     this.observedFreq = observedFreq;
289   }
290 
291   /**
292    * Returns the observed frequency (for NMR Spectra)
293    *
294    * @return the observed frequency (for NMR Spectra)
295    */
getObservedFreq()296   public double getObservedFreq() {
297     return observedFreq;
298   }
299 
setHydrogenCount(int nH)300   public void setHydrogenCount(int nH) {
301     this.nH = nH;
302   }
303 
getHydrogenCount()304   public int getHydrogenCount() {
305     return nH;
306   }
307 
is1D()308   public boolean is1D() {
309     return numDim == 1;
310   }
311 
getNumDim()312   public int getNumDim() {
313     return numDim;
314   }
315 
setNumDim(int n)316   public void setNumDim(int n) {
317     numDim = n;
318   }
319 
320   // 2D nucleus calc
321 
setY2D(double d)322   public void setY2D(double d) {
323     y2D = d;
324   }
325 
getY2D()326   public double getY2D() {
327     return y2D;
328   }
329 
setY2DUnits(String units)330   public void setY2DUnits(String units) {
331     y2DUnits = units;
332   }
333 
getY2DPPM()334   public double getY2DPPM() {
335     double d = y2D;
336     if (y2DUnits.equals("HZ"))
337       d /= freq2dY;
338     return d;
339   }
340 
setNucleusAndFreq(String nuc, boolean isX)341   public void setNucleusAndFreq(String nuc, boolean isX) {
342   	nuc = fixNucleus(nuc);
343     if (isX)
344       nucleusX = nuc;
345     else
346       nucleusY = nuc;
347     double freq;
348     if (observedNucl.indexOf(nuc) >= 0) {
349       freq = observedFreq;
350     } else {
351       double g1 = getGyromagneticRatio(fixNucleus(observedNucl));
352       double g2 = getGyromagneticRatio(nuc);
353       freq = observedFreq * g2 / g1;
354     }
355     if (isX)
356       freq2dX = freq;
357     else
358       freq2dY = freq;
359     Logger.info("Freq for " + nuc + " = " + freq);
360   }
361 
362 
363   /**
364    * Remove nonstandard marks to give simple nucleus 1H not ^1H
365    * @param nuc
366    * @return "1H", "13C", etc.
367    */
fixNucleus(String nuc)368   private String fixNucleus(String nuc) {
369   	return PT.rep(PT.trim(nuc,"[]^<>"), "NUC_", "");
370 	}
371 
372 	/**
373    * source: http://www.mathworks.com/matlabcentral/fileexchange/11722-nmr-properties/content/isotopes.m
374    * % REFERENCES
375 % 1. "Nuclear spins, moments, and other data related to NMR spectroscopy" (9-93)
376 %    CRC Handbook of Chemistry and Physics, 83th Ed., CRC Press, Boca Raton, FL,
377 %    2002.
378 % 2. Stone, N. J., <www.nndc.bnl.gov/nndc/stone_moments/>
379 % 3. http://www.hbcpnetbase.com/
380    */
381 
382   /* '*' indicates
383    * from CODATA 2010 Physical Constants Task Group
384 1H      267.5222005        42.57748060
385 2H      41.0662791      6.53590131
386 13C     67.2828400      10.70839657
387 15N     -27.1261804     -4.31726570
388 19F     251.8148000        40.07757016
389 23Na    70.8084930      11.26952167
390 31P     108.3940000     17.25144090
391    */
392 
393   private final static double[] gyroData = {
394     1, 42.5774806,//*H   Hydrogen  1/2
395     2, 6.53590131,//*H   Deuterium 1
396     3, 45.4148 ,  // H   Tritium  1/2
397     3, 32.436 ,   // He  Helium  1/2
398     6, 6.2661 ,   // Li  Lithium 1
399     7, 16.5483 ,  // Li  Lithium  3/2
400     9, 5.9842 ,   // Be  Beryllium  3/2
401     10, 4.5752 ,  // B   Boron 3
402     11, 13.663 ,  // B   Boron  3/2
403     13, 10.70839657,//*C Carbon  1/2
404     14, 3.07770646,//*N  Nitrogen 1
405     15, 4.31726570,//*N  Nitrogen  1/2
406     17, 5.7742 ,  // O   Oxygen  5/2
407     19, 40.07757016,//*F Fluorine  1/2
408     21, 3.3631 ,  // Ne  Neon  3/2
409     23, 11.26952167,//*Na Sodium  3/2
410     25, 2.6083 ,  // Mg  Magnesium  5/2
411     27, 11.1031 , // Al  Aluminum  5/2
412     29, 8.4655 ,  // Si  Silicon  1/2
413     31, 17.25144090,//*P Phosphorus  1/2
414     33, 3.2717 ,  // S   Sulfur  3/2
415     35, 4.1765 ,  // Cl  Chlorine  3/2
416     37, 3.4765 ,  // Cl  Chlorine  3/2
417     37, 5.819 ,   // Ar  Argone  3/2
418     39, 3.46 ,    // Ar  Argone  7/2
419     39, 1.9893 ,  // K   Potassium  3/2
420     40, 2.4737 ,  // K   Potassium 4
421     41, 1.0919 ,  // K   Potassium  3/2
422     43, 2.8688 ,  // Ca  Calcium  7/2
423     45, 10.3591 , // Sc  Scandium  7/2
424     47, 2.4041 ,  // Ti  Titanium  5/2
425     49, 2.4048 ,  // Ti  Titanium  7/2
426     50, 4.2505 ,  // V   Vanadium 6
427     51, 11.2133 , // V   Vanadium  7/2
428     53, 2.4115 ,  // Cr  Chromium  3/2
429     55, 10.5763 , // Mn  Manganese  5/2
430     57, 1.3816 ,  // Fe  Iron  1/2
431     59, 10.077 ,  // Co  Cobalt  7/2
432     61, 3.8114 ,  // Ni  Nickel  3/2
433     63, 11.2982 , // Cu  Copper  3/2
434     65, 12.103 ,  // Cu  Copper  3/2
435     67, 2.6694 ,  // Zn  Zinc  5/2
436     69, 10.2478 , // Ga  Gallium  3/2
437     71, 13.0208 , // Ga  Gallium  3/2
438     73, 1.4897 ,  // Ge  Germanium  9/2
439     75, 7.315 ,   // As  Arsenic  3/2
440     77, 8.1571 ,  // Se  Selenium  1/2
441     79, 10.7042 , // Br  Bromine  3/2
442     81, 11.5384 , // Br  Bromine  3/2
443     83, 1.6442 ,  // Kr  Krypton  9/2
444     85, 4.1254 ,  // Rb  Rubidium  5/2
445     87, 13.9811 , // Rb  Rubidium  3/2
446     87, 1.8525 ,  // Sr  Strontium  9/2
447     89, 2.0949 ,  // Y   Yttrium  1/2
448     91, 3.9748 ,  // Zr  Zirconium  5/2
449     93, 10.4523 , // Nb  Niobium  9/2
450     95, 2.7874 ,  // Mo  Molybdenum  5/2
451     97, 2.8463 ,  // Mo  Molybdenum  5/2
452     99, 9.6294 ,  // Tc  Technetium  9/2
453     99, 1.9553 ,  // Ru  Ruthenium  5/2
454     101, 2.1916 , // Ru  Ruthenium  5/2
455     103, 1.3477 , // Rh  Rhodium  1/2
456     105, 1.957 ,  // Pd  Palladium  5/2
457     107, 1.7331 , // Ag  Silver  1/2
458     109, 1.9924 , // Ag  Silver  1/2
459     111, 9.0692 , // Cd  Cadmium  1/2
460     113, 9.4871 , // Cd  Cadmium  1/2
461     113, 9.3655 , // In  Indium  9/2
462     115, 9.3856 , // In  Indium  9/2
463     115, 14.0077 ,// Sn  Tin  1/2
464     117, 15.261 , // Sn  Tin  1/2
465     119, 15.966 , // Sn  Tin  1/2
466     121, 10.2551 ,// Sb  Antimony  5/2
467     123, 5.5532 , // Sb  Antimony  7/2
468     123, 11.2349 ,// Te  Tellurium  1/2
469     125, 13.5454 ,// Te  Tellurium  1/2
470     127, 8.5778 , // I   Iodine  5/2
471     129, 11.8604 ,// Xe  Xenon  1/2
472     131, 3.5159 , // Xe  Xenon  3/2
473     133, 5.6234 , // Cs  Cesium  7/2
474     135, 4.2582 , // Ba  Barium  3/2
475     137, 4.7634 , // Ba  Barium  3/2
476     138, 5.6615 , // La  Lanthanum 5
477     139, 6.0612 , // La  Lanthanum  7/2
478     137, 4.88 ,   // Ce  Cerium  3/2
479     139, 5.39 ,   // Ce  Cerium  3/2
480     141, 2.37 ,   // Ce  Cerium  7/2
481     141, 13.0359 ,// Pr  Praseodymium  5/2
482     143, 2.319 ,  // Nd  Neodymium  7/2
483     145, 1.429 ,  // Nd  Neodymium  7/2
484     143, 11.59 ,  // Pm  Promethium  5/2
485     147, 5.62 ,   // Pm  Promethium  7/2
486     147, 1.7748 , // Sm  Samarium  7/2
487     149, 14631 ,  // Sm  Samarium  7/2
488     151, 10.5856 ,// Eu  Europium  5/2
489     153, 4.6745 , // Eu  Europium  5/2
490     155, 1.312 ,  // Gd  Gadolinium  3/2
491     157, 1.72 ,   // Gd  Gadolinium  3/2
492     159, 10.23 ,  // Tb  Terbium  3/2
493     161, 1.4654 , // Dy  Dysprosium  5/2
494     163, 2.0508 , // Dy  Dysprosium  5/2
495     165, 9.0883 , // Ho  Holmium  7/2
496     167, 1.2281 , // Er  Erbium  7/2
497     169, 3.531 ,  // Tm  Thulium  1/2
498     171, 7.5261 , // Yb  Ytterbium  1/2
499     173, 2.073 ,  // Yb  Ytterbium  5/2
500     175, 4.8626 , // Lu  Lutetium  7/2
501     176, 3.451 ,  // Lu  Lutetium 7
502     177, 1.7282 , // Hf  Hafnium  7/2
503     179, 1.0856 , // Hf  Hafnium  9/2
504     180, 4.087 ,  // Ta  Tantalum 9
505     181, 5.1627 , // Ta  Tantalum  7/2
506     183, 1.7957 , // W   Tungsten  1/2
507     185, 9.7176 , // Re  Rhenium  5/2
508     187, 9.817 ,  // Re  Rhenium  5/2
509     187, 0.9856 , // Os  Osmium  1/2
510     189, 3.3536 , // Os  Osmium  3/2
511     191, 0.7658 , // Ir  Iridium  3/2
512     191, 0.8319 , // Ir  Iridium  3/2
513     195, 9.2922 , // Pt  Platinum  1/2
514     197, 0.7406 , // Au  Gold  3/2
515     199, 7.7123 , // Hg  Mercury  1/2
516     201, 2.8469 , // Hg  Mercury  3/2
517     203, 24.7316 ,// Tl  Thallium  1/2
518     205, 24.9749 ,// Tl  Thallium  1/2
519     207, 9.034 ,  // Pb  Lead  1/2
520     209, 6.963 ,  // Bi  Bismuth  9/2
521     209, 11.7 ,   // Po  Polonium  1/2
522     211, 9.16 ,   // Rn  Radon  1/2
523     223, 5.95 ,   // Fr  Francium  3/2
524     223, 1.3746 , // Ra  Radium  3/2
525     225, 11.187 , // Ra  Radium  1/2
526     227, 5.6 ,    // Ac  Actinium  3/2
527     229, 1.4 ,    // Th  Thorium  5/2
528     231, 10.2 ,   // Pa  Protactinium  3/2
529     235, 0.83 ,   // U   Uranium  7/2
530     237, 9.57 ,   // Np  Neptunium  5/2
531     239, 3.09 ,   // Pu  Plutonium  1/2
532     243, 4.6 ,    // Am  Americium  5/2
533     1E100
534   };
535 
536   final private static Map<String, Double> gyroMap = new Hashtable<String, Double>();
537 
538   static {
539     for (int i = 0, n = gyroData.length - 1; i < n; i += 2)
540       gyroMap.put("" + (int)gyroData[i], Double.valueOf(gyroData[i + 1]));
541 
542 //    System.out.println(getGyroMagneticRatio("13C"));
543 //    System.out.println(getGyroMagneticRatio("1H"));
544 //    System.out.println(getNominalSpecFreq("13C", 100.612769));
545   }
546 
getNominalSpecFreq(String nuc, double freq)547   public static int getNominalSpecFreq(String nuc, double freq) {
548     double d = freq * getGyromagneticRatio("1H") / getGyromagneticRatio(nuc);
549     int century = (int) Math.round(d / 100) * 100;
550     return (Double.isNaN(d) ? -1 : Math.abs(d - century) < 2 ? century : (int) Math.round(d));
551   }
552 
getGyromagneticRatio(String nuc)553   public static double getGyromagneticRatio(String nuc) {
554     Double v = null;
555     try {
556       v = gyroMap.get(nuc);
557       if (v != null)
558         return v.doubleValue();
559 
560       int pt = 0;
561       while (pt < nuc.length() && Character.isDigit(nuc.charAt(pt)))
562         pt++;
563       v = gyroMap.get(nuc.substring(0, pt));
564       if (v != null)
565         gyroMap.put(nuc, v);
566     } catch (Exception e) {
567       /// ignore
568     }
569     return (v == null ? Double.NaN : v.doubleValue());
570     //    pt = PT.parseInt(nuc.substring(pt));
571     //    int i = 0;
572     //    for (int n = gyroData.length - 1; i < n; i += 2)
573     //      if (gyroData[i] >= pt)
574     //        break;
575     //    return (gyroData[i] == pt ? gyroData[i + 1] : Double.NaN);
576   }
577 
578 
579 
580 //////////////// derived info /////////////
581 
isTransmittance()582   public boolean isTransmittance() {
583     String s = yUnits.toLowerCase();
584     return (s.equals("transmittance") || s.contains("trans") || s.equals("t"));
585   }
586 
isAbsorbance()587   public boolean isAbsorbance() {
588     String s = yUnits.toLowerCase();
589     return (s.equals("absorbance") || s.contains("abs") || s.equals("a"));
590   }
591 
canSaveAsJDX()592   public boolean canSaveAsJDX() {
593     return getDataClass().equals("XYDATA");
594   }
595 
canIntegrate()596   public boolean canIntegrate() {
597     return (continuous && (isHNMR() || isGC()) && is1D());
598   }
599 
isAutoOverlayFromJmolClick()600   public boolean isAutoOverlayFromJmolClick() {
601     return (isGC());// || isUVVis());
602   }
603 
isGC()604   public boolean isGC() {
605     return dataType.startsWith("GC") || dataType.startsWith("GAS");
606   }
607 
isMS()608   public boolean isMS() {
609     return dataType.startsWith("MASS") || dataType.startsWith("MS");
610   }
611 
isStackable()612 	public boolean isStackable() {
613 		return !isMS();
614 	}
615 
isScalable()616 	public boolean isScalable() {
617 		return true;
618 	}
619 
620 
getYRef()621 	public double getYRef() {
622 		return (!isTransmittance() ? 0.0 : Coordinate.getMaxY(xyCoords, 0, xyCoords.length - 1) < 2 ? 1.0 : 100.0);
623 	}
624 
isInverted()625 	public boolean isInverted() {
626 		return isTransmittance(); // IR
627 	}
628 
canConvertTransAbs()629   public boolean canConvertTransAbs() {
630     return (continuous && (yUnits.toLowerCase().contains("abs"))
631         || yUnits.toLowerCase().contains("trans"));
632   }
633 
canShowSolutionColor()634   public boolean canShowSolutionColor() {
635     return (isContinuous() && canConvertTransAbs()
636         && (xUnits.toLowerCase().contains("nanometer") || xUnits.equalsIgnoreCase("nm"))
637         && getFirstX() < 401 && getLastX() > 699 && xyCoords.length >= 30);
638   }
639 
640   /**
641    * Determines if the spectrum should be displayed with abscissa unit of Part
642    * Per Million (PPM) instead of Hertz (HZ)
643    *
644    * @return true if abscissa unit should be PPM
645    */
isHZtoPPM()646   public boolean isHZtoPPM() {
647     return isHZtoPPM;
648   }
649 
650   /**
651    * Sets the value to true if the spectrum should be displayed with abscissa
652    * unit of Part Per Million (PPM) instead of Hertz (HZ)
653    *
654    * @param val
655    *        true or false
656    */
setHZtoPPM(boolean val)657   public void setHZtoPPM(boolean val) {
658     isHZtoPPM = val;
659   }
660 
661   /**
662    * Sets value to true if spectrum is increasing
663    *
664    * @param val
665    *        true if spectrum is increasing
666    */
setIncreasing(boolean val)667   public void setIncreasing(boolean val) {
668     xIncreases = val;
669   }
670 
671   /**
672    * Returns true if the spectrum is increasing; used by SVGExporter only
673    *
674    * @return true if the spectrum is increasing
675    */
isXIncreasing()676   public boolean isXIncreasing() {
677     return xIncreases;
678   }
679 
680   /**
681    * Determines if the plot should be displayed decreasing by default
682    *
683    * @return true or false
684    */
shouldDisplayXAxisIncreasing()685   public boolean shouldDisplayXAxisIncreasing() {
686     String dt = dataType.toUpperCase();
687     String xu = xUnits.toUpperCase();
688     if (dt.contains("NMR") && !dt.contains("FID")) {
689       return false;
690     } else if (dt.contains("LINK") && xu.contains("CM")) {
691       return false; // I think this was because of a bug where BLOCK files kept type as LINK ?
692     } else if (dt.startsWith("IR") || dt.contains("INFRA")
693         && xu.contains("CM")) {
694       return false;
695     } else if (dt.contains("RAMAN") && xu.contains("CM")) {
696       return false;
697     } else if (dt.contains("VIS") && xu.contains("NANOMETERS")) {
698       return true;
699     }
700     return xIncreases;
701   }
702 
703   /**
704    * Sets value to true if spectrum is continuous
705    *
706    * @param val
707    *        true if spectrum is continuous
708    */
setContinuous(boolean val)709   public void setContinuous(boolean val) {
710     continuous = val;
711   }
712 
713   /**
714    * Returns true if spectrum is continuous
715    *
716    * @return true if spectrum is continuous
717    */
isContinuous()718   public boolean isContinuous() {
719     return continuous;
720   }
721 
722   // For AnIML IR/UV files:
723 
724   // public double pathlength
725 
726 //  /**
727 //   * Returns the pathlength of the sample (required for AnIML IR/UV files)
728 //   *
729 //   * @return the pathlength
730 //   */
731 //  public String getPathlength() {
732 //    return pathlength;
733 //  }
734 
getHeaderRowDataAsArray()735   public String[][] getHeaderRowDataAsArray() {
736     int n = 8;
737     if (observedFreq != ERROR)
738       n++;
739     if (observedNucl != "")
740       n++;
741     String[][] rowData = getHeaderRowDataAsArray(true, n);
742     int i = rowData.length - n;
743     if (observedFreq != ERROR)
744       rowData[i++] = new String[] { "##.OBSERVE FREQUENCY", "" + observedFreq };
745     if (observedNucl != "")
746       rowData[i++] = new String[] { "##.OBSERVE NUCLEUS", observedNucl };
747     rowData[i++] = new String[] { "##XUNITS", isHZtoPPM ? "HZ" : xUnits };
748     rowData[i++] = new String[] { "##YUNITS", yUnits };
749     double x = (xIncreases ? getFirstX() : getLastX());
750     rowData[i++] = new String[] { "##FIRSTX",
751         String.valueOf(isHZtoPPM() ? x * observedFreq : x) };
752     x = (xIncreases ? getLastX() : getFirstX());
753     rowData[i++] = new String[] { "##FIRSTY",
754         String.valueOf(xIncreases ? getFirstY() : getLastY()) };
755     rowData[i++] = new String[] { "##LASTX",
756         String.valueOf(isHZtoPPM() ? x * observedFreq : x) };
757     rowData[i++] = new String[] { "##XFACTOR", String.valueOf(getXFactor()) };
758     rowData[i++] = new String[] { "##YFACTOR", String.valueOf(getYFactor()) };
759     rowData[i++] = new String[] { "##NPOINTS",
760         String.valueOf(xyCoords.length) };
761     return rowData;
762   }
763 
getDefaultUnitPrecision()764 	public int getDefaultUnitPrecision() {
765 		return 2;
766 	}
767 
setMeasurementText(Measurement m)768 	public String setMeasurementText(Measurement m) {
769 		double dx = m.getValue();
770 		if (Double.isNaN(dx))
771 			return "";
772 		int precision = 1;
773 		String units = "";
774 		if (isNMR()) {
775 			if (is1D()) {
776 				boolean isIntegral = (m instanceof Integral);
777 				if (isHNMR() || isIntegral) {
778 					if (!isIntegral) {
779 						dx *= observedFreq;
780   					units = " Hz";
781 					}
782 				} else {
783 					units = " ppm";
784 					precision = 2;
785 				}
786 			} else {
787 				return "";
788 				// 2D?
789 			}
790 		}
791 		return (dx < 0.1 ? "" : DF.formatDecimalDbl(dx, precision) + units);
792 	}
793 
isNMR()794   public boolean isNMR() {
795     return (dataType.toUpperCase().indexOf("NMR") >= 0);
796   }
797   /**
798    * Determines if a spectrum is an HNMR spectrum
799    * @return true if an HNMR, false otherwise
800    */
isHNMR()801   public boolean isHNMR() {
802     return (isNMR() && observedNucl.toUpperCase().indexOf("H") >= 0);
803   }
804 
805   /**
806    * Sets the array of coordinates
807    *
808    * @param coords
809    *        the array of Coordinates
810    */
setXYCoords(Coordinate[] coords)811   public void setXYCoords(Coordinate[] coords) {
812     xyCoords = coords;
813   }
814 
invertYAxis()815   public JDXDataObject invertYAxis() {
816   	for (int i = xyCoords.length; --i >= 0;) {
817   		xyCoords[i].setYVal(-xyCoords[i].getYVal());
818   	}
819   	double d = minY;
820   	minY = -maxY;
821   	maxY = -d;
822   	return this;
823   }
824 
825   /**
826    * Returns the first X value
827    *
828    * @return the first X value
829    */
getFirstX()830   public double getFirstX() {
831     return xyCoords[0].getXVal();
832   }
833 
834   /**
835    * Returns the first Y value
836    *
837    * @return the first Y value
838    */
getFirstY()839   public double getFirstY() {
840     //if(isIncreasing())
841     return xyCoords[0].getYVal();
842     //else
843     //  return xyCoords[getNumberOfPoints() - 1].getYVal();
844   }
845 
846   /**
847    * Returns the last X value
848    *
849    * @return the last X value
850    */
getLastX()851   public double getLastX() {
852     // if(isIncreasing())
853     return xyCoords[xyCoords.length - 1].getXVal();
854     // else
855     //   return xyCoords[0].getXVal();
856   }
857 
858   /**
859    * Returns the last Y value
860    *
861    * @return the last Y value
862    */
getLastY()863   public double getLastY() {
864     return xyCoords[xyCoords.length - 1].getYVal();
865   }
866 
867   /**
868    * Calculates and returns the minimum x value in the list of coordinates
869    * Fairly expensive operation
870    *
871    * @return the minimum x value in the list of coordinates
872    */
getMinX()873   public double getMinX() {
874     return (Double.isNaN(minX) ? (minX = Coordinate.getMinX(xyCoords, 0, xyCoords.length - 1)) : minX);
875   }
876 
877   /**
878    * Calculates and returns the minimum y value in the list of coordinates
879    * Fairly expensive operation
880    *
881    * @return the minimum x value in the list of coordinates
882    */
getMinY()883   public double getMinY() {
884     return (Double.isNaN(minY) ? (minY = Coordinate.getMinY(xyCoords, 0, xyCoords.length - 1)) : minY);
885   }
886 
887   /**
888    * Calculates and returns the maximum x value in the list of coordinates
889    * Fairly expensive operation
890    *
891    * @return the maximum x value in the list of coordinates
892    */
getMaxX()893   public double getMaxX() {
894     return (Double.isNaN(maxX) ? (maxX = Coordinate.getMaxX(xyCoords, 0, xyCoords.length - 1)) : maxX);
895   }
896 
897   /**
898    * Calculates and returns the maximum y value in the list of coordinates
899    * Fairly expensive operation
900    *
901    * @return the maximum y value in the list of coordinates
902    */
getMaxY()903   public double getMaxY() {
904     return (Double.isNaN(maxY) ? (maxY = Coordinate.getMaxY(xyCoords, 0, xyCoords.length - 1)) : maxY);
905   }
906 
normalizeSimulation(double max)907 	public void normalizeSimulation(double max) {
908 		// for simulations
909 		if (!isNMR() || !is1D())
910 			return;
911 		double f = max / getMaxY();
912 		maxY = Double.NaN;
913 		Coordinate.applyScale(xyCoords, 1, f);
914 		Logger.info("Y values have been scaled by a factor of " + f);
915 	}
916 
917   /**
918    * Returns the delta X
919    *
920    * @return the delta X
921    */
getDeltaX()922   public double getDeltaX() {
923     return (Double.isNaN(deltaX) ? (deltaX = Coordinate.deltaX(getLastX(), getFirstX(), xyCoords.length)) : deltaX);
924   }
925 
copyTo(JDXDataObject newObj)926   public void copyTo(JDXDataObject newObj) {
927     newObj.setTitle(title);
928     newObj.setJcampdx(jcampdx);
929     newObj.setOrigin(origin);
930     newObj.setOwner(owner);
931     newObj.setDataClass(dataClass);
932     newObj.setDataType(dataType);
933     newObj.setHeaderTable(headerTable);
934 
935     newObj.setXFactor(xFactor);
936     newObj.setYFactor(yFactor);
937     newObj.setXUnits(xUnits);
938     newObj.setYUnits(yUnits);
939     newObj.setXLabel(xLabel);
940     newObj.setYLabel(yLabel);
941 
942     //newSpectrum.setPathlength(getPathlength());
943     newObj.setXYCoords(xyCoords);
944     newObj.setContinuous(continuous);
945     newObj.setIncreasing(xIncreases);
946 
947     newObj.observedFreq = observedFreq;
948     newObj.observedNucl = observedNucl;
949     newObj.fileShiftRef = fileShiftRef;
950     newObj.fileShiftRefDataPt = fileShiftRefDataPt;
951     newObj.fileShiftRefType = fileShiftRefType;
952     newObj.isHZtoPPM = isHZtoPPM;
953     newObj.numDim = numDim;
954     newObj.nucleusX = nucleusX;
955     newObj.nucleusY = nucleusY;
956     newObj.freq2dX = freq2dX;
957     newObj.freq2dY = freq2dY;
958     newObj.setFilePath(filePath);
959     newObj.nH = nH;
960 
961   }
962 
getTypeLabel()963   public String getTypeLabel() {
964     return (isNMR() ? nucleusX + "NMR" : dataType);
965   }
966 
getDefaultAnnotationInfo(AType type)967   public Object[] getDefaultAnnotationInfo(AType type) {
968 		String[] s1;
969 		int[] s2;
970 		boolean isNMR = isNMR();
971 		switch (type) {
972 		case Integration:
973 			return new Object[] { null, new int[] { 1 }, null };
974 		case Measurements:
975 			s1 = (isNMR ? new String[] { "Hz", "ppm" } : new String[] {""});
976 			s2 = (isHNMR() ? new int[] { 1, 4 }
977 			: new int[] { 1, 3 });
978 			return new Object[] { s1, s2, Integer.valueOf(0) };
979 		case PeakList:
980 			s1 = (isNMR ? new String[] { "Hz", "ppm" } : new String[] {""} );
981 			s2 = (isHNMR() ? new int[] { 1, 2 } : new int[] { 1, 1 });
982 			return new Object[] { s1, s2, Integer.valueOf(isNMR ? 1 : 0) };
983 		case NONE:
984 		case OverlayLegend:
985 			break;
986 		case Views:
987 			break;
988 		}
989 		return null;
990 	}
991 
getPeakListArray(Measurement m, double[]last, double maxY)992 	public double[] getPeakListArray(Measurement m, double[]last, double maxY) {
993 		double x = m.getXVal();
994 		double y = m.getYVal();
995 		if (isNMR())
996 			y /= maxY;
997 		double dx = Math.abs(x - last[0]);
998 		last[0] = x;
999 		double ddx = dx + last[1];
1000 		last[1] = dx;
1001 		double dddx = ddx + last[2];
1002 		last[2] = ddx;
1003 		if (isNMR()) {
1004 			return new double[] {x, y, x * observedFreq, (dx * observedFreq > 20 ? 0 : dx * observedFreq)
1005 			, (ddx * observedFreq > 20 ? 0 : ddx * observedFreq)
1006 			, (dddx * observedFreq > 20 ? 0 : dddx * observedFreq)};
1007 		}
1008 		return new double[] { x, y };
1009 	}
1010 
1011 	/**
1012 	 * Called by JDXReader immediately after decompression.
1013 	 *
1014 	 */
finalizeCoordinates()1015   void finalizeCoordinates() {
1016     double freq = (Double.isNaN(freq2dX) ? observedFreq
1017         : freq2dX);
1018     // apply offset
1019     boolean isHz = (freq != ERROR
1020         && getXUnits().toUpperCase().equals("HZ"));
1021     if (fileShiftRef != ERROR && freq != ERROR
1022         && dataType.toUpperCase().contains("SPECTRUM")
1023         && jcampdx.indexOf("JEOL") < 0 // BH 2020.09.16 J Muzyka Centre College
1024     ) {
1025       applyShiftReference(isHz ? freq : 1, fileShiftRef);
1026     }
1027     if (fileFirstX > fileLastX)
1028       Coordinate.reverse(xyCoords);
1029     if (isHz) {
1030       Coordinate.applyScale(xyCoords, (1.0 / freq), 1);
1031       setXUnits("PPM");
1032       setHZtoPPM(true);
1033     }
1034   }
1035 
1036   /**
1037    * Set the shift, pt, and type for applyShiftReference() from processing
1038    * ##.SHIFTREFERENCE, ##$REFERENCEPOINT, or ##OFFSET
1039    *
1040    * @param shift
1041    * @param pt
1042    * @param type
1043    */
setShiftReference(double shift, int pt, int type)1044   void setShiftReference(double shift, int pt, int type) {
1045     fileShiftRef = shift;
1046     fileShiftRefDataPt = (pt > 0 ? pt : 1);
1047     fileShiftRefType = type;
1048   }
1049 
isShiftTypeSpecified()1050   boolean isShiftTypeSpecified() {
1051     return  (fileShiftRefType != JDXDataObject.REF_TYPE_UNSPECIFIED);
1052   }
1053 
1054   /**
1055    * Applies the shift reference to all coordinates. Used by JDXReader only.
1056    *
1057    * @param referenceFreq
1058    *        the observed frequency
1059    * @param shift
1060    */
applyShiftReference(double referenceFreq, double shift)1061   private void applyShiftReference(double referenceFreq, double shift) {
1062 
1063     if (fileShiftRefDataPt > xyCoords.length || fileShiftRefDataPt < 0)
1064       return;
1065 
1066     Coordinate coord;
1067     switch (fileShiftRefType) {
1068     case REF_TYPE_STANDARD:
1069       shift = xyCoords[fileShiftRefDataPt - 1].getXVal() - shift * referenceFreq;
1070       break;
1071     case REF_TYPE_BRUKER:
1072       shift = fileFirstX - shift * referenceFreq;
1073       break;
1074     case REF_TYPE_VARIAN:
1075       shift = fileLastX + shift;
1076       break;
1077     }
1078 
1079     for (int index = 0; index < xyCoords.length; index++) {
1080       coord = xyCoords[index];
1081       coord.setXVal(coord.getXVal() - shift);
1082       xyCoords[index] = coord;
1083     }
1084 
1085   }
1086 
1087 
1088 }
1089