earthmodel.cc
1 #include "Constants.h"
2 #include "Settings.h"
3 #include "earthmodel.hh"
4 #include "icemodel.hh"
5 #include <cmath>
6 #include "Tools.h"
7 #include "vector.hh"
8 #include "position.hh"
9 #include <iostream>
10 #include <fstream>
11 #include "icemc_random.h"
12 
13 #include "signal.hh"
14 #include "Primaries.h"
15 #include "secondaries.hh"
16 #include "EnvironmentVariable.h"
17 
18 const string ICEMC_SRC_DIR=EnvironmentVariable::ICEMC_SRC_DIR();
19 const string ICEMC_DATA_DIR=ICEMC_SRC_DIR+"/data/";
20 // input files for Crust 2.0
21 const string crust20_in=ICEMC_DATA_DIR+"/outcr"; // Crust 2.0 data
22 const string crust20_out=ICEMC_SRC_DIR+"/altitudes.txt"; // output file for plotting
23 
24 
25 using std::cout;
26 using std::endl;
27 using std::ios;
28 using std::fstream;
29 
30 
31 const double EarthModel::COASTLINE(30.);
32 const double EarthModel::MAXTHETA(180.);
33 const int EarthModel::ILAT_COASTLINE((int)((COASTLINE/MAXTHETA)*(double)NLAT+0.00001)); // corresponding latitude bin to "coastline"
34 const double EarthModel::GEOID_MAX(6.378137E6); // parameters of geoid model
35 const double EarthModel::GEOID_MIN(6.356752E6); // from Geodetic Reference System 1980, Bulletin Geodesique, Vol 54:395,1980. // The previous reference gave issue number 3 instead of page number 395
36 
37 
38 EarthModel::EarthModel(int model,int WEIGHTABSORPTION_SETTING) {
39 
40 
41  FLATSURFACE = 0;
42  radii[0]=1.2e13;
43  radii[1]=(EarthModel::R_EARTH-4.0E4)*(EarthModel::R_EARTH-4.0E4);
44  radii[2]=(EarthModel::R_EARTH*EarthModel::R_EARTH); // average radii of boundaries between earth layers
45 
46 
47  // cout << "In EarthModel, model is " << model << "\n";
48  weightabsorption= WEIGHTABSORPTION_SETTING;
49 
50  CONSTANTICETHICKNESS = (int) (model / 1000);
51  model -= CONSTANTICETHICKNESS * 1000;
52 
53  CONSTANTCRUST = (int) (model / 100);
54  model -= CONSTANTCRUST * 100;
55 
56  FIXEDELEVATION = (int) (model / 10);
57  model -= FIXEDELEVATION * 10;
58 
59  EARTH_MODEL = model;
60  //cout<<"CONSTICETHK = "<<CONSTANTICETHICKNESS<<", CNSTCRST = "<<CONSTANTCRUST<<", FIXDELV = "<<FIXEDELEVATION<<", EARTH_MODEL = "<<EARTH_MODEL<<endl;
61  for (int i=0;i<NLON;i++) {
62 
63  Tools::Zero(elevationarray[i],NLAT);
64  Tools::Zero(waterthkarray[i],NLAT);
65  Tools::Zero(icethkarray[i],NLAT);
66  Tools::Zero(softsedthkarray[i],NLAT);
67  Tools::Zero(hardsedthkarray[i],NLAT);
68  Tools::Zero(uppercrustthkarray[i],NLAT);
69  Tools::Zero(middlecrustthkarray[i],NLAT);
70  Tools::Zero(lowercrustthkarray[i],NLAT);
71  Tools::Zero(crustthkarray[i],NLAT);
72 
73 
74  Tools::Zero(surfacer[i],NLAT);
75  Tools::Zero(icer[i],NLAT);
76  Tools::Zero(waterr[i],NLAT);
77  Tools::Zero(softsedr[i],NLAT);
78  Tools::Zero(hardsedr[i],NLAT);
79  Tools::Zero(uppercrustr[i],NLAT);
80  Tools::Zero(middlecrustr[i],NLAT);
81  Tools::Zero(lowercrustr[i],NLAT);
82 
83  Tools::Zero(waterdensityarray[i],NLAT);
84  Tools::Zero(icedensityarray[i],NLAT);
85  Tools::Zero(softseddensityarray[i],NLAT);
86  Tools::Zero(hardseddensityarray[i],NLAT);
87  Tools::Zero(uppercrustdensityarray[i],NLAT);
88  Tools::Zero(middlecrustdensityarray[i],NLAT);
89  Tools::Zero(lowercrustdensityarray[i],NLAT);
90 
91  } //Zero Earth model arrays
92 
93  // see monte carlo note #17
94  for (int i=0;i<NLAT;i++) {
95  geoid[i]=GEOID_MIN*GEOID_MAX/sqrt(pow(GEOID_MIN,2.)-(pow(GEOID_MIN,2.)-pow(GEOID_MAX,2.))*pow(cos(dGetTheta(i)),2.));
96  } //for
97 
98 
99  // Crust 2.0 is binned in 2deg x 2deg bins, area of bin depends on latitude.
100  // calculating surface area of bins
101  phistep=2*PI/(double)NLON;
102  thetastep=(MAXTHETA*RADDEG)/NLAT;
103  for (int i=0;i<NLAT;i++) {
104  area[i]=phistep*(cos(dGetTheta(i))-cos(dGetTheta(i+1)))*pow(geoid[i],2.);
105  } //for
106 
107  if (EARTH_MODEL == 0)
108  ReadCrust(crust20_in);
109  else {
110  cout<<"Error! Unknown Earth model requested! Defaulting to Crust 2.0 model.\n";
111  ReadCrust(crust20_in);
112  } //else
113 
114 } //EarthModel constructor (int mode)
115 
116 EarthModel::~EarthModel() {} //EarthModel destructor - no dynamic variables, nothing to delete
117 
118 
119 double EarthModel::LongtoPhi_0isPrimeMeridian(double longitude) {
120 
121  double phi;
122  // convert longitude (-180 to 180) to phi (0 to 2pi) wrt +x
123  // in radians
124  phi=(90-longitude);
125  if (phi<0.)
126  phi+=360.;
127 
128  phi=phi*RADDEG;
129 
130  return phi;
131 }
132 double EarthModel::LongtoPhi_0is180thMeridian(double longitude) {
133 
134  double phi;
135  // convert longitude (0 to 360) to phi (0 to 2pi) wrt +x
136 
137  phi=(270.-longitude);
138  if (phi<0.)
139  phi+=360.;
140 
141  phi=phi*RADDEG;
142  // in radians
143 
144  return phi;
145 }
146 
147 double EarthModel::Geoid(double latitude) {
148  // latitude here is 0 at the south pole and 180 at the north pole
149 
150  return (GEOID_MIN*GEOID_MAX/
151  sqrt(GEOID_MIN*GEOID_MIN-(GEOID_MIN*GEOID_MIN-GEOID_MAX*GEOID_MAX)*
152  cos(latitude*RADDEG)*cos(latitude*RADDEG)));
153 } //Geoid(lat)
154 
155 double EarthModel::Geoid(const Position &pos) {
156  return Geoid(pos.Lat());
157 } //Geoid(Position)
158 
159 double EarthModel::IceThickness(double lon,double lat) {
160  return icethkarray[(int)(lon/2)][(int)(lat/2)]*1000.;
161 } //IceThickness(lon,lat)
162 
163 double EarthModel::IceThickness(const Position& pos) {
164  return IceThickness(pos.Lon(),pos.Lat());
165 } //IceThickness(Position)
166 int EarthModel::InFirn(const Position& pos) {
167  if (pos.Mag()-Surface(pos)<FIRNDEPTH)
168  return 0;
169  return 1;
170 } //InFirn(Position)
171 double EarthModel::SurfaceDeepIce(const Position& pos) { // surface of the deep ice (where you reach the firn)
172  return surfacer[(int)(pos.Lon()/2)][(int)(pos.Lat()/2)] + geoid[(int)(pos.Lat()/2)] + FIRNDEPTH;
173 } //Surface(lon,lat)
174 
175 double EarthModel::Surface(double lon,double lat) {
176  return surfacer[(int)(lon/2)][(int)(lat/2)] + geoid[(int)(lat/2)];
177 } //Surface(lon,lat)
178 
179 double EarthModel::Surface(const Position& pos) {
180  return surfacer[(int)(pos.Lon()/2)][(int)(pos.Lat()/2)] + geoid[(int)(pos.Lat()/2)];
181 } //Surface(Position)
182 
183 double EarthModel::RockSurface(double lon,double lat) {
184  return (Surface(lon,lat) - IceThickness(lon,lat) - WaterDepth(lon,lat));
185 } //RockSurface(lon,lat)
186 
187 double EarthModel::RockSurface(const Position& pos) {
188  return RockSurface(pos.Lon(),pos.Lat());
189 } //RockSurface(lon,lat)
190 
191 double EarthModel::SurfaceAboveGeoid(double lon,double lat) {
192  return surfacer[(int)(lon/2)][(int)(lat/2)];
193 } //SurfaceAboveGeoid(lon,lat)
194 
195 double EarthModel::SurfaceAboveGeoid(const Position& pos) {
196  return surfacer[(int)(pos.Lon()/2)][(int)(pos.Lat()/2)];
197 } //SurfaceAboveGeoid(Position)
198 
199 double EarthModel::WaterDepth(double lon,double lat) {
200  return waterthkarray[(int)(lon/2)][(int)(lat/2)]*1000;
201 } //WaterDepth(lon,lat)
202 
203 double EarthModel::WaterDepth(const Position& pos) {
204  return WaterDepth(pos.Lon(),pos.Lat());
205 } //WaterDepth(Position)
206 
207 double EarthModel::GetLat(double theta) {
208  return theta*DEGRAD;
209 } //GetLat
210 
211 double EarthModel::GetLon(double phi) {
212  // input is phi in radians wrt +x
213  double phi_deg = phi*DEGRAD;
214  if (phi_deg > 270)
215  phi_deg = phi_deg - 360.; // this puts it from -90 to 270
216 
217  return (360.*3./4. - phi_deg); // returns 0 to 360 degrees (going from -180 to 180 deg longitude like Crust 2.0 does)
218 } //GetLon
219 
220 double EarthModel::GetDensity(double altitude, const Position earth_in,
221  int& crust_entered, // 1 or 0
222  bool * inice
223  ){
224 
225  Position where = earth_in;
226 
227  double lon = where.Lon();
228  double lat = where.Lat();
229  //cout <<"Lon and Lat are "<<lon<<","<<lat<<"\n";
230 
231  int ilon = (int)(lon/2);
232  int ilat = (int)(lat/2);
233 
234  double ddensity =0; //initilize ddensity
235 
236  double surface_elevation = this->SurfaceAboveGeoid(lon,lat); // altitude of surface relative to geoid at earth entrance point
237 
238  double local_icethickness = this->IceThickness(lon,lat);
239  double local_waterdepth = WaterDepth(lon,lat);
240 
241  if (inice) *inice = false;
242 
243 
244  if(altitude>surface_elevation+0.1){ // if it is above the surface, it's messed up
245 
246  }
247  if(altitude>surface_elevation+0.1){
248  ddensity=1.25;
249  //cout <<"density is air! \n";
250  }
251  if (altitude<=surface_elevation+0.1 && altitude>(surface_elevation-local_icethickness)) // the 0.1 is just to take care of precision issues. It could have been 0.01 or 0.001.
252  {
253  ddensity=icedensityarray[ilon][ilat]*1000;
254  if (inice) *inice = true;
255  }
256 
257  else if (altitude<=(surface_elevation-local_icethickness) && altitude>(surface_elevation-local_icethickness-local_waterdepth))
258  ddensity=waterdensityarray[ilon][ilat]*1000;
259  else if (altitude<=(surface_elevation-local_icethickness-local_waterdepth) && altitude>softsedr[ilon][ilat]) {
260  ddensity=softseddensityarray[ilon][ilat]*1000;
261  crust_entered=1; //Switch that lets us know we've penetrated into the crust
262  } //end if
263  else if (altitude<=softsedr[ilon][ilat] && altitude>hardsedr[ilon][ilat])
264  ddensity=hardseddensityarray[ilon][ilat]*1000;
265  else if (altitude<=hardsedr[ilon][ilat] && altitude>uppercrustr[ilon][ilat])
266  ddensity=uppercrustdensityarray[ilon][ilat]*1000;
267  else if (altitude<=uppercrustr[ilon][ilat] && altitude>middlecrustr[ilon][ilat])
268  ddensity=middlecrustdensityarray[ilon][ilat]*1000;
269  else if (altitude<=middlecrustr[ilon][ilat] && altitude>lowercrustr[ilon][ilat])
270  ddensity=lowercrustdensityarray[ilon][ilat]*1000;
271  else if (altitude<=lowercrustr[ilon][ilat])
272  ddensity=densities[1];
273 
274  return ddensity;
275 
276 }//Get Density
277 
278 
279 
280 int EarthModel::Getchord(bool unbiased_selection,
281  double len_int_kgm2,
282  const Position &earth_in, // place where neutrino entered the earth
283  double distance_in_ice,
284  bool include_ice_absorption,
285  const Position &posnu, // position of the interaction
286  int inu,
287  double& chord, // chord length
288  double& probability_tmp, // weight
289  double& weight1_tmp,
290  double& nearthlayers, // core, mantle, crust
291  double myair,
292  double& total_kgm2, // length in kg m^2
293  int& crust_entered, // 1 or 0
294  int& mantle_entered, // 1 or 0
295  int& core_entered) {
296 
297  Vector chord3;
298  Vector nchord;
299  double x=0;
300  double lat,lon;
301  // int ilon,ilat;
302 
303  total_kgm2 = 0; //Initialize column density
304  nearthlayers=0; // this counts the number of earth layers the neutrino traverses.
305  // Want to find probability that the neutrino survives its trip
306  // through the earth.
307 
308  //Find the chord, its length and its unit vector.
309  chord3 = posnu - earth_in;
310  chord=chord3.Mag();
311  nchord = chord3 / chord;
312 
313  if (chord<=1) {
314  cout << "short chord " << chord << "\n";
315  return 0;
316  }
317  if (chord>2.*R_EARTH+1000) {
318  cout << "bad chord" << " " << chord << ". Event is " << inu << "\n";
319  }
320 
321  Position where=earth_in;
322  //cout <<"where(1) is "<<where;
323  // the sin of the angle between the neutrino path and the
324  // radial vector to its earth entrance point determines
325  // if it will get to the next layer down.
326  double costh=(where*nchord)/where.Mag();
327  double sinth=sqrt(1-costh*costh);
328  double distance=0;
329  double halfchord=0;
330 
331 
332 
333  if (getchord_method<1 || getchord_method>3)
334  cout << "Bogus method!\n";
335 
336  // we are really focusing on method 2 - method 1 has not been maintenanced in a long time!!
337  // use at your own risk.
338  if (getchord_method==1) {
339  double L=0;
340  weight1_tmp=0;
341 
342  if (sinth>sqrt(radii[1]/radii[2])) {
343  nearthlayers++;
344 
345  // these only skim the first layer.
346  L=len_int_kgm2/densities[2];
347 
348  weight1_tmp=exp(-posnu.Distance(where)/L);
349  }
350  else {
351  nearthlayers++;
352 
353  // these get to the second layer down.
354  L=len_int_kgm2/densities[2];
355  // compute distance before it gets to the next layer.
356  halfchord=sqrt(radii[1]-radii[2]*sinth*sinth);
357  distance=sqrt(radii[2])*costh-halfchord;
358 
359  weight1_tmp=exp(-distance/L);
360 
361  // get position where it enters the second layer.
362  where = earth_in + distance*nchord;
363 
364  // determine if it enters the core or not.
365  costh=(where*nchord)/where.Mag();
366  sinth=sqrt(1-costh*costh);
367 
368  if (sinth>sqrt(radii[0]/radii[1])) {
369 
370 
371  halfchord=sqrt(radii[1])*costh;
372  nearthlayers++;
373 
374  // these do not enter the core.
375  L=len_int_kgm2/densities[1];
376 
377 
378  weight1_tmp *= exp(-2*halfchord/L);
379 
380  L=len_int_kgm2/densities[2];
381  // this is where it exits the second layer and enters the crust again.
382  where = where + 2*halfchord*nchord;
383  weight1_tmp*=exp(-where.Distance(posnu)/L);
384  }
385  else {
386  nearthlayers++;
387  // these enter the core.
388  L=len_int_kgm2/densities[1];
389 
390  // compute distance before entering the core.
391  halfchord=sqrt(radii[0]-radii[1]*sinth*sinth);
392  distance=sqrt(radii[1])*costh-halfchord;
393  weight1_tmp*=exp(-distance/L);
394 
395  // go through the core.
396  L=len_int_kgm2/densities[0];
397  weight1_tmp*=exp(-2*halfchord/L);
398 
399  // go through 2nd layer again.
400  L=len_int_kgm2/densities[1];
401  weight1_tmp*=exp(-distance/L);
402 
403  // through the crust and end up at posnu.
404  L=len_int_kgm2/densities[2];
405 
406  where = where + (2*distance+2*halfchord)*nchord;
407  weight1_tmp*=exp(-where.Distance(posnu)/L);
408  } //else
409  } //else
410  } //if getchord_method==1
411  if (getchord_method==2) {
412 
413  x=0; // x is the distance you move as you step through the earth.
414 
415  lon = where.Lon();
416  lat = where.Lat();
417  // ilon = (int)(lon/2);
418  // ilat = (int)(lat/2);
419 
420  double surface_elevation = this->SurfaceAboveGeoid(lon,lat); // altitude of surface relative to geoid at earth entrance point
421 
422  // double local_icethickness = this->IceThickness(lon,lat);
423  // double local_waterdepth = WaterDepth(lon,lat);
424  double altitude=0;
425  weight1_tmp=1;
426  probability_tmp=1;
427  double step=Tools::dMin(len_int_kgm2/densities[1]/10,500.); //how big is the step size
428  // either 1/10 of an interaction length in the mantle or 500 m, whichever is smaller.
429  // 500 m is approximately the feature size in Crust 2.0.
430  //------------------added on Dec 8------------------------
431  weight1_tmp*=exp(-myair/len_int_kgm2);//add atmosphere attenuation // fenfang's atten. due to atmosphere
432  //------------------added on Dec 8------------------------
433  total_kgm2+=myair;
434 
435 
436 
437  double L_ice=len_int_kgm2/Signal::RHOICE;
438 
439  if (unbiased_selection)
440  {
441  probability_tmp*=1-exp(-1.*(distance_in_ice/L_ice)); // probability it interacts somewhere along its path (at all). We have already sampled exponentially along the chord, so want to multiply by chance of interacting at all!
442  }
443 
444  double L=0;
445 
446  double ddensity=Signal::RHOAIR;
447  nearthlayers=1;
448 
449  if (where*nchord>0.) { // look at direction of neutrino where it enters the earth.
450  cout << "This one's trouble. Neutrino exit point looks more like an entrance point. Event is " << inu << "\n";
451  cout << "where is " << where[0] << " " << where[1] << " " << where[2] << "\n";
452  cout << "nchord is " << nchord[0] << " " << nchord[1] << " " << nchord[2] << "\n";
453  cout << "dot product is " << where*nchord/sqrt(where*where) << "\n";
454  cout << "posnu is " << posnu[0] << " " << posnu[1] << " " << posnu[2] << "\n";
455  cout << "Length of chord is : "<<chord<<endl;
456  } //end if
457 
458  altitude=where.Mag()-Geoid(lat); // what is the altitude of the entrance point
459 
460  if(altitude>surface_elevation+0.1) // if it is above the surface, it's messed up
461  cout << "neutrino entrance point is above the surface. Event is " << inu << "\n";
462  //cout <<"altitude is "<<altitude<<"\n";
463 
464  while(altitude>MIN_ALTITUDE_CRUST && x<posnu.Distance(earth_in)) { // starting at earth entrance point, step toward interaction position until you've reached the interaction or you are below the crust.
465  // while(altitude>MIN_ALTITUDE_CRUST && x<dDistance(enterice,earth_in)) {
466 
467  bool inice;
468  ddensity = this->GetDensity(altitude,where,crust_entered,&inice);
469 
470  L=len_int_kgm2/ddensity; // get the interaction length for that density
471  if (!inice || include_ice_absorption)
472  {
473  weight1_tmp*=exp(-step/L); // adjust the weight accordingly
474  total_kgm2+=ddensity*step; //increase column density accordingly
475  }
476  if (exp(-step/L) > 1)
477  cout<<"Oops! len_int_kgm2, ddensity, factor : "<<len_int_kgm2<<" , "<<ddensity<<" , "<<exp(-step/L)<<endl;
478  x+=step; // distance you have stepped through the earth so far.
479 
480  where += step*nchord;// find where you are now along the neutrino's path
481 
482  lon = where.Lon();
483  lat = where.Lat();
484  // ilon = (int)(lon/2);
485  // ilat = (int)(lat/2);
486  altitude=where.Mag()-Geoid(lat); //what is the altitude
487  surface_elevation = this->SurfaceAboveGeoid(lon,lat); // altitude of surface relative to geoid at earth entrance point
488  // local_icethickness = this->IceThickness(lon,lat);
489  // local_waterdepth = WaterDepth(lon,lat);
490 
491  } //end while
492 
493  if (x>posnu.Distance(earth_in) && weightabsorption) { // if you left the loop because you have already stepped the whole distance from the entrance point to the neutrino interaction position
494  probability_tmp*=weight1_tmp;
495  return 1;
496  }
497  // if you left the loop because you're not in the crust anymore
498  if (altitude<=MIN_ALTITUDE_CRUST) {
499 
500  mantle_entered=1; //Switch that lets us know we're into the mantle
501 
502  // determine if it enters the core or not.
503  sinth=sin(where.Angle(nchord));
504  costh=sqrt(1-sinth*sinth);
505 
506  if (sinth>sqrt(radii[0]/radii[1])) { // it does not enter the core, just the mantle
507 
508  nearthlayers++; // count the mantle as a layer traversed.
509 
510  L=len_int_kgm2/densities[1]; // interaction length in the mantle
511  halfchord=sqrt(radii[1])*costh; // 1/2 chord the neutrino goes through in the mantle
512 
513  weight1_tmp *= exp(-2*halfchord/L); // adjust the weight for path through mantle
514  total_kgm2+= 2*halfchord*densities[1]; //add column density for path through mantle
515  where += (2*halfchord)*nchord; // neutrino's new position once it reaches the crust again
516 
517  } //end if (not entering core)
518  // these enter the core
519  else {
520  core_entered=1; //Switch that lets us know we've entered the core
521 
522  nearthlayers+=2; // count the mantle and core as a layer traversed.
523 
524  L=len_int_kgm2/densities[1]; // interaction length in mantle
525 
526  // compute distance before entering the core.
527  halfchord=sqrt(radii[0]-radii[1]*sinth*sinth); // find distance it travels in the mantle
528  distance=sqrt(radii[1])*costh-halfchord;
529  weight1_tmp*=exp(-distance/L); // adjust the weight
530  total_kgm2 += 2*distance*densities[1]; //Add column density for trip through mantle
531  // go through the core.
532  L=len_int_kgm2/densities[0]; // interaction length in core
533  weight1_tmp*=exp(-2*halfchord/L); // adjust the weight
534  total_kgm2 += 2*halfchord*densities[0]; //Add column density for trip through core
535  // go through 2nd layer again.
536  L=len_int_kgm2/densities[1];
537  weight1_tmp*=exp(-distance/L);
538  if (exp(-distance/L) > 1)
539  cout<<"Oops2! len_int_kgm2, ddensity, distance, factor : "<<len_int_kgm2<<" , "<<ddensity<<" , "<<distance<<" , "<<exp(-distance/L)<<endl;
540  where += (2*distance+2*halfchord)*nchord; // neutrino's new position once it reaches the crust again
541 
542  } //end else(enter core)
543  } //end if(left crust)
544 
545  lon = where.Lon();
546  lat = where.Lat();
547  // ilon = (int)(lon/2);
548  // ilat = (int)(lat/2);
549  altitude=where.Mag()-Geoid(lat); //what is the altitude
550  surface_elevation = this->SurfaceAboveGeoid(lon,lat); // altitude of surface relative to geoid at earth entrance point
551  // local_icethickness = this->IceThickness(lon,lat);
552  // local_waterdepth = WaterDepth(lon,lat);
553 
554  double distance_remaining=where.Distance(posnu); // how much farther you need to travel before you reach the neutrino interaction point
555 
556  x=0; // this keeps track of how far you've stepped along the neutrino path, starting at the crust entrance.
557  while(x<=distance_remaining) { // keep going until you have reached the interaction position
558 
559  bool inice;
560  ddensity=this->GetDensity(altitude,where,crust_entered,&inice);
561 
562  L=len_int_kgm2/ddensity; // get the interaction length for that density
563 
564  if (!inice || include_ice_absorption)
565  {
566  weight1_tmp*=exp(-step/L); // adjust the weight accordingly
567  total_kgm2 += step*ddensity;
568  }
569 
570  if (exp(-step/L) > 1)
571  cout<<"Oops3! len_int_kgm2, ddensity, step, factor : "<<len_int_kgm2<<" , "<<ddensity<<" , "<<step<<" , "<<exp(-step/L)<<endl;
572  x+=step; // increment how far you've stepped through crust
573 
574 
575  // possible for a neutrino to go through the air but not likely because they aren't the most extreme skimmers (they went through the mantle)
576  where += step*nchord; // where you are now along neutrino's path
577 
578  lon = where.Lon();
579  lat = where.Lat();
580  // ilon = (int)(lon/2);
581  // ilat = (int)(lat/2);
582  altitude=where.Mag()-Geoid(lat); //what is the altitude
583  surface_elevation = this->SurfaceAboveGeoid(lon,lat); // altitude of surface relative to geoid at earth entrance point
584  // local_icethickness = this->IceThickness(lon,lat);
585  // local_waterdepth = WaterDepth(lon,lat);
586  } //while
587 
588  } //if (getchord_method == 2)
589 
590  probability_tmp*=weight1_tmp;
591  //cout <<"probability_tmp(non-tau) is "<<probability_tmp<<".\n";
592 
593  if (weightabsorption==0) {
594  if (getRNG(RNG_ABSORB)->Rndm()>weight1_tmp) {
595 
596  weight1_tmp=0.;
597  return 0;
598  }
599  else {
600 
601  weight1_tmp=1.;
602  return 1;
603  }
604  }
605  else
606  return 1;
607 
608  cout << "made it this far.\n";
609 
610  return 1;
611 } //end Getchord
612 
613 Vector EarthModel::GetSurfaceNormal(const Position &r_out)
614 {
615  Vector n_surf = r_out.Unit();
616  if (FLATSURFACE)
617  return n_surf;
618 
619  double theta=r_out.Theta();
620 
621  int ilon,ilat;
622  GetILonILat(r_out,ilon,ilat);
623 
624  int ilon_previous=ilon-1;
625  if (ilon_previous<0)
626  ilon_previous=NLON-1;
627 
628  int ilon_next=ilon+1;
629  if (ilon_next==NLON)
630  ilon_next=0;
631 
632  double r=(geoid[ilat]+surfacer[ilon][ilat])*sin(theta);
633 
634  double slope_phi=(surfacer[ilon_next][ilat]-surfacer[ilon_previous][ilat])/(r*2*phistep);
635 
636  int ilat_previous=ilat-1;
637  if (ilat_previous<0)
638  ilat_previous=0;
639 
640  int ilat_next=ilat+1;
641  if (ilat_next==NLAT)
642  ilat_next=NLAT-1;
643 
644  double slope_costheta=(surfacer[ilon][ilat_next]-surfacer[ilon][ilat_previous])/((geoid[ilat]+surfacer[ilon][ilat])*2*thetastep);
645 
646  // first rotate n_surf according to tilt in costheta and position on continent - rotate around the y axis.
647  double angle=atan(slope_costheta);
648 
649  n_surf = n_surf.RotateY(angle);
650 
651  // now rotate n_surf according to tilt in phi - rotate around the z axis.
652  angle=atan(slope_phi);
653 
654  n_surf = n_surf.RotateZ(angle);
655 
656  return n_surf;
657 
658 } //method GetSurfaceNormal
659 
660 double EarthModel::SmearPhi(int ilon, double rand) {
661 
662 
663  double phi=((double)(360.*3./4.-((double)ilon+rand)*360/180))*RADDEG;
664  if (phi<0 && phi>-1*PI/2)
665  phi+=2*PI;
666 
667 
668  return phi;
669 } //SmearPhi
670 
671 double EarthModel::SmearTheta(int ilat, double rand) {
672 
673  // remember that we should smear it evenly in cos(theta).
674  // first get the cos(theta)'s at the boundaries.
675 
676  double theta1=dGetTheta(ilat)-PI/(double)NLAT/2.;
677  double theta2=dGetTheta(ilat+1)-PI/(double)NLAT/2.;
678 
679  double costheta1=cos(theta1);
680  double costheta2=cos(theta2);
681 
682 
683 
684  double costheta=rand*(costheta2-costheta1)+costheta1;
685 
686  double theta=acos(costheta);
687 
688  return theta;
689 } //SmearTheta
690 
691 void EarthModel::ReadCrust(string test) {
692 
693  // reads in altitudes of 7 layers of crust, ice and water
694  // puts data in arrays
695 
696  fstream infile(test.c_str(),ios::in);
697 
698  string thisline; // for reading in file
699  string slon; //longitude as a string
700  string slat; // latitude as a string
701  string selev; // elevation (km relative to geoid)
702  string sdepth; // depth (km)
703  string sdensity; // density (g/cm^3)
704  double dlon,dlat; // longitude, latitude as double
705  int endindex; // index along thisline for parsing
706  int beginindex; // same
707 
708  int indexlon=0; // 180 bins in longitude
709  int indexlat=0; // 90 bins in latitude
710 
711  string layertype; // water, ice, etc.
712 
713  while(!infile.eof()) {
714  getline(infile,thisline,'\n');
715 
716  int loc=thisline.find("type, latitude, longitude,");
717 
718  if (loc!=(int)(string::npos)) {
719 
720  beginindex=thisline.find_first_not_of(" ",57);
721 
722  endindex=thisline.find_first_of(" ",61);
723 
724  slat=thisline.substr(beginindex,endindex-beginindex);
725  dlat=(double)atof(slat.c_str());
726 
727  beginindex=thisline.find_first_not_of(" ",68);
728  endindex=thisline.find_first_of(" ",72);
729 
730  slon=thisline.substr(beginindex,endindex-beginindex);
731  dlon=(double)atof(slon.c_str());
732 
733 
734  indexlon=(int)((dlon+180)/2);
735  indexlat=(int)((90+dlat)/2);
736 
737  beginindex=thisline.find_first_not_of(" ",78);
738  endindex=thisline.find_first_of(" ",83);
739 
740  selev=thisline.substr(beginindex,endindex-beginindex);
741  elevationarray[indexlon][indexlat]=(double)atof(selev.c_str());
742 
743  } //if
744 
745  for (int i=0;i<4;i++) {
746  getline(infile,thisline,'\n');
747  } //for
748 
749  for (int i=0;i<7;i++) {
750  getline(infile,thisline,'\n');
751 
752  endindex=thisline.length()-1;
753  beginindex=thisline.find_last_of("0123456789",1000);
754  layertype=thisline.substr(beginindex+3,endindex-beginindex);
755 
756 
757  beginindex=thisline.find_first_not_of(" ",0);
758  endindex=thisline.find_first_of(" ",beginindex);
759 
760  sdepth=thisline.substr(beginindex,endindex-beginindex-1);
761 
762 
763  // fills arrays of thicknesses of each layer
764  if (layertype.substr(0,5)=="water")
765  waterthkarray[indexlon][indexlat]=(double)atof(sdepth.c_str());
766  if (layertype.substr(0,3)=="ice")
767  icethkarray[indexlon][indexlat]=(double)atof(sdepth.c_str());
768  if (layertype.substr(0,8)=="soft sed")
769  softsedthkarray[indexlon][indexlat]=(double)atof(sdepth.c_str());
770  if (layertype.substr(0,8)=="hard sed")
771  hardsedthkarray[indexlon][indexlat]=(double)atof(sdepth.c_str());
772  if (layertype.substr(0,11)=="upper crust")
773  uppercrustthkarray[indexlon][indexlat]=(double)atof(sdepth.c_str());
774  if (layertype.substr(0,12)=="middle crust")
775  middlecrustthkarray[indexlon][indexlat]=(double)atof(sdepth.c_str());
776  if (layertype.substr(0,11)=="lower crust")
777  lowercrustthkarray[indexlon][indexlat]=(double)atof(sdepth.c_str());
778 
779  // cout << "indexlon, indexlat, icethkarray " << indexlon << " " << indexlat << " " << icethkarray[indexlon][indexlat] << "\n";
780 
781  // region where Ross Ice Shelf was not accounted for in Crust 2.0
782  // add it in by hand
783  if (indexlat==5 && (indexlon<=5 || indexlon>=176)) // Ross Ice Shelf
784  icethkarray[indexlon][indexlat]=0.5;
785 
786  beginindex=thisline.find_first_not_of(" ",endindex);
787  endindex=thisline.find_first_of(" ",beginindex);
788 
789 
790  beginindex=thisline.find_first_not_of(" ",endindex);
791  endindex=thisline.find_first_of(" ",beginindex);
792 
793  beginindex=thisline.find_first_not_of(" ",endindex);
794  endindex=thisline.find_first_of(" ",beginindex);
795 
796 
797  sdensity=thisline.substr(beginindex,endindex-beginindex);
798 
799  double ddensity=(double)atof(sdensity.c_str());
800 
801 
802  // fills arrays of densities of each layer
803  if (layertype.substr(0,5)=="water")
804  waterdensityarray[indexlon][indexlat]=ddensity;
805  if (layertype.substr(0,3)=="ice")
806  icedensityarray[indexlon][indexlat]=ddensity;
807  if (layertype.substr(0,8)=="soft sed")
808  softseddensityarray[indexlon][indexlat]=ddensity;
809  if (layertype.substr(0,8)=="hard sed")
810  hardseddensityarray[indexlon][indexlat]=ddensity;
811  if (layertype.substr(0,11)=="upper crust")
812  uppercrustdensityarray[indexlon][indexlat]=ddensity;
813  if (layertype.substr(0,12)=="middle crust")
814  middlecrustdensityarray[indexlon][indexlat]=ddensity;
815  if (layertype.substr(0,11)=="lower crust")
816  lowercrustdensityarray[indexlon][indexlat]=ddensity;
817  } //for (reading all lines for one location given in Crust 2.0 input file)
818 
819  if (CONSTANTCRUST) {
820  softsedthkarray[indexlon][indexlat]=40.;
821  hardsedthkarray[indexlon][indexlat]=0;
822  uppercrustthkarray[indexlon][indexlat]=0;
823  middlecrustthkarray[indexlon][indexlat]=0;
824  lowercrustthkarray[indexlon][indexlat]=0;
825  crustthkarray[indexlon][indexlat]=0;
826  softseddensityarray[indexlon][indexlat]=2.9;
827  } //if (set crust thickness to constant everywhere)
828  if (CONSTANTICETHICKNESS) {
829  icethkarray[indexlon][indexlat]=3.;
830  waterthkarray[indexlon][indexlat]=0.;
831  } //if (set ice thickness to constant everywhere)
832 
833  // adds up total thickness of crust
834  crustthkarray[indexlon][indexlat]=softsedthkarray[indexlon][indexlat]+
835  hardsedthkarray[indexlon][indexlat]+
836  uppercrustthkarray[indexlon][indexlat]+
837  middlecrustthkarray[indexlon][indexlat]+
838  lowercrustthkarray[indexlon][indexlat];
839 
840  if (indexlon==179 && indexlat==0)
841  break;
842  } // done reading file
843 
844  for (int i=0;i<NLON;i++) {
845  for (int j=0;j<NLAT;j++) {
846 
847  if (FIXEDELEVATION)
848  elevationarray[i][j]=icethkarray[i][j]*1000;
849 
850  if (waterthkarray[i][j] != 0)
851  surfacer[i][j]=elevationarray[i][j]+waterthkarray[i][j]*1000+icethkarray[i][j]*1000;
852  else
853  surfacer[i][j]=elevationarray[i][j];
854 
855  if (fabs(surfacer[i][j])<1.E-10)
856  surfacer[i][j] = 0;
857 
858  // reminder- waterr is elevation at *bottom* of water layer, etc.
859  // in units of m
860  waterr[i][j]=surfacer[i][j]-(icethkarray[i][j]+waterthkarray[i][j])*1000;
861  if ((double)fabs(waterr[i][j])<1.E-10)
862  waterr[i][j]=0;
863  icer[i][j]=waterr[i][j]+
864  waterthkarray[i][j]*1000;
865  softsedr[i][j]=waterr[i][j]-
866  softsedthkarray[i][j]*1000;
867  hardsedr[i][j]=waterr[i][j]-
868  (softsedthkarray[i][j]+
869  hardsedthkarray[i][j])*1000;
870  uppercrustr[i][j]=waterr[i][j]-
871  (softsedthkarray[i][j]+
872  hardsedthkarray[i][j]+
873  uppercrustthkarray[i][j])*1000;
874  middlecrustr[i][j]=waterr[i][j]-
875  (softsedthkarray[i][j]+
876  hardsedthkarray[i][j]+
877  uppercrustthkarray[i][j]+
878  middlecrustthkarray[i][j])*1000;
879  lowercrustr[i][j]=waterr[i][j]-
880  (softsedthkarray[i][j]+
881  hardsedthkarray[i][j]+
882  uppercrustthkarray[i][j]+
883  middlecrustthkarray[i][j]+
884  lowercrustthkarray[i][j])*1000;
885  } //for (latitude bins)
886  } //for (longitude bins)
887 
888  // calculate ice volume for comparison with expectation
889  volume=0;
890  ice_area=0.;
891  double sumarea=0; // sum of surface area of ice
892  average_iceth = 0;
893  max_icevol_perbin=0.;
894  max_icethk_perbin=0.;
895  for (int j=0;j<ILAT_COASTLINE;j++) {
896  for (int i=0;i<NLON;i++) {
897  volume+=icethkarray[i][j]*1000.*area[j];
898  if (icethkarray[i][j]>0)
899  ice_area+=area[j];
900  if (icethkarray[i][j]*area[j]>max_icevol_perbin)
901  max_icevol_perbin=icethkarray[i][j]*area[j];
902  if (icethkarray[i][j]>max_icethk_perbin)
903  max_icethk_perbin=icethkarray[i][j];
904 
905  /*
906  // j=6 corresponds to 80deg S
907  if (j==6) {
908  // fill output file, just for plotting
909  outfile << surfacer[i][j] << "\t" << waterr[i][j] << "\t" << icer[i][j] << "\t" << icethkarray[i][j] << " " << waterr[i][j]-icer[i][j] << " " << (waterr[i][j]-icer[i][j])*area[j] << " " << area[j] << " " << volume << "\n";
910  }//ifx
911  */
912 
913  // find average ice thickness
914  average_iceth+=(surfacer[i][j]-icer[i][j])*area[j];
915  sumarea+=area[j];
916  } //for
917  } //for
918  average_iceth=average_iceth/sumarea;
919 
920  cout << "Total ice volume=" << volume << endl;
921 
922  // find the place where the crust is the deepest.
923  // for finding where to start stepping in Getchord
924  MIN_ALTITUDE_CRUST=1.E6;
925  //MAX_VOL=-1.E6;
926  for (int i=0;i<NLON;i++) {
927  for (int j=0;j<NLAT;j++) {
928  if (elevationarray[i][j]-(crustthkarray[i][j])*1000<MIN_ALTITUDE_CRUST) {
929  if (waterthkarray[i][j]==0)
930  MIN_ALTITUDE_CRUST=elevationarray[i][j]-(crustthkarray[i][j]+icethkarray[i][j])*1000;
931  else
932  MIN_ALTITUDE_CRUST=elevationarray[i][j]-crustthkarray[i][j]*1000;
933  }//if
934  //if (icethkarray[i][j]*1000.*area[j]>MAX_VOL)
935  //MAX_VOL=icethkarray[i][j]*1000.*area[j];
936  }//for
937  }//for
938 
939  //record depth of crust-mantle interface
940  radii[1]=(Geoid(0.)+MIN_ALTITUDE_CRUST)*(Geoid(0.)+MIN_ALTITUDE_CRUST);
941 
942 }//ReadCrust
943 
944 
945 Vector EarthModel::PickPosnuForaLonLat(double lon,double lat,double theta,double phi) {
946 
947 
948  double surface_above_geoid = this->SurfaceAboveGeoid(lon,lat);
949  double local_ice_thickness = this->IceThickness(lon,lat);
950 
951  double rnd3=getRNG(RNG_POSNU)->Rndm();
952 
953 
954 
955  double elevation = surface_above_geoid - rnd3*local_ice_thickness; // elevation of interaction
956 
957 
958 
959  //cout << "Inside PickInteractionLocation, lon, lat, local_ice_thickness are " << lon << " " << lat << " " << local_ice_thickness << "\n";
960 
961  if (elevation > surface_above_geoid || elevation < (surface_above_geoid - local_ice_thickness))
962  cout<<"elevation > surface_above_geoid || elevation < (surface_above_geoid - local_ice_thickness)\n";
963 
964  Vector posnu((elevation+this->Geoid(lat))*sin(theta)*cos(phi),(elevation+this->Geoid(lat))*sin(theta)*sin(phi),(elevation+this->Geoid(lat))*cos(theta));
965 
966  if (((this->Geoid(lat) + surface_above_geoid)) - posnu.Mag() < 0) {
967  //cout<<"/nYikes! (Geoid(lat) + Surface(lon,lat)) - sqrt(dSquare(posnu) = "<<((this->Geoid(lat) + surface_above_geoid)) - posnu.Mag()<<"/nlon, lat: "<<lon<<" , "<<lat<< " " << endl<<endl;
968  //cout << "local_ice_thickness is " << local_ice_thickness << "\n";
969  }
970 
971  return posnu;
972 }
973 
974 double EarthModel::dGetTheta(int ilat) {
975  return RADDEG*ilat*MAXTHETA/NLAT;
976 } //dGetTheta(int)
977 
978 double EarthModel::dGetPhi(int ilon) {
979  // this takes as an input the crust 2.0 index 0=-180 deg longitude to 179=+180 deg longitude
980  // its output is phi in radians
981  // from ~ -pi/2 to 3*pi/2
982  return (double)(-1*((double)ilon+0.5)+(double)NLON)*2*PI/(double)NLON-PI/2;
983 } //dGetPhi(int)
984 
985 void EarthModel::GetILonILat(const Position &p,int& ilon,int& ilat) {
986  // Phi function outputs from 0 to 2*pi wrt +x
987  double phi_deg=p.Phi()*DEGRAD;
988 
989  if (phi_deg>270)
990  phi_deg=phi_deg-360;
991  // now it's from -90 to 270
992 
993  ilon=(int)((360.*3./4.-phi_deg)*180./360.); // ilon is from 0 (at -180 longitude) to 180 (at 180 longitude)
994 
995  ilat=(int)((p.Theta()*DEGRAD)/2.);
996 
997 } //method GetILonILat
998 void EarthModel::EarthCurvature(double *array,double depth_temp) {
999 
1000  Position parray;
1001  parray.SetXYZ(array[0],array[1],array[2]);
1002 
1003  // adjust array coordinates so that it fits to a curved earth surface at a specific depth
1004  double length=Surface(parray)-depth_temp; // length=distance from center of earth
1005 
1006  double rxposx=array[0]; // x coordinate of antenna position
1007  double rxposy=array[1]; // y coordinate of antenna position
1008  double rxdr=sqrt(rxposx*rxposx+rxposy*rxposy); // distance in horizontal plane from the center of the detector to the antenna
1009  if (Tools::dSquare(array)==0) cout << "Attempt of divide by zero in Earth curvature!!\n";
1010  double rxdtheta=asin(rxdr/sqrt(Tools::dSquare(array)));
1011  double rxdphi=atan2(rxposy,rxposx);
1012 
1013  array[0]=length*sin(rxdtheta)*cos(rxdphi);// have the array sit on a sphere of radius "length"
1014  array[1]=length*sin(rxdtheta)*sin(rxdphi);
1015  array[2]=length*cos(rxdtheta);
1016 
1017 }
1018 Position EarthModel::WhereDoesItEnter(const Position &posnu,const Vector &nnu) {
1019  // now get neutrino entry point...
1020  double p = posnu.Mag(); // radius of interaction
1021  double costheta = (nnu*posnu) / p; // theta of neutrino at interaction position
1022  double sintheta = sqrt(1-costheta*costheta);
1023 
1024  double lon = posnu.Lon();
1025  double lat = posnu.Lat();
1026 
1027  double a=0; // length of chord
1028 
1029  double R = Surface(lon,lat);
1030  double delta = R - p; // depth of the interaction
1031  // if interaction occurs below surface, as it should
1032 
1033  if (delta>-0.001) {
1034  a=p*costheta+sqrt(R*R*costheta*costheta+2*delta*R*sintheta*sintheta); // chord length
1035  if (a<0) {
1036  cout << "Negative chord length: " << a << "\n";
1037  } //end if
1038  } //end if (interaction below surface)
1039  else if (delta<=-0.001) {
1040 
1041  cout << "lon, lat from WhereDoesItEnter is " << lon << " " << lat << "\n";
1042  cout << "geoid, surface, p, surface-p are " << Geoid(lat) << " " << Surface(lon,lat) << " " << p << " , "<<(Surface(lon,lat)-p)<<"\n";
1043 
1044  } //else if: error: interaction takes place above the surface
1045 
1046 
1047  // first approx
1048  // find where nnu intersects spherical earth surface
1049  Position r_in = posnu - a*nnu;
1050 
1051  int iter = 0;
1052  // now do correction 3 times
1053  //for (iter=0; iter<3; iter++) {
1054  // delta = r_in.Mag() - antarctica1->Surface( r_in );
1055  // r_in = r_in + (delta * nnu);
1056  //}
1057 
1058  // how far away r_in is from surface, along line to center of earth
1059  delta = r_in.Mag() - Surface( r_in );
1060 
1061  while ( fabs(delta) >= 0.1 ) { //if it's greater than 10 cm
1062  r_in = r_in + (delta * nnu); // move distance delta along nnu for the next iteration
1063  delta = r_in.Mag() - Surface( r_in ); // find new delta
1064  iter++;
1065  if ( iter > 10 ) { // stop after 10 iterations and just revert to simple answer
1066  //cout<<"\n r_in iteration more than 10 times!!! delta : "<<delta<<". now set r_in as before."<<endl;
1067  r_in = Surface( r_in ) * r_in.Unit(); // the way before
1068  delta = r_in.Mag() - Surface( r_in );
1069  }
1070  }
1071 
1072 
1073  //lon = r_in.Lon();
1074  //lat = r_in.Lat();
1075 
1076  //r_in = antarctica1->Surface(lon,lat) * r_in.Unit();
1077 
1078 
1079  return r_in;
1080 } //method WhereDoesItEnter
1081 
1082 
1083 int EarthModel::GeoidIntersection(Vector x0,Vector p0, Position * int1, Position * int2, double extra_height, double * ds) const
1084 {
1085 
1086 
1114  double POLAR_RADIUS = 6356752.31425 + extra_height;
1115  double EQUATORIAL_RADIUS = 6378137.0 + extra_height;
1116  double EQ2 = EQUATORIAL_RADIUS*EQUATORIAL_RADIUS;
1117  double PO2 = POLAR_RADIUS*POLAR_RADIUS;
1118  double RAT = EQ2/PO2;
1119 
1120 
1121 
1122  //d^2 terms
1123  double a = p0.X()*p0.X() + p0.Y()*p0.Y() + p0.Z()*p0.Z() *RAT;
1124 
1125  //d terms
1126  double b = 2 * ( p0.X()*x0.X() + x0.Y()*p0.Y() + x0.Z()*p0.Z() *RAT) ;
1127 
1128  //constant terms
1129  double c = -EQ2 + x0.X()*x0.X() + x0.Y()*x0.Y() + x0.Z()*x0.Z() *RAT;
1130 
1131  //check discriminant
1132  double discr = b*b-4*a*c;
1133 
1134  //no solution
1135  if (discr < 0)
1136  {
1137  return 0;
1138  }
1139 
1140  discr = sqrt(discr);
1141 
1142  double d0= (-b + discr)/(2*a);
1143  double d1= (-b - discr)/(2*a);
1144  if (ds)
1145  {
1146  ds[0] = d0;
1147  ds[1] = d1;
1148  }
1149 
1150  if (int1)
1151  {
1152  int1->SetXYZ(
1153  x0.X() + d0 *p0.X(),
1154  x0.Y() + d0 *p0.Y(),
1155  x0.Z() + d0 *p0.Z() );
1156 
1157  }
1158  if (int2)
1159  {
1160  int2->SetXYZ(
1161  x0.X() + d1 *p0.X(),
1162  x0.Y() + d1 *p0.Y(),
1163  x0.Z() + d1 *p0.Z() );
1164 
1165  }
1166 
1167  return discr == 0 ? 1 : 2;
1168 }
double Distance(const Position &second) const
Returns chord distance (direct distance between two vectors)
Definition: position.cc:37
const char * ICEMC_SRC_DIR()
double Lat() const
Returns latitude, where the +z direction is at 0 latitude.
Definition: position.cc:47
This class is a 3-vector that represents a position on the Earth&#39;s surface.
Definition: position.hh:26
int GeoidIntersection(Vector x0, Vector p0, Position *int1, Position *int2, double extra_height=5500, double *ds=0) const
Definition: earthmodel.cc:1083
This class represents a three-vector. Operators are overloaded to provide for the familiar operations...
Definition: vector.hh:27
double Lon() const
Returns longitude.
Definition: position.cc:51