def _loss_and_grad_on_velocity_field(self, u):
     u_field = self.reshape_velocity_field(u)
     grad = np.zeros(u_field.shape)
     nx, ny, nz = self.node_nums()
     assert nx == ny
     loss = 0
     cnt = 0
     outlet_bd = int(np.ceil(self._outlet_range * nx))
     eps = 1e-8
     outlet_idx = []
     for j in range(outlet_bd, ny):
         for k in range(nz):
             outlet_idx.append((nx - 1, j, k))
     for i in range(outlet_bd, nx):
         for k in range(nz):
             outlet_idx.append((i, ny - 1, k))
     for i, j, k in outlet_idx:
         cnt += 1
         ux, uy, _ = u_field[i, j, k]
         angle = np.arctan2(uy, ux)
         loss += np.abs(angle - np.pi / 4)
         dangle_ux = -uy / (ux**2 + uy**2 + eps)
         dangle_uy = ux / (ux**2 + uy**2 + eps)
         grad[i, j, k] += ndarray([
             np.sign(angle - np.pi / 4) * dangle_ux,
             np.sign(angle - np.pi / 4) * dangle_uy, 0
         ])
     loss /= cnt
     grad /= cnt
     return loss, ndarray(grad).ravel()
Exemple #2
0
    def __init__(self, seed, folder):
        np.random.seed(seed)

        cell_nums = (64, 48)
        E = 100
        nu = 0.499
        vol_tol = 1e-3
        edge_sample_num = 2
        EnvBase.__init__(self, cell_nums, E, nu, vol_tol, edge_sample_num,
                         folder)

        # Initialize the parametric shapes.
        self._parametric_shape_info = [('bezier', 8), ('bezier', 8),
                                       ('bezier', 8)]
        # Initialize the node conditions.
        self._node_boundary_info = []
        inlet_velocity = 10
        inlet_range = ndarray([0.45, 0.55])
        inlet_lb, inlet_ub = inlet_range * cell_nums[0]
        outlet_range = ndarray([0.4, 0.6])
        outlet_lb, outlet_ub = outlet_range * cell_nums[1]
        for i in range(cell_nums[0] + 1):
            if inlet_lb < i < inlet_ub:
                self._node_boundary_info.append(((i, 0, 0), 0))
                self._node_boundary_info.append(((i, 0, 1), inlet_velocity))
        # Initialize the interface.
        self._interface_boundary_type = 'free-slip'

        # Other data members.
        self._inlet_velocity = inlet_velocity
        self._inlet_range = inlet_range
        self._outlet_range = outlet_range
    def __init__(self, nu, scale):
        cell_nums = (int(32 * scale), int(24 * scale))
        E = 100
        vol_tol = 1e-3
        edge_sample_num = 2
        EnvBase.__init__(self, cell_nums, E, nu, vol_tol, edge_sample_num,
                         None)

        # Initial condition.
        control_points_lower = ndarray([[32, 10], [22, 10], [12, 10], [0, 4]
                                        ]) * scale
        control_points_upper = ndarray([[0, 20], [12, 14], [22, 14], [32, 14]
                                        ]) * scale
        self._sample = np.concatenate(
            [control_points_lower.ravel(),
             control_points_upper.ravel()])

        # Initialize the parametric shapes.
        self._parametric_shape_info = [('bezier', 8), ('bezier', 8)]
        # Initialize the node conditions.
        self._node_boundary_info = []
        inlet_velocity = 1.0
        for j in range(cell_nums[1] + 1):
            if control_points_lower[3, 1] < j < control_points_upper[0, 1]:
                self._node_boundary_info.append(((0, j, 0), inlet_velocity))
                self._node_boundary_info.append(((0, j, 1), 0))
        # Initialize the interface.
        self._interface_boundary_type = 'free-slip'

        self._scale = scale
