C++ 对CUDA::推力函子进行嵌套调用的函子,作为zip_迭代器运行
我发现使用CUDA::Thurst迭代器在GPU上实现运行在GPU上的ODEs解算器例程时遇到了一些困难,这些迭代器在GPU中求解了一系列耦合的一阶方程。我想研究前一种方法,使用户能够使用处理向量元组的任意函子尽可能像人类一样编写方程组。下面是一小段代码:C++ 对CUDA::推力函子进行嵌套调用的函子,作为zip_迭代器运行,c++,cuda,thrust,C++,Cuda,Thrust,我发现使用CUDA::Thurst迭代器在GPU上实现运行在GPU上的ODEs解算器例程时遇到了一些困难,这些迭代器在GPU中求解了一系列耦合的一阶方程。我想研究前一种方法,使用户能够使用处理向量元组的任意函子尽可能像人类一样编写方程组。下面是一小段代码: #include <thrust/device_vector.h> #include <thrust/transform.h> #include <thrust/sequence.h> #include &
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/fill.h>
#include <thrust/replace.h>
#include <thrust/functional.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>
__host__ __device__ float f1(float x)
{
return sinf(x);
}
__host__ __device__ float f2(float x)
{
return cosf(x);
}
__host__ __device__ float Vx(float x)
{
return sinf(x);
}
struct q_dot
{
float x;
float delta;
q_dot(float _x,float _delta): x(_x),delta(_delta){};
template <typename Tuple>
__host__ __device__
float operator()(Tuple t)
{
float p = thrust::get<1>(t) + delta;
return p/MASS;
}
};
struct p_dot
{
float x;
float delta;
p_dot(float _x,float _delta): x(_x),delta(_delta){};
template <typename Tuple>
__host__ __device__
float operator()(Tuple t)
{
float q = thrust::get<0>(t) + delta;
return -Vx(q);
}
};
struct euler_functor
{
unsigned fn;
float h;
float er;
float x0;
euler_functor(unsigned _fn,float _x0,float _h, float _er) : fn(_fn),h(_h),er(_er),x0(_x0) {};
template <typename Tuple>
__host__ __device__
void operator()(Tuple t) const {
// if (fn == 1) y = h*f1(y);
//else if (fn == 2) y = h*f2(y); This can be handled in this way?
q = h*p_dot(x0,h/2)(t);
p = h*p_dot(x0,h/2)(t);
float er_p,er_q;
er_p=0.5*h*p_dot(x0,h/2)(t);
er_q=0.5*h*q_dot(x0,h/2)(t);
er = er_p;
}
};
int main(void)
{
float t=0;
float t_step=0.1;
float error;
const unsigned N = 8;
// allocate three device_vectors with 10 elements
thrust::device_vector<float> Q(N),P(N);
// initilaize to some values
thrust::sequence(Q.begin(), Q.end(), 0.0f, (float)(6.283/(float)N));
// initilaize to some values
thrust::sequence(P.begin(), P.end(), 0.0f, (float)(10.283/(float)N));
// apply euler for each element of Q and P
//thrust::for_each(X.begin(),X.end(),euler_functor(1,t,t_step,error)); this becomes:
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(Q.begin(),P.begin())),
thrust::make_zip_iterator(thrust::make_tuple( Q.end(), P.end())),euler_functor(1,t,t_step,error));
// print the values
for(int i = 0; i < N; i++) std::cout<< Q[i]<<" "<<P[i]<< std::endl;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
__主机设备浮点f1(浮点x)
{
返回sinf(x);
}
__主机设备浮点数f2(浮点数x)
{
返回cosf(x);
}
__主机设备浮点Vx(浮点x)
{
返回sinf(x);
}
结构q_点
{
浮动x;
浮动三角洲;
q_点(float _x,float _delta):x(_x),delta(_delta){};
样板
__主机设备__
浮点运算符()(元组t)
{
浮动p=推力::get(t)+增量;
返回p/质量;
}
};
结构点
{
浮动x;
浮动三角洲;
p_点(float _x,float _delta):x(_x),delta(_delta){};
样板
__主机设备__
浮点运算符()(元组t)
{
浮动q=推力::get(t)+增量;
返回-Vx(q);
}
};
结构euler_函子
{
未签名的fn;
浮动h;
浮子;
浮点数x0;
euler_函子(无符号fn,float x0,float h,float er):fn(fn),h(h),er(er),x0(x0){;
样板
__主机设备__
void运算符()(元组t)常量{
//如果(fn==1)y=h*f1(y);
//否则,如果(fn==2)y=h*f2(y),可以这样处理吗?
q=h*p_点(x0,h/2)(t);
p=h*p_点(x0,h/2)(t);
浮动er_p,er_q;
er_p=0.5*h*p_点(x0,h/2)(t);
er_q=0.5*h*q_点(x0,h/2)(t);
er=er_p;
}
};
内部主(空)
{
浮动t=0;
浮动t_阶跃=0.1;
浮动误差;
常数无符号N=8;
//分配三个包含10个元素的设备_向量
推力:器件_矢量Q(N),P(N);
//初始化为某些值
推力:顺序(Q.开始(),Q.结束(),0.0f,(浮动)(6.283/(浮动)N));
//初始化为某些值
推力:顺序(P.开始(),P.结束(),0.0f,(浮动)(10.283/(浮动)N));
//对Q和P的每个元素应用euler
//推力::对于每个(X.begin(),X.end(),euler_函子(1,t,t_步,error)),这变成:
推力::for_each(推力::make_zip_迭代器(推力::make_元组(Q.begin(),P.begin()),
推力::make_-zip_迭代器(推力::make_元组(Q.end(),P.end())、euler_函子(1,t,t_步,error));
//打印值
对于(int i=0;i
质量
未定义
你的p_点
和q_点
函子需要额外的\u设备
装饰
在euler函子中使用p
和q
变量没有任何意义;它们没有在任何地方定义,这也不是将值返回到p
和q
向量的正确方法,如果这是您的意图的话
我们不会通过实例化时传递给函子的变量返回数据。因此,为了在每个时间步返回er
变量,我创建了一个单独的向量(ERP
和ERQ
)来执行此操作
这是一个修改过的代码,它解决了上述问题和其他各种问题。虽然我没有详细检查算法,但它似乎返回了合理的结果
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/fill.h>
#include <thrust/replace.h>
#include <thrust/functional.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>
#define MASS 1.0f
__host__ __device__ float f1(float x)
{
return sinf(x);
}
__host__ __device__ float f2(float x)
{
return cosf(x);
}
__host__ __device__ float Vx(float x)
{
return sinf(x);
}
struct q_dot
{
float x;
float delta;
__host__ __device__
q_dot(float _x,float _delta): x(_x),delta(_delta){};
template <typename Tuple>
__host__ __device__
float operator()(Tuple t)
{
float p = thrust::get<1>(t) + delta;
return p/MASS;
}
};
struct p_dot
{
float x;
float delta;
__host__ __device__
p_dot(float _x,float _delta): x(_x),delta(_delta){};
template <typename Tuple>
__host__ __device__
float operator()(Tuple t)
{
float q = thrust::get<0>(t) + delta;
return -Vx(q);
}
};
struct euler_functor
{
unsigned fn;
float h;
float x0;
euler_functor(unsigned _fn,float _x0,float _h) : fn(_fn),h(_h),x0(_x0) {};
template <typename Tuple>
__host__ __device__
void operator()(const Tuple &t) {
// if (fn == 1) y = h*f1(y);
//else if (fn == 2) y = h*f2(y);
float t0, t1, t2, t3;
t0 = h*p_dot(x0,h/2.0f)(t);
t1 = h*q_dot(x0,h/2.0f)(t);
t2=0.5*h*p_dot(x0,h/2.0f)(t);
t3=0.5*h*q_dot(x0,h/2.0f)(t);
thrust::get<0>(t) = t0;
thrust::get<1>(t) = t1;
thrust::get<2>(t) = t2;
thrust::get<3>(t) = t3;
}
};
int main(void)
{
float t=0;
float t_step=0.1;
const unsigned N = 8;
// allocate three device_vectors with 10 elements
thrust::device_vector<float> Q(N),P(N), ERP(N), ERQ(N);
// initilaize to some values
thrust::sequence(Q.begin(), Q.end(), 0.0f, (float)(6.283/(float)N));
// initilaize to some values
thrust::sequence(P.begin(), P.end(), 0.0f, (float)(10.283/(float)N));
for(int i = 0; i < N; i++) std::cout<< Q[i]<<" "<<P[i]<< " "<< ERP[i] << " " << ERQ[i] << std::endl;
std::cout<< "*****" << std::endl;
// apply euler for each element of Q and P
//thrust::for_each(X.begin(),X.end(),euler_functor(1,t,t_step,error)); this becomes:
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(Q.begin(),P.begin(),ERP.begin(), ERQ.begin())),thrust::make_zip_iterator(thrust::make_tuple(Q.end(),P.end(),ERP.end(), ERQ.end())),euler_functor(1,t,t_step));
// print the values
for(int i = 0; i < N; i++) std::cout<< Q[i]<<" "<<P[i]<< " "<< ERP[i] << " " << ERQ[i] << std::endl;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义质量为1.0f
__主机设备浮点f1(浮点x)
{
返回sinf(x);
}
__主机设备浮点数f2(浮点数x)
{
返回cosf(x);
}
__主机设备浮点Vx(浮点x)
{
返回sinf(x);
}
结构q_点
{
浮动x;
浮动三角洲;
__主机设备__
q_点(float _x,float _delta):x(_x),delta(_delta){};
样板
__主机设备__
浮点运算符()(元组t)
{
浮动p=推力::get(t)+增量;
返回p/质量;
}
};
结构点
{
浮动x;
浮动三角洲;
__主机设备__
p_点(float _x,float _delta):x(_x),delta(_delta){};
样板
__主机设备__
浮点运算符()(元组t)
{
浮动q=推力::get(t)+增量;
返回-Vx(q);
}
};
结构euler_函子
{
未签名的fn;
浮动h;
浮点数x0;
euler_函子(无符号fn,float x0,float h):fn(fn),h(h),x0(x0){};
样板
__主机设备__
void运算符()(常量元组(&t){
//如果(fn==1)y=h*f1(y);
//如果(fn==2)y=h*f2(y);
浮球t0、t1、t2、t3;
t0=h*p_点(x0,h/2.0f)(t);
t1=h*q_点(x0,h/2.0f)(t);
t2=0.5*h*p_点(x0,h/2.0f)(t);
t3=0.5*h*q_点(x0,h/2.0f)(t);
推力:get(t)=t0;
推力:get(t)=t1;
推力:get(t)=t2;
推力:get(t)=t3;
}
};
内部主(空)
{
浮动t=0;
浮动t_阶跃=0.1;
常数无符号N=8;
//分配三个包含10个元素的设备_向量
推力:设备向量Q(N),P(N),ERP(N),ERQ(N);
//初始化为某些值
推力:顺序(Q.开始(),Q.结束(),0.0f,(浮动)(6.283/(浮动)N));
//初始化为某些值
推力:顺序(P.开始(),P.结束(),0.0f,(浮动)(10.283/(浮动)N));
对于(inti=0;i