icemodel.cc
1 #include "vector.hh"
2 #include "TH1.h"
3 #include "TFile.h"
4 #include "TChain.h"
5 #include "Constants.h"
6 #include "Settings.h"
7 #include "earthmodel.hh"
8 #include "icemodel.hh"
9 #include <assert.h>
10 
11 
12 #include "signal.hh"
13 #include "position.hh"
14 #include "Primaries.h"
15 #include "anita.hh"
16 #include "ray.hh"
17 #include "balloon.hh"
18 #include "Settings.h"
19 #include "EnvironmentVariable.h"
20 
21 #include "icemc_random.h"
22 
23 #include <fstream>
24 #include <iostream>
25 
26 
27 using std::endl;
28 using std::cout;
29 using std::string;
30 using std::ifstream;
31 using std::cerr;
32 
33 const string ICEMC_SRC_DIR = EnvironmentVariable::ICEMC_SRC_DIR();
34 const string ICEMC_DATA_DIR = ICEMC_SRC_DIR+"/data/";
35 
36 
37 #ifdef ICEMODEL_DEBUG_TREE
38 ClassImp(icemodel_debug);
39 #include "TTree.h"
40 static TFile * debugfile = 0;
41 static TTree * debugtree = 0;
42 
43 static icemodel_debug * dbg = new icemodel_debug;
44 
45 
46 static void write_the_tree()
47 {
48  if (debugtree)
49  {
50  debugfile->cd();
51  debugtree->Write();
52  delete debugfile ;
53  }
54 }
55 
56 static void setupTree()
57 {
58  if (!debugtree)
59  {
60 
61  debugfile = new TFile(Form("icemodel_debug_%d.root",getpid()),"RECREATE");
62  debugtree = new TTree("debug","debug");
63  debugtree->Branch("dbg",dbg);
64  atexit(write_the_tree);
65  }
66 }
67 
68 
69 
70 
71 
72 class FillTreeOnReturn
73 {
74 
75  public:
76  FillTreeOnReturn(TFile * cdto, TTree * tree) : f(cdto), t(tree) { ; }
77  ~FillTreeOnReturn() {
78  TDirectory * tmp = gDirectory;
79  f->cd();
80  t->Fill();
81  tmp->cd();
82  }
83  private:
84  TFile * f;
85  TTree * t;
86 };
87 
88 #endif
89 
90 
91 static bool inHistBounds(double x, double y, const TH2 & h)
92 {
93  if (x < h.GetXaxis()->GetXmin()) return false;
94  if (y < h.GetYaxis()->GetXmin()) return false;
95  if (x > h.GetXaxis()->GetXmax()) return false;
96  if (y > h.GetYaxis()->GetXmax()) return false;
97 
98  return true;
99 }
100 
101 
102 
103 
104 IceModel::IceModel(int model,int earth_model,int WEIGHTABSORPTION_SETTING) : EarthModel(earth_model,WEIGHTABSORPTION_SETTING)
105 {
106 
107  bedmap_R = scale_factor*bedmap_c_0 * pow(( (1 + eccentricity*sin(71*RADDEG)) / (1 - eccentricity*sin(71*RADDEG)) ),eccentricity/2) * tan((PI/4) - (71*RADDEG)/2); //varies with latitude, defined here for 71 deg S latitude
108  bedmap_nu = bedmap_R / cos(71*RADDEG);
109 
110  //Parameters of the BEDMAP ice model. (See http://www.antarctica.ac.uk/aedc/bedmap/download/)
111  nCols_ice=1200; //number of columns in data, set by header file (should be 1200)
112  nRows_ice=1000; //number of rows in data, set by header file (should be 1000)
113  cellSize=5000; //in meters, set by header file (should be 5000) - same for both files
114  xLowerLeft_ice=-3000000;
115  yLowerLeft_ice=-2500000;
116  nCols_ground=1068;
117  nRows_ground=869;
118  xLowerLeft_ground=-2661600;
119  yLowerLeft_ground=-2149967;
120  nCols_water=1200;
121  nRows_water=1000;
122  xLowerLeft_water=-3000000;
123  yLowerLeft_water=-2500000;
124  NODATA=-9999;
125 
126  h_ice_thickness.SetTitle("BEDMAP Ice Thickness; Easting (m), Northing (m)");
127 
128  h_ground_elevation.SetTitle("BEDMAP Ground Elevation; Easting (m), Northing (m)");
129 
130  h_water_depth.SetTitle("BEDMAP Water Depth; Easting (m), Northing (m)");
131 
132  sample_x = 0;
133  sample_y = 0;
134 
135  ice_model=model;
136  DEPTH_DEPENDENT_N = (int) (model / 10);
137  ice_model -= DEPTH_DEPENDENT_N * 10;
138 
139 
140  if (ice_model != 0 && ice_model != 1) {
141  cout<<"Error! Unknown ice model requested! Defaulting to Crust 2.0.\n";
142  ice_model = 0;
143  } //if
144  else if (ice_model==1) {
145  ReadIceThickness();
146  ReadWaterDepth();
147  ReadGroundBed();
148  } //else if (BEDMAP)
149  //read in attenuation length data for direct signals
150  int i=0;
151 
152  ifstream sheetup((ICEMC_DATA_DIR+"/icesheet_attenlength_up.txt").c_str());
153  if(sheetup.fail())
154  {
155  cerr << "Failed to open icesheet_attenlength_up.txt" << endl;
156  exit(1);
157  }
158 
159  i=0;
160  while(sheetup>>d_sheetup[i]>>l_sheetup[i])
161  {
162  i++;
163  }
164  sheetup.close();
165 
166  ifstream shelfup((ICEMC_DATA_DIR+"/iceshelf_attenlength_up.txt").c_str());
167  if(shelfup.fail())
168  {
169  cerr << "Failed to open iceshelf_attenlength_up.txt" << endl;
170  exit(1);
171  }
172 
173  i=0;
174  while(shelfup>>d_shelfup[i]>>l_shelfup[i])
175  {
176  i++;
177  }
178  shelfup.close();
179 
180  ifstream westlandup((ICEMC_DATA_DIR+"/westland_attenlength_up.txt").c_str());
181 
182  if(westlandup.fail())
183  {cerr << "Failed to open westland_attenlength_up.txt";
184  exit(1);
185  }
186  i=0;
187  while(westlandup>>d_westlandup[i]>>l_westlandup[i])
188  {
189  i++;
190  }
191  westlandup.close();
192 
193 
194  //read in attenuation length for downgoing signals
195  ifstream sheetdown((ICEMC_DATA_DIR+"/icesheet_attenlength_down.txt").c_str());
196  if(sheetdown.fail())
197  {
198  cerr << "Failed to open icesheet_attenlength_down.txt" << endl;
199  exit(1);
200  }
201 
202  i=0;
203  while(sheetdown>>d_sheetdown[i]>>l_sheetdown[i])
204  {
205  i++;
206  }
207  sheetdown.close();
208 
209  ifstream shelfdown((ICEMC_DATA_DIR+"/iceshelf_attenlength_down.txt").c_str());
210  if(shelfdown.fail())
211  {
212  cerr << "Failed to open iceshelf_attenlength_down.txt" << endl;
213  exit(1);
214  }
215 
216  i=0;
217  while(shelfdown>>d_shelfdown[i]>>l_shelfdown[i])
218  {
219  i++;
220  }
221  shelfdown.close();
222 
223  ifstream westlanddown((ICEMC_DATA_DIR+"/westland_attenlength_down.txt").c_str());
224  if(westlanddown.fail())
225  {cerr << "Failed to open westland_attenlength_down.txt";
226  exit(1);
227  }
228  i=0;
229  while(westlanddown>>d_westlanddown[i]>>l_westlanddown[i])
230  {
231  i++;
232  }
233  westlanddown.close();
234 
235 
236  cart_ice_top = 0;
237  cart_ice_bot = 0;
238  cart_ice_file = 0;
239  cart_resolution = 0;
240  cart_min_z = -1;
241  cart_max_z = -1;
242 }
243 //constructor IceModel(int model)
244 //
245 IceModel::~IceModel()
246 {
247  if (cart_ice_top) delete cart_ice_top;
248  if (cart_ice_bot) delete cart_ice_bot;
249  if (cart_ice_file) delete cart_ice_file;
250 
251 }
252 
253 
254 Position IceModel::PickBalloonPosition() {
255  Vector temp;
256  return temp;
257 
258 }
259 
260 Position IceModel::PickInteractionLocation(int ibnposition, Settings *settings1, const Position &rbn, Interaction *interaction1) {
261 
262  // random numbers used
263  double rnd1=0;
264  double rnd3=1.;
265 
266  double vol_bybin=0.; // volume of ice in each bin
267  int whichbin_forcrust20=0; // choice of a bin of ice for the interaction to occur in, for Crust 2.0
268  int which_coord=0;// choice of coordinates for the interaction, for Bedmap
269  double phi=0,theta=0; // phi and theta for interaction location
270  double lon=0,lat=0; // longitude and latitude corresponding to those phi and theta
271  int ilat=0,ilon=0; // ilat and ilon bins where interaction occurs
272  int e_coord=0; //east coordinate of interaction, from Bedmap
273  int n_coord=0; // north coordinate of interaction, from Bedmap
274 
275  TRandom * rng = getRNG(RNG_INTERACTION_LOCATION);
276 
277  (void) settings1;
278  (void) rbn;
279  (void) interaction1;
280 
281  //in case of roughness, create an array of allowable indices for the lookup (so this stay local to this function and we don't modify *horizon[ibnposition] and fark up other things downstream)
282  /*if(settings1->ROUGHNESS){
283 
284  interaction1->noway=0;
285  interaction1->wheredoesitleave_err=0;
286  interaction1->neverseesice=0;
287  interaction1->wheredoesitenterice_err=0;
288  interaction1->toohigh=0;
289  interaction1->toolow=0;
290 
291  bool bl_foundit = false;
292  Position temppos;
293 
294  while (!bl_foundit){
295  // go through selecting a shift off the balloon position to get lon,lat
296  Vector blnormal = GetSurfaceNormal(rbn).Unit();
297  Vector unitx = Vector();
298  Vector unity;
299 
300  unitx = unitx - unitx.Dot(blnormal)*blnormal;
301  unity = blnormal.Cross(unitx);
302 
303  temppos = rbn + rng->Rndm() * settings1->ROUGH_INTPOS_SHIFT * unitx + rng->Rndm() * settings1->ROUGH_INTPOS_SHIFT * unity;
304  lon = temppos.Lon();
305  lat = temppos.Lat();
306  //if( !IceThickness(lon,lat)){ //ignore if not thick enough
307  // continue; // PickPosnuForaLonLat below complained too much
308  //}
309  bl_foundit = true;
310  }
311 
312  theta = lat*RADDEG;
313  phi=LongtoPhi_0is180thMeridian(lon); // convert longitude to phi
314  //cout << rbn.Lon() << " "<< rbn.Lat() << " " <<temppos.Lon()<< " "<<temppos.Lat()<< " :: ";
315  }
316  else{ // NO roughness case*/
317  //cout << "in pickinteractionlocation, size of ilat_inhorizon is " << ilat_inhorizon[ibnposition].size() << "\n";
318  if (ice_model == 0) { // this is Crust 2.0
319  //cout << "Inside Crust 2.0 if statement.\n";
320  // vol_bybin is initialized to 0
321  while(vol_bybin/maxvol_inhorizon[ibnposition]<rnd3) {
322  rnd3=rng->Rndm(); // pick random numbers between 0 and 1
323  rnd1=rng->Rndm();
324 
325  whichbin_forcrust20=(int)(rnd1*(double)ilat_inhorizon[ibnposition].size());
326  ilat=ilat_inhorizon[ibnposition][whichbin_forcrust20];
327 
328  ilon=ilon_inhorizon[ibnposition][whichbin_forcrust20];
329 
330  vol_bybin=icethkarray[ilon][ilat]*1000.*area[ilat];
331  } //while
332  phi=SmearPhi(ilon, rng->Rndm());
333  theta=SmearTheta(ilat, rng->Rndm());
334  lon = GetLon(phi);
335  lat = GetLat(theta);
336  // cout << "ibnposition, phi, theta, lon, lat are " << ibnposition << " " << phi << " " << theta << " " << lon << " " << lat << "\n";
337  } //end if(Crust 2.0)
338  else if (ice_model==1) { // this is Bedmap
339  //cout << "Inside Bedmap if statement.\n";
340  while(vol_bybin/maxvol_inhorizon[ibnposition]<rnd3) {
341  rnd3=rng->Rndm();
342  rnd1=rng->Rndm();
343 
344  which_coord=(int)(rnd1*(double)easting_inhorizon[ibnposition].size());
345 
346  e_coord=easting_inhorizon[ibnposition][which_coord];
347  n_coord=northing_inhorizon[ibnposition][which_coord];
348 
349  // cout << "e_coord, n_coord are " << e_coord << " " << n_coord << "\n";
350 
351  GroundENtoLonLat(e_coord,n_coord,lon,lat); //Recall that the e / n coordinates in horizon were picked from the ground bed array.
352  //lon+=180.;
353  //cout << "lon, lat are " << lon << " " << lat << "\n";
354 
355  if (e_coord > 1068 || e_coord < 0 || n_coord < 0 || n_coord > 869)
356  cout<<"Problem in PickDownward: e_coord, n_coord : "<<e_coord<<" , "<<n_coord<<endl;
357  vol_bybin=IceThickness(lon,lat)*Area(lat);
358  } //while
359  theta = lat*RADDEG;
360  phi=LongtoPhi_0is180thMeridian(lon); // convert longitude to phi
361  } //end if(BEDMAP)
362  //}
363 
364  //all routines (roughness or no) \it{should} deliver a lon, lat, theta, phi
365  //roughness may not sometimes, should add checks or something
366  Vector posnu=PickPosnuForaLonLat(lon,lat,theta,phi);
367  //Vector blnormal = GetSurfaceNormal(rbn).Unit();
368  //cout << blnormal.Angle(Vector(rbn[0]-posnu[0],rbn[1]-posnu[1],rbn[2]-posnu[2]))*180./PI<<"\n";
369  return posnu;
370 } //PickInteractionLocation
371 
372 
373 
374 
375 static int inu = 0;
376 
377 const int PICK_RANDOM_SEGMENT = 1;
378 static void sampleLocation( double len_int_kgm2,
379  std::vector<std::pair<double,double> > & ice_intersections,
380  Interaction * interaction1, const Vector & x, TRandom * rng, IceModel * model )
381 
382 {
383 
384  //bah, this is dumb. But we don't want to have to call Getchord twice for the segments.
385  std::vector<double> interaction_weights(ice_intersections.size());
386  std::vector<double> absorption_weights(ice_intersections.size());
387  double cumulative_prob = 0;
388  std::vector<double> lengths(ice_intersections.size());
389  std::vector<double> cumulative_probs(ice_intersections.size());
390  std::vector<double> chords(ice_intersections.size());
391  std::vector<double> nearthlayers(ice_intersections.size());
392  std::vector<double> total_kgm2(ice_intersections.size());
393  std::vector<int> crust_entered(ice_intersections.size());
394  std::vector<int> mantle_entered(ice_intersections.size());
395  std::vector<int> core_entered(ice_intersections.size());
396  std::vector<Vector> enterices;
397  std::vector<Vector> exitices;
398 
399 
400  //we need a point on the trajectory for this (doesn't have to be the final location!) Use halfway within the first ice intersection as trial point.
401 
402  interaction1->r_in = model->WhereDoesItEnter(x + 0.5 * (ice_intersections[0].second + ice_intersections[0].first) * interaction1->nnu, interaction1->nnu);
403 
404  double L_ice=len_int_kgm2/Signal::RHOICE;
405  interaction1->pathlength_inice = 0;
406 
407  // we need to find the relative probability of having an interaction in each ice segment.
408  // use the probability of interacting in the ice segment (interaction weight) multiplied by the probability of not having absorbed prior to do this
409  // since these are calculated by Getchord, call Getchord once for each ice segment, using the ice entrance point.
410  // Save all the values so that they can be set when the ice interaction point is selected.
411  for (unsigned i = 0; i < ice_intersections.size(); i++)
412  {
413  double this_length = ice_intersections[i].second - ice_intersections[i].first;
414  lengths[i] = this_length;
415 
416  //get absorption weight to enter point
417  enterices.push_back(x + ice_intersections[i].first * interaction1->nnu);
418  exitices.push_back( x + ice_intersections[i].second * interaction1->nnu);
419 
420 
421 
422  model->Getchord(true,
423  len_int_kgm2,
424  interaction1->r_in,
425  this_length, true, //include absorption from OTHER ice. This ice shouldn't be included since using entrance point
426  enterices[i],
427  inu, //may not be perfecly synchronized... for debug only
428  chords[i],
429  interaction_weights[i],
430  absorption_weights[i],
431  nearthlayers[i],
432  0, //TODO myair, not supported for point sources right now
433  total_kgm2[i], crust_entered[i], mantle_entered[i], core_entered[i]);
434 
435 
436  interaction1->pathlength_inice += this_length;
437 
438  cumulative_prob += interaction_weights[i];
439  cumulative_probs[i] = cumulative_prob;
440  }
441 
442  int which = -1;
443  if (PICK_RANDOM_SEGMENT)
444  {
445  which = rng->Integer(ice_intersections.size());
446  }
447  else
448  {
449  //now select the ice we interact in
450  double p = rng->Uniform(0, cumulative_prob);
451  which = std::upper_bound(cumulative_probs.begin(), cumulative_probs.end(), p) - cumulative_probs.begin();
452  }
453 
454  interaction1->r_enterice = enterices[which];
455  interaction1->nuexitice = exitices[which];
456  interaction1->total_kgm2 = total_kgm2[which];
457  interaction1->nearthlayers = nearthlayers[which];
458  interaction1->crust_entered = crust_entered[which];
459  interaction1->mantle_entered = mantle_entered[which];
460  interaction1->core_entered = core_entered[which];
461  interaction1->weight_nu = absorption_weights[which];
462  if (PICK_RANDOM_SEGMENT )
463  {
464  interaction1->weight_nu_prob = interaction_weights[which] * ice_intersections.size();
465 
466  }
467  else
468  {
469  interaction1->weight_nu_prob = cumulative_prob;
470  }
471 
472 
473  //let's exponentially attenuate within the ice (ignoring any gaps in ice... those will be covered in principle by the attenuation weight)
474  double this_length = lengths[which];
475  double distance = 0;
476 
477  //If we have a very short path length in ice, it's ok to just assume it's uniform
478  if (this_length/ L_ice < 1e-3)
479  {
480  distance = rng->Rndm() * this_length;
481  }
482  else
483  {
484  distance = -log(rng->Uniform(exp(-this_length/L_ice),1))*L_ice;
485  }
486 
487 
488 
489 
490  //finally assign the position
491  interaction1->posnu = enterices[which] + distance * interaction1->nnu;
492  inu++;
493 
494 
495 #ifdef ICEMODEL_DEBUG_TREE
496  dbg->sum_weight_probs = cumulative_prob;
497  for (unsigned i = 0; i < enterices.size(); i++)
498  {
499  dbg->abs_weights.push_back(absorption_weights[i]);
500  dbg->weight_probs.push_back(interaction_weights[i]);
501  dbg->lengths.push_back(lengths[i]);
502  }
503 
504 
505 #endif
506 }
507 
508 int IceModel::PickUnbiasedPointSourceNearBalloon(Interaction * interaction1, const Position * balloon_position,
509  double maxdist, double chord_step, double len_int_kgm2, const Vector * force_dir)
510 {
511 
512 #ifdef ICEMODEL_DEBUG_TREE
513  setupTree();
514  dbg->reset() ;
515  FillTreeOnReturn fill (debugfile, debugtree);
516 #endif
517 
518  // first pick the neutrino direction
519  if (!force_dir)
520  {
521  interaction1->PickAnyDirection();
522  }
523  else
524  {
525  interaction1->nnu = *force_dir;
526  }
527 
528  TRandom * rng = getRNG(RNG_INTERACTION_LOCATION);
529 
530 
531  //now we pick a point in the plane normal to the neutrino direction
532  // We will use the point directly below ANITA with an altitude at 0 km as a reference then consider offsets
533  // relative to that in that plane.
534 
535  //piece of shit!
536  Position ref(balloon_position->Lon()+180, balloon_position->Lat(), R_EARTH);
537 
538 
539  // For now, randomly pick an offset up to maxdist km away
540  // This can be optimized by precalculating the polygon
541  // visible from this angle or finding the bounds in some other way...
542  // Especially for nearly orthogonal events this will be far too big...
543  double x= rng->Uniform(-maxdist*1e3,maxdist*1e3);
544  double y= rng->Uniform(-maxdist*1e3,maxdist*1e3);
545  sample_x =x; sample_y = y;
546 
547  // get nnu as a TVector3 since I like those better
548  Vector nudir = interaction1->nnu.Unit(); //is probably already a unit vector?
549  Vector orth = nudir.Orthogonal();
550  Vector orth2 = nudir.Cross(orth);
551 
552  Vector p0 = ref + x*orth + y*orth2;
553 
554  //Where do we intersect the Earth?
555  Position int1;
556  Position int2;
557 
558  //check if we intersect with the (super) geoid.
559  int nintersect = GeoidIntersection(p0, nudir, &int1, &int2);
560 
561 
562 #ifdef ICEMODEL_DEBUG_TREE
563  dbg->balloon.SetXYZ(balloon_position->X(), balloon_position->Y(), balloon_position->Z());
564  dbg->ref.SetXYZ(ref.X(), ref.Y(), ref.Z());
565  dbg->nudir.SetXYZ(nudir.X(), nudir.Y(), nudir.Z());
566  dbg->nintersect = nintersect;
567  dbg->x = x;
568  dbg->y = y;
569  dbg->int1.SetXYZ(int1.X(), int1.Y(), int1.Z());
570  dbg->int2.SetXYZ(int2.X(), int2.Y(), int2.Z());
571 #endif
572 
573  if (nintersect == 0)
574  {
575 
576 #ifdef ICEMODEL_DEBUG_TREE
577  dbg->noway = true;
578 #endif
579  interaction1->neverseesice=1;
580  interaction1->noway = 1;
581  return 0;
582  }
583 
584 
585 
586 
587 
588  std::vector<std::pair<double,double> > ice_intersections;
589  int n_intersections = GetIceIntersectionsCartesian(int1, nudir, ice_intersections,chord_step);
590 
591  if (n_intersections == 0)
592  {
593  #ifdef ICEMODEL_DEBUG_TREE
594  dbg->noway = true;
595 #endif
596  interaction1->pathlength_inice = 0;
597  interaction1->neverseesice = 1;
598  return 0;
599  }
600 // printf("Hits the ice %d times!\n", n_intersections);
601 
602  sampleLocation(len_int_kgm2, ice_intersections, interaction1,int1, rng, this);
603 
604 
605 
606 #ifdef ICEMODEL_DEBUG_TREE
607  dbg->exitice.SetXYZ(interaction1->nuexitice.X(),interaction1->nuexitice.Y(),interaction1->nuexitice.Z());
608  dbg->enterice.SetXYZ(interaction1->r_enterice.X(),interaction1->r_enterice.Y(),interaction1->r_enterice.Z());
609  dbg->nupos.SetXYZ(interaction1->posnu.X(),interaction1->posnu.Y(),interaction1->posnu.Z());
610 #endif
611 
612 
613 
614  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)>0) {
615  interaction1->toohigh=1;
616  return 0;
617  }
618  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)+IceThickness(interaction1->posnu)<0) {
619  interaction1->toolow=1;
620  return 0;
621  }
622 
623 
624  return 1;
625 }
626 
627 
628 
629 int IceModel::PickUnbiased(Interaction *interaction1, double len_int_kgm2, double & position_weight, double chord_step, Vector * force_dir) {
630 
631  TRandom * rng = getRNG(RNG_INTERACTION_LOCATION);
632  if (!force_dir)
633  {
634  interaction1->PickAnyDirection(); // first pick the neutrino direction
635  }
636  else
637  {
638  interaction1->nnu = *force_dir;
639  }
640 
641 
642  //now we pick a point somewhere on the surface of the superellipsoid.
643  //up to the coastline
644  //TODO, can pick closer to payload but hard to do while keeping ellipsoidal geometry...
645  //instead, will just reject points far away...
646 
647  double sinth = rng->Uniform(0, sin(COASTLINE*RADDEG));
648  double phi = rng->Uniform(0,2*TMath::Pi());
649 
650  double costh = sqrt(1-sinth*sinth);
651 
652  const double RMAX = GEOID_MAX + 5500;
653  const double RMIN = GEOID_MIN + 5500;
654  Vector p0(RMAX * cos(phi) * sinth, RMAX * sin(phi) * sinth, RMIN*costh);
655 
656 
657  // The position weight is (maybe) the dot product of the position with the neutrino direction
658  // this is actually the inverse weight
659  position_weight = 1./fabs(p0.Unit() * interaction1->nnu);
660 
661  //but actually, we can be double counting if the other superellipsoid intesrection is above coastline because
662  //we can sample the same trajectory twice. So let's divide position_weight by two if that is indeed the case.
663 
664  Position ints[2];
665  GeoidIntersection(p0, interaction1->nnu, &ints[0],&ints[2]);
666 
667  int nabovecoastline = 0;
668  for (int i =0; i < 2; i++)
669  {
670  if (ints[i].Lat() < COASTLINE) nabovecoastline++;
671  }
672  assert(nabovecoastline>0);
673  position_weight /= nabovecoastline;
674  interaction1->r_enterice = p0;
675 
676  //now let's set the ice intersactions
677  std::vector<std::pair<double,double> > ice_intersections;
678  int n_intersections = GetIceIntersectionsCartesian(p0, interaction1->nnu, ice_intersections,chord_step);
679 
680 
681  if (!n_intersections)
682  {
683  interaction1->noway = 1;
684  interaction1->neverseesice=1;
685  interaction1->pathlength_inice = 0;
686  return 0;
687  }
688 
689  sampleLocation(len_int_kgm2, ice_intersections, interaction1,p0, rng,this);
690 
691 
692  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)>0) {
693  interaction1->toohigh=1;
694  //cout << "inu, toohigh is " << inu << " " << interaction1->toohigh << "\n";
695  return 0;
696  }
697  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)+IceThickness(interaction1->posnu)<0) {
698  interaction1->toolow=1;
699  //cout << "inu, toolow is " << inu << " " << interaction1->toolow << "\n";
700  return 0;
701  }
702 
703  return 1;
704 
705 }
706 
707 Vector IceModel::GetSurfaceNormal(const Position &r_out) {
708  Vector n_surf = r_out.Unit();
709  if (FLATSURFACE)
710  return n_surf;
711 
712  if (ice_model==0) {
713  double theta=r_out.Theta();
714 
715  int ilon,ilat;
716  GetILonILat(r_out,ilon,ilat);
717 
718  int ilon_previous=ilon-1;
719  if (ilon_previous<0)
720  ilon_previous=NLON-1;
721 
722  int ilon_next=ilon+1;
723  if (ilon_next==NLON)
724  ilon_next=0;
725 
726  double r=(geoid[ilat]+surfacer[ilon][ilat])*sin(theta);
727 
728  double slope_phi=(surfacer[ilon_next][ilat]-surfacer[ilon_previous][ilat])/(r*2*phistep);
729 
730  int ilat_previous=ilat-1;
731  if (ilat_previous<0)
732  ilat_previous=0;
733 
734  int ilat_next=ilat+1;
735  if (ilat_next==NLAT)
736  ilat_next=NLAT-1;
737 
738  double slope_costheta=(surfacer[ilon][ilat_next]-surfacer[ilon][ilat_previous])/((geoid[ilat]+surfacer[ilon][ilat])*2*thetastep);
739 
740  // first rotate n_surf according to tilt in costheta and position on continent - rotate around the y axis.
741  double angle=atan(slope_costheta);
742 
743  n_surf = n_surf.RotateY(angle);
744 
745  // now rotate n_surf according to tilt in phi - rotate around the z axis.
746  angle=atan(slope_phi);
747 
748  n_surf = n_surf.RotateZ(angle);
749  } //end if(Crust 2.0)
750  else if (ice_model==1) {
751  double dist_to_check = 7500; //check elevations at this distance north, south, east and west of event
752  double lon,lat;
753  double lon_prev,lon_next;
754  double lat_prev,lat_next;
755  lon = r_out.Lon();
756  lat = r_out.Lat(); //longitude and latitude of interaction
757  double local_surface_elevation = Surface(lon,lat);
758 
759  lat_next = lat + dist_to_check * (180 / (local_surface_elevation * PI)); //the latitude 7.5 km south of the interaction
760  lat_prev = lat - dist_to_check * (180 / (local_surface_elevation * PI)); //the latitude 7.5 km north of the interaction
761 
762  lon_next = lon + dist_to_check * (180 / (sin(lat*RADDEG) * local_surface_elevation * PI));
763  lon_prev = lon - dist_to_check * (180 / (sin(lat*RADDEG) * local_surface_elevation * PI));
764 
765  if (lat_next > 90) {
766  //cout<<"lat_next is > 90"<<endl;
767  lat_next = 90 - (lat_next - 90); //if we went past the pole, set coordinates for the other side
768  lon_next += 180;
769  lon_prev += 180;
770  } //end if
771  //cout<<"lon, lat: "<<lon<<" , "<<lat<<endl;
772  //correct any out of range longitudes
773  if (lon_next > 360) {
774  //cout<<"lon_next > 360\n";
775  lon_next -= 360;
776  }
777  else if (lon_next < 0) {
778  //cout<<"lon_next < 0\n";
779  lon_next += 360;
780  }
781  if (lon_prev > 360) {
782  //cout<<"lon_prev > 360\n";
783  lon_prev -= 360;
784  }
785  else if (lon_prev < 0) {
786  //cout << "lon_prev < 0";
787  lon_prev += 360;
788  }
789 
790  double slope_phi=(SurfaceAboveGeoid(lon_next,lat)-SurfaceAboveGeoid(lon_prev,lat))/(2*dist_to_check);
791 
792  double slope_costheta=(SurfaceAboveGeoid(lon,lat_next)-SurfaceAboveGeoid(lon,lat_prev))/(2*dist_to_check);
793 
794  // first rotate n_surf according to tilt in costheta - rotate around the y axis.
795  double angle=atan(slope_costheta);
796 
797  n_surf = n_surf.RotateY(angle);
798 
799  // now rotate n_surf according to tilt in phi - rotate around the z axis.
800  angle=atan(slope_phi);
801 
802  n_surf = n_surf.RotateZ(angle);
803  } //end if(BEDMAP)
804 
805  return n_surf;
806 
807 } //method GetSurfaceNormal
808 
809 int IceModel::WhereDoesItEnterIce(const Position &posnu,
810  const Vector &nnu,
811  double stepsize,
812  Position &r_enterice) {
813  // now get exit point...
814  // see my geometry notes.
815  // parameterize the neutrino trajectory and just see where it
816  // crosses the earth radius.
817 
818  // Position r_enterice;
819  double distance=0;
820  int left_edge=0;
821  Position x = posnu;
822  double x2;
823 
824  Position x_previous = posnu;
825 
826  double x_previous2= x_previous * x_previous;
827  x2=x_previous2;
828 
829  double lon = x.Lon(),lat = x.Lat();
830  double lon_old = lon,lat_old = lat;
831  double local_surface = Surface(lon,lat);
832  double rock_previous2= pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
833  double surface_previous2=pow(local_surface,2);
834 
835  double rock2=rock_previous2;
836  double surface2=surface_previous2;
837  int foundit=0; // keeps track of whether you found an ice entrance point
838 
839  // cout << "lon, lat are " << posnu.Lon() << " " << posnu.Lat() << "\n";
840  //cout << "x2 at start is " << x2 << "\n";
841  while (distance<2*local_surface+1000) {
842 
843  distance+=stepsize;
844 
845  x -= stepsize*nnu;
846  x2=x*x;
847  //cout << "x2 is " << x2 << "\n";
848  lon = x.Lon();
849  lat = x.Lat();
850 
851  double ice_thickness=IceThickness(lon,lat);
852  if (lon!=lon_old || lat!=lat_old) {
853  local_surface = Surface(lon,lat);
854 
855  //if (lat>COASTLINE)
856  //left_edge=1;
857 
858  rock2=pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
859  surface2=pow(local_surface,2);
860 
861  if (ice_model==0) {
862  if ((int)(lat)==COASTLINE && rock_previous2 < x2 && surface2 > x2)
863  left_edge=1;
864  } //if (Crust 2.0)
865  } //if (neutrino has stepped into new lon/lat bin)
866 
867  if ((((x_previous2>rock_previous2 && x2<rock2) // crosses rock boundary from above
868  || (x_previous2<surface_previous2 && x2>surface2)) && ice_thickness>0 && lat<COASTLINE) // crosses surface boundary from below
869  || left_edge) {
870  // cout << "lat, COASTLINE, left_edge is " << lat << " " << COASTLINE<< " " << left_edge << "\n";
871  //cout << "x_previous2, surface_previous, x2, surface2 are " << x_previous2 << " " << surface_previous2 << " " << x2 << " " << surface2 << "\n";
872  r_enterice = x;
873  // this gets you out of the loop.
874  //continue;
875  distance=3*Geoid(lat);
876  foundit=1;
877  //cout << "foundit is " << foundit << "\n";
878  //cout << "r_enterice is ";r_enterice.Print();
879  //continue;
880  } //if
881 
882  x_previous = x;
883  x_previous2 = x2;
884  //cout << "x_previous, x_previous2 " << x << " " << x2 << "\n";
885 
886  if (lon!=lon_old || lat!=lat_old) {
887  rock_previous2 = rock2;
888  surface_previous2 = surface2;
889  lat_old = lat;
890  lon_old = lon;
891  } //if
892 
893  } //while
894 
895  return foundit;
896 }//WhereDoesItEnterIce
897 
898 int IceModel::WhereDoesItExitIce(const Position &posnu,
899  const Vector &nnu,
900  double stepsize,
901  Position &r_enterice) {
902  // now get exit point...
903  // see my geometry notes.
904  // parameterize the neutrino trajectory and just see where it
905  // crosses the earth radius.
906 
907  // Position r_enterice;
908  double distance=0;
909  int left_edge=0;
910  Position x = posnu;
911  double x2;
912 
913  Position x_previous = posnu;
914 
915  double x_previous2= x_previous * x_previous;
916  x2=x_previous2;
917 
918  double lon = x.Lon(),lat = x.Lat();
919  double lon_old = lon,lat_old = lat;
920  double local_surface = Surface(lon,lat);
921  double rock_previous2= pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
922  double surface_previous2=pow(local_surface,2);
923 
924  double rock2=rock_previous2;
925  double surface2=surface_previous2;
926  int foundit=0; // keeps track of whether you found an ice entrance point
927 
928 
929 
930  // cout << "lon, lat are " << posnu.Lon() << " " << posnu.Lat() << "\n";
931  //cout << "x2 at start is " << x2 << "\n";
932  int nsteps=0;
933  while (distance<2*local_surface+1000) {
934  //cout << "another step.\n";
935  distance+=stepsize;
936  nsteps++;
937  // cout << "inu, nsteps is " << inu << " " << nsteps << "\n";
938  x -= stepsize*nnu;
939  x2=x*x;
940  //cout << "x2 is " << x2 << "\n";
941  lon = x.Lon();
942  lat = x.Lat();
943 
944  double ice_thickness=IceThickness(lon,lat);
945  if (lon!=lon_old || lat!=lat_old) {
946  local_surface = Surface(lon,lat);
947 
948  //if (lat>COASTLINE)
949  //left_edge=1;
950 
951  rock2=pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
952  surface2=pow(local_surface,2);
953 
954  if (ice_model==0) {
955  if ((int)(lat)==COASTLINE && rock_previous2 < x2 && surface2 > x2)
956  left_edge=1;
957  } //if (Crust 2.0)
958  } //if (neutrino has stepped into new lon/lat bin)
959 
960  if ((((x_previous2<rock_previous2 && x2>rock2) // crosses rock boundary from above
961  || (x_previous2>surface_previous2 && x2<surface2)) && ice_thickness>0 && lat<COASTLINE) // crosses surface boundary from above
962  || left_edge) {
963  // cout << "lat, COASTLINE, left_edge is " << lat << " " << COASTLINE<< " " << left_edge << "\n";
964  //cout << "x_previous2, surface_previous, x2, surface2 are " << x_previous2 << " " << surface_previous2 << " " << x2 << " " << surface2 << "\n";
965  r_enterice = x;
966  // this gets you out of the loop.
967  //continue;
968  distance=3*Geoid(lat);
969  foundit=1;
970  //cout << "foundit is " << foundit << "\n";
971  //continue;
972  } //if
973 
974  x_previous = x;
975  x_previous2 = x2;
976  //cout << "x_previous, x_previous2 " << x << " " << x2 << "\n";
977 
978  if (lon!=lon_old || lat!=lat_old) {
979  rock_previous2 = rock2;
980  surface_previous2 = surface2;
981  lat_old = lat;
982  lon_old = lon;
983  } //if
984 
985  } //while
986 
987  return foundit;
988 }//WhereDoesItExitIce
989 int IceModel::WhereDoesItExitIceForward(const Position &posnu,
990  const Vector &nnu,
991  double stepsize,
992  Position &r_enterice) {
993  // now get exit point...
994  // see my geometry notes.
995  // parameterize the neutrino trajectory and just see where it
996  // crosses the earth radius.
997 
998  // Position r_enterice;
999  double distance=0;
1000  int left_edge=0;
1001  Position x = posnu;
1002  double x2;
1003 
1004  Position x_previous = posnu;
1005 
1006  double x_previous2= x_previous * x_previous;
1007  x2=x_previous2;
1008 
1009  double lon = x.Lon(),lat = x.Lat();
1010  double lon_old = lon,lat_old = lat;
1011  double local_surface = Surface(lon,lat);
1012  double rock_previous2= pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
1013  double surface_previous2=pow(local_surface,2);
1014 
1015  double rock2=rock_previous2;
1016  double surface2=surface_previous2;
1017  int foundit=0; // keeps track of whether you found an ice entrance point
1018 
1019  // cout << "lon, lat are " << posnu.Lon() << " " << posnu.Lat() << "\n";
1020  //cout << "x2 at start is " << x2 << "\n";
1021  while (distance<2*local_surface+1000) {
1022 
1023  distance+=stepsize;
1024 
1025  x += stepsize*nnu;
1026  x2=x*x;
1027  //cout << "x2 is " << x2 << "\n";
1028  lon = x.Lon();
1029  lat = x.Lat();
1030 
1031  double ice_thickness=IceThickness(lon,lat);
1032  if (lon!=lon_old || lat!=lat_old) {
1033  local_surface = Surface(lon,lat);
1034 
1035  //if (lat>COASTLINE)
1036  //left_edge=1;
1037 
1038  rock2=pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
1039  surface2=pow(local_surface,2);
1040 
1041  if (ice_model==0) {
1042  if ((int)(lat)==COASTLINE && rock_previous2 < x2 && surface2 > x2)
1043  left_edge=1;
1044  } //if (Crust 2.0)
1045  } //if (neutrino has stepped into new lon/lat bin)
1046 
1047  if ((((x_previous2<rock_previous2 && x2>rock2) // enters rock boundary from above
1048  || (x_previous2>surface_previous2 && x2<surface2)) && ice_thickness>0 && lat<COASTLINE) // crosses surface boundary from below
1049  || left_edge) {
1050  // cout << "lat, COASTLINE, left_edge is " << lat << " " << COASTLINE<< " " << left_edge << "\n";
1051  //cout << "x_previous2, surface_previous, x2, surface2 are " << x_previous2 << " " << surface_previous2 << " " << x2 << " " << surface2 << "\n";
1052  r_enterice = x;
1053  // this gets you out of the loop.
1054  //continue;
1055  distance=3*Geoid(lat);
1056  foundit=1;
1057  //cout << "foundit is " << foundit << "\n";
1058  //continue;
1059  } //if
1060 
1061  x_previous = x;
1062  x_previous2 = x2;
1063  //cout << "x_previous, x_previous2 " << x << " " << x2 << "\n";
1064 
1065  if (lon!=lon_old || lat!=lat_old) {
1066  rock_previous2 = rock2;
1067  surface_previous2 = surface2;
1068  lat_old = lat;
1069  lon_old = lon;
1070  } //if
1071 
1072  } //while
1073 
1074  return foundit;
1075 }//WhereDoesItExitIceForward
1076 
1077 
1078 double IceModel::IceThickness(double lon, double lat) {
1079  //This method returns the thickness of the ice in meters at a location specified by a latitude and longitude (in degrees). A switch in the input file can be set to determine whether the Crust 2.0 model or the BEDMAP model is used to find the ice depth. Code by Stephen Hoover.
1080  double ice_thickness=0;
1081  //cout << "ice_model is " << ice_model << "\n";
1082  //cout << "icethkarray is " << icethkarray[(int)(lon/2)][(int)(lat/2)]*1000. << "\n";
1083  if (ice_model==1) {
1084  double E=0;
1085  double N=0;
1086  LonLattoEN(lon,lat,E,N);
1087  if (inHistBounds(E,N,h_ice_thickness))
1088  {
1089  ice_thickness = h_ice_thickness.Interpolate(E,N); //if this region has BEDMAP data, use it.
1090  }
1091  else
1092  {
1093  ice_thickness = icethkarray[(int)(lon/2)][(int)(lat/2)]*1000.; //if the location given is not covered by BEDMAP, use Crust 2.0 data
1094  }
1095  } //BEDMAP ice thickness
1096  else if (ice_model==0) {
1097  ice_thickness = icethkarray[(int)(lon/2)][(int)(lat/2)]*1000.;
1098  //cout << "ilon, ilat are " << (int)(lon/2) << " " << (int)(lat/2) << "\n";
1099  } //Crust 2.0 ice thickness
1100 
1101  return ice_thickness;
1102 } //method IceThickness
1103 double IceModel::IceThickness(const Position &pos) {
1104  //This method returns the thickness of the ice in meters at a location under a given position vector. Code by Stephen Hoover.
1105 
1106  return IceThickness(pos.Lon(),pos.Lat());
1107 } //method IceThickness(position)
1108 
1109 double IceModel::SurfaceAboveGeoid(double lon, double lat) {
1110  //This method returns the elevation above the geoid of the surface of the ice (or bare ground, if no ice is present) in meters, at a location specified by a latitude and longitude (in degrees). In areas covered by water where no ice present, the method returns 0. A switch in the input file can be set to determine whether the Crust 2.0 model or the BEDMAP model is used to find the ice depth. Code by Stephen Hoover.
1111  // lon must be 0 to 360
1112  double surface=0;
1113 
1114  if (ice_model==1) {
1115  double E, N ;
1116  LonLattoEN(lon,lat,E,N);
1117 
1118  if (inHistBounds(E,N, h_ground_elevation))
1119  {
1120  surface = h_ground_elevation.Interpolate(E,N) + h_ice_thickness.Interpolate(E,N) + h_water_depth.Interpolate(E,N);
1121  }
1122  else
1123  {
1124  surface = surfacer[(int)(lon/2)][(int)(lat/2)]; //If the position requested is outside the bounds of the BEDMAP data, use the Crust 2.0 data, regardless of the ice_model flag.
1125  }
1126  } //Elevation of surface above geoid according to BEDMAP
1127  else if (ice_model==0) {
1128  surface = surfacer[(int)(lon/2)][(int)(lat/2)];
1129  } //Elevation of surface above geoid according to Crust 2.0
1130 
1131  return surface;
1132 } //method SurfaceAboveGeoid
1133 
1134 double IceModel::SurfaceAboveGeoid(const Position &pos) {
1135  //This method returns the elevation above the geoid of the surface of the ice (or bare ground, if no ice is present) in meters, at a location specified by a position vector. Code by Stephen Hoover.
1136 
1137  return SurfaceAboveGeoid(pos.Lon(),pos.Lat());
1138 } //method SurfaceAboveGeoid(position)
1139 
1140 double IceModel::Surface(double lon,double lat) {
1141  return (SurfaceAboveGeoid(lon,lat) + Geoid(lat)); // distance from center of the earth to surface
1142 } //Surface
1143 
1144 double IceModel::Surface(const Position& pos) {
1145  return Surface(pos.Lon(),pos.Lat());
1146 } //Surface
1147 
1148 double IceModel::WaterDepth(double lon, double lat) {
1149  //This method returns the depth of water beneath ice shelves in meters, at a location specified by a latitude and longitude (in degrees). A switch in the input file can be set to determine whether the Crust 2.0 model or the BEDMAP model is used to find the ice depth. Code by Stephen Hoover.
1150  double water_depth_value=0;
1151 
1152  if (ice_model==0) {
1153  water_depth_value = waterthkarray[(int)(lon/2)][(int)(lat/2)]*1000;
1154  } //if(Crust 2.0)
1155  else if (ice_model==1) {
1156  double E, N;
1157  LonLattoEN(lon,lat,E,N);
1158  if (inHistBounds(E,N,h_water_depth))
1159  {
1160  water_depth_value = h_water_depth.Interpolate(E,N);
1161  }
1162  else
1163  water_depth_value = waterthkarray[(int)(lon/2)][(int)(lat/2)]*1000;
1164  } //else if(BEDMAP)
1165 
1166  return water_depth_value;
1167 } //method WaterDepth(longitude, latitude)
1168 double IceModel::WaterDepth(const Position &pos) {
1169  //This method returns the depth of water beneath ice shelves in meters, at a location specified by a position vector. Code by Stephen Hoover.
1170 
1171  return WaterDepth(pos.Lon(),pos.Lat());
1172 } //method WaterDepth(position)
1173 
1174 int IceModel::IceOnWater(const Position &pos) {
1175  if(IceThickness(pos)>0.&&WaterDepth(pos)>0.)
1176  return 1;
1177  else return 0;
1178 
1179 }
1180 int IceModel::RossIceShelf(const Position &pos) {
1181  int ilon,ilat;
1182 
1183  GetILonILat(pos,ilon,ilat);
1184 
1185  if ((ilat==2 && ilon>=5 && ilon<=14) ||
1186  (ilat==3 && (ilon>=168 || ilon<=14)) ||
1187  (ilat==4 && (ilon>=168 || ilon<=13)) ||
1188  (ilat==5 && (ilon>=168 || ilon<=14)))
1189  return 1;
1190  else
1191  return 0;
1192 }//RossIceShelf
1193 
1194 int IceModel::RossExcept(const Position &pos) {
1195  int ilon,ilat;
1196  GetILonILat(pos,ilon,ilat);
1197  if(ilon<=178&&ilon>=174&&ilat>=4&&ilat<=5)
1198  return 1;
1199  else
1200  return 0;
1201 }
1202 
1203 
1204 int IceModel::RonneIceShelf(const Position &pos) {
1205  int ilon,ilat;
1206 
1207  GetILonILat(pos,ilon,ilat);
1208 
1209  if ((ilat==4 && ilon>=52 && ilon<=74) ||
1210  (ilat==5 && ilon>=50 && ilon<=71) ||
1211  (ilat==6 && ilon>=55 && ilon<=64))
1212  return 1;
1213  else
1214  return 0;
1215 
1216 }//RonneIceShelf
1217 
1218 int IceModel::WestLand(const Position &pos) {
1219  double lon = pos.Lon() , lat = pos.Lat();
1220 
1221  if((lat>=4&&lat<=26)&&((lon>=0&&lon<=180)||lon>=336))
1222  return 1;
1223  else return 0;
1224 
1225 }//WestLand
1226 
1227 double IceModel::GetBalloonPositionWeight(int ibnpos) {
1228  // cout << "ibnpos, volume_inhorizon, volume are " << ibnpos << " " << volume_inhorizon[ibnpos] << " " << volume << "\n";
1229  if (volume_inhorizon[ibnpos]==0) {
1230  return 0; //we will be skipped anyway
1231  }
1232 
1233  return volume/volume_inhorizon[ibnpos];
1234 } //GetBalloonPositionWeight
1235 
1236 int IceModel::OutsideAntarctica(const Position &pos) {
1237  return (pos.Lat() >= COASTLINE);
1238 } //OutsideAntarctica(Position)
1239 
1240 int IceModel::OutsideAntarctica(double lat) {
1241  return (lat >= COASTLINE);
1242 } //OutsideAntarctica(double lat)
1243 
1244 int IceModel::AcceptableRfexit(const Vector &nsurf_rfexit,const Position &rfexit,const Vector &n_exit2rx) {
1245 
1246  //Make sure there's actually ice where the ray leaves
1247  if (rfexit.Lat()>COASTLINE || IceThickness(rfexit)<0.0001) {
1248  cout << "latitude is " << rfexit.Lat() << " compared to COASTLINE at " << COASTLINE << "\n";
1249  cout << "ice thickness is " << IceThickness(rfexit) << "\n";
1250  return 0;
1251 
1252  } //if
1253 
1254  if (nsurf_rfexit*n_exit2rx<0) {
1255  //cout << "dot product is " << nsurf_rfexit*n_exit2rx << "\n";
1256  return 0;
1257  } //if
1258 
1259  return 1;
1260 } //AcceptableRfexit
1261 
1262 double IceModel::GetN(double altitude) {
1263  // these are Peter's fit parameters
1264  double a1=0.463251;
1265  double b1=0.0140157;
1266  double n=0;
1267 
1268  if (altitude < FIRNDEPTH)
1269  n=Signal::NICE;
1270  else if (altitude >= FIRNDEPTH && altitude <=0 && DEPTH_DEPENDENT_N)
1271  // N_DEPTH=NFIRN-(4.6198+13.62*(altitude_int/1000.))*
1272  //(altitude_int/1000.); // Besson's equation for n(z)
1273  n=NFIRN+a1*(1.0-exp(b1*altitude)); // Peter's equation for n(z)
1274  else if (altitude > 0)
1275  cout<<"Error! N requested for position in air!\n";
1276  else if (!DEPTH_DEPENDENT_N)
1277  n = NFIRN;
1278 
1279  return n;
1280 } //GetN(altitude)
1281 
1282 double IceModel::GetN(const Position &pos) {
1283  return GetN(pos.Mag() - Surface(pos.Lon(),pos.Lat()));
1284 } //GetN(Position)
1285 
1286 double IceModel::EffectiveAttenuationLength(Settings *settings1,const Position &pos,const int &whichray) {
1287  double localmaxdepth = IceThickness(pos);
1288  double depth = Surface(pos) - pos.Mag();
1289  //cout << "depth is " << depth << "\n";
1290  int depth_index=0;
1291  double attenuation_length=0.0;
1292 
1293  if(WestLand(pos) && !CONSTANTICETHICKNESS)
1294  {
1295  depth_index=int(depth*419.9/localmaxdepth);//use 420 m ice shelf attenuation length data as the standard, squeeze or stretch if localmaxdepth is longer or shorter than 420m.
1296  if(RossIceShelf(pos) || RonneIceShelf(pos))
1297  {
1298  if(whichray==0)
1299  attenuation_length=l_shelfup[depth_index];
1300  else if(whichray==1)
1301  attenuation_length=l_shelfdown[depth_index];
1302  else
1303  cerr << " wrong attenuation length " <<endl;
1304 
1305  //for sanity check
1306  if((depth_index+0.5)!=d_shelfup[depth_index])
1307  {
1308  cerr << "the index of the array l_iceshelfup is wrong!" << endl;
1309  exit(1);
1310  }
1311  }
1312  else //in ice sheet of westland
1313  {
1314  if(whichray==0)
1315  attenuation_length=l_westlandup[depth_index];
1316  else if(whichray==1)
1317  attenuation_length=l_westlanddown[depth_index];
1318  else
1319  cerr << " wrong attenuation length " <<endl;
1320  }
1321 
1322  if(settings1->MOOREBAY)//if use Moore's Bay measured data for the west land
1323  attenuation_length*=1.717557; //about 450 m (field attenuation length) for one whole way when assuming -3dB for the power loss at the bottom
1324  }
1325  else //in east antarctica or constant ice thickness
1326  {
1327 
1328  depth_index =int(depth*(2809.9/localmaxdepth));
1329 
1330 
1331  if(whichray==0)
1332  attenuation_length =l_sheetup[depth_index];
1333  else if(whichray==1)
1334  attenuation_length =l_sheetdown[depth_index];
1335  else
1336  cerr << " wrong attenuation length " <<endl;
1337  } //else
1338 
1339  return attenuation_length;
1340 } //EffectiveAttenuationLengthUp
1341 
1342 double IceModel::Area(double latitude) {
1343  //Returns the area of one square of the BEDMAP data at a given latitude.
1344  double lat_rad = (90 - latitude) * RADDEG;
1345 
1346  return (pow(cellSize* ((1 + sin(71*RADDEG)) / (1 + sin(lat_rad))),2));
1347 } //method Area
1348 
1349 void IceModel::LonLattoEN(double lon, double lat, double& E, double& N) {
1350  //takes as input a latitude and longitude (in degrees) and converts to indicies for BEDMAP matricies. Needs a location for the corner of the matrix, as not all the BEDMAP files cover the same area. Code by Stephen Hoover.
1351 
1352 
1353  double lon_rad = (lon - 180) * RADDEG; //convert to radians, and shift origin to conventional spot
1354  double lat_rad = (90 - lat) * RADDEG;
1355 
1356  bedmap_R = scale_factor*bedmap_c_0 * pow(( (1 + eccentricity*sin(lat_rad)) / (1 - eccentricity*sin(lat_rad)) ),eccentricity/2) * tan((PI/4) - lat_rad/2);
1357 
1358  E = bedmap_R * sin(lon_rad);
1359  N = bedmap_R * cos(lon_rad);
1360  return;
1361 } //method LonLattoEN
1362 
1363 
1364 void IceModel::ENtoLonLat(int e_coord, int n_coord, double xLowerLeft, double yLowerLeft, double& lon, double& lat) {
1365  //Takes as input the indicies from a BEDMAP data set, and turns them into latitude and longitude coordinates. Information on which data set (surface data, ice depth, water depth) is necessary, in the form of coordinates of a corner of the map. Code by Stephen Hoover.
1366 
1367  double isometric_lat=0;
1368  double easting = xLowerLeft+(cellSize*(e_coord+0.5)); //Add offset of 0.5 to get coordinates of middle of cell instead of edges.
1369  double northing = -(yLowerLeft+(cellSize*(n_coord+0.5)));
1370 
1371  // cout << "easting, northing are " << easting << " " << northing << "\n";
1372 
1373  //first set longitude
1374 
1375  if (northing!=0)
1376  lon = atan(easting/northing);
1377  else
1378  lon = 90*RADDEG;
1379 
1380  // this puts lon between -pi and pi
1381  if (easting > 0 && lon < 0) //adjust sign of longitude
1382  lon += PI;
1383  else if (easting < 0 && lon > 0)
1384  lon -= PI;
1385  else if (easting == 0 && northing < 0)
1386  lon += PI;
1387 
1388  // now find latitude
1389 
1390  if (easting != 0)
1391  bedmap_R = fabs(easting/sin(lon));
1392  else if (easting == 0 && northing != 0)
1393  bedmap_R = fabs(northing);
1394  else {
1395  lat = 0; //at the pole, set lat=0 degrees
1396  lon = lon*DEGRAD; // now put lon between 180 and 180 (only at pol)
1397  return;
1398  } //else
1399 
1400  isometric_lat = (PI/2) - 2*atan(bedmap_R/(scale_factor*bedmap_c_0));
1401 
1402  lat = isometric_lat + bedmap_a_bar*sin(2*isometric_lat) + bedmap_b_bar*sin(4*isometric_lat) + bedmap_c_bar*sin(6*isometric_lat) + bedmap_d_bar*sin(8*isometric_lat);
1403 
1404  lon = lon * DEGRAD + 180; //convert to degrees, shift 0 to line up with bin 0 of Crust 2.0
1405  lat = 90 - lat*DEGRAD; //convert to degrees, with 0 degrees at the south pole
1406 
1407  // if (lon>160 && lon<165)
1408  //cout << "e_coord, n_coord, easting, northing, lon are " << e_coord << " " << n_coord << " " << easting << " " << northing << " " << lon << "\n";
1409  return;
1410 
1411 } //method ENtoLonLat
1412 
1413 void IceModel::IceENtoLonLat(int e, int n, double& lon, double& lat) {
1414  //Converts indicies of the BEDMAP ice thickness matrix into longitude and latitude. Code by Stephen Hoover.
1415  // cout << "I'm inside IceENtoLonLat.\n";
1416  ENtoLonLat(e,n,xLowerLeft_ice,yLowerLeft_ice,lon,lat);
1417 }//IceENtoLonLat
1418 void IceModel::GroundENtoLonLat(int e, int n, double& lon, double& lat) {
1419  //Converts indicies of the BEDMAP ground elevation matrix into longitude and latitude. Code by Stephen Hoover.
1420  ENtoLonLat(e,n,xLowerLeft_ground,yLowerLeft_ground,lon,lat);
1421 }//GroundENtoLonLat
1422 void IceModel::WaterENtoLonLat(int e, int n, double& lon, double& lat) {
1423  //Converts indicies of the BEDMAP water depth matrix into longitude and latitude. Code by Stephen Hoover.
1424  ENtoLonLat(e,n,xLowerLeft_water,yLowerLeft_water,lon,lat);
1425 }//WaterENtoLonLat
1426 
1427 
1428 
1429 void IceModel::GetMAXHORIZON(Balloon *bn1) {
1430 
1431  double altitude_inmeters=bn1->BN_ALTITUDE;
1432  if (bn1->BN_ALTITUDE==0.)
1433  bn1->MAXHORIZON=8.E5; // if it is a standard flight then use a horizon of 800 km
1434  else
1435  bn1->MAXHORIZON=(sqrt((R_EARTH+altitude_inmeters)*(R_EARTH+altitude_inmeters)-R_EARTH*R_EARTH))*1.1; // find distance from hrizon to balloon, increase it by 10% to be conservative.
1436  cout << "MAXHORIZON is " << bn1->MAXHORIZON << "\n";
1437 }
1438 
1439 
1440 void IceModel::CreateHorizons(Settings *settings1,Balloon *bn1,double theta_bn,double phi_bn,double altitude_bn,ofstream &foutput) {
1441 
1442  // add up volume of ice within horizon of payload
1443  // goes a little beyond horizon.
1444 
1445  // when we select a path in a circle at 80deg S latitude,
1446  // vectors are binned in phi (longitude).
1447 
1448  // when we select the Anita-lite path,
1449  // vectors are binned in time.
1450 
1451  //for (int i=0; i<60;i++)
1452  //cout<<"area at lat "<<(double)i/2<<" is "<<Area((double)i/2)<<endl;
1453 
1454  volume = 0.; // initialize volume to zero
1455 
1456  double total_area=0; // initialize total area to zero
1457  int NBALLOONPOSITIONS; // number of balloon positions considered here
1458  if (bn1->WHICHPATH==2) // if anita-lite
1459  NBALLOONPOSITIONS=(int)((double)bn1->NPOINTS/(double)bn1->REDUCEBALLOONPOSITIONS); //only take 1/100 of the total balloon positions that we have because otherwise it's overkill.
1460  else if (bn1->WHICHPATH==6 || bn1->WHICHPATH==7 || bn1->WHICHPATH==8 || bn1->WHICHPATH==9) {
1461  NBALLOONPOSITIONS=(int)((double)bn1->flightdatachain->GetEntries()/(double)bn1->REDUCEBALLOONPOSITIONS)+1;
1462  }
1463  else if (bn1->WHICHPATH==1) // for picking random point along 80 deg south
1464  NBALLOONPOSITIONS=NPHI; // NPHI is the number of bins in phi for the visible ice in the horizon. This is not the same as NLON, the number of bins in longitude for crust 2.0
1465  else // includes fixed position (bn1->WHICHPATH=0)
1466  NBALLOONPOSITIONS=1;
1467 
1468  volume_inhorizon.resize(NBALLOONPOSITIONS);
1469  maxvol_inhorizon.resize(NBALLOONPOSITIONS);
1470  ilon_inhorizon.resize(NBALLOONPOSITIONS);
1471  ilat_inhorizon.resize(NBALLOONPOSITIONS);
1472  easting_inhorizon.resize(NBALLOONPOSITIONS);
1473  northing_inhorizon.resize(NBALLOONPOSITIONS);
1474 
1475 
1476 
1477  double phi_bn_temp=0; //phi of balloon, temporary variable
1478  Position r_bn_temp; //position of balloon
1479  Position r_bin; // position of each bin
1480 
1481  double surface_elevation=0;
1482  double local_ice_thickness=0;
1483  double lat=0;
1484  double lon=0;
1485  //double r=0; // r,theta and phi are temporary variables
1486  double theta=0;
1487  double phi=0;
1488  int volume_found=0;
1489  char horizon_file[80];
1490  FILE *bedmap_horizons = 0;
1491  char line[200];
1492  int e_coord = 0;
1493  int n_coord = 0;
1494 
1495  if (bn1->WHICHPATH==0)
1496  {
1497  sprintf(horizon_file,"bedmap_horizons_fixed_%g_%g_%g.dat",bn1->BN_LATITUDE, bn1->BN_LATITUDE, bn1->BN_ALTITUDE);
1498  }
1499  else
1500  {
1501  sprintf(horizon_file,"bedmap_horizons_whichpath%i_weights%i.dat",bn1->WHICHPATH,settings1->USEPOSITIONWEIGHTS);
1502  }
1503 
1504  if (ice_model==1 && !settings1->WRITE_FILE) { // for bedmap model, need to be able to read file
1505  if(!(bedmap_horizons = fopen(horizon_file, "r"))) {
1506  printf("Error: unable to open %s. Creating new file.\n", horizon_file);
1507  settings1->WRITE_FILE=1;
1508  }//if
1509  } //if
1510  if (ice_model==1 && settings1->WRITE_FILE) { // for bedmap model, need to be able to write to file
1511  if(!(bedmap_horizons = fopen(horizon_file, "w"))) {
1512  printf("Error: unable to open %s\n", horizon_file);
1513  exit(1);
1514  }//if
1515  } //else if
1516 
1517  if (bn1->WHICHPATH!=2 && bn1->WHICHPATH!=6) // not anita and not anita-lite
1518  lat=GetLat(theta_bn); //get index of latitude, same for all balloon positions
1519 
1520 
1521 
1522  for (int i=0;i<NBALLOONPOSITIONS;i++) { // loop over balloon positions
1523 
1524  maxvol_inhorizon[i]=-1.; // volume of bin with the most ice in the horizon
1525 // double the_time = 0;
1526 
1527  if (bn1->WHICHPATH==2) { // anita or anita-lite path
1528  theta_bn=(90+bn1->latitude_bn_anitalite[i*bn1->REDUCEBALLOONPOSITIONS])*RADDEG; //theta of the balloon wrt north pole
1529  lat=GetLat(theta_bn); // latitude
1530  phi_bn_temp=(-1*bn1->longitude_bn_anitalite[i*bn1->REDUCEBALLOONPOSITIONS]+90.); //phi of the balloon, with 0 at +x and going counter clockwise looking down from the south pole
1531  if (phi_bn_temp<0) //correct phi_bn if it's negative
1532  phi_bn_temp+=360.;
1533  phi_bn_temp*=RADDEG;// turn it into radians
1534 
1535 
1536  altitude_bn=bn1->altitude_bn_anitalite[i*bn1->REDUCEBALLOONPOSITIONS]*12.*CMINCH/100.; // get the altitude for this balloon posistion (ANITA-lite had values in feet)
1537 
1538  } // end if anita-lite
1539 
1540 
1541 
1542  else if (bn1->WHICHPATH==6 || bn1->WHICHPATH==7 || bn1->WHICHPATH==8 || bn1->WHICHPATH==9) {
1543 
1544  bn1->flightdatachain->GetEvent(i*bn1->REDUCEBALLOONPOSITIONS);
1545 // the_time = bn1->realTime_flightdata_temp; //??!?
1546 
1547  theta_bn=(90+(double)bn1->flatitude)*RADDEG; //theta of the balloon wrt north pole
1548  lat=GetLat(theta_bn); // latitude
1549  phi_bn_temp=(-1*(double)bn1->flongitude+90.); //phi of the balloon, with 0 at +x and going counter clockwise looking down from the south pole
1550  if (phi_bn_temp<0) //correct phi_bn if it's negative
1551  phi_bn_temp+=360.;
1552  phi_bn_temp*=RADDEG;// turn it into radians
1553 
1554  altitude_bn=(double)bn1->faltitude; // for anita, altitude in is meters
1555 
1556  } // end if anita or anita-lite
1557  else if (bn1->WHICHPATH==1) // for picking random position along 80 deg south
1558  phi_bn_temp=dGetPhi(i); //get phi of the balloon just based on the balloon positions. Remember nballoonpositions runs from 0 to 179 here.
1559  // the output of dGetPhi is in radians and runs from -pi/2 to 3*pi/2 relative to
1560  else // includes bn1->WHICHPATH=0
1561  phi_bn_temp=phi_bn;
1562 
1563  // altitude_bn has already been set in SetDefaultBalloonPosition
1564  // same for theta_bn
1565  // lat set above
1566 
1567  lon=GetLon(phi_bn_temp); //get longitude for this phi position
1568  // lon goes from 0 (at -180 longitude) to 360 (at 180 longitude)
1569 
1570  // position of balloon
1571  surface_elevation = this->Surface(lon,lat); // distance from center of the earth to surface at this lon and lat
1572  r_bn_temp = Vector(sin(theta_bn)*cos(phi_bn_temp)*(surface_elevation+altitude_bn),
1573  sin(theta_bn)*sin(phi_bn_temp)*(surface_elevation+altitude_bn),
1574  cos(theta_bn)*(surface_elevation+altitude_bn)); // vector from center of the earth to balloon
1575 
1576  // cout << "MAXHORIZON is " << MAXHORIZON << "\n";
1577 
1578 
1579  if (ice_model==0) { // Crust 2.0
1580  for (int j=0;j<NLON;j++) { // loop over bins in longitude
1581  for (int k=0;k<ILAT_COASTLINE;k++) { // loop over bins in latitude
1582 
1583  // get position of each bin
1584  r_bin = Vector(sin(dGetTheta(k))*cos(dGetPhi(j))*(geoid[k]+surfacer[j][k]),
1585  sin(dGetTheta(k))*sin(dGetPhi(j))*(geoid[k]+surfacer[j][k]),
1586  cos(dGetTheta(k))*(geoid[k]+surfacer[j][k])); // vector from center of the earth to the surface of this bin
1587 
1588 
1589  if (!volume_found)
1590  volume += icethkarray[j][k]*1000*area[k]; // add this to the total volume of ice in antarctica
1591  if (!volume_found && icethkarray[j][k] > 0)
1592  total_area += area[k]; // add this to the total area of ice in antarctica
1593 
1594  // if the bin is within the maximum horizon of the balloon or if we don't care
1595  //r=(geoid[k]+surfacer[j][k]);
1596  //phi=dGetPhi(j);
1597  //theta=dGetTheta(k);
1598 
1599  // cout << "USEWEIGHTS is " << USEWEIGHTS << "\n";
1600  if ((settings1->USEPOSITIONWEIGHTS && r_bin.Distance(r_bn_temp)<bn1->MAXHORIZON)
1601  || !settings1->USEPOSITIONWEIGHTS) {
1602  // then put this latitude and longitude in vector
1603 
1604 
1605  ilat_inhorizon[i].push_back(k);
1606  ilon_inhorizon[i].push_back(j);
1607  // add up volume in horizon
1608 
1609 
1610  volume_inhorizon[i]+=icethkarray[j][k]*1000*area[k];
1611 
1612 
1613  // finding which bin in horizon has maximum volume
1614  if (icethkarray[j][k]*1000*area[k]>maxvol_inhorizon[i]) {
1615  maxvol_inhorizon[i]=icethkarray[j][k]*1000.*area[k];
1616  }
1617  } //end if (distance < 800 km)
1618 
1619 
1620  } //end for (k loop)
1621  } //end for (j loop)
1622 
1623  // cout << "i, volume_inhorizon are " << i << " " << volume_inhorizon[i] << "\n";
1624 
1625  // ifi the balloon is too close to the ice, it will think there aren't any
1626  // bins in the horizon, so force it the include the ones just below the balloon
1627  int ilat_bn,ilon_bn;
1628  GetILonILat(r_bn_temp,ilon_bn,ilat_bn); // find which longitude and latitude the balloon is above
1629 
1630  if (ilat_inhorizon[i].size()==0 || ilon_inhorizon[i].size()==0) {
1631  maxvol_inhorizon[i]=icethkarray[ilon_bn][ilat_bn]*1000.*area[ilat_bn]; // need to give it a maximum volume for a bin in horizon
1632  volume_inhorizon[i]=icethkarray[ilon_bn][ilat_bn]*1000.*area[ilat_bn]; // and a total volume for the horizon
1633  }
1634 
1635  if (ilat_inhorizon[i].size()==0) // for the ith balloon position, if it didn't find a latitude bin in horizon
1636  ilat_inhorizon[i].push_back(ilat_bn); // force it to be the one below the balloon
1637 
1638  if (ilon_inhorizon[i].size()==0) // for the ith balloon position, if it didn't find a longitude bin in horizon
1639  ilon_inhorizon[i].push_back(ilon_bn); // force it to be the one below the balloon
1640 
1641 
1642 
1643  } //end if (ice_model==0) Crust 2.0
1644 
1645  else if (ice_model==1 && !settings1->WRITE_FILE) { // for bedmap model
1646  fgets(line,200,bedmap_horizons);
1647  while(line[0] != 'X') {
1648  e_coord = atoi(strtok(line,","));
1649  n_coord = atoi(strtok(NULL,","));
1650  easting_inhorizon[i].push_back(e_coord);
1651  northing_inhorizon[i].push_back(n_coord);
1652  fgets(line,200,bedmap_horizons);
1653  } //while there are more eastings and northings
1654  strtok(line,",");
1655  volume_inhorizon[i] = atof(strtok(NULL,",")); // volume in the horizon
1656  maxvol_inhorizon[i] = atof(strtok(NULL,","));
1657 
1658  if (!volume_found) {
1659  total_area = atof(fgets(line,200,bedmap_horizons)); // total area on the continent
1660  volume = atof(fgets(line,200,bedmap_horizons)); // total volume on the continent
1661  } //if
1662  } //end if (ice_model==1) && !settings1->WRITE_FILE
1663 
1664  else if (ice_model==1 && settings1->WRITE_FILE) { //for BEDMAP model, look through all easting and northing coordinates in the groundbed map (our smallest). Output what we find to a file for later use.
1665 
1666  for (int n_coord=0;n_coord<nRows_ground;n_coord++) {
1667  for (int e_coord=0;e_coord<nCols_ground;e_coord++) {
1668 
1669  GroundENtoLonLat(e_coord,n_coord,lon,lat);
1670 
1671  theta = lat * RADDEG;
1672  phi=LongtoPhi_0is180thMeridian(lon);
1673 
1674  surface_elevation = this->Surface(lon,lat);
1675  local_ice_thickness = this->IceThickness(lon,lat);
1676 
1677  // get position of each bin
1678  r_bin = Vector(sin(theta)*cos(phi)*surface_elevation,
1679  sin(theta)*sin(phi)*surface_elevation,
1680  cos(theta)*surface_elevation);
1681 
1682  if (!volume_found)
1683  volume += local_ice_thickness*Area(lat);
1684  if (!volume_found && local_ice_thickness > 5)
1685  total_area += Area(lat);
1686  if ((settings1->USEPOSITIONWEIGHTS && r_bn_temp.Distance(r_bin)<bn1->MAXHORIZON) || !settings1->USEPOSITIONWEIGHTS) {
1687  fprintf(bedmap_horizons,"%i,%i,\n",e_coord,n_coord);
1688  // then put this latitude and longitude in vector
1689  easting_inhorizon[i].push_back(e_coord);
1690  northing_inhorizon[i].push_back(n_coord);
1691  // add up volume in horizon
1692 
1693  GroundENtoLonLat(e_coord,n_coord,lon,lat);
1694 
1695 
1696  volume_inhorizon[i]+=local_ice_thickness*Area(lat);
1697 
1698  // finding which bin in horizon has maximum volumey
1699  if (local_ice_thickness*Area(lat)>maxvol_inhorizon[i]) {
1700  maxvol_inhorizon[i]=local_ice_thickness*Area(lat);
1701  }
1702  } //end if (distance < 800 km & ice present)
1703  } //end for (e_coord loop)
1704  } //end for (n_coord loop)
1705 
1706  fprintf(bedmap_horizons,"X,%f,%f,\n",volume_inhorizon[i],maxvol_inhorizon[i]);
1707  if (!volume_found) {
1708  fprintf(bedmap_horizons,"%f\n",total_area);
1709  fprintf(bedmap_horizons,"%f\n",volume);
1710  } //if
1711 
1712 
1713  } //end if (ice_model==1) && settings1->WRITE_FILE
1714 
1715  if (!volume_found) {
1716  cout<<"Total surface area covered with ice (in m^2) is : "<<total_area<<endl;
1717  volume_found=1;
1718  } //if
1719 
1720  } //end loop over balloon positions
1721 
1722  if (bedmap_horizons)
1723  fclose(bedmap_horizons);
1724  // finding average volume in horizon over all balloon positions.
1725  volume_inhorizon_average=0;
1726 
1727  for (int i=0;i<NBALLOONPOSITIONS;i++) {
1728  volume_inhorizon_average+=volume_inhorizon[i];
1729 
1730  } //for
1731  volume_inhorizon_average/=(double)NBALLOONPOSITIONS;
1732 
1733  //cout << "Total volume of ice in Antarctica with this ice model (m^3): " << volume << "\n";
1734  //cout << "Average volume of ice within a horizon is " << volume_inhorizon_average << "\n";
1735 
1736  foutput << "Average volume of ice within a horizon is " << volume_inhorizon_average << "\n";
1737 
1738  foutput << "Average thickness of ice within horizon, averages over balloon positions " << volume_inhorizon_average/PI/pow(bn1->MAXHORIZON,2) << "\n";
1739 } //method CreateHorizons
1740 
1741 
1742 void IceModel::ReadIceThickness() {
1743  //Reads the BEDMAP ice thickness data. Assumes the file is in directory "data". Code by Ryan Nichol, added to Monte Carlo by Stephen Hoover
1744 
1745  ifstream IceThicknessFile((ICEMC_DATA_DIR+"/icethic.asc").c_str());
1746  if(!IceThicknessFile) {
1747  cerr << "Couldn't open: $ICEMC_DATA_DIR/icethic.asc" << endl;
1748  exit(1);
1749  }
1750 
1751  cout<<"Reading in BEDMAP data on ice thickness.\n";
1752 
1753  string tempBuf1;
1754  string tempBuf2;
1755  string tempBuf3;
1756  string tempBuf4;
1757  string tempBuf5;
1758  string tempBuf6;
1759  int temp1,temp2,temp3,temp4,temp5,temp6;
1760 
1761  IceThicknessFile >> tempBuf1 >> temp1 >> tempBuf2 >> temp2
1762  >> tempBuf3 >> temp3 >> tempBuf4 >> temp4
1763  >> tempBuf5 >> temp5 >> tempBuf6 >> temp6;
1764 
1765  if(tempBuf1 == string("ncols")) {
1766  nCols_ice=temp1;
1767  }
1768  if(tempBuf2 == string("nrows")) {
1769  nRows_ice=temp2;
1770  }
1771  if(tempBuf3 == string("xllcorner")) {
1772  xLowerLeft_ice=temp3;
1773  }
1774  if(tempBuf4 == string("yllcorner")) {
1775  yLowerLeft_ice=temp4;
1776  }
1777  if(tempBuf5 == string("cellsize")) {
1778  cellSize=temp5;
1779  }
1780  if(tempBuf6 == string("NODATA_value")) {
1781  NODATA=temp6;
1782  }
1783  //cout<<"nCols_ice, nRows_ice "<<nCols_ice<<" , "<<nRows_ice<<endl;
1784  //cout<<"xLL_ice, yLL_ice, cellsize "<<xLowerLeft_ice<<" , "<<yLowerLeft_ice<<" , "<<cellSize<<endl<<endl;
1785 
1786  assert(nRows_ice == 1000 && nCols_ice==1200);
1787 
1788  h_ice_thickness.SetBins(nCols_ice, xLowerLeft_ice, xLowerLeft_ice + nCols_ice*cellSize,
1789  nRows_ice, yLowerLeft_ice, yLowerLeft_ice+nRows_ice*cellSize);
1790 
1791  double theValue;
1792  volume=0.;
1793  ice_area=0.;
1794  max_icevol_perbin=0.;
1795  max_icethk_perbin=0.;
1796  double lon_tmp,lat_tmp;
1797  for(int rowNum=0;rowNum<nRows_ice;rowNum++) {
1798  for(int colNum=0;colNum<nCols_ice;colNum++) {
1799  IceENtoLonLat(colNum,rowNum,lon_tmp,lat_tmp);
1800  IceThicknessFile >> theValue;
1801  if(theValue==NODATA)
1802  theValue=0; //Set ice depth to 0 where we have no data.
1803 
1804  //note that the histogram has a backwards indexing on rows since it's defined in a different order
1805  h_ice_thickness.SetBinContent(1+colNum, nRows_ice-rowNum, theValue);
1806  volume+=theValue*Area(lat_tmp);
1807  if (theValue>0)
1808  ice_area+=Area(lat_tmp);
1809  if (theValue*Area(lat_tmp)>max_icevol_perbin)
1810  max_icevol_perbin=theValue*Area(lat_tmp);
1811  if (theValue>max_icethk_perbin)
1812  max_icethk_perbin=theValue;
1813  }//for
1814  }//for
1815 
1816  IceThicknessFile.close();
1817  return;
1818 } //method ReadIceThickness
1819 
1820 void IceModel::ReadGroundBed() {
1821  //Reads the BEDMAP data on the elevation of the ground beneath the ice. If there is water beneath the ice, the ground elevation is given the value 0. Assumes the file is in directory "data". Code by Ryan Nichol, added to Monte Carlo by Stephen Hoover
1822  ifstream GroundBedFile((ICEMC_DATA_DIR+"/groundbed.asc").c_str());
1823  if(!GroundBedFile) {
1824  cerr << "Couldn't open: ICEMC_DATA_DIR/groundbed.asc" << endl;
1825  exit(1);
1826  }
1827 
1828  cout<<"Reading in BEDMAP data on elevation of ground.\n";
1829 
1830  string tempBuf1;
1831  string tempBuf2;
1832  string tempBuf3;
1833  string tempBuf4;
1834  string tempBuf5;
1835  string tempBuf6;
1836  int temp1,temp2,temp3,temp4,temp5,temp6;
1837 
1838  GroundBedFile >> tempBuf1 >> temp1 >> tempBuf2 >> temp2
1839  >> tempBuf3 >> temp3 >> tempBuf4 >> temp4
1840  >> tempBuf5 >> temp5 >> tempBuf6 >> temp6;
1841 
1842  if(tempBuf1 == string("ncols")) {
1843  nCols_ground=temp1;
1844  }
1845  if(tempBuf2 == string("nrows")) {
1846  nRows_ground=temp2;
1847  }
1848  if(tempBuf3 == string("xllcorner")) {
1849  xLowerLeft_ground=temp3;
1850  }
1851  if(tempBuf4 == string("yllcorner")) {
1852  yLowerLeft_ground=temp4;
1853  }
1854  if(tempBuf5 == string("cellsize")) {
1855  cellSize=temp5;
1856  }
1857  if(tempBuf6 == string("NODATA_value")) {
1858  NODATA=temp6;
1859  }
1860  assert(nRows_ground == 869 && nCols_ground==1068);
1861 
1862  h_ground_elevation.SetBins(nCols_ground, xLowerLeft_ground, xLowerLeft_ground + nCols_ground*cellSize,
1863  nRows_ground, yLowerLeft_ground, yLowerLeft_ground + nRows_ground*cellSize);
1864 
1865  //cout<<"nCols_ground, nRows_ground "<<nCols_ground<<" , "<<nRows_ground<<endl;
1866  //cout<<"xLL_ground, yLL_ground, cellsize "<<xLowerLeft_ground<<" , "<<yLowerLeft_ground<<" , "<<cellSize<<endl<<endl;
1867 
1868  double theValue;
1869  for(int rowNum=0;rowNum<nRows_ground;rowNum++) {
1870  for(int colNum=0;colNum<nCols_ground;colNum++) {
1871  GroundBedFile >> theValue;
1872 
1873  if(theValue==NODATA)
1874  theValue=0; //Set elevation to 0 where we have no data.
1875  h_ground_elevation.SetBinContent(colNum+1,nRows_ground-rowNum, double(theValue));
1876  //if (theValue != -96 && theValue != 0)
1877  //cout<<"ground_elevation: "<<theValue<<endl;
1878  }//for
1879  }//for
1880 
1881  GroundBedFile.close();
1882  return;
1883 } //method ReadGroundBed
1884 
1885 void IceModel::ReadWaterDepth() {
1886  //Reads BEDMAP data on the depth of water beneath the ice. Where no water is present, the value 0 is entered. Assumes the file is in directory "data". Code by Ryan Nichol, added to Monte Carlo by Stephen Hoover
1887  ifstream WaterDepthFile((ICEMC_DATA_DIR+"/water.asc").c_str());
1888  if(!WaterDepthFile) {
1889  cerr << "Couldn't open: ICEMC_DATA_DIR/water.asc" << endl;
1890  exit(1);
1891  }
1892 
1893  cout<<"Reading in BEDMAP data on water depth.\n";
1894 
1895  string tempBuf1;
1896  string tempBuf2;
1897  string tempBuf3;
1898  string tempBuf4;
1899  string tempBuf5;
1900  string tempBuf6;
1901  int temp1,temp2,temp3,temp4,temp5,temp6;
1902 
1903  WaterDepthFile >> tempBuf1 >> temp1 >> tempBuf2 >> temp2
1904  >> tempBuf3 >> temp3 >> tempBuf4 >> temp4
1905  >> tempBuf5 >> temp5 >> tempBuf6 >> temp6;
1906 
1907  if(tempBuf1 == string("ncols")) {
1908  nCols_water=temp1;
1909  }
1910  if(tempBuf2 == string("nrows")) {
1911  nRows_water=temp2;
1912  }
1913  if(tempBuf3 == string("xllcorner")) {
1914  xLowerLeft_water=temp3;
1915  }
1916  if(tempBuf4 == string("yllcorner")) {
1917  yLowerLeft_water=temp4;
1918  }
1919  if(tempBuf5 == string("cellsize")) {
1920  cellSize=temp5;
1921  }
1922  if(tempBuf6 == string("NODATA_value")) {
1923  NODATA=temp6;
1924  }
1925 
1926  //cout<<"nCols_water, nRows_water "<<nCols_water<<" , "<<nRows_water<<endl;
1927  //cout<<"xLL_water, yLL_water, cellsize "<<xLowerLeft_water<<" , "<<yLowerLeft_water<<" , "<<cellSize<<endl<<endl;
1928 
1929  assert(nRows_water == 1000 && nCols_water==1200);
1930 
1931  h_water_depth.SetBins(nCols_water, xLowerLeft_water, xLowerLeft_water + nCols_water*cellSize,
1932  nRows_water, yLowerLeft_water, yLowerLeft_water+nRows_water*cellSize);
1933  double theValue;
1934  for(int rowNum=0;rowNum<nRows_water;rowNum++) {
1935  for(int colNum=0;colNum<nCols_water;colNum++) {
1936  WaterDepthFile >> theValue;
1937 
1938  if(theValue==NODATA)
1939  theValue=0; //Set depth to 0 where we have no data.
1940  h_water_depth.SetBinContent(1+colNum,nRows_water-rowNum, double(theValue));
1941  }//for
1942  }//for
1943 
1944  WaterDepthFile.close();
1945  return;
1946 } //method ReadWaterDepth
1947 
1948 
1949 
1950 
1951 //Methods related to the 2D cartesian surfaces
1952 //
1953 
1954 
1955 void IceModel::CreateCartesianTopAndBottom(int resolution, bool force)
1956 {
1957  TString fname;
1958 
1959  if (resolution == cart_resolution)
1960  {
1961  return ;
1962  }
1963 
1964  cart_resolution = resolution;
1965 
1966  if (cart_ice_file) delete cart_ice_file;
1967 
1968  fname.Form("%s/cartesian_icemodel_%d_%d.root", getenv("ICEMC_SRC_DIR")?: ".", ice_model , resolution);
1969 
1970  TDirectory * olddir = gDirectory;
1971 
1972  //check if it exists
1973  if (!force)
1974  {
1975  cart_ice_file = new TFile(fname);
1976 
1977  if (!cart_ice_file->IsOpen())
1978  {
1979  delete cart_ice_file;
1980  }
1981  else
1982  {
1983  cart_ice_top = (TH2*) cart_ice_file->Get("top");
1984  cart_ice_bot = (TH2*) cart_ice_file->Get("bot");
1985 
1986  if (!cart_ice_top || !cart_ice_bot)
1987  {
1988  delete cart_ice_file;
1989  }
1990 
1991  else
1992  {
1993  olddir->cd();
1994  return;
1995  }
1996  }
1997  }
1998 
1999  //if we got this far, we don't already have it
2000  cart_ice_file = new TFile(fname,"RECREATE");
2001  //the bounds will roughly be +/- REARTH /2,so we'll convert that to our resolution
2002 
2003  printf("Creating new cartesian ice file at %s...\n", cart_ice_file->GetName());
2004 
2005  double bound = ceil(6371000/2/resolution)*resolution;
2006  int nbins = (2*bound)/resolution;
2007 
2008  TString hname;
2009  hname.Form("icetop_%d_%d", ice_model, resolution);
2010  TString htitle;
2011  htitle.Form("Ice Top (model=%d, res=%d m)", ice_model, resolution);
2012  cart_ice_top = new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
2013 
2014  hname.Form("icebot_%d_%d", ice_model, resolution);
2015  htitle.Form("Ice Bottom (model=%d, res=%d m)", ice_model, resolution);
2016  cart_ice_bot= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
2017 
2018  // auxiliary hists
2019  hname.Form("ice_bot_r_%d_%d",ice_model, resolution);
2020  htitle.Form("Ice Bottom (r) (model=%d, res=%d m)", ice_model, resolution);
2021 
2022  TH2 * r_bot= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
2023 
2024  hname.Form("ice_top_r_%d_%d",ice_model, resolution);
2025  htitle.Form("Ice top (r) (model=%d, res=%d m)", ice_model, resolution);
2026 
2027  TH2 * r_top= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
2028 
2029  hname.Form("ice_bot_alt_%d_%d",ice_model, resolution);
2030  htitle.Form("Ice Bottom (alt) (model=%d, res=%d m)", ice_model, resolution);
2031 
2032  TH2 * alt_bot= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
2033 
2034  hname.Form("ice_top_alt_%d_%d",ice_model, resolution);
2035  htitle.Form("Ice top (alt) (model=%d, res=%d m)", ice_model, resolution);
2036 
2037  TH2 * alt_top= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
2038 
2039 
2040  for (int j = 1; j <= nbins; j++)
2041  {
2042  double y = cart_ice_top->GetYaxis()->GetBinCenter(j);
2043  for (int i = 1; i <= nbins; i++)
2044  {
2045  double x = cart_ice_top->GetXaxis()->GetBinCenter(i);
2046 
2047  double r2 = x*x+y*y;
2048  const double a = 6378137;
2049  const double a2 = a*a;
2050  if (r2 > a2) continue;
2051  const double b = 6356752.314245; ;
2052  const double b2 = b*b;
2053  double z_geoid = sqrt((1-r2/a2)*b2);
2054 
2055  Position p(Vector(x,y,z_geoid));
2056  double lon = p.Lon();
2057  double lat = p.Lat();
2058  double ice_depth = IceThickness(lon,lat);
2059  if (ice_depth)
2060  {
2061  double surface_above_geoid = SurfaceAboveGeoid(lon,lat);
2062  double geoid = Geoid(lat);
2063  double surface = surface_above_geoid+geoid;
2064 
2065  Position top(lon,lat,surface);
2066  Position bot(lon,lat,surface-ice_depth);
2067 
2068  cart_ice_top->SetBinContent(i,j,top.Z());
2069  cart_ice_bot->SetBinContent(i,j,bot.Z());
2070 
2071  r_top->SetBinContent(i,j,surface);
2072  r_bot->SetBinContent(i,j,surface-ice_depth);
2073 
2074  alt_top->SetBinContent(i,j,surface_above_geoid);
2075  alt_bot->SetBinContent(i,j,surface_above_geoid-ice_depth);
2076  }
2077  }
2078  }
2079 
2080  cart_ice_top->Write("top");
2081  cart_ice_bot->Write("bot");
2082  r_top->Write("r_top");
2083  r_bot->Write("r_bot");
2084  alt_top->Write("alt_top");
2085  alt_bot->Write("alt_bot");
2086  cart_ice_file->Flush();
2087  printf("...Done!\n");
2088  olddir->cd();
2089 
2090 }
2091 
2092 
2093 bool IceModel::CartesianIsInIce(double x,double y, double z)
2094 {
2095  const TH2 * htop = GetCartesianTop();
2096  if (z > cart_max_z) return false;
2097  if (z < cart_min_z) return false;
2098  if (x < htop->GetXaxis()->GetXmin()) return false;
2099  if (x > htop->GetXaxis()->GetXmax()) return false;
2100  if (y < htop->GetYaxis()->GetXmin()) return false;
2101  if (y > htop->GetYaxis()->GetXmax()) return false;
2102 
2103  double top = ((TH2*)htop)->Interpolate(x,y);
2104  if (!top) return false;
2105 
2106  return z < top && z > ((TH2*)GetCartesianBottom())->Interpolate(x,y);
2107 }
2108 
2109 int IceModel::GetIceIntersectionsCartesian(const Position & posnu, const Vector & nnu_in,
2110  std::vector<std::pair<double,double> > & intersection_points,
2111  double start_step, int map_resolution)
2112 {
2113  if (map_resolution!= cart_resolution) CreateCartesianTopAndBottom(map_resolution);
2114 
2115  if (cart_max_z == -1)
2116  {
2117  cart_max_z = GetCartesianTop()->GetMaximum();
2118 
2119  cart_min_z = cart_max_z;
2120 
2121  const TH2 * hbot = GetCartesianBottom();
2122 
2123  for (int j = 1; j <= hbot->GetNbinsY(); j++)
2124  {
2125  for (int i = 1; i <= hbot->GetNbinsX(); i++)
2126  {
2127  double val = hbot->GetBinContent(i,j);
2128  if (val > 0 && val < cart_min_z) cart_min_z = val;
2129  }
2130  }
2131  }
2132 
2133 
2134  std::vector<double> boundaries;
2135 
2136  //is our start point in the ice?
2137 
2138  bool start_in_ice = CartesianIsInIce(posnu.X(), posnu.Y(), posnu.Z());
2139 
2140  Vector nnu = nnu_in.Unit();
2141  //let's start at the position and go both ways
2142  for (int dir = -1; dir <=1 ; dir+=2)
2143  {
2144 
2145  Vector x = posnu;
2146  bool was_in_ice = start_in_ice;
2147 
2148  // go until we are way to far away from the Earth to matter
2149 
2150  double displacement = 0;
2151  bool jumped = false;
2152  bool just_jumped = false;
2153  while (true) //this is mean Earth radius + 5 km.
2154  {
2155 // printf("%g -> %g,%g,%g\n", displacement, x.X(),x.Y(), x.Z());
2156  displacement += start_step*dir;
2157  x = posnu + displacement*nnu;
2158  double mag2 = x.X()*x.X() + x.Y()*x.Y() + x.Z()*x.Z();
2159  // printf(" %g\n", sqrt(mag2));
2160  if (mag2 > (7000e3*7000e3))
2161  {
2162  printf("wtf: [%g,%g,%g], %g\n", x.X(), x.Y(), x.Z(), mag2);
2163 
2164  }
2165  if (mag2 > (6365e3*6365e3))
2166  {
2167  break;
2168  }
2169 
2170  //jump to the other side of the world if we dip down too much!
2171  if (mag2 < (6355.5e3*6355.5e3) && !jumped && !was_in_ice)
2172  {
2173  // printf("Trying to go to other side of the earth! start displacement: %g, mag: %g\n", displacement,sqrt(mag2));
2174  double ds[2];
2175  GeoidIntersection(x,dir*nnu, 0,0,-1000,ds);
2176  //now figure out which is on the opposite side of the Earth from where we are... since we're using our current position and direction it should be the positive one!
2177  displacement = (ds[0] > 0 ? ds[0] : ds[1])*dir;
2178  //printf("End displacement: %g\n", displacement);
2179  jumped = true;
2180  just_jumped = true;
2181  continue;
2182  }
2183 
2184  bool is_in_ice = CartesianIsInIce(x.X(),x.Y(),x.Z());
2185 
2186  //this is no bueno...we won't find the right boundary in this case!
2187  // let's back up 500 m from where we were at the start of this iteration
2188  if (just_jumped && is_in_ice)
2189  {
2190  displacement -= dir*(500+start_step);
2191  continue;
2192  }
2193 
2194  just_jumped = false;
2195 
2196  if (was_in_ice!=is_in_ice)
2197  {
2198  //binary search for the boundary to 1 m resolution
2199 
2200  Vector xsearch = x;
2201  double step = -start_step*dir/2;
2202  bool search_was_in_ice = is_in_ice;
2203  double boundary_displacement = displacement;
2204 
2205  while (fabs(step) > 1)
2206  {
2207  boundary_displacement+=step;
2208  xsearch = posnu + boundary_displacement * nnu;
2209  bool search_is_in_ice = CartesianIsInIce(xsearch.X(),xsearch.Y(),xsearch.Z());
2210 
2211  step*=0.5;
2212  if (search_is_in_ice!=search_was_in_ice) step*=-1;
2213  search_was_in_ice = search_is_in_ice;
2214  }
2215 
2216  //we found a boundary! (if there is more than one boundary within this segment... we probably picked a random one. Oh well.
2217  boundaries.push_back(boundary_displacement);
2218  }
2219  was_in_ice = is_in_ice;
2220  }
2221  }
2222 
2223  std::sort(boundaries.begin(), boundaries.end());
2224 
2225  if (boundaries.size() % 2)
2226  {
2227  fprintf(stderr,"Uh oh, have an odd number of boundaries (%lu) . That means there's a bug...\n", boundaries.size());
2228  for (unsigned i = 0; i < boundaries.size(); i++) printf(" %g ", boundaries[i]);
2229  printf("\n");
2230  assert(0);
2231  return -1;
2232  }
2233 
2234  for (unsigned i = 0; i < boundaries.size()/2; i++)
2235  {
2236  intersection_points.push_back(std::pair<double,double>(boundaries[2*i], boundaries[2*i+1]));
2237  }
2238 
2239  return boundaries.size()/2;
2240 }
2241 
int WHICHPATH
0=fixed balloon position,1=randomized,2=ANITA-lite GPS data,3=banana plot
Definition: balloon.hh:57
double Distance(const Position &second) const
Returns chord distance (direct distance between two vectors)
Definition: position.cc:37
double MAXHORIZON
pick the interaction within this distance from the balloon so that it is within the horizon ...
Definition: balloon.hh:78
int REDUCEBALLOONPOSITIONS
only take every 100th entry in the flight data file
Definition: balloon.hh:56
const char * ICEMC_SRC_DIR()
double altitude_bn_anitalite[100000]
same for altitude
Definition: balloon.hh:85
double BN_LATITUDE
balloon latitude for fixed balloon location
Definition: balloon.hh:89
double weight_nu
Weight for neutrino that survives to posnu.
Definition: Primaries.h:191
double Lat() const
Returns latitude, where the +z direction is at 0 latitude.
Definition: position.cc:47
Reads in and stores input settings for the run.
Definition: Settings.h:37
int NPOINTS
number of GPS positions we&#39;re picking from.
Definition: balloon.hh:80
double BN_ALTITUDE
pick balloon altitude
Definition: balloon.hh:59
This class is a 3-vector that represents a position on the Earth&#39;s surface.
Definition: position.hh:26
Stores everything about a particular neutrino interaction. Interaction.
Definition: Primaries.h:135
double longitude_bn_anitalite[100000]
same for longitude
Definition: balloon.hh:84
double total_kgm2
number of earth layers traversed
Definition: Primaries.h:206
Position r_in
position where neutrino enters the earth
Definition: Primaries.h:194
Shape of the earth, ice thicknesses, profiles of earth layers, densities, neutrino absorption...
Definition: earthmodel.hh:40
double weight_nu_prob
Weight for neutrino that survives to posnu and interacts in the ice.
Definition: Primaries.h:192
void PickAnyDirection()
Constructor.
Definition: Primaries.cc:277
double latitude_bn_anitalite[100000]
latitude at times along flightpath, equally distributed among gps data. This is filled with anita or ...
Definition: balloon.hh:83
Handles everything related to balloon positions, payload orientation over the course of a flight...
Definition: balloon.hh:30
Position nuexitice
place where neutrino would have left the ice
Definition: Primaries.h:197
This class represents a three-vector. Operators are overloaded to provide for the familiar operations...
Definition: vector.hh:27
Position r_enterice
position where neutrino enters the ice
Definition: Primaries.h:195
double Lon() const
Returns longitude.
Definition: position.cc:51
Ice thicknesses and water depth.
Definition: icemodel.hh:103
Vector nnu
direction of neutrino (+z in south pole direction)
Definition: Primaries.h:187