Exemple #4
0
 def loss_and_grad(x):
     cell.Initialize(E, nu, threshold, edge_sample_num, x)
     loss = ndarray(loss_func()).ravel().dot(weight)
     grad = np.zeros(4)
     for i in range(4):
         grad[i] = ndarray(grad_func(i)).ravel().dot(weight)
     return loss, grad
Exemple #5
0
    def __init__(
        self,
        cell_nums,  # 2D or 3D int array.
        E,  # Young's modulus.
        nu,  # Poisson's ratio.
        vol_tol,  # vol_tol <= mixed cell <= 1 - vol_tol.
        edge_sample_num,  # The number of samples inside each cell's axis.
        folder  # The folder that stores temporary files.
    ):
        # The following data members are provided:
        # - _cell_nums and _node_nums;
        # - _dim;
        # - _cell_options;
        # - _folder;
        # - _parametric_shape_info: a list of (string, int);
        # - _node_boundary_info: a list of (int, float) or ((int, int, int), float) (2D) or
        #   ((int, int, int, int), float) (3D) that describes the boundary conditions.
        # - _interface_boundary_type: either 'no-slip' or 'free-slip' (default).

        # Sanity check the inputs.
        cell_nums = ndarray(cell_nums).astype(np.int32)
        assert cell_nums.size in [2, 3]

        # The value of E does not quite matter as it simply scale the QP problem by a constant factor.
        E = float(E)
        assert E > 0

        nu = float(nu)
        assert 0 < nu < 0.5

        vol_tol = float(vol_tol)
        assert 0 < vol_tol < 0.5

        edge_sample_num = int(edge_sample_num)
        assert edge_sample_num > 1

        if folder is not None:
            folder = Path(folder)
            create_folder(folder, exist_ok=True)

        # Create data members.
        self._cell_nums = np.copy(cell_nums)
        self._node_nums = ndarray([n + 1 for n in cell_nums]).astype(np.int32)
        self._dim = self._cell_nums.size
        self._cell_options = {
            'E': E,
            'nu': nu,
            'vol_tol': vol_tol,
            'edge_sample_num': edge_sample_num
        }
        self._folder = folder

        ###########################################################################
        # Derived classes should implement these data members.
        ###########################################################################
        self._parametric_shape_info = []
        self._node_boundary_info = []
        self._interface_boundary_type = 'free-slip'
 def loss_and_grad(x):
     shape.Initialize(cell_nums, x, True)
     sdf = ndarray(shape.signed_distances())
     loss = sdf_weight.ravel().dot(sdf)
     grad = 0
     for i in range(nx):
         for j in range(ny):
             grad += sdf_weight[i, j] * ndarray(shape.signed_distance_gradients((i, j)))
     return loss, grad
Exemple #7
0
 def _render_customized_2d(self, scene, ax):
     nx, ny = self._node_nums
     lines = []
     for i in range(nx):
         for j in range(ny):
             v_begin = ndarray([i, j])
             v_end = v_begin + ndarray(scene.GetFluidicForceDensity((i, j)))
             lines.append((v_begin, v_end))
     ax.add_collection(
         mc.LineCollection(lines, colors='tab:red', linestyle='-'))
