source: trunk/src/SDLineFinder.cc@ 344

Last change on this file since 344 was 344, checked in by vor010, 20 years ago

An algorithm to detect line wings, which are
below detection threshold, has been added

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 KB
Line 
1//#---------------------------------------------------------------------------
2//# SDLineFinder.cc: A class for automated spectral line search
3//#--------------------------------------------------------------------------
4//# Copyright (C) 2004
5//# ATNF
6//#
7//# This program is free software; you can redistribute it and/or modify it
8//# under the terms of the GNU General Public License as published by the Free
9//# Software Foundation; either version 2 of the License, or (at your option)
10//# any later version.
11//#
12//# This program is distributed in the hope that it will be useful, but
13//# WITHOUT ANY WARRANTY; without even the implied warranty of
14//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15//# Public License for more details.
16//#
17//# You should have received a copy of the GNU General Public License along
18//# with this program; if not, write to the Free Software Foundation, Inc.,
19//# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
20//#
21//# Correspondence concerning this software should be addressed as follows:
22//# Internet email: Malte.Marquarding@csiro.au
23//# Postal address: Malte Marquarding,
24//# Australia Telescope National Facility,
25//# P.O. Box 76,
26//# Epping, NSW, 2121,
27//# AUSTRALIA
28//#
29//# $Id:
30//#---------------------------------------------------------------------------
31
32
33// ASAP
34#include "SDLineFinder.h"
35
36// STL
37#include <functional>
38#include <algorithm>
39#include <iostream>
40
41using namespace asap;
42using namespace casa;
43using namespace std;
44using namespace boost::python;
45
46namespace asap {
47
48///////////////////////////////////////////////////////////////////////////////
49//
50// IStatHolder - an abstract class to collect statistics from the running
51// mean calculator, if necessary.
52// We define it here, because it is used in LFRunningMean and
53// SDLineFinder only
54//
55
56struct IStatHolder {
57 // This function is called for each spectral channel processed by
58 // the running mean calculator. The order of channel numbers may be
59 // arbitrary
60 // ch - a number of channel, corresponding to (approximately) the centre
61 // of the running box
62 // box_nchan - number of channels in the box
63 //
64 virtual void accumulate(int ch, Float sum, Float sum2, int box_nchan)
65 throw(AipsError) = 0;
66};
67
68//
69///////////////////////////////////////////////////////////////////////////////
70
71///////////////////////////////////////////////////////////////////////////////
72//
73// SignAccumulator - a simple class to deal with running mean statistics:
74// it stores the sign of the value-mean only
75//
76class SignAccumulator : public IStatHolder {
77 Vector<Int> sign; // either +1, -1 or 0
78 const Vector<Float> &spectrum; // a reference to the spectrum
79 // to calculate the sign
80public:
81 // all channels >=nchan are ignored
82 SignAccumulator(uInt nchan, const Vector<Float> &in_spectrum);
83
84 // This function is called for each spectral channel processed by
85 // the running mean calculator. The order of channel numbers may be
86 // arbitrary
87 // ch - a number of channel, corresponding to (approximately) the centre
88 // of the running box
89 // box_nchan - number of channels in the box
90 //
91 virtual void accumulate(int ch, Float sum, Float, int box_nchan)
92 throw(AipsError);
93
94 // access to the sign
95 const Vector<Int>& getSigns() const throw();
96};
97
98//
99///////////////////////////////////////////////////////////////////////////////
100
101///////////////////////////////////////////////////////////////////////////////
102//
103// LFRunningMean - a running mean algorithm for line detection
104//
105//
106
107// An auxiliary class implementing one pass of the line search algorithm,
108// which uses a running mean. We define this class here because it is
109// used in SDLineFinder only. The incapsulation of this code into a separate
110// class will provide a possibility to add new algorithms with minor changes
111class LFRunningMean {
112 // The input data to work with. Use reference symantics to avoid
113 // an unnecessary copying
114 const casa::Vector<casa::Float> &spectrum; // a buffer for the spectrum
115 const casa::Vector<casa::Bool> &mask; // associated mask
116 const std::pair<int,int> &edge; // start and stop+1 channels
117 // to work with
118
119 // statistics for running mean filtering
120 casa::Float sum; // sum of fluxes
121 casa::Float sumsq; // sum of squares of fluxes
122 int box_chan_cntr; // actual number of channels in the box
123 int max_box_nchan; // maximum allowed number of channels in the box
124 // (calculated from boxsize and actual spectrum size)
125
126 // temporary line edge channels and flag, which is True if the line
127 // was detected in the previous channels.
128 std::pair<int,int> cur_line;
129 casa::Bool is_detected_before;
130 int min_nchan; // A minimum number of consequtive
131 // channels, which should satisfy
132 // the detection criterion, to be
133 // a detection
134 casa::Float threshold; // detection threshold - the
135 // minimal signal to noise ratio
136public:
137 // set up the object with the references to actual data
138 // as well as the detection criterion (min_nchan and threshold, see above)
139 // and the number of channels in the running box
140 LFRunningMean(const casa::Vector<casa::Float> &in_spectrum,
141 const casa::Vector<casa::Bool> &in_mask,
142 const std::pair<int,int> &in_edge,
143 int in_max_box_nchan,
144 int in_min_nchan = 3,
145 casa::Float in_threshold = 5);
146
147 // replace the detection criterion
148 void setCriterion(int in_min_nchan, casa::Float in_threshold) throw();
149
150 // find spectral lines and add them into list
151 // if statholder is not NULL, the accumulate function of it will be
152 // called for each channel to save statistics
153 void findLines(std::list<pair<int,int> > &lines,
154 IStatHolder* statholder = NULL) throw(casa::AipsError);
155
156protected:
157 // supplementary function to control running mean calculations.
158 // It adds a specified channel to the running mean box and
159 // removes (ch-maxboxnchan+1)'th channel from there
160 // Channels, for which the mask is false or index is beyond the
161 // allowed range, are ignored
162 void advanceRunningBox(int ch) throw(casa::AipsError);
163
164
165 // test a channel against current running mean & rms
166 // if channel specified is masked out or beyond the allowed indexes,
167 // false is returned
168 casa::Bool testChannel(int ch) const
169 throw(std::exception, casa::AipsError);
170
171 // process a channel: update curline and is_detected before and
172 // add a new line to the list, if necessary using processCurLine()
173 void processChannel(std::list<pair<int,int> > &lines,
174 int ch) throw(casa::AipsError);
175
176 // process the interval of channels stored in curline
177 // if it satisfies the criterion, add this interval as a new line
178 void processCurLine(std::list<pair<int,int> > &lines) throw(casa::AipsError);
179
180};
181
182//
183///////////////////////////////////////////////////////////////////////////////
184} // namespace asap
185
186///////////////////////////////////////////////////////////////////////////////
187//
188// SignAccumulator - a simple class to deal with running mean statistics:
189// it stores the sign of the value-mean only
190//
191
192// all channels >=nchan are ignored
193SignAccumulator::SignAccumulator(uInt nchan,
194 const Vector<Float> &in_spectrum) : sign(nchan,0),
195 spectrum(in_spectrum) {}
196
197
198// This function is called for each spectral channel processed by
199// the running mean calculator. The order of channel numbers may be
200// arbitrary
201// ch - a number of channel, corresponding to (approximately) the centre
202// of the running box
203// box_nchan - number of channels in the box
204//
205void SignAccumulator::accumulate(int ch, Float sum, Float, int box_nchan)
206 throw(AipsError)
207{
208 if (ch>=sign.nelements()) return;
209 DebugAssert(ch>=0,AipsError);
210 DebugAssert(ch<=spectrum.nelements(), AipsError);
211 if (box_nchan) {
212 Float buf=spectrum[ch]-sum/Float(box_nchan);
213 if (buf>0) sign[ch]=1;
214 else if (buf<0) sign[ch]=-1;
215 else sign[ch]=0;
216 } else sign[ch]=0;
217}
218
219// access to the sign
220const Vector<Int>& SignAccumulator::getSigns() const throw()
221{
222 return sign;
223}
224
225
226//
227///////////////////////////////////////////////////////////////////////////////
228
229
230///////////////////////////////////////////////////////////////////////////////
231//
232// LFRunningMean - a running mean algorithm for line detection
233//
234//
235
236// set up the object with the references to actual data
237// as well as the detection criterion (min_nchan and threshold, see above)
238// and the number of channels in the running box
239LFRunningMean::LFRunningMean(const casa::Vector<casa::Float> &in_spectrum,
240 const casa::Vector<casa::Bool> &in_mask,
241 const std::pair<int,int> &in_edge,
242 int in_max_box_nchan,
243 int in_min_nchan, casa::Float in_threshold) :
244 spectrum(in_spectrum), mask(in_mask), edge(in_edge),
245 max_box_nchan(in_max_box_nchan),
246 min_nchan(in_min_nchan),threshold(in_threshold) {}
247
248// replace the detection criterion
249void LFRunningMean::setCriterion(int in_min_nchan, casa::Float in_threshold)
250 throw()
251{
252 min_nchan=in_min_nchan;
253 threshold=in_threshold;
254}
255
256
257// supplementary function to control running mean calculations.
258// It adds a specified channel to the running mean box and
259// removes (ch-max_box_nchan+1)'th channel from there
260// Channels, for which the mask is false or index is beyond the
261// allowed range, are ignored
262void LFRunningMean::advanceRunningBox(int ch) throw(AipsError)
263{
264 if (ch>=edge.first && ch<edge.second)
265 if (mask[ch]) { // ch is a valid channel
266 ++box_chan_cntr;
267 sum+=spectrum[ch];
268 sumsq+=square(spectrum[ch]);
269 }
270 int ch2remove=ch-max_box_nchan;
271 if (ch2remove>=edge.first && ch2remove<edge.second)
272 if (mask[ch2remove]) { // ch2remove is a valid channel
273 --box_chan_cntr;
274 sum-=spectrum[ch2remove];
275 sumsq-=square(spectrum[ch2remove]);
276 }
277}
278
279// test a channel against current running mean & rms
280// if channel specified is masked out or beyond the allowed indexes,
281// false is returned
282Bool LFRunningMean::testChannel(int ch) const throw(exception, AipsError)
283{
284 if (ch<edge.first || ch>=edge.second) return False;
285 if (!mask[ch]) return False;
286 DebugAssert(box_chan_cntr, AipsError);
287 Float mean=sum/Float(box_chan_cntr);
288 Float variance=sqrt(sumsq/Float(box_chan_cntr)-square(mean));
289 /*
290 if (ch>3900 && ch<4100)
291 cout<<"Tested "<<ch<<" mean="<<mean<<" variance="<<variance<<" sp-mean="<<spectrum[ch]-mean<<endl;
292 */
293 return fabs(spectrum[ch]-mean)>=threshold*variance;
294}
295
296// process a channel: update cur_line and is_detected before and
297// add a new line to the list, if necessary
298void LFRunningMean::processChannel(std::list<pair<int,int> > &lines,
299 int ch) throw(casa::AipsError)
300{
301 try {
302 if (testChannel(ch)) {
303 if (is_detected_before)
304 cur_line.second=ch+1;
305 else {
306 is_detected_before=True;
307 cur_line.first=ch;
308 cur_line.second=ch+1;
309 }
310 } else processCurLine(lines);
311 }
312 catch (const AipsError &ae) {
313 throw;
314 }
315 catch (const exception &ex) {
316 throw AipsError(String("SDLineFinder::processChannel - STL error: ")+ex.what());
317 }
318}
319
320// process the interval of channels stored in cur_line
321// if it satisfies the criterion, add this interval as a new line
322void LFRunningMean::processCurLine(std::list<pair<int,int> > &lines)
323 throw(casa::AipsError)
324{
325 try {
326 if (is_detected_before) {
327 if (cur_line.second-cur_line.first>min_nchan) {
328 // it was a detection. We need to change the list
329 Bool add_new_line=False;
330 if (lines.size()) {
331 for (int i=lines.back().second;i<cur_line.first;++i)
332 if (mask[i]) { // one valid channel in between
333 // means that we deal with a separate line
334 add_new_line=True;
335 break;
336 }
337 } else add_new_line=True;
338 if (add_new_line)
339 lines.push_back(cur_line);
340 else lines.back().second=cur_line.second;
341 }
342 is_detected_before=False;
343 }
344 }
345 catch (const AipsError &ae) {
346 throw;
347 }
348 catch (const exception &ex) {
349 throw AipsError(String("SDLineFinder::processCurLine - STL error: ")+ex.what());
350 }
351}
352
353// find spectral lines and add them into list
354void LFRunningMean::findLines(std::list<pair<int,int> > &lines,
355 IStatHolder* statholder)
356 throw(casa::AipsError)
357{
358 const int minboxnchan=4;
359
360 // fill statistics for initial box
361 box_chan_cntr=0; // no channels are currently in the box
362 sum=0; // initialize statistics
363 sumsq=0;
364 int initial_box_ch=edge.first;
365 for (;initial_box_ch<edge.second && box_chan_cntr<max_box_nchan;
366 ++initial_box_ch)
367 advanceRunningBox(initial_box_ch);
368
369 if (initial_box_ch==edge.second)
370 throw AipsError("LFRunningMean::findLines - too much channels are masked");
371
372 // actual search algorithm
373 is_detected_before=False;
374
375 if (statholder!=NULL)
376 for (int n=0;n<initial_box_ch-max_box_nchan/2;++n)
377 statholder->accumulate(n,sum,sumsq,box_chan_cntr);
378
379 if (box_chan_cntr>=minboxnchan)
380 // there is a minimum amount of data. We can search in the
381 // half of the initial box
382 for (int n=edge.first;n<initial_box_ch-max_box_nchan/2;++n)
383 processChannel(lines,n);
384
385 // now the box can be moved. n+max_box_nchan/2 is a new index which haven't
386 // yet been included in the running mean.
387 for (int n=initial_box_ch-max_box_nchan/2;n<edge.second;++n) {
388 advanceRunningBox(n+max_box_nchan/2); // update running mean & variance
389 if (statholder!=NULL)
390 statholder->accumulate(n,sum,sumsq,box_chan_cntr);
391 if (box_chan_cntr>=minboxnchan) // have enough data to process
392 processChannel(lines,n);
393 else processCurLine(lines); // just finish what was accumulated before
394 }
395 if (statholder!=NULL)
396 for (int n=edge.second;n<spectrum.nelements();++n)
397 statholder->accumulate(n,sum,sumsq,box_chan_cntr);
398}
399
400//
401///////////////////////////////////////////////////////////////////////////////
402
403///////////////////////////////////////////////////////////////////////////////
404//
405// SDLineFinder::IntersectsWith - An auxiliary object function to test
406// whether two lines have a non-void intersection
407//
408
409
410// line1 - range of the first line: start channel and stop+1
411SDLineFinder::IntersectsWith::IntersectsWith(const std::pair<int,int> &in_line1) :
412 line1(in_line1) {}
413
414
415// return true if line2 intersects with line1 with at least one
416// common channel, and false otherwise
417// line2 - range of the second line: start channel and stop+1
418bool SDLineFinder::IntersectsWith::operator()(const std::pair<int,int> &line2)
419 const throw()
420{
421 if (line2.second<line1.first) return false; // line2 is at lower channels
422 if (line2.first>line1.second) return false; // line2 is at upper channels
423 return true; // line2 has an intersection or is adjacent to line1
424}
425
426//
427///////////////////////////////////////////////////////////////////////////////
428
429///////////////////////////////////////////////////////////////////////////////
430//
431// SDLineFinder::BuildUnion - An auxiliary object function to build a union
432// of several lines to account for a possibility of merging the nearby lines
433//
434
435// set an initial line (can be a first line in the sequence)
436SDLineFinder::BuildUnion::BuildUnion(const std::pair<int,int> &line1) :
437 temp_line(line1) {}
438
439// update temp_line with a union of temp_line and new_line
440// provided there is no gap between the lines
441void SDLineFinder::BuildUnion::operator()(const std::pair<int,int> &new_line)
442 throw()
443{
444 if (new_line.first<temp_line.first) temp_line.first=new_line.first;
445 if (new_line.second>temp_line.second) temp_line.second=new_line.second;
446}
447
448// return the result (temp_line)
449const std::pair<int,int>& SDLineFinder::BuildUnion::result() const throw()
450{
451 return temp_line;
452}
453
454//
455///////////////////////////////////////////////////////////////////////////////
456
457///////////////////////////////////////////////////////////////////////////////
458//
459// SDLineFinder::LaterThan - An auxiliary object function to test whether a
460// specified line is at lower spectral channels (to preserve the order in
461// the line list)
462//
463
464// setup the line to compare with
465SDLineFinder::LaterThan::LaterThan(const std::pair<int,int> &in_line1) :
466 line1(in_line1) {}
467
468// return true if line2 should be placed later than line1
469// in the ordered list (so, it is at greater channel numbers)
470bool SDLineFinder::LaterThan::operator()(const std::pair<int,int> &line2)
471 const throw()
472{
473 if (line2.second<line1.first) return false; // line2 is at lower channels
474 if (line2.first>line1.second) return true; // line2 is at upper channels
475
476 // line2 intersects with line1. We should have no such situation in
477 // practice
478 return line2.first>line1.first;
479}
480
481//
482///////////////////////////////////////////////////////////////////////////////
483
484
485///////////////////////////////////////////////////////////////////////////////
486//
487// SDLineFinder - a class for automated spectral line search
488//
489//
490
491SDLineFinder::SDLineFinder() throw() : edge(0,0)
492{
493 // detection threshold - the minimal signal to noise ratio
494 threshold=3.; // 3 sigma is a default
495 box_size=1./16.; // default box size for running mean calculations is
496 // 1/16 of the whole spectrum
497 // A minimum number of consequtive channels, which should satisfy
498 // the detection criterion, to be a detection
499 min_nchan=3; // default is 3 channels
500}
501
502SDLineFinder::~SDLineFinder() throw(AipsError) {}
503
504// set scan to work with (in_scan parameter), associated mask (in_mask
505// parameter) and the edge channel rejection (in_edge parameter)
506// if in_edge has zero length, all channels chosen by mask will be used
507// if in_edge has one element only, it represents the number of
508// channels to drop from both sides of the spectrum
509// in_edge is introduced for convinience, although all functionality
510// can be achieved using a spectrum mask only
511void SDLineFinder::setScan(const SDMemTableWrapper &in_scan,
512 const std::vector<bool> &in_mask,
513 const boost::python::tuple &in_edge) throw(AipsError)
514{
515 try {
516 scan=in_scan.getCP();
517 AlwaysAssert(!scan.null(),AipsError);
518 if (scan->nRow()!=1)
519 throw AipsError("SDLineFinder::setScan - in_scan contains more than 1 row."
520 "Choose one first.");
521 mask=in_mask;
522 if (mask.nelements()!=scan->nChan())
523 throw AipsError("SDLineFinder::setScan - in_scan and in_mask have different"
524 "number of spectral channels.");
525
526 // number of elements in the in_edge tuple
527 int n=extract<int>(in_edge.attr("__len__")());
528 if (n>2 || n<0)
529 throw AipsError("SDLineFinder::setScan - the length of the in_edge parameter"
530 "should not exceed 2");
531 if (!n) {
532 // all spectrum, no rejection
533 edge.first=0;
534 edge.second=scan->nChan();
535 } else {
536 edge.first=extract<int>(in_edge.attr("__getitem__")(0));
537 if (edge.first<0)
538 throw AipsError("SDLineFinder::setScan - the in_edge parameter has a negative"
539 "number of channels to drop");
540 if (edge.first>=scan->nChan())
541 throw AipsError("SDLineFinder::setScan - all channels are rejected by the in_edge parameter");
542 if (n==2) {
543 edge.second=extract<int>(in_edge.attr("__getitem__")(1));
544 if (edge.second<0)
545 throw AipsError("SDLineFinder::setScan - the in_edge parameter has a negative"
546 "number of channels to drop");
547 edge.second=scan->nChan()-edge.second;
548 } else edge.second=scan->nChan()-edge.first;
549 if (edge.second<0 || (edge.second+edge.first)>scan->nChan())
550 throw AipsError("SDLineFinder::setScan - all channels are rejected by the in_edge parameter");
551 }
552 }
553 catch(const AipsError &ae) {
554 // setScan is unsuccessfull, reset scan/mask/edge
555 scan=CountedConstPtr<SDMemTable>(); // null pointer
556 mask.resize(0);
557 edge=pair<int,int>(0,0);
558 throw;
559 }
560}
561
562// search for spectral lines. Number of lines found is returned
563int SDLineFinder::findLines() throw(casa::AipsError)
564{
565 const int minboxnchan=4;
566 if (scan.null())
567 throw AipsError("SDLineFinder::findLines - a scan should be set first,"
568 " use set_scan");
569 DebugAssert(mask.nelements()==scan->nChan(), AipsError);
570 int max_box_nchan=int(scan->nChan()*box_size); // number of channels in running
571 // box
572 if (max_box_nchan<2)
573 throw AipsError("SDLineFinder::findLines - box_size is too small");
574
575 scan->getSpectrum(spectrum);
576
577 lines.resize(0); // search from the scratch
578 Vector<Bool> temp_mask(mask);
579
580 while (true) {
581 // line find algorithm
582 LFRunningMean lfalg(spectrum,temp_mask,edge,max_box_nchan,min_nchan,
583 threshold);
584 SignAccumulator sacc(spectrum.nelements(),spectrum);
585
586 // a buffer for new lines found at this iteration
587 std::list<pair<int,int> > new_lines;
588
589 lfalg.findLines(new_lines,&sacc);
590 if (!new_lines.size()) break; // nothing new
591
592 searchForWings(new_lines, sacc.getSigns());
593
594 // update the list (lines) merging intervals, if necessary
595 addNewSearchResult(new_lines,lines);
596 // get a new mask
597 temp_mask=getMask();
598 }
599 return int(lines.size());
600}
601
602
603// get the mask to mask out all lines that have been found (default)
604// if invert=true, only channels belong to lines will be unmasked
605// Note: all channels originally masked by the input mask (in_mask
606// in setScan) or dropped out by the edge parameter (in_edge
607// in setScan) are still excluded regardless on the invert option
608std::vector<bool> SDLineFinder::getMask(bool invert)
609 const throw(casa::AipsError)
610{
611 try {
612 if (scan.null())
613 throw AipsError("SDLineFinder::getMask - a scan should be set first,"
614 " use set_scan followed by find_lines");
615 DebugAssert(mask.nelements()==scan->nChan(), AipsError);
616 /*
617 if (!lines.size())
618 throw AipsError("SDLineFinder::getMask - one have to search for "
619 "lines first, use find_lines");
620 */
621 std::vector<bool> res_mask(mask.nelements());
622 // iterator through lines
623 std::list<std::pair<int,int> >::const_iterator cli=lines.begin();
624 for (int ch=0;ch<res_mask.size();++ch)
625 if (ch<edge.first || ch>=edge.second) res_mask[ch]=false;
626 else if (!mask[ch]) res_mask[ch]=false;
627 else {
628 res_mask[ch]=!invert; // no line by default
629 if (cli==lines.end()) continue;
630 if (ch>=cli->first && ch<cli->second)
631 res_mask[ch]=invert; // this is a line
632 if (ch>=cli->second)
633 ++cli; // next line in the list
634 }
635
636 return res_mask;
637 }
638 catch (const AipsError &ae) {
639 throw;
640 }
641 catch (const exception &ex) {
642 throw AipsError(String("SDLineFinder::getMask - STL error: ")+ex.what());
643 }
644}
645
646// get range for all lines found. If defunits is true (default), the
647// same units as used in the scan will be returned (e.g. velocity
648// instead of channels). If defunits is false, channels will be returned
649std::vector<int> SDLineFinder::getLineRanges(bool defunits)
650 const throw(casa::AipsError)
651{
652 try {
653 if (scan.null())
654 throw AipsError("SDLineFinder::getLineRanges - a scan should be set first,"
655 " use set_scan followed by find_lines");
656 DebugAssert(mask.nelements()==scan->nChan(), AipsError);
657
658 if (!lines.size())
659 throw AipsError("SDLineFinder::getLineRanges - one have to search for "
660 "lines first, use find_lines");
661
662 // temporary
663 if (defunits)
664 throw AipsError("SDLineFinder::getLineRanges - sorry, defunits=true have not "
665 "yet been implemented");
666 //
667 std::vector<int> res(2*lines.size());
668 // iterator through lines & result
669 std::list<std::pair<int,int> >::const_iterator cli=lines.begin();
670 std::vector<int>::iterator ri=res.begin();
671 for (;cli!=lines.end() && ri!=res.end();++cli,++ri) {
672 *ri=cli->first;
673 if (++ri!=res.end())
674 *ri=cli->second-1;
675 }
676 return res;
677 }
678 catch (const AipsError &ae) {
679 throw;
680 }
681 catch (const exception &ex) {
682 throw AipsError(String("SDLineFinder::getLineRanges - STL error: ")+ex.what());
683 }
684}
685
686// concatenate two lists preserving the order. If two lines appear to
687// be adjacent, they are joined into the new one
688void SDLineFinder::addNewSearchResult(const std::list<pair<int, int> > &newlines,
689 std::list<std::pair<int, int> > &lines_list)
690 throw(AipsError)
691{
692 try {
693 for (std::list<pair<int,int> >::const_iterator cli=newlines.begin();
694 cli!=newlines.end();++cli) {
695
696 // the first item, which has a non-void intersection or touches
697 // the new line
698 std::list<pair<int,int> >::iterator pos_beg=find_if(lines_list.begin(),
699 lines_list.end(), IntersectsWith(*cli));
700 // the last such item
701 std::list<pair<int,int> >::iterator pos_end=find_if(pos_beg,
702 lines_list.end(), not1(IntersectsWith(*cli)));
703
704 // extract all lines which intersect or touch a new one into
705 // a temporary buffer. This may invalidate the iterators
706 // line_buffer may be empty, if no lines intersects with a new
707 // one.
708 std::list<pair<int,int> > lines_buffer;
709 lines_buffer.splice(lines_buffer.end(),lines_list, pos_beg, pos_end);
710
711 // build a union of all intersecting lines
712 pair<int,int> union_line=for_each(lines_buffer.begin(),
713 lines_buffer.end(),BuildUnion(*cli)).result();
714
715 // search for a right place for the new line (union_line) and add
716 std::list<pair<int,int> >::iterator pos2insert=find_if(lines_list.begin(),
717 lines_list.end(), LaterThan(union_line));
718 lines_list.insert(pos2insert,union_line);
719 }
720 }
721 catch (const AipsError &ae) {
722 throw;
723 }
724 catch (const exception &ex) {
725 throw AipsError(String("SDLineFinder::addNewSearchResult - STL error: ")+ex.what());
726 }
727}
728
729// extend all line ranges to the point where a value stored in the
730// specified vector changes (e.g. value-mean change its sign)
731// This operation is necessary to include line wings, which are below
732// the detection threshold. If lines becomes adjacent, they are
733// merged together. Any masked channel stops the extension
734void SDLineFinder::searchForWings(std::list<std::pair<int, int> > &newlines,
735 const casa::Vector<casa::Int> &signs) throw(casa::AipsError)
736{
737 try {
738 for (std::list<pair<int,int> >::iterator li=newlines.begin();
739 li!=newlines.end();++li) {
740 // update the left hand side
741 for (int n=li->first-1;n>=edge.first;--n) {
742 if (!mask[n]) break;
743 if (signs[n]==signs[li->first] && signs[li->first])
744 li->first=n;
745 else break;
746 }
747 // update the right hand side
748 for (int n=li->second;n<edge.second;++n) {
749 if (!mask[n]) break;
750 if (signs[n]==signs[li->second-1] && signs[li->second-1])
751 li->second=n;
752 else break;
753 }
754 }
755 // need to search for possible mergers.
756 std::list<std::pair<int, int> > result_buffer;
757 addNewSearchResult(newlines,result_buffer);
758 newlines.clear();
759 newlines.splice(newlines.end(),result_buffer);
760 }
761 catch (const AipsError &ae) {
762 throw;
763 }
764 catch (const exception &ex) {
765 throw AipsError(String("SDLineFinder::extendLines - STL error: ")+ex.what());
766 }
767}
Note: See TracBrowser for help on using the repository browser.