def weighted_delta_tracking_no_absorption(lambda_): """ pg. 111:5, Algorithm 1. (rhs). Modified as per Sec. 5.1.3. Removal of volume absorption/emission events. """ sigma_t_majorante_lambda = ms.sigma_t_majorante[lambda_] x = 0. w = 1. while True: x += exp_sample(sigma_t_majorante_lambda) if x > ms.domain_length: return (x, 0.) else: sigma_s = ms.get_sigma_s(x)[lambda_] sigma_a = ms.get_sigma_a(x)[lambda_] sigma_n = sigma_t_majorante_lambda - sigma_s - sigma_a ps = sigma_s / (sigma_s + abs(sigma_n)) pn = abs(sigma_n) / (sigma_s + abs(sigma_n)) r = random.uniform(0.,1.) if r < ps: w *= sigma_s / sigma_t_majorante_lambda / ps * ms.get_integrand(x)[lambda_] return (x, w) else: w *= sigma_n / sigma_t_majorante_lambda / pn
def ratio_tracking(): """ pg. 111:16, Eq (41) """ sigma_t_majorante = ms.sigma_t_majorante_across_channels x = 0. weight = np.ones(2, np.float32) while True: x += exp_sample(sigma_t_majorante) if x > ms.domain_length: return weight else: sigma_s = ms.get_sigma_s(x) sigma_a = ms.get_sigma_a(x) sigma_n = sigma_t_majorante - sigma_s - sigma_a weight *= sigma_n / sigma_t_majorante
def single_lambda_ratio_tracking(lambda_): """ pg. 111:16, Eq (41) """ sigma_t_majorante_lambda = ms.sigma_t_majorante[lambda_] x = 0. weight = 1. while True: x += exp_sample(sigma_t_majorante_lambda) if x > ms.domain_length: return weight else: sigma_s = ms.get_sigma_s(x)[lambda_] sigma_a = ms.get_sigma_a(x)[lambda_] sigma_n = sigma_t_majorante_lambda - sigma_s - sigma_a weight *= sigma_n / sigma_t_majorante_lambda
def weighted_next_flight_estimator(): """ pg. 111:16, Eq (39) More variance than ratio tracking?! """ sigma_t_majorante = ms.sigma_t_majorante_across_channels x = 0. weight_product = np.ones(2, np.float32) weight = np.zeros(2, np.float32) while True: weight += np.exp(sigma_t_majorante * (x - ms.domain_length)) * weight_product x += exp_sample(sigma_t_majorante) if x > ms.domain_length: return weight else: sigma_s = ms.get_sigma_s(x) sigma_a = ms.get_sigma_a(x) sigma_n = sigma_t_majorante - sigma_s - sigma_a weight_product *= sigma_n / sigma_t_majorante
def delta_tracking(lambda_): """ pg. 111:5, Algorithm 1. (lhs). Although this is a very well known algorithm. Also known as woodcock tracking. """ sigma_t_majorante_lambda = ms.sigma_t_majorante[lambda_] x = 0. while True: x += exp_sample(sigma_t_majorante_lambda) if x > ms.domain_length: return (x, 0.) else: sigma_s = ms.get_sigma_s(x)[lambda_] sigma_a = ms.get_sigma_a(x)[lambda_] sigma_n = sigma_t_majorante_lambda - sigma_s - sigma_a r = random.uniform(0.,1.) if r < (sigma_a / sigma_t_majorante_lambda): return (x, 0.) elif r < (1. - (sigma_n / sigma_t_majorante_lambda)): return (x, ms.get_integrand(x)[lambda_]) else: pass # Null collision
def spectral_tracking_no_absorption(x = 0, weights = None): """ pg. 111:10, Algorithm 4. Modified as per Sec. 5.1.3. Removal of volume absorption/emission events. """ weights = weights.copy() if weights is not None else np.ones(2, np.float32) while True: x += exp_sample(ms.sigma_t_majorante_across_channels) if x > ms.domain_length: return (x, weights) else: sigma_s = ms.get_sigma_s(x) sigma_a = ms.get_sigma_a(x) sigma_n = ms.sigma_t_majorante_across_channels - sigma_s - sigma_a pt, pn = the_probability_scheme(weights, sigma_s, sigma_n) r = random.uniform(0.,1.) if r < pt: weights *= sigma_s / ms.sigma_t_majorante_across_channels * ms.get_integrand(x) / pt return (x, weights) else: weights *= sigma_n / ms.sigma_t_majorante_across_channels / pn
def spectral_tracking(): """ pg. 111:10, Algorithm 4 """ weights = np.ones(2, np.float32) x = 0. while True: x += exp_sample(ms.sigma_t_majorante_across_channels) if x > ms.domain_length: return (x, weights) else: sigma_s = ms.get_sigma_s(x) sigma_a = ms.get_sigma_a(x) sigma_n = ms.sigma_t_majorante_across_channels - sigma_s - sigma_a ps, pa, pn = the_probability_scheme(weights, sigma_s, sigma_a, sigma_n) r = random.uniform(0.,1.) if r < pa: return (x, np.zeros(2, np.float32)) elif r < 1. - pn: weights *= sigma_s / ms.sigma_t_majorante_across_channels * ms.get_integrand(x) / ps return (x, weights) else: weights *= sigma_n / ms.sigma_t_majorante_across_channels / pn
def construct_piecewise_constant_transmittance(): """ By ratio tracking. We have positions xi, and associated weight wi. If we want to obtain an estimate of the transmittance of some point y, T(y) we look up the next xi which comes afterwards and use the estimate T^(y) = wi. In expectation T^(y) equals the true transmittance T(y). """ sigma_t_majorante = ms.sigma_t_majorante_across_channels x = 0. weight = np.ones(2, np.float32) points_and_weights = [c_(x, weight)] while True: x += exp_sample(sigma_t_majorante) if x > ms.domain_length: points_and_weights += [c_(x,weight)] break else: points_and_weights += [c_(x, weight)] sigma_s = ms.get_sigma_s(x) sigma_a = ms.get_sigma_a(x) sigma_n = sigma_t_majorante - sigma_s - sigma_a weight *= sigma_n / sigma_t_majorante term_criterion = np.amax(weight) # Russian roulette termination. Otherwise I would have to traverse # through the entire domain which would be very inefficient if the # mean free path length is short r = random.uniform(0., 1.) survival_probability = term_criterion if r < survival_probability: # live on weight /= survival_probability else: points_and_weights += [c_(ms.domain_length*1.1,np.zeros_like(weight))] break return np.asarray(points_and_weights)