Line data Source code
1 : //# FluxStandard.cc: Implementation of FluxStandard.h
2 : //# Copyright (C) 1996,1997,1999,2001,2002
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id: FluxStandard.cc 21292 2012-11-28 14:58:19Z gervandiepen $
27 : //----------------------------------------------------------------------------
28 :
29 : #include <components/ComponentModels/FluxStandard.h>
30 : //#include <components/ComponentModels/FluxStdsQS.h>
31 : #include <components/ComponentModels/FluxStdsQS2.h>
32 : #include <components/ComponentModels/FluxCalc_SS_JPL_Butler.h>
33 : #include <components/ComponentModels/ComponentType.h>
34 : #include <components/ComponentModels/ComponentList.h>
35 : #include <components/ComponentModels/SkyComponent.h>
36 : #include <components/ComponentModels/ConstantSpectrum.h>
37 : #include <components/ComponentModels/TabularSpectrum.h>
38 : #include <components/ComponentModels/PointShape.h>
39 : #include <components/ComponentModels/DiskShape.h>
40 : #include <casacore/casa/BasicMath/Math.h>
41 : #include <casacore/casa/BasicSL/String.h>
42 : #include <casacore/casa/BasicSL/Constants.h>
43 : #include <casacore/casa/Logging/LogIO.h>
44 : #include <casacore/casa/OS/File.h>
45 : #include <casacore/casa/OS/Path.h>
46 : #include <casacore/casa/Utilities/CountedPtr.h>
47 : #include <sstream>
48 : #include <iomanip>
49 : #include <casacore/measures/Measures/MDirection.h>
50 : #include <casacore/measures/Measures/MCDirection.h>
51 : #include <casacore/measures/Measures/MeasConvert.h>
52 : #include <casacore/measures/Measures/MEpoch.h>
53 : #include <casacore/measures/Measures/MFrequency.h>
54 : #include <casacore/measures/Measures/MeasTable.h>
55 :
56 : using namespace casacore;
57 : namespace casa { //# NAMESPACE CASA - BEGIN
58 :
59 : //----------------------------------------------------------------------------
60 :
61 7 : FluxStandard::FluxStandard(const FluxStandard::FluxScale scale) :
62 7 : itsFluxScale(scale),
63 7 : has_direction_p(false),
64 7 : interpmethod_p("")
65 : {
66 : // Default constructor
67 : // Output to private data:
68 : // itsFluxScale FluxStandard::FluxScale Flux scale (eg. BAARS)
69 : //
70 7 : }
71 :
72 : //----------------------------------------------------------------------------
73 :
74 7 : FluxStandard::~FluxStandard()
75 : {
76 : // Default destructor
77 : //
78 7 : }
79 :
80 : //----------------------------------------------------------------------------
81 :
82 0 : Bool FluxStandard::compute (const String& sourceName,
83 : const MDirection& sourceDir,
84 : const MFrequency& mfreq,
85 : const MEpoch& mtime,
86 : Flux <Double>& value, Flux <Double>& error)
87 : {
88 : // I refuse to duplicate the monstrosity below to skip a short for loop.
89 0 : Vector<Flux<Double> > fluxes(1);
90 0 : Vector<Flux<Double> > errors(1);
91 0 : Vector<MFrequency> mfreqs(1);
92 :
93 0 : mfreqs[0] = mfreq;
94 0 : Bool success = compute(sourceName, sourceDir, mfreqs, mtime, fluxes, errors);
95 :
96 0 : value = fluxes[0];
97 0 : error = errors[0];
98 0 : return success;
99 0 : }
100 :
101 7 : Bool FluxStandard::compute(const String& sourceName,
102 : const MDirection& sourceDir,
103 : const Vector<Vector<MFrequency> >& mfreqs,
104 : const MEpoch& mtime,
105 : Vector<Vector<Flux<Double> > >& values,
106 : Vector<Vector<Flux<Double> > >& errors)
107 : {
108 7 : Bool success = true;
109 7 : uInt nspws = mfreqs.nelements();
110 :
111 44 : for(uInt spw = 0; spw < nspws; ++spw)
112 37 : success &= compute(sourceName, sourceDir, mfreqs[spw], mtime, values[spw], errors[spw],
113 : spw == 0);
114 :
115 7 : return success;
116 : }
117 :
118 37 : Bool FluxStandard::compute(const String& sourceName,
119 : const MDirection& sourceDir,
120 : const Vector<MFrequency>& mfreqs,
121 : const MEpoch& mtime,
122 : Vector<Flux<Double> >& values,
123 : Vector<Flux<Double> >& errors,
124 : const Bool verbose)
125 : {
126 : // Compute the flux density for a specified source at a specified set of
127 : // frequencies.
128 : // Inputs:
129 : // sourceName Source name
130 : // mfreqs Desired frequencies
131 : // mtime Desired time
132 : // Output:
133 : // values Computed total flux densities
134 : // errors Flux density uncertainties; 0 => not known.
135 : // compute false if sourceName is not recognized
136 : // as a standard reference.
137 : //
138 74 : LogIO os(LogOrigin("FluxStandard", "compute"));
139 :
140 : // There used to be a big
141 : // if(string == 'dfa" || string == "bla" || ...)
142 : // ...else if...else...
143 : // chain here, with a similar
144 : // switch(standard) statement inside each if clause. Finally, inside each
145 : // switch case came the actual calculation, usually a 2nd or 3rd order
146 : // polynomial in log(freq).
147 : //
148 : // This meant that the chain of string comparisons and case selections,
149 : // typically more expensive than the actual calculation, was repeated for
150 : // each frequency. It would have been better to do the source and standard
151 : // determination at the start, and then do the calculation like
152 : // ans = coeffs[std][src][0] + lf * (coeffs[std][src][1] + lf * ...),
153 : // but:
154 : // * std and src would naturally be enums, and thus not quite
155 : // natural indices for an array.
156 : // * The standards do not necessarily use the same set, or number,
157 : // of sources.
158 : // Both of those could be gotten around by using a std::map, but then
159 : // accessing the coeffs entails a function call. Also, it ties the
160 : // functional form of the standards to a low-order polynomial in
161 : // log(freq).
162 : //
163 : // If a function call will be used anyway, why not use a functor to cache the
164 : // (std, src) state? It is more convenient than adding a loop over
165 : // log10(frequency) inside each switch case.
166 :
167 : //CountedPtr<FluxCalcQS> fluxStdPtr;
168 37 : CountedPtr<FluxCalcVQS> fluxStdPtr;
169 37 : Bool timeVariable(false);
170 37 : if(itsFluxScale == BAARS)
171 0 : fluxStdPtr = new NSTDS::FluxStdBaars;
172 37 : else if(itsFluxScale == PERLEY_90)
173 0 : fluxStdPtr = new NSTDS::FluxStdPerley90;
174 37 : else if(itsFluxScale == PERLEY_TAYLOR_95)
175 0 : fluxStdPtr = new NSTDS::FluxStdPerleyTaylor95;
176 37 : else if(itsFluxScale == PERLEY_TAYLOR_99)
177 5 : fluxStdPtr = new NSTDS::FluxStdPerleyTaylor99;
178 32 : else if(itsFluxScale == PERLEY_BUTLER_2010)
179 0 : fluxStdPtr = new NSTDS::FluxStdPerleyButler2010;
180 32 : else if(itsFluxScale == PERLEY_BUTLER_2013) {
181 0 : fluxStdPtr = new NSTDS::FluxStdPerleyButler2013;
182 0 : timeVariable=true; // to read from the table
183 0 : if (interpmethod_p=="") {
184 0 : ostringstream oss;
185 0 : oss << "Unset interpmethod. Please set the method first";
186 0 : throw(AipsError(String(oss)));
187 0 : }
188 : }
189 32 : else if(itsFluxScale == SCAIFE_HEALD_2012)
190 0 : fluxStdPtr = new NSTDS::FluxStdScaifeHeald2012;
191 32 : else if(itsFluxScale == STEVENS_REYNOLDS_2016)
192 0 : fluxStdPtr = new NSTDS::FluxStdStevensReynolds2016;
193 32 : else if(itsFluxScale == PERLEY_BUTLER_2017) {
194 32 : fluxStdPtr = new NSTDS::FluxStdPerleyButler2017;
195 32 : timeVariable=true; // to read from the table
196 32 : if (interpmethod_p=="") {
197 0 : ostringstream oss;
198 0 : oss << "Unset interpmethod. Please set the method first";
199 0 : throw(AipsError(String(oss)));
200 0 : }
201 : }
202 : else{
203 0 : if(verbose)
204 : os << LogIO::SEVERE
205 0 : << "Flux standard " << standardName(itsFluxScale)
206 : << " cannot be used this way. (Does it require a time?)"
207 0 : << LogIO::POST;
208 0 : return false;
209 : }
210 : os << LogIO::DEBUG1
211 37 : << "Using flux standard: " << standardName(itsFluxScale)
212 37 : << LogIO::POST;
213 :
214 : // Set the source or fail.
215 : // setSource needs J2000 coordinates for source matching by position
216 37 : MDirection sourceDirJ2000;
217 37 : if (sourceDir.getRefString()!="J2000") {
218 0 : MeasFrame frame(mtime);
219 0 : MDirection::Ref outref(MDirection::J2000, frame);
220 0 : sourceDirJ2000 = MDirection::Convert(sourceDir, outref)();
221 0 : }
222 : else {
223 37 : sourceDirJ2000 = sourceDir;
224 : }
225 37 : if(!fluxStdPtr->setSource(sourceName,sourceDirJ2000)){
226 0 : if(verbose)
227 : os << LogIO::SEVERE
228 0 : << sourceName << " is not recognized by " << standardName(itsFluxScale)
229 0 : << LogIO::POST;
230 : // TODO?: Look for another standard that does recognize sourceName?
231 0 : return false;
232 : }
233 : else{
234 37 : direction_p = fluxStdPtr->getDirection();
235 37 : has_direction_p = true;
236 : }
237 : // Compute the flux density values and their uncertainties, returning whether
238 : // or not it worked.
239 37 : if (timeVariable) return (*fluxStdPtr)(values,errors,mfreqs,mtime,interpmethod_p);
240 5 : return (*fluxStdPtr)(values, errors, mfreqs);
241 37 : }
242 :
243 : // Like compute, but it also saves a ComponentList for the source to disk
244 : // and returns the name (sourceName_mfreqGHzmtime.cl), making it suitable for
245 : // resolved sources.
246 : // mtime is ignored for nonvariable objects.
247 : // Solar System objects are typically resolved and variable!
248 : //
249 : // Currently each component "list" only has 1 or 0 components.
250 : //
251 : // Inputs:
252 : // sourceName const String& Source name
253 : // mfreqs const Vector<MFrequency>& Desired frequencies
254 : // mtime const MEpoch& Desired time
255 : // Output:
256 : // values Vector<Flux>& Computed total flux densities
257 : // errors Vector<Flux>& Flux density errors;
258 : // (0 => unknown).
259 : // clnames Vector<String>& Pathnames of the
260 : // ComponentLists. "" if no
261 : // components were made.
262 : //
263 7 : Bool FluxStandard::computeCL(const String& sourceName,
264 : const Vector<Vector<MFrequency> >& mfreqs,
265 : const MEpoch& mtime, const MDirection& position,
266 : Vector<Vector<Flux<Double> > >& values,
267 : Vector<Vector<Flux<Double> > >& errors,
268 : Vector<String>& clpaths,
269 : const String& prefix)
270 : {
271 14 : LogIO os(LogOrigin("FluxStandard", "computeCL"));
272 7 : uInt nspws = mfreqs.nelements();
273 7 : Bool success = false;
274 :
275 7 : if(itsFluxScale < FluxStandard::HAS_RESOLUTION_INFO){
276 7 : if(this->compute(sourceName, position, mfreqs, mtime, values, errors)){
277 : // Create a point component with the specified flux density.
278 7 : MDirection dummy;
279 7 : PointShape point(position.getValue().separation(dummy.getValue()) < 1e-7 &&
280 14 : position.getRef() == dummy.getRef() ? direction_p : position);
281 :
282 44 : for(uInt spw = 0; spw < nspws; ++spw){
283 74 : clpaths[spw] = makeComponentList(sourceName, mfreqs[spw], mtime,
284 37 : values[spw], point,
285 111 : prefix + "spw" + String::toString(spw) + "_");
286 : }
287 7 : success = true;
288 7 : }
289 : }
290 0 : else if(itsFluxScale == FluxStandard::SS_JPL_BUTLER){
291 0 : FluxCalc_SS_JPL_Butler ssobj(sourceName, mtime);
292 : Double angdiam;
293 :
294 0 : for(uInt spw = 0; spw < nspws; ++spw){
295 0 : ComponentType::Shape cmpshape = ssobj.compute(values[spw], errors[spw], angdiam,
296 : mfreqs[spw], spw == 0);
297 :
298 0 : switch(cmpshape){
299 0 : case ComponentType::DISK:
300 : {
301 : // Create a uniform disk component with the specified flux density.
302 0 : MDirection dummy;
303 0 : DiskShape disk;
304 :
305 : // Should we worry about tracking position?
306 0 : disk.setRefDirection(position.getValue().separation(dummy.getValue()) < 1e-7 &&
307 0 : position.getRef() == dummy.getRef() ? ssobj.getDirection() :
308 : position);
309 :
310 0 : disk.setWidthInRad(angdiam, angdiam, 0.0);
311 :
312 0 : clpaths[spw] = makeComponentList(sourceName, mfreqs[spw], mtime,
313 0 : values[spw], disk,
314 0 : prefix + "spw" + String::toString(spw) + "_");
315 0 : success = true;
316 0 : break;
317 0 : }
318 0 : default: {
319 0 : ostringstream oss;
320 :
321 0 : oss << ComponentType::name(cmpshape) << " is not a supported component type.";
322 0 : throw(AipsError(String(oss)));
323 0 : }
324 : }
325 : }
326 0 : }
327 7 : return success;
328 7 : }
329 :
330 2 : void FluxStandard::setInterpMethod(const String& interpmethod)
331 : {
332 4 : LogIO os(LogOrigin("FluxStandard", "setInterpMode"));
333 2 : if(interpmethod.contains("nearest")) {
334 2 : interpmethod_p = "nearestNeighbour";
335 : }
336 0 : else if(interpmethod.contains("linear")) {
337 0 : interpmethod_p = "linear";
338 : }
339 0 : else if(interpmethod.contains("cubic")) {
340 0 : interpmethod_p = "cubic";
341 : }
342 0 : else if(interpmethod.contains("spline")) {
343 0 : interpmethod_p = "spline";
344 : }
345 : else {
346 0 : ostringstream oss;
347 0 : oss << interpmethod << " is not a supported interpolation method";
348 0 : throw(AipsError(String(oss)));
349 0 : }
350 2 : }
351 :
352 :
353 :
354 37 : String FluxStandard::makeComponentList(const String& sourceName,
355 : const Vector<MFrequency>& mfreqs,
356 : const MEpoch& mtime,
357 : const Vector<Flux<Double> >& values,
358 : const ComponentShape& cmp,
359 : const String& prefix)
360 : {
361 74 : LogIO os(LogOrigin("FluxStandard", "makeComponentList"));
362 37 : uInt nchans = mfreqs.nelements();
363 :
364 37 : if(nchans > 1){
365 32 : Vector<MVFrequency> freqvals(nchans);
366 :
367 2080 : for(uInt c = 0; c < nchans; ++c)
368 2048 : freqvals[c] = mfreqs[c].getValue();
369 :
370 32 : TabularSpectrum ts(mfreqs[0], freqvals, values, mfreqs[0].getRef());
371 :
372 : return makeComponentList(sourceName, mfreqs[0], mtime,
373 32 : values[0], cmp, ts, prefix);
374 32 : }
375 : else{
376 5 : ConstantSpectrum cspectrum;
377 :
378 : return makeComponentList(sourceName, mfreqs[0], mtime,
379 5 : values[0], cmp, cspectrum, prefix);
380 5 : }
381 37 : }
382 :
383 37 : String FluxStandard::makeComponentList(const String& sourceName,
384 : const MFrequency& mfreq,
385 : const MEpoch& mtime,
386 : const Flux<Double>& fluxval,
387 : const ComponentShape& cmp,
388 : const SpectralModel& spectrum,
389 : const String& prefix)
390 : {
391 74 : LogIO os(LogOrigin("FluxStandard", "makeComponentList"));
392 :
393 : // Make up the ComponentList's pathname.
394 37 : ostringstream oss;
395 37 : oss << prefix << sourceName << "_" //<< setprecision(1)
396 37 : << mfreq.get("GHz").getValue() << "GHz";
397 : // String datetime; // to nearest minute.
398 37 : oss << mtime.get("d").getValue() << "d.cl";
399 37 : String clpath(oss);
400 : // allow space as a part of the path
401 : //uInt nspaces = clpath.gsub(" ", "_");
402 :
403 : os << LogIO::DEBUG1
404 : << "sourceName: " << sourceName
405 74 : << "\nmfreq: " << mfreq.get("GHz").getValue() << "GHz"
406 74 : << "\nmtime: " << mtime.get("d").getValue() << "d"
407 : // << "\nclpath: " << clpath << " (replaced " << nspaces
408 : // << " spaces)"
409 111 : << LogIO::POST;
410 :
411 : // If clpath already exists on disk, assume our work here is done, and don't
412 : // try to redo it. It's not just laziness - it avoids collisions.
413 : // This happens when a continuum spw has the same center freq as a spectral
414 : // spw that is not being scaled by channel.
415 37 : File testExistence(clpath);
416 37 : if(!testExistence.isDirectory()){
417 : // Create a component list containing cmp, and force a call to its d'tor
418 : // using scoping rules.
419 37 : ComponentList cl;
420 37 : SkyComponent skycomp(fluxval, cmp, spectrum);
421 :
422 37 : cl.add(skycomp);
423 : // Since fluxval is given for mfreq, it should update the reference frequency
424 : // set via SpectralIndex (TT)
425 37 : Int ncl=cl.nelements();
426 37 : Vector<Int> which(1);
427 37 : which(0) = ncl-1;
428 74 : MVFrequency mvfreq = MVFrequency(mfreq.get("Hz").getValue());
429 37 : cl.setRefFrequency(which,mvfreq);
430 37 : cl.rename(clpath, Table::New);
431 37 : }
432 74 : return clpath;
433 37 : }
434 :
435 : //----------------------------------------------------------------------------
436 :
437 7 : Bool FluxStandard::matchStandard (const String& name,
438 : FluxStandard::FluxScale& stdEnum,
439 : String& stdName)
440 : {
441 : // Match an input string to a standard/catalog enum and descriptor
442 : // Inputs:
443 : // name const String& Input string
444 : // Output:
445 : // stdEnum FluxStandard::FluxScale Matching enum
446 : // stdName String Standard descriptor for
447 : // the matching enum.
448 : // matchStandard Bool true if matched; false
449 : // if default returned.
450 : //
451 : // Set default enum
452 7 : stdEnum = FluxStandard::PERLEY_TAYLOR_99;
453 : // stdEnum = FluxStandard::PERLEY_BUTLER_2010; // Not yet!
454 :
455 : // Local lowercase copy of input string
456 7 : String lname = name;
457 7 : lname.downcase();
458 7 : Bool matched = true;
459 :
460 : // Case input string match of:
461 : //
462 : // Perley (1990)
463 21 : if (lname.contains("perley") &&
464 14 : (lname.contains("90") || lname.contains("1990"))) {
465 0 : stdEnum = FluxStandard::PERLEY_90;
466 : }
467 : // Perley-Taylor (1995)
468 17 : else if (lname.contains("perley") && lname.contains("taylor") &&
469 10 : (lname.contains("95") || lname.contains("1995"))) {
470 0 : stdEnum = FluxStandard::PERLEY_TAYLOR_95;
471 : }
472 : // Perley-Taylor (1999)
473 12 : else if (lname.contains("perley") && lname.contains("taylor") &&
474 5 : (lname.contains("99") || lname.contains("1999"))) {
475 5 : stdEnum = FluxStandard::PERLEY_TAYLOR_99;
476 : }
477 : // Perley-Butler (2010)
478 6 : else if (lname.contains("perley") && lname.contains("butler") &&
479 4 : (lname.contains("10") || lname.contains("2010"))) {
480 0 : stdEnum = FluxStandard::PERLEY_BUTLER_2010;
481 : }
482 : // Perley-Butler (2013)
483 6 : else if (lname.contains("perley") && lname.contains("butler") &&
484 4 : (lname.contains("13") || lname.contains("2013"))) {
485 0 : stdEnum = FluxStandard::PERLEY_BUTLER_2013;
486 : }
487 : // Perley-Butler (2017)
488 4 : else if (lname.contains("perley") && lname.contains("butler") &&
489 2 : (lname.contains("17") || lname.contains("2017"))) {
490 2 : stdEnum = FluxStandard::PERLEY_BUTLER_2017;
491 : }
492 : // Scaife & Heald (2012)
493 0 : else if (lname.contains("scaife") && lname.contains("heald") &&
494 0 : (lname.contains("12") || lname.contains("2012"))) {
495 0 : stdEnum = FluxStandard::SCAIFE_HEALD_2012;
496 : }
497 : // Stevens-Reynolds (2016)
498 0 : else if (lname.contains("stevens") && lname.contains("reynolds") &&
499 0 : (lname.contains("16") || lname.contains("2016"))) {
500 0 : stdEnum = FluxStandard::STEVENS_REYNOLDS_2016;
501 : }
502 : // Baars
503 0 : else if (lname.contains("baars")) {
504 0 : stdEnum = FluxStandard::BAARS;
505 : }
506 0 : else if(lname.contains("jpl") || lname.contains("horizons")){
507 0 : stdEnum = FluxStandard::SS_JPL_BUTLER;
508 : }
509 : else
510 0 : matched = false;
511 :
512 : // Retrieve standard descriptor
513 7 : stdName = standardName (stdEnum);
514 :
515 7 : return matched;
516 7 : }
517 :
518 : //----------------------------------------------------------------------------
519 :
520 44 : String FluxStandard::standardName (const FluxStandard::FluxScale& stdEnum)
521 : {
522 : // Return the standard descriptor for a specified standard/catalog enum
523 : // Inputs:
524 : // stdEnum FluxStandard::FluxScale Standard/catalog enum
525 : // Output:
526 : // standardName String Standard descriptor
527 : //
528 : // Case scale enum of:
529 : //
530 44 : String stdName;
531 44 : switch (stdEnum) {
532 0 : case BAARS: {
533 0 : stdName = "Baars";
534 0 : break;
535 : }
536 0 : case PERLEY_90: {
537 0 : stdName = "Perley 90";
538 0 : break;
539 : }
540 0 : case PERLEY_TAYLOR_95: {
541 0 : stdName = "Perley-Taylor 95";
542 0 : break;
543 : }
544 10 : case PERLEY_TAYLOR_99: {
545 10 : stdName = "Perley-Taylor 99";
546 10 : break;
547 : }
548 0 : case PERLEY_BUTLER_2010: {
549 0 : stdName = "Perley-Butler 2010";
550 0 : break;
551 : }
552 0 : case PERLEY_BUTLER_2013: {
553 0 : stdName = "Perley-Butler 2013";
554 0 : break;
555 : }
556 0 : case SCAIFE_HEALD_2012: {
557 0 : stdName = "Scaife-Heald 2012";
558 0 : break;
559 : }
560 34 : case PERLEY_BUTLER_2017: {
561 34 : stdName = "Perley-Butler 2017";
562 34 : break;
563 : }
564 0 : case STEVENS_REYNOLDS_2016: {
565 0 : stdName = "Stevens-Reynolds 2016";
566 0 : break;
567 : }
568 0 : case SS_JPL_BUTLER:
569 : {
570 0 : stdName = "JPL-Butler Solar System Object";
571 0 : break;
572 : }
573 0 : default:
574 : {
575 0 : stdName = "unrecognized standard";
576 : }
577 : }
578 44 : return stdName;
579 0 : }
580 :
581 : //----------------------------------------------------------------------------
582 : // End of FluxStandard definition.
583 : //----------------------------------------------------------------------------
584 :
585 : } //# NAMESPACE CASA - END
586 :
|