Exemple #8
0
 def sample(self):
     control_points_lower = ndarray([[34, 10], [22, 10], [12, 10], [
         -2, 4
     ]]) + np.random.normal(size=(4, 2)) * 0.01
     control_points_upper = ndarray([[-2, 20], [12, 14], [22, 14], [
         34, 14
     ]]) + np.random.normal(size=(4, 2)) * 0.01
     x0 = np.concatenate(
         [control_points_lower.ravel(),
          control_points_upper.ravel()])
     return x0
    def __init__(self, seed, folder):
        np.random.seed(seed)

        cell_nums = (64, 64, 4)
        E = 100
        nu = 0.499
        vol_tol = 1e-2
        edge_sample_num = 2
        EnvBase.__init__(self, cell_nums, E, nu, vol_tol, edge_sample_num,
                         folder)

        # Initialize the parametric shapes.
        self._parametric_shape_info = [('bezier', 11), ('bezier', 11),
                                       ('bezier', 11)]
        # Initialize the node conditions.
        self._node_boundary_info = []

        inlet_range = ndarray([0.4, 0.6])
        outlet_range = 0.8
        cx, cy, _ = self.cell_nums()
        assert cx == cy
        nx, ny, nz = self.node_nums()
        inlet_bd = inlet_range * cx
        outlet_bd = outlet_range * cx
        inlet_velocity = ndarray([1.0, 0.0])
        for j in range(ny):
            for k in range(nz):
                # Set the inlet at i = 0.
                if inlet_bd[0] < j < inlet_bd[1]:
                    self._node_boundary_info.append(
                        ((0, j, k, 0), inlet_velocity[0]))
                    self._node_boundary_info.append(((0, j, k, 1), 0))
                    self._node_boundary_info.append(((0, j, k, 2), 0))

                    self._node_boundary_info.append(
                        ((j, 0, k, 0), inlet_velocity[1]))
                    self._node_boundary_info.append(((j, 0, k, 1), 0))
                    self._node_boundary_info.append(((j, 0, k, 2), 0))
        # Set the top and bottom plane.
        for i in range(nx):
            for j in range(ny):
                for k in [0, nz - 1]:
                    self._node_boundary_info.append(((i, j, k, 2), 0))
        # Initialize the interface.
        self._interface_boundary_type = 'free-slip'

        # Other data members.
        self._inlet_range = inlet_range
        self._outlet_range = outlet_range
        self._inlet_bd = inlet_bd
        self._outlet_bd = outlet_bd
        self._inlet_velocity = inlet_velocity
Exemple #10
0
 def _loss_and_grad_on_velocity_field(self, u):
     u_field = self.reshape_velocity_field(u)
     grad = np.zeros(u_field.shape)
     cnt = 0
     loss = 0
     for j, (ux, uy) in enumerate(u_field[-1]):
         if ux > 0:
             cnt += 1
             u_diff = ndarray([ux, uy]) - ndarray(
                 [self._outlet_velocity, 0])
             loss += u_diff.dot(u_diff)
             grad[-1, j] += 2 * u_diff
     loss /= cnt
     grad /= cnt
     return loss, ndarray(grad).ravel()
Exemple #11
0
 def _loss_and_grad_on_velocity_field(self, u):
     u_field = self.reshape_velocity_field(u)
     grad = np.zeros(u_field.shape)
     nx, ny, nz = self.node_nums()
     assert nx == ny
     loss = 0
     cnt = 0
     for i in range(nx):
         for j in range(ny):
             if self._outlet_bezier.signed_distance((i, j)) > 0:
                 cnt += 1
                 uxy = u_field[i, j, nz - 1, :2]
                 ux_pos = u_field[i + 1, j, nz - 1, :2]
                 uy_pos = u_field[i, j + 1, nz - 1, :2]
                 # Compute the curl.
                 curl = ux_pos[1] - uy_pos[0] - uxy[1] + uxy[0]
                 loss += (curl - self._desired_omega)**2
                 # ux_pos[1]
                 grad[i + 1, j, nz - 1,
                      1] += 2 * (curl - self._desired_omega)
                 grad[i, j + 1, nz - 1,
                      0] += -2 * (curl - self._desired_omega)
                 grad[i, j, nz - 1, 1] += -2 * (curl - self._desired_omega)
                 grad[i, j, nz - 1, 0] += 2 * (curl - self._desired_omega)
     loss /= cnt
     grad /= cnt
     return loss, ndarray(grad).ravel()
    def _variables_to_shape_params(self, x):
        x = ndarray(x).copy().ravel()
        assert x.size == 26

        cx, cy, _ = self._cell_nums
        assert cx == cy

        # Since there are two modes, we have two sets of parameters.
        def get_params_and_grads(rotation_angle_idx):
            params = np.concatenate([
                x[:24] * cx,
                ndarray([0.6 * cx, 0.5 * cy, x[rotation_angle_idx]]),
                (self._upper * cx).ravel(),
                ndarray([0.0, self._dir_offset, 1.0]),
                (self._lower * cx).ravel(),
                ndarray([0.0, -self._dir_offset, 1.0]),
                (self._right * cx).ravel(),
                ndarray([self._dir_offset, 0.0, 1.0]),
            ])
            grads = np.zeros((params.size, x.size))
            for i in range(24):
                grads[i, i] = cx
            grads[26, rotation_angle_idx] = 1
            grads = ndarray(grads)
            return params, grads

        params_on, grads_on = get_params_and_grads(24)
        params_off, grads_off = get_params_and_grads(25)
        return [(params_on, grads_on), (params_off, grads_off)]
