Example #1
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'
Example #2
0
    def _render_3d(self, xk, img_name, options):
        assert self._folder
        _, info = self.solve(xk, False, options)
        # For the basic _render_2d function, we assume mode = 1.
        mode_num = len(info)
        for m in range(mode_num):
            mode_folder = Path(self._folder / 'mode_{:04d}'.format(m))
            create_folder(mode_folder, exist_ok=True)
            scene = info[m]['scene']
            u_field = info[m]['velocity_field']

            # A proper range for placing the scene is [-0.4, 0.4] x [-0.3, 0.3] x [0, 0.6].
            render_options = {
                'file_name': str(mode_folder / img_name),
                'resolution': (1024, 768),
                'light_map': 'uffizi-large.exr',
                'light_map_scale': 0.75,
                'sample': options['spp'],
                'max_depth': 2,
                'camera_pos': (0.1, -0.65, 1.1),
                'camera_lookat': (0, 0, 0),
            }
            renderer = PbrtRenderer(render_options)
            renderer.add_tri_mesh(Path(root_path) / 'asset/mesh/plane.obj',
                                  transforms=[('s', 1.5)],
                                  color=(.4, .4, .4),
                                  texture_img='background.png')

            # Render the solid-fluid interface.
            cx, cy, cz = self._cell_nums
            nx, ny, nz = self._node_nums
            # How to use cmap:
            # cmap(0.0) to cmap(1.0) covers the whole range of the colormap.
            cmap = plt.get_cmap('jet')
            scale = np.min([0.8 / cx, 0.6 / cy, 0.6 / cz])
            transforms = [('t', (-cx / 2, -cy / 2, 0)), ('s', scale)]
            # Assemble an obj mesh.
            image_prefix = '.'.join(img_name.split('.')[:-1])
            interface_file_name = mode_folder / '{}.obj'.format(image_prefix)
            sdf = np.zeros((nx, ny, nz))
            for i in range(nx):
                for j in range(ny):
                    for k in range(nz):
                        sdf[i, j, k] = scene.GetSignedDistance((i, j, k))
            sdf = ndarray(sdf)
            verts, faces, _, _ = measure.marching_cubes_lewiner(sdf, 0)
            verts = ndarray(verts)
            faces = ndarray(faces).astype(np.int32) + 1

            # Write obj files.
            with open(interface_file_name, 'w') as f:
                for v in verts:
                    f.write('v {:6f} {:6f} {:6f}\n'.format(*v))
                for fi in faces:
                    f.write('f {:d} {:d} {:d}\n'.format(*fi))

            renderer.add_tri_mesh(interface_file_name,
                                  transforms=transforms,
                                  color=(1.0, 0.61, 0.0))

            # Render the velocity field.
            lines = []
            max_u_len = -np.inf
            for i in range(nx):
                for j in range(ny):
                    for k in range(nz):
                        if scene.GetSignedDistance((i, j, k)) >= 0: continue
                        v_begin = ndarray([i, j, k])
                        v_end = v_begin + u_field[i, j, k]
                        u_len = np.linalg.norm(u_field[i, j, k])
                        if u_len > max_u_len:
                            max_u_len = u_len
                        lines.append((v_begin, v_end))
            # Scale the line lengths so that the maximum length is 1/10 of the longest axis.
            lines_scale = 0.1 * np.max(self._cell_nums) / max_u_len
            # width is 1/10 of the cell size.
            width = 0.1
            for v_begin, v_end in lines:
                # Compute the color.
                color_idx = self._color_velocity(v_end - v_begin)
                color = ndarray(cmap(color_idx))[:3]
                v0 = v_begin
                v3 = (v_end - v_begin) * lines_scale + v_begin
                v1 = (2 * v0 + v3) / 3
                v2 = (v0 + 2 * v3) / 3
                renderer.add_shape_mesh(
                    {
                        'name': 'curve',
                        'point': ndarray([v0, v1, v2, v3]),
                        'width': width
                    },
                    color=color,
                    transforms=transforms)
            renderer.render(verbose=True)
