调整 Tensorflow2 代码 - 模拟反应扩散孤子以包含 3 个速度场

Adapting Tensorflow2 code - simulating a reaction-diffusion soliton to include 3 velocity fields

我正在尝试修改一个程序来模拟由 X、Y 和 G 基板组成的反应扩散孤子。该程序包括 Navier-Stokes 方程,以便为基板提供涡旋运动。

目前,代码根据速度场 u 和 v 为 X、Y 和 G 提供 rotational/vortical 运动,表示此 2D 模拟中 x 和 y 方向上的速度矢量。 z 轴为 X、Y 和 G 浓度势。

在 1D 中它看起来像这样:

我想更改代码,使基板 X、Y 和 G 各自具有不同的速度(不仅仅是相同的速度)。 IE。 X velocity field --> u_X 和 v_X 等。有人可以帮我修改代码吗?

这是我到目前为止所做的:

原始code: and theory代码基于。

显示了为单独的速度场更改的代码 here

代码是 运行 例如:python3 render_video.py ~/tf2-model-g/nucleation_and_motion_in_fluid_2D.mp4 --params params/nucleation_and_motion_in_fluid_2D.yaml

首先,我将 fluid_model_g________1st_attempt.py#L69 更改为:

    elif self.dims == 2:
        #self.u = tf.constant(u[0], 'float64') # original 2 lines
        #self.v = tf.constant(u[1], 'float64')

        #BJD adaptions - 6 lines below 9.6.2021 
        self.u_X = tf.constant(u[0], 'float64')
        self.v_X = tf.constant(u[1], 'float64')
        self.u_Y = tf.constant(u[2], 'float64')
        self.v_Y = tf.constant(u[3], 'float64')
        self.u_G = tf.constant(u[4], 'float64')
        self.v_G = tf.constant(u[5], 'float64')
        

def diffusion_advection_integrator@fluid_model_g________1st_attempt.py#L159:

        def diffusion_advection_integrator(G, X, Y, u_X, v_X, u_Y, v_Y, u_G, v_G, divergence1,divergence2, divergence3): # BJD original 10.6.2021
        
            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')
            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 # BJD original
            G -= (u_G*G_dx + v_G*G_dy + G*divergence1) * self.dt # BJD change 10.6.2021
            #X -= (u*X_dx + v*X_dy + X*divergence) * self.dt # BJD original
            #Y -= (u*Y_dx + v*Y_dy + Y*divergence) * self.dt # BJD original
            X -= (u_X*X_dx + v_X*X_dy + X*divergence2) * self.dt # BJD change 10.6.2021
            Y -= (u_Y*Y_dx + v_Y*Y_dy + Y*divergence3) * self.dt # BJD change 10.6.2021

            return G, X, Y
            

原始代码显示在这里:fluid_model_g.py#L57 and here: fluid_model_g.py#L119

新代码中包含 3 个单独的密度:@fluid_model_g________1st_attempt.py#L297

    # rho = tf.math.log(self.params['base-density'] + density_of_reactants) # BJD original here
    rho1 = tf.math.log(self.params['base-density1'] + density_of_reactants) # BJD added 10.6.2021
    rho2 = tf.math.log(self.params['base-density2'] + density_of_reactants) # BJD added 10.6.2021
    rho3 = tf.math.log(self.params['base-density3'] + density_of_reactants) # BJD added 10.6.2021
    

base-density1base-density2base-density3已添加到yaml文件:

#base-density: 35.0 ~ BJD original here
base-density1: 35.0 # BJD added 10.6.2021
base-density2: 36.0 # BJD added 10.6.2021
base-density3: 37.0 # BJD added 10.6.2021