def test_shape_composition_2d_single(shape_info, verbose):
    np.random.seed(42)

    cell_nums = (32, 24)
    shape = ShapeComposition2d()
    params = []
    for name, param in shape_info:
        shape.AddParametricShape(name, param.size)
        params.append(ndarray(param).ravel())
    params = np.concatenate(params)
    params += np.random.normal(size=params.size) * 0.01
    shape.Initialize(cell_nums, params, True)

    if verbose:
        visualize_level_set(shape)

    # Verify the gradients.
    nx = shape.node_num(0)
    ny = shape.node_num(1)
    sdf_weight = np.random.normal(size=(nx, ny))
    def loss_and_grad(x):
        shape.Initialize(cell_nums, x, True)
        sdf = ndarray(shape.signed_distances())
        loss = sdf_weight.ravel().dot(sdf)
        grad = 0
        for i in range(nx):
            for j in range(ny):
                grad += sdf_weight[i, j] * ndarray(shape.signed_distance_gradients((i, j)))
        return loss, grad
    from py_diff_stokes_flow.common.grad_check import check_gradients
    return check_gradients(loss_and_grad, params.ravel(), verbose=verbose)
def test_shape_composition_3d(verbose):
    return test_shape_composition_3d_single(
        [('polar_bezier3',
          ndarray([
              1, 4, 1, 4, 1, 4, 1, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 1, 4, 1, 4, 1,
              4, 1, 5, 5, np.pi / 3
          ]))], verbose)
 def get_params_and_grads(rotation_angle_idx):
     params = np.concatenate([
         x[:24] * cx,
         ndarray([0.6 * cx, 0.5 * cy, x[rotation_angle_idx]]),
         (self._upper * cx).ravel(),
         ndarray([0.0, self._dir_offset, 1.0]),
         (self._lower * cx).ravel(),
         ndarray([0.0, -self._dir_offset, 1.0]),
         (self._right * cx).ravel(),
         ndarray([self._dir_offset, 0.0, 1.0]),
     ])
     grads = np.zeros((params.size, x.size))
     for i in range(24):
         grads[i, i] = cx
     grads[26, rotation_angle_idx] = 1
     grads = ndarray(grads)
     return params, grads
Exemple #16
0
 def _loss_and_grad_on_velocity_field(self, u):
     u_field = self.reshape_velocity_field(u)
     grad = np.zeros(u_field.shape)
     nx, ny, nz = self.node_nums()
     loss = 0
     cnt = 0
     for j in range(ny):
         for k in range(nz):
             if self._outlet_bd[0, 0] < j < self._outlet_bd[0, 1] or \
                 self._outlet_bd[1, 0] < j < self._outlet_bd[1, 1]:
                 cnt += 1
                 u_diff = u_field[nx - 1, j, k] - ndarray([0.5, 0, 0])
                 loss += u_diff.dot(u_diff)
                 grad[nx - 1, j, k] += 2 * u_diff
     loss /= cnt
     grad /= cnt
     return loss, ndarray(grad).ravel()
