def test_stepping_dim_in_condition_lowering(self): """ Check that the compiler performs lowering on conditions with TimeDimensions and generates the expected code:: if (g[t][x + 1][y + 1] <= 10){ if (g[t0][x + 1][y + 1] <= 10){ ... --> ... } } This test increments a function by one at every timestep until it is less-or-equal to 10 (g<=10) while although operator runs for 13 timesteps. """ grid = Grid(shape=(4, 4)) _, y = grid.dimensions ths = 10 g = TimeFunction(name='g', grid=grid) ci = ConditionalDimension(name='ci', parent=y, condition=Le(g, ths)) op = Operator(Eq(g.forward, g + 1, implicit_dims=ci)) op.apply(time_M=ths + 3) assert np.all(g.data[0, :, :] == ths) assert np.all(g.data[1, :, :] == ths + 1) assert 'if (g[t0][x + 1][y + 1] <= 10)\n' '{\n g[t1][x + 1][y + 1] = g[t0][x + 1][y + 1] + 1' in str(op.ccode)
def test_expr_like_lowering(self): """ Test the lowering of an expr-like ConditionalDimension's condition. This test makes an Operator that should indexify and lower the condition passed in the Conditional Dimension """ grid = Grid(shape=(3, 3)) g1 = Function(name='g1', grid=grid) g2 = Function(name='g2', grid=grid) g1.data[:] = 0.49 g2.data[:] = 0.49 x, y = grid.dimensions ci = ConditionalDimension(name='ci', parent=y, condition=Le((g1 + g2), 1.01*(g1 + g2))) f = Function(name='f', shape=grid.shape, dimensions=(x, ci)) Operator(Eq(f, g1+g2)).apply() assert np.all(f.data[:] == g1.data[:] + g2.data[:])
def _axial_setup(self): """ Update the axial distance function from the signed distance function. """ # Recurring value for tidiness m_size = int(self._order/2) # Create a padded version of the signed distance function pad_sdf = Function(name='pad_sdf', grid=self._pad, space_order=self._order) pad_sdf.data[:] = np.pad(self._sdf.data, (m_size,), 'edge') # Set default values for axial distance self._axial[0].data[:] = -self._order*self._pad.spacing[0] self._axial[1].data[:] = -self._order*self._pad.spacing[1] self._axial[2].data[:] = -self._order*self._pad.spacing[2] # Equations to decompose distance into axial distances x, y, z = self._pad.dimensions h_x, h_y, h_z = self._pad.spacing pos = sp.Matrix([x*h_x, y*h_y, z*h_z]) sdf_grad = grad(pad_sdf).evaluate # Gradient of the sdf # Plane eq: a*x + b*y + c*z = d a = sdf_grad[0] b = sdf_grad[1] c = sdf_grad[2] d = sdf_grad.dot(pos - pad_sdf*sdf_grad) # Only need to calculate adjacent to boundary close_sdf = Le(sp.Abs(pad_sdf), h_x) # Conditional mask for calculation mask = ConditionalDimension(name='mask', parent=z, condition=close_sdf) eq_x = Eq(self._axial[0], (d - b*pos[1] - c*pos[2])/a - pos[0], implicit_dims=mask) eq_y = Eq(self._axial[1], (d - a*pos[0] - c*pos[2])/b - pos[1], implicit_dims=mask) eq_z = Eq(self._axial[2], (d - a*pos[0] - b*pos[1])/c - pos[2], implicit_dims=mask) op_axial = Operator([eq_x, eq_y, eq_z], name='Axial') op_axial.apply() # Deal with silly values x x_nan_mask = np.isnan(self._axial[0].data) self._axial[0].data[x_nan_mask] = -self._order*h_x x_big_mask = np.abs(self._axial[0].data) > h_x self._axial[0].data[x_big_mask] = -self._order*h_x # Deal with silly values y y_nan_mask = np.isnan(self._axial[1].data) self._axial[1].data[y_nan_mask] = -self._order*h_y y_big_mask = np.abs(self._axial[1].data) > h_y self._axial[1].data[y_big_mask] = -self._order*h_y # Deal with silly values z z_nan_mask = np.isnan(self._axial[2].data) self._axial[2].data[z_nan_mask] = -self._order*h_z z_big_mask = np.abs(self._axial[2].data) > h_z self._axial[2].data[z_big_mask] = -self._order*h_z