fluid_model_g.py 的底部,更改了这些行:

    if self.dims == 2:
        #u, v = self.u, self.v  # Store unintegrated flow so that we're on the same timestep --- BJD original line 9.6.2021
        u_X, v_X = self.u_X, self.v_X  # Store unintegrated flow so that we're on the same timestep --- BJD added 9.6.2021
        u_Y, v_Y = self.u_Y, self.v_Y  # Store unintegrated flow so that we're on the same timestep --- BJD added 9.6.2021
        u_G, v_G = self.u_G, self.v_G  # Store unintegrated flow so that we're on the same timestep --- BJD added 9.6.2021

        #self.u, self.v, divergence = self.flow_integrator(rho, self.u, self.v) -BJD original line 9.6.2021
        self.u_X, self.v_X, divergence1 = self.flow_integrator(rho1, self.u_X, self.v_X) #--- BJD added 9.6.2021
        self.u_Y, self.v_Y, divergence2 = self.flow_integrator(rho2, self.u_Y, self.v_Y) #--- BJD added 9.6.2021
        self.u_G, self.v_G, divergence3 = self.flow_integrator(rho3, self.u_G, self.v_G) #--- BJD added 9.6.2021

        #self.G, self.X, self.Y = self.diffusion_advection_integrator(self.G, self.X, self.Y, u, v, divergence) # BJD original line 10.6.2021
        self.G, self.X, self.Y = self.diffusion_advection_integrator(self.G, self.X, self.Y, u_X, v_X, u_Y, v_Y, u_G, v_G, divergence1, divergence2, divergence3) #--- BJD added 10.6.2021
        

查看行:fluid_model_g________1st_attempt.py#L47

    #super().__init__(dx, dt, concentration_G.shape) # BJD original 13.6.2021
    super().__init__(dx, dt, concentration_G.shape, concentration_X.shape, concentration_Y.shape) # BJD change 13.6.2021
    

我开始更改文件 pde_solver.py @ pde_solver________1st_attempt.py#L10 and pde_solver________1st_attempt.py#L16 and pde_solver________1st_attempt.py#L55; pde_solver________1st_attempt.py#L81 and pde_solver________1st_attempt.py#L99

def __init__(self, dx, dt, shape_G, shape_X, shape_Y): # shape_G, shape_X, shape_Y ::: put in by David J. 13.6.2021
    self.dx = dx
    self.dt = dt
    self.t = 0

    omega = []
    for s in shape_G:  # shape_G, shape_X, shape_Y, i.e. 3 for loops made; original 1 for loop ::: put in by David J. 13.6.2021
        wave_numbers = np.arange(s)
        wave_numbers -= s * (2*wave_numbers > s)  # Deal with TensorFlow's uncentered FFT
        expected_span = 2*np.pi
        actual_span = s*dx
        omega.append(wave_numbers * expected_span / actual_span)
    for s in shape_X:
        wave_numbers = np.arange(s)
        wave_numbers -= s * (2*wave_numbers > s)  # Deal with TensorFlow's uncentered FFT
        expected_span = 2*np.pi
        actual_span = s*dx
        omega.append(wave_numbers * expected_span / actual_span)
    for s in shape_Y:
        wave_numbers = np.arange(s)
        wave_numbers -= s * (2*wave_numbers > s)  # Deal with TensorFlow's uncentered FFT
        expected_span = 2*np.pi
        actual_span = s*dx
        omega.append(wave_numbers * expected_span / actual_span)
    self.omega = np.meshgrid(*omega, indexing='ij')
    self.dims = len(shape_G) + len(shape_X) + len(shape_Y)
    # The naming is a bit off. These are not actual 'kernels'.
    # They are discrete fourier transforms of the periodic versions of the kernels
    if self.dims == 1:
        self.fft = tf.signal.fft
        self.ifft = tf.signal.ifft
        self.omega_x = self.omega[0]
    elif self.dims == 2:
        self.fft = tf.signal.fft2d
        self.ifft = tf.signal.ifft2d

        self.omega_x = self.omega[0]
        self.omega_y = self.omega[1]
    elif self.dims == 3:
        self.fft = tf.signal.fft3d
        self.ifft = tf.signal.ifft3d

        self.omega_x = self.omega[0]
        self.omega_y = self.omega[1]
        self.omega_z = self.omega[2]
    elif self.dims == 6: # With 3 fluids 2 dimensions # :::: put in by David J. 13.6.2021
        self.fft = tf.signal.fft2d
        self.ifft = tf.signal.ifft2d

        self.omega_x = self.omega[0]
        self.omega_y = self.omega[1]
        self.omega_X_x = self.omega[2]
        self.omega_X_y = self.omega[3]
        self.omega_Y_x = self.omega[4]
        self.omega_Y_y = self.omega[5]
    else:
        raise ValueError('{} dimensions not supported'.format(self.dims))