Exemple #17
0
 def get_bezier(radius):
     bezier = ShapeComposition2d()
     params = np.concatenate(
         [np.full(8, radius) * cx,
          ndarray([0.5 * cx, 0.5 * cy, 0])])
     bezier.AddParametricShape('polar_bezier', params.size)
     cxy = StdIntArray2d((int(cx), int(cy)))
     bezier.Initialize(cxy, params, True)
     return bezier
Exemple #18
0
 def reshape_velocity_field(self, u):
     u_array = ndarray(u)
     assert len(u_array.shape) in [1, self._dim + 1]
     assert u_array.size == np.prod(self._node_nums) * self._dim
     if len(u_array.shape) == 1:
         return np.copy(u_array).reshape(
             tuple(self._node_nums) + (self._dim, ))
     else:
         return np.copy(u_array).ravel()
Exemple #19
0
def plot_velocity_field(ax, u_field, s, u_max):
    x_size = ndarray(np.arange(u_field.shape[0])) / s
    y_size = ndarray(np.arange(u_field.shape[1])) / s
    X, Y = np.meshgrid(x_size, y_size)
    u_norm = np.sqrt(np.sum(u_field**2, axis=(2, )))
    strm = ax.streamplot(X,
                         Y,
                         u_field[:, :, 0].T,
                         u_field[:, :, 1].T,
                         density=(cell_nums[0] / cell_nums[1] * 3, 3),
                         color=u_norm.T,
                         norm=matplotlib.colors.Normalize(0, u_max),
                         arrowstyle='->',
                         linewidth=1.5,
                         cmap='coolwarm')
    ax.set_xlim([0, cell_nums[0]])
    ax.set_ylim([0, cell_nums[1]])
    ax.set_xticks([])
    ax.set_yticks([])
Exemple #20
0
    def _variables_to_shape_params(self, x):
        x = ndarray(x).copy().ravel()
        assert x.size == 5

        cx, cy = self._cell_nums
        # Convert x to the shape parameters.
        lower = ndarray([
            [1, x[4]],
            x[2:4],
            x[:2],
            [0, self._inlet_range[0]],
        ])
        lower[:, 0] *= cx
        lower[:, 1] *= cy
        upper = ndarray([
            [0, self._inlet_range[1]],
            [x[0], 1 - x[1]],
            [x[2], 1 - x[3]],
            [1, 1 - x[4]],
        ])
        upper[:, 0] *= cx
        upper[:, 1] *= cy
        params = np.concatenate([lower.ravel(), upper.ravel()])

        # Jacobian.
        J = np.zeros((params.size, x.size))
        J[1, 4] = 1
        J[2, 2] = 1
        J[3, 3] = 1
        J[4, 0] = 1
        J[5, 1] = 1
        J[10, 0] = 1
        J[11, 1] = -1
        J[12, 2] = 1
        J[13, 3] = -1
        J[15, 4] = -1
        # Scale it by cx and cy.
        J[:, 0] *= cx
        J[:, 2] *= cx
        J[:, 1] *= cy
        J[:, 3] *= cy
        J[:, 4] *= cy
        return ndarray(params).copy(), ndarray(J).copy()
Exemple #21
0
    def _variables_to_shape_params(self, x):
        x = ndarray(x).copy().ravel()
        assert x.size == 32

        cx, cy, _ = self._cell_nums
        assert cx == cy
        params = np.concatenate([
            np.full(8, self._inlet_radius),
            x,
            np.full(8, self._outlet_radius),
            ndarray([0.5, 0.5, 0]),
        ])
        params[:-1] *= cx

        # Jacobian.
        J = np.zeros((params.size, x.size))
        for i in range(x.size):
            J[8 + i, i] = cx
        return ndarray(params).copy(), ndarray(J).copy()
