Line data Source code
1 : //# SpectralIndex.cc:
2 : //# Copyright (C) 1998,1999,2000,2003
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: SpectralIndex.cc 21292 2012-11-28 14:58:19Z gervandiepen $
27 :
28 : #include <components/ComponentModels/PowerLogPoly.h>
29 : #include <casacore/casa/Arrays/Vector.h>
30 : #include <casacore/casa/Arrays/ArrayLogical.h>
31 : #include <casacore/casa/Containers/RecordInterface.h>
32 : #include <casacore/casa/Exceptions/Error.h>
33 : #include <casacore/casa/Arrays/IPosition.h>
34 : #include <casacore/casa/Logging/LogIO.h>
35 : #include <casacore/casa/Logging/LogOrigin.h>
36 : #include <casacore/casa/BasicMath/Math.h>
37 : #include <casacore/measures/Measures/MFrequency.h>
38 : #include <casacore/measures/Measures/MCFrequency.h>
39 : #include <casacore/measures/Measures/MeasConvert.h>
40 : #include <casacore/casa/Quanta/MVFrequency.h>
41 : #include <casacore/casa/Quanta/Quantum.h>
42 : #include <casacore/casa/Utilities/Assert.h>
43 : #include <casacore/casa/Utilities/DataType.h>
44 : #include <casacore/casa/BasicSL/String.h>
45 :
46 : using namespace casacore;
47 : namespace casa { //# NAMESPACE CASA - BEGIN
48 :
49 0 : PowerLogPoly::PowerLogPoly() : SpectralModel() {}
50 :
51 0 : PowerLogPoly::PowerLogPoly(
52 : const MFrequency& refFreq, const Vector<Double> coeffs
53 0 : ) : SpectralModel(refFreq), _coeffs(coeffs.copy()),
54 0 : _errors(Vector<Double>(coeffs.size(), 0)) {}
55 :
56 0 : PowerLogPoly::PowerLogPoly(const PowerLogPoly& other)
57 0 : : SpectralModel(other), _coeffs(other._coeffs.copy()),
58 0 : _errors(other._errors.copy()) {}
59 :
60 0 : PowerLogPoly::~PowerLogPoly() {}
61 :
62 0 : PowerLogPoly& PowerLogPoly::operator=(const PowerLogPoly& other) {
63 0 : if (this != &other) {
64 0 : SpectralModel::operator=(other);
65 0 : _coeffs.resize(other._coeffs.size());
66 0 : _coeffs = other._coeffs.copy();
67 0 : _errors.resize(other._errors.size());
68 0 : _errors = other._errors.copy();
69 : }
70 0 : return *this;
71 : }
72 :
73 0 : ComponentType::SpectralShape PowerLogPoly::type() const {
74 0 : return ComponentType::PLP;
75 : }
76 :
77 0 : Double PowerLogPoly::_getNu0(const MFrequency::Ref& refFrame) const {
78 0 : const MFrequency& refFreq(refFrequency());
79 0 : const auto nu0 = refFrame == refFreq.getRef()
80 0 : ? refFreq.getValue().getValue()
81 0 : : MFrequency::Convert(refFreq, refFrame)().getValue().getValue();
82 0 : ThrowIf(nu0 <= 0.0, "the reference frequency is zero or negative");
83 0 : return nu0;
84 : }
85 :
86 0 : Double PowerLogPoly::_getIntensityRatio(Double x) const {
87 0 : const auto logx = log(x);
88 0 : Double exponent = 0;
89 0 : for(uInt i=0; i<_coeffs.size(); ++i) {
90 0 : if (i == 0) {
91 0 : exponent = _coeffs[i];
92 : }
93 0 : else if (i == 1) {
94 0 : exponent += _coeffs[i] * logx;
95 : }
96 0 : else if (i == 2) {
97 0 : exponent += _coeffs[i] * logx * logx;
98 : }
99 : else {
100 0 : exponent += _coeffs[i] * pow(logx, i);
101 : }
102 : }
103 0 : return pow(x, exponent);
104 : }
105 :
106 0 : Double PowerLogPoly::sample(const MFrequency& centerFreq) const {
107 0 : const auto x = centerFreq.getValue()/_getNu0(centerFreq.getRef());
108 0 : return _getIntensityRatio(x);
109 : }
110 :
111 0 : void PowerLogPoly::sampleStokes(
112 : const MFrequency& centerFreq, Vector<Double>& iquv
113 : ) const {
114 0 : ThrowIf(iquv.size() != 4, "Four stokes parameters in iquv are expected");
115 0 : iquv[0] *= sample(centerFreq);
116 : // TODO add full stokes support.
117 0 : }
118 :
119 0 : void PowerLogPoly::sample(
120 : Vector<Double>& scale, const Vector<MFrequency::MVType>& frequencies,
121 : const MFrequency::Ref& refFrame
122 : ) const {
123 0 : const auto nSamples = frequencies.size();
124 0 : ThrowIf(
125 : scale.size() != nSamples,
126 : "A Vector of length " + String::toString(nSamples) + " is required"
127 : );
128 0 : const auto nu0 = _getNu0(refFrame);
129 0 : for (uInt i=0; i<nSamples; ++i) {
130 0 : scale[i] = _getIntensityRatio(frequencies[i].getValue()/nu0);
131 : }
132 0 : }
133 :
134 0 : void PowerLogPoly::sampleStokes(
135 : Matrix<Double>& iquv, const Vector<MFrequency::MVType>& frequencies,
136 : const MFrequency::Ref& refFrame
137 : ) const {
138 0 : ThrowIf(
139 : iquv.shape() != IPosition(2, frequencies.size(), 4),
140 : "Incorrect Matrix shape"
141 : );
142 0 : const auto nSamples = frequencies.size();
143 0 : const auto nu0 = _getNu0(refFrame);
144 0 : for (uInt i=0; i<nSamples; ++i) {
145 0 : iquv(i, 0) *= _getIntensityRatio(frequencies[i].getValue()/nu0);
146 : }
147 : // TODO full polarization implementation to come
148 0 : }
149 :
150 0 : SpectralModel* PowerLogPoly::clone() const {
151 0 : SpectralModel* tmpPtr = new PowerLogPoly(*this);
152 0 : AlwaysAssert(tmpPtr, AipsError);
153 0 : return tmpPtr;
154 : }
155 :
156 0 : uInt PowerLogPoly::nParameters() const {
157 0 : return _coeffs.size();
158 : }
159 :
160 0 : void PowerLogPoly::setParameters(const Vector<Double>& newSpectralParms) {
161 0 : _coeffs.resize(0);
162 0 : _coeffs = newSpectralParms.copy();
163 0 : const auto s = _coeffs.size();
164 0 : if (_errors.size() != s) {
165 0 : _errors.resize(s, True);
166 : }
167 0 : }
168 :
169 0 : Vector<Double> PowerLogPoly::parameters() const {
170 0 : return _coeffs.copy();
171 : }
172 :
173 0 : void PowerLogPoly::setErrors(const Vector<Double>& newSpectralErrs) {
174 0 : ThrowIf(anyLT(newSpectralErrs, 0.0), "The errors must be non-negative.");
175 0 : _errors.resize(newSpectralErrs.size());
176 0 : _errors = newSpectralErrs.copy();
177 0 : const auto s = _errors.size();
178 0 : if (_coeffs.size() != s) {
179 0 : _coeffs.resize(s, True);
180 : }
181 0 : }
182 :
183 0 : Vector<Double> PowerLogPoly::errors() const {
184 0 : return _errors.copy();
185 : }
186 :
187 0 : Bool PowerLogPoly::fromRecord(
188 : String& errorMessage, const RecordInterface& record) {
189 0 : if (! SpectralModel::fromRecord(errorMessage, record)) {
190 0 : return false;
191 : }
192 0 : if (!record.isDefined(String("coeffs"))) {
193 0 : errorMessage += "The record must have an 'coeffs' field";
194 0 : return false;
195 : }
196 : {
197 0 : const RecordFieldId coeffs("coeffs");
198 0 : Vector<Double> coeffVal;
199 0 : switch (record.dataType(coeffs)) {
200 0 : case TpArrayDouble:
201 : case TpArrayFloat:
202 : case TpArrayInt:
203 0 : coeffVal = record.asArrayDouble(coeffs);
204 0 : break;
205 0 : default:
206 0 : errorMessage += "The 'coeff' field must be an array of numbers";
207 0 : return false;
208 : }
209 0 : setParameters(coeffVal);
210 : }
211 : // TODO full stokes implementation to come
212 : {
213 0 : Vector<Double> errorVals(nParameters(), 0.0);
214 0 : if (record.isDefined("error")) {
215 0 : const RecordFieldId error("error");
216 0 : switch (record.dataType(error)) {
217 0 : case TpArrayDouble:
218 : case TpArrayFloat:
219 : case TpArrayInt: {
220 0 : const auto x = record.asArrayDouble(error);
221 0 : if (x.size() != nParameters()) {
222 0 : errorMessage = "Coefficient and error array lengths are not equal";
223 0 : return false;
224 : }
225 : else {
226 0 : setErrors(x);
227 : }
228 : }
229 0 : break;
230 0 : default:
231 0 : errorMessage += "The 'error' field must be an array of numbers";
232 0 : return false;
233 : }
234 : }
235 : }
236 0 : return true;
237 : }
238 :
239 0 : Bool PowerLogPoly::toRecord(
240 : String& errorMessage, RecordInterface& record) const {
241 0 : if (! SpectralModel::toRecord(errorMessage, record)) {
242 0 : return false;
243 : }
244 0 : record.define("coeffs", parameters());
245 : // TODO full stokes support still to come
246 0 : record.define("error", errors());
247 0 : return true;
248 : }
249 :
250 0 : Bool PowerLogPoly::convertUnit(
251 : String&, const RecordInterface&
252 : ) {
253 : // parameters are dimensionless, no conversion can be done
254 0 : return true;
255 : }
256 :
257 0 : Bool PowerLogPoly::ok() const {
258 0 : if (! SpectralModel::ok()) {
259 0 : return false;
260 : }
261 0 : if (refFrequency().getValue().getValue() <= 0.0) {
262 0 : LogIO logErr(LogOrigin("PowerLogPoly", "ok()"));
263 : logErr << LogIO::SEVERE << "The reference frequency is zero or negative!"
264 0 : << LogIO::POST;
265 0 : return false;
266 : }
267 0 : if (anyGT(abs(_coeffs), 100.0)) {
268 0 : LogIO logErr(LogOrigin("PowerLogPoly", "ok()"));
269 : logErr << LogIO::SEVERE << "At least one coefficient is greater than 100!"
270 0 : << LogIO::POST;
271 0 : return false;
272 : }
273 0 : return true;
274 : }
275 :
276 : } //# NAMESPACE CASA - END
|