001 package edu.nrao.sss.model.source; 002 003 import java.math.BigDecimal; 004 005 import javax.xml.bind.annotation.XmlType; 006 007 import edu.nrao.sss.astronomy.VelocityConvention; 008 import edu.nrao.sss.astronomy.VelocityFrame; 009 import edu.nrao.sss.measure.Frequency; 010 import edu.nrao.sss.measure.FrequencyRange; 011 import edu.nrao.sss.measure.LinearVelocity; 012 013 /** 014 * The velocity of an astronomical source. 015 * <p> 016 * <b>Version Info:</b> 017 * <table style="margin-left:2em"> 018 * <tr><td>$Revision: 1710 $</td> 019 * <tr><td>$Date: 2008-11-14 11:54:07 -0700 (Fri, 14 Nov 2008) $</td> 020 * <tr><td>$Author: dharland $</td> 021 * </table></p> 022 * 023 * @author David M. Harland 024 * @since 2006-03-24 025 */ 026 @XmlType 027 public class SourceVelocity 028 implements Cloneable, Comparable<SourceVelocity> 029 { 030 private VelocityConvention convention; 031 private VelocityFrame restFrame; 032 private FrequencyRange validFrequency; 033 private LinearVelocity radialVelocity; 034 035 /** Creates a new instance. */ 036 public SourceVelocity() 037 { 038 validFrequency = new FrequencyRange(); 039 radialVelocity = new LinearVelocity(); 040 041 initialize(); 042 } 043 044 private void initialize() 045 { 046 convention = VelocityConvention.getDefault(); 047 restFrame = VelocityFrame.getDefault(); 048 049 radialVelocity.set(BigDecimal.ZERO, convention.getDefaultUnits()); 050 } 051 052 /** Returns this velocity to its initial state. */ 053 public void reset() 054 { 055 initialize(); 056 057 validFrequency.reset(); 058 } 059 060 /** 061 * Sets the convention used for this velocity. 062 * <p> 063 * If {@code newConvention} is <i>null</i>, it will be treated as 064 * a non-null default type.</p> 065 * 066 * @param newConvention the measurement convention used by this velocity. 067 */ 068 public void setConvention(VelocityConvention newConvention) 069 { 070 if (newConvention == null) 071 newConvention = VelocityConvention.getDefault(); 072 073 convention = newConvention; 074 } 075 076 /** 077 * Returns the convention used for this velocity. 078 * 079 * @return the velocity convention used by this source velocity. 080 */ 081 public VelocityConvention getConvention() 082 { 083 return convention; 084 } 085 086 /** 087 * Sets the frame of rest used for this velocity. 088 * 089 * @param restFrame the frame of rest used for this velocity. 090 */ 091 public void setRestFrame(VelocityFrame restFrame) 092 { 093 this.restFrame = restFrame; 094 } 095 096 /** 097 * Returns the frame of rest used for this velocity. 098 * 099 * @return the frame of rest used for this velocity. 100 */ 101 public VelocityFrame getRestFrame() 102 { 103 return restFrame; 104 } 105 106 /** 107 * Sets the speed of this source velocity. 108 * Note that {@code newSpeed} will be referenced internally by this object, 109 * so any changes made to it after this call will be reflected herein. 110 * <p> 111 * If {@code newSpeed} is <i>null</i>, this velocity's speed will be set 112 * to zero, with the units set according to the current 113 * {@link #getConvention() convention}.</p> 114 * 115 * @param newSpeed 116 * the new radial velocity for this source velocity. 117 */ 118 public void setRadialVelocity(LinearVelocity newSpeed) 119 { 120 if (newSpeed != null) 121 radialVelocity = newSpeed; 122 else 123 radialVelocity.set(BigDecimal.ZERO, convention.getDefaultUnits()); 124 } 125 126 /** 127 * Returns the speed of this source velocity. 128 * <p> 129 * The return value is guaranteed to be non-null. It is 130 * also the speed that is held internally by this source 131 * velocity, so any changes made to the returned speed 132 * will be reflected in this object.</p> 133 * 134 * @return 135 * the radial velocity for this source velocity. 136 */ 137 public LinearVelocity getRadialVelocity() 138 { 139 return radialVelocity; 140 } 141 142 /** 143 * Sets the valid frequency range for this source velocity, 144 * assuming the source is at rest. 145 * <p> 146 * If {@code newRange} is <i>null</i>, this velocity's frequency 147 * range will be set to all (positive) frequencies.</p> 148 * 149 * @param newRange the frequency range for this source velocity. 150 */ 151 public void setValidFrequency(FrequencyRange newRange) 152 { 153 validFrequency = (newRange == null) ? new FrequencyRange() : newRange; 154 } 155 156 /** 157 * Returns the frequency range for which this source velocity 158 * is valid. 159 * <p> 160 * The return value is guaranteed to be non-null. It is 161 * also the range that is held internally by this source 162 * velocity, so any changes made to the returned range 163 * will be reflected in this object.</p> 164 * 165 * @return the valid frequency range for this source velocity. 166 */ 167 public FrequencyRange getValidFrequency() 168 { 169 return validFrequency; 170 } 171 172 /** 173 * Returns an observed frequency based on a rest frequency and the 174 * convention and magnitude of this source velocity. 175 * 176 * @param restFreq 177 * a rest frequency that is to be transformed to 178 * another value based on this velocity. 179 * 180 * @return 181 * an observed frequency based on {@code restFreq} and this velocity. 182 */ 183 public Frequency calcShiftedFrequency(Frequency restFreq) 184 { 185 BigDecimal velocityInConventionalUnits = 186 radialVelocity.toUnits(convention.getDefaultUnits()); 187 188 BigDecimal factor = 189 convention.getFrequencyShiftFactor(velocityInConventionalUnits); 190 191 return restFreq.clone().multiplyBy(factor); 192 } 193 194 @Override 195 public String toString() 196 { 197 final String DELIM = ";"; 198 StringBuilder buff = new StringBuilder(); 199 200 buff.append("velocity = ").append(radialVelocity).append(DELIM); 201 buff.append(" frame = ").append(restFrame).append(DELIM); 202 buff.append(" convention = ").append(convention).append(DELIM); 203 buff.append(" frequency = ").append(validFrequency).append(DELIM); 204 205 return buff.toString(); 206 } 207 208 /** 209 * Returns a source velocity that is equal to this one. 210 * <p> 211 * If anything goes wrong during the cloning procedure, 212 * a {@code RuntimeException} will be thrown.</p> 213 */ 214 @Override 215 public SourceVelocity clone() 216 { 217 SourceVelocity clone = null; 218 219 try 220 { 221 //This line takes care of the primitive & immutable fields properly 222 clone = (SourceVelocity)super.clone(); 223 224 clone.setValidFrequency(this.getValidFrequency().clone()); 225 clone.setRadialVelocity(this.radialVelocity.clone()); 226 } 227 catch (Exception ex) 228 { 229 throw new RuntimeException(ex); 230 } 231 232 return clone; 233 } 234 235 /** Returns <i>true</i> if {@code o} is equal to this source velocity. */ 236 @Override 237 public boolean equals(Object o) 238 { 239 //Quick exit if o is this 240 if (o == this) 241 return true; 242 243 //Quick exit if o is null 244 if (o == null) 245 return false; 246 247 //Quick exit if classes are different 248 if (!o.getClass().equals(this.getClass())) 249 return false; 250 251 SourceVelocity other = (SourceVelocity)o; 252 253 //Separated the tests for easier debugging 254 if (!other.restFrame.equals(this.restFrame)) 255 return false; 256 257 if (!other.validFrequency.equals(this.validFrequency)) 258 return false; 259 260 if (!other.getRadialVelocity().equals(this.getRadialVelocity())) 261 return false; 262 263 return true; 264 } 265 266 /** Returns a hash code value for this source velocity. */ 267 @Override 268 public int hashCode() 269 { 270 //Taken from the Effective Java book by Joshua Bloch. 271 //The constants 17 & 37 are arbitrary & carry no meaning. 272 int result = 17; 273 274 result = 37 * result + radialVelocity.hashCode(); 275 result = 37 * result + restFrame.hashCode(); 276 result = 37 * result + validFrequency.hashCode(); 277 278 return result; 279 } 280 281 /** 282 * Compares this velocity to {@code other} for order. 283 * <p> 284 * One velocity is deemed to be "less than" the other if it has 285 * a valid frequency range that is less than that of the other. 286 * In the case that two velocities have the same valid frequency range, 287 * the rest frame is used as a tie-breaker. If these are the 288 * same the velocity value, in km/s, is compared next. 289 * If no differences are found, the return value is zero.</p> 290 * 291 * @param other the velocity to which this one is compared. 292 * 293 * @return a negative integer, zero, or a positive integer as this velocity 294 * is less than, equal to, or greater than the other velocity. 295 */ 296 public int compareTo(SourceVelocity other) 297 { 298 //First compare the valid frequency ranges 299 int answer = this.validFrequency.compareTo(other.validFrequency); 300 if (answer != 0) 301 return answer; 302 303 //Rest frame 304 answer = this.restFrame.compareTo(other.restFrame); 305 if (answer != 0) 306 return answer; 307 308 //Velocity 309 answer = this.getRadialVelocity().compareTo(other.getRadialVelocity()); 310 if (answer != 0) 311 return answer; 312 313 //No differences found 314 return 0; 315 } 316 }