Line data Source code
1 : //# ComponentShape.cc:
2 : //# Copyright (C) 1998,1999,2000
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 : //# $Id: ComponentShape.cc 21130 2011-10-18 07:39:05Z gervandiepen $
27 :
28 : #include <components/ComponentModels/ComponentShape.h>
29 : #include <casacore/casa/Arrays/ArrayLogical.h>
30 : #include <casacore/casa/Arrays/Matrix.h>
31 : #include <casacore/casa/Arrays/Vector.h>
32 : #include <casacore/casa/Arrays/IPosition.h>
33 : #include <casacore/casa/Containers/Record.h>
34 : #include <casacore/casa/Containers/RecordFieldId.h>
35 : #include <casacore/casa/Containers/RecordInterface.h>
36 : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
37 : #include <casacore/casa/Exceptions/Error.h>
38 : #include <casacore/casa/Logging/LogIO.h>
39 : #include <casacore/casa/BasicSL/Complex.h>
40 : #include <casacore/measures/Measures/MeasureHolder.h>
41 : #include <casacore/measures/Measures/MeasFrame.h>
42 : #include <casacore/measures/Measures/MeasRef.h>
43 : #include <casacore/casa/Quanta/Quantum.h>
44 : #include <casacore/casa/Quanta/UnitVal.h>
45 : #include <casacore/casa/Utilities/Assert.h>
46 : #include <casacore/casa/Utilities/DataType.h>
47 : #include <casacore/casa/BasicSL/String.h>
48 : #include <casacore/casa/Quanta/QuantumHolder.h>
49 :
50 : using namespace casacore;
51 : namespace casa { //# NAMESPACE CASA - BEGIN
52 :
53 128999 : ComponentShape::ComponentShape()
54 128999 : :itsDir(),
55 128999 : itsDirErrLat(0, "rad"),
56 257998 : itsDirErrLong(0, "rad")
57 : {
58 128999 : DebugAssert(ComponentShape::ok(), AipsError);
59 128999 : }
60 :
61 3245 : ComponentShape::ComponentShape(const MDirection& direction)
62 3245 : :itsDir(direction),
63 3245 : itsDirErrLat(0, "rad"),
64 6490 : itsDirErrLong(0, "rad")
65 : {
66 3245 : DebugAssert(ComponentShape::ok(), AipsError);
67 3245 : }
68 :
69 30044 : ComponentShape::ComponentShape(const ComponentShape& other)
70 : :RecordTransformable(),
71 30044 : itsDir(other.itsDir),
72 30044 : itsDirErrLat(other.itsDirErrLat),
73 60088 : itsDirErrLong(other.itsDirErrLong)
74 : {
75 30044 : DebugAssert(ComponentShape::ok(), AipsError);
76 30044 : }
77 :
78 :
79 162287 : ComponentShape::~ComponentShape() {
80 162287 : }
81 :
82 2719 : const String& ComponentShape::ident() const {
83 2719 : DebugAssert(ComponentShape::ok(), AipsError);
84 2719 : static String typeString;
85 2719 : typeString = ComponentType::name(type());
86 2719 : return typeString;
87 : }
88 :
89 4 : ComponentShape& ComponentShape::operator=(const ComponentShape& other) {
90 4 : if (this != &other) {
91 4 : itsDir = other.itsDir;
92 4 : itsDirErrLat = other.itsDirErrLat;
93 4 : itsDirErrLong = other.itsDirErrLong;
94 : }
95 4 : DebugAssert(ComponentShape::ok(), AipsError);
96 4 : return *this;
97 : }
98 :
99 4 : void ComponentShape::copyDirectionInfo(const ComponentShape& that) {
100 : // Call only this class' = method only, not the subclass version
101 4 : ComponentShape::operator=(that);
102 4 : }
103 :
104 :
105 79782 : void ComponentShape::setRefDirection(const MDirection& newRefDir) {
106 79782 : itsDir = newRefDir;
107 79782 : DebugAssert(ComponentShape::ok(), AipsError);
108 79782 : }
109 :
110 63503 : const MDirection& ComponentShape::refDirection() const {
111 63503 : DebugAssert(ComponentShape::ok(), AipsError);
112 63503 : return itsDir;
113 : }
114 :
115 : void
116 79831 : ComponentShape::setRefDirectionError(
117 : const Quantum<Double>& newRefDirErrLat,
118 : const Quantum<Double>& newRefDirErrLong
119 : ) {
120 79831 : ThrowIf(
121 : badError(newRefDirErrLat) || badError(newRefDirErrLong),
122 : "The errors must be non-negative angular quantities"
123 : );
124 79831 : itsDirErrLat = newRefDirErrLat;
125 79831 : itsDirErrLong = newRefDirErrLong;
126 79831 : DebugAssert(ComponentShape::ok(), AipsError);
127 79831 : }
128 :
129 10471 : const Quantum<Double>& ComponentShape::refDirectionErrorLat() const {
130 10471 : return itsDirErrLat;
131 : }
132 :
133 10471 : const Quantum<Double>& ComponentShape::refDirectionErrorLong() const {
134 10471 : return itsDirErrLong;
135 : }
136 :
137 0 : void ComponentShape::sample(Vector<Double>& scale,
138 : const Vector<MDirection::MVType>& directions,
139 : const MDirection::Ref& refFrame,
140 : const MVAngle& pixelLatSize,
141 : const MVAngle& pixelLongSize) const {
142 0 : DebugAssert(ComponentShape::ok(), AipsError);
143 0 : const uInt nSamples = directions.nelements();
144 0 : DebugAssert(scale.nelements() == nSamples, AipsError);
145 :
146 0 : for (uInt i = 0; i < nSamples; i++) {
147 0 : scale(i) = sample(MDirection(directions(i), refFrame),
148 : pixelLatSize, pixelLongSize);
149 : }
150 0 : }
151 :
152 0 : void ComponentShape::visibility(Vector<DComplex>& scale,
153 : const Matrix<Double>& uvw,
154 : const Double& frequency) const {
155 0 : DebugAssert(ComponentShape::ok(), AipsError);
156 0 : const uInt nSamples = scale.nelements();
157 0 : DebugAssert(uvw.ncolumn() == nSamples, AipsError);
158 0 : DebugAssert(uvw.nrow() == 3, AipsError);
159 :
160 0 : for (uInt i = 0; i < nSamples; i++) {
161 0 : scale(i) = visibility(uvw.column(i), frequency);
162 : }
163 0 : }
164 :
165 980 : void ComponentShape::visibility(Matrix<DComplex>& scale,
166 : const Matrix<Double>& uvw,
167 : const Vector<Double>& frequencies) const {
168 980 : DebugAssert(ComponentShape::ok(), AipsError);
169 980 : const uInt nuvw = uvw.ncolumn();
170 980 : const uInt nfreq=frequencies.nelements();
171 980 : DebugAssert(nfreq >0 , AipsError);
172 980 : scale.resize(nuvw, nfreq);
173 3430 : for (uInt j =0 ; j < nfreq; ++j){
174 602700 : for (uInt i = 0; i < nuvw; i++) {
175 600250 : scale(i,j) = visibility(uvw.column(i), frequencies[j]);
176 : }
177 : }
178 980 : }
179 :
180 78012 : Bool ComponentShape::fromRecord(String& errorMessage,
181 : const RecordInterface& record) {
182 78012 : const String dirString("direction");
183 78012 : if (!record.isDefined(dirString)) {
184 : // The there is no direction field then the direction is NOT changed!
185 37 : return true;
186 : }
187 77975 : const RecordFieldId direction(dirString);
188 77975 : if (record.dataType(direction) != TpRecord) {
189 0 : errorMessage += "The 'direction' field must be a record\n";
190 0 : return false;
191 : }
192 77975 : const Record& dirRecord = record.asRecord(direction);
193 77975 : MeasureHolder mh;
194 77975 : if (!mh.fromRecord(errorMessage, dirRecord)) {
195 0 : errorMessage += "Could not parse the reference direction\n";
196 0 : return false;
197 : }
198 77975 : if (!mh.isMDirection()) {
199 0 : errorMessage += "The reference direction is not a direction measure\n";
200 0 : return false;
201 : }
202 77975 : setRefDirection(mh.asMDirection());
203 77975 : const String errorString("error");
204 77975 : if (!dirRecord.isDefined(errorString)) {
205 : // The there is no error field then the error is NOT changed!
206 0 : return true;
207 : }
208 77975 : const RecordFieldId error(errorString);
209 77975 : if (dirRecord.dataType(error) != TpRecord) {
210 0 : errorMessage += "The 'error' field must be a record\n";
211 0 : return false;
212 : }
213 77975 : const Record& errRecord = dirRecord.asRecord(error);
214 :
215 77975 : Quantum<Double> longErr, latErr;
216 233925 : if (!fromAngQRecord(longErr, errorMessage, "longitude", errRecord) ||
217 155950 : !fromAngQRecord(latErr, errorMessage, "latitude", errRecord)) {
218 0 : errorMessage += "Direction error not changed\n";
219 0 : return false;
220 : }
221 77975 : setRefDirectionError(latErr, longErr);
222 77975 : DebugAssert(ComponentShape::ok(), AipsError);
223 77975 : return true;
224 78012 : }
225 :
226 7375 : Bool ComponentShape::toRecord(String& errorMessage,
227 : RecordInterface& record) const {
228 7375 : DebugAssert(ComponentShape::ok(), AipsError);
229 7375 : record.define(RecordFieldId("type"), ComponentType::name(type()));
230 7375 : Record dirRecord;
231 7375 : const MeasureHolder mh(refDirection());
232 7375 : if (!mh.toRecord(errorMessage, dirRecord)) {
233 0 : errorMessage += "Could not convert the reference direction to a record\n";
234 0 : return false;
235 : }
236 :
237 7375 : Record errRec;
238 : {
239 7375 : const QuantumHolder qhLong(refDirectionErrorLong());
240 7375 : const QuantumHolder qhLat(refDirectionErrorLat());
241 7375 : Record latRec, longRec;
242 14750 : if (!qhLong.toRecord(errorMessage, longRec) ||
243 7375 : !qhLat.toRecord(errorMessage, latRec)) {
244 0 : errorMessage += "Could not convert the direction errors to a record\n";
245 0 : return false;
246 : }
247 7375 : errRec.defineRecord(RecordFieldId("longitude"), longRec);
248 7375 : errRec.defineRecord(RecordFieldId("latitude"), latRec);
249 7375 : }
250 7375 : dirRecord.defineRecord(RecordFieldId("error"), errRec);
251 7375 : record.defineRecord(RecordFieldId("direction"), dirRecord);
252 7375 : return true;
253 7375 : }
254 :
255 23802544 : Bool ComponentShape::ok() const {
256 23802544 : if (ComponentShape::badError(itsDirErrLat)) {
257 0 : LogIO logErr(LogOrigin("ComponentShape", "ok()"));
258 0 : logErr << LogIO::SEVERE << "The latitude error is bad." << LogIO::POST;
259 0 : return false;
260 0 : }
261 23802544 : if (ComponentShape::badError(itsDirErrLong)) {
262 0 : LogIO logErr(LogOrigin("ComponentShape", "ok()"));
263 0 : logErr << LogIO::SEVERE << "The longitude error is bad." << LogIO::POST;
264 0 : return false;
265 0 : }
266 23802544 : return true;
267 : }
268 :
269 77975 : ComponentType::Shape ComponentShape::getType(String& errorMessage,
270 : const RecordInterface& record) {
271 77975 : const String typeString("type");
272 77975 : if (!record.isDefined(typeString)) {
273 : errorMessage +=
274 0 : String("The 'shape' record does not have a 'type' field.\n");
275 0 : return ComponentType::UNKNOWN_SHAPE;
276 : }
277 77975 : const RecordFieldId type(typeString);
278 77975 : if (record.dataType(type) != TpString) {
279 0 : errorMessage += String("The 'type' field, in the shape record,") +
280 0 : String(" must be a String\n");
281 0 : return ComponentType::UNKNOWN_SHAPE;
282 : }
283 77975 : if (record.shape(type) != IPosition(1,1)) {
284 0 : errorMessage += String("The 'type' field, in the shape record,") +
285 0 : String(" must have only 1 element\n");
286 0 : return ComponentType::UNKNOWN_SHAPE;
287 : }
288 77975 : const String& typeVal = record.asString(type);
289 77975 : return ComponentType::shape(typeVal);
290 77975 : }
291 :
292 738 : Vector<Double> ComponentShape::toPixel (const DirectionCoordinate& dirCoord) const
293 : {
294 738 : Vector<Double> pixelCen(2);
295 738 : if (!dirCoord.toPixel(pixelCen, itsDir)) {
296 0 : LogIO os(LogOrigin("ComponentShape", "toPixel(...)"));
297 : os << "DirectionCoordinate conversion to pixel failed because "
298 0 : << dirCoord.errorMessage() << LogIO::EXCEPTION;
299 0 : }
300 738 : return pixelCen;
301 0 : }
302 :
303 :
304 526 : Bool ComponentShape::fromPixel (const Vector<Double>& parameters,
305 : const DirectionCoordinate& dirCoord)
306 : {
307 1052 : LogIO os(LogOrigin("ComponentShape", "fromPixel(...)"));
308 526 : if (parameters.nelements()!=2) {
309 0 : os << "You must give a vector of length 2" << LogIO::EXCEPTION;
310 : }
311 : //
312 526 : if (!dirCoord.toWorld(itsDir, parameters)) {
313 : os << "DirectionCoordinate conversion to pixel failed because "
314 0 : << dirCoord.errorMessage() << LogIO::EXCEPTION;
315 : }
316 526 : return true;
317 526 : }
318 :
319 :
320 2491 : Bool ComponentShape::differentRefs(const MeasRef<MDirection>& ref1,
321 : const MeasRef<MDirection>& ref2) {
322 2491 : if (ref1.getType() != ref2.getType()) return true;
323 : //# The MeasRef<T>::getFrame function should really be const.
324 2491 : const MeasFrame& frame1 = const_cast<MeasRef<MDirection>&>(ref1).getFrame();
325 2491 : const MeasFrame& frame2 = const_cast<MeasRef<MDirection>&>(ref2).getFrame();
326 2491 : if (frame1.empty() && frame2.empty()) return false;
327 2410 : return frame1 == frame2;
328 : //# I should also check the offsets but I cannot see how to fish
329 : //# them out of the MeasRef<T> class
330 : }
331 :
332 47810944 : Bool ComponentShape::badError(const Quantum<Double>& quantum) {
333 47810944 : return !(quantum.check(UnitVal::ANGLE)) || (quantum.getValue() < 0.0);
334 : }
335 :
336 245074 : Bool ComponentShape::fromAngQRecord(Quantum<Double>& retVal,
337 : String& errorMessage,
338 : const String& fieldString,
339 : const RecordInterface& record) {
340 :
341 245074 : if (!record.isDefined(fieldString)) {
342 0 : errorMessage += "The '" + fieldString + "' field does not exist\n";
343 0 : return false;
344 : }
345 245074 : const RecordFieldId field(fieldString);
346 245074 : if (!(record.dataType(field) == TpRecord ||
347 0 : ((record.dataType(field) == TpString) &&
348 245074 : (record.shape(field) == IPosition(1,1))))) {
349 0 : errorMessage += "The '" + fieldString + "' field must be a record\n";
350 0 : errorMessage += "or a string (but not a vector of strings)\n";
351 0 : return false;
352 : }
353 245074 : QuantumHolder qHolder;
354 245074 : if (record.dataType(field) == TpString) {
355 0 : if (!qHolder.fromString(errorMessage, record.asString(field))) {
356 0 : errorMessage += "Problem parsing the '" + fieldString + "' string\n";
357 0 : return false;
358 : }
359 245074 : } else if (!qHolder.fromRecord(errorMessage, record.asRecord(field))) {
360 0 : errorMessage += "Problem parsing the '" + fieldString +"' record\n";
361 0 : return false;
362 : }
363 245074 : if (!(qHolder.isScalar() && qHolder.isReal())) {
364 0 : errorMessage += "The '" + fieldString + "' field is not a quantity\n";
365 0 : return false;
366 : }
367 245074 : retVal = qHolder.asQuantumDouble();
368 245074 : if (retVal.getFullUnit() != Unit("rad")) {
369 0 : errorMessage += "The '" + fieldString +
370 0 : "' field must have angular units\n";
371 0 : return false;
372 : }
373 245074 : return true;
374 245074 : }
375 :
376 : // Local Variables:
377 : // compile-command: "gmake ComponentShape"
378 : // End:
379 :
380 : } //# NAMESPACE CASA - END
381 :
|