Source code for rayoptics.raytr.sampler

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright © 2020 Michael J. Hayford
"""Various generators and utilities for producing 2d distributions

.. Created on Tue Mar 24 21:14:31 2020

.. codeauthor: Michael J. Hayford
"""

import math
import numpy as np


[docs]def grid_ray_generator(grid_rng): """Generator function to produce a 2d square regular grid. arguments: grid_rng: start, stop, num start: 2d numpy array of lower left grid coords stop: 2d numpy array of upper right grid coords num: the number of samples along each axis A sample input might be: grid_start = np.array([-1., -1.]) grid_stop = np.array([1., 1.]) grid_rng = grid_start, grid_stop, num_rays """ start, stop, num = grid_rng sample_pt = np.array(start) step = np.array((stop - start)/(num - 1)) for i in range(num): for j in range(num): yield np.array(sample_pt) sample_pt[1] += step[1] sample_pt[0] += step[0] sample_pt[1] = start[1]
[docs]def csd_grid_ray_generator(grid_rng): start = np.array(grid_rng[0]) stop = grid_rng[1] num = grid_rng[2] step = np.array((stop - start)/(num - 1)) for i in range(num): for j in range(num): xy = concentric_sample_disk(start, offset=False) yield xy start[1] += step[1] start[0] += step[0] start[1] = grid_rng[0][1]
[docs]def polar_grid_ray_generator(grid_rng): start = np.array(grid_rng[0]) stop = grid_rng[1] num = grid_rng[2] step = np.array((stop - start)/(num - 1)) for i in range(num): for j in range(num): yield np.array(start) start[1] += step[1] start[0] += step[0] start[1] = grid_rng[0][1]
# Using the above nested radical formula for g=phi_d # or you could just hard-code it. # phi(1) = 1.61803398874989484820458683436563 # phi(2) = 1.32471795724474602596090885447809
[docs]def phi(d): x = 2.0000 for i in range(10): x = pow(1+x, 1/(d+1)) return x
[docs]def R_2_quasi_random_generator(n): """A 2d sequence based on a R**2 quasi-random sequence See `The Unreasonable Effectiveness of Quasirandom Sequences <http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/ >` """ d = 2 g = phi(d) alpha = np.zeros(d) for j in range(d): alpha[j] = pow(1/g, j+1) % 1 # This number can be any real number. # Common default setting is typically seed= # But seed = 0.5 is generally better. seed = 0.5 z = np.zeros((n, d)) for i in range(n): z[i] = (seed + alpha*(i+1)) % 1 yield z[i]
[docs]def concentric_sample_disk(u, offset=True): """Map a 2d unit square sample to the unit disk.""" if offset: uOffset = 2*u - np.array([1, 1]) else: uOffset = u if uOffset[0] == 0 and uOffset[1] == 0: return np.array([0, 0]) if abs(uOffset[0]) > abs(uOffset[1]): r = uOffset[0] theta = np.pi/4 * (uOffset[1]/uOffset[0]) else: r = uOffset[1] theta = np.pi/2 - np.pi/4 * (uOffset[0]/uOffset[1]) return r*np.array([math.cos(theta), math.sin(theta)])
[docs]def create_generator(sampler, *sampler_args, mapper=None, **kwargs): def gen(): for xy in sampler(*sampler_args): if mapper: yield mapper(xy, **kwargs) else: yield xy return gen()