001 package edu.nrao.sss.model.source; 002 003 import java.math.BigDecimal; 004 import java.net.MalformedURLException; 005 import java.net.URL; 006 import java.util.*; 007 008 import edu.nrao.sss.astronomy.*; 009 import edu.nrao.sss.math.MathUtil; 010 import edu.nrao.sss.measure.*; 011 import edu.nrao.sss.util.*; 012 013 /** 014 * Helper for test classes; builds sources and their components. 015 * <p> 016 * <b>Version Info:</b> 017 * <table style="margin-left:2em"> 018 * <tr><td>$Revision: 1361 $</td></tr> 019 * <tr><td>$Date: 2008-06-19 14:21:15 -0600 (Thu, 19 Jun 2008) $</td></tr> 020 * <tr><td>$Author: dharland $</td></tr> 021 * </table></p> 022 * 023 * @author David M. Harland 024 * @since 2006-09-29 025 */ 026 public class SourceBuilder 027 { 028 private static final EnumerationUtility ENUM_UTIL = 029 EnumerationUtility.getSharedInstance(); 030 031 private Random random = new Random(System.currentTimeMillis()); 032 033 private boolean setId = false; 034 private Long nextSourceId = 1L; 035 private Long nextTableId = 1L; 036 037 private SkyPositionBuilder positionBuilder = new SkyPositionBuilder(); 038 039 //Used for coordinating multiple intervals 040 private Date timeIntervalEnd = null; 041 042 //============================================================================ 043 // PUBLIC METHODS 044 //============================================================================ 045 046 /** 047 * Tells the factory methods whether or not they should set the object 048 * identifiers. 049 */ 050 public void setIdentifiers(boolean setIds) 051 { 052 setId = setIds; 053 } 054 055 public Source makeSource(String name) 056 { 057 Source source = new Source(name == null ? makeName() : name); 058 059 if (setId) 060 source.setId(nextSourceId++); 061 062 //User info 063 Date now = new Date(); 064 source.setCreatedOn(now); 065 source.setLastUpdatedOn(now); 066 067 long id = 1L + (long)random.nextInt(1000); 068 source.setCreatedBy(id); 069 source.setLastUpdatedBy(id); 070 071 if (random.nextDouble() > 0.8) 072 source.setOriginOfInformation(makeName()); 073 074 //Aliases 075 List<String> aliases = source.getAliases(); 076 int count = random.nextInt(5); 077 for (int i=0; i < count; i++) 078 aliases.add(makeName()); 079 080 //User-defined keywords 081 Map<String, String> udvs = source.getUserDefinedValues(); 082 count = random.nextInt(5); 083 for (int i=0; i < count; i++) 084 udvs.put(makeName(), makeName()); 085 086 //Image links 087 List<SourceImageLink> images = source.getImageLinks(); 088 count = random.nextInt(5); 089 for (int i=0; i < count; i++) 090 images.add(makeImageLink()); 091 092 //Info links 093 List<URL> links = source.getLinks(); 094 count = random.nextInt(5); 095 for (int i=0; i < count; i++) 096 links.add(makeInfoLink()); 097 098 //Historical records 099 List<String> historicalRecords = source.getHistoricalRecords(); 100 count = random.nextInt(5); 101 for (int i=0; i < count; i++) 102 historicalRecords.add(makeHistoricalRecord()); 103 104 //Notes 105 List<String> notes = source.getNotes(); 106 count = random.nextInt(3); 107 for (int n=0; n < count; n++) 108 notes.add("Random note #"+n); 109 110 //Subsources 111 makeSubsource(source.getCentralSubsource()); 112 113 count = random.nextInt(2); 114 for (int ss=0; ss < count; ss++) 115 source.addSubsource(makeSubsource(null)); 116 117 return source; 118 } 119 120 public SourceLookupTable makeTable(String name) 121 { 122 SourceLookupTable table = new SourceLookupTable(name == null ? makeName() 123 : name); 124 if (setId) 125 table.setId(nextTableId++); 126 127 Calendar cal = Calendar.getInstance(); 128 129 int entryCount = 4 + random.nextInt(6); 130 for (int e=0; e < entryCount; e++) 131 { 132 table.put(cal.getTime(), makeSource(null)); 133 cal.add(Calendar.DATE, 10); 134 } 135 136 return table; 137 } 138 139 public SourceGroup makeGroup(String name) 140 { 141 SourceGroup group = new SourceGroup(null, name == null ? makeName() : name); 142 143 //Add sources 144 final int MIN_SRC_COUNT = 5; 145 int srcCount = MIN_SRC_COUNT + random.nextInt(15); 146 for (int s=0; s < srcCount; s++) 147 group.add(makeSource(null)); 148 149 Calendar cal = Calendar.getInstance(); 150 List<SourceCatalogEntry> sources = group.getAll(); 151 152 //Add a table that contains only existing sources 153 SourceLookupTable table = new SourceLookupTable("Made From Existing Sources"); 154 for (int s=0; s < MIN_SRC_COUNT; s++) 155 { 156 table.put(cal.getTime(), (Source)sources.get(s)); 157 cal.add(Calendar.DATE, 10); 158 } 159 group.add(table); 160 161 //Add a table that contains only new sources 162 group.add(makeTable("Made From New Sources")); 163 164 //Add a table that contains a mix of new & existing sources 165 table = makeTable("Made From New And Existing Sources"); 166 cal.setTime(table.getKeySet().last()); 167 for (int s=0; s < MIN_SRC_COUNT; s++) 168 { 169 cal.add(Calendar.DATE, 10); 170 table.put(cal.getTime(), (Source)sources.get(s)); 171 } 172 group.add(table); 173 174 //Notes 175 List<String> notes = group.getNotes(); 176 int count = random.nextInt(3); 177 for (int n=0; n < count; n++) 178 notes.add("Random note #"+n); 179 180 return group; 181 } 182 183 public SourceCatalog makeCatalog(String name) 184 { 185 SourceCatalog catalog = new SourceCatalog(name == null ? makeName() : name); 186 187 Date now = new Date(); 188 catalog.setCreatedOn(now); 189 catalog.setLastUpdatedOn(now); 190 191 long id = 1L + (long)random.nextInt(1000); 192 catalog.setCreatedBy(id); 193 catalog.setLastUpdatedBy(id); 194 catalog.setOwner(id); 195 196 //Add sources 197 int srcCount = 20 + random.nextInt(20); 198 for (int s=0; s < srcCount; s++) 199 catalog.addItem(makeSource(null)); 200 201 //Add a table 202 catalog.addItem(makeTable("Table 1")); 203 204 //Add groups 205 int grpCount = random.nextInt(5); 206 for (int g=0; g < grpCount; g++) 207 catalog.addGroup(makeGroup(null)); 208 209 //Notes 210 List<String> notes = catalog.getNotes(); 211 int count = random.nextInt(3); 212 for (int n=0; n < count; n++) 213 notes.add("Random note #"+n); 214 215 return catalog; 216 } 217 218 //============================================================================ 219 // SUBSOURCE 220 //============================================================================ 221 222 Subsource makeSubsource(Subsource ss) 223 { 224 if (ss == null) 225 { 226 ss = new Subsource(); 227 ss.setName(makeName()); 228 } 229 230 int count = 0; 231 232 //Position 233 ss.setPosition(makePosition()); 234 235 //Velocities 236 count = 1 + random.nextInt(2); 237 for (int v=0; v < count; v++) 238 ss.addVelocity(makeVelocity()); 239 240 //Brightnesses 241 timeIntervalEnd = null; 242 count = 1 + random.nextInt(2); 243 for (int b=0; b < count; b++) 244 ss.addBrightness(makeBrightness()); 245 246 VlaFluxObservation fluxObs = makeVlaFluxData(); 247 SourceBrightness[] sb = SourceBrightness.createBrightnesses(fluxObs); 248 ss.addBrightness(sb[0]); 249 ss.addBrightness(sb[1]); 250 251 return ss; 252 } 253 254 //============================================================================ 255 // POSITION 256 //============================================================================ 257 258 private SkyPosition makePosition() 259 { 260 return positionBuilder.makePosition(); 261 } 262 263 //Moved old position-building code to new SkyPositionBuilder class 264 265 //============================================================================ 266 // VELOCITY 267 //============================================================================ 268 269 /** Returns a velocity populated with random values. */ 270 SourceVelocity makeVelocity() 271 { 272 SourceVelocity velocity = new SourceVelocity(); 273 274 velocity.setConvention(ENUM_UTIL.getRandomValueFor(VelocityConvention.class)); 275 276 velocity.setRestFrame(ENUM_UTIL.getRandomValueFor(VelocityFrame.class)); 277 278 velocity.setValidFrequency(makeFrequencyRange()); 279 280 LinearVelocity speed = 281 new LinearVelocity(BigDecimal.valueOf(1000.0 * random.nextDouble()), 282 velocity.getConvention().getDefaultUnits()); 283 284 velocity.setRadialVelocity(speed); 285 286 return velocity; 287 } 288 289 //============================================================================ 290 // BRIGHTNESS 291 //============================================================================ 292 293 /** Returns a brightness populated with random values. */ 294 SourceBrightness makeBrightness() 295 { 296 SourceBrightness brightness; 297 298 double x = random.nextDouble(); 299 300 if (x < 0.05) brightness = makeCleanFileBrightness(); 301 else if (x < 0.10) brightness = makeFitsFileBrightness(); 302 else if (x < 0.35) brightness = makeGaussianBrightness(); 303 else if (x < 0.60) brightness = makeDiskBrightness(); 304 else if (x < 0.85) brightness = makePointBrightness(); 305 else brightness = makeUnknownBrightness(); 306 307 return brightness; 308 } 309 310 /** Simulates an observation record from the VLA. */ 311 VlaFluxObservation makeVlaFluxData() 312 { 313 VlaFluxObservation data = new VlaFluxObservation(); 314 315 data.Source = "bogus"; 316 data.mjad = 47000.0 + random.nextInt(8000); 317 data.correlator_mode = "no idea"; 318 data.el_end = random.nextInt(30); 319 data.obs_start = 12.0 * random.nextDouble(); 320 data.obs_end = 12.0 * random.nextDouble() + 12.0; 321 data.time_obs = data.obs_end - data.obs_start; 322 data.ac_freq = 50.0 + random.nextDouble(); 323 data.bd_freq = data.ac_freq + 0.05; 324 data.ac_flux = random.nextDouble() * random.nextInt(10); 325 data.bd_flux = random.nextDouble() * random.nextInt(10); 326 data.ac_flux_stddev = data.ac_flux * 0.1 * random.nextDouble(); 327 data.bd_flux_stddev = data.bd_flux * 0.1 * random.nextDouble(); 328 329 return data; 330 } 331 332 private SourceBrightness makeCleanFileBrightness() 333 { 334 CleanFileBrightness brightness = new CleanFileBrightness(); 335 336 brightness.setValidTime(makeTimeInterval(timeIntervalEnd)); 337 338 try 339 { 340 brightness.setBrightnessFile(new URL( 341 "http://lacerta.gsfc.nasa.gov/vlbi/images/J2359-3133/J2359-3133_X_2005_07_09_yyk_map.fits")); 342 } 343 catch (MalformedURLException ex) 344 { 345 brightness.setBrightnessFile(null); 346 } 347 348 return brightness; 349 } 350 351 private SourceBrightness makeFitsFileBrightness() 352 { 353 FitsFileBrightness brightness = new FitsFileBrightness(); 354 355 brightness.setValidTime(makeTimeInterval(timeIntervalEnd)); 356 357 try 358 { 359 brightness.setBrightnessFile(new URL( 360 "http://lacerta.gsfc.nasa.gov/vlbi/images/J2359-3133/J2359-3133_X_2005_07_09_yyk_vis.fits")); 361 } 362 catch (MalformedURLException ex) 363 { 364 brightness.setBrightnessFile(null); 365 } 366 367 return brightness; 368 } 369 370 private SourceBrightness makePointBrightness() 371 { 372 PointBrightness brightness = new PointBrightness(); 373 374 brightness.setValidTime(makeTimeInterval(timeIntervalEnd)); 375 376 brightness.setValidFrequency(makeFrequencyRange()); 377 brightness.setPeakFluxDensity(makeFluxDensity()); 378 brightness.setTotalFluxDensity(makeFluxDensity()); 379 brightness.setPolarization( 380 ENUM_UTIL.getRandomValueFor(StokesParameter.class)); 381 382 return brightness; 383 } 384 385 private SourceBrightness makeUnknownBrightness() 386 { 387 UnknownBrightness brightness = new UnknownBrightness(); 388 389 brightness.setValidTime(makeTimeInterval(timeIntervalEnd)); 390 391 brightness.setValidFrequency(makeFrequencyRange()); 392 brightness.setPeakFluxDensity(makeFluxDensity()); 393 brightness.setTotalFluxDensity(makeFluxDensity()); 394 brightness.setPolarization( 395 ENUM_UTIL.getRandomValueFor(StokesParameter.class)); 396 brightness.setDiameter(10.0 + 90.0 * random.nextDouble()); 397 398 return brightness; 399 } 400 401 private SourceBrightness makeGaussianBrightness() 402 { 403 GaussianBrightness brightness = new GaussianBrightness(); 404 405 brightness.setValidTime(makeTimeInterval(timeIntervalEnd)); 406 407 brightness.setValidFrequency(makeFrequencyRange()); 408 brightness.setPeakFluxDensity(makeFluxDensity()); 409 brightness.setTotalFluxDensity(makeFluxDensity()); 410 brightness.setPolarization( 411 ENUM_UTIL.getRandomValueFor(StokesParameter.class)); 412 413 double axis = 10.0 + 90.0 * random.nextDouble(); 414 brightness.setMinorAxisDiameter(axis); 415 brightness.setMajorAxisDiameter(axis * (1.0 + 3.0 * random.nextDouble())); 416 417 return brightness; 418 } 419 420 private SourceBrightness makeDiskBrightness() 421 { 422 DiskBrightness brightness = new DiskBrightness(); 423 424 brightness.setValidTime(makeTimeInterval(timeIntervalEnd)); 425 426 brightness.setValidFrequency(makeFrequencyRange()); 427 brightness.setPeakFluxDensity(makeFluxDensity()); 428 brightness.setTotalFluxDensity(makeFluxDensity()); 429 brightness.setPolarization( 430 ENUM_UTIL.getRandomValueFor(StokesParameter.class)); 431 432 double axis = 10.0 + 90.0 * random.nextDouble(); 433 brightness.setMinorAxisDiameter(axis); 434 brightness.setMajorAxisDiameter(axis * (1.0 + 3.0 * random.nextDouble())); 435 436 brightness.setLimbDarkening(-1.0 + 2.0 * random.nextDouble()); 437 438 return brightness; 439 } 440 441 //============================================================================ 442 // HELPERS 443 //============================================================================ 444 445 private static final String[] histPrefix = 446 { 447 "Once upon a time,", 448 "In the beginning", 449 "In days of old", 450 "It is written that", 451 "A long, long time ago" 452 }; 453 454 private String makeHistoricalRecord() 455 { 456 StringBuilder buff = 457 new StringBuilder(histPrefix[random.nextInt(histPrefix.length)]); 458 459 int wordCount = 3 + random.nextInt(10); 460 for (int w=1; w <= wordCount; w++) 461 buff.append(' ').append(makeName()); 462 463 buff.append('.'); 464 465 return buff.toString(); 466 } 467 468 SourceImageLink makeImageLink() 469 { 470 SourceImageLink link = 471 new SourceImageLink(makeFrequency(), 472 ENUM_UTIL.getRandomValueFor(StokesParameter.class), 473 makeUrl()); 474 475 link.setDisplayName("Image " + random.nextInt(10000)); 476 477 if (random.nextDouble() > 0.5) 478 { 479 StringBuilder buff = new StringBuilder("Hey, "); 480 int wordCount = random.nextInt(10); 481 for (int w=0; w < wordCount; w++) 482 buff.append(makeName()).append(' '); 483 buff.append(makeName()).append('!'); 484 485 link.setComments(buff.toString()); 486 } 487 488 return link; 489 } 490 491 private static final String[] URLS = 492 { 493 "http://www.google.com", 494 "http://www.yahoo.com", 495 "http://www.wikipedia.com", 496 "http://www.nrao.edu", 497 "http://www.aoc.nrao.edu/~dharland/SteveAndDave.jpg", 498 "http://www.aoc.nrao.edu/~dharland/spongeBobHat.jpg", 499 "http://www.nj.com/mets/", 500 "http://www.nj.com/giants/" 501 }; 502 503 URL makeInfoLink() 504 { 505 return makeUrl(URLS[random.nextInt(URLS.length)]); 506 } 507 508 private URL makeUrl() 509 { 510 return makeUrl("http://"+makeName()+".com/"+makeName()+".html"); 511 } 512 513 private URL makeUrl(String addr) 514 { 515 try { 516 return new URL(addr); 517 } 518 catch (Exception ex) { 519 return null; 520 } 521 } 522 523 private Frequency makeFrequency() 524 { 525 return new Frequency(new BigDecimal(0.9 + 999.0 * random.nextDouble()), 526 ENUM_UTIL.getRandomValueFor(FrequencyUnits.class)); 527 } 528 529 private FrequencyRange makeFrequencyRange() 530 { 531 FrequencyUnits freqUnits = 532 ENUM_UTIL.getRandomValueFor(FrequencyUnits.class); 533 534 BigDecimal freqLow = new BigDecimal(1.0 + 99.0 * random.nextDouble()); 535 BigDecimal freqHigh = freqLow.multiply(new BigDecimal(1.0 + 9.0 * random.nextDouble())); 536 537 //Try infinite freq once in awhile 538 if (random.nextDouble() <= 0.02) 539 freqHigh = MathUtil.POSITIVE_INFINITY; 540 541 return new FrequencyRange(new Frequency(freqLow, freqUnits), 542 new Frequency(freqHigh, freqUnits)); 543 } 544 545 private FluxDensity makeFluxDensity() 546 { 547 double r = 0.1 + 1000.0 * random.nextDouble(); 548 return new FluxDensity(BigDecimal.valueOf(r), 549 ENUM_UTIL.getRandomValueFor(FluxDensityUnits.class)); 550 } 551 552 private TimeInterval makeTimeInterval(Date startTime) 553 { 554 int year, month, day; 555 Date from; 556 Calendar cal = Calendar.getInstance(); 557 558 if (startTime == null) 559 { 560 year = 1950 + random.nextInt(55); 561 month = random.nextInt(12); 562 day = 1 + random.nextInt(27); 563 cal.set(year, month, day); 564 from = cal.getTime(); 565 } 566 else 567 { 568 from = startTime; 569 } 570 571 year = 2006 + random.nextInt(100); 572 month = random.nextInt(12); 573 day = 1 + random.nextInt(27); 574 cal.set(year, month, day); 575 timeIntervalEnd = cal.getTime(); 576 577 return new TimeInterval(from, timeIntervalEnd); 578 } 579 580 private String makeName() 581 { 582 StringBuilder srcName = new StringBuilder(); 583 584 int numChars = random.nextInt(3)+3; 585 for (int i=0; i < numChars; i++) 586 srcName.append((char)('a'+random.nextInt(25))); 587 588 return srcName.toString(); 589 } 590 }