Example #3
0
    def _render_2d(self, xk, img_name, options):
        assert self._folder
        loss, info = self.solve(xk, False, options)
        # For the basic _render_2d function, we assume mode = 1.
        mode_num = len(info)
        for m in range(mode_num):
            mode_folder = Path(self._folder / 'mode_{:04d}'.format(m))
            create_folder(mode_folder, exist_ok=True)
            scene = info[m]['scene']
            u_field = info[m]['velocity_field']

            cx, cy = self._cell_nums
            face_color = ndarray([247 / 255, 247 / 255, 247 / 255])
            plt.rcParams['figure.facecolor'] = face_color
            plt.rcParams['axes.facecolor'] = face_color
            fig = plt.figure(figsize=(12, 10))
            ax = fig.add_subplot(111)
            padding = 5
            ax.set_title('Loss: {:3.6e}'.format(loss))
            ax.set_xticks([])
            ax.set_yticks([])
            ax.set_xlim([-padding, cx + padding])
            ax.set_ylim([-padding, cy + padding])
            ax.set_aspect('equal')
            ax.axis('off')

            # Plot cells.
            lines = []
            colors = []
            shift = 0.0
            fluidic_node = np.ones((cx + 1, cy + 1))
            for i in range(cx):
                for j in range(cy):
                    if scene.IsFluidCell((i, j)):
                        color = 'k'
                    elif scene.IsSolidCell((i, j)):
                        color = 'k'
                        fluidic_node[i, j] = fluidic_node[
                            i + 1,
                            j] = fluidic_node[i,
                                              j + 1] = fluidic_node[i + 1,
                                                                    j + 1] = 0
                    else:
                        color = 'k'
                    pts = [(i + shift, j + shift), (i + 1 - shift, j + shift),
                           (i + 1 - shift, j + 1 - shift),
                           (i + shift, j + 1 - shift)]
                    lines += [(pts[0], pts[1]), (pts[1], pts[2]),
                              (pts[2], pts[3]), (pts[3], pts[0])]
                    colors += [
                        color,
                    ] * 4
            ax.add_collection(
                mc.LineCollection(lines, colors=colors, linewidth=0.5))

            # Plot velocity fields.
            cmap = plt.get_cmap('coolwarm')
            lines = []
            colors = []
            u_min = np.inf
            u_max = -np.inf
            for i in range(cx + 1):
                for j in range(cy + 1):
                    uij = u_field[i, j]
                    uij_norm = np.linalg.norm(uij)
                    if uij_norm > 0:
                        if uij_norm > u_max:
                            u_max = uij_norm
                        if uij_norm < u_min:
                            u_min = uij_norm

            for i in range(cx + 1):
                for j in range(cy + 1):
                    if not fluidic_node[i, j]: continue
                    uij = u_field[i, j]
                    uij_norm = np.linalg.norm(uij)
                    v0 = ndarray([i, j])
                    v1 = v0 + uij
                    lines.append((v0, v1))
                    # Determine the color.
                    color = cmap((uij_norm - u_min) / (u_max - u_min))
                    colors.append(color)

            ax.add_collection(
                mc.LineCollection(lines, colors=colors, linewidth=1.0))

            # Plot solid-fluid interfaces.
            lines = []

            def cutoff(d0, d1):
                assert d0 * d1 <= 0
                # (0, d0), (t, 0), (1, d1).
                # t / -d0 = 1 / (d1 - d0)
                return -d0 / (d1 - d0)

            for i in range(cx):
                for j in range(cy):
                    if not scene.IsMixedCell((i, j)): continue
                    ps = [(i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)]
                    ds = [scene.GetSignedDistance(p) for p in ps]
                    ps = ndarray(ps)
                    vs = []
                    for k in range(4):
                        k_next = (k + 1) % 4
                        if ds[k] * ds[k_next] <= 0:
                            t = cutoff(ds[k], ds[k_next])
                            vs.append((1 - t) * ps[k] + t * ps[k_next])
                    vs_len = len(vs)
                    for k in range(vs_len):
                        lines.append((vs[k], vs[(k + 1) % vs_len]))
            ax.add_collection(
                mc.LineCollection(lines, colors='tab:orange', linewidth=1))

            # Plot other customized data if needed.
            self._render_customized_2d(scene, ax)

            fig.savefig(mode_folder / img_name)
            plt.close()
Example #4
0
if __name__ == '__main__':
    # This script assumes the data folder exists.
    data_folder = Path('amplifier')
    cnt = 0
    while True:
        data_file_name = data_folder / '{:04d}.data'.format(cnt)
        if not os.path.exists(data_file_name):
            cnt -= 1
            break
        cnt += 1
    data_file_name = data_folder / '{:04d}.data'.format(cnt)
    opt_history = pickle.load(open(data_file_name, 'rb'))

    # Setting up the environment.
    folder = Path('draw_design')
    create_folder(folder, exist_ok=True)
    seed = 42
    env = AmplifierEnv2d(seed, folder)

    create_folder(folder / 'init_design', exist_ok=True)

    def draw_init_design(design_params, file_name, draw_control_points=False):
        _, info = env.solve(design_params, False, {'solver': 'eigen'})
        u = info[0]['velocity_field']
        node_nums = env.node_nums()
        sdf = np.zeros(node_nums)
        for i in range(node_nums[0]):
            for j in range(node_nums[1]):
                sdf[i, j] = info[0]['scene'].GetSignedDistance((i, j))
                if sdf[i, j] >= 0:
                    u[i, j] = 0
