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: aips2-request@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 36 : FluxStandard::FluxStandard(const FluxStandard::FluxScale scale) :
62 : itsFluxScale(scale),
63 : has_direction_p(false),
64 36 : interpmethod_p("")
65 : {
66 : // Default constructor
67 : // Output to private data:
68 : // itsFluxScale FluxStandard::FluxScale Flux scale (eg. BAARS)
69 : //
70 36 : }
71 :
72 : //----------------------------------------------------------------------------
73 :
74 36 : FluxStandard::~FluxStandard()
75 : {
76 : // Default destructor
77 : //
78 36 : }
79 :
80 : //----------------------------------------------------------------------------
81 :
82 47 : 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 94 : Vector<Flux<Double> > fluxes(1);
90 94 : Vector<Flux<Double> > errors(1);
91 47 : Vector<MFrequency> mfreqs(1);
92 :
93 47 : mfreqs[0] = mfreq;
94 47 : Bool success = compute(sourceName, sourceDir, mfreqs, mtime, fluxes, errors);
95 :
96 47 : value = fluxes[0];
97 47 : error = errors[0];
98 94 : return success;
99 : }
100 :
101 19 : 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 19 : Bool success = true;
109 19 : uInt nspws = mfreqs.nelements();
110 :
111 75 : for(uInt spw = 0; spw < nspws; ++spw)
112 56 : success &= compute(sourceName, sourceDir, mfreqs[spw], mtime, values[spw], errors[spw],
113 : spw == 0);
114 :
115 19 : return success;
116 : }
117 :
118 103 : 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 309 : 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 206 : CountedPtr<FluxCalcVQS> fluxStdPtr;
169 103 : Bool timeVariable(false);
170 103 : if(itsFluxScale == BAARS)
171 0 : fluxStdPtr = new NSTDS::FluxStdBaars;
172 103 : else if(itsFluxScale == PERLEY_90)
173 0 : fluxStdPtr = new NSTDS::FluxStdPerley90;
174 103 : else if(itsFluxScale == PERLEY_TAYLOR_95)
175 0 : fluxStdPtr = new NSTDS::FluxStdPerleyTaylor95;
176 103 : else if(itsFluxScale == PERLEY_TAYLOR_99)
177 8 : fluxStdPtr = new NSTDS::FluxStdPerleyTaylor99;
178 95 : else if(itsFluxScale == PERLEY_BUTLER_2010)
179 2 : fluxStdPtr = new NSTDS::FluxStdPerleyButler2010;
180 93 : else if(itsFluxScale == PERLEY_BUTLER_2013) {
181 6 : fluxStdPtr = new NSTDS::FluxStdPerleyButler2013;
182 6 : timeVariable=true; // to read from the table
183 6 : if (interpmethod_p=="") {
184 0 : ostringstream oss;
185 0 : oss << "Unset interpmethod. Please set the method first";
186 0 : throw(AipsError(String(oss)));
187 : }
188 : }
189 87 : else if(itsFluxScale == SCAIFE_HEALD_2012)
190 0 : fluxStdPtr = new NSTDS::FluxStdScaifeHeald2012;
191 87 : else if(itsFluxScale == STEVENS_REYNOLDS_2016)
192 0 : fluxStdPtr = new NSTDS::FluxStdStevensReynolds2016;
193 87 : else if(itsFluxScale == PERLEY_BUTLER_2017) {
194 87 : fluxStdPtr = new NSTDS::FluxStdPerleyButler2017;
195 87 : timeVariable=true; // to read from the table
196 87 : if (interpmethod_p=="") {
197 0 : ostringstream oss;
198 0 : oss << "Unset interpmethod. Please set the method first";
199 0 : throw(AipsError(String(oss)));
200 : }
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 103 : << "Using flux standard: " << standardName(itsFluxScale)
212 103 : << LogIO::POST;
213 :
214 : // Set the source or fail.
215 : // setSource needs J2000 coordinates for source matching by position
216 206 : MDirection sourceDirJ2000;
217 103 : 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 : }
222 : else {
223 103 : sourceDirJ2000 = sourceDir;
224 : }
225 103 : 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 103 : direction_p = fluxStdPtr->getDirection();
235 103 : has_direction_p = true;
236 : }
237 : // Compute the flux density values and their uncertainties, returning whether
238 : // or not it worked.
239 103 : if (timeVariable) return (*fluxStdPtr)(values,errors,mfreqs,mtime,interpmethod_p);
240 10 : return (*fluxStdPtr)(values, errors, mfreqs);
241 : }
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 20 : 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 43 : LogIO os(LogOrigin("FluxStandard", "computeCL"));
272 20 : uInt nspws = mfreqs.nelements();
273 20 : Bool success = false;
274 :
275 20 : if(itsFluxScale < FluxStandard::HAS_RESOLUTION_INFO){
276 13 : if(this->compute(sourceName, position, mfreqs, mtime, values, errors)){
277 : // Create a point component with the specified flux density.
278 26 : MDirection dummy;
279 13 : PointShape point(position.getValue().separation(dummy.getValue()) < 1e-7 &&
280 26 : position.getRef() == dummy.getRef() ? direction_p : position);
281 :
282 61 : for(uInt spw = 0; spw < nspws; ++spw){
283 96 : clpaths[spw] = makeComponentList(sourceName, mfreqs[spw], mtime,
284 48 : values[spw], point,
285 144 : prefix + "spw" + String::toString(spw) + "_");
286 : }
287 13 : success = true;
288 : }
289 : }
290 7 : else if(itsFluxScale == FluxStandard::SS_JPL_BUTLER){
291 14 : FluxCalc_SS_JPL_Butler ssobj(sourceName, mtime);
292 : Double angdiam;
293 :
294 21 : for(uInt spw = 0; spw < nspws; ++spw){
295 17 : ComponentType::Shape cmpshape = ssobj.compute(values[spw], errors[spw], angdiam,
296 : mfreqs[spw], spw == 0);
297 :
298 17 : switch(cmpshape){
299 14 : case ComponentType::DISK:
300 : {
301 : // Create a uniform disk component with the specified flux density.
302 28 : MDirection dummy;
303 28 : DiskShape disk;
304 :
305 : // Should we worry about tracking position?
306 28 : disk.setRefDirection(position.getValue().separation(dummy.getValue()) < 1e-7 &&
307 42 : position.getRef() == dummy.getRef() ? ssobj.getDirection() :
308 : position);
309 :
310 14 : disk.setWidthInRad(angdiam, angdiam, 0.0);
311 :
312 28 : clpaths[spw] = makeComponentList(sourceName, mfreqs[spw], mtime,
313 14 : values[spw], disk,
314 42 : prefix + "spw" + String::toString(spw) + "_");
315 14 : success = true;
316 14 : break;
317 : }
318 3 : default: {
319 6 : ostringstream oss;
320 :
321 3 : oss << ComponentType::name(cmpshape) << " is not a supported component type.";
322 3 : throw(AipsError(String(oss)));
323 : }
324 : }
325 : }
326 : }
327 34 : return success;
328 : }
329 :
330 11 : void FluxStandard::setInterpMethod(const String& interpmethod)
331 : {
332 33 : LogIO os(LogOrigin("FluxStandard", "setInterpMode"));
333 11 : if(interpmethod.contains("nearest")) {
334 11 : 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 : }
350 11 : }
351 :
352 :
353 :
354 67 : 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 201 : LogIO os(LogOrigin("FluxStandard", "makeComponentList"));
362 67 : uInt nchans = mfreqs.nelements();
363 :
364 67 : if(nchans > 1){
365 106 : Vector<MVFrequency> freqvals(nchans);
366 :
367 33644 : for(uInt c = 0; c < nchans; ++c)
368 33591 : freqvals[c] = mfreqs[c].getValue();
369 :
370 106 : TabularSpectrum ts(mfreqs[0], freqvals, values, mfreqs[0].getRef());
371 :
372 : return makeComponentList(sourceName, mfreqs[0], mtime,
373 53 : values[0], cmp, ts, prefix);
374 : }
375 : else{
376 28 : ConstantSpectrum cspectrum;
377 :
378 : return makeComponentList(sourceName, mfreqs[0], mtime,
379 14 : values[0], cmp, cspectrum, prefix);
380 : }
381 : }
382 :
383 79 : 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 237 : LogIO os(LogOrigin("FluxStandard", "makeComponentList"));
392 :
393 : // Make up the ComponentList's pathname.
394 158 : ostringstream oss;
395 79 : oss << prefix << sourceName << "_" //<< setprecision(1)
396 79 : << mfreq.get("GHz").getValue() << "GHz";
397 : // String datetime; // to nearest minute.
398 79 : oss << mtime.get("d").getValue() << "d.cl";
399 79 : 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 158 : << "\nmfreq: " << mfreq.get("GHz").getValue() << "GHz"
406 158 : << "\nmtime: " << mtime.get("d").getValue() << "d"
407 : // << "\nclpath: " << clpath << " (replaced " << nspaces
408 : // << " spaces)"
409 237 : << 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 158 : File testExistence(clpath);
416 79 : if(!testExistence.isDirectory()){
417 : // Create a component list containing cmp, and force a call to its d'tor
418 : // using scoping rules.
419 158 : ComponentList cl;
420 158 : SkyComponent skycomp(fluxval, cmp, spectrum);
421 :
422 79 : cl.add(skycomp);
423 : // Since fluxval is given for mfreq, it should update the reference frequency
424 : // set via SpectralIndex (TT)
425 79 : Int ncl=cl.nelements();
426 158 : Vector<Int> which(1);
427 79 : which(0) = ncl-1;
428 158 : MVFrequency mvfreq = MVFrequency(mfreq.get("Hz").getValue());
429 79 : cl.setRefFrequency(which,mvfreq);
430 79 : cl.rename(clpath, Table::New);
431 : }
432 158 : return clpath;
433 : }
434 :
435 : //----------------------------------------------------------------------------
436 :
437 36 : 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 36 : stdEnum = FluxStandard::PERLEY_TAYLOR_99;
453 : // stdEnum = FluxStandard::PERLEY_BUTLER_2010; // Not yet!
454 :
455 : // Local lowercase copy of input string
456 36 : String lname = name;
457 36 : lname.downcase();
458 36 : Bool matched = true;
459 :
460 : // Case input string match of:
461 : //
462 : // Perley (1990)
463 94 : if (lname.contains("perley") &&
464 58 : (lname.contains("90") || lname.contains("1990"))) {
465 0 : stdEnum = FluxStandard::PERLEY_90;
466 : }
467 : // Perley-Taylor (1995)
468 50 : else if (lname.contains("perley") && lname.contains("taylor") &&
469 14 : (lname.contains("95") || lname.contains("1995"))) {
470 0 : stdEnum = FluxStandard::PERLEY_TAYLOR_95;
471 : }
472 : // Perley-Taylor (1999)
473 43 : else if (lname.contains("perley") && lname.contains("taylor") &&
474 7 : (lname.contains("99") || lname.contains("1999"))) {
475 7 : stdEnum = FluxStandard::PERLEY_TAYLOR_99;
476 : }
477 : // Perley-Butler (2010)
478 62 : else if (lname.contains("perley") && lname.contains("butler") &&
479 33 : (lname.contains("10") || lname.contains("2010"))) {
480 11 : stdEnum = FluxStandard::PERLEY_BUTLER_2010;
481 : }
482 : // Perley-Butler (2013)
483 37 : else if (lname.contains("perley") && lname.contains("butler") &&
484 19 : (lname.contains("13") || lname.contains("2013"))) {
485 3 : stdEnum = FluxStandard::PERLEY_BUTLER_2013;
486 : }
487 : // Perley-Butler (2017)
488 23 : else if (lname.contains("perley") && lname.contains("butler") &&
489 8 : (lname.contains("17") || lname.contains("2017"))) {
490 8 : stdEnum = FluxStandard::PERLEY_BUTLER_2017;
491 : }
492 : // Scaife & Heald (2012)
493 7 : 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 7 : 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 7 : else if (lname.contains("baars")) {
504 0 : stdEnum = FluxStandard::BAARS;
505 : }
506 7 : else if(lname.contains("jpl") || lname.contains("horizons")){
507 7 : stdEnum = FluxStandard::SS_JPL_BUTLER;
508 : }
509 : else
510 0 : matched = false;
511 :
512 : // Retrieve standard descriptor
513 36 : stdName = standardName (stdEnum);
514 :
515 72 : return matched;
516 : }
517 :
518 : //----------------------------------------------------------------------------
519 :
520 139 : 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 139 : String stdName;
531 139 : 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 15 : case PERLEY_TAYLOR_99: {
545 15 : stdName = "Perley-Taylor 99";
546 15 : break;
547 : }
548 13 : case PERLEY_BUTLER_2010: {
549 13 : stdName = "Perley-Butler 2010";
550 13 : break;
551 : }
552 9 : case PERLEY_BUTLER_2013: {
553 9 : stdName = "Perley-Butler 2013";
554 9 : break;
555 : }
556 0 : case SCAIFE_HEALD_2012: {
557 0 : stdName = "Scaife-Heald 2012";
558 0 : break;
559 : }
560 95 : case PERLEY_BUTLER_2017: {
561 95 : stdName = "Perley-Butler 2017";
562 95 : break;
563 : }
564 0 : case STEVENS_REYNOLDS_2016: {
565 0 : stdName = "Stevens-Reynolds 2016";
566 0 : break;
567 : }
568 7 : case SS_JPL_BUTLER:
569 : {
570 7 : stdName = "JPL-Butler Solar System Object";
571 7 : break;
572 : }
573 0 : default:
574 : {
575 0 : stdName = "unrecognized standard";
576 : }
577 : }
578 139 : return stdName;
579 : }
580 :
581 : //----------------------------------------------------------------------------
582 : // End of FluxStandard definition.
583 : //----------------------------------------------------------------------------
584 :
585 : } //# NAMESPACE CASA - END
586 :
|