class PDESolverDx(PDESolver):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.dims == 1:
            self.kernel_dx = tf.constant(1j * self.omega_x, 'complex128')
        elif self.dims == 2:
            self.kernel_dx = tf.constant(1j * self.omega_x, 'complex128')
            self.kernel_dy = tf.constant(1j * self.omega_y, 'complex128')
        elif self.dims == 3:
            self.kernel_dx = tf.constant(1j * self.omega_x, 'complex128')
            self.kernel_dy = tf.constant(1j * self.omega_y, 'complex128')
            self.kernel_dz = tf.constant(1j * self.omega_z, 'complex128')
        elif self.dims == 6:   # :::: put in by David J. 13.6.2021
            self.kernel_dx = tf.constant(1j * self.omega_x, 'complex128')
            self.kernel_dy = tf.constant(1j * self.omega_y, 'complex128')
            self.kernel_X_dx = tf.constant(1j * self.omega_X_x, 'complex128')
            self.kernel_X_dy = tf.constant(1j * self.omega_X_y, 'complex128')
            self.kernel_Y_dx = tf.constant(1j * self.omega_Y_x, 'complex128')
            self.kernel_Y_dy = tf.constant(1j * self.omega_Y_y, 'complex128')


class PDESolverDx2(PDESolverDx):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.dims == 1:
            self.kernel_laplacian = tf.constant(-self.omega_x**2, 'complex128')
        elif self.dims == 2:
            self.kernel_laplacian = tf.constant(-(self.omega_x**2 + self.omega_y**2), 'complex128')
        elif self.dims == 3:
            self.kernel_laplacian = tf.constant(-(self.omega_x**2 + self.omega_y**2 + self.omega_z**2), 'complex128')
        elif self.dims == 6:  # :::: put in by David J. 13.6.2021
            self.kernel_laplacian = tf.constant(-(self.omega_x**2 + self.omega_y**2), 'complex128')
            self.kernel_laplacian_X = tf.constant(-(self.omega_X_x**2 + self.omega_X_y**2), 'complex128')
            self.kernel_laplacian_Y = tf.constant(-(self.omega_Y_x**2 + self.omega_Y_y**2), 'complex128')

原文显示在这里:pde_solver.py#L10

这是我所能得到的!谁能帮我解决这个程序更改,包括 X、Y 和 G 基板的单独速度场?

直觉上,答案似乎如下所示,只需为每个 GX 和 [=17 重新定义不同的 rho(压力项) =].其中,速度场uv,每次都重新定义:

def step(self):
    self.G, self.X, self.Y = self.reaction_integrator(self.G, self.X, self.Y)
    density_of_reactants = (
        self.params['density_G'] * self.G +
        self.params['density_X'] * self.X +
        self.params['density_Y'] * self.Y
    )

    if self.dims == 2:
        u, v = self.u, self.v  # Store unintegrated flow so that we're on the same timestep

        rho = tf.math.log(35.0 + density_of_reactants) # rho defined for self.G
        self.u, self.v, divergence = self.flow_integrator(rho, self.u, self.v)
        self.G = self.diffusion_advection_integrator(self.G, self.X, self.Y, u, v, divergence) # G calculated

        rho = tf.math.log(36.0 + density_of_reactants) # rho defined for self.X
        self.u, self.v, divergence = self.flow_integrator(rho, self.u, self.v)
        self.X = self.diffusion_advection_integrator(self.G, self.X, self.Y, u, v, divergence) # X calculated
                
        rho = tf.math.log(37.0 + density_of_reactants) # rho defined for self.Y
        self.u, self.v, divergence = self.flow_integrator(rho, self.u, self.v)
        self.Y = self.diffusion_advection_integrator(self.G, self.X, self.Y, u, v, divergence) # Y calculated

原代码为here.

然而,这给出了错误信息:

Exception has occurred: ValueError
in user code:

    /home/brendan/software/tf2-model-g-velocity/fluid_model_g.py:122 diffusion_advection_integrator  *
        f_X = self.fft(tf.cast(X, 'complex128'))
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py:201 wrapper  **
        return target(*args, **kwargs)
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/ops/math_ops.py:920 cast
        x = ops.convert_to_tensor(x, name="x")
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1499 convert_to_tensor
        ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py:1502 _autopacking_conversion_function
        return _autopacking_helper(v, dtype, name or "packed")
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/ops/array_ops.py:1438 _autopacking_helper
        return gen_array_ops.pack(elems_as_tensors, name=scope)
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/ops/gen_array_ops.py:6476 pack
        _, _, _op, _outputs = _op_def_library._apply_op_helper(
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/framework/op_def_library.py:742 _apply_op_helper
        op = g._create_op_internal(op_type_name, inputs, dtypes=None,
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/framework/func_graph.py:591 _create_op_internal
        return super(FuncGraph, self)._create_op_internal(  # pylint: disable=protected-access
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:3477 _create_op_internal
        ret = Operation(
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1974 __init__
        self._c_op = _create_c_op(self._graph, node_def, inputs,
    /home/brendan/.local/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1815 _create_c_op
        raise ValueError(str(e))

    ValueError: Shapes must be equal rank, but are 3 and 2
        From merging shape 0 with other shapes. for '{{node Cast_1/x}} = Pack[N=3, T=DT_DOUBLE, axis=0](X, X_1, X_2)' with input shapes: [3,426,240], [426,240], [426,240].

During handling of the above exception, another exception occurred:

  File "/tmp/tmp10_g9n1p.py", line 15, in tf__diffusion_advection_integrator
    f_X = ag__.converted_call(ag__.ld(self).fft, (ag__.converted_call(ag__.ld(tf).cast, (ag__.ld(X), 'complex128'), None, fscope),), None, fscope)

During handling of the above exception, another exception occurred:

  File "/home/brendan/software/tf2-model-g-velocity/fluid_model_g.py", line 282, in step
    self.Y = self.diffusion_advection_integrator(self.G, self.X, self.Y, u, v, divergence) # Y calculated
  File "/home/brendan/software/tf2-model-g-velocity/render_video.py", line 78, in nucleation_and_motion_in_G_gradient_fluid_2D
    fluid_model_g.step()
  File "/home/brendan/software/tf2-model-g-velocity/render_video.py", line 292, in <module>
    episodes[args.episode](writer, args)

出现了Shapes must be equal rank,所以:

self.Y = self.diffusion_advection_integrator(self.G, self.X, self.Y, u, v, divergence) # Y calculated

必须是:

self.G, self.X, self.Y = self.diffusion_advection_integrator(self.G, self.X, self.Y, u, v, divergence)

问题已通过以下过程解决。 diffusion_advection_integrator() 的 3 个独立函数制作位置:

def diffusion_advection_integrator1(G, u, v, divergence): 
def diffusion_advection_integrator2(X, u, v, divergence): 
def diffusion_advection_integrator3(Y, u, v, divergence): 

每个仅包含 GXY 组件。原码here.

然后剩下的代码更新如下:

    self.reaction_integrator = tf.function(reaction_integrator_curried)
    self.flow_integrator = tf.function(flow_integrator)
    #self.diffusion_advection_integrator = tf.function(diffusion_advection_integrator) # original
    self.diffusion_advection_integrator1 = tf.function(diffusion_advection_integrator1) # BJD added 25.6.2021
    self.diffusion_advection_integrator2 = tf.function(diffusion_advection_integrator2) # BJD added 25.6.2021
    self.diffusion_advection_integrator3 = tf.function(diffusion_advection_integrator3) # BJD added 25.6.2021

def step(self):
    self.G, self.X, self.Y = self.reaction_integrator(self.G, self.X, self.Y)
    density_of_reactants = (
        self.params['density_G'] * self.G +
        self.params['density_X'] * self.X +
        self.params['density_Y'] * self.Y
    )

    if self.dims == 2:
        u, v = self.u, self.v  # Store unintegrated flow so that we're on the same timestep

        rho = tf.math.log(35.0 + density_of_reactants) # rho defined for self.G
        self.u, self.v, divergence = self.flow_integrator(rho, self.u, self.v)
        self.G = self.diffusion_advection_integrator1(self.G, u, v, divergence) # G calculated

        rho = tf.math.log(36.0 + density_of_reactants) # rho defined for self.X
        self.u, self.v, divergence = self.flow_integrator(rho, self.u, self.v)
        self.X = self.diffusion_advection_integrator2(self.X, u, v, divergence) # X calculated
                
        rho = tf.math.log(37.0 + density_of_reactants) # rho defined for self.Y
        self.u, self.v, divergence = self.flow_integrator(rho, self.u, self.v)
        self.Y = self.diffusion_advection_integrator3(self.Y, u, v, divergence) # Y calculated

上面部分的原始代码显示在here.