Line data Source code
1 : //# BeamCalc.cc: Implementation for BeamCalc
2 : //# Copyright (C) 1996,1997,1998,1999,2000,2002
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 adressed 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 : //#
27 : //# $Id$
28 :
29 : //#include <stdio.h>
30 : //#include <complex.h>
31 : #include <cmath>
32 : #include <math.h>
33 : //#include <stdlib.h>
34 : //#include <string.h>
35 : #include <casacore/images/Images/TempImage.h>
36 : #include <synthesis/MeasurementEquations/AntennaResponses.h>
37 : #include <casacore/tables/Tables/TableProxy.h>
38 : #include <casacore/casa/Exceptions.h>
39 : #include <casacore/casa/Containers/ValueHolder.h>
40 : #include <casacore/casa/Arrays/Array.h>
41 : #include <synthesis/TransformMachines/SynthesisError.h>
42 : #include <synthesis/TransformMachines/BeamCalc.h>
43 : #include <casacore/casa/OS/Timer.h>
44 : #include <casacore/casa/System/AppState.h>
45 : #include <casacore/casa/OS/Directory.h>
46 : #include <casatools/Config/State.h>
47 : #ifdef _OPENMP
48 : #include <omp.h>
49 : #endif
50 : #if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 4))
51 : #define GCC44x 1
52 : #else
53 : #define GCC44x 0
54 : #endif
55 :
56 :
57 : using namespace std;
58 : using namespace casacore;
59 : namespace casa{
60 :
61 : const Double BeamCalc::METER_INCH = 39.37008;
62 : const Double BeamCalc::INCH_METER = (1.0/BeamCalc::METER_INCH);
63 : const Double BeamCalc::NS_METER = 0.299792458; // Exact
64 : const Double BeamCalc::METER_NS = (1.0/BeamCalc::NS_METER);
65 : const Double BeamCalc::DEG_RAD = M_PI/180.0;
66 : const Double BeamCalc::RAD_DEG = 180.0/M_PI;
67 :
68 : BeamCalc* BeamCalc::instance_p = 0;
69 :
70 0 : BeamCalc::BeamCalc():
71 : obsName_p(""),
72 : antType_p(""),
73 : obsTime_p(),
74 : BeamCalc_NumBandCodes_p(0),
75 : BeamCalcGeometries_p(0),
76 : bandMinFreq_p(0),
77 : bandMaxFreq_p(0),
78 0 : antRespPath_p(""){
79 0 : }
80 :
81 0 : BeamCalc* BeamCalc::Instance(){
82 0 : if(instance_p==0){
83 0 : instance_p = new BeamCalc();
84 : }
85 0 : return instance_p;
86 : }
87 :
88 : // initialise the beam calculation parameters
89 0 : void BeamCalc::setBeamCalcGeometries(const String& obsName,
90 : const String& antType,
91 : const MEpoch& obsTime,
92 : const String& otherAntRayPath){
93 :
94 0 : Unit uS("s");
95 0 : Bool verbose = false;
96 :
97 :
98 0 : if(obsName==obsName_p
99 0 : && antType==antType_p
100 0 : && obsTime.get(uS).getValue()==obsTime_p.get(uS).getValue()
101 0 : && otherAntRayPath.empty()
102 : ){
103 0 : return; // nothing to do (assuming the databases haven't changed)
104 : }
105 :
106 0 : cout << "Processing request for geometries from observatory " << obsName << ", antenna type " << antType << endl;
107 :
108 0 : LogIO os;
109 0 : os << LogOrigin("BeamCalc", "setBeamCalcGeometries()");
110 :
111 0 : if(obsName!=""){
112 0 : obsName_p = obsName;
113 : }
114 0 : if(antType!=""){
115 0 : antType_p = antType;
116 : }
117 0 : obsTime_p = obsTime;
118 :
119 :
120 0 : BeamCalcGeometries_p.resize(0);
121 :
122 0 : AntennaResponses aR;
123 0 : String antRespPath;
124 0 : String antRayPath = otherAntRayPath;
125 :
126 0 : Bool useInternal = false;
127 :
128 0 : os << LogIO::NORMAL << "Initialisation of geometries for observatory " << obsName_p
129 0 : << ", antenna type " << antType_p << LogIO::POST;
130 :
131 0 : if(otherAntRayPath.empty()){
132 0 : if(!MeasTable::AntennaResponsesPath(antRespPath, obsName_p)) {
133 0 : useInternal = true;
134 : }
135 : else{
136 0 : if(!aR.init(antRespPath)){
137 : // init failed
138 : String mesg="Initialisation of antenna response parameters for observatory "
139 0 : +obsName_p+" failed using path "+antRespPath;
140 0 : SynthesisError err(mesg);
141 0 : throw(err);
142 : }
143 : uInt respImageChannel;
144 0 : MFrequency respImageNomFreq;
145 : AntennaResponses::FuncTypes respImageFType;
146 0 : MVAngle respImageRotOffset;
147 :
148 0 : if(!aR.getImageName(antRayPath,
149 : respImageChannel,
150 : respImageNomFreq,
151 : respImageFType,
152 : respImageRotOffset,
153 : //
154 0 : obsName_p,
155 0 : obsTime_p,
156 0 : MFrequency(Quantity(0.,Unit("Hz")), MFrequency::TOPO), // any frequency
157 0 : AntennaResponses::INTERNAL,
158 0 : antType_p
159 : )
160 : ){ // no matching response found
161 : os << LogIO::NORMAL << "No matching antenna response found for observatory "
162 0 : << obsName_p << LogIO::POST;
163 0 : useInternal = true;
164 : }
165 : }
166 :
167 0 : if(useInternal){
168 :
169 0 : Bool found = False;
170 0 : String fullFileName;
171 0 : const std::list<std::string> &data_path = AppStateSource::fetch( ).dataPath( );
172 0 : const std::string distrodata_path =casatools::get_state().distroDataPath( );
173 : //cerr<<"distrodata_path="<<distrodata_path<<endl;
174 : //cerr<<"DATA PATH==="<< *data_path <<endl;
175 : // The data path search need to be rewritten to adopt the recommanded setting via python
176 : // file for CASA6.
177 : // For now, only the first path that actually exist will be set to the data path (TT 2018.12.10)
178 0 : if (data_path.size() > 0 ) {
179 0 : for ( std::list<std::string>::const_iterator it=data_path.begin(); ! found && it != data_path.end(); ++it ) {
180 0 : Path lpath = Path(*it);
181 : //os<<"Here to datapath="<<lpath<<LogIO::POST;
182 : //Path lpath = Path(data_path);
183 0 : String slpath = lpath.absoluteName();
184 0 : String subdirname;
185 0 : if(obsName_p=="VLA" || obsName_p=="EVLA") {
186 0 : subdirname="/nrao/VLA";
187 : }
188 0 : else if(obsName_p=="ALMA"){
189 0 : subdirname="/alma/response";
190 : }
191 : //Directory ddir(slpath+subdirname);
192 : try {
193 0 : Directory ddir(slpath+subdirname);
194 0 : ddir.exists();
195 0 : found = True;
196 0 : fullFileName=slpath;
197 0 : break;
198 : }
199 0 : catch (...) {
200 : }
201 :
202 : //if (ddir.exists()) {
203 : // cerr<<" ddir exists:"<<slpath<<subdirname<<endl;
204 : // found = True;
205 : // fullFileName=slpath;
206 : // break;
207 : //}
208 : }
209 0 : if (!found && distrodata_path!="") {
210 0 : fullFileName = distrodata_path;
211 0 : found = True;
212 : }
213 : }
214 0 : else if(!found) {
215 0 : const char *sep=" ";
216 0 : char *aipsPath = strtok(getenv("CASAPATH"),sep);
217 0 : if (aipsPath == NULL)
218 0 : throw(SynthesisError("CASAPATH not found."));
219 0 : fullFileName=aipsPath;
220 0 : fullFileName+="/data";
221 : }
222 :
223 :
224 0 : if(obsName_p=="VLA" && antType_p=="STANDARD"){
225 0 : os << LogIO::NORMAL << "Will use default geometries for VLA STANDARD." << LogIO::POST;
226 0 : BeamCalc_NumBandCodes_p = VLABeamCalc_NumBandCodes;
227 0 : BeamCalcGeometries_p.resize(BeamCalc_NumBandCodes_p);
228 0 : bandMinFreq_p.resize(BeamCalc_NumBandCodes_p);
229 0 : bandMaxFreq_p.resize(BeamCalc_NumBandCodes_p);
230 0 : for(uInt i=0; i<BeamCalc_NumBandCodes_p; i++){
231 0 : copyBeamCalcGeometry(&BeamCalcGeometries_p[i], &VLABeamCalcGeometryDefaults[i]);
232 0 : bandMinFreq_p[i] = VLABandMinFreqDefaults[i];
233 0 : bandMaxFreq_p[i] = VLABandMaxFreqDefaults[i];
234 : }
235 : //antRespPath_p = fullFileName + "/data/nrao/VLA";
236 0 : antRespPath_p = fullFileName + "/nrao/VLA";
237 : }
238 0 : else if(obsName_p=="EVLA" && antType_p=="STANDARD"){
239 0 : os << LogIO::NORMAL << "Will use default geometries for EVLA STANDARD." << LogIO::POST;
240 0 : BeamCalc_NumBandCodes_p = EVLABeamCalc_NumBandCodes;
241 0 : BeamCalcGeometries_p.resize(BeamCalc_NumBandCodes_p);
242 0 : bandMinFreq_p.resize(BeamCalc_NumBandCodes_p);
243 0 : bandMaxFreq_p.resize(BeamCalc_NumBandCodes_p);
244 0 : for(uInt i=0; i<BeamCalc_NumBandCodes_p; i++){
245 0 : copyBeamCalcGeometry(&BeamCalcGeometries_p[i], &EVLABeamCalcGeometryDefaults[i]);
246 0 : bandMinFreq_p[i] = EVLABandMinFreqDefaults[i];
247 0 : bandMaxFreq_p[i] = EVLABandMaxFreqDefaults[i];
248 : }
249 : //antRespPath_p = fullFileName + "/data/nrao/VLA";
250 0 : antRespPath_p = fullFileName + "/nrao/VLA";
251 : }
252 0 : else if(obsName_p=="ALMA" && (antType_p=="DA" || antType_p=="DV" || antType_p=="PM")){
253 0 : os << LogIO::NORMAL << "Will use default geometries for ALMA DA, DV, and PM." << LogIO::POST;
254 0 : BeamCalc_NumBandCodes_p = ALMABeamCalc_NumBandCodes;
255 0 : BeamCalcGeometries_p.resize(BeamCalc_NumBandCodes_p);
256 0 : bandMinFreq_p.resize(BeamCalc_NumBandCodes_p);
257 0 : bandMaxFreq_p.resize(BeamCalc_NumBandCodes_p);
258 0 : for(uInt i=0; i<BeamCalc_NumBandCodes_p; i++){
259 0 : copyBeamCalcGeometry(&BeamCalcGeometries_p[i], &ALMABeamCalcGeometryDefaults[i]);
260 0 : if(antType_p=="DA"){
261 0 : BeamCalcGeometries_p[i].legwidth *= -1.; // change from + to x shape
262 : }
263 0 : bandMinFreq_p[i] = ALMABandMinFreqDefaults[i];
264 0 : bandMaxFreq_p[i] = ALMABandMaxFreqDefaults[i];
265 : }
266 : //antRespPath_p = fullFileName + "/data/alma/responses";
267 0 : antRespPath_p = fullFileName + "/alma/responses";
268 : }
269 : else{
270 : String mesg="We don't have any antenna ray tracing parameters available for observatory "
271 0 : +obsName_p+", antenna type "+antType_p;
272 0 : SynthesisError err(mesg);
273 0 : throw(err);
274 : }
275 0 : return;
276 : } // end if(useInternal)
277 : }
278 :
279 :
280 0 : os << LogIO::NORMAL << "from file " << antRayPath << endl;
281 :
282 : try {
283 : // read temp table from ASCII file
284 0 : TableProxy antParTab = TableProxy(antRayPath, String(""), String("tempRayTraceTab.tab"),
285 0 : false, IPosition(), // autoheader, autoshape
286 0 : String(" "), // separator
287 0 : String("#"), // comment marker
288 : 0,-1, // first and last line
289 0 : Vector<String>(), Vector<String>());
290 :
291 0 : antParTab.deleteTable(true); // table will be deleted when it goes out of scope
292 :
293 : // read the table
294 0 : uInt nRows = antParTab.nrows();
295 0 : BeamCalc_NumBandCodes_p = nRows;
296 :
297 0 : BeamCalcGeometries_p.resize(BeamCalc_NumBandCodes_p);
298 0 : bandMinFreq_p.resize(BeamCalc_NumBandCodes_p);
299 0 : bandMaxFreq_p.resize(BeamCalc_NumBandCodes_p);
300 :
301 0 : for(uInt i=0; i<BeamCalc_NumBandCodes_p; i++){
302 0 : sprintf(BeamCalcGeometries_p[i].name, "%s", antParTab.getCell("NAME", i).asString().c_str());
303 0 : bandMinFreq_p[i] = antParTab.getCell("MINFREQ", i).asDouble() * 1E9; // expect GHz
304 0 : bandMaxFreq_p[i] = antParTab.getCell("MAXFREQ", i).asDouble() * 1E9;
305 0 : BeamCalcGeometries_p[i].sub_h = antParTab.getCell("SUB_H", i).asDouble();
306 0 : Array<Double> ta1;
307 0 : ta1.assign(antParTab.getCell("FEEDPOS", i).asArrayDouble());
308 0 : for(uInt j=0; j<3;j++){
309 0 : BeamCalcGeometries_p[i].feedpos[j] = ta1(IPosition(1,j));
310 : }
311 0 : BeamCalcGeometries_p[i].subangle = antParTab.getCell("SUBANGLE", i).asDouble();
312 0 : BeamCalcGeometries_p[i].legwidth = antParTab.getCell("LEGWIDTH", i).asDouble();
313 0 : BeamCalcGeometries_p[i].legfoot = antParTab.getCell("LEGFOOT", i).asDouble();
314 0 : BeamCalcGeometries_p[i].legapex = antParTab.getCell("LEGAPEX", i).asDouble();
315 0 : BeamCalcGeometries_p[i].Rhole = antParTab.getCell("RHOLE", i).asDouble();
316 0 : BeamCalcGeometries_p[i].Rant = antParTab.getCell("RANT", i).asDouble();
317 0 : BeamCalcGeometries_p[i].reffreq = antParTab.getCell("REFFREQ", i).asDouble(); // stay in GHz
318 0 : Array<Double> ta2;
319 0 : ta2.assign(antParTab.getCell("TAPERPOLY", i).asArrayDouble());
320 0 : for(uInt j=0; j<5;j++){
321 0 : BeamCalcGeometries_p[i].taperpoly[j] = ta2(IPosition(1,j));
322 : }
323 0 : BeamCalcGeometries_p[i].ntaperpoly = antParTab.getCell("NTAPERPOLY", i).asInt();
324 0 : BeamCalcGeometries_p[i].astigm_0 = antParTab.getCell("ASTIGM_0", i).asDouble();
325 0 : BeamCalcGeometries_p[i].astigm_45 = antParTab.getCell("ASTIGM_45", i).asDouble();
326 0 : if(verbose){
327 : cout << "i name bandMinFreq_p bandMaxFreq_p sub_h feedpos feedpos feedpos subangle legwidth legfoot legapex"
328 0 : << " Rhole Rant reffreq taperpoly taperpoly taperpoly taperpoly taperpoly ntaperpoly astigm0 astigm45" << endl;
329 0 : cout << i << " " << BeamCalcGeometries_p[i].name << " " << bandMinFreq_p[i] << " " << bandMaxFreq_p[i]
330 0 : << " " << BeamCalcGeometries_p[i].sub_h
331 0 : << " " << BeamCalcGeometries_p[i].feedpos[0] << " " << BeamCalcGeometries_p[i].feedpos[1]
332 0 : << " " << BeamCalcGeometries_p[i].feedpos[2]
333 0 : << " " << BeamCalcGeometries_p[i].subangle << " " << BeamCalcGeometries_p[i].legwidth
334 0 : << " " << BeamCalcGeometries_p[i].legfoot << " " << BeamCalcGeometries_p[i].legapex
335 0 : << " " << BeamCalcGeometries_p[i].Rhole << " " << BeamCalcGeometries_p[i].Rant << " " << BeamCalcGeometries_p[i].reffreq
336 0 : << " " << BeamCalcGeometries_p[i].taperpoly[0] << " " << BeamCalcGeometries_p[i].taperpoly[1]
337 0 : << " " << BeamCalcGeometries_p[i].taperpoly[2] << " " << BeamCalcGeometries_p[i].taperpoly[3]
338 0 : << " " << BeamCalcGeometries_p[i].taperpoly[4] << " " << BeamCalcGeometries_p[i].ntaperpoly
339 0 : << " " << BeamCalcGeometries_p[i].astigm_0 << " " << BeamCalcGeometries_p[i].astigm_45 << endl;
340 : }
341 : }
342 :
343 0 : } catch (AipsError x) {
344 0 : String mesg="Initialisation of antenna ray tracing parameters for observatory "+obsName_p
345 0 : +" failed using path "+antRayPath+"\n with message "+x.getMesg();
346 0 : BeamCalcGeometries_p.resize(0);
347 0 : SynthesisError err(mesg);
348 0 : throw(err);
349 : }
350 :
351 0 : if(antRespPath.empty()){ // use containing directory of the antRayPath
352 0 : antRespPath_p = Path(antRayPath).dirName();
353 : }
354 : else{
355 0 : antRespPath_p = Path(antRespPath).dirName();
356 : }
357 :
358 0 : os << LogIO::NORMAL << "... successful." << LogIO::POST;
359 :
360 0 : return;
361 :
362 : }
363 :
364 0 : Int BeamCalc::getBandID(Double freq, // in Hz
365 : const String& obsName,
366 : const String& bandName,
367 : const String& antType,
368 : const MEpoch& obsTime,
369 : const String& otherAntRayPath){
370 :
371 0 : setBeamCalcGeometries(obsName, antType, obsTime, otherAntRayPath);
372 :
373 : // Check against bandName if it is a non-NULL string. Otherwise
374 : // check against frequency range. The latter method is only for
375 : // backward compatibility reasons and for older MSes which did not
376 : // have correct band names in the SPW sub-table.
377 0 : if (bandName != "")
378 0 : for(uInt i=0; i<BeamCalcGeometries_p.nelements(); i++)
379 0 : if(String(BeamCalcGeometries_p[i].bandName)==bandName) return i;
380 :
381 : // If the control flow gets here, the given bandName did not match
382 : // in SPW names in the MS. So use the fall-back option of using
383 : // the reference frequency to get the band ID (this will lead to
384 : // incorrect ID for the edge SPWs which might overlap in frequecy
385 : // with the adjecent band).
386 0 : for(uInt i=0; i<BeamCalc_NumBandCodes_p; i++){
387 0 : if((bandMinFreq_p[i]<=freq)&&(freq<=bandMaxFreq_p[i])){
388 0 : return i;
389 : }
390 : }
391 0 : ostringstream mesg;
392 0 : mesg << obsName << "/" << bandName << "/" << antType << "/" << freq << "(Hz) combination not recognized.";
393 0 : throw(SynthesisError(mesg.str()));
394 :
395 : }
396 :
397 :
398 :
399 0 : calcAntenna* BeamCalc::newAntenna(Double sub_h, Double feed_x, Double feed_y, Double feed_z,
400 : Double ftaper, Double thmax, const char *geomfile)
401 : {
402 : calcAntenna *a;
403 : Int i;
404 : Double d, r, m, z;
405 : FILE *in;
406 0 : String fullFileName(antRespPath_p);
407 0 : fullFileName = fullFileName + String("/") + geomfile;
408 :
409 0 : in = fopen(fullFileName.c_str(), "r");
410 :
411 0 : if(!in)
412 : {
413 0 : String msg = "File " + fullFileName
414 0 : + " not found.\n Did you forget to install package data repository?\n";
415 0 : throw(SynthesisError(msg));
416 : }
417 :
418 0 : a = (calcAntenna *)malloc(sizeof(calcAntenna));
419 :
420 0 : for(i = 0; i < MAXGEOM; i++)
421 : {
422 0 : if(fscanf(in, "%lf%lf%lf", &r, &z, &m) != 3) break;
423 0 : a->z[i] = z;
424 0 : a->m[i] = m;
425 0 : a->radius = r;
426 : }
427 0 : fclose(in);
428 0 : a->ngeom = i;
429 0 : a->zedge = z;
430 0 : a->deltar = a->radius/(float)(a->ngeom-1.0);
431 0 : a->bestparabola = a->zedge/(a->radius*a->radius);
432 0 : if(i < 3)
433 : {
434 0 : fprintf(stderr, "geom file not valid\n");
435 0 : free(a);
436 0 : return 0;
437 : }
438 :
439 0 : z = sub_h-feed_z;
440 :
441 0 : a->sub_h = sub_h;
442 0 : a->feed[0] = feed_x;
443 0 : a->feed[1] = feed_y;
444 0 : a->feed[2] = feed_z;
445 0 : d = std::sqrt((double)(feed_x*feed_x + feed_y*feed_y + z*z));
446 0 : if(z > 0.0)
447 : {
448 0 : a->K = sub_h + d;
449 0 : a->feeddir[0] = -feed_x/d;
450 0 : a->feeddir[1] = -feed_y/d;
451 0 : a->feeddir[2] = (sub_h-feed_z)/d;
452 : }
453 : else
454 : {
455 0 : a->K = std::sqrt((double(feed_x*feed_x + feed_y*feed_y + feed_z*feed_z)));
456 0 : a->feeddir[0] = -feed_x/d;
457 0 : a->feeddir[1] = -feed_y/d;
458 0 : a->feeddir[2] = (sub_h-feed_z)/d;
459 : }
460 0 : for(i = 0; i < 3; i++) a->pfeeddir[i] = a->feeddir[i];
461 0 : a->ftaper = fabs(ftaper);
462 0 : a->thmax = thmax;
463 0 : a->fa2pi = 2.0*M_PI*std::sqrt((double)ftaper)*0.1874/sin(thmax*M_PI/180.0);
464 0 : a->legwidth = 0.0;
465 0 : a->legfoot = a->radius/2.0;
466 0 : a->legapex = sub_h*1.2;
467 0 : a->legthick = 0.0;
468 0 : a->hole_radius = 0.0;
469 0 : a->dir[0] = a->dir[1] = 0.0;
470 0 : a->dir[2] = 1.0;
471 0 : strcpy(a->name, "unnamed");
472 0 : a->k[0] = a->k[1] = a->k[2] = 0.0;
473 : /* default to no polarization state */
474 0 : Antennasetfreq(a, 1.0);
475 0 : Antennasetdir(a, 0); /* compute hhat and vhat */
476 0 : a->gridsize = 0;
477 0 : dishvalue(a, a->legfoot, &a->legfootz, 0);
478 :
479 0 : return a;
480 : }
481 :
482 0 : void BeamCalc::deleteAntenna(calcAntenna *a)
483 : {
484 0 : if(!a) return;
485 :
486 0 : free(a);
487 : }
488 :
489 0 : void BeamCalc::Antennasetfreq(calcAntenna *a, Double freq)
490 : {
491 : Int i;
492 :
493 0 : a->freq = freq;
494 0 : a->lambda = NS_METER/freq;
495 0 : for(i = 0; i < 3; i++) a->k[i] = -2.0*M_PI*a->dir[i]/a->lambda;
496 0 : }
497 :
498 0 : void BeamCalc::Antennasetdir(calcAntenna *a, const Double *dir)
499 : {
500 : Double hmag;
501 : Int i;
502 :
503 0 : if(dir)
504 : {
505 0 : for(i = 0; i < 3; i++) a->dir[i] = dir[i];
506 0 : if(a->dir[0] == 0.0 && a->dir[1] == 0.0)
507 : {
508 0 : a->hhat[0] = 1.0;
509 0 : a->hhat[1] = a->hhat[2] = 0.0;
510 0 : a->vhat[1] = 1.0;
511 0 : a->vhat[0] = a->vhat[2] = 0.0;
512 : }
513 : else
514 : {
515 0 : a->hhat[0] = a->dir[1];
516 0 : a->hhat[1] = -a->dir[0];
517 0 : a->hhat[2] = 0.0;
518 0 : hmag = sqrt(a->hhat[0]*a->hhat[0]
519 0 : + a->hhat[1]*a->hhat[1]);
520 0 : a->hhat[0] /= hmag;
521 0 : a->hhat[1] /= hmag;
522 :
523 0 : a->vhat[0] = a->hhat[1]*a->dir[2]
524 0 : - a->hhat[2]*a->dir[1];
525 0 : a->vhat[1] = a->hhat[2]*a->dir[0]
526 0 : - a->hhat[0]*a->dir[2];
527 0 : a->vhat[2] = a->hhat[0]*a->dir[1]
528 0 : - a->hhat[1]*a->dir[0];
529 : }
530 : }
531 0 : for(i = 0; i < 3; i++) a->k[i] = -2.0*M_PI*a->dir[i]/a->lambda;
532 0 : }
533 :
534 : /* sets feeddir after pathology is considered */
535 0 : void BeamCalc::alignfeed(calcAntenna *a, const Pathology *p)
536 : {
537 : Int i, j;
538 0 : Double f[3], s0[3], s[3], d[3], m=0.0;
539 :
540 0 : for(i = 0; i < 3; i++) f[i] = a->feed[i] + p->feedshift[i];
541 0 : for(i = 0; i < 3; i++) s0[i] = -p->subrotpoint[i];
542 0 : s0[2] += a->sub_h;
543 0 : for(i = 0; i < 3; i++)
544 : {
545 0 : s[i] = 0.0;
546 0 : for(j = 0; j < 3; j++)
547 0 : s[i] += p->subrot[i][j]*s0[j];
548 0 : s[i] += p->subrotpoint[i] + p->subshift[i];
549 0 : d[i] = s[i]-f[i];
550 0 : m += d[i]*d[i];
551 : }
552 0 : m = sqrt(m);
553 0 : for(i = 0; i < 3; i++) a->feeddir[i] = d[i]/m;
554 0 : }
555 :
556 0 : void BeamCalc::getfeedbasis(const calcAntenna *a, Double B[3][3])
557 : {
558 : Int i;
559 : Double *dir, *vhat, *hhat;
560 :
561 0 : hhat = B[0];
562 0 : vhat = B[1];
563 0 : dir = B[2];
564 :
565 0 : for(i = 0; i < 3; i++) dir[i] = a->pfeeddir[i];
566 :
567 0 : if(dir[0] == 0.0 && dir[1] == 0.0)
568 : {
569 0 : vhat[0] = 1.0;
570 0 : vhat[1] = vhat[2] = 0.0;
571 0 : hhat[1] = 1.0;
572 0 : hhat[0] = hhat[2] = 0.0;
573 : }
574 : else
575 : {
576 0 : vhat[0] = dir[1];
577 0 : vhat[1] = -dir[0];
578 0 : vhat[2] = 0.0;
579 0 : norm3(vhat);
580 :
581 0 : hhat[0] = vhat[1]*dir[2] - vhat[2]*dir[1];
582 0 : hhat[1] = vhat[2]*dir[0] - vhat[0]*dir[2];
583 0 : hhat[2] = vhat[0]*dir[1] - vhat[1]*dir[0];
584 : }
585 0 : }
586 :
587 0 : void BeamCalc::Efield(const calcAntenna *a, const Complex *pol, Complex *E)
588 : {
589 : Double B[3][3];
590 : Double *hhat, *vhat;
591 :
592 0 : getfeedbasis(a, B);
593 0 : hhat = B[0];
594 0 : vhat = B[1];
595 :
596 0 : for(Int i = 0; i < 3; i++)
597 0 : E[i] = Complex(hhat[i],0) * pol[0] + Complex(vhat[i],0) * pol[1];
598 0 : }
599 :
600 0 : Int BeamCalc::Antennasetfeedpattern(calcAntenna* /*a*/,
601 : const char* /*filename*/,
602 : Double /*scale*/)
603 : {
604 : #if 0
605 : Int i, N, Nmax;
606 : Double x, delta;
607 : VecArray pat;
608 :
609 : a->feedpatterndelta = 0.0;
610 : if(a->feedpattern) deleteVector(a->feedpattern);
611 :
612 : if(filename == 0) return 1;
613 :
614 : pat = VecArrayfromfile(filename, 2);
615 :
616 : if(!pat) return 0;
617 : N = VectorSize(pat[0]);
618 : g_assert(N > 2);
619 : g_assert(pat[0][0] == 0.0);
620 :
621 : delta = pat[0][1];
622 : g_assert(delta > 0.0);
623 : for(i = 2; i < N; i++)
624 : {
625 : x = pat[0][i]-pat[0][i-1]-delta;
626 : g_assert(fabs(x) < delta/10000.0);
627 : }
628 :
629 : /* convert to radians */
630 : delta *= M_PI/180.0;
631 :
632 : /* and scale it */
633 : if(scale > 0.0) delta *= scale;
634 :
635 : /* Do we need to truncate the pattern? */
636 : Nmax = M_PI/delta;
637 : if(N > Nmax)
638 : {
639 : a->feedpattern = newVector(Nmax);
640 : for(i = 0; i < Nmax; i++)
641 : a->feedpattern[i] = fabs(pat[1][i]);
642 : deleteVector(pat[1]);
643 : }
644 : else a->feedpattern = pat[1];
645 :
646 : a->feedpatterndelta = delta;
647 : deleteVector(pat[0]);
648 : deleteVecArray(pat);
649 : #endif
650 0 : return 1;
651 : }
652 :
653 0 : calcAntenna* BeamCalc::newAntennafromApertureCalcParams(ApertureCalcParams *ap)
654 : {
655 : calcAntenna *a;
656 0 : Double dir[3] = {0.0, 0.0, 1.0};
657 : Double sub_h, feed_x, feed_y, feed_z, thmax, ftaper;
658 : char geomfile[128];//, *feedfile;
659 : BeamCalcGeometry *geom;
660 : Int i;
661 : Double x, freq, df;
662 :
663 : //LogIO os;
664 0 : if((0<=ap->band) && (ap->band<(Int)BeamCalcGeometries_p.size())){
665 0 : geom = &(BeamCalcGeometries_p[ap->band]);
666 : //os << "Using antenna parameters for " << geom->bandName << " band" << LogIO::POST;
667 : }
668 : else{
669 0 : SynthesisError err(String("Internal Error: attempt to access beam geometry for non-existing band."));
670 0 : throw(err);
671 : }
672 :
673 0 : sub_h = geom->sub_h;
674 0 : feed_x = geom->feedpos[0]; feed_x = -feed_x;
675 0 : feed_y = geom->feedpos[1];
676 0 : feed_z = geom->feedpos[2];
677 : //feedfile = 0;
678 0 : thmax = geom->subangle;
679 :
680 0 : freq = ap->freq;
681 0 : if(freq <= 0.0) freq = geom->reffreq;
682 :
683 0 : df = freq-geom->reffreq;
684 0 : x = 1.0;
685 0 : ftaper = 0.0;
686 0 : for(i = 0; i < geom->ntaperpoly; i++)
687 : {
688 0 : ftaper += geom->taperpoly[i]*x;
689 0 : x *= df;
690 : }
691 0 : sprintf(geomfile, "%s.surface", geom->name);
692 :
693 0 : a = newAntenna(sub_h, feed_x, feed_y, feed_z, ftaper, thmax, geomfile);
694 0 : if(!a) return 0;
695 :
696 0 : strcpy(a->name, geom->name);
697 :
698 : /* feed pattern file is two column text file containing
699 : * angle (in degrees) and power (in dBi)
700 : */
701 :
702 : // if(feedfile != 0)
703 : // {
704 : // Double scale;
705 : // scale = getKeyValueDouble(kv, "feedpatternscale");
706 : // if(!Antennasetfeedpattern(a, feedfile, scale))
707 : // {
708 : // deleteAntenna(a);
709 : // fprintf(stderr, "Problem with feed file <%s>\n",
710 : // feedfile);
711 : // return 0;
712 : // }
713 : // }
714 :
715 0 : Antennasetfreq(a, ap->freq);
716 :
717 0 : a->legwidth = geom->legwidth;
718 0 : a->legfoot = geom->legfoot;
719 0 : a->legapex = geom->legapex;
720 :
721 0 : a->hole_radius = geom->Rhole;
722 :
723 0 : a->astigm_0 = geom->astigm_0;
724 0 : a->astigm_45 = geom->astigm_45;
725 :
726 0 : Antennasetdir(a, dir);
727 :
728 0 : return a;
729 : }
730 :
731 0 : Int BeamCalc::dishvalue(const calcAntenna *a, Double r, Double *z, Double *m)
732 : {
733 : Double ma, mb, mc, zav, A, B, C, D;
734 : Double x, d, dd;
735 0 : Double s = 1.0;
736 : Int n;
737 :
738 0 : if(r == 0)
739 : {
740 0 : *z = a->z[0];
741 0 : *m = 0.0;
742 0 : return 1;
743 : }
744 :
745 0 : if(r < 0)
746 : {
747 0 : s = -1.0;
748 0 : r = -r;
749 : }
750 0 : d = a->deltar;
751 0 : dd = d*d;
752 :
753 0 : n = (Int)floor(r/d + 0.5); /* the middle point */
754 0 : if(n > a->ngeom-2) n = a->ngeom-2;
755 :
756 0 : x = r - n*d;
757 :
758 0 : if(n == 0)
759 : {
760 0 : mc = a->m[1];
761 0 : ma = -mc;
762 0 : mb = 0.0;
763 0 : zav = 2.0*a->z[1] + a->z[0];
764 : }
765 : else
766 : {
767 0 : ma = a->m[n-1];
768 0 : mb = a->m[n];
769 0 : mc = a->m[n+1];
770 0 : zav = a->z[n-1] + a->z[n] + a->z[n+1];
771 : }
772 :
773 0 : A = mb;
774 0 : B = 0.5*(mc - ma)/d;
775 0 : C = 0.5*(mc - 2.0*mb + ma)/dd;
776 :
777 0 : D = (zav - B*dd)/3.0;
778 :
779 0 : if(m) *m = s*(A + B*x + C*x*x);
780 0 : if(z) *z = s*(D + A*x + B*x*x/2.0 + C*x*x*x/3.0);
781 :
782 0 : return 1;
783 : }
784 :
785 0 : Int BeamCalc::astigdishvalue(const calcAntenna *a, Double x, Double y, Double *z, Double *m)
786 : {
787 : Double ma, mb, mc, zav, A, B, C, D;
788 : Double r, rr, theta, xp, d, dd, z5, z6, astigm, dastigm;
789 0 : Double s = 1.0;
790 : Int n;
791 :
792 0 : rr = x*x + y*y;
793 0 : r = sqrt(rr);
794 :
795 0 : if(r==0. || (a->astigm_0==0. && a->astigm_45==0.))
796 : {
797 0 : return dishvalue(a, r, z, m);
798 : }
799 :
800 : // the Zernike polynomials Z5 and Z6
801 : Double sin2th, cos2th, rho, rho2;
802 :
803 0 : theta = atan2(y,x);
804 0 : sin2th = sin(2.*theta);
805 0 : cos2th = cos(2.*theta);
806 0 : rho = r / a->radius;
807 0 : rho2 = rho*rho;
808 :
809 0 : z5 = sqrt(6.) * rho2 * sin2th;
810 0 : z6 = sqrt(6.) * rho2 * cos2th;
811 :
812 0 : astigm = 1. + a->astigm_45 * z5 + a->astigm_0 * z6;
813 0 : dastigm = 2.* rho2/r * sqrt(6.)*(a->astigm_45*sin2th + a->astigm_0*cos2th);
814 :
815 0 : d = a->deltar;
816 0 : dd = d*d;
817 :
818 0 : n = (Int)floor(r/d + 0.5); /* the middle point */
819 0 : if(n > a->ngeom-2) n = a->ngeom-2;
820 :
821 0 : xp = r - n*d;
822 :
823 0 : if(n == 0)
824 : {
825 0 : mc = a->m[1];
826 0 : ma = -mc;
827 0 : mb = 0.0;
828 0 : zav = 2.0*a->z[1] + a->z[0];
829 : }
830 : else
831 : {
832 0 : ma = a->m[n-1];
833 0 : mb = a->m[n];
834 0 : mc = a->m[n+1];
835 0 : zav = a->z[n-1] + a->z[n] + a->z[n+1];
836 : }
837 :
838 0 : A = mb;
839 0 : B = 0.5*(mc - ma)/d;
840 0 : C = 0.5*(mc - 2.0*mb + ma)/dd;
841 :
842 0 : D = (zav - B*dd)/3.0;
843 :
844 :
845 0 : Double zn = s*(D + A*xp + B*xp*xp/2.0 + C*xp*xp*xp/3.0);
846 0 : if(z) *z = zn * astigm;
847 0 : if(m) *m = s*(A + B*xp + C*xp*xp) * astigm + dastigm * zn;
848 :
849 0 : return 1;
850 : }
851 :
852 : /* Returns position of subreflector piece (x, y, z) and
853 : * its normal (u, v, w)
854 : */
855 0 : Int BeamCalc::subfromdish(const calcAntenna *a, Double x, Double y, Double *subpoint)
856 : {
857 : Double r, z, m, u, v, w;
858 : Double dx, dy, dz, dl, t;
859 : Double n[3], sf[3], sd[3];
860 : Int i;
861 :
862 0 : r = sqrt(x*x + y*y);
863 :
864 0 : if(r == 0)
865 : {
866 0 : subpoint[0] = 0.0;
867 0 : subpoint[1] = 0.0;
868 0 : subpoint[2] = a->sub_h;
869 : }
870 : else
871 : {
872 0 : astigdishvalue(a, x, y, &z, &m);
873 :
874 : /* Compute reflected unit vector direction */
875 0 : m = tan(2.0*atan(m));
876 0 : w = 1.0/sqrt(1.0+m*m);
877 0 : u = -m*(x/r)*w;
878 0 : v = -m*(y/r)*w;
879 :
880 0 : dx = a->feed[0]-x;
881 0 : dy = a->feed[1]-y;
882 0 : dz = a->feed[2]-z;
883 0 : dl = a->K + z;
884 :
885 0 : t = 0.5*(dx*dx + dy*dy + dz*dz - dl*dl)
886 0 : / (-dl + u*dx + v*dy + w*dz);
887 :
888 0 : subpoint[0] = x + u*t;
889 0 : subpoint[1] = y + v*t;
890 0 : subpoint[2] = z + w*t;
891 : }
892 :
893 0 : for(i = 0; i < 3; i++) sf[i] = a->feed[i] - subpoint[i];
894 0 : sd[0] = x - subpoint[0];
895 0 : sd[1] = y - subpoint[1];
896 0 : sd[2] = z - subpoint[2];
897 :
898 0 : norm3(sf);
899 0 : norm3(sd);
900 :
901 0 : for(i = 0; i < 3; i++) n[i] = sd[i]+sf[i];
902 :
903 0 : norm3(n);
904 :
905 0 : for(i = 0; i < 3; i++) subpoint[3+i] = n[i];
906 :
907 0 : return 1;
908 : }
909 :
910 0 : Int BeamCalc::dishfromsub(const calcAntenna *a, Double x, Double y, Double *dishpoint)
911 : {
912 :
913 : Double x1, y1, dx, dy, mx, my, r, d;
914 0 : const Double eps = 0.001;
915 0 : Int iter, niter=500;
916 : Double sub[5][6];
917 :
918 0 : x1 = x;
919 0 : y1 = y;
920 :
921 0 : for(iter = 0; iter < niter; iter++)
922 : {
923 0 : subfromdish(a, x1, y1, sub[0]);
924 0 : subfromdish(a, x1-eps, y1, sub[1]);
925 0 : subfromdish(a, x1+eps, y1, sub[2]);
926 0 : subfromdish(a, x1, y1-eps, sub[3]);
927 0 : subfromdish(a, x1, y1+eps, sub[4]);
928 0 : mx = 0.5*(sub[2][0]-sub[1][0])/eps;
929 0 : my = 0.5*(sub[4][1]-sub[3][1])/eps;
930 0 : dx = (x-sub[0][0])/mx;
931 0 : dy = (y-sub[0][1])/my;
932 0 : if(fabs(dx) > a->radius/7.0)
933 : {
934 0 : if(dx < 0) dx = -a->radius/7.0;
935 0 : else dx = a->radius/7.0;
936 : }
937 0 : if(fabs(dy) > a->radius/7.0)
938 : {
939 0 : if(dy < 0) dy = -a->radius/7.0;
940 0 : else dy = a->radius/7.0;
941 : }
942 0 : r = sqrt(x1*x1 + y1*y1);
943 0 : if(r >= a->radius)
944 0 : if(x1*dx + y1*dy > 0.0) return 0;
945 0 : x1 += 0.5*dx;
946 0 : y1 += 0.5*dy;
947 0 : if(fabs(dx) < 0.005*eps && fabs(dy) < 0.005*eps) break;
948 : }
949 0 : if(iter == niter) return 0;
950 :
951 0 : r = sqrt(x1*x1 + y1*y1);
952 0 : dishpoint[0] = x1;
953 0 : dishpoint[1] = y1;
954 : // dishpoint[2] = polyvalue(a->shape, r);
955 0 : dishpoint[3] = sub[0][0];
956 0 : dishpoint[4] = sub[0][1];
957 0 : dishpoint[5] = sub[0][2];
958 0 : d = sqrt(1.0+mx*mx+my*my);
959 0 : dishpoint[6] = mx/d;
960 0 : dishpoint[7] = my/d;
961 0 : dishpoint[8] = 1.0/d;
962 0 : dishpoint[9] = sub[0][3];
963 0 : dishpoint[10] = sub[0][4];
964 0 : dishpoint[11] = sub[0][5];
965 :
966 0 : if(r > a->radius) return 0;
967 0 : else return 1;
968 : }
969 :
970 0 : void BeamCalc::printAntenna(const calcAntenna *a)
971 : {
972 0 : printf("Antenna: %s %p\n", a->name, a);
973 0 : printf(" freq = %f GHz lambda = %f m\n", a->freq, a->lambda);
974 0 : printf(" feeddir = %f, %f, %f\n",
975 0 : a->feeddir[0], a->feeddir[1], a->feeddir[2]);
976 0 : printf(" pfeeddir = %f, %f, %f\n",
977 0 : a->pfeeddir[0], a->pfeeddir[1], a->pfeeddir[2]);
978 0 : }
979 :
980 0 : Ray * BeamCalc::newRay(const Double *sub)
981 : {
982 : Ray *ray;
983 : Int i;
984 :
985 0 : ray = (Ray *)malloc(sizeof(Ray));
986 0 : for(i = 0; i < 6; i++) ray->sub[i] = sub[i];
987 :
988 0 : return ray;
989 : }
990 :
991 0 : void BeamCalc::deleteRay(Ray *ray)
992 : {
993 0 : if(ray) free(ray);
994 0 : }
995 :
996 0 : Pathology* BeamCalc::newPathology()
997 : {
998 : Pathology *P;
999 : Int i, j;
1000 :
1001 0 : P = (Pathology *)malloc(sizeof(Pathology));
1002 :
1003 0 : for(i = 0; i < 3; i++) P->subrotpoint[i] = P->subshift[i] = P->feedshift[i] = 0.0;
1004 0 : for(i = 0; i < 3; i++) for(j = 0; j < 3; j++)
1005 0 : P->feedrot[i][j] = P->subrot[i][j] = 0.0;
1006 0 : for(i = 0; i < 3; i++) P->feedrot[i][i] = P->subrot[i][i] = 1.0;
1007 :
1008 0 : P->az_offset = 0.0;
1009 0 : P->el_offset = 0.0;
1010 0 : P->phase_offset = 0.0;
1011 0 : P->focus = 0.0;
1012 :
1013 0 : return P;
1014 : }
1015 :
1016 0 : Pathology* BeamCalc::newPathologyfromApertureCalcParams(ApertureCalcParams* /*ap*/)
1017 : {
1018 : Pathology *P;
1019 :
1020 0 : P = newPathology();
1021 :
1022 0 : return P;
1023 : }
1024 :
1025 0 : void BeamCalc::deletePathology(Pathology *P)
1026 : {
1027 0 : if(P) free(P);
1028 0 : }
1029 :
1030 0 : void BeamCalc::normvec(const Double *a, const Double *b, Double *c)
1031 : {
1032 : Int i;
1033 : Double r;
1034 0 : for(i = 0; i < 3; i++) c[i] = a[i] - b[i];
1035 0 : r = sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]);
1036 0 : for(i = 0; i < 3; i++) c[i] /= r;
1037 0 : }
1038 :
1039 0 : Double BeamCalc::dAdOmega(const calcAntenna *a, const Ray *ray1, const Ray *ray2,
1040 : const Ray *ray3, const Pathology *p)
1041 : {
1042 : Double A, Omega;
1043 : Double n1[3], n2[3], n3[3], f[3], ci, cj, ck;
1044 : Int i;
1045 :
1046 : /* Area in aperture is in a plane z = const */
1047 0 : A = 0.5*fabs(
1048 0 : (ray1->aper[0]-ray2->aper[0])*(ray1->aper[1]-ray3->aper[1]) -
1049 0 : (ray1->aper[0]-ray3->aper[0])*(ray1->aper[1]-ray2->aper[1]) );
1050 :
1051 0 : for(i = 0; i < 3; i++) f[i] = a->feed[i] + p->feedshift[i];
1052 :
1053 0 : normvec(ray1->sub, f, n1);
1054 0 : normvec(ray2->sub, f, n2);
1055 0 : normvec(ray3->sub, f, n3);
1056 :
1057 0 : for(i = 0; i < 3; i++)
1058 : {
1059 0 : n1[i] -= n3[i];
1060 0 : n2[i] -= n3[i];
1061 : }
1062 :
1063 0 : ci = n1[1]*n2[2] - n1[2]*n2[1];
1064 0 : cj = n1[2]*n2[0] - n1[0]*n2[2];
1065 0 : ck = n1[0]*n2[1] - n1[1]*n2[0];
1066 :
1067 0 : Omega = 0.5*sqrt(ci*ci + cj*cj + ck*ck);
1068 :
1069 0 : return A/Omega;
1070 : }
1071 :
1072 0 : Double BeamCalc::dOmega(const calcAntenna *a, const Ray *ray1, const Ray *ray2,
1073 : const Ray *ray3, const Pathology *p)
1074 : {
1075 : Double Omega;
1076 : Double n1[3], n2[3], n3[3], f[3], ci, cj, ck;
1077 : Int i;
1078 :
1079 0 : for(i = 0; i < 3; i++) f[i] = a->feed[i] + p->feedshift[i];
1080 :
1081 0 : normvec(ray1->sub, f, n1);
1082 0 : normvec(ray2->sub, f, n2);
1083 0 : normvec(ray3->sub, f, n3);
1084 :
1085 0 : for(i = 0; i < 3; i++)
1086 : {
1087 0 : n1[i] -= n3[i];
1088 0 : n2[i] -= n3[i];
1089 : }
1090 :
1091 0 : ci = n1[1]*n2[2] - n1[2]*n2[1];
1092 0 : cj = n1[2]*n2[0] - n1[0]*n2[2];
1093 0 : ck = n1[0]*n2[1] - n1[1]*n2[0];
1094 :
1095 0 : Omega = 0.5*sqrt(ci*ci + cj*cj + ck*ck);
1096 :
1097 0 : return Omega;
1098 : }
1099 :
1100 0 : Double BeamCalc::Raylen(const Ray *ray)
1101 : {
1102 : Double len, d[3];
1103 : Int i;
1104 :
1105 : /* feed to subreflector */
1106 0 : for(i = 0; i < 3; i++) d[i] = ray->feed[i] - ray->sub[i];
1107 0 : len = sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
1108 :
1109 : /* subreflector to dish */
1110 0 : for(i = 0; i < 3; i++) d[i] = ray->sub[i] - ray->dish[i];
1111 0 : len += sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
1112 :
1113 : /* dish to aperture */
1114 0 : for(i = 0; i < 3; i++) d[i] = ray->dish[i] - ray->aper[i];
1115 0 : len += sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
1116 :
1117 0 : return len;
1118 : }
1119 :
1120 0 : void BeamCalc::Pathologize(Double *sub, const Pathology *p)
1121 : {
1122 : Int i;
1123 : Int j;
1124 : Double tmp[6];
1125 :
1126 0 : for(i = 0; i < 3; i++) sub[i] -= p->subrotpoint[i];
1127 :
1128 0 : for(i = 0; i < 3; i++)
1129 : {
1130 0 : tmp[i] = 0.0;
1131 0 : tmp[i+3] = 0.0;
1132 0 : for(j = 0; j < 3; j++) tmp[i] += p->subrot[i][j]*sub[j];
1133 0 : for(j = 0; j < 3; j++) tmp[i+3] += p->subrot[i][j]*sub[j+3];
1134 : }
1135 :
1136 0 : for(i = 0; i < 3; i++)
1137 0 : sub[i] = tmp[i] + p->subrotpoint[i] + p->subshift[i];
1138 0 : for(i = 4; i < 6; i++)
1139 0 : sub[i] = tmp[i];
1140 0 : }
1141 :
1142 0 : void BeamCalc::applyPathology(Pathology *P, calcAntenna *a)
1143 : {
1144 : Double dx[3];
1145 : Int i, j;
1146 :
1147 0 : if(P->focus != 0.0)
1148 : {
1149 0 : dx[0] = -a->feed[0];
1150 0 : dx[1] = -a->feed[1];
1151 0 : dx[2] = a->sub_h-a->feed[2];
1152 0 : norm3(dx);
1153 0 : for(i = 0; i < 3; i++) P->feedshift[i] += P->focus*dx[i];
1154 :
1155 0 : P->focus = 0.0;
1156 : }
1157 :
1158 0 : for(i = 0; i < 3; i++) a->pfeeddir[i] = 0.0;
1159 0 : for(j = 0; j < 3; j++) for(i = 0; i < 3; i++)
1160 0 : a->pfeeddir[j] += P->feedrot[j][i]*a->feeddir[i];
1161 0 : }
1162 :
1163 :
1164 0 : void BeamCalc::intersectdish(const calcAntenna *a, const Double *sub, const Double *unitdir,
1165 : Double *dish, Int niter)
1166 : {
1167 : Double A, B, C, t, m, r;
1168 : Double x[3], n[3];
1169 : Int i, iter;
1170 :
1171 : /* First intersect with ideal paraboloid */
1172 0 : A = a->bestparabola*(unitdir[0]*unitdir[0] + unitdir[1]*unitdir[1]);
1173 0 : B = 2.0*a->bestparabola*(unitdir[0]*sub[0] + unitdir[1]*sub[1])
1174 0 : -unitdir[2];
1175 0 : C = a->bestparabola*(sub[0]*sub[0] + sub[1]*sub[1]) - sub[2];
1176 0 : t = 0.5*(sqrt(B*B-4.0*A*C) - B)/A; /* take greater root */
1177 :
1178 0 : for(iter = 0; ; iter++)
1179 : {
1180 : /* get position (x) and normal (n) on the real dish */
1181 0 : for(i = 0; i < 2; i++) x[i] = sub[i] + t*unitdir[i];
1182 0 : r = sqrt(x[0]*x[0] + x[1]*x[1]);
1183 0 : astigdishvalue(a, x[0], x[1], &(x[2]), &m);
1184 0 : n[2] = 1.0/sqrt(1.0+m*m);
1185 0 : n[0] = -m*(x[0]/r)*n[2];
1186 0 : n[1] = -m*(x[1]/r)*n[2];
1187 :
1188 0 : if(iter >= niter) break;
1189 :
1190 0 : A = B = 0;
1191 0 : for(i = 0; i < 3; i++)
1192 : {
1193 0 : A += n[i]*(x[i]-sub[i]); /* n dot (x-sub) */
1194 0 : B += n[i]*unitdir[i]; /* n dot unitdir */
1195 : }
1196 0 : t = A/B;
1197 : }
1198 :
1199 0 : for(i = 0; i < 3; i++)
1200 : {
1201 0 : dish[i] = x[i];
1202 0 : dish[i+3] = n[i];
1203 : }
1204 0 : }
1205 :
1206 0 : void BeamCalc::intersectaperture(const calcAntenna *a, const Double *dish,
1207 : const Double *unitdir, Double *aper)
1208 : {
1209 : Double t;
1210 : Int i;
1211 :
1212 0 : t = (a->zedge-dish[2])/unitdir[2];
1213 0 : for(i = 0; i < 3; i++) aper[i] = dish[i] + t*unitdir[i];
1214 :
1215 0 : aper[3] = aper[4] = 0.0;
1216 0 : aper[5] = 1.0;
1217 0 : }
1218 :
1219 : /* gain in power */
1220 0 : Double BeamCalc::feedfunc(const calcAntenna *a, Double theta)
1221 : {
1222 : Double stheta;
1223 :
1224 0 : stheta = sin(theta);
1225 0 : return exp(2.0*(-0.083)*a->fa2pi*a->fa2pi*stheta*stheta);
1226 : }
1227 :
1228 : /* gain in power */
1229 0 : Double BeamCalc::feedgain(const calcAntenna *a, const Ray *ray, const Pathology */*p*/)
1230 : {
1231 0 : Double costheta = 0.0;
1232 : Double v[3];
1233 : Int i;
1234 :
1235 0 : for(i = 0; i < 3; i++) v[i] = ray->sub[i] - ray->feed[i];
1236 0 : norm3(v);
1237 :
1238 0 : for(i = 0; i < 3; i++)
1239 : {
1240 0 : costheta += a->pfeeddir[i]*v[i];
1241 : }
1242 :
1243 :
1244 0 : return exp(2.0*(-0.083)*a->fa2pi*a->fa2pi*(1.0-costheta*costheta));
1245 : }
1246 :
1247 0 : Ray* BeamCalc::trace(const calcAntenna *a, Double x, Double y, const Pathology *p)
1248 : {
1249 : Ray *ray;
1250 : Double idealsub[12];
1251 0 : Double fu[3], du[3], au[3], ndotf=0.0, ndotd=0.0;
1252 : Int i;
1253 0 : const Int niter = 7;
1254 :
1255 0 : subfromdish(a, x, y, idealsub);
1256 :
1257 0 : ray = newRay(idealsub);
1258 :
1259 0 : Pathologize(ray->sub, p);
1260 :
1261 0 : if(ray->sub[5] < -1.0 || ray->sub[5] > -0.0)
1262 : {
1263 0 : deleteRay(ray);
1264 0 : return 0;
1265 : }
1266 :
1267 0 : for(i = 0; i < 3; i++) ray->feed[i] = a->feed[i] + p->feedshift[i];
1268 :
1269 : /* now determine unit vector pointing to dish */
1270 :
1271 : /* unit toward feed */
1272 0 : for(i = 0; i < 3; i++) fu[i] = ray->feed[i] - ray->sub[i];
1273 0 : norm3(fu);
1274 :
1275 : /* unit toward dish */
1276 0 : for(i = 0; i < 3; i++) ndotf += ray->sub[i+3]*fu[i];
1277 0 : for(i = 0; i < 3; i++) du[i] = 2.0*ray->sub[i+3]*ndotf - fu[i];
1278 :
1279 : /* dish point */
1280 0 : intersectdish(a, ray->sub, du, ray->dish, niter);
1281 :
1282 : /* unit toward aperture */
1283 0 : for(i = 0; i < 3; i++) ndotd += ray->dish[i+3]*du[i];
1284 0 : for(i = 0; i < 3; i++) au[i] = du[i] - 2.0*ray->dish[i+3]*ndotd;
1285 :
1286 0 : intersectaperture(a, ray->dish, au, ray->aper);
1287 :
1288 0 : return ray;
1289 : }
1290 :
1291 0 : void BeamCalc::tracepol(Complex *E0, const Ray *ray, Complex *E1)
1292 : {
1293 0 : Complex fac;
1294 : Double v1[3], v2[3], v3[3];
1295 : Double r[3];
1296 : Int i;
1297 :
1298 0 : for(i = 0; i < 3; i++)
1299 : {
1300 0 : v1[i] = ray->sub[i] - ray->feed[i];
1301 0 : v2[i] = ray->dish[i] - ray->sub[i];
1302 0 : v3[i] = ray->aper[i] - ray->dish[i];
1303 0 : E1[i] = E0[i];
1304 : }
1305 0 : norm3(v1);
1306 0 : norm3(v2);
1307 0 : norm3(v3);
1308 :
1309 0 : for(i = 0; i < 3; i++) r[i] = v1[i] - v2[i];
1310 0 : norm3(r);
1311 0 : fac = Complex(r[0],0)*E1[0] + Complex(r[1],0)*E1[1] + Complex(r[2],0)*E1[2];
1312 0 : for(i = 0; i < 3; i++) E1[i] = Complex(r[i],0)*fac*2.0 - E1[i];
1313 :
1314 0 : for(i = 0; i < 3; i++) r[i] = v2[i] - v3[i];
1315 0 : norm3(r);
1316 0 : fac = Complex(r[0],0)*E1[0] + Complex(r[1],0)*E1[1] + Complex(r[2],0)*E1[2];
1317 0 : for(i = 0; i < 3; i++) E1[i] = Complex(r[i],0)*fac*2.0 - E1[i];
1318 0 : }
1319 :
1320 0 : Int BeamCalc::legplanewaveblock(const calcAntenna *a, Double x, Double y)
1321 : {
1322 : /* outside the leg foot area, the blockage is spherical wave */
1323 0 : if(x*x + y*y > a->legfoot*a->legfoot) return 0;
1324 :
1325 0 : if(a->legwidth == 0.0) return 0;
1326 :
1327 0 : if(strcmp(a->name, "VLBA") == 0)
1328 : {
1329 0 : const Double s=1.457937;
1330 0 : const Double c=1.369094;
1331 0 : if(fabs(s*x+c*y) < -a->legwidth) return 1;
1332 0 : if(fabs(s*x-c*y) < -a->legwidth) return 1;
1333 : }
1334 0 : else if(a->legwidth < 0.0) /* "x shaped" legs */
1335 : {
1336 0 : if(fabs(x-y)*M_SQRT2 < -a->legwidth) return 1;
1337 0 : if(fabs(x+y)*M_SQRT2 < -a->legwidth) return 1;
1338 : }
1339 0 : else if(a->legwidth > 0.0) /* "+ shaped" legs */
1340 : {
1341 0 : if(fabs(x)*2.0 < a->legwidth) return 1;
1342 0 : if(fabs(y)*2.0 < a->legwidth) return 1;
1343 : }
1344 :
1345 0 : return 0;
1346 : }
1347 :
1348 0 : Int BeamCalc::legplanewaveblock2(const calcAntenna *a, const Ray *ray)
1349 : {
1350 : Int i, n;
1351 : Double dr2;
1352 : // phi set but not used
1353 : Double theta /*, phi*/;
1354 : Double r0[3], dr[3], l0[3], l1[3], dl[3], D[3];
1355 : Double D2, N[3], ll, rr;
1356 0 : const Double thetaplus[4] =
1357 : {0, M_PI/2.0, M_PI, 3.0*M_PI/2.0};
1358 0 : const Double thetacross[4] =
1359 : {0.25*M_PI, 0.75*M_PI, 1.25*M_PI, 1.75*M_PI};
1360 0 : const Double thetavlba[4] =
1361 : {0.816817, 2.3247756, 3.9584096, 5.466368};
1362 : const Double *thetalut;
1363 :
1364 0 : if(a->legwidth == 0.0) return 0;
1365 :
1366 0 : if(strcmp(a->name, "VLBA") == 0) thetalut = thetavlba;
1367 0 : else if(a->legwidth < 0.0) thetalut = thetacross;
1368 0 : else thetalut = thetaplus;
1369 :
1370 : /* inside the leg feet is plane wave blockage */
1371 0 : dr2 = ray->dish[0]*ray->dish[0] + ray->dish[1]*ray->dish[1];
1372 0 : if(dr2 >= a->legfoot*a->legfoot) return 0;
1373 :
1374 0 : for(i = 0; i < 3; i++)
1375 : {
1376 0 : r0[i] = ray->dish[i];
1377 0 : dr[i] = ray->aper[i] - r0[i];
1378 : }
1379 0 : rr = r0[0]*r0[0] + r0[1]*r0[1];
1380 :
1381 0 : l0[2] = a->legfootz;
1382 0 : l1[0] = l1[1] = 0.0;
1383 0 : l1[2] = a->legapex;
1384 : // phi set but not used
1385 : // phi = atan2(r0[1], r0[0]);
1386 0 : for(n = 0; n < 4; n++)
1387 : {
1388 0 : theta = thetalut[n];
1389 0 : l0[0] = a->legfoot*cos(theta);
1390 0 : l0[1] = a->legfoot*sin(theta);
1391 0 : ll = l0[0]*l0[0] + l0[1]*l0[1];
1392 0 : if((l0[0]*r0[0] + l0[1]*r0[1])/sqrt(ll*rr) < 0.7) continue;
1393 0 : for(i = 0; i < 3; i++) dl[i] = l1[i] - l0[i];
1394 0 : for(i = 0; i < 3; i++) D[i] = r0[i] - l0[i];
1395 :
1396 0 : N[0] = dr[1]*dl[2] - dr[2]*dl[1];
1397 0 : N[1] = dr[2]*dl[0] - dr[0]*dl[2];
1398 0 : N[2] = dr[0]*dl[1] - dr[1]*dl[0];
1399 0 : norm3(N);
1400 :
1401 0 : D2 = D[0]*N[0] + D[1]*N[1] + D[2]*N[2];
1402 :
1403 0 : if(fabs(D2) <= 0.5*fabs(a->legwidth)) return 1;
1404 : }
1405 :
1406 0 : return 0;
1407 : }
1408 :
1409 0 : Int BeamCalc::legsphericalwaveblock(const calcAntenna *a, const Ray *ray)
1410 : {
1411 : Int i, n;
1412 : Double dr2;
1413 : // phi set but not used
1414 : Double theta /*, phi*/;
1415 : Double r0[3], dr[3], l0[3], l1[3], dl[3], D[3];
1416 : Double D2, N[3], ll, rr;
1417 0 : const Double thetaplus[4] =
1418 : {0, M_PI/2.0, M_PI, 3.0*M_PI/2.0};
1419 0 : const Double thetacross[4] =
1420 : {0.25*M_PI, 0.75*M_PI, 1.25*M_PI, 1.75*M_PI};
1421 0 : const Double thetavlba[4] =
1422 : {0.816817, 2.3247756, 3.9584096, 5.466368};
1423 : const Double *thetalut;
1424 :
1425 0 : if(a->legwidth == 0.0) return 0;
1426 :
1427 0 : if(strcmp(a->name, "VLBA") == 0) thetalut = thetavlba;
1428 0 : else if(a->legwidth < 0.0) thetalut = thetacross;
1429 0 : else thetalut = thetaplus;
1430 :
1431 : /* inside the leg feet is plane wave blockage */
1432 0 : dr2 = ray->dish[0]*ray->dish[0] + ray->dish[1]*ray->dish[1];
1433 0 : if(dr2 < a->legfoot*a->legfoot) return 0;
1434 :
1435 0 : for(i = 0; i < 3; i++)
1436 : {
1437 0 : r0[i] = ray->dish[i];
1438 0 : dr[i] = ray->sub[i] - r0[i];
1439 : }
1440 0 : rr = r0[0]*r0[0] + r0[1]*r0[1];
1441 :
1442 0 : l0[2] = a->legfootz;
1443 0 : l1[0] = l1[1] = 0.0;
1444 0 : l1[2] = a->legapex;
1445 : // phi set but not used
1446 : // phi = atan2(r0[1], r0[0]);
1447 0 : for(n = 0; n < 4; n++)
1448 : {
1449 0 : theta = thetalut[n];
1450 0 : l0[0] = a->legfoot*cos(theta);
1451 0 : l0[1] = a->legfoot*sin(theta);
1452 0 : ll = l0[0]*l0[0] + l0[1]*l0[1];
1453 0 : if((l0[0]*r0[0] + l0[1]*r0[1])/sqrt(ll*rr) < 0.7) continue;
1454 0 : for(i = 0; i < 3; i++) dl[i] = l1[i] - l0[i];
1455 0 : for(i = 0; i < 3; i++) D[i] = r0[i] - l0[i];
1456 :
1457 0 : N[0] = dr[1]*dl[2] - dr[2]*dl[1];
1458 0 : N[1] = dr[2]*dl[0] - dr[0]*dl[2];
1459 0 : N[2] = dr[0]*dl[1] - dr[1]*dl[0];
1460 0 : norm3(N);
1461 :
1462 0 : D2 = D[0]*N[0] + D[1]*N[1] + D[2]*N[2];
1463 :
1464 0 : if(fabs(D2) <= 0.5*fabs(a->legwidth)) return 1;
1465 : }
1466 :
1467 0 : return 0;
1468 : }
1469 :
1470 :
1471 0 : void BeamCalc::copyBeamCalcGeometry(BeamCalcGeometry* to, BeamCalcGeometry* from){
1472 0 : sprintf(to->name, "%s", from->name);
1473 0 : sprintf(to->bandName, "%s", from->bandName);
1474 0 : to->sub_h = from->sub_h;
1475 0 : for(uInt j=0; j<3;j++){
1476 0 : to->feedpos[j] = from->feedpos[j];
1477 : }
1478 0 : to->subangle = from->subangle;
1479 0 : to->legwidth = from->legwidth;
1480 0 : to->legfoot = from->legfoot;
1481 0 : to->legapex = from->legapex;
1482 0 : to->Rhole = from->Rhole;
1483 0 : to->Rant = from->Rant;
1484 0 : to->reffreq = from->reffreq;
1485 0 : for(uInt j=0; j<5;j++){
1486 0 : to->taperpoly[j] = from->taperpoly[j];
1487 : }
1488 0 : to->ntaperpoly = from->ntaperpoly;
1489 0 : to->astigm_0 = from->astigm_0;
1490 0 : to->astigm_45 = from->astigm_45;
1491 :
1492 0 : }
1493 :
1494 :
1495 : /* The meat of the calculation */
1496 :
1497 :
1498 0 : Int BeamCalc::calculateAperture(ApertureCalcParams *ap)
1499 : {
1500 : // not used
1501 : // Complex fp, Exr, Eyr, Exl, Eyl;
1502 0 : Complex Er[3], El[3];
1503 0 : Complex Pr[2], Pl[2];
1504 0 : Complex q[2];
1505 : //Double dx, dy, Rhole, Rant, x0, y0, R2, H2, eps;
1506 : //Complex rr, rl, lr, ll, tmp;
1507 : Double L0, phase;
1508 : Double sp, cp;
1509 : Double B[3][3];
1510 : calcAntenna *a;
1511 : Pathology *p;
1512 : Int nx, ny, os;
1513 : Int i, j;
1514 : //Double pac, pas; /* parallactic angle cosine / sine */
1515 0 : Complex Iota; Iota=Complex(0,1);
1516 :
1517 : //UNUSED: Complex E1[3];
1518 : //UNUSED: Double x,y, r2, L, amp, dP, dA, d0, x1, y1, dx1, dy1, dx2, dy2, dO;
1519 : //UNUSED: Ray *ray, *rayx, *rayy;
1520 : //UNUSED: Int iter;
1521 : //UNUSED: Int niter=6;
1522 :
1523 0 : a = newAntennafromApertureCalcParams(ap);
1524 0 : p = newPathologyfromApertureCalcParams(ap);
1525 :
1526 : /* compute central ray pathlength */
1527 : {
1528 : Ray *tmpRay;
1529 0 : tmpRay = trace(a, 0.0, 0.00001, p);
1530 0 : L0 = Raylen(tmpRay);
1531 0 : deleteRay(tmpRay);
1532 : }
1533 :
1534 : //pac = cos(ap->pa+M_PI/2);
1535 : //pas = sin(ap->pa+M_PI/2);
1536 :
1537 0 : if(obsName_p=="EVLA" || obsName_p=="VLA"){
1538 : /* compute polarization vectors in circular basis */
1539 0 : Pr[0] = 1.0/M_SQRT2; Pr[1] = Iota/M_SQRT2;
1540 0 : Pl[0] = 1.0/M_SQRT2; Pl[1] = -Iota/M_SQRT2;
1541 :
1542 : /* compensate for feed orientation */
1543 0 : getfeedbasis(a, B);
1544 0 : phase = atan2(B[0][1], B[0][0]);
1545 0 : cp = cos(phase);
1546 0 : sp = sin(phase);
1547 :
1548 0 : q[0] = Pr[0];
1549 0 : q[1] = Pr[1];
1550 0 : Pr[0] = Complex(cp,0)*q[0] + Complex(sp,0)*q[1];
1551 0 : Pr[1] = -Complex(sp,0)*q[0] + Complex(cp,0)*q[1];
1552 0 : q[0] = Pl[0];
1553 0 : q[1] = Pl[1];
1554 0 : Pl[0] = Complex(cp,0)*q[0] + Complex(sp,0)*q[1];
1555 0 : Pl[1] = -Complex(sp,0)*q[0] + Complex(cp,0)*q[1];
1556 : }
1557 : else{
1558 : /* in linear basis */
1559 0 : Pr[0] = 1.0; Pr[1] = 0.0;
1560 0 : Pl[0] = 0.0; Pl[1] = 1.0;
1561 : }
1562 :
1563 :
1564 :
1565 : /* compute 3-vector feed efields for the two polarizations */
1566 0 : Efield(a, Pr, Er);
1567 0 : Efield(a, Pl, El);
1568 0 : ap->aperture->set(Complex(0.0));
1569 :
1570 0 : os = ap->oversamp;
1571 0 : nx = ap->nx*os;
1572 0 : ny = ap->ny*os;
1573 : //dx = ap->dx/os;
1574 : //dy = ap->dy/os;
1575 : //x0 = ap->x0 - ap->dx/2.0 + dx/2.0;
1576 : //y0 = ap->y0 - ap->dy/2.0 + dy/2.0;
1577 : //Rant = a->radius;
1578 : //Rhole = a->hole_radius;
1579 : //R2 = Rant*Rant;
1580 : //H2 = Rhole*Rhole;
1581 :
1582 : //eps = dx/4.0;
1583 :
1584 0 : IPosition pos(4);
1585 : // shape = ap->aperture->shape();
1586 :
1587 :
1588 : // cerr << "max threads " << omp_get_max_threads()
1589 : // << " threads available " << omp_get_num_threads()
1590 : // << endl;
1591 : //Int Nth=1;
1592 : //#ifdef _OPENMP
1593 : //Nth=max(omp_get_max_threads()-2,1);
1594 : //#endif
1595 : // Timer tim;
1596 : // tim.mark();
1597 : //#pragma omp parallel default(none) firstprivate(Er, El, nx, ny) private(i,j) shared(ap, a, p, L0) num_threads(Nth)
1598 : {
1599 : //#pragma omp for
1600 0 : for(j = 0; j < ny; j++)
1601 : {
1602 0 : for(i = 0; i < nx; i++)
1603 : {
1604 0 : computePixelValues(ap, a, p, L0, Er, El, i,j);
1605 : }
1606 : }
1607 : }
1608 : // tim.show("BeamCalc:");
1609 :
1610 0 : deletePathology(p);
1611 0 : deleteAntenna(a);
1612 :
1613 0 : return 1;
1614 : }
1615 :
1616 0 : void BeamCalc::computePixelValues(const ApertureCalcParams *ap,
1617 : const calcAntenna *a, const Pathology *p,
1618 : const Double &L0,
1619 : Complex *Er, Complex *El,
1620 : const Int &i, const Int &j)
1621 : {
1622 0 : Complex fp, Exr, Eyr, Exl, Eyl;
1623 : // Complex Er[3], El[3];
1624 0 : Complex E1[3];
1625 : Double dx, dy, Rant, x0, y0, x, y, r2, R2, H2, eps, Rhole;
1626 0 : Complex rr, rl, lr, ll, tmp;
1627 : Double L, amp, dP, dA, dO, x1, y1, dx1, dy1, dx2, dy2, phase;
1628 : //Int nx, ny;
1629 : Int os;
1630 0 : Int niter=6;
1631 : Double pac, pas;
1632 : Double cp,sp; /* parallactic angle cosine / sine */
1633 0 : Complex Iota; Iota=Complex(0,1);
1634 0 : IPosition pos(4);pos=0;
1635 :
1636 0 : Ray *ray=0, *rayx=0, *rayy=0;
1637 : /* determine parallactic angle rotated coordinates */
1638 :
1639 0 : os = ap->oversamp;
1640 : //nx = ap->nx*os;
1641 : //ny = ap->ny*os;
1642 0 : dx = ap->dx/os;
1643 0 : dy = ap->dy/os;
1644 0 : x0 = ap->x0 - ap->dx/2.0 + dx/2.0;
1645 0 : y0 = ap->y0 - ap->dy/2.0 + dy/2.0;
1646 0 : Rant = a->radius;
1647 0 : Rhole = a->hole_radius;
1648 0 : R2 = Rant*Rant;
1649 0 : H2 = Rhole*Rhole;
1650 : // for(Int i=0; i < nx; ++i)
1651 : {
1652 0 : eps = dx/4.0;
1653 0 : pac = cos(ap->pa+M_PI/2);
1654 0 : pas = sin(ap->pa+M_PI/2);
1655 :
1656 0 : x = pac*(x0 + i*dx) - pas*(y0 + j*dy);
1657 0 : y = pas*(x0 + i*dx) + pac*(y0 + j*dy);
1658 0 : x = -x;
1659 :
1660 0 : if(fabs(x) > Rant) goto nextpoint;
1661 0 : if(fabs(y) > Rant) goto nextpoint;
1662 0 : r2 = x*x + y*y;
1663 0 : if(r2 > R2) goto nextpoint;
1664 0 : if(r2 < H2) goto nextpoint;
1665 :
1666 0 : ray = rayx = rayy = 0;
1667 :
1668 0 : x1 = x;
1669 0 : y1 = y;
1670 :
1671 0 : for(Int iter = 0; iter < niter; iter++)
1672 : {
1673 0 : ray = trace(a, x1, y1, p);
1674 0 : if(!ray) goto nextpoint;
1675 0 : x1 += (x - ray->aper[0]);
1676 0 : y1 += (y - ray->aper[1]);
1677 0 : deleteRay(ray);
1678 0 : ray = 0;
1679 : }
1680 :
1681 0 : ray = trace(a, x1, y1, p);
1682 :
1683 : /* check for leg blockage */
1684 0 : if(legplanewaveblock2(a, ray))
1685 0 : goto nextpoint;
1686 0 : if(legsphericalwaveblock(a, ray))
1687 0 : goto nextpoint;
1688 :
1689 0 : if(y < 0) rayy = trace(a, x1, y1+eps, p);
1690 0 : else rayy = trace(a, x1, y1-eps, p);
1691 :
1692 0 : if(x < 0) rayx = trace(a, x1+eps, y1, p);
1693 0 : else rayx = trace(a, x1-eps, y1, p);
1694 :
1695 0 : if(ray == 0 || rayx == 0 || rayy == 0)
1696 0 : goto nextpoint;
1697 :
1698 : /* compute solid angle subtended at the feed */
1699 0 : dx1 = rayx->aper[0]-ray->aper[0];
1700 0 : dy1 = rayx->aper[1]-ray->aper[1];
1701 0 : dx2 = rayy->aper[0]-ray->aper[0];
1702 0 : dy2 = rayy->aper[1]-ray->aper[1];
1703 :
1704 0 : dA = 0.5*fabs(dx1*dy2 - dx2*dy1);
1705 0 : dO = (dOmega(a, rayx, rayy, ray, p)/dA)*dx*dx;
1706 0 : dP = dO*feedgain(a, ray, p);
1707 0 : amp = sqrt(dP);
1708 :
1709 0 : L = Raylen(ray);
1710 :
1711 0 : phase = 2.0*M_PI*(L-L0)/a->lambda;
1712 :
1713 : /* phase retard the wave */
1714 0 : cp = cos(phase);
1715 0 : sp = sin(phase);
1716 : // fp = cp + sp*1.0i;
1717 :
1718 0 : fp = Complex(cp,sp);
1719 :
1720 :
1721 0 : tracepol(Er, ray, E1);
1722 0 : Exr = fp*amp*E1[0];
1723 0 : Eyr = fp*amp*E1[1];
1724 :
1725 : // rr = Exr - 1.0i*Eyr;
1726 : // rl = Exr + 1.0i*Eyr;
1727 0 : rr = Exr - Iota*Eyr;
1728 0 : rl = Exr + Iota*Eyr;
1729 :
1730 0 : tracepol(El, ray, E1);
1731 0 : Exl = fp*amp*E1[0];
1732 0 : Eyl = fp*amp*E1[1];
1733 : // lr = Exl - 1.0i*Eyl;
1734 : // ll = Exl + 1.0i*Eyl;
1735 0 : lr = Exl - Iota*Eyl;
1736 0 : ll = Exl + Iota*Eyl;
1737 : // pos(0)=(Int)((j/os) - (25.0/dy/os)/2 + shape(0)/2 - 0.5);
1738 : // pos(1)=(Int)((i/os) - (25.0/dx/os)/2 + shape(1)/2 - 0.5);
1739 : // Following 3 lines go with ANT tag in VLACalc.....
1740 : // Double antRadius=BeamCalcGeometryDefaults[ap->band].Rant;
1741 : // pos(0)=(Int)((j/os) - (antRadius/dy/os) + shape(0)/2 - 0.5);
1742 : // pos(1)=(Int)((i/os) - (antRadius/dx/os) + shape(1)/2 - 0.5);
1743 : // Following 2 lines go with the PIX tag in VLACalc...
1744 0 : pos(0)=(Int)((j/os));
1745 0 : pos(1)=(Int)((i/os));
1746 0 : pos(3)=0;
1747 :
1748 0 : pos(2)=0;tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+rr,pos);
1749 0 : pos(2)=1;tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+rl,pos);
1750 0 : pos(2)=2;tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+lr,pos);
1751 0 : pos(2)=3;tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+ll,pos);
1752 0 : nextpoint:
1753 0 : if(ray) deleteRay(ray);
1754 0 : if(rayx) deleteRay(rayx);
1755 0 : if(rayy) deleteRay(rayy);
1756 : }
1757 0 : }
1758 : //
1759 : //----------------------------------------------------------------------
1760 : // Compute only the required polarizations.
1761 : //
1762 0 : Int BeamCalc::calculateAperture(ApertureCalcParams *ap, const Int& whichPoln)
1763 : {
1764 : //Complex fp, Exr, Eyr, Exl, Eyl;
1765 0 : Complex Er[3], El[3];
1766 0 : Complex Pr[2], Pl[2];
1767 0 : Complex q[2];
1768 : //Double dx, dy, Rhole, Rant;//x0, y0, R2, H2, eps;
1769 : //Complex rr, rl, lr, ll, tmp;
1770 : Double L0, phase;
1771 : Double sp, cp;
1772 : Double B[3][3];
1773 : calcAntenna *a;
1774 : Pathology *p;
1775 : Int nx, ny, os;
1776 : Int i, j;
1777 : //Double pac, pas; /* parallactic angle cosine / sine */
1778 0 : Complex Iota; Iota=Complex(0,1);
1779 :
1780 : //UNUSED: Complex E1[3];
1781 : //UNUSED: Double x,y, r2, L, amp, dP, dA, d0, x1, y1, dx1, dy1, dx2, dy2, dO;
1782 : //UNUSED: Ray *ray, *rayx, *rayy;
1783 : //UNUSED: Int iter;
1784 : //UNUSED: Int niter=6;
1785 :
1786 0 : a = newAntennafromApertureCalcParams(ap);
1787 0 : p = newPathologyfromApertureCalcParams(ap);
1788 :
1789 : /* compute central ray pathlength */
1790 : {
1791 : Ray *tmpRay;
1792 0 : tmpRay = trace(a, 0.0, 0.00001, p);
1793 0 : L0 = Raylen(tmpRay);
1794 0 : deleteRay(tmpRay);
1795 : }
1796 :
1797 : //pac = cos(ap->pa+M_PI/2);
1798 : //pas = sin(ap->pa+M_PI/2);
1799 :
1800 0 : if(obsName_p=="EVLA" || obsName_p=="VLA"){
1801 : /* compute polarization vectors in circular basis */
1802 0 : Pr[0] = 1.0/M_SQRT2; Pr[1] = Iota/M_SQRT2;
1803 0 : Pl[0] = 1.0/M_SQRT2; Pl[1] = -Iota/M_SQRT2;
1804 :
1805 : /* compensate for feed orientation */
1806 0 : getfeedbasis(a, B);
1807 0 : phase = atan2(B[0][1], B[0][0]);
1808 0 : cp = cos(phase);
1809 0 : sp = sin(phase);
1810 :
1811 0 : q[0] = Pr[0];
1812 0 : q[1] = Pr[1];
1813 0 : Pr[0] = Complex(cp,0)*q[0] + Complex(sp,0)*q[1];
1814 0 : Pr[1] = -Complex(sp,0)*q[0] + Complex(cp,0)*q[1];
1815 0 : q[0] = Pl[0];
1816 0 : q[1] = Pl[1];
1817 0 : Pl[0] = Complex(cp,0)*q[0] + Complex(sp,0)*q[1];
1818 0 : Pl[1] = -Complex(sp,0)*q[0] + Complex(cp,0)*q[1];
1819 : }
1820 : else{
1821 : /* in linear basis */
1822 0 : Pr[0] = 1.0; Pr[1] = 0.0;
1823 0 : Pl[0] = 0.0; Pl[1] = 1.0;
1824 : }
1825 :
1826 :
1827 :
1828 : /* compute 3-vector feed efields for the two polarizations */
1829 0 : if ((whichPoln == Stokes::RR) || (whichPoln == Stokes::XX))
1830 0 : Efield(a, Pr, Er);
1831 0 : else if ((whichPoln == Stokes::LL) || (whichPoln == Stokes::YY))
1832 0 : Efield(a, Pl, El);
1833 : else
1834 0 : {Efield(a, Pr, Er); Efield(a, Pl, El);}
1835 :
1836 0 : ap->aperture->set(Complex(0.0));
1837 :
1838 0 : os = ap->oversamp;
1839 0 : nx = ap->nx*os;
1840 0 : ny = ap->ny*os;
1841 : // dx = ap->dx/os;
1842 : // dy = ap->dy/os;
1843 : //x0 = ap->x0 - ap->dx/2.0 + dx/2.0;
1844 : //y0 = ap->y0 - ap->dy/2.0 + dy/2.0;
1845 : // Rant = a->radius;
1846 : // Rhole = a->hole_radius;
1847 : //R2 = Rant*Rant;
1848 : //H2 = Rhole*Rhole;
1849 :
1850 : //eps = dx/4.0;
1851 :
1852 0 : IPosition pos(4);
1853 : // shape = ap->aperture->shape();
1854 :
1855 :
1856 : // cerr << "max threads " << omp_get_max_threads()
1857 : // << " threads available " << omp_get_num_threads()
1858 : // << endl;
1859 : // Int Nth=1, localWhichPoln=whichPoln;
1860 0 : Int localWhichPoln=whichPoln;
1861 : //#ifdef _OPENMP
1862 : //Nth=max(omp_get_max_threads()-2,1);
1863 : //#endif
1864 : // Timer tim;
1865 : // tim.mark();
1866 : //#if GCC44x
1867 : //#pragma omp parallel default(none) firstprivate(Er, El, nx, ny, localWhichPoln) private(i,j) shared(ap, a, p, L0) num_threads(Nth)
1868 : //#else
1869 : //#pragma omp parallel default(none) firstprivate(Er, El, nx, ny, localWhichPoln) private(i,j) shared(ap, a, p, L0) num_threads(Nth)
1870 : //#endif
1871 : {
1872 : //#pragma omp for
1873 0 : for(j = 0; j < ny; j++)
1874 : {
1875 0 : for(i = 0; i < nx; i++)
1876 : {
1877 0 : computePixelValues(ap, a, p, L0, Er, El, i,j,localWhichPoln);
1878 : }
1879 : }
1880 : }
1881 : // tim.show("BeamCalc:");
1882 :
1883 0 : deletePathology(p);
1884 0 : deleteAntenna(a);
1885 :
1886 0 : return 1;
1887 : }
1888 :
1889 0 : void BeamCalc::computePixelValues(const ApertureCalcParams *ap,
1890 : const calcAntenna *a, const Pathology *p,
1891 : const Double &L0,
1892 : Complex *Er, Complex *El,
1893 : const Int &i, const Int &j,
1894 : const Int& whichPoln)
1895 : {
1896 0 : Complex fp, Exr, Eyr, Exl, Eyl;
1897 : // Complex Er[3], El[3];
1898 0 : Complex E1[3];
1899 : Double dx, dy, x0, y0, x, y, r2, Rhole, Rant, R2, H2, eps;
1900 0 : Complex rr, rl, lr, ll, tmp;
1901 : Double L, amp, dP, dA, dO, x1, y1, dx1, dy1, dx2, dy2, phase;
1902 : //Int nx, ny;
1903 : Int os;
1904 0 : Int niter=6;
1905 : Double pac, pas, cp,sp; /* parallactic angle cosine / sine */
1906 0 : Complex Iota; Iota=Complex(0,1);
1907 0 : IPosition pos(4);pos=0;
1908 :
1909 0 : Ray *ray=0, *rayx=0, *rayy=0;
1910 : /* determine parallactic angle rotated coordinates */
1911 :
1912 0 : os = ap->oversamp;
1913 : //nx = ap->nx*os;
1914 : //ny = ap->ny*os;
1915 0 : dx = ap->dx/os;
1916 0 : dy = ap->dy/os;
1917 0 : x0 = ap->x0 - ap->dx/2.0 + dx/2.0;
1918 0 : y0 = ap->y0 - ap->dy/2.0 + dy/2.0;
1919 0 : Rant = a->radius;
1920 0 : Rhole = a->hole_radius;
1921 0 : R2 = Rant*Rant;
1922 0 : H2 = Rhole*Rhole;
1923 : // for(Int i=0; i < nx; ++i)
1924 : {
1925 0 : eps = dx/4.0;
1926 0 : pac = cos(ap->pa+M_PI/2);
1927 0 : pas = sin(ap->pa+M_PI/2);
1928 :
1929 0 : x = pac*(x0 + i*dx) - pas*(y0 + j*dy);
1930 0 : y = pas*(x0 + i*dx) + pac*(y0 + j*dy);
1931 0 : x = -x;
1932 :
1933 0 : if(fabs(x) > Rant) goto nextpoint;
1934 0 : if(fabs(y) > Rant) goto nextpoint;
1935 0 : r2 = x*x + y*y;
1936 0 : if(r2 > R2) goto nextpoint;
1937 0 : if(r2 < H2) goto nextpoint;
1938 :
1939 0 : ray = rayx = rayy = 0;
1940 :
1941 0 : x1 = x;
1942 0 : y1 = y;
1943 :
1944 0 : for(Int iter = 0; iter < niter; iter++)
1945 : {
1946 0 : ray = trace(a, x1, y1, p);
1947 0 : if(!ray) goto nextpoint;
1948 0 : x1 += (x - ray->aper[0]);
1949 0 : y1 += (y - ray->aper[1]);
1950 0 : deleteRay(ray);
1951 0 : ray = 0;
1952 : }
1953 :
1954 0 : ray = trace(a, x1, y1, p);
1955 :
1956 : /* check for leg blockage */
1957 0 : if(legplanewaveblock2(a, ray))
1958 0 : goto nextpoint;
1959 0 : if(legsphericalwaveblock(a, ray))
1960 0 : goto nextpoint;
1961 :
1962 0 : if(y < 0) rayy = trace(a, x1, y1+eps, p);
1963 0 : else rayy = trace(a, x1, y1-eps, p);
1964 :
1965 0 : if(x < 0) rayx = trace(a, x1+eps, y1, p);
1966 0 : else rayx = trace(a, x1-eps, y1, p);
1967 :
1968 0 : if(ray == 0 || rayx == 0 || rayy == 0)
1969 0 : goto nextpoint;
1970 :
1971 : /* compute solid angle subtended at the feed */
1972 0 : dx1 = rayx->aper[0]-ray->aper[0];
1973 0 : dy1 = rayx->aper[1]-ray->aper[1];
1974 0 : dx2 = rayy->aper[0]-ray->aper[0];
1975 0 : dy2 = rayy->aper[1]-ray->aper[1];
1976 :
1977 0 : dA = 0.5*fabs(dx1*dy2 - dx2*dy1);
1978 0 : dO = (dOmega(a, rayx, rayy, ray, p)/dA)*dx*dx;
1979 0 : dP = dO*feedgain(a, ray, p);
1980 0 : amp = sqrt(dP);
1981 :
1982 0 : L = Raylen(ray);
1983 :
1984 0 : phase = 2.0*M_PI*(L-L0)/a->lambda;
1985 :
1986 : /* phase retard the wave */
1987 0 : cp = cos(phase);
1988 0 : sp = sin(phase);
1989 : // fp = cp + sp*1.0i;
1990 :
1991 0 : fp = Complex(cp,sp);
1992 :
1993 :
1994 0 : tracepol(Er, ray, E1);
1995 0 : Exr = fp*amp*E1[0];
1996 0 : Eyr = fp*amp*E1[1];
1997 : // rr = Exr - 1.0i*Eyr;
1998 : // rl = Exr + 1.0i*Eyr;
1999 0 : rr = Exr - Iota*Eyr;
2000 0 : rl = Exr + Iota*Eyr;
2001 :
2002 0 : tracepol(El, ray, E1);
2003 0 : Exl = fp*amp*E1[0];
2004 0 : Eyl = fp*amp*E1[1];
2005 : // lr = Exl - 1.0i*Eyl;
2006 : // ll = Exl + 1.0i*Eyl;
2007 0 : lr = Exl - Iota*Eyl;
2008 0 : ll = Exl + Iota*Eyl;
2009 :
2010 : // pos(0)=(Int)((j/os) - (25.0/dy/os)/2 + shape(0)/2 - 0.5);
2011 : // pos(1)=(Int)((i/os) - (25.0/dx/os)/2 + shape(1)/2 - 0.5);
2012 : // Following 3 lines go with ANT tag in VLACalc.....
2013 : // Double antRadius=BeamCalcGeometryDefaults[ap->band].Rant;
2014 : // pos(0)=(Int)((j/os) - (antRadius/dy/os) + shape(0)/2 - 0.5);
2015 : // pos(1)=(Int)((i/os) - (antRadius/dx/os) + shape(1)/2 - 0.5);
2016 : // Following 2 lines go with the PIX tag in VLACalc...
2017 0 : pos(0)=(Int)((j/os));
2018 0 : pos(1)=(Int)((i/os));
2019 0 : pos(2)=0;
2020 0 : pos(3)=0;
2021 :
2022 0 : if (whichPoln==Stokes::RR)
2023 0 : {tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+rr,pos);}
2024 0 : else if (whichPoln==Stokes::RL)
2025 0 : {tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+rl,pos);}
2026 0 : else if (whichPoln==Stokes::LR)
2027 0 : {tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+lr,pos);}
2028 0 : else if (whichPoln==Stokes::LL)
2029 0 : {tmp=ap->aperture->getAt(pos);ap->aperture->putAt(tmp+ll,pos);}
2030 : else {
2031 0 : SynthesisError err(String("BeamCalc::computePixelValues: Cannot handle Stokes ")+String(whichPoln));
2032 0 : throw(err);
2033 : }
2034 :
2035 0 : nextpoint:
2036 0 : if(ray) deleteRay(ray);
2037 0 : if(rayx) deleteRay(rayx);
2038 0 : if(rayy) deleteRay(rayy);
2039 : }
2040 0 : }
2041 :
2042 : //
2043 : //----------------------------------------------------------------------
2044 : // Compute only the required polarizations.for linear polarization
2045 : //
2046 0 : Int BeamCalc::calculateApertureLinPol(ApertureCalcParams *ap, const Int& whichPoln)
2047 : {
2048 0 : Complex Ex[3], Ey[3];
2049 0 : Complex Px[2], Py[2];
2050 : //Double dx, dy, Rhole, Rant;//x0, y0, R2, H2, eps;
2051 : Double L0;
2052 : calcAntenna *a;
2053 : Pathology *p;
2054 : Int nx, ny, os;
2055 : Int i, j;
2056 : //Double pac, pas; /* parallactic angle cosine / sine */
2057 : // Complex Iota=Complex(0,1);
2058 :
2059 :
2060 0 : a = newAntennafromApertureCalcParams(ap);
2061 0 : p = newPathologyfromApertureCalcParams(ap);
2062 :
2063 : /* compute central ray pathlength */
2064 : {
2065 : Ray *tmpRay;
2066 0 : tmpRay = trace(a, 0.0, 0.00001, p);
2067 0 : L0 = Raylen(tmpRay);
2068 0 : deleteRay(tmpRay);
2069 : }
2070 :
2071 : //pac = cos(ap->pa+M_PI/2);
2072 : //pas = sin(ap->pa+M_PI/2);
2073 :
2074 : /* in linear basis */
2075 0 : Px[0] = 0.0; Px[1] = 1.0;
2076 0 : Py[0] = 1.0; Py[1] = 0.0;
2077 :
2078 0 : IPosition pos(4); pos=0;
2079 :
2080 : /* compute 3-vector feed efields for the two polarizations */
2081 0 : Efield(a, Py, Ey);
2082 0 : Efield(a, Px, Ex);
2083 :
2084 0 : if (whichPoln == Stokes::XX){
2085 0 : pos(2)=0;
2086 : }
2087 0 : else if (whichPoln == Stokes::YY){
2088 0 : pos(2)=3;
2089 : }
2090 0 : else if (whichPoln == Stokes::XY){
2091 0 : pos(2)=1;
2092 : }
2093 0 : else if (whichPoln == Stokes::YX){
2094 0 : pos(2)=2;
2095 : }
2096 : else {
2097 0 : SynthesisError err(String("BeamCalc::calculateApertureLinPol: Cannot handle Stokes ")+String(whichPoln));
2098 0 : throw(err);
2099 : }
2100 :
2101 : // set only the affected plane to zero
2102 0 : for(j = 0; j < ap->nx; j++){
2103 0 : pos(0)= j;
2104 0 : for(i = 0; i < ap->ny; i++){
2105 0 : pos(1)= i;
2106 0 : ap->aperture->putAt(Complex(0.),pos);
2107 : }
2108 : }
2109 :
2110 0 : os = ap->oversamp;
2111 0 : nx = ap->nx*os;
2112 0 : ny = ap->ny*os;
2113 : // dx = ap->dx/os;
2114 : // dy = ap->dy/os;
2115 : //x0 = ap->x0 - ap->dx/2.0 + dx/2.0;
2116 : //y0 = ap->y0 - ap->dy/2.0 + dy/2.0;
2117 : // Rant = a->radius;
2118 : // Rhole = a->hole_radius;
2119 : //R2 = Rant*Rant;
2120 : //H2 = Rhole*Rhole;
2121 :
2122 : //eps = dx/4.0;
2123 :
2124 : // cerr << "max threads " << omp_get_max_threads()
2125 : // << " threads available " << omp_get_num_threads()
2126 : // << endl;
2127 0 : Int Nth=1, localWhichPoln=whichPoln;
2128 : #ifdef _OPENMP
2129 0 : Nth=max(omp_get_max_threads()-2,1);
2130 : #endif
2131 : // Timer tim;
2132 : // tim.mark();
2133 : #if GCC44x
2134 0 : #pragma omp parallel default(none) firstprivate(Ex, Ey, nx, ny, localWhichPoln) private(i,j) shared(ap, a, p, L0) num_threads(Nth)
2135 : #else
2136 : #pragma omp parallel default(none) firstprivate(Ex, Ey, nx, ny, localWhichPoln) private(i,j) shared(ap, a, p, L0) num_threads(Nth)
2137 : #endif
2138 : {
2139 : #pragma omp for
2140 : for(j = 0; j < ny; j++)
2141 : {
2142 : for(i = 0; i < nx; i++)
2143 : {
2144 : computePixelValuesLinPol(ap, a, p, L0, Ex, Ey, i,j,localWhichPoln);
2145 : }
2146 : }
2147 : }
2148 : // tim.show("BeamCalc:");
2149 :
2150 0 : deletePathology(p);
2151 0 : deleteAntenna(a);
2152 :
2153 0 : return 1;
2154 : }
2155 :
2156 0 : void BeamCalc::computePixelValuesLinPol(const ApertureCalcParams *ap,
2157 : const calcAntenna *a, const Pathology *p,
2158 : const Double &L0,
2159 : Complex *Ex, Complex *Ey,
2160 : const Int &i, const Int &j,
2161 : const Int& whichPoln)
2162 : {
2163 0 : Complex fp, Exx, Eyx, Exy, Eyy;
2164 :
2165 0 : Complex E1[3];
2166 : Double dx, dy, x0, y0, x, y, r2, Rhole, Rant, R2, H2, eps;
2167 0 : Complex xx, xy, yx, yy, tmp;
2168 : Double L, amp, dP, dA, dO, x1, y1, dx1, dy1, dx2, dy2, phase;
2169 : //Int nx, ny;
2170 : Int os;
2171 0 : Int niter=6;
2172 : Double pac, pas, cp,sp; /* parallactic angle cosine / sine */
2173 0 : Complex Iota; Iota=Complex(0,1);
2174 0 : IPosition pos(4);pos=0;
2175 :
2176 0 : Ray *ray=0, *rayx=0, *rayy=0;
2177 : /* determine parallactic angle rotated coordinates */
2178 :
2179 0 : os = ap->oversamp;
2180 : //nx = ap->nx*os;
2181 : //ny = ap->ny*os;
2182 0 : dx = ap->dx/os;
2183 0 : dy = ap->dy/os;
2184 0 : x0 = ap->x0 - ap->dx/2.0 + dx/2.0;
2185 0 : y0 = ap->y0 - ap->dy/2.0 + dy/2.0;
2186 0 : Rant = a->radius;
2187 0 : Rhole = a->hole_radius;
2188 0 : R2 = Rant*Rant;
2189 0 : H2 = Rhole*Rhole;
2190 : // for(Int i=0; i < nx; ++i)
2191 : {
2192 0 : eps = dx/4.0;
2193 0 : pac = cos(ap->pa+M_PI/2);
2194 0 : pas = sin(ap->pa+M_PI/2);
2195 :
2196 0 : x = pac*(x0 + i*dx) - pas*(y0 + j*dy);
2197 0 : y = pas*(x0 + i*dx) + pac*(y0 + j*dy);
2198 0 : x = -x;
2199 :
2200 0 : if(fabs(x) > Rant) goto nextpoint;
2201 0 : if(fabs(y) > Rant) goto nextpoint;
2202 0 : r2 = x*x + y*y;
2203 0 : if(r2 > R2) goto nextpoint;
2204 0 : if(r2 < H2) goto nextpoint;
2205 :
2206 0 : ray = rayx = rayy = 0;
2207 :
2208 0 : x1 = x;
2209 0 : y1 = y;
2210 :
2211 0 : for(Int iter = 0; iter < niter; iter++)
2212 : {
2213 0 : ray = trace(a, x1, y1, p);
2214 0 : if(!ray) goto nextpoint;
2215 0 : x1 += (x - ray->aper[0]);
2216 0 : y1 += (y - ray->aper[1]);
2217 0 : deleteRay(ray);
2218 0 : ray = 0;
2219 : }
2220 :
2221 0 : ray = trace(a, x1, y1, p);
2222 :
2223 : /* check for leg blockage */
2224 0 : if(legplanewaveblock2(a, ray))
2225 0 : goto nextpoint;
2226 0 : if(legsphericalwaveblock(a, ray))
2227 0 : goto nextpoint;
2228 :
2229 0 : if(y < 0) rayy = trace(a, x1, y1+eps, p);
2230 0 : else rayy = trace(a, x1, y1-eps, p);
2231 :
2232 0 : if(x < 0) rayx = trace(a, x1+eps, y1, p);
2233 0 : else rayx = trace(a, x1-eps, y1, p);
2234 :
2235 0 : if(ray == 0 || rayx == 0 || rayy == 0)
2236 0 : goto nextpoint;
2237 :
2238 : /* compute solid angle subtended at the feed */
2239 0 : dx1 = rayx->aper[0]-ray->aper[0];
2240 0 : dy1 = rayx->aper[1]-ray->aper[1];
2241 0 : dx2 = rayy->aper[0]-ray->aper[0];
2242 0 : dy2 = rayy->aper[1]-ray->aper[1];
2243 :
2244 0 : dA = 0.5*fabs(dx1*dy2 - dx2*dy1);
2245 0 : dO = (dOmega(a, rayx, rayy, ray, p)/dA)*dx*dx;
2246 0 : dP = dO*feedgain(a, ray, p);
2247 0 : amp = sqrt(dP);
2248 :
2249 0 : L = Raylen(ray);
2250 :
2251 0 : phase = 2.0*M_PI*(L-L0)/a->lambda;
2252 :
2253 : /* phase retard the wave */
2254 0 : cp = cos(phase);
2255 0 : sp = sin(phase);
2256 :
2257 0 : fp = Complex(cp,sp);
2258 :
2259 :
2260 0 : tracepol(Ex, ray, E1);
2261 0 : Exx = fp*amp*E1[0];
2262 0 : Eyx = fp*amp*E1[1];
2263 :
2264 0 : tracepol(Ey, ray, E1);
2265 0 : Exy = fp*amp*E1[0];
2266 0 : Eyy = fp*amp*E1[1];
2267 :
2268 :
2269 0 : xx = Exx;
2270 0 : xy = Complex(0.);
2271 0 : yx = Complex(0.);
2272 0 : yy = Eyy;
2273 :
2274 : // pos(0)=(Int)((j/os) - (25.0/dy/os)/2 + shape(0)/2 - 0.5);
2275 : // pos(1)=(Int)((i/os) - (25.0/dx/os)/2 + shape(1)/2 - 0.5);
2276 : // Following 3 lines go with ANT tag in VLACalc.....
2277 : // Double antRadius=BeamCalcGeometryDefaults[ap->band].Rant;
2278 : // pos(0)=(Int)((j/os) - (antRadius/dy/os) + shape(0)/2 - 0.5);
2279 : // pos(1)=(Int)((i/os) - (antRadius/dx/os) + shape(1)/2 - 0.5);
2280 : // Following 2 lines go with the PIX tag in VLACalc...
2281 0 : pos(0)=(Int)((j/os));
2282 0 : pos(1)=(Int)((i/os));
2283 0 : pos(3)=0;
2284 :
2285 0 : if (whichPoln==Stokes::XX){
2286 0 : pos(2)=0;
2287 0 : tmp=ap->aperture->getAt(pos);
2288 0 : ap->aperture->putAt(tmp+xx,pos);
2289 : }
2290 :
2291 0 : else if (whichPoln==Stokes::XY){
2292 0 : pos(2)=1;
2293 0 : tmp=ap->aperture->getAt(pos);
2294 0 : ap->aperture->putAt(tmp+xy,pos);
2295 : }
2296 :
2297 0 : else if (whichPoln==Stokes::YX){
2298 0 : pos(2)=2;
2299 0 : tmp=ap->aperture->getAt(pos);
2300 0 : ap->aperture->putAt(tmp+yx,pos);
2301 : }
2302 :
2303 0 : else if (whichPoln==Stokes::YY){
2304 0 : pos(2)=3;
2305 0 : tmp=ap->aperture->getAt(pos);
2306 0 : ap->aperture->putAt(tmp+yy,pos);
2307 : }
2308 :
2309 0 : nextpoint:
2310 0 : if(ray) deleteRay(ray);
2311 0 : if(rayx) deleteRay(rayx);
2312 0 : if(rayy) deleteRay(rayy);
2313 : }
2314 0 : }
2315 : };
2316 :
|