Example #1
0
    def __init__(self,
                 concentration_G,
                 concentration_X,
                 concentration_Y,
                 dx,
                 dt=None,
                 params=None,
                 source_functions=None):
        if dt is None:
            dt = 0.1 * dx

        if dt > 0.5 * dx:
            warnings.warn(
                "Time increment {} too large for simulation stability with grid constant {}"
                .format(dt, dx))

        super().__init__(dx, dt, concentration_G.shape)

        if concentration_X.shape != concentration_Y.shape or concentration_X.shape != concentration_G.shape:
            raise ValueError("Concentration shapes must match")

        self.params = params or DEFAULT_PARAMS
        self.source_functions = source_functions or {}

        self.G = tf.constant(concentration_G, dtype="float64")
        self.X = tf.constant(concentration_X, dtype="float64")
        self.Y = tf.constant(concentration_Y, dtype="float64")

        if self.dims == 1:
            omega2 = self.omega_x**2
        elif self.dims == 2:
            omega_x, omega_y = self.omega_x, self.omega_y
            omega2 = omega_x**2 + omega_y**2
        elif self.dims == 3:
            omega_x, omega_y, omega_z = self.omega_x, self.omega_y, self.omega_z
            omega2 = omega_x**2 + omega_y**2 + omega_z**2
        else:
            raise ValueError('Only up to 3D supported')

        delta = tf.cast(-omega2 * self.dt, 'complex128')
        decay_G = tf.exp(self.params['D_G'] * delta)
        decay_X = tf.exp(self.params['D_X'] * delta)
        decay_Y = tf.exp(self.params['D_Y'] * delta)

        def diffusion_integrator(*cons):
            result = []
            for decay, concentration in zip([decay_G, decay_X, decay_Y], cons):
                f = self.fft(tf.cast(concentration, 'complex128'))
                f *= decay
                result.append(tf.cast(tf.math.real(self.ifft(f)), 'float64'))
            return result

        reaction_integrator_curried = lambda con_G, con_X, con_Y: reaction_integrator(
            con_G, con_X, con_Y, self.dt, self.params['A'], self.params['B'],
            self.params['k2'], self.params['k-2'], self.params['k5'])

        self.diffusion_integrator = tf.function(diffusion_integrator)
        self.reaction_integrator = tf.function(reaction_integrator_curried)
Example #2
0
def get_trajectories(A, B, k2, k_2, k5):
    G, X, Y = randn(3, 10)
    Gs = [G]
    Xs = [X]
    Ys = [Y]

    for _ in range(1000):
        G, X, Y = reaction_integrator(G, X, Y, 0.02, A, B, k2, k_2, k5)
        Gs.append(G)
        Xs.append(X)
        Ys.append(Y)

    return array([Gs, Xs, Ys])
