source: trunk/external-alma/components/SpectralComponents/Spectral2Estimate.tcc@ 3124

Last change on this file since 3124 was 3106, checked in by Takeshi Nakazato, 8 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes/No

Interface Changes: Yes/No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No

Module(s): Module Names change impacts.

Description: Describe your changes here...


Check-in asap modifications from Jim regarding casacore namespace conversion.

File size: 9.4 KB
RevLine 
[2980]1//# Spectral2Estimate.cc: Member templates for SpectralEstimate
2//# Copyright (C) 2001,2002,2003,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:
[3106]20//# casacore::Internet email: aips2-request@nrao.edu.
[2980]21//# Postal address: AIPS++ Project Office
22//# National Radio Astronomy Observatory
23//# 520 Edgemont Road
24//# Charlottesville, VA 22903-2475 USA
25//#
26//# $Id: Spectral2Estimate.tcc 21465 2014-06-19 05:56:56Z gervandiepen $
27
28//# Includes
29#include <components/SpectralComponents/SpectralEstimate.h>
30
31#include <casa/BasicMath/Math.h>
32#include <casa/BasicSL/Constants.h>
33#include <casa/Utilities/Assert.h>
34#include <components/SpectralComponents/CompiledSpectralElement.h>
35#include <components/SpectralComponents/GaussianSpectralElement.h>
36#include <components/SpectralComponents/PolynomialSpectralElement.h>
37
38namespace casa { //#Begin namespace casa
39
40//# Member templates
41template <class MT>
[3106]42const SpectralList &SpectralEstimate::estimate(const casacore::Vector<MT> &prof,
43 casacore::Vector<MT> *der) {
[2980]44 if (prof.nelements() != lprof_p) {
45 delete [] deriv_p; deriv_p = 0; lprof_p = 0;
46 lprof_p = prof.nelements();
[3106]47 deriv_p = new casacore::Double[lprof_p];
[2980]48 };
49 // Check if signal in window
50 if (!window(prof)) return slist_p;
51 // Limit window
[3106]52 windowEnd_p = min(windowEnd_p+q_p , casacore::Int(lprof_p));
[2980]53 windowLow_p = max(windowLow_p-q_p , 0 );
54 // Get the second derivatives
55 findc2(prof);
56 // Next for debugging
57 if (der) {
[3106]58 for (casacore::uInt i=0; i<lprof_p; i++) (*der)[i] = deriv_p[i];
[2980]59 };
60 // Find the estimates (sorted)
61 findga(prof);
62 // cout << slist_p << endl;
63 return slist_p;
64}
65
66template <class MT>
[3106]67const SpectralList& SpectralEstimate::estimate(const casacore::Vector<MT>& x,
68 const casacore::Vector<MT>& y)
[2980]69{
70 if (x.nelements() != y.nelements()) {
71 throw(AipsError("Abcissa and ordinate vectors must be the same length"));
72 }
73 if (x.nelements()==1) {
74 throw(AipsError("Not enough elements in vectors"));
75 }
76 // Get pixel-based estimate (into slist_p)
77 estimate(y);
78 // Convert
[3106]79 for (casacore::uInt i=0; i<slist_p.nelements(); i++) {
[2980]80 if (slist_p[i]->getType() != SpectralElement::GAUSSIAN) {
81 throw AipsError("Non-gaussian spectral types cannot be estimated");
82 }
83 const GaussianSpectralElement elIn = *dynamic_cast<const GaussianSpectralElement *>(slist_p[i]);
84 GaussianSpectralElement elOut = convertElement (x, elIn);
85 slist_p.set(elOut, i);
86 }
87 return slist_p;
88}
89
90
91template <class MT>
[3106]92casacore::uInt SpectralEstimate::window(const casacore::Vector<MT> &prof) {
[2980]93 windowLow_p =0;
94 windowEnd_p = 0;
95 if (!useWindow_p || rms_p <= 0.0 || lprof_p == 0) {
96 if (regionEnd_p) {
[3106]97 windowLow_p = min(max(0,regionLow_p),casacore::Int(lprof_p));
98 windowEnd_p = min(regionEnd_p, casacore::Int(lprof_p));
[2980]99 } else windowEnd_p = lprof_p;
100 return windowEnd_p-windowLow_p;
101 };
102 // Total flux in profile and max position
[3106]103 casacore::Double flux(0.0);
104 casacore::Double pmax(prof(0));
105 casacore::uInt imax(0);
106 for (casacore::Int i=windowLow_p; i<windowEnd_p; i++) {
[2980]107 if (prof(i)>pmax) {
108 pmax = prof(i);
109 imax = i;
110 };
111 flux += prof(i);
112 };
113 // No data
114 if (pmax < cutoff_p) return 0;
115 // Window boundaries; new/old base and centre; width
[3106]116 casacore::Int width(-1);
117 casacore::Int nw(0);
118 casacore::Double bnew(flux), bold;
119 casacore::Double cnew(imax), cold;
[2980]120 do {
121 width++;
122 cold = cnew;
123 bold = bnew;
[3106]124 windowLow_p = max(0, casacore::Int(cold-width+0.5));
125 windowEnd_p = min(casacore::Int(lprof_p), casacore::Int(cold+width+1.5));
[2980]126 // flux and first moment in window
[3106]127 casacore::Double s(0);
128 casacore::Double c(0);
129 for (casacore::Int i=windowLow_p; i<windowEnd_p; i++) {
[2980]130 s += prof(i);
131 c += i*prof(i);
132 };
133 bnew = flux-s;
134 nw = lprof_p-windowEnd_p+windowLow_p;
135 if (s != 0.0) {
136 cnew = c/s;
137 if (cnew < 0 || cnew >= lprof_p) cnew = cold;
138 };
139 } while (abs(bnew-bold) > rms_p && nw);
140 return windowEnd_p-windowLow_p;
141}
142
143template <class MT>
[3106]144void SpectralEstimate::findc2(const casacore::Vector<MT> &prof) {
145 for (casacore::Int i=windowLow_p; i<windowEnd_p; i++) {
[2980]146 // Moments
[3106]147 casacore::Double m0(0.0);
148 casacore::Double m2(0.0);
149 for (casacore::Int j = -q_p; j <= q_p; j++) {
150 casacore::Int k = i+j;
151 if (k >= 0 && k<casacore::Int(lprof_p)) {
[2980]152 // add to moments
153 m0 += prof(k);
154 m2 += prof(k)*j*j;
155 };
156 };
157 // get the derivative
158 deriv_p[i] = a_p*(m2-b_p*m0);
159 };
160}
161
162template <class MT>
[3106]163void SpectralEstimate::findga(const casacore::Vector<MT> &prof) {
164 casacore::Int i(windowLow_p-1);
[2980]165 // Window on Gaussian
[3106]166 casacore::Int iclo(windowLow_p);
167 casacore::Int ichi(windowLow_p);
[2980]168 // Peak counter
[3106]169 casacore::Int nmax = 0;
[2980]170 GaussianSpectralElement tspel;
171 while (++i < windowEnd_p) {
172 if (deriv_p[i] > 0.0) {
173 // At edge?
174 if (i > windowLow_p && i < windowEnd_p-1) {
175 // Peak in 2nd derivative
176 if (deriv_p[i-1] < deriv_p[i] && deriv_p[i+1] < deriv_p[i]) nmax++;
177 // At start
178 } else if (i == windowLow_p && deriv_p[i+1] < deriv_p[i]) nmax++;
179 // At end of window
180 else if (i == windowEnd_p-1 && deriv_p[i-1] < deriv_p[i]) nmax++;
181 };
182 switch (nmax) {
183 // Search for next peak
184 case 1:
185 break;
186 // Found a Gaussian
187 case 2: {
188 // Some moments
[3106]189 casacore::Double m0m(0);
190 casacore::Double m0(0);
191 casacore::Double m1(0);
192 casacore::Double m2(0);
[2980]193 ichi = i;
194 // Do Schwarz' calculation
[3106]195 casacore::Double b = deriv_p[iclo];
196 casacore::Double a = (deriv_p[ichi] - b) / (ichi-iclo);
197 for (casacore::Int ic=iclo; ic<=ichi; ic++) {
[2980]198 m0m += min(deriv_p[ic], 0.0);
[3106]199 casacore::Double wi = deriv_p[ic] - a*(ic-iclo) - b;
[2980]200 m0 += wi;
201 m1 += wi*ic;
202 m2 += wi*ic*ic;
203 };
204 // determinant
[3106]205 casacore::Double det = m2*m0 - m1*m1;
[2980]206 if (det > 0.0 && fabs(m0m) > FLT_EPSILON) {
[3106]207 casacore::Double xm = m1/m0;
208 casacore::Double sg = 1.69*sqrt(det) / fabs(m0);
[2980]209 // Width above critical?
210 if (sg > sigmin_p) {
[3106]211 casacore::Int is = casacore::Int(1.73*sg+0.5);
212 casacore::Int im = casacore::Int(xm+0.5);
213 casacore::Double yl(0);
[2980]214 if ((im-is) >= 0) yl = prof(im-is);
[3106]215 casacore::Double yh(0);
216 if ((im + is) <= casacore::Int(lprof_p-1)) yh = prof(im+is);
217 casacore::Double ym = prof(im);
[2980]218 // modified by dmehringer 2012apr03 to deal with 0 denominator
219 // 0.0/0.0 produces NaN on Linux but 0 on OSX
[3106]220 casacore::Double pg = (ym-0.5*(yh+yl));
[2980]221 if (pg != 0) {
[3106]222 casacore::Double denom = (1.0-exp(-0.5*(is*is)/sg/sg));
[2980]223 if (denom == 0) {
224 throw AipsError("Bailing because division by zero is undefined");
225 }
226 pg /= denom;
227 }
228 // end dmehring mods
229 pg = min(pg, ym);
230 // cout << "pg " << pg << " cutoff " << cutoff_p << endl;
231 // Above critical level? Add to list
232 if (pg > cutoff_p) {
233 // cout << pg << " " << xm << " " << sg << endl;
234 tspel.setAmpl(pg);
235 tspel.setCenter(xm);
236 tspel.setSigma(sg);
237 slist_p.insert(tspel);
238 };
239 };
240 };
241 // Next gaussian
242 iclo = ichi;
243 nmax--;
244 break;
245 }
246 default:
247 iclo = i+1;
248 break;
249 };
250 };
251}
252
253template <class MT>
[3106]254GaussianSpectralElement SpectralEstimate::convertElement (const casacore::Vector<MT>& x,
[2980]255 const GaussianSpectralElement& el) const
256{
257 GaussianSpectralElement elOut = el;
[3106]258 const casacore::Int& idxMax = x.nelements()-1;
[2980]259
260// Get current (pars are amp, center, width as the SpectralElement
261// will always be a Gaussian)
262
[3106]263 casacore::Vector<casacore::Double> par, err;
[2980]264 el.get(par);
265 el.getError(err);
266
267// Center
268
[3106]269 casacore::Int cenIdx = casacore::Int(par[1]);
[2980]270
271// Get the x-increment, local to the center, as best we can from
272// the abcissa vector. The following algorithm assumes the X
273// vector is monotonic
274
[3106]275 casacore::Double incX;
[2980]276 if (cenIdx-1<0) {
277 incX = x[1] - x[0];
278 } else if (cenIdx+1>idxMax) {
279 incX = x[idxMax] - x[idxMax-1];
280 } else {
281 incX = 0.5 * (x(cenIdx+1) - x(cenIdx-1));
282 }
283//
284 if (cenIdx<0) {
285 par[1] = incX*par[1] + x[0]; // Extrapolate from x[0]
286 } else if (cenIdx>idxMax) {
287 par[1] = incX*(par[1]-idxMax) + x[idxMax]; // Extrapolate from x[idxMax]
288 } else {
[3106]289 casacore::Double dIdx = par[1] - cenIdx;
290 par[1] = x[cenIdx] + dIdx*incX; // casacore::Interpolate
[2980]291 }
292 err[1] = abs(err[1] * incX);
293
294// Width
295
296 par[2] = abs(par[2] * incX);
297 err[2] = abs(err[2] * incX);
298
299 elOut.set(par);
300 elOut.setError(err);
301 return elOut;
302}
303
304
305} //# End namespace casa
Note: See TracBrowser for help on using the repository browser.