diff --git a/setup.cfg b/setup.cfg index 1e1cbd3..0009b5d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -108,7 +108,7 @@ formats = bdist_wheel [flake8] # Some sane defaults for the code style checker flake8 max_line_length = 88 -extend_ignore = E203, W503 +extend_ignore = E203, W503, E501 # ^ Black-compatible # E203 and W503 have edge cases handled by black exclude = diff --git a/src/polyphy/core/common.py b/src/polyphy/core/common.py index 7424ba3..fcedc80 100644 --- a/src/polyphy/core/common.py +++ b/src/polyphy/core/common.py @@ -39,8 +39,7 @@ def set_precision(float_precision): PPTypes.FLOAT_CPU = np.float16 PPTypes.FLOAT_GPU = ti.f16 else: - raise ValueError("Invalid float precision value. Supported values: \ - float64, float32, float16") + raise ValueError("Invalid float precision value. Supported values: float64, float32, float16") class PPConfig: diff --git a/src/polyphy/core/discrete2D.py b/src/polyphy/core/discrete2D.py index 2067af0..44396b8 100644 --- a/src/polyphy/core/discrete2D.py +++ b/src/polyphy/core/discrete2D.py @@ -21,20 +21,16 @@ def register_data(self, ppData): self.ppData = ppData self.TRACE_RESOLUTION_MAX = 1440 self.DATA_TO_AGENTS_RATIO = ( - PPTypes.FLOAT_CPU(ppData.N_DATA) / - PPTypes.FLOAT_CPU(ppData.N_AGENTS) + PPTypes.FLOAT_CPU(ppData.N_DATA) / PPTypes.FLOAT_CPU(ppData.N_AGENTS) ) self.DOMAIN_SIZE_MAX = np.max([ppData.DOMAIN_SIZE[0], ppData.DOMAIN_SIZE[1]]) - self.TRACE_RESOLUTION = PPTypes.INT_CPU( - (PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[0] / - self.DOMAIN_SIZE_MAX, PPTypes.FLOAT_CPU( - self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[1] / - self.DOMAIN_SIZE_MAX) - ) + self.TRACE_RESOLUTION = PPTypes.INT_CPU(( + PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[0] / self.DOMAIN_SIZE_MAX, + PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[1] / self.DOMAIN_SIZE_MAX + )) self.DEPOSIT_RESOLUTION = ( - self.TRACE_RESOLUTION[0] // - PPConfig.DEPOSIT_DOWNSCALING_FACTOR, self.TRACE_RESOLUTION[1] // - PPConfig.DEPOSIT_DOWNSCALING_FACTOR + self.TRACE_RESOLUTION[0] // PPConfig.DEPOSIT_DOWNSCALING_FACTOR, + self.TRACE_RESOLUTION[1] // PPConfig.DEPOSIT_DOWNSCALING_FACTOR ) # Check if these are set and if not give them decent initial estimates @@ -65,12 +61,10 @@ def __load_from_file__(self): self.domain_min = (np.min(self.data[:, 0]), np.min(self.data[:, 1])) self.domain_max = (np.max(self.data[:, 0]), np.max(self.data[:, 1])) self.domain_size = np.subtract(self.domain_max, self.domain_min) - self.DOMAIN_MIN = (self.domain_min[0] - PPConfig.DOMAIN_MARGIN * - self.domain_size[0], self.domain_min[1] - - PPConfig.DOMAIN_MARGIN * self.domain_size[1]) - self.DOMAIN_MAX = (self.domain_max[0] + PPConfig.DOMAIN_MARGIN * - self.domain_size[0], self.domain_max[1] + - PPConfig.DOMAIN_MARGIN * self.domain_size[1]) + self.DOMAIN_MIN = (self.domain_min[0] - PPConfig.DOMAIN_MARGIN * self.domain_size[0], + self.domain_min[1] - PPConfig.DOMAIN_MARGIN * self.domain_size[1]) + self.DOMAIN_MAX = (self.domain_max[0] + PPConfig.DOMAIN_MARGIN * self.domain_size[0], + self.domain_max[1] + PPConfig.DOMAIN_MARGIN * self.domain_size[1]) self.DOMAIN_SIZE = np.subtract(self.DOMAIN_MAX, self.DOMAIN_MIN) self.AVG_WEIGHT = np.mean(self.data[:, 2]) @@ -83,12 +77,12 @@ def __generate_test_data__(self, rng): self.DOMAIN_MIN = (0.0, 0.0) self.DOMAIN_MAX = (PPConfig.DOMAIN_SIZE_DEFAULT, PPConfig.DOMAIN_SIZE_DEFAULT) self.data = np.zeros(shape=(self.N_DATA, 3), dtype=PPTypes.FLOAT_CPU) - self.data[:, 0] = rng.normal(loc=self.DOMAIN_MIN[0] + 0.5 * - self.DOMAIN_MAX[0], scale=0.13 * - self.DOMAIN_SIZE[0], size=self.N_DATA) - self.data[:, 1] = rng.normal(loc=self.DOMAIN_MIN[1] + 0.5 * - self.DOMAIN_MAX[1], scale=0.13 * - self.DOMAIN_SIZE[1], size=self.N_DATA) + self.data[:, 0] = rng.normal(loc=self.DOMAIN_MIN[0] + 0.5 * self.DOMAIN_MAX[0], + scale=0.13 * self.DOMAIN_SIZE[0], + size=self.N_DATA) + self.data[:, 1] = rng.normal(loc=self.DOMAIN_MIN[1] + 0.5 * self.DOMAIN_MAX[1], + scale=0.13 * self.DOMAIN_SIZE[1], + size=self.N_DATA) self.data[:, 2] = np.mean(self.data[:, 2]) @@ -139,7 +133,8 @@ def __init__(self, rng, ppKernels, ppConfig): self.agents[:, 1] = rng.uniform(low=ppConfig.ppData.DOMAIN_MIN[1] + 0.001, high=ppConfig.ppData.DOMAIN_MAX[1] - 0.001, size=ppConfig.ppData.N_AGENTS) - self.agents[:, 2] = rng.uniform(low=0.0, high=2.0 * np.pi, + self.agents[:, 2] = rng.uniform(low=0.0, + high=2.0 * np.pi, size=ppConfig.ppData.N_AGENTS) self.agents[:, 3] = 1.0 Logger.logToStdOut("info", 'Agent sample:', self.agents[0, :]) @@ -155,16 +150,9 @@ def __init__(self, rng, ppKernels, ppConfig): self.vis_field = ti.Vector.field(n=3, dtype=PPTypes.FLOAT_GPU, shape=ppConfig.VIS_RESOLUTION) Logger.logToStdOut("info", 'Total GPU memory allocated:', - PPTypes.INT_CPU(4 * (self.data_field.shape[0] * 3 + - self.agents_field.shape[0] * 4 + - self.deposit_field.shape[0] * - self.deposit_field.shape[1] * 2 + - self.trace_field.shape[0] * - self.trace_field.shape[1] * 1 + - self.vis_field.shape[0] * - self.vis_field.shape[1] * 3 - ) / 2 ** 20), 'MB') - + PPTypes.INT_CPU( + 4 * (self.data_field.shape[0] * 3 + self.agents_field.shape[0] * 4 + self.deposit_field.shape[0] * self.deposit_field.shape[1] * 2 + self.trace_field.shape[0] * self.trace_field.shape[1] * 1 + self.vis_field.shape[0] * self.vis_field.shape[1] * 3 + ) / 2 ** 20), 'MB') self.ppConfig = ppConfig self.ppKernels = ppKernels self.__init_internal_data__(ppKernels) diff --git a/src/polyphy/core/discrete3D.py b/src/polyphy/core/discrete3D.py index 1c97a95..bfde1ae 100644 --- a/src/polyphy/core/discrete3D.py +++ b/src/polyphy/core/discrete3D.py @@ -25,12 +25,9 @@ def register_data(self, ppData): self.DOMAIN_SIZE_MAX = np.max( [ppData.DOMAIN_SIZE[0], ppData.DOMAIN_SIZE[1], ppData.DOMAIN_SIZE[2]]) self.TRACE_RESOLUTION = PPTypes.INT_CPU(( - PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[0] / - self.DOMAIN_SIZE_MAX, - PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[1] / - self.DOMAIN_SIZE_MAX, - PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[2] / - self.DOMAIN_SIZE_MAX)) + PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[0] / self.DOMAIN_SIZE_MAX, + PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[1] / self.DOMAIN_SIZE_MAX, + PPTypes.FLOAT_CPU(self.TRACE_RESOLUTION_MAX) * ppData.DOMAIN_SIZE[2] / self.DOMAIN_SIZE_MAX)) self.DEPOSIT_RESOLUTION = ( self.TRACE_RESOLUTION[0] // PPConfig.DEPOSIT_DOWNSCALING_FACTOR, self.TRACE_RESOLUTION[1] // PPConfig.DEPOSIT_DOWNSCALING_FACTOR, @@ -138,12 +135,10 @@ def store_fit(self): Logger.logToStdOut("info", 'Storing solution data in data/fits/') deposit = self.deposit_field.to_numpy() np.save( - self.ppConfig.ppData.ROOT + 'data/fits/deposit_' + current_stamp + - '.npy', deposit) + self.ppConfig.ppData.ROOT + 'data/fits/deposit_' + current_stamp + '.npy', deposit) trace = self.trace_field.to_numpy() np.save( - self.ppConfig.ppData.ROOT + 'data/fits/trace_' + current_stamp + - '.npy', trace) + self.ppConfig.ppData.ROOT + 'data/fits/trace_' + current_stamp + '.npy', trace) return current_stamp, deposit, trace def __init__(self, rng, ppKernels, ppConfig): @@ -196,13 +191,8 @@ def __init__(self, rng, ppKernels, ppConfig): Logger.logToStdOut( "info", 'Total GPU memory allocated:', PPTypes.INT_CPU( - 4 * ( - self.data_field.shape[0] * 4 + - self.agents_field.shape[0] * 6 + - self.deposit_field.shape[0] * self.deposit_field.shape[1] * 2 + - self.trace_field.shape[0] * self.trace_field.shape[1] * 1 + - self.vis_field.shape[0] * self.vis_field.shape[1] * 3 - ) / 2 ** 20), 'MB') + 4 * (self.data_field.shape[0] * 4 + self.agents_field.shape[0] * 6 + self.deposit_field.shape[0] * self.deposit_field.shape[1] * 2 + self.trace_field.shape[0] * self.trace_field.shape[1] * 1 + self.vis_field.shape[0] * self.vis_field.shape[1] * 3 + ) / 2 ** 20), 'MB') self.ppConfig = ppConfig self.ppKernels = ppKernels self.__init_internal_data__(ppKernels) @@ -212,7 +202,11 @@ class PPSimulation_3DDiscrete(PPSimulation): def __drawGUI__(self, window, ppConfig): GuiHelper.draw(self, window, ppConfig) - def __init__(self, ppInternalData, ppConfig, batch_mode=False, num_iterations=-1): + def __init__(self, + ppInternalData, + ppConfig, + batch_mode=False, + num_iterations=-1): self.current_deposit_index = 0 self.do_export = False self.do_screenshot = False diff --git a/src/polyphy/kernel/common.py b/src/polyphy/kernel/common.py index 66bd308..b26fabe 100644 --- a/src/polyphy/kernel/common.py +++ b/src/polyphy/kernel/common.py @@ -26,8 +26,7 @@ def ray_AABB_intersection(self, ray_pos, ray_dir, AABB_min, AABB_max): t5 = (AABB_max[2] - ray_pos[2]) / ray_dir[2] t6 = ti.max(ti.max(ti.min(t0, t1), ti.min(t2, t3)), ti.min(t4, t5)) t7 = ti.min(ti.min(ti.max(t0, t1), ti.max(t2, t3)), ti.max(t4, t5)) - return PPTypes.VEC2f(-1.0, -1.0) if ( - t7 < 0.0 or t6 >= t7) else PPTypes.VEC2f(t6, t7) + return PPTypes.VEC2f(-1.0, -1.0) if (t7 < 0.0 or t6 >= t7) else PPTypes.VEC2f(t6, t7) # GPU kernels (callable by core classes via Taichi API) ======================== @ti.kernel diff --git a/src/polyphy/kernel/discrete2D.py b/src/polyphy/kernel/discrete2D.py index 4787078..a4d333f 100644 --- a/src/polyphy/kernel/discrete2D.py +++ b/src/polyphy/kernel/discrete2D.py @@ -81,31 +81,23 @@ def agent_step_2D_discrete( # Generate new mutated direction by perturbing the original dir_fwd = self.angle_to_dir_2D(angle) angle_mut = angle - if directional_sampling_distribution \ - == PPConfig.EnumDirectionalSamplingDistribution.DISCRETE: - angle_mut += ( - 1.0 if ti.random(dtype=PPTypes.FLOAT_GPU) > 0.5 else -1.0)\ - * sense_angle - elif directional_sampling_distribution \ - == PPConfig.EnumDirectionalSamplingDistribution.CONE: - angle_mut += 2.0 * (ti.random(dtype=PPTypes.FLOAT_GPU) - 0.5)\ - * sense_angle + if directional_sampling_distribution == PPConfig.EnumDirectionalSamplingDistribution.DISCRETE: + angle_mut += (1.0 if ti.random(dtype=PPTypes.FLOAT_GPU) > 0.5 else -1.0) * sense_angle + elif directional_sampling_distribution == PPConfig.EnumDirectionalSamplingDistribution.CONE: + angle_mut += 2.0 * (ti.random(dtype=PPTypes.FLOAT_GPU) - 0.5) * sense_angle dir_mut = self.angle_to_dir_2D(angle_mut) # Generate sensing distance for the agent, constant or probabilistic agent_sensing_distance = sense_distance distance_scaling_factor = 1.0 - if distance_sampling_distribution \ - == PPConfig.EnumDistanceSamplingDistribution.EXPONENTIAL: + if distance_sampling_distribution == PPConfig.EnumDistanceSamplingDistribution.EXPONENTIAL: xi = timath.clamp(ti.random(dtype=PPTypes.FLOAT_GPU), 0.001, 0.999) # log & pow are unstable in extremes distance_scaling_factor = -ti.log(xi) - elif distance_sampling_distribution \ - == PPConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN: + elif distance_sampling_distribution == PPConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN: xi = timath.clamp(ti.random(dtype=PPTypes.FLOAT_GPU), 0.001, 0.999) # log & pow are unstable in extremes - distance_scaling_factor = -0.3033 * ti.log( - (ti.pow(xi + 0.005, -0.4) - 0.9974) / 7.326) + distance_scaling_factor = -0.3033 * ti.log((ti.pow(xi + 0.005, -0.4) - 0.9974) / 7.326) agent_sensing_distance *= distance_scaling_factor # Fetch deposit to guide the agent @@ -113,54 +105,40 @@ def agent_step_2D_discrete( deposit_mut = 0.0 if deposit_fetching_strategy == PPConfig.EnumDepositFetchingStrategy.NN: deposit_fwd = deposit_field[self.world_to_grid_2D( - pos + agent_sensing_distance * dir_fwd, PPTypes.VEC2f(DOMAIN_MIN), + pos + agent_sensing_distance * dir_fwd, + PPTypes.VEC2f(DOMAIN_MIN), PPTypes.VEC2f(DOMAIN_MAX), PPTypes.VEC2i(DEPOSIT_RESOLUTION))][current_deposit_index] deposit_mut = deposit_field[self.world_to_grid_2D( pos + agent_sensing_distance * dir_mut, - PPTypes.VEC2f(DOMAIN_MIN), PPTypes.VEC2f(DOMAIN_MAX), + PPTypes.VEC2f(DOMAIN_MIN), + PPTypes.VEC2f(DOMAIN_MAX), PPTypes.VEC2i(DEPOSIT_RESOLUTION))][current_deposit_index] - elif deposit_fetching_strategy \ - == PPConfig.EnumDepositFetchingStrategy.NN_PERTURBED: + elif deposit_fetching_strategy == PPConfig.EnumDepositFetchingStrategy.NN_PERTURBED: # Fetches the deposit by perturbing the original position by small delta # Provides cheap stochastic filtering instead of multi-fetch filters - field_dd = 2.0 * ti.cast(DOMAIN_SIZE[0], PPTypes.FLOAT_GPU) / \ - ti.cast(DEPOSIT_RESOLUTION[0], PPTypes.FLOAT_GPU) - pos_fwd = pos + agent_sensing_distance * dir_fwd + ( - field_dd * ti.random(dtype=PPTypes.FLOAT_GPU) * - self.angle_to_dir_2D(2.0 * timath.pi * - ti.random(dtype=PPTypes.FLOAT_GPU))) + field_dd = 2.0 * ti.cast(DOMAIN_SIZE[0], PPTypes.FLOAT_GPU) / ti.cast(DEPOSIT_RESOLUTION[0], PPTypes.FLOAT_GPU) + pos_fwd = pos + agent_sensing_distance * dir_fwd + (field_dd * ti.random(dtype=PPTypes.FLOAT_GPU) * self.angle_to_dir_2D(2.0 * timath.pi * ti.random(dtype=PPTypes.FLOAT_GPU))) deposit_fwd = deposit_field[self.world_to_grid_2D( pos_fwd, PPTypes.VEC2f(DOMAIN_MIN), PPTypes.VEC2f(DOMAIN_MAX), PPTypes.VEC2i(DEPOSIT_RESOLUTION))][current_deposit_index] - pos_mut = pos + agent_sensing_distance * dir_mut + ( - field_dd * ti.random(dtype=PPTypes.FLOAT_GPU) * - self.angle_to_dir_2D(2.0 * timath.pi * - ti.random(dtype=PPTypes.FLOAT_GPU))) + pos_mut = pos + agent_sensing_distance * dir_mut + (field_dd * ti.random(dtype=PPTypes.FLOAT_GPU) * self.angle_to_dir_2D(2.0 * timath.pi * ti.random(dtype=PPTypes.FLOAT_GPU))) deposit_mut = deposit_field[self.world_to_grid_2D( - pos_mut, PPTypes.VEC2f(DOMAIN_MIN), + pos_mut, + PPTypes.VEC2f(DOMAIN_MIN), PPTypes.VEC2f(DOMAIN_MAX), PPTypes.VEC2i(DEPOSIT_RESOLUTION))][current_deposit_index] # Generate new direction for the agent based on the sampled deposit angle_new = angle - if directional_mutation_type \ - == PPConfig.EnumDirectionalMutationType.DETERMINISTIC: - angle_new = ( - steering_rate * angle_mut + (1.0-steering_rate) * angle) if ( - deposit_mut > deposit_fwd) else ( - angle) - elif directional_mutation_type \ - == PPConfig.EnumDirectionalMutationType.PROBABILISTIC: + if directional_mutation_type == PPConfig.EnumDirectionalMutationType.DETERMINISTIC: + angle_new = (steering_rate * angle_mut + (1.0-steering_rate) * angle) if (deposit_mut > deposit_fwd) else (angle) + elif directional_mutation_type == PPConfig.EnumDirectionalMutationType.PROBABILISTIC: p_remain = ti.pow(deposit_fwd, sampling_exponent) p_mutate = ti.pow(deposit_mut, sampling_exponent) mutation_probability = p_mutate / (p_remain + p_mutate) - angle_new = ( - steering_rate * angle_mut + (1.0-steering_rate) * angle) if ( - ti.random( - dtype=PPTypes.FLOAT_GPU) < mutation_probability) else ( - angle) + angle_new = (steering_rate * angle_mut + (1.0-steering_rate) * angle) if (ti.random(dtype=PPTypes.FLOAT_GPU) < mutation_probability) else (angle) dir_new = self.angle_to_dir_2D(angle_new) pos_new = pos + step_size * distance_scaling_factor * dir_new @@ -172,33 +150,30 @@ def agent_step_2D_discrete( pos_new[1] = self.custom_mod( pos_new[1] - DOMAIN_MIN[1] + DOMAIN_SIZE[1], DOMAIN_SIZE[1]) + DOMAIN_MIN[1] - elif agent_boundary_handling \ - == PPConfig.EnumAgentBoundaryHandling.REINIT_CENTER: + elif agent_boundary_handling == PPConfig.EnumAgentBoundaryHandling.REINIT_CENTER: if pos_new[0] <= DOMAIN_MIN[0] \ or pos_new[0] >= DOMAIN_MAX[0] \ or pos_new[1] <= DOMAIN_MIN[1] \ or pos_new[1] >= DOMAIN_MAX[1]: pos_new[0] = 0.5 * (DOMAIN_MIN[0] + DOMAIN_MAX[0]) pos_new[1] = 0.5 * (DOMAIN_MIN[1] + DOMAIN_MAX[1]) - elif agent_boundary_handling \ - == PPConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY: + elif agent_boundary_handling == PPConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY: if pos_new[0] <= DOMAIN_MIN[0] \ or pos_new[0] >= DOMAIN_MAX[0] \ or pos_new[1] <= DOMAIN_MIN[1] \ or pos_new[1] >= DOMAIN_MAX[1]: pos_new[0] = DOMAIN_MIN[0] + timath.clamp( - ti.random(dtype=PPTypes.FLOAT_GPU), - 0.001, 0.999) * DOMAIN_SIZE[0] + ti.random(dtype=PPTypes.FLOAT_GPU), 0.001, 0.999) * DOMAIN_SIZE[0] pos_new[1] = DOMAIN_MIN[1] + timath.clamp( - ti.random(dtype=PPTypes.FLOAT_GPU), - 0.001, 0.999) * DOMAIN_SIZE[1] + ti.random(dtype=PPTypes.FLOAT_GPU), 0.001, 0.999) * DOMAIN_SIZE[1] agents_field[agent][0] = pos_new[0] agents_field[agent][1] = pos_new[1] agents_field[agent][2] = angle_new # Generate deposit and trace at the new position - deposit_cell = self.world_to_grid_2D(pos_new, PPTypes.VEC2f(DOMAIN_MIN), + deposit_cell = self.world_to_grid_2D(pos_new, + PPTypes.VEC2f(DOMAIN_MIN), PPTypes.VEC2f(DOMAIN_MAX), PPTypes.VEC2i(DEPOSIT_RESOLUTION)) deposit_field[deposit_cell][current_deposit_index] += agent_deposit * weight @@ -249,8 +224,7 @@ def trace_relaxation_step_2D_discrete( for cell in ti.grouped(trace_field): # Perturb the attenuation by a small factor # to avoid accumulating quantization errors - trace_field[cell][0] *= ( - attenuation - 0.001 + 0.002 * ti.random(dtype=PPTypes.FLOAT_GPU)) + trace_field[cell][0] *= (attenuation - 0.001 + 0.002 * ti.random(dtype=PPTypes.FLOAT_GPU)) return @ti.kernel @@ -276,6 +250,5 @@ def render_visualization_2D_discrete( PPTypes.VEC3f( trace_vis * trace_val, deposit_vis * deposit_val, - ti.pow(ti.log(1.0 + 0.2 * trace_vis * trace_val), - 3.0)), 1.0/2.2) + ti.pow(ti.log(1.0 + 0.2 * trace_vis * trace_val), 3.0)), 1.0/2.2) return diff --git a/src/polyphy/kernel/discrete3D.py b/src/polyphy/kernel/discrete3D.py index 2a32eff..171985b 100644 --- a/src/polyphy/kernel/discrete3D.py +++ b/src/polyphy/kernel/discrete3D.py @@ -21,11 +21,10 @@ def world_to_grid_3D( grid_resolution) -> PPTypes.VEC3i: pos_relative = (pos_world - domain_min) / (domain_max - domain_min) grid_coord = ti.cast( - pos_relative * ti.cast(grid_resolution, - PPTypes.FLOAT_GPU), PPTypes.INT_GPU) - return ti.max( - PPTypes.VEC3i(0, 0, 0), - ti.min(grid_coord, grid_resolution - (1, 1, 1))) + pos_relative * ti.cast( + grid_resolution, + PPTypes.FLOAT_GPU), PPTypes.INT_GPU) + return ti.max(PPTypes.VEC3i(0, 0, 0), ti.min(grid_coord, grid_resolution - (1, 1, 1))) @ti.func def angles_to_dir_3D(self, theta, phi) -> PPTypes.VEC3f: @@ -97,40 +96,37 @@ def agent_step_3D_discrete( # Generate sensing distance for the agent, constant or probabilistic agent_sensing_distance = sense_distance distance_scaling_factor = 1.0 - if distance_sampling_distribution \ - == PPConfig.EnumDistanceSamplingDistribution.EXPONENTIAL: + if distance_sampling_distribution == PPConfig.EnumDistanceSamplingDistribution.EXPONENTIAL: xi = timath.clamp(ti.random(dtype=PPTypes.FLOAT_GPU), 0.001, 0.999) # log & pow are unstable in extremes distance_scaling_factor = -ti.log(xi) - elif distance_sampling_distribution \ - == PPConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN: + elif distance_sampling_distribution == PPConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN: xi = timath.clamp(ti.random(dtype=PPTypes.FLOAT_GPU), 0.001, 0.999) # log & pow are unstable in extremes - distance_scaling_factor = -0.3033 * ti.log( - (ti.pow(xi + 0.005, -0.4) - 0.9974) / 7.326) + distance_scaling_factor = -0.3033 * ti.log((ti.pow(xi + 0.005, -0.4) - 0.9974) / 7.326) agent_sensing_distance *= distance_scaling_factor # Generate new mutated direction by perturbing the original # TODO implement the other sampling strategies dir_fwd = self.angles_to_dir_3D(theta, phi) xi_dir = 1.0 - if directional_sampling_distribution \ - == PPConfig.EnumDirectionalSamplingDistribution.CONE: + if directional_sampling_distribution == PPConfig.EnumDirectionalSamplingDistribution.CONE: xi_dir = ti.random(dtype=PPTypes.FLOAT_GPU) theta_sense = theta - xi_dir * sense_angle off_fwd_dir = self.angles_to_dir_3D(theta_sense, phi) - random_azimuth = ti.random( - dtype=PPTypes.FLOAT_GPU) * 2.0 * timath.pi - timath.pi + random_azimuth = ti.random(dtype=PPTypes.FLOAT_GPU) * 2.0 * timath.pi - timath.pi dir_mut = self.axial_rotate_3D(off_fwd_dir, dir_fwd, random_azimuth) # Fetch deposit to guide the agent # TODO implement the other mutation strategies deposit_fwd = deposit_field[self.world_to_grid_3D( - pos + agent_sensing_distance * dir_fwd, PPTypes.VEC3f(DOMAIN_MIN), + pos + agent_sensing_distance * dir_fwd, + PPTypes.VEC3f(DOMAIN_MIN), PPTypes.VEC3f(DOMAIN_MAX), PPTypes.VEC3i(DEPOSIT_RESOLUTION))][current_deposit_index] deposit_mut = deposit_field[self.world_to_grid_3D( - pos + agent_sensing_distance * dir_mut, PPTypes.VEC3f(DOMAIN_MIN), + pos + agent_sensing_distance * dir_mut, + PPTypes.VEC3f(DOMAIN_MIN), PPTypes.VEC3f(DOMAIN_MAX), PPTypes.VEC3i(DEPOSIT_RESOLUTION))][current_deposit_index] @@ -160,8 +156,7 @@ def agent_step_3D_discrete( pos_new[2] = self.custom_mod( pos_new[2] - DOMAIN_MIN[2] + DOMAIN_SIZE[2], DOMAIN_SIZE[2]) + DOMAIN_MIN[2] - elif agent_boundary_handling \ - == PPConfig.EnumAgentBoundaryHandling.REINIT_CENTER: + elif agent_boundary_handling == PPConfig.EnumAgentBoundaryHandling.REINIT_CENTER: if pos_new[0] <= DOMAIN_MIN[0] \ or pos_new[0] >= DOMAIN_MAX[0] \ or pos_new[1] <= DOMAIN_MIN[1] \ @@ -171,8 +166,7 @@ def agent_step_3D_discrete( pos_new[0] = 0.5 * (DOMAIN_MIN[0] + DOMAIN_MAX[0]) pos_new[1] = 0.5 * (DOMAIN_MIN[1] + DOMAIN_MAX[1]) pos_new[2] = 0.5 * (DOMAIN_MIN[2] + DOMAIN_MAX[2]) - elif agent_boundary_handling \ - == PPConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY: + elif agent_boundary_handling == PPConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY: if pos_new[0] <= DOMAIN_MIN[0] \ or pos_new[0] >= DOMAIN_MAX[0] \ or pos_new[1] <= DOMAIN_MIN[1] \ @@ -288,17 +282,8 @@ def render_visualization_3D_raymarched( for x, y in ti.ndrange(VIS_RESOLUTION[0], VIS_RESOLUTION[1]): # Compute x and y ray directions in neutral camera position - rx = DOMAIN_SIZE_MAX * ( - ti.cast( - x, - PPTypes.FLOAT_GPU) / ti.cast( - VIS_RESOLUTION[0], - PPTypes.FLOAT_GPU)) - 0.5 * DOMAIN_SIZE_MAX - ry = DOMAIN_SIZE_MAX * (ti.cast( - y, - PPTypes.FLOAT_GPU) / ti.cast( - VIS_RESOLUTION[1], - PPTypes.FLOAT_GPU)) - 0.5 * DOMAIN_SIZE_MAX + rx = DOMAIN_SIZE_MAX * (ti.cast(x, PPTypes.FLOAT_GPU) / ti.cast(VIS_RESOLUTION[0], PPTypes.FLOAT_GPU)) - 0.5 * DOMAIN_SIZE_MAX + ry = DOMAIN_SIZE_MAX * (ti.cast(y, PPTypes.FLOAT_GPU) / ti.cast(VIS_RESOLUTION[1], PPTypes.FLOAT_GPU)) - 0.5 * DOMAIN_SIZE_MAX ry /= aspect_ratio # Initialize ray origin and direction @@ -338,9 +323,7 @@ def render_visualization_3D_raymarched( ray_L += PPTypes.VEC3f( trace_vis * trace_val, deposit_vis * deposit_val, - ti.pow( - ti.log(1.0 + 0.2 * trace_vis * trace_val), - 3.0)) / n_ray_steps_f + ti.pow(ti.log(1.0 + 0.2 * trace_vis * trace_val), 3.0)) / n_ray_steps_f ray_pos += ray_delta * ray_dir t_current += ray_delta diff --git a/src/polyphy/utils/cli_helper.py b/src/polyphy/utils/cli_helper.py index 55f308e..bba7897 100644 --- a/src/polyphy/utils/cli_helper.py +++ b/src/polyphy/utils/cli_helper.py @@ -128,15 +128,13 @@ def parse_values(ppConfig): ppConfig.setter("input_file", str(args.input_file)) else: ppConfig.setter("input_file", '') - raise AssertionError("Please specify the main input data file \ - (string relative to the root directory)") + raise AssertionError("Please specify the main input data file (string relative to the root directory)") if args.batch_mode: print("Batch mode activated!") if args.num_iterations: print(f"Number of iterations: {int(args.num_iterations)}") else: - raise AssertionError("Please set number of iterations for batch mode \ - using -n ") + raise AssertionError("Please set number of iterations for batch mode using -n ") if args.num_iterations and not args.batch_mode: raise AssertionError("Please set to batch mode") if args.sensing_dist: diff --git a/src/polyphy/utils/gui_helper.py b/src/polyphy/utils/gui_helper.py index 4bbf3df..526b9a4 100644 --- a/src/polyphy/utils/gui_helper.py +++ b/src/polyphy/utils/gui_helper.py @@ -14,25 +14,21 @@ class GuiHelper: def draw(self, window, ppConfig): # Draw main interactive control GUI window.GUI.begin( - 'Main', 0.01, 0.01, 0.32 * 1024.0 / - PPTypes.FLOAT_CPU(ppConfig.VIS_RESOLUTION[0]), 0.74 * 1024.0 / - PPTypes.FLOAT_CPU(ppConfig.VIS_RESOLUTION[1])) + 'Main', 0.01, 0.01, 0.32 * 1024.0 / PPTypes.FLOAT_CPU(ppConfig.VIS_RESOLUTION[0]), + 0.74 * 1024.0 / PPTypes.FLOAT_CPU(ppConfig.VIS_RESOLUTION[1])) window.GUI.text("MCPM parameters:") ppConfig.sense_distance = window.GUI.slider_float( - 'Sensing dist', ppConfig.sense_distance, - 0.1, 0.05 * ppConfig.DOMAIN_SIZE_MAX) + 'Sensing dist', ppConfig.sense_distance, 0.1, 0.05 * ppConfig.DOMAIN_SIZE_MAX) ppConfig.sense_angle = window.GUI.slider_float( 'Sensing angle', ppConfig.sense_angle, 0.01, 0.5 * np.pi) ppConfig.sampling_exponent = window.GUI.slider_float( 'Sampling expo', ppConfig.sampling_exponent, 0.1, 5.0) ppConfig.step_size = window.GUI.slider_float( - 'Step size', ppConfig.step_size, - 0.0, 0.005 * ppConfig.DOMAIN_SIZE_MAX) + 'Step size', ppConfig.step_size, 0.0, 0.005 * ppConfig.DOMAIN_SIZE_MAX) ppConfig.data_deposit = window.GUI.slider_float( 'Data deposit', ppConfig.data_deposit, 0.0, ppConfig.MAX_DEPOSIT) ppConfig.agent_deposit = window.GUI.slider_float( - 'Agent deposit', ppConfig.agent_deposit, 0.0, - 10.0 * ppConfig.MAX_DEPOSIT * ppConfig.DATA_TO_AGENTS_RATIO) + 'Agent deposit', ppConfig.agent_deposit, 0.0,10.0 * ppConfig.MAX_DEPOSIT * ppConfig.DATA_TO_AGENTS_RATIO) ppConfig.deposit_attenuation = window.GUI.slider_float( 'Deposit attn', ppConfig.deposit_attenuation, 0.8, 0.999) ppConfig.trace_attenuation = window.GUI.slider_float( @@ -43,70 +39,34 @@ def draw(self, window, ppConfig): 'Trace vis', math.log(ppConfig.trace_vis, 10.0), -3.0, 3.0)) window.GUI.text("Distance distribution:") - if window.GUI.checkbox( - "Constant", ppConfig.distance_sampling_distribution - == ppConfig.EnumDistanceSamplingDistribution.CONSTANT): - ppConfig.distance_sampling_distribution = \ - ppConfig.EnumDistanceSamplingDistribution.CONSTANT - if window.GUI.checkbox( - "Exponential", ppConfig.distance_sampling_distribution - == ppConfig.EnumDistanceSamplingDistribution.EXPONENTIAL): - ppConfig.distance_sampling_distribution = \ - ppConfig.EnumDistanceSamplingDistribution.EXPONENTIAL - if window.GUI.checkbox( - "Maxwell-Boltzmann", ppConfig.distance_sampling_distribution - == ppConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN): - ppConfig.distance_sampling_distribution = \ - ppConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN + if window.GUI.checkbox("Constant", ppConfig.distance_sampling_distribution == ppConfig.EnumDistanceSamplingDistribution.CONSTANT): + ppConfig.distance_sampling_distribution = ppConfig.EnumDistanceSamplingDistribution.CONSTANT + if window.GUI.checkbox("Exponential", ppConfig.distance_sampling_distribution == ppConfig.EnumDistanceSamplingDistribution.EXPONENTIAL): + ppConfig.distance_sampling_distribution = ppConfig.EnumDistanceSamplingDistribution.EXPONENTIAL + if window.GUI.checkbox("Maxwell-Boltzmann", ppConfig.distance_sampling_distribution == ppConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN): + ppConfig.distance_sampling_distribution = ppConfig.EnumDistanceSamplingDistribution.MAXWELL_BOLTZMANN window.GUI.text("Directional distribution:") - if window.GUI.checkbox( - "Discrete", ppConfig.directional_sampling_distribution - == ppConfig.EnumDirectionalSamplingDistribution.DISCRETE): - ppConfig.directional_sampling_distribution = \ - ppConfig.EnumDirectionalSamplingDistribution.DISCRETE - if window.GUI.checkbox( - "Cone", ppConfig.directional_sampling_distribution - == ppConfig.EnumDirectionalSamplingDistribution.CONE): - ppConfig.directional_sampling_distribution = \ - ppConfig.EnumDirectionalSamplingDistribution.CONE + if window.GUI.checkbox("Discrete", ppConfig.directional_sampling_distribution == ppConfig.EnumDirectionalSamplingDistribution.DISCRETE): + ppConfig.directional_sampling_distribution = ppConfig.EnumDirectionalSamplingDistribution.DISCRETE + if window.GUI.checkbox("Cone", ppConfig.directional_sampling_distribution == ppConfig.EnumDirectionalSamplingDistribution.CONE): + ppConfig.directional_sampling_distribution = ppConfig.EnumDirectionalSamplingDistribution.CONE window.GUI.text("Directional mutation:") - if window.GUI.checkbox( - "Deterministic", ppConfig.directional_mutation_type - == ppConfig.EnumDirectionalMutationType.DETERMINISTIC): - ppConfig.directional_mutation_type = \ - ppConfig.EnumDirectionalMutationType.DETERMINISTIC - if window.GUI.checkbox( - "Stochastic", ppConfig.directional_mutation_type - == ppConfig.EnumDirectionalMutationType.PROBABILISTIC): - ppConfig.directional_mutation_type = \ - ppConfig.EnumDirectionalMutationType.PROBABILISTIC + if window.GUI.checkbox("Deterministic", ppConfig.directional_mutation_type == ppConfig.EnumDirectionalMutationType.DETERMINISTIC): + ppConfig.directional_mutation_type = ppConfig.EnumDirectionalMutationType.DETERMINISTIC + if window.GUI.checkbox("Stochastic", ppConfig.directional_mutation_type == ppConfig.EnumDirectionalMutationType.PROBABILISTIC): + ppConfig.directional_mutation_type = ppConfig.EnumDirectionalMutationType.PROBABILISTIC window.GUI.text("Deposit fetching:") - if window.GUI.checkbox( - "Nearest neighbor", ppConfig.deposit_fetching_strategy - == ppConfig.EnumDepositFetchingStrategy.NN): - ppConfig.deposit_fetching_strategy = \ - ppConfig.EnumDepositFetchingStrategy.NN - if window.GUI.checkbox( - "Noise-perturbed NN", ppConfig.deposit_fetching_strategy - == ppConfig.EnumDepositFetchingStrategy.NN_PERTURBED): - ppConfig.deposit_fetching_strategy = \ - ppConfig.EnumDepositFetchingStrategy.NN_PERTURBED + if window.GUI.checkbox("Nearest neighbor", ppConfig.deposit_fetching_strategy == ppConfig.EnumDepositFetchingStrategy.NN): + ppConfig.deposit_fetching_strategy = ppConfig.EnumDepositFetchingStrategy.NN + if window.GUI.checkbox("Noise-perturbed NN", ppConfig.deposit_fetching_strategy == ppConfig.EnumDepositFetchingStrategy.NN_PERTURBED): + ppConfig.deposit_fetching_strategy = ppConfig.EnumDepositFetchingStrategy.NN_PERTURBED window.GUI.text("Agent boundary handling:") - if window.GUI.checkbox( - "Wrap around", ppConfig.agent_boundary_handling - == ppConfig.EnumAgentBoundaryHandling.WRAP): - ppConfig.agent_boundary_handling = \ - ppConfig.EnumAgentBoundaryHandling.WRAP - if window.GUI.checkbox( - "Reinitialize center", ppConfig.agent_boundary_handling - == ppConfig.EnumAgentBoundaryHandling.REINIT_CENTER): - ppConfig.agent_boundary_handling = \ - ppConfig.EnumAgentBoundaryHandling.REINIT_CENTER - if window.GUI.checkbox( - "Reinitialize randomly", ppConfig.agent_boundary_handling - == ppConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY): - ppConfig.agent_boundary_handling = \ - ppConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY + if window.GUI.checkbox("Wrap around", ppConfig.agent_boundary_handling == ppConfig.EnumAgentBoundaryHandling.WRAP): + ppConfig.agent_boundary_handling = ppConfig.EnumAgentBoundaryHandling.WRAP + if window.GUI.checkbox("Reinitialize center", ppConfig.agent_boundary_handling == ppConfig.EnumAgentBoundaryHandling.REINIT_CENTER): + ppConfig.agent_boundary_handling = ppConfig.EnumAgentBoundaryHandling.REINIT_CENTER + if window.GUI.checkbox("Reinitialize randomly", ppConfig.agent_boundary_handling == ppConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY): + ppConfig.agent_boundary_handling = ppConfig.EnumAgentBoundaryHandling.REINIT_RANDOMLY window.GUI.text("Misc controls:") self.do_simulate = window.GUI.checkbox("Run simulation", self.do_simulate) @@ -119,8 +79,7 @@ def draw(self, window, ppConfig): # Do not exceed prescribed line length of 120 characters, # there is no text wrapping in Taichi GUI window.GUI.begin('Help', 0.35 * 1024.0 / PPTypes.FLOAT_CPU( - ppConfig.VIS_RESOLUTION[0]), - 0.01, 0.6, 0.30 * 1024.0 / PPTypes.FLOAT_CPU(ppConfig.VIS_RESOLUTION[1])) + ppConfig.VIS_RESOLUTION[0]), 0.01, 0.6, 0.30 * 1024.0 / PPTypes.FLOAT_CPU(ppConfig.VIS_RESOLUTION[1])) window.GUI.text("Welcome to PolyPhy 2D GUI variant written by researchers at \ UCSC/OSPO with the help of numerous external contributors\n\ (https://github.com/PolyPhyHub).\