001    package edu.nrao.sss.model.source;
002    
003    import edu.nrao.sss.astronomy.StokesParameter;
004    import edu.nrao.sss.measure.Angle;
005    import edu.nrao.sss.measure.ArcUnits;
006    import edu.nrao.sss.measure.Frequency;
007    import edu.nrao.sss.measure.FrequencyRange;
008    import edu.nrao.sss.measure.FluxDensity;
009    import edu.nrao.sss.measure.TimeDuration;
010    import edu.nrao.sss.measure.TimeInterval;
011    import edu.nrao.sss.measure.TimeUnits;
012    
013    import java.math.BigDecimal;
014    import java.util.Calendar;
015    import java.util.Date;
016    import java.util.TimeZone;
017    
018    /**
019     * An observation of the flux from a source performed by the
020     * Very Large Array.
021     * <p>
022     * This class was copied from edu.nrao.legacy.VLAFluxData.
023     * It has not (yet?) been altered to match more closely the
024     * style of the other classes in the SSS Domain Model.</p>
025     * <p>
026     * This class is not suggested for general use.</p>
027     * <p>
028     * <b>Version Info:</b>
029     * <table style="margin-left:2em">
030     *   <tr><td>$Revision: 1314 $</td></tr>
031     *   <tr><td>$Date: 2008-05-30 11:31:14 -0600 (Fri, 30 May 2008) $</td></tr>
032     *   <tr><td>$Author: dharland $</td></tr>
033     * </table></p>
034     * 
035     * @author David M. Harland
036     * @since 2007-05-21
037     */
038    public class VlaFluxObservation
039      implements Cloneable
040    {
041      //The names of these variables were copied directly from
042      //edu.nrao.legacy.VLAFluxData.
043      public String Source;
044      public double mjad;
045      public String correlator_mode;
046      public double el_end;           //Units?
047      public double obs_start;        //in Radians
048      public double obs_end;          //in Radians
049      public double time_obs;         //Length of obsvn?  This is an mjd
050      public double ac_freq;          //Right circular polarized, in Ghz
051      public double bd_freq;          //Left circular polarized
052      public double ac_flux;          //in Janskies
053      public double ac_flux_stddev;
054      public double bd_flux;
055      public double bd_flux_stddev;
056    
057      /** Used by a factory method of SourceBrightness. */
058      SourceBrightness[] makeBrightnesses()
059      {
060        //Circular polarizations
061        final int LEFT  = 0;
062        final int RIGHT = 1;
063    
064        PointBrightness[] result = new PointBrightness[2];
065    
066        result[LEFT] = (PointBrightness)
067          SourceBrightness.createBrightness(BrightnessDistribution.POINT);
068    
069        result[LEFT].setPolarization(StokesParameter.LL);
070    
071        //XXX The endpoint will have to be changed by the client of this method if
072        //they want something besides infinity.
073        TimeInterval ti = new TimeInterval();
074        ti.set(getDateFromMjad((int)this.mjad, obs_start), ti.getEnd());
075        result[LEFT].setValidTime(ti);
076    
077        FrequencyRange fr = new FrequencyRange(
078          new Frequency(new BigDecimal(this.ac_freq)),
079          new Frequency(new BigDecimal(this.bd_freq))
080        );
081    
082        result[LEFT].setValidFrequency(fr);
083        result[LEFT].setPeakFluxDensity(new FluxDensity(BigDecimal.valueOf(this.bd_flux)));
084    
085        result[RIGHT] = (PointBrightness)result[LEFT].clone();
086        result[RIGHT].setPolarization(StokesParameter.RR);
087        result[RIGHT].setPeakFluxDensity(new FluxDensity(BigDecimal.valueOf(this.ac_flux)));
088    
089        return result;
090      }
091    
092      /**
093       * @return a UTC date representing this particular mjad.
094       * @param mjad A MJAD with no fractional day component
095       * @param rads A fractional day represented in radians.
096       */
097      private Date getDateFromMjad(int mjad, double rads)
098      {
099        Angle startTime = new Angle(BigDecimal.valueOf(rads), ArcUnits.RADIAN);
100        double startHour = startTime.toUnits(ArcUnits.HOUR).doubleValue();
101    
102        TimeDuration start = new TimeDuration(BigDecimal.valueOf(startHour));
103        int hour = (int)start.getIntegralPart(TimeUnits.HOUR);
104        int min = (int)start.getIntegralPart(TimeUnits.MINUTE);
105    
106        //Ignore anything more precise than seconds
107        int sec = start.getPart(TimeUnits.SECOND).intValue();
108    
109        //Intialize the calendar to the Gregorian date that represents 0.0 MJD
110        Calendar c = Calendar.getInstance();
111        c.setTimeZone(TimeZone.getTimeZone("UTC"));
112        c.set(1858, Calendar.NOVEMBER, 17, 0, 0, 0);
113    
114        //Add the days, hours, etc.
115        c.add(Calendar.DAY_OF_YEAR, mjad);
116        c.add(Calendar.HOUR_OF_DAY, hour);
117        c.add(Calendar.MINUTE, min);
118        c.add(Calendar.SECOND, sec);
119    
120        return c.getTime();
121      }
122    
123      /* (non-Javadoc)
124       * @see java.lang.Object#toString()
125       */
126      @Override
127      public String toString()
128      {
129        StringBuilder buff = new StringBuilder();
130    
131        final String DELIM = ";";
132    
133        buff.append("VLA FLUX OBSERVATION;");
134        buff.append("Source=").append(Source).append(DELIM);
135        buff.append("mjad=").append(mjad).append(DELIM);
136        buff.append("correlator_mode=").append(correlator_mode).append(DELIM);
137        buff.append("el_end=").append(el_end).append(DELIM);
138        buff.append("obs_start=").append(obs_start).append(DELIM);
139        buff.append("obs_end=").append(obs_end).append(DELIM);
140        buff.append("time_obs=").append(time_obs).append(DELIM);
141        buff.append("ac_freq=").append(ac_freq).append(DELIM);
142        buff.append("bd_freq=").append(bd_freq).append(DELIM);
143        buff.append("ac_flux=").append(ac_flux).append(DELIM);
144        buff.append("ac_flux_stddev=").append(ac_flux_stddev).append(DELIM);
145        buff.append("bd_flux=").append(bd_flux).append(DELIM);
146        buff.append("bd_flux_stddev=").append(bd_flux_stddev).append(DELIM);
147    
148        return buff.toString();
149      }
150    
151      /**
152       *  Returns a copy of this observation.
153       *  <p>
154       *  If anything goes wrong during the cloning procedure,
155       *  a {@code RuntimeException} will be thrown.</p>
156       */
157      @Override
158      public VlaFluxObservation clone()
159      {
160        VlaFluxObservation clone = null;
161    
162        try
163        {
164          //This line takes care of the primitive & immutable fields properly
165          clone = (VlaFluxObservation)super.clone();
166    
167          //There are no contained objects to clone.
168        }
169        catch (Exception ex)
170        {
171          throw new RuntimeException(ex);
172        }
173    
174        return clone;
175      }
176    
177      /** Returns <i>true</i> if {@code o} is equal to this observation. */
178      @Override
179      public boolean equals(Object o)
180      {
181        //Quick exit if o is this
182        if (o == this)
183          return true;
184    
185        //Quick exit if o is null
186        if (o == null)
187          return false;
188    
189        //Quick exit if classes are different
190        if (!o.getClass().equals(this.getClass()))
191          return false;
192    
193        VlaFluxObservation other = (VlaFluxObservation)o;
194    
195        return
196          other.Source.equalsIgnoreCase(this.Source) &&
197          other.correlator_mode.equalsIgnoreCase(this.correlator_mode) &&
198          other.mjad           == this.mjad           &&
199          other.el_end         == this.el_end         &&
200          other.obs_start      == this.obs_start      &&
201          other.obs_end        == this.obs_end        &&
202          other.time_obs       == this.time_obs       &&
203          other.ac_freq        == this.ac_freq        &&
204          other.bd_freq        == this.bd_freq        &&
205          other.ac_flux        == this.ac_flux        &&
206          other.bd_flux        == this.bd_flux        &&
207          other.ac_flux_stddev == this.ac_flux_stddev &&
208          other.bd_flux_stddev == this.bd_flux_stddev;
209      }
210    
211      /** Returns a hash code value for this observation. */
212      @Override
213      public int hashCode()
214      {
215        //Taken from the Effective Java book by Joshua Bloch.
216        //The constants 17 & 37 are arbitrary & carry no meaning.
217        int result = 17;
218    
219        //You must keep this method in sync w/ equals
220    
221        result = 37 * result + Source.hashCode();
222        result = 37 * result + correlator_mode.hashCode();
223    
224        result = 37 * result + new Double(mjad).hashCode();
225        result = 37 * result + new Double(el_end).hashCode();
226        result = 37 * result + new Double(obs_start).hashCode();
227        result = 37 * result + new Double(obs_end).hashCode();
228        result = 37 * result + new Double(time_obs).hashCode();
229        result = 37 * result + new Double(ac_freq).hashCode();
230        result = 37 * result + new Double(bd_freq).hashCode();
231        result = 37 * result + new Double(ac_flux).hashCode();
232        result = 37 * result + new Double(bd_flux).hashCode();
233        result = 37 * result + new Double(ac_flux_stddev).hashCode();
234        result = 37 * result + new Double(bd_flux_stddev).hashCode();
235    
236        return result;
237      }
238    }