def setup_function(self): # object for oscillation parameters self.osc_params = OscParams() # setup the layers #if self.params.earth_model.value is not None: earth_model = find_resource(self.params.earth_model.value) YeI = self.params.YeI.value.m_as('dimensionless') YeO = self.params.YeO.value.m_as('dimensionless') YeM = self.params.YeM.value.m_as('dimensionless') prop_height = self.params.prop_height.value.m_as('km') detector_depth = self.params.detector_depth.value.m_as('km') self.layers = Layers(earth_model, detector_depth, prop_height) self.layers.setElecFrac(YeI, YeO, YeM) # set the correct data mode self.data.data_specs = self.calc_specs # --- calculate the layers --- if self.calc_mode == 'binned': # speed up calculation by adding links # as layers don't care about flavour self.data.link_containers('nu', [ 'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc' ]) for container in self.data: self.layers.calcLayers(container['true_coszen'].get('host')) container['densities'] = self.layers.density.reshape( (container.size, self.layers.max_layers)) container['distances'] = self.layers.distance.reshape( (container.size, self.layers.max_layers)) # don't forget to un-link everything again self.data.unlink_containers() # --- setup empty arrays --- if self.calc_mode == 'binned': self.data.link_containers('nu', [ 'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc' ]) self.data.link_containers('nubar', [ 'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc' ]) for container in self.data: container['probability'] = np.empty((container.size, 3, 3), dtype=FTYPE) self.data.unlink_containers() # setup more empty arrays for container in self.data: container['prob_e'] = np.empty((container.size), dtype=FTYPE) container['prob_mu'] = np.empty((container.size), dtype=FTYPE)
def setup_function(self): # setup Earth model if self.params.earth_model.value is not None: earth_model = find_resource(self.params.earth_model.value) YeI = self.params.YeI.value.m_as('dimensionless') YeO = self.params.YeO.value.m_as('dimensionless') YeM = self.params.YeM.value.m_as('dimensionless') else: earth_model = None # setup the layers prop_height = self.params.prop_height.value.m_as('km') detector_depth = self.params.detector_depth.value.m_as('km') self.layers = Layers(earth_model, detector_depth, prop_height) if earth_model is not None: self.layers.setElecFrac(YeI, YeO, YeM) # set the correct data mode self.data.representation = self.calc_mode # --- calculate the layers --- if self.data.is_map: # speed up calculation by adding links # as layers don't care about flavour self.data.link_containers('nu', ['nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc']) for container in self.data: if self.params.earth_model.value is not None: self.layers.calcLayers(container['true_coszen']) container['densities'] = self.layers.density.reshape((container.size, self.layers.max_layers)) container['distances'] = self.layers.distance.reshape((container.size, self.layers.max_layers)) else: self.layers.calcPathLength(container['true_coszen']) container['distances'] = self.layers.distance # don't forget to un-link everything again self.data.unlink_containers() # --- setup empty arrays --- if self.data.is_map: self.data.link_containers('nu', ['nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc']) self.data.link_containers('nubar', ['nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc']) for container in self.data: container['probability'] = np.empty((container.size, 3, 3), dtype=FTYPE) self.data.unlink_containers() # setup more empty arrays for container in self.data: container['prob_e'] = np.empty((container.size), dtype=FTYPE) container['prob_mu'] = np.empty((container.size), dtype=FTYPE)
def setup_function(self): import ROOT # setup the layers earth_model = find_resource(self.earth_model) self.layers = Layers(earth_model, self.detector_depth, self.prop_height) # This is a bit hacky, but setting the electron density to 1. # gives us the total density of matter, which is what we want. self.layers.setElecFrac(1., 1., 1.) # setup cross-sections self.xsroot = ROOT.TFile(self.xsec_file) # set the correct data mode self.data.data_specs = self.calc_specs # --- calculate the layers --- if self.calc_mode == 'binned': # layers don't care about flavor self.data.link_containers('nu', [ 'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc' ]) for container in self.data: self.layers.calcLayers(container['true_coszen'].get(WHERE)) container['densities'] = self.layers.density.reshape( (container.size, self.layers.max_layers)) container['distances'] = self.layers.distance.reshape( (container.size, self.layers.max_layers)) container['rho_int'] = np.empty((container.size), dtype=FTYPE) # don't forget to un-link everything again self.data.unlink_containers() # --- setup cross section and survival probability --- if self.calc_mode == 'binned': # The cross-sections do not depend on nc/cc, so we can at least link those containers self.data.link_containers('nue', ['nue_cc', 'nue_nc']) self.data.link_containers('nuebar', ['nuebar_cc', 'nuebar_nc']) self.data.link_containers('numu', ['numu_cc', 'numu_nc']) self.data.link_containers('numubar', ['numubar_cc', 'numubar_nc']) self.data.link_containers('nutau', ['nutau_cc', 'nutau_nc']) self.data.link_containers('nutaubar', ['nutaubar_cc', 'nutaubar_nc']) for container in self.data: container['xsection'] = np.empty((container.size), dtype=FTYPE) container['survival_prob'] = np.empty((container.size), dtype=FTYPE) self.data.unlink_containers()
def setup_function(self): sys.path.append(self.globes_wrapper) import GLoBES ### you need to start GLoBES from the folder containing a dummy experiment # therefore we go to the folder, load GLoBES and then go back curdir = os.getcwd() os.chdir(self.globes_wrapper) self.globes_calc = GLoBES.GLoBESCalculator("calc") os.chdir(curdir) self.globes_calc.InitSteriles(2) # object for oscillation parameters self.osc_params = OscParams() earth_model = find_resource(self.earth_model) prop_height = self.prop_height.m_as('km') detector_depth = self.detector_depth.m_as('km') self.layers = Layers(earth_model, detector_depth, prop_height) # The electron fractions are taken into account internally by GLoBES/SNU. # See the SNU patch for details. It uses the density to decide # whether it is in the core or in the mantle. Therefore, we just multiply by # one to give GLoBES the raw densities. self.layers.setElecFrac(1., 1., 1.) # set the correct data mode self.data.data_specs = self.calc_specs # --- calculate the layers --- if self.calc_mode == 'binned': # speed up calculation by adding links # as layers don't care about flavour self.data.link_containers('nu', ['nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc']) for container in self.data: self.layers.calcLayers(container['true_coszen'].get('host')) container['densities'] = self.layers.density.reshape((container.size, self.layers.max_layers)) container['distances'] = self.layers.distance.reshape((container.size, self.layers.max_layers)) # don't forget to un-link everything again self.data.unlink_containers() # setup probability containers for container in self.data: container['prob_e'] = np.empty((container.size), dtype=FTYPE) container['prob_mu'] = np.empty((container.size), dtype=FTYPE) container['prob_nonsterile'] = np.empty((container.size), dtype=FTYPE)
def setup_function(self): earth_model = find_resource(self.earth_model) prop_height = self.prop_height detector_depth = self.detector_depth self.layers = Layers(earth_model, detector_depth, prop_height) # We must treat densities and electron fractions correctly here, so we set them # to 1 in the Layers module to get unweighted densities. self.layers.setElecFrac(1, 1, 1) nsq_units = nsq.Const() # natural units for nusquids # Because we don't want to extrapolate, we check that all points at which we # want to evaluate probabilities are fully contained within the node specs. This # is of course not necessary in events mode. if isinstance(self.node_mode, MultiDimBinning) and not self.exact_mode: logging.debug("setting up nuSQuIDS nodes in binned mode") # we can prepare the calculator like this only in binned mode, see # compute_function for node_mode == "events" self.data.representation = self.calc_mode for container in self.data: for var in ["true_coszen", "true_energy"]: unit = "dimensionless" if var == "true_coszen" else "GeV" upper_bound = np.max(self.node_mode[var].bin_edges.m_as(unit)) lower_bound = np.min(self.node_mode[var].bin_edges.m_as(unit)) err_msg = ( "The outer edges of the node_mode must encompass " "the entire range of calc_specs to avoid extrapolation" ) if np.any(container[var] > upper_bound): maxval = np.max(container[var]) raise ValueError( err_msg + f"\nmax input: {maxval}, upper " f"bound: {upper_bound}" ) if np.any(container[var] < lower_bound): minval = np.max(container[var]) raise ValueError( err_msg + f"\nmin input: {minval}, lower " f"bound: {lower_bound}" ) # Layers in nuSQuIDS are special: We need all the individual distances and # densities for the nodes to solve the interaction picture states, but on # the final calculation grid (or events) we only need the *total* traversed # distance. Because we are placing nodes at the bin edges rather than the # bin middle, this doesn't really fit with how containers store data, so we # are making arrays as variables that never go into the container. # These are stored because we need them later during interpolation self.coszen_node_mode = self.node_mode["true_coszen"].bin_edges.m_as( "dimensionless" ) self.e_node_mode = self.node_mode["true_energy"].bin_edges.m_as("GeV") logging.debug( f"Setting up nodes at\n" f"cos_zen = \n{self.coszen_node_mode}\n" f"energy = \n{self.e_node_mode}\n" ) # things are getting a bit meshy from here... self.e_mesh, self.cosz_mesh = np.meshgrid( self.e_node_mode, self.coszen_node_mode ) e_nodes = self.e_mesh.ravel() coszen_nodes = self.cosz_mesh.ravel() # The lines below should not be necessary because we will always get at # least two numbers from the bin edges. However, if either energy or coszen # somehow was just a scalar, we would need to broadcast it out to the same # size. Keeping the code in here in case you want to use the stage in 1D. # convert lists to ndarrays and scalars to ndarrays with length 1 e_nodes = np.atleast_1d(e_nodes) coszen_nodes = np.atleast_1d(coszen_nodes) # broadcast against each other and make a copy # (see https://numpy.org/doc/stable/reference/generated/numpy.broadcast_arrays.html) e_nodes, coszen_nodes = [ np.array(a) for a in np.broadcast_arrays(e_nodes, coszen_nodes) ] assert len(e_nodes) == len(coszen_nodes) assert coszen_nodes.ndim == 1 assert e_nodes.ndim == 1 self.layers.calcLayers(coszen_nodes) distances = np.reshape( self.layers.distance, (len(e_nodes), self.layers.max_layers) ) densities = np.reshape( self.layers.density, (len(e_nodes), self.layers.max_layers) ) # HACK: We need the correct electron densities for each layer. We can # determine whether we are in the core or mantle based on the density. # Needless to say it isn't optimal to have these numbers hard-coded. ye = np.zeros_like(densities) ye[densities < 10] = self.YeM ye[(densities >= 10) & (densities < 13)] = self.YeO ye[densities >= 13] = self.YeI self.nus_layer = self.nusquids_layers_class( distances * nsq_units.km, densities, ye, e_nodes * nsq_units.GeV, self.num_neutrinos, nsq.NeutrinoType.both, ) self.apply_prop_settings(self.nus_layer) # Now that we have our nusquids calculator set up on the node grid, we make # container output space for the probability output which may be on a finer grid # than the nodes or even working in events mode. self.data.representation = self.calc_mode # --- calculate the layers --- if isinstance(self.calc_mode, MultiDimBinning): # as layers don't care about flavour self.data.link_containers( "nu", [ "nue_cc", "numu_cc", "nutau_cc", "nue_nc", "numu_nc", "nutau_nc", "nuebar_cc", "numubar_cc", "nutaubar_cc", "nuebar_nc", "numubar_nc", "nutaubar_nc", ], ) # calculate the distance difference between minimum and maximum production # height, if applicable if self.avg_height: layers_min = Layers( earth_model, detector_depth, self.prop_height - self.prop_height_range / 2.0, ) layers_min.setElecFrac(1, 1, 1) layers_max = Layers( earth_model, detector_depth, self.prop_height + self.prop_height_range / 2.0, ) layers_max.setElecFrac(1, 1, 1) for container in self.data: self.layers.calcLayers(container["true_coszen"]) distances = self.layers.distance.reshape((container.size, -1)) tot_distances = np.sum(distances, axis=1) if self.avg_height: layers_min.calcLayers(container["true_coszen"]) dists_min = layers_min.distance.reshape((container.size, -1)) min_tot_dists = np.sum(dists_min, axis=1) layers_max.calcLayers(container["true_coszen"]) dists_max = layers_max.distance.reshape((container.size, -1)) max_tot_dists = np.sum(dists_max, axis=1) # nuSQuIDS assumes the original distance is the longest distance and # the averaging range is the difference between the minimum and maximum # distance. avg_ranges = max_tot_dists - min_tot_dists tot_distances = max_tot_dists assert np.all(avg_ranges > 0) # If the low-pass cutoff is zero, nusquids will not evaluate the filter. container["lowpass_cutoff"] = self.eval_lowpass_cutoff * np.ones( container.size ) if not self.apply_lowpass_above_hor: container["lowpass_cutoff"] = np.where( container["true_coszen"] >= 0, 0, container["lowpass_cutoff"] ) if isinstance(self.node_mode, MultiDimBinning) and not self.exact_mode: # To project out probabilities we only need the *total* distance container["tot_distances"] = tot_distances if self.avg_height: container["avg_ranges"] = avg_ranges else: container["avg_ranges"] = np.zeros(container.size, dtype=FTYPE) if not self.apply_height_avg_below_hor: container["avg_ranges"] = np.where( container["true_coszen"] >= 0, container["avg_ranges"], 0.0 ) elif self.node_mode == "events" or self.exact_mode: # in any other mode (events or exact) we store all densities and # distances in the container in calc_specs densities = self.layers.density.reshape((container.size, -1)) container["densities"] = densities container["distances"] = distances self.data.unlink_containers() if isinstance(self.calc_mode, MultiDimBinning): self.data.link_containers("nue", ["nue_cc", "nue_nc"]) self.data.link_containers("numu", ["numu_cc", "numu_nc"]) self.data.link_containers("nutau", ["nutau_cc", "nutau_nc"]) self.data.link_containers("nuebar", ["nuebar_cc", "nuebar_nc"]) self.data.link_containers("numubar", ["numubar_cc", "numubar_nc"]) self.data.link_containers("nutaubar", ["nutaubar_cc", "nutaubar_nc"]) # setup more empty arrays for container in self.data: container["prob_e"] = np.empty((container.size), dtype=FTYPE) container["prob_mu"] = np.empty((container.size), dtype=FTYPE) if self.use_taus: container["prob_tau"] = np.empty((container.size), dtype=FTYPE) self.data.unlink_containers() if self.exact_mode: return # --- containers for interpolated states --- # This is not needed in exact mode if isinstance(self.calc_mode, MultiDimBinning): self.data.link_containers( "nu", ["nue_cc", "numu_cc", "nutau_cc", "nue_nc", "numu_nc", "nutau_nc"] ) self.data.link_containers( "nubar", [ "nuebar_cc", "numubar_cc", "nutaubar_cc", "nuebar_nc", "numubar_nc", "nutaubar_nc", ], ) for container in self.data: container["interp_states_e"] = np.empty( (container.size, self.num_neutrinos ** 2), dtype=FTYPE, ) container["interp_states_mu"] = np.empty( (container.size, self.num_neutrinos ** 2), dtype=FTYPE, ) container["interp_states_tau"] = np.empty( (container.size, self.num_neutrinos ** 2), dtype=FTYPE, ) self.data.unlink_containers() self.interpolation_warning_issued = False
def setup_function(self): earth_model = find_resource(self.earth_model) prop_height = self.prop_height detector_depth = self.detector_depth self.layers = Layers(earth_model, detector_depth, prop_height) self.layers.setElecFrac(self.YeI, self.YeO, self.YeM) nsq_units = nsq.Const() # natural units for nusquids # Because we don't want to extrapolate, we check that all points at which we # want to evaluate probabilities are fully contained within the node specs. This # is of course not necessary in events mode. if self.node_mode == "binned" and not self.exact_mode: logging.debug("setting up nuSQuIDS nodes in binned mode") # we can prepare the calculator like this only in binned mode, see # compute_function for node_mode == "events" self.data.data_specs = self.calc_specs for container in self.data: for var in ["true_coszen", "true_energy"]: upper_bound = np.max(self.node_specs[var].bin_edges) lower_bound = np.min(self.node_specs[var].bin_edges) err_msg = ( "The outer edges of the node_specs must encompass " "the entire range of calc_specs to avoid extrapolation" ) if np.any(container[var].get(WHERE) > upper_bound): maxval = np.max(container[var].get(WHERE)) raise ValueError(err_msg + f"\nmax input: {maxval}, upper " f"bound: {upper_bound}") if np.any(container[var].get(WHERE) < lower_bound): minval = np.max(container[var].get(WHERE)) raise ValueError(err_msg + f"\nmin input: {minval}, lower " f"bound: {lower_bound}") # Layers in nuSQuIDS are special: We need all the individual distances and # densities for the nodes to solve the interaction picture states, but on # the final calculation grid (or events) we only need the *total* traversed # distance. Because we are placing nodes at the bin edges rather than the # bin middle, this doesn't really fit with how containers store data, so we # are making arrays as variables that never go into the container. # These are stored because we need them later during interpolation self.coszen_node_specs = self.node_specs[ "true_coszen"].bin_edges.m_as("dimensionless") self.e_node_specs = self.node_specs["true_energy"].bin_edges.m_as( "GeV") logging.debug(f"Setting up nodes at\n" f"cos_zen = \n{self.coszen_node_specs}\n" f"energy = \n{self.e_node_specs}\n") # things are getting a bit meshy from here... self.e_mesh, self.cosz_mesh = np.meshgrid(self.e_node_specs, self.coszen_node_specs) e_nodes = self.e_mesh.ravel() coszen_nodes = self.cosz_mesh.ravel() # The lines below should not be necessary because we will always get at # least two numbers from the bin edges. However, if either energy or coszen # somehow was just a scalar, we would need to broadcast it out to the same # size. Keeping the code in here in case you want to use the stage in 1D. # convert lists to ndarrays and scalars to ndarrays with length 1 e_nodes = np.atleast_1d(e_nodes) coszen_nodes = np.atleast_1d(coszen_nodes) # broadcast against each other and make a copy # (see https://numpy.org/doc/stable/reference/generated/numpy.broadcast_arrays.html) e_nodes, coszen_nodes = [ np.array(a) for a in np.broadcast_arrays(e_nodes, coszen_nodes) ] assert len(e_nodes) == len(coszen_nodes) assert coszen_nodes.ndim == 1 assert e_nodes.ndim == 1 self.layers.calcLayers(coszen_nodes) distances = np.reshape(self.layers.distance, (len(e_nodes), self.layers.max_layers)) densities = np.reshape(self.layers.density, (len(e_nodes), self.layers.max_layers)) # electron fraction is already included by multiplying the densities with # them in the Layers module, so we pass 1. to nuSQuIDS (unless energies are # very high, this should be equivalent). ye = np.broadcast_to(np.array([1.]), (len(e_nodes), self.layers.max_layers)) self.nus_layer = nsq.nuSQUIDSLayers( distances * nsq_units.km, densities, ye, e_nodes * nsq_units.GeV, self.num_neutrinos, nsq.NeutrinoType.both, ) self.apply_prop_settings(self.nus_layer) # Now that we have our nusquids calculator set up on the node grid, we make # container output space for the probability output which may be on a finer grid # than the nodes or even working in events mode. self.data.data_specs = self.calc_specs # --- calculate the layers --- if self.calc_mode == "binned": # as layers don't care about flavour self.data.link_containers("nu", [ "nue_cc", "numu_cc", "nutau_cc", "nue_nc", "numu_nc", "nutau_nc", "nuebar_cc", "numubar_cc", "nutaubar_cc", "nuebar_nc", "numubar_nc", "nutaubar_nc" ]) # calculate the distance difference between minimum and maximum production # height, if applicable if self.avg_height: layers_min = Layers(earth_model, detector_depth, self.prop_height_min) layers_min.setElecFrac(self.YeI, self.YeO, self.YeM) for container in self.data: self.layers.calcLayers(container["true_coszen"].get("host")) distances = self.layers.distance.reshape( (container.size, self.layers.max_layers)) tot_distances = np.sum(distances, axis=1) if self.avg_height: layers_min.calcLayers(container["true_coszen"].get("host")) dists_min = layers_min.distance.reshape( (container.size, self.layers.max_layers)) min_tot_dists = np.sum(dists_min, axis=1) # nuSQuIDS assumes the original distance is the longest distance and # the averaging range is the difference between the minimum and maximum # distance. avg_ranges = tot_distances - min_tot_dists assert np.all(avg_ranges > 0) if self.node_mode == "binned" and not self.exact_mode: # To project out probabilities we only need the *total* distance container["tot_distances"] = tot_distances # for the binned node_mode we already calculated layers above if self.avg_height: container["avg_ranges"] = avg_ranges elif self.node_mode == "events" or self.exact_mode: # in any other mode (events or exact) we store all densities and # distances in the container in calc_specs densities = self.layers.density.reshape( (container.size, self.layers.max_layers)) container["densities"] = densities container["distances"] = distances self.data.unlink_containers() if self.calc_mode == "binned": self.data.link_containers("nue", ["nue_cc", "nue_nc"]) self.data.link_containers("numu", ["numu_cc", "numu_nc"]) self.data.link_containers("nutau", ["nutau_cc", "nutau_nc"]) self.data.link_containers("nuebar", ["nuebar_cc", "nuebar_nc"]) self.data.link_containers("numubar", ["numubar_cc", "numubar_nc"]) self.data.link_containers("nutaubar", ["nutaubar_cc", "nutaubar_nc"]) # setup more empty arrays for container in self.data: container["prob_e"] = np.empty((container.size), dtype=FTYPE) container["prob_mu"] = np.empty((container.size), dtype=FTYPE) self.data.unlink_containers() if self.exact_mode: return # --- containers for interpolated states --- # This is not needed in exact mode if self.calc_mode == "binned": self.data.link_containers("nu", [ "nue_cc", "numu_cc", "nutau_cc", "nue_nc", "numu_nc", "nutau_nc" ]) self.data.link_containers("nubar", [ "nuebar_cc", "numubar_cc", "nutaubar_cc", "nuebar_nc", "numubar_nc", "nutaubar_nc" ]) for container in self.data: container["interp_states_e"] = np.empty( (container.size, self.num_neutrinos**2), dtype=FTYPE, ) container["interp_states_mu"] = np.empty( (container.size, self.num_neutrinos**2), dtype=FTYPE, ) self.data.unlink_containers()
def setup_function(self): # object for oscillation parameters self.osc_params = OscParams() if self.reparam_mix_matrix: logging.debug( 'Working with reparameterizated version of mixing matrix.') else: logging.debug( 'Working with standard parameterization of mixing matrix.') if self.nsi_type == 'vacuum-like': logging.debug('Working in vacuum-like NSI parameterization.') self.nsi_params = VacuumLikeNSIParams() elif self.nsi_type == 'standard': logging.debug('Working in standard NSI parameterization.') self.nsi_params = StdNSIParams() # setup the layers #if self.params.earth_model.value is not None: earth_model = find_resource(self.params.earth_model.value) self.YeI = self.params.YeI.value.m_as('dimensionless') self.YeO = self.params.YeO.value.m_as('dimensionless') self.YeM = self.params.YeM.value.m_as('dimensionless') prop_height = self.params.prop_height.value.m_as('km') detector_depth = self.params.detector_depth.value.m_as('km') self.layers = Layers(earth_model, detector_depth, prop_height) self.layers.setElecFrac(self.YeI, self.YeO, self.YeM) # --- calculate the layers --- if self.is_map: # speed up calculation by adding links # as layers don't care about flavour self.data.link_containers('nu', [ 'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc', 'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc' ]) for container in self.data: self.layers.calcLayers(container['true_coszen']) container['densities'] = self.layers.density.reshape( (container.size, self.layers.max_layers)) container['distances'] = self.layers.distance.reshape( (container.size, self.layers.max_layers)) # don't forget to un-link everything again self.data.unlink_containers() # --- setup empty arrays --- if self.is_map: self.data.link_containers('nu', [ 'nue_cc', 'numu_cc', 'nutau_cc', 'nue_nc', 'numu_nc', 'nutau_nc' ]) self.data.link_containers('nubar', [ 'nuebar_cc', 'numubar_cc', 'nutaubar_cc', 'nuebar_nc', 'numubar_nc', 'nutaubar_nc' ]) for container in self.data: container['probability'] = np.empty((container.size, 3, 3), dtype=FTYPE) self.data.unlink_containers() # setup more empty arrays for container in self.data: container['prob_e'] = np.empty((container.size), dtype=FTYPE) container['prob_mu'] = np.empty((container.size), dtype=FTYPE)