def trace_packet(r_packet, numba_model, numba_plasma, estimators): """ Traces the RPacket through the ejecta and stops when an interaction happens (heart of the calculation) Parameters ---------- r_packet : tardis.montecarlo.montecarlo_numba.r_packet.RPacket numba_model : tardis.montecarlo.montecarlo_numba.numba_interface.NumbaModel numba_plasma : tardis.montecarlo.montecarlo_numba.numba_interface.NumbaPlasma estimators : tardis.montecarlo.montecarlo_numba.numba_interface.Estimators Returns ------- """ r_inner = numba_model.r_inner[r_packet.current_shell_id] r_outer = numba_model.r_outer[r_packet.current_shell_id] ( distance_boundary, delta_shell, ) = calculate_distance_boundary(r_packet.r, r_packet.mu, r_inner, r_outer) # defining start for line interaction start_line_id = r_packet.next_line_id # defining taus tau_event = -np.log(np.random.random()) tau_trace_line_combined = 0.0 # e scattering initialization cur_electron_density = numba_plasma.electron_density[ r_packet.current_shell_id] distance_electron = calculate_distance_electron(cur_electron_density, tau_event) # Calculating doppler factor doppler_factor = get_doppler_factor(r_packet.r, r_packet.mu, numba_model.time_explosion) comov_nu = r_packet.nu * doppler_factor cur_line_id = start_line_id # initializing varibale for Numba # - do not remove last_line_id = len(numba_plasma.line_list_nu) - 1 for cur_line_id in range(start_line_id, len(numba_plasma.line_list_nu)): # Going through the lines nu_line = numba_plasma.line_list_nu[cur_line_id] nu_line_last_interaction = numba_plasma.line_list_nu[cur_line_id - 1] # Getting the tau for the next line tau_trace_line = numba_plasma.tau_sobolev[cur_line_id, r_packet.current_shell_id] # Adding it to the tau_trace_line_combined tau_trace_line_combined += tau_trace_line # Calculating the distance until the current photons co-moving nu # redshifts to the line frequency is_last_line = cur_line_id == last_line_id distance_trace = calculate_distance_line( r_packet, comov_nu, is_last_line, nu_line, numba_model.time_explosion, ) # calculating the tau electron of how far the trace has progressed tau_trace_electron = calculate_tau_electron(cur_electron_density, distance_trace) # calculating the trace tau_trace_combined = tau_trace_line_combined + tau_trace_electron if ((distance_boundary <= distance_trace) and (distance_boundary <= distance_electron) ) and distance_trace != 0.0: interaction_type = InteractionType.BOUNDARY # BOUNDARY r_packet.next_line_id = cur_line_id distance = distance_boundary break if ((distance_electron < distance_trace) and (distance_electron < distance_boundary)) and distance_trace != 0.0: interaction_type = InteractionType.ESCATTERING # print('scattering') distance = distance_electron r_packet.next_line_id = cur_line_id break # Updating the J_b_lu and E_dot_lu # This means we are still looking for line interaction and have not # been kicked out of the path by boundary or electron interaction update_line_estimators( estimators, r_packet, cur_line_id, distance_trace, numba_model.time_explosion, ) if (tau_trace_combined > tau_event and not montecarlo_configuration.disable_line_scattering): interaction_type = InteractionType.LINE # Line r_packet.last_interaction_in_nu = r_packet.nu r_packet.last_line_interaction_in_id = cur_line_id r_packet.next_line_id = cur_line_id distance = distance_trace break if not is_last_line: test_for_close_line(r_packet, cur_line_id + 1, nu_line, numba_plasma) # Recalculating distance_electron using tau_event - # tau_trace_line_combined distance_electron = calculate_distance_electron( cur_electron_density, tau_event - tau_trace_line_combined) else: # Executed when no break occurs in the for loop # We are beyond the line list now and the only next thing is to see # if we are interacting with the boundary or electron scattering if cur_line_id == (len(numba_plasma.line_list_nu) - 1): # Treatment for last line cur_line_id += 1 if distance_electron < distance_boundary: distance = distance_electron interaction_type = InteractionType.ESCATTERING # print('scattering') else: distance = distance_boundary interaction_type = InteractionType.BOUNDARY # r_packet.next_line_id = cur_line_id return distance, interaction_type, delta_shell
def trace_vpacket_volley(r_packet, vpacket_collection, numba_model, numba_plasma): """ Shoot a volley of vpackets (the vpacket collection specifies how many) from the current position of the rpacket. Parameters ---------- r_packet : [type] [description] vpacket_collection : [type] [description] numba_model : [type] [description] numba_plasma : [type] [description] """ if (r_packet.nu < vpacket_collection.v_packet_spawn_start_frequency) or ( r_packet.nu > vpacket_collection.v_packet_spawn_end_frequency): return no_of_vpackets = vpacket_collection.number_of_vpackets if no_of_vpackets == 0: return ### TODO theoretical check for r_packet nu within vpackets bins - is done somewhere else I think if r_packet.r > numba_model.r_inner[0]: # not on inner_boundary r_inner_over_r = numba_model.r_inner[0] / r_packet.r mu_min = -math.sqrt(1 - r_inner_over_r * r_inner_over_r) v_packet_on_inner_boundary = False if montecarlo_configuration.full_relativity: mu_min = angle_aberration_LF_to_CMF(r_packet, numba_model.time_explosion, mu_min) else: v_packet_on_inner_boundary = True mu_min = 0.0 mu_bin = (1.0 - mu_min) / no_of_vpackets r_packet_doppler_factor = get_doppler_factor(r_packet.r, r_packet.mu, numba_model.time_explosion) for i in range(no_of_vpackets): v_packet_mu = mu_min + i * mu_bin + np.random.random() * mu_bin if v_packet_on_inner_boundary: # The weights are described in K&S 2014 weight = 2 * v_packet_mu / no_of_vpackets else: weight = (1 - mu_min) / (2 * no_of_vpackets) # C code: next line, angle_aberration_CMF_to_LF( & virt_packet, storage); if montecarlo_configuration.full_relativity: v_packet_mu = angle_aberration_CMF_to_LF( r_packet, numba_model.time_explosion, v_packet_mu) v_packet_doppler_factor = get_doppler_factor( r_packet.r, v_packet_mu, numba_model.time_explosion) # transform between r_packet mu and v_packet_mu doppler_factor_ratio = r_packet_doppler_factor / v_packet_doppler_factor v_packet_nu = r_packet.nu * doppler_factor_ratio v_packet_energy = r_packet.energy * weight * doppler_factor_ratio v_packet = VPacket( r_packet.r, v_packet_mu, v_packet_nu, v_packet_energy, r_packet.current_shell_id, r_packet.next_line_id, i, ) tau_vpacket = trace_vpacket(v_packet, numba_model, numba_plasma) v_packet.energy *= math.exp(-tau_vpacket) vpacket_collection.set_properties( v_packet.nu, v_packet.energy, v_packet_mu, r_packet.r, r_packet.last_interaction_in_nu, r_packet.last_interaction_type, r_packet.last_line_interaction_in_id, r_packet.last_line_interaction_out_id, )
def single_packet_loop( r_packet, numba_model, numba_plasma, estimators, vpacket_collection, rpacket_tracker, ): """ Parameters ---------- r_packet : tardis.montecarlo.montecarlo_numba.r_packet.RPacket numba_model : tardis.montecarlo.montecarlo_numba.numba_interface.NumbaModel numba_plasma : tardis.montecarlo.montecarlo_numba.numba_interface.NumbaPlasma estimators : tardis.montecarlo.montecarlo_numba.numba_interface.Estimators vpacket_collection : tardis.montecarlo.montecarlo_numba.numba_interface.VPacketCollection rpacket_collection : tardis.montecarlo.montecarlo_numba.numba_interface.RPacketCollection Returns ------- None This function does not return anything but changes the r_packet object and if virtual packets are requested - also updates the vpacket_collection """ line_interaction_type = montecarlo_configuration.line_interaction_type if montecarlo_configuration.full_relativity: set_packet_props_full_relativity(r_packet, numba_model) else: set_packet_props_partial_relativity(r_packet, numba_model) r_packet.initialize_line_id(numba_plasma, numba_model) trace_vpacket_volley( r_packet, vpacket_collection, numba_model, numba_plasma ) if montecarlo_configuration.RPACKET_TRACKING: rpacket_tracker.track(r_packet) # this part of the code is temporary and will be better incorporated while r_packet.status == PacketStatus.IN_PROCESS: # Compute continuum quantities # trace packet (takes opacities) doppler_factor = get_doppler_factor( r_packet.r, r_packet.mu, numba_model.time_explosion ) comov_nu = r_packet.nu * doppler_factor chi_e = chi_electron_calculator( numba_plasma, comov_nu, r_packet.current_shell_id ) if montecarlo_configuration.CONTINUUM_PROCESSES_ENABLED: ( chi_bf_tot, chi_bf_contributions, current_continua, x_sect_bfs, chi_ff, ) = chi_continuum_calculator( numba_plasma, comov_nu, r_packet.current_shell_id ) chi_continuum = chi_e + chi_bf_tot + chi_ff escat_prob = chi_e / chi_continuum # probability of e-scatter distance, interaction_type, delta_shell = trace_packet_continuum( r_packet, numba_model, numba_plasma, estimators, chi_continuum, escat_prob, ) update_bound_free_estimators( comov_nu, r_packet.energy * doppler_factor, r_packet.current_shell_id, distance, estimators, numba_plasma.t_electrons[r_packet.current_shell_id], x_sect_bfs, current_continua, numba_plasma.bf_threshold_list_nu, ) else: escat_prob = 1.0 chi_continuum = chi_e distance, interaction_type, delta_shell = trace_packet_continuum( r_packet, numba_model, numba_plasma, estimators, chi_continuum, escat_prob, ) # If continuum processes: update continuum estimators if interaction_type == InteractionType.BOUNDARY: move_r_packet( r_packet, distance, numba_model.time_explosion, estimators ) move_packet_across_shell_boundary( r_packet, delta_shell, len(numba_model.r_inner) ) elif interaction_type == InteractionType.LINE: r_packet.last_interaction_type = 2 move_r_packet( r_packet, distance, numba_model.time_explosion, estimators ) line_scatter( r_packet, numba_model.time_explosion, line_interaction_type, numba_plasma, ) trace_vpacket_volley( r_packet, vpacket_collection, numba_model, numba_plasma ) elif interaction_type == InteractionType.ESCATTERING: r_packet.last_interaction_type = 1 move_r_packet( r_packet, distance, numba_model.time_explosion, estimators ) thomson_scatter(r_packet, numba_model.time_explosion) trace_vpacket_volley( r_packet, vpacket_collection, numba_model, numba_plasma ) elif ( montecarlo_configuration.CONTINUUM_PROCESSES_ENABLED and interaction_type == InteractionType.CONTINUUM_PROCESS ): r_packet.last_interaction_type = InteractionType.CONTINUUM_PROCESS move_r_packet( r_packet, distance, numba_model.time_explosion, estimators ) continuum_event( r_packet, numba_model.time_explosion, numba_plasma, chi_bf_tot, chi_ff, chi_bf_contributions, current_continua, ) trace_vpacket_volley( r_packet, vpacket_collection, numba_model, numba_plasma ) else: pass if montecarlo_configuration.RPACKET_TRACKING: rpacket_tracker.track(r_packet)
def trace_packet_continuum(r_packet, numba_model, numba_plasma, estimators, chi_continuum, escat_prob): """ Traces the RPacket through the ejecta and stops when an interaction happens (heart of the calculation) Parameters ---------- r_packet : tardis.montecarlo.montecarlo_numba.r_packet.RPacket numba_model : tardis.montecarlo.montecarlo_numba.numba_interface.NumbaModel numba_plasma : tardis.montecarlo.montecarlo_numba.numba_interface.NumbaPlasma estimators : tardis.montecarlo.montecarlo_numba.numba_interface.Estimators Returns ------- """ r_inner = numba_model.r_inner[r_packet.current_shell_id] r_outer = numba_model.r_outer[r_packet.current_shell_id] ( distance_boundary, delta_shell, ) = calculate_distance_boundary(r_packet.r, r_packet.mu, r_inner, r_outer) # defining start for line interaction start_line_id = r_packet.next_line_id # defining taus tau_event = -np.log(np.random.random()) tau_trace_line_combined = 0.0 # Calculating doppler factor doppler_factor = get_doppler_factor(r_packet.r, r_packet.mu, numba_model.time_explosion) comov_nu = r_packet.nu * doppler_factor distance_continuum = tau_event / chi_continuum cur_line_id = start_line_id # initializing varibale for Numba # - do not remove last_line_id = len(numba_plasma.line_list_nu) - 1 for cur_line_id in range(start_line_id, len(numba_plasma.line_list_nu)): # Going through the lines nu_line = numba_plasma.line_list_nu[cur_line_id] # Getting the tau for the next line tau_trace_line = numba_plasma.tau_sobolev[cur_line_id, r_packet.current_shell_id] # Adding it to the tau_trace_line_combined tau_trace_line_combined += tau_trace_line # Calculating the distance until the current photons co-moving nu # redshifts to the line frequency is_last_line = cur_line_id == last_line_id distance_trace = calculate_distance_line( r_packet, comov_nu, is_last_line, nu_line, numba_model.time_explosion, ) # calculating the tau continuum of how far the trace has progressed tau_trace_continuum = chi_continuum * distance_trace # calculating the trace tau_trace_combined = tau_trace_line_combined + tau_trace_continuum distance = min(distance_trace, distance_boundary, distance_continuum) if distance_trace != 0: if distance == distance_boundary: interaction_type = InteractionType.BOUNDARY # BOUNDARY r_packet.next_line_id = cur_line_id break elif distance == distance_continuum: if not montecarlo_configuration.CONTINUUM_PROCESSES_ENABLED: interaction_type = InteractionType.ESCATTERING else: zrand = np.random.random() if zrand < escat_prob: interaction_type = InteractionType.ESCATTERING else: interaction_type = InteractionType.CONTINUUM_PROCESS r_packet.next_line_id = cur_line_id break # Updating the J_b_lu and E_dot_lu # This means we are still looking for line interaction and have not # been kicked out of the path by boundary or electron interaction update_line_estimators( estimators, r_packet, cur_line_id, distance_trace, numba_model.time_explosion, ) if (tau_trace_combined > tau_event and not montecarlo_configuration.disable_line_scattering): interaction_type = InteractionType.LINE # Line r_packet.last_interaction_in_nu = r_packet.nu r_packet.last_line_interaction_in_id = cur_line_id r_packet.next_line_id = cur_line_id distance = distance_trace break # Recalculating distance_continuum using tau_event - # tau_trace_line_combined # I don't think this needs to be updated # since tau_event is already the result of the integral # from the initial line distance_continuum = (tau_event - tau_trace_line_combined) / (chi_continuum) else: # Executed when no break occurs in the for loop # We are beyond the line list now and the only next thing is to see # if we are interacting with the boundary or electron scattering if cur_line_id == (len(numba_plasma.line_list_nu) - 1): # Treatment for last line cur_line_id += 1 if distance_continuum < distance_boundary: distance = distance_continuum if not montecarlo_configuration.CONTINUUM_PROCESSES_ENABLED: interaction_type = InteractionType.ESCATTERING else: zrand = np.random.random() if zrand < escat_prob: interaction_type = InteractionType.ESCATTERING else: interaction_type = InteractionType.CONTINUUM_PROCESS else: distance = distance_boundary interaction_type = InteractionType.BOUNDARY return distance, interaction_type, delta_shell