Exemple #22
0
def test_bezier_2d(verbose):
    np.random.seed(42)
    folder = Path('bezier_2d')

    cell_nums = (32, 24)
    control_points = ndarray([[32, 12], [22, 6], [12, 18], [0, 12]])
    control_points[:, 1] += np.random.normal(size=4)
    bezier = Bezier2d()
    bezier.Initialize(cell_nums, control_points.ravel(), True)
    sdf = ndarray(bezier.signed_distances())
    sdf_master = np.load(folder / 'sdf_master.npy')
    if np.max(np.abs(sdf - sdf_master)) > 0:
        if verbose:
            print_error('Incorrect signed distance function.')
        return False

    if verbose:
        visualize_level_set(bezier)

    # Verify the gradients.
    nx = bezier.node_num(0)
    ny = bezier.node_num(1)
    sdf_weight = np.random.normal(size=(nx, ny))

    def loss_and_grad(x):
        bezier = Bezier2d()
        bezier.Initialize(cell_nums, x.ravel(), True)
        sdf = ndarray(bezier.signed_distances())
        loss = sdf_weight.ravel().dot(sdf)
        grad = 0
        for i in range(nx):
            for j in range(ny):
                grad += sdf_weight[i, j] * ndarray(
                    bezier.signed_distance_gradients((i, j)))
        return loss, grad

    from py_diff_stokes_flow.common.grad_check import check_gradients
    return check_gradients(loss_and_grad,
                           control_points.ravel(),
                           verbose=verbose)
def test_shape_composition_2d(verbose):
    flag = test_shape_composition_2d_single([
        ( 'bezier',
            ndarray([
                [32, 10],
                [22, 10],
                [12, 4],
                [0, 4]
            ])
        ),
        ( 'bezier',
            ndarray([
                [0, 20],
                [12, 20],
                [22, 14],
                [32, 14]
            ])
        ),
    ], verbose)
    if not flag: return False

    flag = test_shape_composition_2d_single([
        ( 'plane', ndarray([1, 0.1, -16]) ),
        ( 'sphere', ndarray([16, 12, 8]) ),
    ], verbose)
    if not flag: return False

    flag = test_shape_composition_2d_single([
        ( 'polar_bezier',
            ndarray([
                4, 8, 4, 8, 4, 8, 4, 8,
                16, 12,
                np.pi / 3
            ])
        ),
    ], verbose)
    if not flag: return False

    return True
    def _loss_and_grad_on_velocity_field(self, u):
        u_field = self.reshape_velocity_field(u)
        grad = np.zeros(u_field.shape)
        nx, ny, nz = self.node_nums()
        assert nx == ny
        loss = 0
        cnt = 0
        target_velocity = ndarray([self._inlet_velocity[0], self._inlet_velocity[1], 0.])
        for j in range(ny):
            for k in range(nz):
                if j > self._outlet_bd:
                    cnt += 1
                    u_diff = u_field[nx - 1, j, k] - target_velocity
                    loss += u_diff.dot(u_diff)
                    grad[nx - 1, j, k] += 2 * u_diff

                    cnt += 1
                    u_diff = u_field[j, ny - 1, k] - target_velocity
                    loss += u_diff.dot(u_diff)
                    grad[j, ny - 1, k] += 2 * u_diff
        loss /= cnt
        grad /= cnt
        return loss, ndarray(grad).ravel()
 def loss_and_grad(u_single, target_field):
     u_field = self.reshape_velocity_field(u_single)
     loss = 0
     grad = np.zeros(u_field.shape)
     cnt = 0
     for j in range(ny):
         for k in range(nz):
             if self._boundary_bezier.signed_distance(
                 (int(nx - 1), int(j), int(k))) < 0:
                 uxyz = u_field[nx - 1, j, k]
                 u_diff = uxyz - target_field[j, k]
                 loss += u_diff.dot(u_diff)
                 grad[nx - 1, j, k] += 2 * u_diff
                 cnt += 1
     loss /= cnt
     grad /= cnt
     return loss, ndarray(grad).ravel()
    def _variables_to_shape_params(self, x):
        x = ndarray(x).copy().ravel()
        assert x.size == 5

        cx, cy, _ = self._cell_nums
        assert cx == cy
        lower_left = ndarray([
            [self._inlet_range[0], 0],
            [x[4], x[0]],
            [x[0], x[4]],
            [0, self._inlet_range[0]]
        ])
        right = ndarray([
            [1., self._outlet_range],
            [x[2], x[3]],
            [self._inlet_range[1], x[1]],
            [self._inlet_range[1], 0]
        ])
        upper = ndarray([
            [0, self._inlet_range[1]],
            [x[1], self._inlet_range[1]],
            [x[3], x[2]],
            [self._outlet_range, 1.]
        ])
        lower_left *= cx
        right *= cx
        upper *= cx

        params = np.concatenate([lower_left.ravel(),
            [-0.01, -0.01, 1],
            right.ravel(),
            [0.01, 0, 1],
            upper.ravel(),
            [0, 0.01, 1],
        ])

        # Jacobian.
        J = np.zeros((params.size, x.size))
        J[2, 4] = J[3, 0] = 1
        J[4, 0] = J[5, 4] = 1

        J[13, 2] = J[14, 3] = 1
        J[16, 1] = 1

        J[24, 1] = J[26, 3] = J[27, 2] = 1
        J *= cx
        return ndarray(params).copy(), ndarray(J).copy()
