Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 需要一种从大量三维坐标系绘制平面的有效方法_Python_Performance_Parallel Processing_Cuda_Scientific Computing - Fatal编程技术网

Python 需要一种从大量三维坐标系绘制平面的有效方法

Python 需要一种从大量三维坐标系绘制平面的有效方法,python,performance,parallel-processing,cuda,scientific-computing,Python,Performance,Parallel Processing,Cuda,Scientific Computing,我在2D摄像机上采集了一些探测器数据,然后将其转换为实验室帧,这样我就得到了图像中每个像素的(x^2+y^2)和z坐标。但是物体绕着法线旋转,每次旋转都有一个img。我对(x^2+y^2)应用一个旋转矩阵,得到每个img的x和y矩阵,因此每个图像/角度的结果都是这样的。所以每个像素都有一个3D位置和强度 z x y img 444444444 123456789 123456789 123456789

我在2D摄像机上采集了一些探测器数据,然后将其转换为实验室帧,这样我就得到了图像中每个像素的(
x^2+y^2
)和
z
坐标。但是物体绕着法线旋转,每次旋转都有一个img。我对(
x^2+y^2
)应用一个旋转矩阵,得到每个
img
x
y
矩阵,因此每个图像/角度的结果都是这样的。所以每个像素都有一个3D位置和强度

z                  x            y          img
444444444     123456789     123456789    123456789                  
333333333     123456789     123456789    423466789
222222222     123456789     123456789    223256789
111111111     123456789     123456789    523456689
然后我想做的是提取一个平面,即在给定的z范围内绘制一张x,y的地图

以下情况使问题稍微复杂一些:

实验室框架实际上是弯曲的,所以我不能指望x和y的每一行都是一样的。 图像大小约为2048x2048x32位(Tiff)-可以有1000个图像

我目前的解决方案是使用CUDA/Numba,我有一个函数计算给定角度的
z
x
y
img
,所以我对所有角度都这样做。然后,每次我都会对一些行进行切片,并用
x
y
img
值来扩展列表。然后使用
scipy.interpolate.griddata
生成二维地图
griddata
也非常慢,GPU上的任何东西都可能更好

整个过程相当缓慢,所以我正在寻找更好的解决方案,或者可能已经有一个库在这样做了?CUDA代码看起来是这样的,它不是那么慢,而是它自己:

#constants are q0, angi, rot_direction, SDD, k0, Binv
@cuda.jit
    def detector_to_hkl_kernel(h_glob,k_glob,l_glob,omega_rad):
        #get the current thread position
        j,i = cuda.grid(2)

        if j < h_glob.shape[0] and i < h_glob.shape[1]:
            delta_z= (q0[1]-j)*pixel_y  #real-space dinstance from centre pixel y
            delta_x = (i-q0[0])*pixel_x  #real-space dinstance from centre pixel x
            delR = math.sqrt(delta_x**2 + delta_z**2)            
            dist = math.sqrt(delta_x**2+SDD**2 + delta_z**2) #distance to pixel      

            #lab coorindates of pixel in azimuthal angles
            del_pix  = math.atan(delta_x/ SDD)
            gam_pix = math.atan(delta_z/math.sqrt(delta_x**2 + SDD**2))-angi*math.cos(del_pix)
                            
            #lab coordinates in momenturm transfer                                  
            qx = k0*(math.cos(gam_pix)*math.cos(del_pix)-math.cos(angi))
            qy = k0*(math.cos(gam_pix)*math.sin(del_pix)) 
            qz = k0*(math.sin(gam_pix)+math.sin(angi))

            so = math.sin(rotDirection*omega_rad)
            co = math.cos(rotDirection*omega_rad)
            # we deal with the angle of incidence in the momentum transfer calc
            # so that part of the rotation matrix can be fixed
            ci = 1 #math.cos(angi) 
            si = 0 #math.sin(angi)

            #rotation matrix
            hphi_1 = so*(ci*qy+si*qz)+co*qx
            hphi_2 = co*(ci*qy+si*qz)-so*qx
            hphi_3 = ci*qz-si*qy
                
            #H= Binv dot Hphi 
            # compute the dot product manually 
            h_glob[j,i] = Binv[0][0]*hphi_1+Binv[0][1]*hphi_2+Binv[0][2]*hphi_3
            k_glob[j,i] = Binv[1][0]*hphi_1+Binv[1][1]*hphi_2+Binv[1][2]*hphi_3
            l_glob[j,i] = Binv[2][0]*hphi_1+Binv[2][1]*hphi_2+Binv[2][2]*hphi_3              
            
        
    h_global_mem  = cuda.to_device(np.zeros((pixel_count_y,pixel_count_x)))
    k_global_mem  = cuda.to_device(np.zeros((pixel_count_y,pixel_count_x)))
    l_global_mem  = cuda.to_device(np.zeros((pixel_count_y,pixel_count_x)))                  

    # Configure the blocks
    threadsperblock = (16, 16)
    blockspergrid_x = int(math.ceil(pixel_count_y / threadsperblock[0]))
    blockspergrid_y = int(math.ceil(pixel_count_x / threadsperblock[1]))
    blockspergrid = (blockspergrid_x, blockspergrid_y)

    detector_to_hkl_kernel[blockspergrid, threadsperblock](h_global_mem,k_global_mem,l_global_mem, omega_rad)        
    return [h_global_mem.copy_to_host(),k_global_mem.copy_to_host(),l_global_mem.copy_to_host()]  
#常数为q0、angi、旋转方向、SDD、k0、Binv
@cuda.jit
def探测器至hkl_内核(h_glob、k_glob、l_glob、omega_rad):
#获取当前线程位置
j、 i=cuda.grid(2)
如果j
首先,请注意,这里使用的是双精度,主流的中端消费级GPU计算双精度浮点数的速度非常慢。事实上,GTX 1660超级GPU的简单精度计算能力为5027千兆次,双精度计算能力仅为157千兆次(慢32倍)。一个简单的解决方案是通过指定
dtype=np.float32
或使用
array.astype(np.float32)
转换数组,在代码中使用简单精度浮点数。如果不能使用简单精度或混合精度,另一种昂贵的解决方案可能是使用专用于此的专业GPU

此外,可以提前计算多个表达式并将其存储在常量中。这包括例如
math.cos(angi)
math.sin(angi)
1.0/SDD
。其他一些表达式可以存储在临时变量中,因为编译器可能无法有效地分解代码(主要原因是)

此外,三角函数通常非常昂贵,尤其是当您希望计算符合IEEE-754标准时(这可能是
math.xxx
调用的情况)。您可以改为使用近似值。CUDA提供了
\uuuu cosf
\uuuu sinf
\uuu tanf
内部函数,这些函数应该更快(但如果使用它们,请注意结果)。我不确定您是否可以直接调用它们,但您可以将参数
fastmath=True
添加到JIT装饰器中,它可以为您这样做

我认为使用32x8的2D线程块可能会快一点,因为线程是以扭曲方式打包的