Line data Source code
1 : //# SpectralElement.cc: Describes (a set of related) spectral lines
2 : //# Copyright (C) 2001,2004
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 :
27 : #include <components/SpectralComponents/GaussianMultipletSpectralElement.h>
28 :
29 : #include <casacore/casa/IO/ArrayIO.h>
30 : #include <casacore/casa/Arrays/ArrayLogical.h>
31 : #include <casacore/casa/Arrays/ArrayMath.h>
32 : #include <casacore/casa/Containers/Record.h>
33 : #include <components/SpectralComponents/GaussianSpectralElement.h>
34 :
35 : #include <iostream>
36 :
37 : using namespace casacore;
38 : namespace casa { //# NAMESPACE CASA - BEGIN
39 :
40 : #define _ORIGIN String("GaussianMultipletSpectralElement::") + __FUNCTION__ + ":" + String::toString(__LINE__) + ": "
41 :
42 2 : GaussianMultipletSpectralElement::GaussianMultipletSpectralElement(
43 : const vector<GaussianSpectralElement>& estimates,
44 : const Matrix<Double>& constraints
45 2 : ) : CompiledSpectralElement(SpectralElement::GMULTIPLET),
46 2 : _gaussians(estimates),_constraints(constraints),
47 4 : _paramIndices(estimates.size(), 3, 0) {
48 2 : if(estimates.size() != constraints.nrow()+1) {
49 0 : throw AipsError(
50 0 : _ORIGIN
51 0 : + "Mismatch between size of estimates and constraints"
52 0 : );
53 : }
54 2 : if (constraints.ncolumn() != 3) {
55 0 : throw AipsError(_ORIGIN + "constraints does not have 3 columns");
56 : }
57 2 : Matrix<Bool> fixed(LogicalArray(constraints != 0.0));
58 6 : for (uInt i=1; i<estimates.size(); i++) {
59 4 : if (! estimates[0].fixedAmpl()
60 4 : && estimates[i].fixedAmpl()
61 8 : && fixed(i-1, 0)
62 : ) {
63 0 : throw AipsError(_ORIGIN + "You cannot fix the amplitude of a "
64 : "non-reference Gaussian if the reference Gaussian's "
65 : "amplitude is not fixed and there is a relationship "
66 : "between the two amplitudes."
67 0 : );
68 : }
69 4 : if (! estimates[0].fixedCenter()
70 4 : && estimates[i].fixedCenter()
71 8 : && fixed(i-1, 1)
72 : ) {
73 0 : throw AipsError(_ORIGIN + "You cannot fix the center of a non-reference "
74 : "Gaussian if the reference Gaussian's center is not fixed and there "
75 : "is a relationship between the two centers."
76 0 : );
77 : }
78 4 : if (! estimates[0].fixedWidth()
79 4 : && estimates[i].fixedWidth()
80 8 : && fixed(i-1, 2)
81 : ) {
82 0 : throw AipsError(_ORIGIN + "You cannot fix the width of a non-reference "
83 : "Gaussian if the reference Gaussian's width is not fixed and there "
84 : "is a relationship between the two widths."
85 0 : );
86 : }
87 : }
88 2 : ostringstream myfunc;
89 2 : myfunc << "p0*exp(-0.5 * (x-p1)*(x-p1) / p2/p2)";
90 2 : Vector<Double> parm(3 + nfalse(fixed), 0);
91 2 : Vector<Double> errs = parm.copy();
92 2 : parm[0] = _gaussians[0].getAmpl();
93 2 : parm[1] = _gaussians[0].getCenter();
94 2 : parm[2] = _gaussians[0].getSigma();
95 2 : errs[0] = _gaussians[0].getAmplErr();
96 2 : errs[1] = _gaussians[0].getCenterErr();
97 2 : errs[2] = _gaussians[0].getSigmaErr();
98 2 : Vector<Bool> f(parm.size(), true);
99 2 : f[0] = _gaussians[0].fixedAmpl();
100 2 : f[1] = _gaussians[0].fixedCenter();
101 2 : f[2] = _gaussians[0].fixedSigma();
102 2 : _paramIndices(0, 0) = 0;
103 2 : _paramIndices(0, 1) = 1;
104 2 : _paramIndices(0, 2) = 2;
105 2 : uInt p = 3;
106 6 : for (uInt i=0; i<constraints.nrow(); i++) {
107 4 : String amp;
108 4 : if (constraints(i, 0) != 0) {
109 4 : amp = String::toString(constraints(i, 0)) + "*p0";
110 : }
111 : else {
112 0 : amp = "p" + String::toString(p);
113 0 : parm[p] = _gaussians[i+1].getAmpl();
114 0 : errs[p] = _gaussians[i+1].getAmplErr();
115 0 : f[p] = _gaussians[i+1].fixedAmpl();
116 0 : _paramIndices(i+1, 0) = p;
117 0 : p++;
118 : }
119 4 : String center;
120 4 : if (constraints(i, 1) != 0) {
121 2 : center = "x-(p1+(" + String::toString(constraints(i, 1)) + "))";
122 : }
123 : else {
124 2 : center = "x-p" + String::toString(p);
125 2 : parm[p] = _gaussians[i+1].getCenter();
126 2 : errs[p] = _gaussians[i+1].getCenterErr();
127 2 : f[p] = _gaussians[i+1].fixedCenter();
128 2 : _paramIndices(i+1, 1) = p;
129 2 : p++;
130 :
131 : }
132 4 : String sigma;
133 4 : if (constraints(i, 2) != 0) {
134 0 : sigma = String::toString(constraints(i, 2)) + "*p2";
135 : }
136 : else {
137 4 : sigma = "p" + String::toString(p);
138 4 : parm[p] = _gaussians[i+1].getSigma();
139 4 : errs[p] = _gaussians[i+1].getSigmaErr();
140 4 : f[p] = _gaussians[i+1].fixedSigma();
141 4 : _paramIndices(i+1, 2) = p;
142 4 : p++;
143 : }
144 4 : myfunc << " + " << amp << "*exp(-0.5 * (" << center << ")*("
145 4 : << center << ") / (" << sigma << ") / (" << sigma << "))";
146 4 : }
147 2 : _setFunction(myfunc.str());
148 : // have to set the GaussianSpectralElement parameters
149 2 : set(parm);
150 2 : setError(errs);
151 2 : fix(f);
152 2 : }
153 :
154 353 : GaussianMultipletSpectralElement::GaussianMultipletSpectralElement(
155 : const GaussianMultipletSpectralElement& other
156 706 : ) : CompiledSpectralElement(other), _gaussians(other._gaussians),
157 353 : _constraints(other._constraints),
158 706 : _paramIndices(other._paramIndices) {}
159 :
160 :
161 708 : GaussianMultipletSpectralElement::~GaussianMultipletSpectralElement() {}
162 :
163 353 : SpectralElement* GaussianMultipletSpectralElement::clone() const {
164 353 : return new GaussianMultipletSpectralElement(*this);
165 : }
166 :
167 0 : GaussianMultipletSpectralElement& GaussianMultipletSpectralElement::operator=(
168 : const GaussianMultipletSpectralElement &other
169 : ) {
170 0 : if (this != &other) {
171 0 : CompiledSpectralElement::operator=(other);
172 0 : _gaussians = other._gaussians;
173 0 : _constraints.resize(other._constraints.shape());
174 0 : _constraints = other._constraints.copy();
175 0 : _paramIndices.resize(other._paramIndices.shape());
176 0 : _paramIndices = other._paramIndices.copy();
177 : }
178 0 : return *this;
179 : }
180 :
181 0 : Bool GaussianMultipletSpectralElement::operator==(
182 : const GaussianMultipletSpectralElement& other
183 : ) const {
184 : return(
185 0 : CompiledSpectralElement::operator==(other)
186 0 : && allTrue(Vector<GaussianSpectralElement>(_gaussians) == Vector<GaussianSpectralElement>(other._gaussians))
187 0 : && allTrue(_constraints == other._constraints)
188 0 : );
189 : }
190 :
191 : const vector<GaussianSpectralElement>&
192 53 : GaussianMultipletSpectralElement::getGaussians() const {
193 53 : return _gaussians;
194 : }
195 :
196 0 : const Matrix<Double>& GaussianMultipletSpectralElement::getConstraints() const {
197 0 : return _constraints;
198 : }
199 :
200 0 : Bool GaussianMultipletSpectralElement::toRecord(RecordInterface& out) const {
201 0 : out.define(RecordFieldId("type"), fromType(getType()));
202 0 : Record gaussians;
203 0 : for (uInt i=0; i<_gaussians.size(); i++) {
204 0 : Record gaussian;
205 0 : _gaussians[i].toRecord(gaussian);
206 0 : gaussians.defineRecord(
207 0 : "*" + String::toString(i), gaussian
208 : );
209 0 : }
210 0 : out.defineRecord("gaussians", gaussians);
211 0 : out.define("fixedMatrix", _constraints);
212 0 : return true;
213 0 : }
214 :
215 28 : void GaussianMultipletSpectralElement::set(const Vector<Double>& param) {
216 28 : if (get().size() > 0 && param.size() != get().size()) {
217 0 : ostringstream x;
218 0 : x << _ORIGIN << "Inconsistent number of parameters. Got "
219 0 : << param.size() << ". Must be " << get().size();
220 0 : throw AipsError(x.str());
221 0 : }
222 28 : SpectralElement::_set(param);
223 28 : Double amp0 = param[0];
224 28 : Double center0 = param[1];
225 28 : Double sigma0 = param[2];
226 28 : _gaussians[0].setAmpl(amp0);
227 28 : _gaussians[0].setCenter(center0);
228 28 : _gaussians[0].setSigma(sigma0);
229 28 : uInt p = 3;
230 196 : for (uInt i=3; i<_paramIndices.size(); i++) {
231 168 : uInt gNumber = i/3;
232 168 : uInt pNumber = i%3;
233 168 : uInt pIndex = _paramIndices(gNumber, pNumber);
234 168 : Double fRel = _constraints(gNumber-1, pNumber);
235 168 : if (pNumber == 0) {
236 56 : Double amp = pIndex == 0 ? fRel*amp0 : param[p];
237 56 : _gaussians[gNumber].setAmpl(amp);
238 : }
239 112 : else if (pNumber == 1) {
240 56 : Double center = pIndex == 0 ? fRel+center0 : param[p];
241 56 : _gaussians[gNumber].setCenter(center);
242 : }
243 56 : else if (pNumber == 2) {
244 56 : Double sigma = pIndex == 0 ? fRel*sigma0 : param[p];
245 56 : _gaussians[gNumber].setSigma(sigma);
246 : }
247 168 : if (pIndex > 0) {
248 84 : p++;
249 : }
250 : }
251 28 : }
252 :
253 28 : void GaussianMultipletSpectralElement::setError(const Vector<Double> &err) {
254 28 : SpectralElement::setError(err);
255 28 : Double amp0 = err[0];
256 28 : Double center0 = err[1];
257 28 : Double sigma0 = err[2];
258 28 : Vector<Double> errors(3);
259 28 : errors[0] = err[0];
260 28 : errors[1] = err[1];
261 28 : errors[2] = err[2];
262 28 : _gaussians[0].setError(errors);
263 28 : uInt p = 3;
264 196 : for (uInt i=3; i<_paramIndices.size(); i++) {
265 168 : uInt gNumber = i/3;
266 168 : uInt pNumber = i%3;
267 168 : uInt pIndex = _paramIndices(gNumber, pNumber);
268 168 : Double fRel = _constraints(gNumber-1, pNumber);
269 168 : if (pNumber == 0) {
270 56 : errors[0] = pIndex == 0 ? fRel*amp0 : err[p];
271 : }
272 112 : else if (pNumber == 1) {
273 56 : errors[1] = pIndex == 0 ? center0 : err[p];
274 : }
275 56 : else if (pNumber == 2) {
276 56 : errors[2] = pIndex == 0 ? fRel*sigma0 : err[p];
277 : }
278 168 : _gaussians[gNumber].setError(errors);
279 :
280 168 : if (pIndex > 0) {
281 84 : p++;
282 : }
283 : }
284 28 : }
285 :
286 2 : void GaussianMultipletSpectralElement::fix(const Vector<Bool>& fix) {
287 2 : SpectralElement::fix(fix);
288 2 : Bool amp0 = fix[0];
289 2 : Bool center0 = fix[1];
290 2 : Bool sigma0 = fix[2];
291 2 : Vector<Bool> fixed(3);
292 2 : fixed[0] = fix[0];
293 2 : fixed[1] = fix[1];
294 2 : fixed[2] = fix[2];
295 2 : _gaussians[0].fix(fixed);
296 2 : uInt p = 3;
297 14 : for (uInt i=3; i<_paramIndices.size(); i++) {
298 12 : uInt gNumber = i/3;
299 12 : uInt pNumber = i%3;
300 12 : uInt pIndex = _paramIndices(gNumber, pNumber);
301 12 : if (pNumber == 0) {
302 4 : fixed[0] = pIndex == 0 ? amp0 : fix[p];
303 : }
304 8 : else if (pNumber == 1) {
305 4 : fixed[1] = pIndex == 0 ? center0 : fix[p];
306 : }
307 4 : else if (pNumber == 2) {
308 4 : fixed[2] = pIndex == 0 ? sigma0 : fix[p];
309 : }
310 12 : _gaussians[gNumber].fix(fixed);
311 12 : if (pIndex > 0) {
312 6 : p++;
313 : }
314 : }
315 2 : }
316 :
317 0 : ostream &operator<<(ostream& os, const GaussianMultipletSpectralElement& elem) {
318 0 : os << SpectralElement::fromType((elem.getType())) << " element: " << endl;
319 0 : os << " Function: " << elem.getFunction() << endl;
320 0 : os << " Gaussians:" << endl;
321 0 : Vector<GaussianSpectralElement> gaussians(elem.getGaussians());
322 0 : for (uInt i=0; i<gaussians.size(); i++) {
323 0 : os << "Gaussian " << i << ": " << gaussians[i] << endl;
324 : }
325 0 : Matrix<Double> r = elem.getConstraints();
326 0 : os << "Constraints: " << endl;
327 0 : for (uInt i=1; i<gaussians.size(); i++) {
328 0 : for (uInt j=0; j<3; j++) {
329 0 : Double v = r(i-1, j);
330 0 : if (v != 0) {
331 0 : switch (j) {
332 0 : case 0:
333 0 : os << " Amplitude ratio of component " << i
334 0 : << " to the reference component is fixed at " << v;
335 0 : break;
336 0 : case 1:
337 0 : os << " Center offset of component " << i
338 0 : << " to the reference component is fixed at " << v;
339 0 : break;
340 0 : case 2:
341 0 : os << " FWHM ratio of component " << i
342 0 : << " to the reference component is fixed at " << v;
343 0 : break;
344 0 : default:
345 0 : throw AipsError(_ORIGIN + "Logic Error");
346 : }
347 : }
348 : }
349 : }
350 0 : return os;
351 0 : }
352 :
353 : } //# NAMESPACE CASA - END
354 :
355 :
|