Example #5
0
    def __init__(self, options=None):
        self.__temporary_folder = Path('.tmp')
        create_folder(self.__temporary_folder)
        if options is None: options = {}

        # Image metadata.
        file_name = options['file_name'] if 'file_name' in options else 'output.exr'
        file_name = str(file_name)
        assert file_name.endswith('.png') or file_name.endswith('.exr')
        file_name_only = file_name[:-4]
        self.__file_name_only = file_name_only

        resolution = options['resolution'] if 'resolution' in options else (800, 800)
        resolution = tuple(resolution)
        assert len(resolution) == 2
        resolution = [int(r) for r in resolution]
        self.__resolution = tuple(resolution)

        sample = options['sample'] if 'sample' in options else 4
        sample = int(sample)
        assert sample > 0
        self.__sample = sample

        max_depth = options['max_depth'] if 'max_depth' in options else 4
        max_depth = int(max_depth)
        assert max_depth > 0
        self.__max_depth = max_depth

        # Camera metadata.
        camera_pos = options['camera_pos'] if 'camera_pos' in options else (2, -2.2, 2)
        camera_pos = ndarray(camera_pos).ravel()
        assert camera_pos.size == 3
        self.__camera_pos = camera_pos

        camera_lookat = options['camera_lookat'] if 'camera_lookat' in options else (0.5, 0.5, 0.5)
        camera_lookat = ndarray(camera_lookat).ravel()
        assert camera_lookat.size == 3
        self.__camera_lookat = camera_lookat

        camera_up = options['camera_up'] if 'camera_up' in options else (0, 0, 1)
        camera_up = ndarray(camera_up).ravel()
        assert camera_up.size == 3
        self.__camera_up = camera_up

        fov = options['fov'] if 'fov' in options else 33
        fov = float(fov)
        assert 0 < fov < 90
        self.__fov = fov

        # Lighting.
        lightmap = options['light_map'] if 'light_map' in options else 'lightmap.exr'
        lightmap = Path(root_path) / 'asset/texture/{}'.format(lightmap)
        self.__lightmap = lightmap

        lightmap_scale = options['light_map_scale'] if 'light_map_scale' in options else 1.0
        lightmap_scale = float(lightmap_scale)
        self.__lightmap_scale = lightmap_scale

        # A list of objects.
        self.__tri_objects = []
        self.__shape_objects = []
Example #6
0
import sys
sys.path.append('../')

import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
import matplotlib.colors
from matplotlib import collections as mc

from py_diff_stokes_flow.env.refinement_env_2d import RefinementEnv2d
from py_diff_stokes_flow.common.common import ndarray, print_error, create_folder

if __name__ == '__main__':
    folder = Path('draw_pipeline')
    create_folder(folder, exist_ok=True)

    nu = 0.45
    scale = 0.75
    env = RefinementEnv2d(0.45, scale)

    _, info = env.solve(env.sample(), False, {'solver': 'eigen'})
    u = info[0]['velocity_field']
    node_nums = env.node_nums()
    sdf = np.zeros(node_nums)
    for i in range(node_nums[0]):
        for j in range(node_nums[1]):
            sdf[i, j] = info[0]['scene'].GetSignedDistance((i, j))
            if sdf[i, j] >= 0:
                u[i, j] = 0

    # Draw design parameters.
import sys
sys.path.append('../')

from pathlib import Path
import shutil
import os
import numpy as np

from py_diff_stokes_flow.common.renderer import PbrtRenderer
from py_diff_stokes_flow.common.common import print_info, create_folder
from py_diff_stokes_flow.common.project_path import root_path

if __name__ == '__main__':
    folder = Path('pbrt_renderer_demo')
    create_folder(folder)

    # Render.
    options = {
        'file_name': str(folder / 'demo.png'),
        'light_map': 'uffizi-large.exr',
        'sample': 16,
        'max_depth': 4,
        'camera_pos': (0, -2, 0.8),
        'camera_lookat': (0, 0, 0),
    }
    renderer = PbrtRenderer(options)
    renderer.add_tri_mesh(Path(root_path) / 'asset/mesh/curved_ground.obj',
        texture_img='chkbd_24_0.7')
    renderer.add_tri_mesh(Path(root_path) / 'asset/mesh/bunny.obj',
        transforms=[
            ('s', 0.4),