Exemple #27
0
def test_cell_2d(verbose):
    np.random.seed(42)

    cell = Cell2d()
    E = 1e5
    nu = 0.45
    threshold = 1e-3
    edge_sample_num = 3
    # Consider a line that passes (0.5, 0.5) with a slope between 1/3 and 1.
    p = ndarray([0.5, 0.5])
    k = np.random.uniform(low=1 / 3, high=1)
    # Line equation: (y - p[1]) / (x - p[0]) = k.
    # y - p[1] = kx - kp[0].
    # kx - y + p[1] - kp[0].
    line_eq = ndarray([k, -1, p[1] - k * p[0]])
    # Solid area: line_eq >= 0.
    # So, the lower part is the solid area.
    # This means corner distance from [0, 0] and [1, 0] are positive.
    sdf_at_corners = []
    for c in [(0, 0), (0, 1), (1, 0), (1, 1)]:
        sdf_at_corners.append(
            (line_eq[0] * c[0] + line_eq[1] * c[1] + line_eq[2]) /
            np.linalg.norm(line_eq[:2]))
    cell.Initialize(E, nu, threshold, edge_sample_num, sdf_at_corners)

    # Check if all areas are correct.
    dx = 1 / 3
    x_intercept = (-line_eq[1] * dx - line_eq[2]) / line_eq[0]
    area_00 = x_intercept * x_intercept * k * 0.5
    area_01 = dx**2 - (dx - x_intercept)**2 * k * 0.5
    area_02 = dx**2
    area_10 = 0
    area_11 = dx**2 * 0.5
    area_12 = dx**2
    area_20 = 0
    area_21 = dx**2 - area_01
    area_22 = dx**2 - area_00
    area = ndarray([
        area_00, area_01, area_02, area_10, area_11, area_12, area_20, area_21,
        area_22
    ])
    area_from_cell = ndarray(cell.sample_areas())
    if not np.allclose(area, area_from_cell):
        if verbose:
            print_error('area is inconsistent.')
        return False

    # Check if all line segments are correct.
    line_00 = np.sqrt(1 + k**2) * x_intercept
    line_01 = np.sqrt(1 + k**2) * (dx - x_intercept)
    line_02 = 0
    line_10 = 0
    line_11 = np.sqrt(1 + k**2) * dx
    line_12 = 0
    line_20 = 0
    line_21 = line_01
    line_22 = line_00
    line = ndarray([
        line_00, line_01, line_02, line_10, line_11, line_12, line_20, line_21,
        line_22
    ])
    line_from_cell = ndarray(cell.sample_boundary_areas())
    if not np.allclose(line, line_from_cell):
        if verbose:
            print_error('boundary area is inconsistent.')
        return False

    # Test the gradients.
    for loss_func, grad_func, name in [
        (cell.py_normal, cell.py_normal_gradient, 'normal'),
        (cell.offset, cell.py_offset_gradient, 'offset'),
        (cell.sample_areas, cell.py_sample_areas_gradient, 'sample_areas'),
        (cell.sample_boundary_areas, cell.py_sample_boundary_areas_gradient,
         'sample_boundary_areas'), (cell.area, cell.py_area_gradient, 'area'),
        (cell.py_energy_matrix, cell.py_energy_matrix_gradient,
         'energy_matrix'),
        (cell.py_dirichlet_vector, cell.py_dirichlet_vector_gradient,
         'dirichlet_vector')
    ]:
        if verbose:
            print_info('Checking loss and gradient:', name)
        dim = ndarray(loss_func()).size
        weight = np.random.normal(size=dim)

        def loss_and_grad(x):
            cell.Initialize(E, nu, threshold, edge_sample_num, x)
            loss = ndarray(loss_func()).ravel().dot(weight)
            grad = np.zeros(4)
            for i in range(4):
                grad[i] = ndarray(grad_func(i)).ravel().dot(weight)
            return loss, grad

        if not check_gradients(
                loss_and_grad, ndarray(sdf_at_corners), verbose=verbose):
            if verbose:
                print_error('Gradient check failed.')
            return False

    return True
