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 
376 static void sampleLocation( double len_int_kgm2,
377  std::vector<std::pair<double,double> > & ice_intersections,
378  Interaction * interaction1, const Vector & x, TRandom * rng )
379 
380 {
381  std::vector<double> cumulative_dists(ice_intersections.size());
382  interaction1->pathlength_inice = 0;
383  for (unsigned i = 0; i < ice_intersections.size(); i++)
384  {
385  double this_distance = ice_intersections[i].second - ice_intersections[i].first;
386  interaction1->pathlength_inice += this_distance;
387  cumulative_dists[i] = interaction1->pathlength_inice;
388  }
389 
390  //let's exponentially attenuate within the ice (ignoring any gaps in ice... those will be covered in principle by the attenuation weight)
391 
392  double distance = -1;
393  double L_ice=len_int_kgm2/Signal::RHOICE;
394  //If we have a very short path length in ice, it's ok to just assume it's uniform
395  if (interaction1->pathlength_inice / L_ice < 1e-3)
396  {
397  distance = rng->Rndm() * interaction1->pathlength_inice;
398  }
399  else
400  {
401  distance = -log(rng->Uniform(exp(-interaction1->pathlength_inice/L_ice),1))*L_ice;
402  }
403 
404 
405  //now figure out where that distance is
406 
407  unsigned which = 0;
408  for (which= 0; which < cumulative_dists.size(); which++)
409  {
410  if (distance < cumulative_dists[which])
411  break;
412  }
413 
414  Vector enterice = x + ice_intersections[which].first * interaction1->nnu;
415  Vector exitice = x + ice_intersections[which].second * interaction1->nnu;
416  interaction1->posnu = enterice + (which == 0 ? distance : distance-cumulative_dists[which-1]) * interaction1->nnu;
417  interaction1->nuexitice = exitice; // do we need to flip these?
418  interaction1->r_enterice = enterice;
419 }
420 
421 int IceModel::PickUnbiasedPointSourceNearBalloon(Interaction * interaction1, const Position * balloon_position,
422  double maxdist, double chord_step, double len_int_kgm2, const Vector * force_dir)
423 {
424 
425 #ifdef ICEMODEL_DEBUG_TREE
426  setupTree();
427  dbg->reset() ;
428  FillTreeOnReturn fill (debugfile, debugtree);
429 #endif
430 
431  // first pick the neutrino direction
432  if (!force_dir)
433  {
434  interaction1->PickAnyDirection();
435  }
436  else
437  {
438  interaction1->nnu = *force_dir;
439  }
440 
441  TRandom * rng = getRNG(RNG_INTERACTION_LOCATION);
442 
443 
444  //now we pick a point in the plane normal to the neutrino direction
445  // We will use the point directly below ANITA with an altitude at 0 km as a reference then consider offsets
446  // relative to that in that plane.
447 
448  //piece of shit!
449  Position ref(balloon_position->Lon()+180, balloon_position->Lat(), R_EARTH);
450 
451 
452  // For now, randomly pick an offset up to maxdist km away
453  // This can be optimized by precalculating the polygon
454  // visible from this angle or finding the bounds in some other way...
455  // Especially for nearly orthogonal events this will be far too big...
456  double x= rng->Uniform(-maxdist*1e3,maxdist*1e3);
457  double y= rng->Uniform(-maxdist*1e3,maxdist*1e3);
458  sample_x =x; sample_y = y;
459 
460  // get nnu as a TVector3 since I like those better
461  Vector nudir = interaction1->nnu.Unit(); //is probably already a unit vector?
462  Vector orth = nudir.Orthogonal();
463  Vector orth2 = nudir.Cross(orth);
464 
465  Vector p0 = ref + x*orth + y*orth2;
466 
467  //Where do we intersect the Earth?
468  Position int1;
469  Position int2;
470 
471  //check if we intersect with the (super) geoid.
472  int nintersect = GeoidIntersection(p0, nudir, &int1, &int2);
473 
474 
475 #ifdef ICEMODEL_DEBUG_TREE
476  dbg->balloon.SetXYZ(balloon_position->X(), balloon_position->Y(), balloon_position->Z());
477  dbg->ref.SetXYZ(ref.X(), ref.Y(), ref.Z());
478  dbg->nudir.SetXYZ(nudir.X(), nudir.Y(), nudir.Z());
479  dbg->nintersect = nintersect;
480  dbg->x = x;
481  dbg->y = y;
482  dbg->int1.SetXYZ(int1.X(), int1.Y(), int1.Z());
483  dbg->int2.SetXYZ(int2.X(), int2.Y(), int2.Z());
484 #endif
485 
486  if (nintersect == 0)
487  {
488 
489 #ifdef ICEMODEL_DEBUG_TREE
490  dbg->noway = true;
491 #endif
492  interaction1->neverseesice=1;
493  interaction1->noway = 1;
494  return 0;
495  }
496 
497 
498 
499 
500 
501  std::vector<std::pair<double,double> > ice_intersections;
502  int n_intersections = GetIceIntersectionsCartesian(int1, nudir, ice_intersections,chord_step);
503 
504  if (n_intersections == 0)
505  {
506  #ifdef ICEMODEL_DEBUG_TREE
507  dbg->noway = true;
508 #endif
509  interaction1->pathlength_inice = 0;
510  interaction1->neverseesice = 1;
511  return 0;
512  }
513 // printf("Hits the ice %d times!\n", n_intersections);
514 
515  sampleLocation(len_int_kgm2, ice_intersections, interaction1,int1, rng);
516 
517 
518 
519 #ifdef ICEMODEL_DEBUG_TREE
520  dbg->exitice.SetXYZ(exitice.X(),exitice.Y(),exitice.Z());
521  dbg->enterice.SetXYZ(enterice.X(),enterice.Y(),enterice.Z());
522  dbg->nupos.SetXYZ(interaction1->posnu.X(),interaction1->posnu.Y(),interaction1->posnu.Z());
523 #endif
524 
525 
526 
527  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)>0) {
528  interaction1->toohigh=1;
529  return 0;
530  }
531  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)+IceThickness(interaction1->posnu)<0) {
532  interaction1->toolow=1;
533  return 0;
534  }
535 
536 
537  return 1;
538 }
539 
540 
541 
542 int IceModel::PickUnbiased(Interaction *interaction1, double len_int_kgm2, double & position_weight, double chord_step, Vector * force_dir) {
543 
544  TRandom * rng = getRNG(RNG_INTERACTION_LOCATION);
545  if (!force_dir)
546  {
547  interaction1->PickAnyDirection(); // first pick the neutrino direction
548  }
549  else
550  {
551  interaction1->nnu = *force_dir;
552  }
553 
554 
555  //now we pick a point somewhere on the surface of the superellipsoid.
556  //up to the coastline
557  //TODO, can pick closer to payload but hard to do while keeping ellipsoidal geometry...
558  //instead, will just reject points far away...
559 
560  double sinth = rng->Uniform(0, sin(COASTLINE*RADDEG));
561  double phi = rng->Uniform(0,2*TMath::Pi());
562 
563  double costh = sqrt(1-sinth*sinth);
564 
565  const double RMAX = GEOID_MAX + 5500;
566  const double RMIN = GEOID_MIN + 5500;
567  Vector p0(RMAX * cos(phi) * sinth, RMAX * sin(phi) * sinth, RMIN*costh);
568 
569 
570  // The position weight is (maybe) the dot product of the position with the neutrino direction
571  // this is actually the inverse weight
572  position_weight = 1./fabs(p0.Unit() * interaction1->nnu);
573 
574  //but actually, we can be double counting if the other superellipsoid intesrection is above coastline because
575  //we can sample the same trajectory twice. So let's divide position_weight by two if that is indeed the case.
576 
577  Position ints[2];
578  GeoidIntersection(p0, interaction1->nnu, &ints[0],&ints[2]);
579 
580  int nabovecoastline = 0;
581  for (int i =0; i < 2; i++)
582  {
583  if (ints[i].Lat() < COASTLINE) nabovecoastline++;
584  }
585  assert(nabovecoastline>0);
586  position_weight /= nabovecoastline;
587  interaction1->r_enterice = p0;
588 
589  //now let's set the ice intersactions
590  std::vector<std::pair<double,double> > ice_intersections;
591  int n_intersections = GetIceIntersectionsCartesian(p0, interaction1->nnu, ice_intersections,chord_step);
592 
593 
594  if (!n_intersections)
595  {
596  interaction1->noway = 1;
597  interaction1->neverseesice=1;
598  interaction1->pathlength_inice = 0;
599  return 0;
600  }
601 
602  sampleLocation(len_int_kgm2, ice_intersections, interaction1,p0, rng);
603 
604 
605  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)>0) {
606  interaction1->toohigh=1;
607  //cout << "inu, toohigh is " << inu << " " << interaction1->toohigh << "\n";
608  return 0;
609  }
610  if (interaction1->posnu.Mag()-Surface(interaction1->posnu)+IceThickness(interaction1->posnu)<0) {
611  interaction1->toolow=1;
612  //cout << "inu, toolow is " << inu << " " << interaction1->toolow << "\n";
613  return 0;
614  }
615 
616  return 1;
617 
618 }
619 
620 Vector IceModel::GetSurfaceNormal(const Position &r_out) {
621  Vector n_surf = r_out.Unit();
622  if (FLATSURFACE)
623  return n_surf;
624 
625  if (ice_model==0) {
626  double theta=r_out.Theta();
627 
628  int ilon,ilat;
629  GetILonILat(r_out,ilon,ilat);
630 
631  int ilon_previous=ilon-1;
632  if (ilon_previous<0)
633  ilon_previous=NLON-1;
634 
635  int ilon_next=ilon+1;
636  if (ilon_next==NLON)
637  ilon_next=0;
638 
639  double r=(geoid[ilat]+surfacer[ilon][ilat])*sin(theta);
640 
641  double slope_phi=(surfacer[ilon_next][ilat]-surfacer[ilon_previous][ilat])/(r*2*phistep);
642 
643  int ilat_previous=ilat-1;
644  if (ilat_previous<0)
645  ilat_previous=0;
646 
647  int ilat_next=ilat+1;
648  if (ilat_next==NLAT)
649  ilat_next=NLAT-1;
650 
651  double slope_costheta=(surfacer[ilon][ilat_next]-surfacer[ilon][ilat_previous])/((geoid[ilat]+surfacer[ilon][ilat])*2*thetastep);
652 
653  // first rotate n_surf according to tilt in costheta and position on continent - rotate around the y axis.
654  double angle=atan(slope_costheta);
655 
656  n_surf = n_surf.RotateY(angle);
657 
658  // now rotate n_surf according to tilt in phi - rotate around the z axis.
659  angle=atan(slope_phi);
660 
661  n_surf = n_surf.RotateZ(angle);
662  } //end if(Crust 2.0)
663  else if (ice_model==1) {
664  double dist_to_check = 7500; //check elevations at this distance north, south, east and west of event
665  double lon,lat;
666  double lon_prev,lon_next;
667  double lat_prev,lat_next;
668  lon = r_out.Lon();
669  lat = r_out.Lat(); //longitude and latitude of interaction
670  double local_surface_elevation = Surface(lon,lat);
671 
672  lat_next = lat + dist_to_check * (180 / (local_surface_elevation * PI)); //the latitude 7.5 km south of the interaction
673  lat_prev = lat - dist_to_check * (180 / (local_surface_elevation * PI)); //the latitude 7.5 km north of the interaction
674 
675  lon_next = lon + dist_to_check * (180 / (sin(lat*RADDEG) * local_surface_elevation * PI));
676  lon_prev = lon - dist_to_check * (180 / (sin(lat*RADDEG) * local_surface_elevation * PI));
677 
678  if (lat_next > 90) {
679  //cout<<"lat_next is > 90"<<endl;
680  lat_next = 90 - (lat_next - 90); //if we went past the pole, set coordinates for the other side
681  lon_next += 180;
682  lon_prev += 180;
683  } //end if
684  //cout<<"lon, lat: "<<lon<<" , "<<lat<<endl;
685  //correct any out of range longitudes
686  if (lon_next > 360) {
687  //cout<<"lon_next > 360\n";
688  lon_next -= 360;
689  }
690  else if (lon_next < 0) {
691  //cout<<"lon_next < 0\n";
692  lon_next += 360;
693  }
694  if (lon_prev > 360) {
695  //cout<<"lon_prev > 360\n";
696  lon_prev -= 360;
697  }
698  else if (lon_prev < 0) {
699  //cout << "lon_prev < 0";
700  lon_prev += 360;
701  }
702 
703  double slope_phi=(SurfaceAboveGeoid(lon_next,lat)-SurfaceAboveGeoid(lon_prev,lat))/(2*dist_to_check);
704 
705  double slope_costheta=(SurfaceAboveGeoid(lon,lat_next)-SurfaceAboveGeoid(lon,lat_prev))/(2*dist_to_check);
706 
707  // first rotate n_surf according to tilt in costheta - rotate around the y axis.
708  double angle=atan(slope_costheta);
709 
710  n_surf = n_surf.RotateY(angle);
711 
712  // now rotate n_surf according to tilt in phi - rotate around the z axis.
713  angle=atan(slope_phi);
714 
715  n_surf = n_surf.RotateZ(angle);
716  } //end if(BEDMAP)
717 
718  return n_surf;
719 
720 } //method GetSurfaceNormal
721 
722 int IceModel::WhereDoesItEnterIce(const Position &posnu,
723  const Vector &nnu,
724  double stepsize,
725  Position &r_enterice) {
726  // now get exit point...
727  // see my geometry notes.
728  // parameterize the neutrino trajectory and just see where it
729  // crosses the earth radius.
730 
731  // Position r_enterice;
732  double distance=0;
733  int left_edge=0;
734  Position x = posnu;
735  double x2;
736 
737  Position x_previous = posnu;
738 
739  double x_previous2= x_previous * x_previous;
740  x2=x_previous2;
741 
742  double lon = x.Lon(),lat = x.Lat();
743  double lon_old = lon,lat_old = lat;
744  double local_surface = Surface(lon,lat);
745  double rock_previous2= pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
746  double surface_previous2=pow(local_surface,2);
747 
748  double rock2=rock_previous2;
749  double surface2=surface_previous2;
750  int foundit=0; // keeps track of whether you found an ice entrance point
751 
752  // cout << "lon, lat are " << posnu.Lon() << " " << posnu.Lat() << "\n";
753  //cout << "x2 at start is " << x2 << "\n";
754  while (distance<2*local_surface+1000) {
755 
756  distance+=stepsize;
757 
758  x -= stepsize*nnu;
759  x2=x*x;
760  //cout << "x2 is " << x2 << "\n";
761  lon = x.Lon();
762  lat = x.Lat();
763 
764  double ice_thickness=IceThickness(lon,lat);
765  if (lon!=lon_old || lat!=lat_old) {
766  local_surface = Surface(lon,lat);
767 
768  //if (lat>COASTLINE)
769  //left_edge=1;
770 
771  rock2=pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
772  surface2=pow(local_surface,2);
773 
774  if (ice_model==0) {
775  if ((int)(lat)==COASTLINE && rock_previous2 < x2 && surface2 > x2)
776  left_edge=1;
777  } //if (Crust 2.0)
778  } //if (neutrino has stepped into new lon/lat bin)
779 
780  if ((((x_previous2>rock_previous2 && x2<rock2) // crosses rock boundary from above
781  || (x_previous2<surface_previous2 && x2>surface2)) && ice_thickness>0 && lat<COASTLINE) // crosses surface boundary from below
782  || left_edge) {
783  // cout << "lat, COASTLINE, left_edge is " << lat << " " << COASTLINE<< " " << left_edge << "\n";
784  //cout << "x_previous2, surface_previous, x2, surface2 are " << x_previous2 << " " << surface_previous2 << " " << x2 << " " << surface2 << "\n";
785  r_enterice = x;
786  // this gets you out of the loop.
787  //continue;
788  distance=3*Geoid(lat);
789  foundit=1;
790  //cout << "foundit is " << foundit << "\n";
791  //cout << "r_enterice is ";r_enterice.Print();
792  //continue;
793  } //if
794 
795  x_previous = x;
796  x_previous2 = x2;
797  //cout << "x_previous, x_previous2 " << x << " " << x2 << "\n";
798 
799  if (lon!=lon_old || lat!=lat_old) {
800  rock_previous2 = rock2;
801  surface_previous2 = surface2;
802  lat_old = lat;
803  lon_old = lon;
804  } //if
805 
806  } //while
807 
808  return foundit;
809 }//WhereDoesItEnterIce
810 
811 int IceModel::WhereDoesItExitIce(const Position &posnu,
812  const Vector &nnu,
813  double stepsize,
814  Position &r_enterice) {
815  // now get exit point...
816  // see my geometry notes.
817  // parameterize the neutrino trajectory and just see where it
818  // crosses the earth radius.
819 
820  // Position r_enterice;
821  double distance=0;
822  int left_edge=0;
823  Position x = posnu;
824  double x2;
825 
826  Position x_previous = posnu;
827 
828  double x_previous2= x_previous * x_previous;
829  x2=x_previous2;
830 
831  double lon = x.Lon(),lat = x.Lat();
832  double lon_old = lon,lat_old = lat;
833  double local_surface = Surface(lon,lat);
834  double rock_previous2= pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
835  double surface_previous2=pow(local_surface,2);
836 
837  double rock2=rock_previous2;
838  double surface2=surface_previous2;
839  int foundit=0; // keeps track of whether you found an ice entrance point
840 
841 
842 
843  // cout << "lon, lat are " << posnu.Lon() << " " << posnu.Lat() << "\n";
844  //cout << "x2 at start is " << x2 << "\n";
845  int nsteps=0;
846  while (distance<2*local_surface+1000) {
847  //cout << "another step.\n";
848  distance+=stepsize;
849  nsteps++;
850  // cout << "inu, nsteps is " << inu << " " << nsteps << "\n";
851  x -= stepsize*nnu;
852  x2=x*x;
853  //cout << "x2 is " << x2 << "\n";
854  lon = x.Lon();
855  lat = x.Lat();
856 
857  double ice_thickness=IceThickness(lon,lat);
858  if (lon!=lon_old || lat!=lat_old) {
859  local_surface = Surface(lon,lat);
860 
861  //if (lat>COASTLINE)
862  //left_edge=1;
863 
864  rock2=pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
865  surface2=pow(local_surface,2);
866 
867  if (ice_model==0) {
868  if ((int)(lat)==COASTLINE && rock_previous2 < x2 && surface2 > x2)
869  left_edge=1;
870  } //if (Crust 2.0)
871  } //if (neutrino has stepped into new lon/lat bin)
872 
873  if ((((x_previous2<rock_previous2 && x2>rock2) // crosses rock boundary from above
874  || (x_previous2>surface_previous2 && x2<surface2)) && ice_thickness>0 && lat<COASTLINE) // crosses surface boundary from above
875  || left_edge) {
876  // cout << "lat, COASTLINE, left_edge is " << lat << " " << COASTLINE<< " " << left_edge << "\n";
877  //cout << "x_previous2, surface_previous, x2, surface2 are " << x_previous2 << " " << surface_previous2 << " " << x2 << " " << surface2 << "\n";
878  r_enterice = x;
879  // this gets you out of the loop.
880  //continue;
881  distance=3*Geoid(lat);
882  foundit=1;
883  //cout << "foundit is " << foundit << "\n";
884  //continue;
885  } //if
886 
887  x_previous = x;
888  x_previous2 = x2;
889  //cout << "x_previous, x_previous2 " << x << " " << x2 << "\n";
890 
891  if (lon!=lon_old || lat!=lat_old) {
892  rock_previous2 = rock2;
893  surface_previous2 = surface2;
894  lat_old = lat;
895  lon_old = lon;
896  } //if
897 
898  } //while
899 
900  return foundit;
901 }//WhereDoesItExitIce
902 int IceModel::WhereDoesItExitIceForward(const Position &posnu,
903  const Vector &nnu,
904  double stepsize,
905  Position &r_enterice) {
906  // now get exit point...
907  // see my geometry notes.
908  // parameterize the neutrino trajectory and just see where it
909  // crosses the earth radius.
910 
911  // Position r_enterice;
912  double distance=0;
913  int left_edge=0;
914  Position x = posnu;
915  double x2;
916 
917  Position x_previous = posnu;
918 
919  double x_previous2= x_previous * x_previous;
920  x2=x_previous2;
921 
922  double lon = x.Lon(),lat = x.Lat();
923  double lon_old = lon,lat_old = lat;
924  double local_surface = Surface(lon,lat);
925  double rock_previous2= pow((local_surface - IceThickness(lon,lat) - WaterDepth(lon,lat)),2);
926  double surface_previous2=pow(local_surface,2);
927 
928  double rock2=rock_previous2;
929  double surface2=surface_previous2;
930  int foundit=0; // keeps track of whether you found an ice entrance point
931 
932  // cout << "lon, lat are " << posnu.Lon() << " " << posnu.Lat() << "\n";
933  //cout << "x2 at start is " << x2 << "\n";
934  while (distance<2*local_surface+1000) {
935 
936  distance+=stepsize;
937 
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) // enters rock boundary from above
961  || (x_previous2>surface_previous2 && x2<surface2)) && ice_thickness>0 && lat<COASTLINE) // crosses surface boundary from below
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 }//WhereDoesItExitIceForward
989 
990 
991 double IceModel::IceThickness(double lon, double lat) {
992  //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.
993  double ice_thickness=0;
994  //cout << "ice_model is " << ice_model << "\n";
995  //cout << "icethkarray is " << icethkarray[(int)(lon/2)][(int)(lat/2)]*1000. << "\n";
996  if (ice_model==1) {
997  double E=0;
998  double N=0;
999  LonLattoEN(lon,lat,E,N);
1000  if (inHistBounds(E,N,h_ice_thickness))
1001  {
1002  ice_thickness = h_ice_thickness.Interpolate(E,N); //if this region has BEDMAP data, use it.
1003  }
1004  else
1005  {
1006  ice_thickness = icethkarray[(int)(lon/2)][(int)(lat/2)]*1000.; //if the location given is not covered by BEDMAP, use Crust 2.0 data
1007  }
1008  } //BEDMAP ice thickness
1009  else if (ice_model==0) {
1010  ice_thickness = icethkarray[(int)(lon/2)][(int)(lat/2)]*1000.;
1011  //cout << "ilon, ilat are " << (int)(lon/2) << " " << (int)(lat/2) << "\n";
1012  } //Crust 2.0 ice thickness
1013 
1014  return ice_thickness;
1015 } //method IceThickness
1016 double IceModel::IceThickness(const Position &pos) {
1017  //This method returns the thickness of the ice in meters at a location under a given position vector. Code by Stephen Hoover.
1018 
1019  return IceThickness(pos.Lon(),pos.Lat());
1020 } //method IceThickness(position)
1021 
1022 double IceModel::SurfaceAboveGeoid(double lon, double lat) {
1023  //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.
1024  // lon must be 0 to 360
1025  double surface=0;
1026 
1027  if (ice_model==1) {
1028  double E, N ;
1029  LonLattoEN(lon,lat,E,N);
1030 
1031  if (inHistBounds(E,N, h_ground_elevation))
1032  {
1033  surface = h_ground_elevation.Interpolate(E,N) + h_ice_thickness.Interpolate(E,N) + h_water_depth.Interpolate(E,N);
1034  }
1035  else
1036  {
1037  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.
1038  }
1039  } //Elevation of surface above geoid according to BEDMAP
1040  else if (ice_model==0) {
1041  surface = surfacer[(int)(lon/2)][(int)(lat/2)];
1042  } //Elevation of surface above geoid according to Crust 2.0
1043 
1044  return surface;
1045 } //method SurfaceAboveGeoid
1046 
1047 double IceModel::SurfaceAboveGeoid(const Position &pos) {
1048  //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.
1049 
1050  return SurfaceAboveGeoid(pos.Lon(),pos.Lat());
1051 } //method SurfaceAboveGeoid(position)
1052 
1053 double IceModel::Surface(double lon,double lat) {
1054  return (SurfaceAboveGeoid(lon,lat) + Geoid(lat)); // distance from center of the earth to surface
1055 } //Surface
1056 
1057 double IceModel::Surface(const Position& pos) {
1058  return Surface(pos.Lon(),pos.Lat());
1059 } //Surface
1060 
1061 double IceModel::WaterDepth(double lon, double lat) {
1062  //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.
1063  double water_depth_value=0;
1064 
1065  if (ice_model==0) {
1066  water_depth_value = waterthkarray[(int)(lon/2)][(int)(lat/2)]*1000;
1067  } //if(Crust 2.0)
1068  else if (ice_model==1) {
1069  double E, N;
1070  LonLattoEN(lon,lat,E,N);
1071  if (inHistBounds(E,N,h_water_depth))
1072  {
1073  water_depth_value = h_water_depth.Interpolate(E,N);
1074  }
1075  else
1076  water_depth_value = waterthkarray[(int)(lon/2)][(int)(lat/2)]*1000;
1077  } //else if(BEDMAP)
1078 
1079  return water_depth_value;
1080 } //method WaterDepth(longitude, latitude)
1081 double IceModel::WaterDepth(const Position &pos) {
1082  //This method returns the depth of water beneath ice shelves in meters, at a location specified by a position vector. Code by Stephen Hoover.
1083 
1084  return WaterDepth(pos.Lon(),pos.Lat());
1085 } //method WaterDepth(position)
1086 
1087 int IceModel::IceOnWater(const Position &pos) {
1088  if(IceThickness(pos)>0.&&WaterDepth(pos)>0.)
1089  return 1;
1090  else return 0;
1091 
1092 }
1093 int IceModel::RossIceShelf(const Position &pos) {
1094  int ilon,ilat;
1095 
1096  GetILonILat(pos,ilon,ilat);
1097 
1098  if ((ilat==2 && ilon>=5 && ilon<=14) ||
1099  (ilat==3 && (ilon>=168 || ilon<=14)) ||
1100  (ilat==4 && (ilon>=168 || ilon<=13)) ||
1101  (ilat==5 && (ilon>=168 || ilon<=14)))
1102  return 1;
1103  else
1104  return 0;
1105 }//RossIceShelf
1106 
1107 int IceModel::RossExcept(const Position &pos) {
1108  int ilon,ilat;
1109  GetILonILat(pos,ilon,ilat);
1110  if(ilon<=178&&ilon>=174&&ilat>=4&&ilat<=5)
1111  return 1;
1112  else
1113  return 0;
1114 }
1115 
1116 
1117 int IceModel::RonneIceShelf(const Position &pos) {
1118  int ilon,ilat;
1119 
1120  GetILonILat(pos,ilon,ilat);
1121 
1122  if ((ilat==4 && ilon>=52 && ilon<=74) ||
1123  (ilat==5 && ilon>=50 && ilon<=71) ||
1124  (ilat==6 && ilon>=55 && ilon<=64))
1125  return 1;
1126  else
1127  return 0;
1128 
1129 }//RonneIceShelf
1130 
1131 int IceModel::WestLand(const Position &pos) {
1132  double lon = pos.Lon() , lat = pos.Lat();
1133 
1134  if((lat>=4&&lat<=26)&&((lon>=0&&lon<=180)||lon>=336))
1135  return 1;
1136  else return 0;
1137 
1138 }//WestLand
1139 
1140 double IceModel::GetBalloonPositionWeight(int ibnpos) {
1141  // cout << "ibnpos, volume_inhorizon, volume are " << ibnpos << " " << volume_inhorizon[ibnpos] << " " << volume << "\n";
1142  if (volume_inhorizon[ibnpos]==0) {
1143  return 0; //we will be skipped anyway
1144  }
1145 
1146  return volume/volume_inhorizon[ibnpos];
1147 } //GetBalloonPositionWeight
1148 
1149 int IceModel::OutsideAntarctica(const Position &pos) {
1150  return (pos.Lat() >= COASTLINE);
1151 } //OutsideAntarctica(Position)
1152 
1153 int IceModel::OutsideAntarctica(double lat) {
1154  return (lat >= COASTLINE);
1155 } //OutsideAntarctica(double lat)
1156 
1157 int IceModel::AcceptableRfexit(const Vector &nsurf_rfexit,const Position &rfexit,const Vector &n_exit2rx) {
1158 
1159  //Make sure there's actually ice where the ray leaves
1160  if (rfexit.Lat()>COASTLINE || IceThickness(rfexit)<0.0001) {
1161  cout << "latitude is " << rfexit.Lat() << " compared to COASTLINE at " << COASTLINE << "\n";
1162  cout << "ice thickness is " << IceThickness(rfexit) << "\n";
1163  return 0;
1164 
1165  } //if
1166 
1167  if (nsurf_rfexit*n_exit2rx<0) {
1168  //cout << "dot product is " << nsurf_rfexit*n_exit2rx << "\n";
1169  return 0;
1170  } //if
1171 
1172  return 1;
1173 } //AcceptableRfexit
1174 
1175 double IceModel::GetN(double altitude) {
1176  // these are Peter's fit parameters
1177  double a1=0.463251;
1178  double b1=0.0140157;
1179  double n=0;
1180 
1181  if (altitude < FIRNDEPTH)
1182  n=Signal::NICE;
1183  else if (altitude >= FIRNDEPTH && altitude <=0 && DEPTH_DEPENDENT_N)
1184  // N_DEPTH=NFIRN-(4.6198+13.62*(altitude_int/1000.))*
1185  //(altitude_int/1000.); // Besson's equation for n(z)
1186  n=NFIRN+a1*(1.0-exp(b1*altitude)); // Peter's equation for n(z)
1187  else if (altitude > 0)
1188  cout<<"Error! N requested for position in air!\n";
1189  else if (!DEPTH_DEPENDENT_N)
1190  n = NFIRN;
1191 
1192  return n;
1193 } //GetN(altitude)
1194 
1195 double IceModel::GetN(const Position &pos) {
1196  return GetN(pos.Mag() - Surface(pos.Lon(),pos.Lat()));
1197 } //GetN(Position)
1198 
1199 double IceModel::EffectiveAttenuationLength(Settings *settings1,const Position &pos,const int &whichray) {
1200  double localmaxdepth = IceThickness(pos);
1201  double depth = Surface(pos) - pos.Mag();
1202  //cout << "depth is " << depth << "\n";
1203  int depth_index=0;
1204  double attenuation_length=0.0;
1205 
1206  if(WestLand(pos) && !CONSTANTICETHICKNESS)
1207  {
1208  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.
1209  if(RossIceShelf(pos) || RonneIceShelf(pos))
1210  {
1211  if(whichray==0)
1212  attenuation_length=l_shelfup[depth_index];
1213  else if(whichray==1)
1214  attenuation_length=l_shelfdown[depth_index];
1215  else
1216  cerr << " wrong attenuation length " <<endl;
1217 
1218  //for sanity check
1219  if((depth_index+0.5)!=d_shelfup[depth_index])
1220  {
1221  cerr << "the index of the array l_iceshelfup is wrong!" << endl;
1222  exit(1);
1223  }
1224  }
1225  else //in ice sheet of westland
1226  {
1227  if(whichray==0)
1228  attenuation_length=l_westlandup[depth_index];
1229  else if(whichray==1)
1230  attenuation_length=l_westlanddown[depth_index];
1231  else
1232  cerr << " wrong attenuation length " <<endl;
1233  }
1234 
1235  if(settings1->MOOREBAY)//if use Moore's Bay measured data for the west land
1236  attenuation_length*=1.717557; //about 450 m (field attenuation length) for one whole way when assuming -3dB for the power loss at the bottom
1237  }
1238  else //in east antarctica or constant ice thickness
1239  {
1240 
1241  depth_index =int(depth*(2809.9/localmaxdepth));
1242 
1243 
1244  if(whichray==0)
1245  attenuation_length =l_sheetup[depth_index];
1246  else if(whichray==1)
1247  attenuation_length =l_sheetdown[depth_index];
1248  else
1249  cerr << " wrong attenuation length " <<endl;
1250  } //else
1251 
1252  return attenuation_length;
1253 } //EffectiveAttenuationLengthUp
1254 
1255 double IceModel::Area(double latitude) {
1256  //Returns the area of one square of the BEDMAP data at a given latitude.
1257  double lat_rad = (90 - latitude) * RADDEG;
1258 
1259  return (pow(cellSize* ((1 + sin(71*RADDEG)) / (1 + sin(lat_rad))),2));
1260 } //method Area
1261 
1262 void IceModel::LonLattoEN(double lon, double lat, double& E, double& N) {
1263  //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.
1264 
1265 
1266  double lon_rad = (lon - 180) * RADDEG; //convert to radians, and shift origin to conventional spot
1267  double lat_rad = (90 - lat) * RADDEG;
1268 
1269  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);
1270 
1271  E = bedmap_R * sin(lon_rad);
1272  N = bedmap_R * cos(lon_rad);
1273  return;
1274 } //method LonLattoEN
1275 
1276 
1277 void IceModel::ENtoLonLat(int e_coord, int n_coord, double xLowerLeft, double yLowerLeft, double& lon, double& lat) {
1278  //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.
1279 
1280  double isometric_lat=0;
1281  double easting = xLowerLeft+(cellSize*(e_coord+0.5)); //Add offset of 0.5 to get coordinates of middle of cell instead of edges.
1282  double northing = -(yLowerLeft+(cellSize*(n_coord+0.5)));
1283 
1284  // cout << "easting, northing are " << easting << " " << northing << "\n";
1285 
1286  //first set longitude
1287 
1288  if (northing!=0)
1289  lon = atan(easting/northing);
1290  else
1291  lon = 90*RADDEG;
1292 
1293  // this puts lon between -pi and pi
1294  if (easting > 0 && lon < 0) //adjust sign of longitude
1295  lon += PI;
1296  else if (easting < 0 && lon > 0)
1297  lon -= PI;
1298  else if (easting == 0 && northing < 0)
1299  lon += PI;
1300 
1301  // now find latitude
1302 
1303  if (easting != 0)
1304  bedmap_R = fabs(easting/sin(lon));
1305  else if (easting == 0 && northing != 0)
1306  bedmap_R = fabs(northing);
1307  else {
1308  lat = 0; //at the pole, set lat=0 degrees
1309  lon = lon*DEGRAD; // now put lon between 180 and 180 (only at pol)
1310  return;
1311  } //else
1312 
1313  isometric_lat = (PI/2) - 2*atan(bedmap_R/(scale_factor*bedmap_c_0));
1314 
1315  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);
1316 
1317  lon = lon * DEGRAD + 180; //convert to degrees, shift 0 to line up with bin 0 of Crust 2.0
1318  lat = 90 - lat*DEGRAD; //convert to degrees, with 0 degrees at the south pole
1319 
1320  // if (lon>160 && lon<165)
1321  //cout << "e_coord, n_coord, easting, northing, lon are " << e_coord << " " << n_coord << " " << easting << " " << northing << " " << lon << "\n";
1322  return;
1323 
1324 } //method ENtoLonLat
1325 
1326 void IceModel::IceENtoLonLat(int e, int n, double& lon, double& lat) {
1327  //Converts indicies of the BEDMAP ice thickness matrix into longitude and latitude. Code by Stephen Hoover.
1328  // cout << "I'm inside IceENtoLonLat.\n";
1329  ENtoLonLat(e,n,xLowerLeft_ice,yLowerLeft_ice,lon,lat);
1330 }//IceENtoLonLat
1331 void IceModel::GroundENtoLonLat(int e, int n, double& lon, double& lat) {
1332  //Converts indicies of the BEDMAP ground elevation matrix into longitude and latitude. Code by Stephen Hoover.
1333  ENtoLonLat(e,n,xLowerLeft_ground,yLowerLeft_ground,lon,lat);
1334 }//GroundENtoLonLat
1335 void IceModel::WaterENtoLonLat(int e, int n, double& lon, double& lat) {
1336  //Converts indicies of the BEDMAP water depth matrix into longitude and latitude. Code by Stephen Hoover.
1337  ENtoLonLat(e,n,xLowerLeft_water,yLowerLeft_water,lon,lat);
1338 }//WaterENtoLonLat
1339 
1340 
1341 
1342 void IceModel::GetMAXHORIZON(Balloon *bn1) {
1343 
1344  double altitude_inmeters=bn1->BN_ALTITUDE*12.*CMINCH/100.;
1345  if (bn1->BN_ALTITUDE==0.)
1346  bn1->MAXHORIZON=8.E5; // if it is a standard flight then use a horizon of 800 km
1347  else
1348  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.
1349  cout << "MAXHORIZON is " << bn1->MAXHORIZON << "\n";
1350 }
1351 
1352 
1353 void IceModel::CreateHorizons(Settings *settings1,Balloon *bn1,double theta_bn,double phi_bn,double altitude_bn,ofstream &foutput) {
1354 
1355  // add up volume of ice within horizon of payload
1356  // goes a little beyond horizon.
1357 
1358  // when we select a path in a circle at 80deg S latitude,
1359  // vectors are binned in phi (longitude).
1360 
1361  // when we select the Anita-lite path,
1362  // vectors are binned in time.
1363 
1364  //for (int i=0; i<60;i++)
1365  //cout<<"area at lat "<<(double)i/2<<" is "<<Area((double)i/2)<<endl;
1366 
1367  volume = 0.; // initialize volume to zero
1368 
1369  double total_area=0; // initialize total area to zero
1370  int NBALLOONPOSITIONS; // number of balloon positions considered here
1371  if (bn1->WHICHPATH==2) // if anita-lite
1372  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.
1373  else if (bn1->WHICHPATH==6 || bn1->WHICHPATH==7 || bn1->WHICHPATH==8 || bn1->WHICHPATH==9) {
1374  NBALLOONPOSITIONS=(int)((double)bn1->flightdatachain->GetEntries()/(double)bn1->REDUCEBALLOONPOSITIONS)+1;
1375  }
1376  else if (bn1->WHICHPATH==1) // for picking random point along 80 deg south
1377  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
1378  else // includes fixed position (bn1->WHICHPATH=0)
1379  NBALLOONPOSITIONS=1;
1380 
1381  volume_inhorizon.resize(NBALLOONPOSITIONS);
1382  maxvol_inhorizon.resize(NBALLOONPOSITIONS);
1383  ilon_inhorizon.resize(NBALLOONPOSITIONS);
1384  ilat_inhorizon.resize(NBALLOONPOSITIONS);
1385  easting_inhorizon.resize(NBALLOONPOSITIONS);
1386  northing_inhorizon.resize(NBALLOONPOSITIONS);
1387 
1388 
1389 
1390  double phi_bn_temp=0; //phi of balloon, temporary variable
1391  Position r_bn_temp; //position of balloon
1392  Position r_bin; // position of each bin
1393 
1394  double surface_elevation=0;
1395  double local_ice_thickness=0;
1396  double lat=0;
1397  double lon=0;
1398  //double r=0; // r,theta and phi are temporary variables
1399  double theta=0;
1400  double phi=0;
1401  int volume_found=0;
1402  char horizon_file[80];
1403  FILE *bedmap_horizons = new FILE();
1404  char line[200];
1405  int e_coord = 0;
1406  int n_coord = 0;
1407 
1408  sprintf(horizon_file,"bedmap_horizons_whichpath%i_weights%i.dat",bn1->WHICHPATH,settings1->USEPOSITIONWEIGHTS);
1409 
1410  if (ice_model==1 && !settings1->WRITE_FILE) { // for bedmap model, need to be able to read file
1411  if(!(bedmap_horizons = fopen(horizon_file, "r"))) {
1412  printf("Error: unable to open %s. Creating new file.\n", horizon_file);
1413  settings1->WRITE_FILE=1;
1414  }//if
1415  } //if
1416  if (ice_model==1 && settings1->WRITE_FILE) { // for bedmap model, need to be able to write to file
1417  if(!(bedmap_horizons = fopen(horizon_file, "w"))) {
1418  printf("Error: unable to open %s\n", horizon_file);
1419  exit(1);
1420  }//if
1421  } //else if
1422 
1423  if (bn1->WHICHPATH!=2 && bn1->WHICHPATH!=6) // not anita and not anita-lite
1424  lat=GetLat(theta_bn); //get index of latitude, same for all balloon positions
1425 
1426 
1427 
1428  for (int i=0;i<NBALLOONPOSITIONS;i++) { // loop over balloon positions
1429 
1430  maxvol_inhorizon[i]=-1.; // volume of bin with the most ice in the horizon
1431 // double the_time = 0;
1432 
1433  if (bn1->WHICHPATH==2) { // anita or anita-lite path
1434  theta_bn=(90+bn1->latitude_bn_anitalite[i*bn1->REDUCEBALLOONPOSITIONS])*RADDEG; //theta of the balloon wrt north pole
1435  lat=GetLat(theta_bn); // latitude
1436  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
1437  if (phi_bn_temp<0) //correct phi_bn if it's negative
1438  phi_bn_temp+=360.;
1439  phi_bn_temp*=RADDEG;// turn it into radians
1440 
1441 
1442  altitude_bn=bn1->altitude_bn_anitalite[i*bn1->REDUCEBALLOONPOSITIONS]*12.*CMINCH/100.; // get the altitude for this balloon posistion
1443  //altitude_bn=altitude_bn_anitalite[i*100]*12.*CMINCH/100.; // for anita, altitude in is meters
1444 
1445  } // end if anita-lite
1446 
1447 
1448 
1449  else if (bn1->WHICHPATH==6 || bn1->WHICHPATH==7 || bn1->WHICHPATH==8 || bn1->WHICHPATH==9) {
1450 
1451  bn1->flightdatachain->GetEvent(i*bn1->REDUCEBALLOONPOSITIONS);
1452 // the_time = bn1->realTime_flightdata_temp; //??!?
1453 
1454  theta_bn=(90+(double)bn1->flatitude)*RADDEG; //theta of the balloon wrt north pole
1455  lat=GetLat(theta_bn); // latitude
1456  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
1457  if (phi_bn_temp<0) //correct phi_bn if it's negative
1458  phi_bn_temp+=360.;
1459  phi_bn_temp*=RADDEG;// turn it into radians
1460 
1461  altitude_bn=(double)bn1->faltitude; // for anita, altitude in is meters
1462 
1463  } // end if anita or anita-lite
1464  else if (bn1->WHICHPATH==1) // for picking random position along 80 deg south
1465  phi_bn_temp=dGetPhi(i); //get phi of the balloon just based on the balloon positions. Remember nballoonpositions runs from 0 to 179 here.
1466  // the output of dGetPhi is in radians and runs from -pi/2 to 3*pi/2 relative to
1467  else // includes bn1->WHICHPATH=0
1468  phi_bn_temp=phi_bn;
1469 
1470  // altitude_bn has already been set in SetDefaultBalloonPosition
1471  // same for theta_bn
1472  // lat set above
1473 
1474  lon=GetLon(phi_bn_temp); //get longitude for this phi position
1475  // lon goes from 0 (at -180 longitude) to 360 (at 180 longitude)
1476 
1477  // position of balloon
1478  surface_elevation = this->Surface(lon,lat); // distance from center of the earth to surface at this lon and lat
1479  r_bn_temp = Vector(sin(theta_bn)*cos(phi_bn_temp)*(surface_elevation+altitude_bn),
1480  sin(theta_bn)*sin(phi_bn_temp)*(surface_elevation+altitude_bn),
1481  cos(theta_bn)*(surface_elevation+altitude_bn)); // vector from center of the earth to balloon
1482 
1483  // cout << "MAXHORIZON is " << MAXHORIZON << "\n";
1484 
1485 
1486  if (ice_model==0) { // Crust 2.0
1487  for (int j=0;j<NLON;j++) { // loop over bins in longitude
1488  for (int k=0;k<ILAT_COASTLINE;k++) { // loop over bins in latitude
1489 
1490  // get position of each bin
1491  r_bin = Vector(sin(dGetTheta(k))*cos(dGetPhi(j))*(geoid[k]+surfacer[j][k]),
1492  sin(dGetTheta(k))*sin(dGetPhi(j))*(geoid[k]+surfacer[j][k]),
1493  cos(dGetTheta(k))*(geoid[k]+surfacer[j][k])); // vector from center of the earth to the surface of this bin
1494 
1495 
1496  if (!volume_found)
1497  volume += icethkarray[j][k]*1000*area[k]; // add this to the total volume of ice in antarctica
1498  if (!volume_found && icethkarray[j][k] > 0)
1499  total_area += area[k]; // add this to the total area of ice in antarctica
1500 
1501  // if the bin is within the maximum horizon of the balloon or if we don't care
1502  //r=(geoid[k]+surfacer[j][k]);
1503  //phi=dGetPhi(j);
1504  //theta=dGetTheta(k);
1505 
1506  // cout << "USEWEIGHTS is " << USEWEIGHTS << "\n";
1507  if ((settings1->USEPOSITIONWEIGHTS && r_bin.Distance(r_bn_temp)<bn1->MAXHORIZON)
1508  || !settings1->USEPOSITIONWEIGHTS) {
1509  // then put this latitude and longitude in vector
1510 
1511 
1512  ilat_inhorizon[i].push_back(k);
1513  ilon_inhorizon[i].push_back(j);
1514  // add up volume in horizon
1515 
1516 
1517  volume_inhorizon[i]+=icethkarray[j][k]*1000*area[k];
1518 
1519 
1520  // finding which bin in horizon has maximum volume
1521  if (icethkarray[j][k]*1000*area[k]>maxvol_inhorizon[i]) {
1522  maxvol_inhorizon[i]=icethkarray[j][k]*1000.*area[k];
1523  }
1524  } //end if (distance < 800 km)
1525 
1526 
1527  } //end for (k loop)
1528  } //end for (j loop)
1529 
1530  // cout << "i, volume_inhorizon are " << i << " " << volume_inhorizon[i] << "\n";
1531 
1532  // ifi the balloon is too close to the ice, it will think there aren't any
1533  // bins in the horizon, so force it the include the ones just below the balloon
1534  int ilat_bn,ilon_bn;
1535  GetILonILat(r_bn_temp,ilon_bn,ilat_bn); // find which longitude and latitude the balloon is above
1536 
1537  if (ilat_inhorizon[i].size()==0 || ilon_inhorizon[i].size()==0) {
1538  maxvol_inhorizon[i]=icethkarray[ilon_bn][ilat_bn]*1000.*area[ilat_bn]; // need to give it a maximum volume for a bin in horizon
1539  volume_inhorizon[i]=icethkarray[ilon_bn][ilat_bn]*1000.*area[ilat_bn]; // and a total volume for the horizon
1540  }
1541 
1542  if (ilat_inhorizon[i].size()==0) // for the ith balloon position, if it didn't find a latitude bin in horizon
1543  ilat_inhorizon[i].push_back(ilat_bn); // force it to be the one below the balloon
1544 
1545  if (ilon_inhorizon[i].size()==0) // for the ith balloon position, if it didn't find a longitude bin in horizon
1546  ilon_inhorizon[i].push_back(ilon_bn); // force it to be the one below the balloon
1547 
1548 
1549 
1550  } //end if (ice_model==0) Crust 2.0
1551 
1552  else if (ice_model==1 && !settings1->WRITE_FILE) { // for bedmap model
1553  fgets(line,200,bedmap_horizons);
1554  while(line[0] != 'X') {
1555  e_coord = atoi(strtok(line,","));
1556  n_coord = atoi(strtok(NULL,","));
1557  easting_inhorizon[i].push_back(e_coord);
1558  northing_inhorizon[i].push_back(n_coord);
1559  fgets(line,200,bedmap_horizons);
1560  } //while there are more eastings and northings
1561  strtok(line,",");
1562  volume_inhorizon[i] = atof(strtok(NULL,",")); // volume in the horizon
1563  maxvol_inhorizon[i] = atof(strtok(NULL,","));
1564 
1565  if (!volume_found) {
1566  total_area = atof(fgets(line,200,bedmap_horizons)); // total area on the continent
1567  volume = atof(fgets(line,200,bedmap_horizons)); // total volume on the continent
1568  } //if
1569  } //end if (ice_model==1) && !settings1->WRITE_FILE
1570 
1571  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.
1572 
1573  for (int n_coord=0;n_coord<nRows_ground;n_coord++) {
1574  for (int e_coord=0;e_coord<nCols_ground;e_coord++) {
1575 
1576  GroundENtoLonLat(e_coord,n_coord,lon,lat);
1577 
1578  theta = lat * RADDEG;
1579  phi=LongtoPhi_0is180thMeridian(lon);
1580 
1581  surface_elevation = this->Surface(lon,lat);
1582  local_ice_thickness = this->IceThickness(lon,lat);
1583 
1584  // get position of each bin
1585  r_bin = Vector(sin(theta)*cos(phi)*surface_elevation,
1586  sin(theta)*sin(phi)*surface_elevation,
1587  cos(theta)*surface_elevation);
1588 
1589  if (!volume_found)
1590  volume += local_ice_thickness*Area(lat);
1591  if (!volume_found && local_ice_thickness > 5)
1592  total_area += Area(lat);
1593  if ((settings1->USEPOSITIONWEIGHTS && r_bn_temp.Distance(r_bin)<bn1->MAXHORIZON) || !settings1->USEPOSITIONWEIGHTS) {
1594  fprintf(bedmap_horizons,"%i,%i,\n",e_coord,n_coord);
1595  // then put this latitude and longitude in vector
1596  easting_inhorizon[i].push_back(e_coord);
1597  northing_inhorizon[i].push_back(n_coord);
1598  // add up volume in horizon
1599 
1600  GroundENtoLonLat(e_coord,n_coord,lon,lat);
1601 
1602 
1603  volume_inhorizon[i]+=local_ice_thickness*Area(lat);
1604 
1605  // finding which bin in horizon has maximum volumey
1606  if (local_ice_thickness*Area(lat)>maxvol_inhorizon[i]) {
1607  maxvol_inhorizon[i]=local_ice_thickness*Area(lat);
1608  }
1609  } //end if (distance < 800 km & ice present)
1610  } //end for (e_coord loop)
1611  } //end for (n_coord loop)
1612 
1613  fprintf(bedmap_horizons,"X,%f,%f,\n",volume_inhorizon[i],maxvol_inhorizon[i]);
1614  if (!volume_found) {
1615  fprintf(bedmap_horizons,"%f\n",total_area);
1616  fprintf(bedmap_horizons,"%f\n",volume);
1617  } //if
1618 
1619  } //end if (ice_model==1) && settings1->WRITE_FILE
1620 
1621  if (!volume_found) {
1622  cout<<"Total surface area covered with ice (in m^2) is : "<<total_area<<endl;
1623  volume_found=1;
1624  } //if
1625 
1626  } //end loop over balloon positions
1627 
1628  // finding average volume in horizon over all balloon positions.
1629  volume_inhorizon_average=0;
1630 
1631  for (int i=0;i<NBALLOONPOSITIONS;i++) {
1632  volume_inhorizon_average+=volume_inhorizon[i];
1633 
1634  } //for
1635  volume_inhorizon_average/=(double)NBALLOONPOSITIONS;
1636 
1637  //cout << "Total volume of ice in Antarctica with this ice model (m^3): " << volume << "\n";
1638  //cout << "Average volume of ice within a horizon is " << volume_inhorizon_average << "\n";
1639 
1640  foutput << "Average volume of ice within a horizon is " << volume_inhorizon_average << "\n";
1641 
1642  foutput << "Average thickness of ice within horizon, averages over balloon positions " << volume_inhorizon_average/PI/pow(bn1->MAXHORIZON,2) << "\n";
1643 } //method CreateHorizons
1644 
1645 
1646 void IceModel::ReadIceThickness() {
1647  //Reads the BEDMAP ice thickness data. Assumes the file is in directory "data". Code by Ryan Nichol, added to Monte Carlo by Stephen Hoover
1648 
1649  ifstream IceThicknessFile((ICEMC_DATA_DIR+"/icethic.asc").c_str());
1650  if(!IceThicknessFile) {
1651  cerr << "Couldn't open: $ICEMC_DATA_DIR/icethic.asc" << endl;
1652  exit(1);
1653  }
1654 
1655  cout<<"Reading in BEDMAP data on ice thickness.\n";
1656 
1657  string tempBuf1;
1658  string tempBuf2;
1659  string tempBuf3;
1660  string tempBuf4;
1661  string tempBuf5;
1662  string tempBuf6;
1663  int temp1,temp2,temp3,temp4,temp5,temp6;
1664 
1665  IceThicknessFile >> tempBuf1 >> temp1 >> tempBuf2 >> temp2
1666  >> tempBuf3 >> temp3 >> tempBuf4 >> temp4
1667  >> tempBuf5 >> temp5 >> tempBuf6 >> temp6;
1668 
1669  if(tempBuf1 == string("ncols")) {
1670  nCols_ice=temp1;
1671  }
1672  if(tempBuf2 == string("nrows")) {
1673  nRows_ice=temp2;
1674  }
1675  if(tempBuf3 == string("xllcorner")) {
1676  xLowerLeft_ice=temp3;
1677  }
1678  if(tempBuf4 == string("yllcorner")) {
1679  yLowerLeft_ice=temp4;
1680  }
1681  if(tempBuf5 == string("cellsize")) {
1682  cellSize=temp5;
1683  }
1684  if(tempBuf6 == string("NODATA_value")) {
1685  NODATA=temp6;
1686  }
1687  //cout<<"nCols_ice, nRows_ice "<<nCols_ice<<" , "<<nRows_ice<<endl;
1688  //cout<<"xLL_ice, yLL_ice, cellsize "<<xLowerLeft_ice<<" , "<<yLowerLeft_ice<<" , "<<cellSize<<endl<<endl;
1689 
1690  assert(nRows_ice == 1000 && nCols_ice==1200);
1691 
1692  h_ice_thickness.SetBins(nCols_ice, xLowerLeft_ice, xLowerLeft_ice + nCols_ice*cellSize,
1693  nRows_ice, yLowerLeft_ice, yLowerLeft_ice+nRows_ice*cellSize);
1694 
1695  double theValue;
1696  volume=0.;
1697  ice_area=0.;
1698  max_icevol_perbin=0.;
1699  max_icethk_perbin=0.;
1700  double lon_tmp,lat_tmp;
1701  for(int rowNum=0;rowNum<nRows_ice;rowNum++) {
1702  for(int colNum=0;colNum<nCols_ice;colNum++) {
1703  IceENtoLonLat(colNum,rowNum,lon_tmp,lat_tmp);
1704  IceThicknessFile >> theValue;
1705  if(theValue==NODATA)
1706  theValue=0; //Set ice depth to 0 where we have no data.
1707 
1708  //note that the histogram has a backwards indexing on rows since it's defined in a different order
1709  h_ice_thickness.SetBinContent(1+colNum, nRows_ice-rowNum, theValue);
1710  volume+=theValue*Area(lat_tmp);
1711  if (theValue>0)
1712  ice_area+=Area(lat_tmp);
1713  if (theValue*Area(lat_tmp)>max_icevol_perbin)
1714  max_icevol_perbin=theValue*Area(lat_tmp);
1715  if (theValue>max_icethk_perbin)
1716  max_icethk_perbin=theValue;
1717  }//for
1718  }//for
1719 
1720  IceThicknessFile.close();
1721  return;
1722 } //method ReadIceThickness
1723 
1724 void IceModel::ReadGroundBed() {
1725  //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
1726  ifstream GroundBedFile((ICEMC_DATA_DIR+"/groundbed.asc").c_str());
1727  if(!GroundBedFile) {
1728  cerr << "Couldn't open: ICEMC_DATA_DIR/groundbed.asc" << endl;
1729  exit(1);
1730  }
1731 
1732  cout<<"Reading in BEDMAP data on elevation of ground.\n";
1733 
1734  string tempBuf1;
1735  string tempBuf2;
1736  string tempBuf3;
1737  string tempBuf4;
1738  string tempBuf5;
1739  string tempBuf6;
1740  int temp1,temp2,temp3,temp4,temp5,temp6;
1741 
1742  GroundBedFile >> tempBuf1 >> temp1 >> tempBuf2 >> temp2
1743  >> tempBuf3 >> temp3 >> tempBuf4 >> temp4
1744  >> tempBuf5 >> temp5 >> tempBuf6 >> temp6;
1745 
1746  if(tempBuf1 == string("ncols")) {
1747  nCols_ground=temp1;
1748  }
1749  if(tempBuf2 == string("nrows")) {
1750  nRows_ground=temp2;
1751  }
1752  if(tempBuf3 == string("xllcorner")) {
1753  xLowerLeft_ground=temp3;
1754  }
1755  if(tempBuf4 == string("yllcorner")) {
1756  yLowerLeft_ground=temp4;
1757  }
1758  if(tempBuf5 == string("cellsize")) {
1759  cellSize=temp5;
1760  }
1761  if(tempBuf6 == string("NODATA_value")) {
1762  NODATA=temp6;
1763  }
1764  assert(nRows_ground == 869 && nCols_ground==1068);
1765 
1766  h_ground_elevation.SetBins(nCols_ground, xLowerLeft_ground, xLowerLeft_ground + nCols_ground*cellSize,
1767  nRows_ground, yLowerLeft_ground, yLowerLeft_ground + nRows_ground*cellSize);
1768 
1769  //cout<<"nCols_ground, nRows_ground "<<nCols_ground<<" , "<<nRows_ground<<endl;
1770  //cout<<"xLL_ground, yLL_ground, cellsize "<<xLowerLeft_ground<<" , "<<yLowerLeft_ground<<" , "<<cellSize<<endl<<endl;
1771 
1772  double theValue;
1773  for(int rowNum=0;rowNum<nRows_ground;rowNum++) {
1774  for(int colNum=0;colNum<nCols_ground;colNum++) {
1775  GroundBedFile >> theValue;
1776 
1777  if(theValue==NODATA)
1778  theValue=0; //Set elevation to 0 where we have no data.
1779  h_ground_elevation.SetBinContent(colNum+1,nRows_ground-rowNum, double(theValue));
1780  //if (theValue != -96 && theValue != 0)
1781  //cout<<"ground_elevation: "<<theValue<<endl;
1782  }//for
1783  }//for
1784 
1785  GroundBedFile.close();
1786  return;
1787 } //method ReadGroundBed
1788 
1789 void IceModel::ReadWaterDepth() {
1790  //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
1791  ifstream WaterDepthFile((ICEMC_DATA_DIR+"/water.asc").c_str());
1792  if(!WaterDepthFile) {
1793  cerr << "Couldn't open: ICEMC_DATA_DIR/water.asc" << endl;
1794  exit(1);
1795  }
1796 
1797  cout<<"Reading in BEDMAP data on water depth.\n";
1798 
1799  string tempBuf1;
1800  string tempBuf2;
1801  string tempBuf3;
1802  string tempBuf4;
1803  string tempBuf5;
1804  string tempBuf6;
1805  int temp1,temp2,temp3,temp4,temp5,temp6;
1806 
1807  WaterDepthFile >> tempBuf1 >> temp1 >> tempBuf2 >> temp2
1808  >> tempBuf3 >> temp3 >> tempBuf4 >> temp4
1809  >> tempBuf5 >> temp5 >> tempBuf6 >> temp6;
1810 
1811  if(tempBuf1 == string("ncols")) {
1812  nCols_water=temp1;
1813  }
1814  if(tempBuf2 == string("nrows")) {
1815  nRows_water=temp2;
1816  }
1817  if(tempBuf3 == string("xllcorner")) {
1818  xLowerLeft_water=temp3;
1819  }
1820  if(tempBuf4 == string("yllcorner")) {
1821  yLowerLeft_water=temp4;
1822  }
1823  if(tempBuf5 == string("cellsize")) {
1824  cellSize=temp5;
1825  }
1826  if(tempBuf6 == string("NODATA_value")) {
1827  NODATA=temp6;
1828  }
1829 
1830  //cout<<"nCols_water, nRows_water "<<nCols_water<<" , "<<nRows_water<<endl;
1831  //cout<<"xLL_water, yLL_water, cellsize "<<xLowerLeft_water<<" , "<<yLowerLeft_water<<" , "<<cellSize<<endl<<endl;
1832 
1833  assert(nRows_water == 1000 && nCols_water==1200);
1834 
1835  h_water_depth.SetBins(nCols_water, xLowerLeft_water, xLowerLeft_water + nCols_water*cellSize,
1836  nRows_water, yLowerLeft_water, yLowerLeft_water+nRows_water*cellSize);
1837  double theValue;
1838  for(int rowNum=0;rowNum<nRows_water;rowNum++) {
1839  for(int colNum=0;colNum<nCols_water;colNum++) {
1840  WaterDepthFile >> theValue;
1841 
1842  if(theValue==NODATA)
1843  theValue=0; //Set depth to 0 where we have no data.
1844  h_water_depth.SetBinContent(1+colNum,nRows_water-rowNum, double(theValue));
1845  }//for
1846  }//for
1847 
1848  WaterDepthFile.close();
1849  return;
1850 } //method ReadWaterDepth
1851 
1852 
1853 
1854 
1855 //Methods related to the 2D cartesian surfaces
1856 //
1857 
1858 
1859 void IceModel::CreateCartesianTopAndBottom(int resolution, bool force)
1860 {
1861  TString fname;
1862 
1863  if (resolution == cart_resolution)
1864  {
1865  return ;
1866  }
1867 
1868  cart_resolution = resolution;
1869 
1870  if (cart_ice_file) delete cart_ice_file;
1871 
1872  fname.Form("%s/cartesian_icemodel_%d_%d.root", getenv("ICEMC_SRC_DIR")?: ".", ice_model , resolution);
1873 
1874  TDirectory * olddir = gDirectory;
1875 
1876  //check if it exists
1877  if (!force)
1878  {
1879  cart_ice_file = new TFile(fname);
1880 
1881  if (!cart_ice_file->IsOpen())
1882  {
1883  delete cart_ice_file;
1884  }
1885  else
1886  {
1887  cart_ice_top = (TH2*) cart_ice_file->Get("top");
1888  cart_ice_bot = (TH2*) cart_ice_file->Get("bot");
1889 
1890  if (!cart_ice_top || !cart_ice_bot)
1891  {
1892  delete cart_ice_file;
1893  }
1894 
1895  else
1896  {
1897  olddir->cd();
1898  return;
1899  }
1900  }
1901  }
1902 
1903  //if we got this far, we don't already have it
1904  cart_ice_file = new TFile(fname,"RECREATE");
1905  //the bounds will roughly be +/- REARTH /2,so we'll convert that to our resolution
1906 
1907  printf("Creating new cartesian ice file at %s...\n", cart_ice_file->GetName());
1908 
1909  double bound = ceil(6371000/2/resolution)*resolution;
1910  int nbins = (2*bound)/resolution;
1911 
1912  TString hname;
1913  hname.Form("icetop_%d_%d", ice_model, resolution);
1914  TString htitle;
1915  htitle.Form("Ice Top (model=%d, res=%d m)", ice_model, resolution);
1916  cart_ice_top = new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
1917 
1918  hname.Form("icebot_%d_%d", ice_model, resolution);
1919  htitle.Form("Ice Bottom (model=%d, res=%d m)", ice_model, resolution);
1920  cart_ice_bot= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
1921 
1922  // auxiliary hists
1923  hname.Form("ice_bot_r_%d_%d",ice_model, resolution);
1924  htitle.Form("Ice Bottom (r) (model=%d, res=%d m)", ice_model, resolution);
1925 
1926  TH2 * r_bot= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
1927 
1928  hname.Form("ice_top_r_%d_%d",ice_model, resolution);
1929  htitle.Form("Ice top (r) (model=%d, res=%d m)", ice_model, resolution);
1930 
1931  TH2 * r_top= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
1932 
1933  hname.Form("ice_bot_alt_%d_%d",ice_model, resolution);
1934  htitle.Form("Ice Bottom (alt) (model=%d, res=%d m)", ice_model, resolution);
1935 
1936  TH2 * alt_bot= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
1937 
1938  hname.Form("ice_top_alt_%d_%d",ice_model, resolution);
1939  htitle.Form("Ice top (alt) (model=%d, res=%d m)", ice_model, resolution);
1940 
1941  TH2 * alt_top= new TH2D(hname.Data(), htitle.Data(), nbins,-bound,bound,nbins,-bound,bound);
1942 
1943 
1944  for (int j = 1; j <= nbins; j++)
1945  {
1946  double y = cart_ice_top->GetYaxis()->GetBinCenter(j);
1947  for (int i = 1; i <= nbins; i++)
1948  {
1949  double x = cart_ice_top->GetXaxis()->GetBinCenter(i);
1950 
1951  double r2 = x*x+y*y;
1952  const double a = 6378137;
1953  const double a2 = a*a;
1954  if (r2 > a2) continue;
1955  const double b = 6356752.314245; ;
1956  const double b2 = b*b;
1957  double z_geoid = sqrt((1-r2/a2)*b2);
1958 
1959  Position p(Vector(x,y,z_geoid));
1960  double lon = p.Lon();
1961  double lat = p.Lat();
1962  double ice_depth = IceThickness(lon,lat);
1963  if (ice_depth)
1964  {
1965  double surface_above_geoid = SurfaceAboveGeoid(lon,lat);
1966  double geoid = Geoid(lat);
1967  double surface = surface_above_geoid+geoid;
1968 
1969  Position top(lon,lat,surface);
1970  Position bot(lon,lat,surface-ice_depth);
1971 
1972  cart_ice_top->SetBinContent(i,j,top.Z());
1973  cart_ice_bot->SetBinContent(i,j,bot.Z());
1974 
1975  r_top->SetBinContent(i,j,surface);
1976  r_bot->SetBinContent(i,j,surface-ice_depth);
1977 
1978  alt_top->SetBinContent(i,j,surface_above_geoid);
1979  alt_bot->SetBinContent(i,j,surface_above_geoid-ice_depth);
1980  }
1981  }
1982  }
1983 
1984  cart_ice_top->Write("top");
1985  cart_ice_bot->Write("bot");
1986  r_top->Write("r_top");
1987  r_bot->Write("r_bot");
1988  alt_top->Write("alt_top");
1989  alt_bot->Write("alt_bot");
1990  cart_ice_file->Flush();
1991  printf("...Done!\n");
1992  olddir->cd();
1993 
1994 }
1995 
1996 
1997 bool IceModel::CartesianIsInIce(double x,double y, double z)
1998 {
1999  const TH2 * htop = GetCartesianTop();
2000  if (z > cart_max_z) return false;
2001  if (z < cart_min_z) return false;
2002  if (x < htop->GetXaxis()->GetXmin()) return false;
2003  if (x > htop->GetXaxis()->GetXmax()) return false;
2004  if (y < htop->GetYaxis()->GetXmin()) return false;
2005  if (y > htop->GetYaxis()->GetXmax()) return false;
2006 
2007  double top = ((TH2*)htop)->Interpolate(x,y);
2008  if (!top) return false;
2009 
2010  return z < top && z > ((TH2*)GetCartesianBottom())->Interpolate(x,y);
2011 }
2012 
2013 int IceModel::GetIceIntersectionsCartesian(const Position & posnu, const Vector & nnu_in,
2014  std::vector<std::pair<double,double> > & intersection_points,
2015  double start_step, int map_resolution)
2016 {
2017  if (map_resolution!= cart_resolution) CreateCartesianTopAndBottom(map_resolution);
2018 
2019  if (cart_max_z == -1)
2020  {
2021  cart_max_z = GetCartesianTop()->GetMaximum();
2022 
2023  cart_min_z = cart_max_z;
2024 
2025  const TH2 * hbot = GetCartesianBottom();
2026 
2027  for (int j = 1; j <= hbot->GetNbinsY(); j++)
2028  {
2029  for (int i = 1; i <= hbot->GetNbinsX(); i++)
2030  {
2031  double val = hbot->GetBinContent(i,j);
2032  if (val > 0 && val < cart_min_z) cart_min_z = val;
2033  }
2034  }
2035  }
2036 
2037 
2038  std::vector<double> boundaries;
2039 
2040  //is our start point in the ice?
2041 
2042  bool start_in_ice = CartesianIsInIce(posnu.X(), posnu.Y(), posnu.Z());
2043 
2044  Vector nnu = nnu_in.Unit();
2045  //let's start at the position and go both ways
2046  for (int dir = -1; dir <=1 ; dir+=2)
2047  {
2048 
2049  Vector x = posnu;
2050  bool was_in_ice = start_in_ice;
2051 
2052  // go until we are way to far away from the Earth to matter
2053 
2054  double displacement = 0;
2055  bool jumped = false;
2056  bool just_jumped = false;
2057  while (true) //this is mean Earth radius + 5 km.
2058  {
2059 // printf("%g -> %g,%g,%g\n", displacement, x.X(),x.Y(), x.Z());
2060  displacement += start_step*dir;
2061  x = posnu + displacement*nnu;
2062  double mag2 = x.X()*x.X() + x.Y()*x.Y() + x.Z()*x.Z();
2063  // printf(" %g\n", sqrt(mag2));
2064  if (mag2 > (7000e3*7000e3))
2065  {
2066  printf("wtf: [%g,%g,%g], %g\n", x.X(), x.Y(), x.Z(), mag2);
2067 
2068  }
2069  if (mag2 > (6365e3*6365e3))
2070  {
2071  break;
2072  }
2073 
2074  //jump to the other side of the world if we dip down too much!
2075  if (mag2 < (6355.5e3*6355.5e3) && !jumped && !was_in_ice)
2076  {
2077  // printf("Trying to go to other side of the earth! start displacement: %g, mag: %g\n", displacement,sqrt(mag2));
2078  double ds[2];
2079  GeoidIntersection(x,dir*nnu, 0,0,-1000,ds);
2080  //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!
2081  displacement = (ds[0] > 0 ? ds[0] : ds[1])*dir;
2082  //printf("End displacement: %g\n", displacement);
2083  jumped = true;
2084  just_jumped = true;
2085  continue;
2086  }
2087 
2088  bool is_in_ice = CartesianIsInIce(x.X(),x.Y(),x.Z());
2089 
2090  //this is no bueno...we won't find the right boundary in this case!
2091  // let's back up 500 m from where we were at the start of this iteration
2092  if (just_jumped && is_in_ice)
2093  {
2094  displacement -= dir*(500+start_step);
2095  continue;
2096  }
2097 
2098  just_jumped = false;
2099 
2100  if (was_in_ice!=is_in_ice)
2101  {
2102  //binary search for the boundary to 1 m resolution
2103 
2104  Vector xsearch = x;
2105  double step = -start_step*dir/2;
2106  bool search_was_in_ice = is_in_ice;
2107  double boundary_displacement = displacement;
2108 
2109  while (fabs(step) > 1)
2110  {
2111  boundary_displacement+=step;
2112  xsearch = posnu + boundary_displacement * nnu;
2113  bool search_is_in_ice = CartesianIsInIce(xsearch.X(),xsearch.Y(),xsearch.Z());
2114 
2115  step*=0.5;
2116  if (search_is_in_ice!=search_was_in_ice) step*=-1;
2117  search_was_in_ice = search_is_in_ice;
2118  }
2119 
2120  //we found a boundary! (if there is more than one boundary within this segment... we probably picked a random one. Oh well.
2121  boundaries.push_back(boundary_displacement);
2122  }
2123  was_in_ice = is_in_ice;
2124  }
2125  }
2126 
2127  std::sort(boundaries.begin(), boundaries.end());
2128 
2129  if (boundaries.size() % 2)
2130  {
2131  fprintf(stderr,"Uh oh, have an odd number of boundaries (%lu) . That means there's a bug...\n", boundaries.size());
2132  for (unsigned i = 0; i < boundaries.size(); i++) printf(" %g ", boundaries[i]);
2133  printf("\n");
2134  assert(0);
2135  return -1;
2136  }
2137 
2138  for (unsigned i = 0; i < boundaries.size()/2; i++)
2139  {
2140  intersection_points.push_back(std::pair<double,double>(boundaries[2*i], boundaries[2*i+1]));
2141  }
2142 
2143  return boundaries.size()/2;
2144 }
2145 
int WHICHPATH
0=fixed balloon position,1=randomized,2=ANITA-lite GPS data,3=banana plot
Definition: balloon.hh:57
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
Reads in and stores input settings for the run.
Definition: Settings.h:35
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
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:1079
Stores everything about a particular neutrino interaction. Interaction.
Definition: Primaries.h:136
double longitude_bn_anitalite[100000]
same for longitude
Definition: balloon.hh:84
Shape of the earth, ice thicknesses, profiles of earth layers, densities, neutrino absorption...
Definition: earthmodel.hh:40
void PickAnyDirection()
Constructor.
Definition: Primaries.cc:262
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
double Distance(const Position &second) const
Returns chord distance (direct distance between two vectors)
Definition: position.cc:37
Position r_enterice
position where neutrino enters the ice
Definition: Primaries.h:195
double Lon() const
Returns longitude.
Definition: position.cc:51
Vector nnu
direction of neutrino (+z in south pole direction)
Definition: Primaries.h:187