Example #3
0
    def __init__(self,
                 concentration_G,
                 concentration_X,
                 concentration_Y,
                 u,
                 dx,
                 dt=None,
                 params=None,
                 source_functions=None):
        if dt is None:
            dt = 0.1 * dx

        if dt > 0.5 * dx:
            warnings.warn(
                "Time increment {} too large for simulation stability with grid constant {}"
                .format(dt, dx))

        super().__init__(dx, dt, concentration_G.shape)

        self.params = params or DEFAULT_PARAMS
        self.source_functions = source_functions or {}

        self.G = tf.constant(concentration_G, 'float64')
        self.X = tf.constant(concentration_X, 'float64')
        self.Y = tf.constant(concentration_Y, 'float64')

        #self.G = tf.constant(concentration_G, 'complex128')
        #BJD added 3 lines below 9.8.2021
        #self.del_G = tf.constant(concentration_G, 'float64')
        #self.del_X = tf.constant(concentration_X, 'float64')
        #self.del_Y = tf.constant(concentration_Y, 'float64')

        G0, X0, Y0 = steady_state(self.params['A'], self.params['B'],
                                  self.params['k2'], self.params['k-2'],
                                  self.params['k5'])

        if len(u) != self.dims:
            raise ValueError(
                "{0}-dimensional flow must have {0} components".format(
                    self.dims))

        c2 = self.params["speed-of-sound"]**2
        viscosity = self.params["viscosity"]
        if self.dims == 1:
            raise ValueError("1D not supported")
        elif self.dims == 2:
            self.u = tf.constant(u[0], 'float64')
            self.v = tf.constant(u[1], 'float64')

            omega_x, omega_y = self.omega_x, self.omega_y
            omega2 = omega_x**2 + omega_y**2
            omega2_x = tf.constant(
                omega2 + 1 / 3 * omega_x * (omega_x + omega_y), "complex128")
            omega2_y = tf.constant(
                omega2 + 1 / 3 * omega_y * (omega_x + omega_y), "complex128")
            decay_x = tf.exp(-viscosity * omega2_x * self.dt)
            decay_y = tf.exp(-viscosity * omega2_y * self.dt)

            delta = tf.constant(-omega2 * self.dt, "complex128")
            decay_G = tf.exp(self.params['D_G'] * delta)
            decay_X = tf.exp(self.params['D_X'] * delta)
            decay_Y = tf.exp(self.params['D_Y'] * delta)

            def flow_integrator(rho, u, v):
                """
                Flow is integrated with respect to the total log density (rho)
                """
                # Enter Fourier Domain
                f_rho = self.fft(tf.cast(rho, 'complex128'))
                waves_x = self.fft(tf.cast(u, 'complex128'))
                waves_y = self.fft(tf.cast(v, 'complex128'))

                # Viscosity and internal shear
                waves_x *= decay_x
                waves_y *= decay_y

                # Exit Fourier Domain
                u = tf.cast(self.ifft(waves_x), 'float64')
                v = tf.cast(self.ifft(waves_y), 'float64')

                # Calculate gradients
                rho_dx = tf.cast(self.ifft(f_rho * self.kernel_dx), 'float64')
                rho_dy = tf.cast(self.ifft(f_rho * self.kernel_dy), 'float64')
                u_dx = tf.cast(self.ifft(waves_x * self.kernel_dx), 'float64')
                u_dy = tf.cast(self.ifft(waves_x * self.kernel_dy), 'float64')
                v_dx = tf.cast(self.ifft(waves_y * self.kernel_dx), 'float64')
                v_dy = tf.cast(self.ifft(waves_y * self.kernel_dy), 'float64')
                divergence = u_dx + v_dy

                # This would handle log density continuity but it's actually handled individually for G, X and Y
                # rho -= (u*rho_dx + v*rho_dy + divergence) * self.dt

                # Self-advect flow
                du = -u * u_dx - v * u_dy
                dv = -u * v_dx - v * v_dy

                # Propagate pressure waves
                du -= c2 * rho_dx
                dv -= c2 * rho_dy

                # Apply strain
                du += viscosity * (rho_dx * (u_dx + u_dx) + rho_dy *
                                   (u_dy + v_dx) - 2 / 3 * rho_dx * divergence)
                dv += viscosity * (rho_dx * (v_dx + u_dy) + rho_dy *
                                   (v_dy + v_dy) - 2 / 3 * rho_dy * divergence)

                u += du * self.dt
                v += dv * self.dt

                return u, v, divergence

            def diffusion_advection_integrator(G, X, Y, u, v, divergence):
                f_G = self.fft(tf.cast(G, 'complex128'))
                f_X = self.fft(tf.cast(X, 'complex128'))
                f_Y = self.fft(tf.cast(Y, 'complex128'))

                #f_test_function = self.fft(tf.cast(G, 'complex128'))
                #f_test_function = solver.fft(tf.constant(test_function, 'complex128'))
                #test_function_dx_fft = tf.cast(self.ifft(f_test_function * self.kernel_dx), 'float64')
                #test_function_dy_fft = tf.cast(self.ifft(f_test_function * self.kernel_dy), 'float64')
                #test_function_nabla2_fft = np.real(solver.ifft(f_test_function * solver.kernel_laplacian).numpy())
                #np.savetxt("/home/brendan/software/tf2-model-g/arrays/quiver_array34/del_G_dx.txt", test_function_dx_fft) # BJD 9.8.2021
                #np.savetxt("/home/brendan/software/tf2-model-g/arrays/quiver_array34/del_G_dy.txt", test_function_dy_fft) # BJD 9.8.2021

                f_G *= decay_G
                f_X *= decay_X
                f_Y *= decay_Y

                G = tf.cast(self.ifft(f_G), 'float64')
                X = tf.cast(self.ifft(f_X), 'float64')
                Y = tf.cast(self.ifft(f_Y), 'float64')

                G_dx = tf.cast(self.ifft(f_G * self.kernel_dx), 'float64')
                G_dy = tf.cast(self.ifft(f_G * self.kernel_dy), 'float64')
                X_dx = tf.cast(self.ifft(f_X * self.kernel_dx), 'float64')
                X_dy = tf.cast(self.ifft(f_X * self.kernel_dy), 'float64')
                Y_dx = tf.cast(self.ifft(f_Y * self.kernel_dx), 'float64')
                Y_dy = tf.cast(self.ifft(f_Y * self.kernel_dy), 'float64')

                G -= (u * G_dx + v * G_dy + G * divergence) * self.dt
                X -= (u * X_dx + v * X_dy + X * divergence) * self.dt
                Y -= (u * Y_dx + v * Y_dy + Y * divergence) * self.dt
                return G, X, Y
        elif self.dims == 3:
            self.u = tf.constant(u[0], 'float64')
            self.v = tf.constant(u[1], 'float64')
            self.w = tf.constant(u[2], 'float64')

            omega_x, omega_y, omega_z = self.omega_x, self.omega_y, self.omega_z
            omega2 = omega_x**2 + omega_y**2 + omega_z**2
            omega2_x = tf.constant(
                omega2 + 1 / 3 * omega_x * (omega_x + omega_y + omega_z),
                "complex128")
            omega2_y = tf.constant(
                omega2 + 1 / 3 * omega_y * (omega_x + omega_y + omega_z),
                "complex128")
            omega2_z = tf.constant(
                omega2 + 1 / 3 * omega_z * (omega_x + omega_y + omega_z),
                "complex128")
            decay_x = tf.exp(-viscosity * omega2_x * self.dt)
            decay_y = tf.exp(-viscosity * omega2_y * self.dt)
            decay_z = tf.exp(-viscosity * omega2_z * self.dt)

            delta = tf.constant(-omega2 * self.dt, "complex128")
            decay_G = tf.exp(self.params['D_G'] * delta)
            decay_X = tf.exp(self.params['D_X'] * delta)
            decay_Y = tf.exp(self.params['D_Y'] * delta)

            def flow_integrator(rho, u, v, w):
                # Enter Fourier Domain
                f_rho = self.fft(tf.cast(rho, 'complex128'))
                waves_x = self.fft(tf.cast(u, 'complex128'))
                waves_y = self.fft(tf.cast(v, 'complex128'))
                waves_z = self.fft(tf.cast(w, 'complex128'))

                # Viscosity and internal shear
                waves_x *= decay_x
                waves_y *= decay_y
                waves_z *= decay_z

                # Exit Fourier Domain
                u = tf.cast(self.ifft(waves_x), 'float64')
                v = tf.cast(self.ifft(waves_y), 'float64')
                w = tf.cast(self.ifft(waves_z), 'float64')

                # Calculate gradients
                rho_dx = tf.cast(self.ifft(f_rho * self.kernel_dx), 'float64')
                rho_dy = tf.cast(self.ifft(f_rho * self.kernel_dy), 'float64')
                rho_dz = tf.cast(self.ifft(f_rho * self.kernel_dz), 'float64')

                u_dx = tf.cast(self.ifft(waves_x * self.kernel_dx), 'float64')
                u_dy = tf.cast(self.ifft(waves_x * self.kernel_dy), 'float64')
                u_dz = tf.cast(self.ifft(waves_x * self.kernel_dz), 'float64')

                v_dx = tf.cast(self.ifft(waves_y * self.kernel_dx), 'float64')
                v_dy = tf.cast(self.ifft(waves_y * self.kernel_dy), 'float64')
                v_dz = tf.cast(self.ifft(waves_y * self.kernel_dz), 'float64')

                w_dx = tf.cast(self.ifft(waves_z * self.kernel_dx), 'float64')
                w_dy = tf.cast(self.ifft(waves_z * self.kernel_dy), 'float64')
                w_dz = tf.cast(self.ifft(waves_z * self.kernel_dz), 'float64')

                divergence = u_dx + v_dy + w_dz

                # This would handle log density continuity, but we do G, X and Y individually
                # rho -= (u*rho_dx + v*rho_dy + w*rho_dz + divergence) * self.dt

                # Self-advect flow
                du = -u * u_dx - v * u_dy - w * u_dz
                dv = -u * v_dx - v * v_dy - w * v_dz
                dw = -u * w_dx - v * w_dy - w * w_dz

                # Propagate pressure waves
                du -= c2 * rho_dx
                dv -= c2 * rho_dy
                dw -= c2 * rho_dz

                # Apply strain
                du += viscosity * (rho_dx * (u_dx + u_dx) + rho_dy *
                                   (u_dy + v_dx) + rho_dz *
                                   (u_dz + w_dx) - 2 / 3 * rho_dx * divergence)
                dv += viscosity * (rho_dx * (v_dx + u_dy) + rho_dy *
                                   (v_dy + v_dy) + rho_dz *
                                   (v_dz + w_dy) - 2 / 3 * rho_dy * divergence)
                dw += viscosity * (rho_dx * (w_dx + u_dz) + rho_dy *
                                   (w_dy + v_dz) + rho_dz *
                                   (w_dz + w_dz) - 2 / 3 * rho_dz * divergence)

                u += du * self.dt
                v += dv * self.dt
                w += dw * self.dt

                return u, v, w, divergence

            def diffusion_advection_integrator(G, X, Y, u, v, w, divergence):
                f_G = self.fft(tf.cast(G, 'complex128'))
                f_X = self.fft(tf.cast(X, 'complex128'))
                f_Y = self.fft(tf.cast(Y, 'complex128'))

                f_G *= decay_G
                f_X *= decay_X
                f_Y *= decay_Y

                G = tf.cast(self.ifft(f_G), 'float64')
                X = tf.cast(self.ifft(f_X), 'float64')
                Y = tf.cast(self.ifft(f_Y), 'float64')

                G_dx = tf.cast(self.ifft(f_G * self.kernel_dx), 'float64')
                G_dy = tf.cast(self.ifft(f_G * self.kernel_dy), 'float64')
                G_dz = tf.cast(self.ifft(f_G * self.kernel_dz), 'float64')
                X_dx = tf.cast(self.ifft(f_X * self.kernel_dx), 'float64')
                X_dy = tf.cast(self.ifft(f_X * self.kernel_dy), 'float64')
                X_dz = tf.cast(self.ifft(f_X * self.kernel_dz), 'float64')
                Y_dx = tf.cast(self.ifft(f_Y * self.kernel_dx), 'float64')
                Y_dy = tf.cast(self.ifft(f_Y * self.kernel_dy), 'float64')
                Y_dz = tf.cast(self.ifft(f_Y * self.kernel_dz), 'float64')

                G -= (u * G_dx + v * G_dy + w * G_dz +
                      (G + G0) * divergence) * self.dt
                X -= (u * X_dx + v * X_dy + w * X_dz +
                      (X + X0) * divergence) * self.dt
                Y -= (u * Y_dx + v * Y_dy + w * Y_dz +
                      (Y + Y0) * divergence) * self.dt
                return G, X, Y
        else:
            raise ValueError('Only up to 3D supported')

        reaction_integrator_curried = lambda con_G, con_X, con_Y: reaction_integrator(
            con_G, con_X, con_Y, self.dt, self.params['A'], self.params['B'],
            self.params['k2'], self.params['k-2'], self.params['k5'])

        self.reaction_integrator = tf.function(reaction_integrator_curried)
        self.flow_integrator = tf.function(flow_integrator)
        self.diffusion_advection_integrator = tf.function(
            diffusion_advection_integrator)