Exemple #28
0
    def _variables_to_shape_params(self, x):
        x = ndarray(x).copy().ravel()
        assert x.size == 8

        cx, cy, _ = self._cell_nums
        lower = ndarray([
            [1, self._outlet_range[0, 0]],
            x[2:4],
            x[:2],
            [0, self._inlet_range[0, 0]],
        ])
        right = ndarray([
            [1, self._outlet_range[1, 0]],
            [x[4], 1 - x[5]],
            x[4:6],
            [1, self._outlet_range[0, 1]],
        ])
        upper = ndarray([
            [0, self._inlet_range[1, 1]],
            [x[0], 1 - x[1]],
            [x[2], 1 - x[3]],
            [1, self._outlet_range[1, 1]],
        ])
        left = ndarray([
            [0, self._inlet_range[0, 1]],
            x[6:8],
            [x[6], 1 - x[7]],
            [0, self._inlet_range[1, 0]],
        ])
        cxy = ndarray([cx, cy])
        lower *= cxy
        right *= cxy
        upper *= cxy
        left *= cxy
        params = np.concatenate([lower.ravel(),
            [0, -0.01, 1],
            right.ravel(),
            [0.01, 0, 1],
            upper.ravel(),
            [0, 0.01, 1],
            left.ravel(),
            [-0.01, 0, 1]
        ])

        # Jacobian.
        J = np.zeros((params.size, x.size))
        J[2, 2] = J[3, 3] = 1
        J[4, 0] = J[5, 1] = 1

        J[13, 4] = 1
        J[14, 5] = -1
        J[15, 4] = J[16, 5] = 1

        J[24, 0] = 1
        J[25, 1] = -1
        J[26, 2] = 1
        J[27, 3] = -1

        J[35, 6] = J[36, 7] = 1
        J[37, 6] = 1
        J[38, 7] = -1
        J[:, ::2] *= cx
        J[:, 1::2] *= cy
        return ndarray(params).copy(), ndarray(J).copy()
Exemple #29
0
 def upper_bound(self):
     return ndarray([.49, .49, .99, .49, .99, .49, .49, .49])
Exemple #30
0
 def lower_bound(self):
     return ndarray([.01, .01, .49, .01, .49, .01, .01, .01])