Swarm-NG  1.1
gravitation_acc.hpp
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) 2010 by Saleh Dindar and the Swarm-NG Development Team *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation; either version 3 of the License. *
7  * *
8  * This program is distributed in the hope that it will be useful, *
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11  * GNU General Public License for more details. *
12  * *
13  * You should have received a copy of the GNU General Public License *
14  * along with this program; if not, write to the *
15  * Free Software Foundation, Inc., *
16  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
17  ************************************************************************/
18 
26 #pragma once
27 
28 #include "gravitation_common.hpp"
29 
30 namespace swarm { namespace gpu { namespace bppt {
31 
38 template<class T>
40  public:
41  const static int nbod = T::n;
42  const static int pair_count = (nbod*(nbod-1))/2;
43  const static int CHUNK_SIZE = SHMEM_CHUNK_SIZE;
44 
45  typedef GravitationAccScalars<CHUNK_SIZE> shared_data [pair_count][3];
46 
47  private:
48  ensemble::SystemRef& sys;
49  shared_data &shared;
50 
52  public:
53  GPUAPI GravitationAcc(ensemble::SystemRef& sys,shared_data &shared):sys(sys),shared(shared){ }
54 
55  private:
56 
57  GPUAPI void calc_pair(int ij)const{
58  int i = first<nbod>( ij );
59  int j = second<nbod>( ij );
60  if(i != j){
61 
62  double dx[3] = { sys[j][0].pos()- sys[i][0].pos(),sys[j][1].pos()- sys[i][1].pos(), sys[j][2].pos()- sys[i][2].pos() };
63  double dv[3] = { sys[j][0].vel()- sys[i][0].vel(),sys[j][1].vel()- sys[i][1].vel(), sys[j][2].vel()- sys[i][2].vel() };
64  double r2 = dx[0]*dx[0]+dx[1]*dx[1]+dx[2]*dx[2];
65  double acc_mag = rsqrt(r2) / r2;
66 
67 #pragma unroll
68  for(int c = 0; c < 3; c ++)
69  {
70  shared[ij][c].acc() = dx[c]* acc_mag;
71  }
72  }
73 
74  }
75 
77  public:
78  GPUAPI double one_over_r(const int b1, const int b2) const
79  {
80  double sum = 0.;
81 
82  for(int d = 0; d < pair_count; d++)
83  {
84  int x = first<nbod>(d), y= second<nbod>(d);
85  if( ((x==b1) && (y==b2)) || (x==b2) && (y==b1))
86  {
87  sum += shared[d][0].acc()*shared[d][0].acc();
88  sum += shared[d][1].acc()*shared[d][1].acc();
89  sum += shared[d][2].acc()*shared[d][2].acc();
90  }
91  }
92  return sum;
93  }
94 
95  private:
96  GPUAPI double sum_acc_planets(int b,int c)const{
97  double acc_sum = 0;
98 
100 #pragma unroll
101  for(int d = 0; d < pair_count; d++){
102  int x = first<nbod>(d), y= second<nbod>(d);
103 
104  if(x == b){
105  if(y != 0)
106  acc_sum += shared[d][c].acc() * sys[y].mass();
107  }else if(y == b){
108  if(x != 0)
109  acc_sum -= shared[d][c].acc() * sys[x].mass();
110  }
111  }
112 
113  return acc_sum;
114  }
115 
116  GPUAPI double sum_acc(int b,int c) const{
117  double acc_from_planets = 0;
118  double acc_from_sun = 0;
119 
121 #pragma unroll
122  for(int d = 0; d < pair_count; d++){
123  int x = first<nbod>(d), y= second<nbod>(d);
124 
125  if(x == b){
126  if(y == 0)
127  acc_from_sun += shared[d][c].acc() * sys[y].mass();
128  else
129  acc_from_planets += shared[d][c].acc() * sys[y].mass();
130  }else if(y == b){
131  if(x == 0)
132  acc_from_sun -= shared[d][c].acc() * sys[x].mass();
133  else
134  acc_from_planets -= shared[d][c].acc() * sys[x].mass();
135  }
136  }
137 
138  return acc_from_sun + acc_from_planets;
139  }
140 
142  public:
143  GPUAPI void operator() (int ij,int b,int c,double& pos,double& vel,double& acc)const{
144  // Write positions to shared (global) memory
145  if(b < nbod && c < 3)
146  sys[b][c].pos() = pos , sys[b][c].vel() = vel;
147  __syncthreads();
148  if(ij < pair_count)
149  calc_pair(ij);
150  __syncthreads();
151  if(b < nbod && c < 3){
152  acc = sum_acc(b,c);
153  }
154  }
155 
171  GPUAPI double acc_planets (int ij,int b,int c)const{
172  if(ij < pair_count)
173  calc_pair(ij);
174  __syncthreads();
175  if(b < nbod && c < 3){
176  return sum_acc_planets(b,c);
177  }else
178  return 0;
179  }
180 
193  GPUAPI double acc (int ij,int b,int c,double& pos,double& vel)const{
194  // Write positions to shared (global) memory
195  if(b < nbod && c < 3)
196  sys[b][c].pos() = pos , sys[b][c].vel() = vel;
197  __syncthreads();
198  if(ij < pair_count)
199  calc_pair(ij);
200  __syncthreads();
201  if(b < nbod && c < 3){
202  return sum_acc(b,c);
203  }else
204  return 0;
205  }
206 
209  return ( 3*nbod > (nbod-1)*nbod/2 ) ? nbod*3 : (nbod-1)*nbod/2;
210  }
211 
213  static GENERIC int shmem_per_system() {
214  return sizeof(shared_data)/CHUNK_SIZE;
215  }
216 
217 
218 };
219 
220 } } } // end of namespace bppt :: gpu :: swarm
221 
222