Line data Source code
1 : //# ParameterParser.h
2 : //# Copyright (C) 2007
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This program is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU General Public License as published by the Free
7 : //# Software Foundation; either version 2 of the License, or (at your option)
8 : //# any later version.
9 : //#
10 : //# This program 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 General Public License for
13 : //# more details.
14 : //#
15 : //# You should have received a copy of the GNU General Public License along
16 : //# with this program; if not, write to the Free Software Foundation, Inc.,
17 : //# 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 : #include <imageanalysis/IO/ParameterParser.h>
27 :
28 : #include <casacore/casa/Arrays/Vector.h>
29 : #include <casacore/casa/Utilities/Regex.h>
30 : #include <casacore/casa/Utilities/Sort.h>
31 : #include <casacore/measures/Measures/Stokes.h>
32 : #include <casacore/casa/IO/ArrayIO.h>
33 :
34 : using namespace casacore;
35 : namespace casa {
36 :
37 632 : vector<uInt> ParameterParser::consolidateAndOrderRanges(
38 : uInt& nSelected, const vector<uInt>& ranges
39 : ) {
40 1264 : uInt arrSize = ranges.size()/2;
41 632 : uInt arrMin[arrSize];
42 632 : uInt arrMax[arrSize];
43 1287 : for (uInt i=0; i<arrSize; i++) {
44 655 : arrMin[i] = ranges[2*i];
45 655 : arrMax[i] = ranges[2*i + 1];
46 : }
47 1264 : Sort sort;
48 632 : sort.sortKey (arrMin, TpUInt);
49 632 : sort.sortKey (arrMax, TpUInt, 0, Sort::Descending);
50 1264 : Vector<uInt> inxvec;
51 632 : vector<uInt> consol(0);
52 632 : sort.sort(inxvec, arrSize);
53 1287 : for (uInt i=0; i<arrSize; i++) {
54 655 : uInt idx = inxvec(i);
55 655 : uInt size = consol.size();
56 655 : uInt min = arrMin[idx];
57 655 : uInt max = arrMax[idx];
58 655 : uInt lastMax = (i == 0) ? 0 : consol[size-1];
59 655 : if (i==0) {
60 : // consol.resize(2, true);
61 : // consol[0] = min;
62 : // consol[1] = max;
63 632 : consol.push_back(min);
64 632 : consol.push_back(max);
65 : }
66 23 : else if (
67 : // overlaps previous range, so extend
68 23 : (min < lastMax && max > lastMax)
69 : // or contiguous with previous range, so extend
70 23 : || min == lastMax + 1
71 : ) {
72 : // overwriting the end value, so do not resize
73 17 : consol[size-1] = max;
74 : }
75 :
76 6 : else if (min > lastMax + 1) {
77 : // non overlap of and not contiguous with previous range,
78 : // so create new end point pair
79 6 : consol.push_back(min);
80 6 : consol.push_back(max);
81 : }
82 : }
83 632 : nSelected = 0;
84 1270 : for (uInt i=0; i<consol.size()/2; i++) {
85 638 : nSelected += consol[2*i + 1] - consol[2*i] + 1;
86 : }
87 1896 : return consol;
88 : }
89 :
90 353 : std::vector<uInt> ParameterParser::spectralRangesFromChans(
91 : uInt& nSelectedChannels, const String& specification, const uInt nChannels
92 : ) {
93 : // First split on commas
94 706 : Vector<String> parts = stringToVector(specification, std::regex("[,;]"));
95 353 : static const Regex regexuInt("^[0-9]+$");
96 353 : static const Regex regexRange("^[0-9]+[ \n\t\r\v\f]*~[ \n\t\r\v\f]*[0-9]+$");
97 353 : static const Regex regexLT("^<.*$");
98 353 : static const Regex regexLTEq("^<=.*$");
99 353 : static const Regex regexGT("^>.*$");
100 353 : static const Regex regexGTEq("^>=.*$");
101 706 : vector<uInt> ranges(0);
102 :
103 689 : for (uInt i=0; i<parts.size(); i++) {
104 357 : parts[i].trim();
105 357 : uInt min = 0;
106 357 : uInt max = 0;
107 357 : if (parts[i].matches(regexuInt)) {
108 : // just one channel
109 310 : min = String::toInt(parts[i]);
110 310 : max = min;
111 : }
112 47 : else if(parts[i].matches(regexRange)) {
113 : // a range of channels
114 33 : Vector<String> values = stringToVector(parts[i], '~');
115 33 : ThrowIf(
116 : values.size() != 2,
117 : "Incorrect specification for channel range " + parts[i]
118 : );
119 33 : values[0].trim();
120 33 : values[1].trim();
121 99 : for(uInt j=0; j < 2; j++) {
122 66 : ThrowIf(
123 : ! values[j].matches(regexuInt),
124 : "For channel specification " + values[j]
125 : + " is not a non-negative integer in "
126 : + parts[i]
127 : );
128 : }
129 33 : min = String::toInt(values[0]);
130 33 : max = String::toInt(values[1]);
131 : }
132 14 : else if (parts[i].matches(regexLT)) {
133 0 : String maxs = parts[i].matches(regexLTEq) ? parts[i].substr(2) : parts[i].substr(1);
134 0 : maxs.trim();
135 0 : ThrowIf(
136 : ! maxs.matches(regexuInt),
137 : "In channel specification, " + maxs
138 : + " is not a non-negative integer in " + parts[i]
139 : );
140 0 : min = 0;
141 0 : max = String::toInt(maxs);
142 0 : if (! parts[i].matches(regexLTEq)) {
143 0 : ThrowIf(
144 : max == 0,
145 : "In channel specification, max channel cannot "
146 : "be less than zero in " + parts[i]
147 : );
148 0 : max--;
149 : }
150 : }
151 14 : else if (parts[i].matches(regexGT)) {
152 1 : String mins = parts[i].matches(regexGTEq)
153 0 : ? parts[i].substr(2)
154 2 : : parts[i].substr(1);
155 1 : mins.trim();
156 1 : ThrowIf(
157 : ! mins.matches(regexuInt),
158 : "In channel specification, " + mins
159 : + " is not an integer in " + parts[i]
160 : );
161 1 : max = nChannels - 1;
162 1 : min = String::toInt(mins);
163 1 : if(! parts[i].matches(regexGTEq)) {
164 1 : min++;
165 : }
166 1 : ThrowIf(
167 : min > nChannels - 1,
168 : "Min channel cannot be greater than the (zero-based) number of channels ("
169 : + String::toString(nChannels - 1) + ") in the image"
170 : );
171 : }
172 : else {
173 13 : ThrowCc(
174 : "Invalid channel specification in " + parts[i]
175 : + " of spec " + specification
176 : );
177 : }
178 344 : ThrowIf(
179 : min > max,
180 : "Min channel " + String::toString(min) + " cannot be greater than max channel "
181 : + String::toString(max) + " in " + parts[i]
182 : );
183 400 : ThrowIf(
184 : max >= nChannels,
185 : "Zero-based max channel " + String::toString(max)
186 : + " must be less than the total number of channels ("
187 : + String::toString(nChannels) + ") in the channel specification " + parts[i]
188 : );
189 336 : ranges.push_back(min);
190 336 : ranges.push_back(max);
191 : }
192 332 : vector<uInt> consolidatedRanges = consolidateAndOrderRanges(nSelectedChannels, ranges);
193 664 : return consolidatedRanges;
194 : }
195 :
196 1 : std::vector<String> ParameterParser::stokesFromString(
197 : String& specification
198 : ) {
199 1 : specification.trim();
200 1 : specification.ltrim('[');
201 1 : specification.rtrim(']');
202 1 : specification.upcase();
203 :
204 2 : Vector<String> parts = stringToVector(specification, std::regex("[,;]"));
205 2 : Vector<String> polNames = Stokes::allNames(false);
206 1 : uInt nNames = polNames.size();
207 2 : Vector<uInt> nameLengths(nNames);
208 33 : for (uInt i=0; i<nNames; ++i) {
209 32 : nameLengths[i] = polNames[i].length();
210 : }
211 1 : uInt *lengthData = nameLengths.data();
212 :
213 2 : Vector<uInt> idx(nNames);
214 2 : Sort sorter;
215 1 : sorter.sortKey(lengthData, TpUInt, 0, Sort::Descending);
216 1 : sorter.sort(idx, nNames);
217 :
218 2 : Vector<String> sortedNames(nNames);
219 33 : for (uInt i=0; i<nNames; i++) {
220 32 : sortedNames[i] = polNames[idx[i]];
221 32 : sortedNames[i].upcase();
222 : }
223 1 : vector<String> myStokes;
224 2 : for (uInt i=0; i<parts.size(); i++) {
225 2 : String part = parts[i];
226 1 : part.trim();
227 2 : Vector<String>::iterator iter = sortedNames.begin();
228 2 : vector<Int> stokes;
229 63 : while (iter != sortedNames.end() && ! part.empty()) {
230 62 : if (part.startsWith(*iter)) {
231 2 : myStokes.push_back(*iter);
232 : // consume the string
233 2 : part = part.substr(iter->length());
234 2 : if (! part.empty()) {
235 : // reset the iterator to start over at the beginning of the list for
236 : // the next specified polarization
237 1 : iter = sortedNames.begin();
238 : }
239 : }
240 : else {
241 60 : ++iter;
242 : }
243 : }
244 1 : ThrowIf(
245 : ! part.empty(),
246 : "(Sub)String " + part + " in stokes specification part " + parts[i]
247 : + " does not match a known polarization."
248 : );
249 : }
250 2 : return myStokes;
251 : }
252 :
253 :
254 : }
|