| 1 | /* | 
| 2 |  * grid_dist_id_iterator_sub.hpp | 
| 3 |  * | 
| 4 |  *  Created on: Feb 4, 2015 | 
| 5 |  *      Author: Pietro Incardona | 
| 6 |  */ | 
| 7 |  | 
| 8 | #ifndef GRID_DIST_ID_ITERATOR_HPP_ | 
| 9 | #define GRID_DIST_ID_ITERATOR_HPP_ | 
| 10 |  | 
| 11 | #define FREE 1 | 
| 12 | #define FIXED 2 | 
| 13 | #define ITERATION_ISOLATION 4 | 
| 14 |  | 
| 15 | #include "Grid/grid_dist_key.hpp" | 
| 16 | #include "VCluster/VCluster.hpp" | 
| 17 | #include "util/GBoxes.hpp" | 
| 18 |  | 
| 19 | #ifdef __NVCC__ | 
| 20 | #include "SparseGridGpu/encap_num.hpp" | 
| 21 | #endif | 
| 22 |  | 
| 23 | template<unsigned int dim> | 
| 24 | struct launch_insert_sparse_lambda_call | 
| 25 | { | 
| 26 | 	template<typename ec_type, typename lambda_t,typename coord_type> | 
| 27 | 	__device__ inline static void call(ec_type & ec,lambda_t f, coord_type coord) | 
| 28 | 	{ | 
| 29 | 		printf("Not implemented in this direction \n" ); | 
| 30 | 	} | 
| 31 |  | 
| 32 | 	template<typename ite_type> | 
| 33 | 	__device__ inline static bool set_keys(grid_key_dx<3,int> & key, grid_key_dx<3,int> & keyg, ite_type & itg) | 
| 34 | 	{ | 
| 35 | 		return false; | 
| 36 | 	} | 
| 37 | }; | 
| 38 |  | 
| 39 | template<> | 
| 40 | struct launch_insert_sparse_lambda_call<3> | 
| 41 | { | 
| 42 | 	template<typename grid_type, typename lambda_t1, typename lambda_t2,typename itd_type, typename coord_type> | 
| 43 | 	__device__ inline static void call(grid_type & grid, | 
| 44 | 									   lambda_t1 f1, lambda_t2 f2, | 
| 45 | 									   unsigned int blockId, | 
| 46 | 									   itd_type itd, | 
| 47 | 									   coord_type & key, | 
| 48 | 									   coord_type & keyg,unsigned int offset, bool & is_block_empty, | 
| 49 | 									   bool is_in) | 
| 50 | 	{ | 
| 51 | #ifdef __NVCC__ | 
| 52 |  | 
| 53 | 	    bool is_active = false; | 
| 54 | 		if (is_in == true) | 
| 55 | 		{is_active = f1(keyg.get(0),keyg.get(1),keyg.get(2));} | 
| 56 |  | 
| 57 | 	    if (is_active == true) | 
| 58 | 	    {is_block_empty = false;} | 
| 59 |  | 
| 60 | 	    __syncthreads(); | 
| 61 |  | 
| 62 | 	    if (is_block_empty == false) | 
| 63 | 	    { | 
| 64 | 	    	auto ec = grid.insertBlock(blockId); | 
| 65 | 	    	enc_num<decltype(grid.insertBlock(blockId))> ecn(ec,offset); | 
| 66 |  | 
| 67 | 	        if ( is_active == true) | 
| 68 | 	        { | 
| 69 | 	        	f2(ecn,keyg.get(0),keyg.get(1),keyg.get(2)); | 
| 70 | 	        	ec.template get<grid_type::pMask>()[offset] = 1; | 
| 71 | 	        } | 
| 72 | 	    } | 
| 73 |  | 
| 74 | #endif | 
| 75 | 	} | 
| 76 |  | 
| 77 | 	template<typename ite_type> | 
| 78 | 	__device__ inline static bool set_keys(grid_key_dx<3,int> & key, grid_key_dx<3,int> & keyg, ite_type & itg) | 
| 79 | 	{ | 
| 80 | #ifdef __NVCC__ | 
| 81 |  | 
| 82 | 		key.set_d(0,threadIdx.x + blockIdx.x * blockDim.x + itg.start.get(0)); | 
| 83 | 		key.set_d(1,threadIdx.y + blockIdx.y * blockDim.y + itg.start.get(1)); | 
| 84 | 		key.set_d(2,threadIdx.z + blockIdx.z * blockDim.z + itg.start.get(2)); | 
| 85 |  | 
| 86 | 		keyg.set_d(0,key.get(0) + itg.origin.get(0)); | 
| 87 | 		keyg.set_d(1,key.get(1) + itg.origin.get(1)); | 
| 88 | 		keyg.set_d(2,key.get(2) + itg.origin.get(2)); | 
| 89 |  | 
| 90 | 		if (key.get(0) > itg.stop.get(0)       || key.get(1) > itg.stop.get(1)       || key.get(2) > itg.stop.get(2) || | 
| 91 | 		    key.get(0) < itg.start_base.get(0) || key.get(1) < itg.start_base.get(1) || key.get(2) < itg.start_base.get(2)) | 
| 92 | 		{return true;} | 
| 93 | #endif | 
| 94 | 		return false; | 
| 95 | 	} | 
| 96 | }; | 
| 97 |  | 
| 98 | template<> | 
| 99 | struct launch_insert_sparse_lambda_call<2> | 
| 100 | { | 
| 101 | 	template<typename grid_type, typename lambda_t1, typename lambda_t2,typename itd_type, typename coord_type> | 
| 102 | 	__device__ inline static void call(grid_type & grid, | 
| 103 | 									   lambda_t1 f1, lambda_t2 f2, | 
| 104 | 									   unsigned int blockId, | 
| 105 | 									   itd_type itd, | 
| 106 | 									   coord_type & key, | 
| 107 | 									   coord_type & keyg,unsigned int offset, bool & is_block_empty, | 
| 108 | 									   bool is_in) | 
| 109 | 	{ | 
| 110 | #ifdef __NVCC__ | 
| 111 |  | 
| 112 | 	    bool is_active = false; | 
| 113 | 		if (is_in == true) | 
| 114 | 		{is_active = f1(keyg.get(0),keyg.get(1));} | 
| 115 |  | 
| 116 | 	    if (is_active == true) | 
| 117 | 	    {is_block_empty = false;} | 
| 118 |  | 
| 119 | 	    __syncthreads(); | 
| 120 |  | 
| 121 | 	    if (is_block_empty == false) | 
| 122 | 	    { | 
| 123 | 	    	auto ec = grid.insertBlock(blockId); | 
| 124 | 	    	enc_num<decltype(grid.insertBlock(blockId))> ecn(ec,offset); | 
| 125 |  | 
| 126 | 	        if ( is_active == true) | 
| 127 | 	        { | 
| 128 | 	        	f2(ecn,keyg.get(0),keyg.get(1)); | 
| 129 | 	        	ec.template get<grid_type::pMask>()[offset] = 1; | 
| 130 | 	        } | 
| 131 | 	    } | 
| 132 |  | 
| 133 | #endif | 
| 134 | 	} | 
| 135 |  | 
| 136 | 	template<typename ite_type> | 
| 137 | 	__device__ inline static bool set_keys(grid_key_dx<2,int> & key, grid_key_dx<2,int> & keyg, ite_type & itg) | 
| 138 | 	{ | 
| 139 | #ifdef __NVCC__ | 
| 140 | 		key.set_d(0,threadIdx.x + blockIdx.x * blockDim.x + itg.start.get(0)); | 
| 141 | 		key.set_d(1,threadIdx.y + blockIdx.y * blockDim.y + itg.start.get(1)); | 
| 142 |  | 
| 143 | 		keyg.set_d(0,key.get(0) + itg.origin.get(0)); | 
| 144 | 		keyg.set_d(1,key.get(1) + itg.origin.get(1)); | 
| 145 |  | 
| 146 | 		if (key.get(0) > itg.stop.get(0)        || key.get(1) > itg.stop.get(1) || | 
| 147 | 		    key.get(0) < itg.start_base.get(0)  || key.get(1) < itg.start_base.get(1)) | 
| 148 | 		{return true;} | 
| 149 | #endif | 
| 150 | 		return false; | 
| 151 | 	} | 
| 152 | }; | 
| 153 |  | 
| 154 | struct launch_insert_sparse | 
| 155 | { | 
| 156 | 	template<typename grid_type, typename ite_type, typename lambda_f1, typename lambda_f2> | 
| 157 | 	__device__ void operator()(grid_type & grid, ite_type itg, bool & is_block_empty, lambda_f1 f1, lambda_f2 f2) | 
| 158 | 	{ | 
| 159 | #ifdef __NVCC__ | 
| 160 |  | 
| 161 | 		grid_key_dx<grid_type::dims,int> key; | 
| 162 | 		grid_key_dx<grid_type::dims,int> keyg; | 
| 163 |  | 
| 164 | 		bool not_active = launch_insert_sparse_lambda_call<grid_type::dims>::set_keys(key,keyg,itg); | 
| 165 |  | 
| 166 | 	    	if (threadIdx.x == 0 && threadIdx.y == 0 && threadIdx.z == 0) | 
| 167 | 	    	{is_block_empty = true;} | 
| 168 |  | 
| 169 | 	    grid.init(); | 
| 170 |  | 
| 171 | 	    int offset = 0; | 
| 172 | 	    	grid_key_dx<grid_type::dims,int> blk; | 
| 173 | 	    	bool out = grid.template getInsertBlockOffset<ite_type>(itg,key,blk,offset); | 
| 174 |  | 
| 175 | 	    	auto blockId = grid.getBlockLinId(blk); | 
| 176 |  | 
| 177 | 		launch_insert_sparse_lambda_call<grid_type::dims>::call(grid,f1,f2,blockId,itg,key,keyg,offset,is_block_empty,!not_active); | 
| 178 |  | 
| 179 | 	    __syncthreads(); | 
| 180 |  | 
| 181 | 	    grid.flush_block_insert(); | 
| 182 | #endif | 
| 183 | 	} | 
| 184 | }; | 
| 185 |  | 
| 186 | template<bool is_free> | 
| 187 | struct selvg | 
| 188 | { | 
| 189 | 	template<typename a_it_type, typename gdb_ext_type, typename gList_type> | 
| 190 | 	static inline void call(a_it_type & a_it, gdb_ext_type & gdb_ext, gList_type & gList, size_t & g_c) | 
| 191 | 	{ | 
| 192 | 		if (gdb_ext.get(g_c).Dbox.isValid() == false) | 
| 193 | 		{g_c++;} | 
| 194 | 		else | 
| 195 | 		{ | 
| 196 | 			a_it.reinitialize(gList.get(g_c).getIterator(gdb_ext.get(g_c).Dbox.getKP1(),gdb_ext.get(g_c).Dbox.getKP2())); | 
| 197 | 			if (a_it.isNext() == false)	{g_c++;} | 
| 198 | 		} | 
| 199 | 	} | 
| 200 | }; | 
| 201 |  | 
| 202 | template<> | 
| 203 | struct selvg<false> | 
| 204 | { | 
| 205 | 	template<typename a_it_type, typename gdb_ext_type, typename gList_type> | 
| 206 | 	static inline void call(a_it_type & a_it, gdb_ext_type & gdb_ext, gList_type & gList, size_t & g_c) | 
| 207 | 	{ | 
| 208 | 		// Full iterator (no subset) | 
| 209 | 		a_it.reinitialize(gList.get(g_c).getIterator()); | 
| 210 | 		if (a_it.isNext() == false)	{g_c++;} | 
| 211 | 	} | 
| 212 | }; | 
| 213 |  | 
| 214 | /*! \brief Distributed grid iterator | 
| 215 |  * | 
| 216 |  * Iterator across the local elements of the distributed grid | 
| 217 |  * | 
| 218 |  * \tparam dim dimensionality of the grid | 
| 219 |  * \tparam device_grid type of basic grid | 
| 220 |  * \tparam stencil it inject the code to calculate stencil offset | 
| 221 |  * \tparam sub_iterator it indicate the sub-iterator type of the device_grid | 
| 222 |  * | 
| 223 |  */ | 
| 224 | template<unsigned int dim, typename device_grid, typename device_sub_it, int impl, typename stencil  = no_stencil > | 
| 225 | class grid_dist_iterator | 
| 226 | { | 
| 227 | 	//! grid list counter | 
| 228 | 	size_t g_c; | 
| 229 |  | 
| 230 | 	//! List of the grids we are going to iterate | 
| 231 | 	const openfpm::vector<device_grid> & gList; | 
| 232 |  | 
| 233 | 	//! Extension of each grid: domain and ghost + domain | 
| 234 | 	const openfpm::vector<GBoxes<device_grid::dims>> & gdb_ext; | 
| 235 |  | 
| 236 | 	//! Actual iterator | 
| 237 | 	device_sub_it a_it; | 
| 238 |  | 
| 239 | 	//! stop point (is the grid size) | 
| 240 | 	grid_key_dx<dim> stop; | 
| 241 |  | 
| 242 | 	/*! \brief from g_c increment g_c until you find a valid grid | 
| 243 | 	 * | 
| 244 | 	 */ | 
| 245 | 	void selectValidGrid() | 
| 246 | 	{ | 
| 247 | 		do | 
| 248 | 		{ | 
| 249 | 			if (impl == FREE) | 
| 250 | 			{ | 
| 251 | 				// When the grid has size 0 potentially all the other informations are garbage | 
| 252 | 				while (g_c < gList.size() && (gList.get(g_c).size() == 0 || gdb_ext.get(g_c).Dbox.isValid() == false ) ) g_c++; | 
| 253 | 			} | 
| 254 | 			else | 
| 255 | 			{ | 
| 256 | 				// When the grid has size 0 potentially all the other informations are garbage | 
| 257 | 				while (g_c < gList.size() && (gList.get(g_c).size() == 0 || gdb_ext.get(g_c).GDbox.isValid() == false) ) g_c++; | 
| 258 | 			} | 
| 259 |  | 
| 260 | 			// get the next grid iterator | 
| 261 | 			if (g_c < gList.size()) | 
| 262 | 			{ | 
| 263 | 				selvg<impl == FREE>::call(a_it,gdb_ext,gList,g_c); | 
| 264 | 			} | 
| 265 | 		} while (g_c < gList.size() && a_it.isNext() == false); | 
| 266 |  | 
| 267 | 	} | 
| 268 |  | 
| 269 | 	public: | 
| 270 |  | 
| 271 | 	/*! \brief Constructor of the distributed grid iterator | 
| 272 | 	 * | 
| 273 | 	 * \param gk std::vector of the local grid | 
| 274 | 	 * \param gdb_ext set of local subdomains | 
| 275 | 	 * \param stop end point | 
| 276 | 	 * | 
| 277 | 	 */ | 
| 278 | 	grid_dist_iterator(const openfpm::vector<device_grid> & gk, | 
| 279 | 					   const openfpm::vector<GBoxes<device_grid::dims>> & gdb_ext, | 
| 280 | 					   const grid_key_dx<dim> & stop) | 
| 281 | 	:g_c(0),gList(gk),gdb_ext(gdb_ext),stop(stop) | 
| 282 | 	{ | 
| 283 | 		// Initialize the current iterator | 
| 284 | 		// with the first grid | 
| 285 | 		selectValidGrid(); | 
| 286 | 	} | 
| 287 |  | 
| 288 |  | 
| 289 | 	/*! \brief Constructor of the distributed grid iterator with | 
| 290 | 	 *         stencil support | 
| 291 | 	 * | 
| 292 | 	 * \param gk std::vector of the local grid | 
| 293 | 	 * \param gdb_ext set of local subdomains | 
| 294 | 	 * \param stop end point | 
| 295 | 	 * \param stencil_pnt stencil points | 
| 296 | 	 * | 
| 297 | 	 */ | 
| 298 | 	grid_dist_iterator(openfpm::vector<device_grid> & gk, | 
| 299 | 			           const openfpm::vector<GBoxes<device_grid::dims>> & gdb_ext, | 
| 300 | 					   const grid_key_dx<dim> & stop, | 
| 301 | 					   const grid_key_dx<dim> (& stencil_pnt)[stencil::nsp]) | 
| 302 | 	:g_c(0),gList(gk),gdb_ext(gdb_ext),a_it(stencil_pnt),stop(stop) | 
| 303 | 	{ | 
| 304 | 		// Initialize the current iterator | 
| 305 | 		// with the first grid | 
| 306 | 		selectValidGrid(); | 
| 307 | 	} | 
| 308 |  | 
| 309 | 	//! Copy constructor | 
| 310 | 	grid_dist_iterator(const grid_dist_iterator<dim,device_grid,device_sub_it,impl,stencil> & g) | 
| 311 | 	:g_c(g.g_c),gList(g.gList),gdb_ext(g.gdb_ext),a_it(g.a_it),stop(g.stop) | 
| 312 | 	{} | 
| 313 |  | 
| 314 | 	//! Copy constructor | 
| 315 | 	grid_dist_iterator(grid_dist_iterator<dim,device_grid,device_sub_it,impl,stencil> && g) | 
| 316 | 	:g_c(g.g_c),gList(g.gList),gdb_ext(g.gdb_ext),a_it(g.a_it),stop(g.stop) | 
| 317 | 	{} | 
| 318 |  | 
| 319 | 	//! Destructor | 
| 320 | 	~grid_dist_iterator() | 
| 321 | 	{ | 
| 322 | 	} | 
| 323 |  | 
| 324 | 	/*! \brief Get the next element | 
| 325 | 	 * | 
| 326 | 	 * \return the next grid_key | 
| 327 | 	 * | 
| 328 | 	 */ | 
| 329 | 	inline grid_dist_iterator<dim,device_grid,device_sub_it,impl,stencil> & operator++() | 
| 330 | 	{ | 
| 331 | 		++a_it; | 
| 332 |  | 
| 333 | 		// check if a_it is at the end | 
| 334 |  | 
| 335 | 		if (a_it.isNext() == true) | 
| 336 | 			return *this; | 
| 337 | 		else | 
| 338 | 		{ | 
| 339 | 			// switch to the new grid | 
| 340 | 			g_c++; | 
| 341 |  | 
| 342 | 			selectValidGrid(); | 
| 343 | 		} | 
| 344 |  | 
| 345 | 		return *this; | 
| 346 | 	} | 
| 347 |  | 
| 348 | 	/*! \brief Check if there is the next element | 
| 349 | 	 * | 
| 350 | 	 * \return true if there is the next, false otherwise | 
| 351 | 	 * | 
| 352 | 	 */ | 
| 353 | 	inline bool isNext() const | 
| 354 | 	{ | 
| 355 | 		// If there are no other grid stop | 
| 356 |  | 
| 357 | 		if (g_c >= gList.size()) | 
| 358 | 		{return false;} | 
| 359 |  | 
| 360 | 		return true; | 
| 361 | 	} | 
| 362 |  | 
| 363 | 	/*! \brief Get the actual key | 
| 364 | 	 * | 
| 365 | 	 * \return the actual key | 
| 366 | 	 * | 
| 367 | 	 */ | 
| 368 | 	inline grid_dist_key_dx<dim, typename device_grid::base_key> get() const | 
| 369 | 	{ | 
| 370 | 		return grid_dist_key_dx<dim,typename device_grid::base_key>(g_c,a_it.get()); | 
| 371 | 	} | 
| 372 |  | 
| 373 | 	/*! \brief it return the stop point of the iterator | 
| 374 | 	 * | 
| 375 | 	 * The stop point of the iterator is just the grid size | 
| 376 | 	 * | 
| 377 | 	 * \return the stop point | 
| 378 | 	 * | 
| 379 | 	 */ | 
| 380 | 	inline grid_key_dx<dim> getStop() const | 
| 381 | 	{ | 
| 382 | 		return stop; | 
| 383 | 	} | 
| 384 |  | 
| 385 | 	/*! \brief it return the start point of the iterator | 
| 386 | 	 * | 
| 387 | 	 * The start point of the iterator is the point with all coordinates zeros | 
| 388 | 	 * | 
| 389 | 	 * \return the start point | 
| 390 | 	 * | 
| 391 | 	 */ | 
| 392 | 	inline grid_key_dx<dim> getStart() const | 
| 393 | 	{ | 
| 394 | 		grid_key_dx<dim> start; | 
| 395 |  | 
| 396 | 		start.zero(); | 
| 397 |  | 
| 398 | 		return start; | 
| 399 | 	} | 
| 400 |  | 
| 401 | 	/*! \brief Get the boxes | 
| 402 | 	 * | 
| 403 | 	 *  Get the boxes that define the local grids | 
| 404 | 	 * | 
| 405 | 	 * \return Vector of local boxes | 
| 406 | 	 * | 
| 407 | 	 */ | 
| 408 | 	inline const openfpm::vector<GBoxes<device_grid::dims>> & getGBoxes() | 
| 409 | 	{ | 
| 410 | 		return gdb_ext; | 
| 411 | 	} | 
| 412 |  | 
| 413 | 	/*! \brief Convert a g_dist_key_dx into a global key | 
| 414 | 	 * | 
| 415 | 	 * \see grid_dist_key_dx | 
| 416 | 	 * \see grid_dist_iterator | 
| 417 | 	 * | 
| 418 | 	 * \param k key position in local coordinates | 
| 419 | 	 * | 
| 420 | 	 * \return the global position in the grid | 
| 421 | 	 * | 
| 422 | 	 */ | 
| 423 | 	inline grid_key_dx<dim> getGKey(const grid_dist_key_dx<dim,typename device_grid::base_key> & k) | 
| 424 | 	{ | 
| 425 | 		// Get the sub-domain id | 
| 426 | 		size_t sub_id = k.getSub(); | 
| 427 |  | 
| 428 | 		auto k_glob = k.getKey(); | 
| 429 |  | 
| 430 | 		// shift | 
| 431 | 		auto k_glob2 = k_glob + gdb_ext.get(sub_id).origin; | 
| 432 |  | 
| 433 | 		return k_glob2; | 
| 434 | 	} | 
| 435 |  | 
| 436 | 	/*! \brief Return the stencil point offset | 
| 437 | 	 * | 
| 438 | 	 * \tparam id | 
| 439 | 	 * | 
| 440 | 	 * \return linearized distributed key | 
| 441 | 	 * | 
| 442 | 	 */ | 
| 443 | 	template<unsigned int id> inline grid_dist_lin_dx getStencil() | 
| 444 | 	{ | 
| 445 | 		return grid_dist_lin_dx(g_c,a_it.template getStencil<id>()); | 
| 446 | 	} | 
| 447 | }; | 
| 448 |  | 
| 449 |  | 
| 450 |  | 
| 451 | #endif /* GRID_DIST_ID_ITERATOR_SUB_HPP_ */ | 
| 452 |  |