SpatialOps
SpatialFieldStore.h
1 /*
2  * Copyright (c) 2014-2017 The University of Utah
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22 
23 #ifndef UT_SpatialFieldStore_h
24 #define UT_SpatialFieldStore_h
25 
26 #include <spatialops/SpatialOpsConfigure.h>
30 
31 #include <stack>
32 #include <map>
33 
34 #include <boost/type_traits.hpp>
35 
36 #ifdef ENABLE_THREADS
37 # include <boost/smart_ptr/detail/spinlock.hpp>
38 # include <boost/thread/mutex.hpp>
39 #endif
40 
41 namespace SpatialOps {
42 
43 
74 template<typename FieldT>
75 class SpatFldPtr {
76 public:
77 
85  SpatFldPtr(FieldT* const field);
86 
97  SpatFldPtr(FieldT* const field, const bool builtFromStore);
98 
109  SpatFldPtr(FieldT* const field, const bool builtFromStore, const short int deviceIndex);
110 
111  ~SpatFldPtr();
112 
114  SpatFldPtr(const SpatFldPtr<FieldT>& p);
115 
117  SpatFldPtr();
118 
120  SpatFldPtr& operator=(const SpatFldPtr& p);
121 
123  SpatFldPtr& operator=(FieldT* const f);
124 
125  inline FieldT& operator*() {
126  return *f_;
127  }
128 
129  inline const FieldT& operator*() const {
130  return *f_;
131  }
132 
133  inline FieldT* operator->() {
134  return f_;
135  }
136 
137  inline const FieldT* operator->() const {
138  return f_;
139  }
140 
141  inline bool isnull() const {
142  return f_ == NULL;
143  }
144 
145  int count() const {
146  return *count_;
147  }
148 
149  bool built_from_store() const {
150  return builtFromStore_;
151  }
152 
157  void detach();
158 
159 private:
160  FieldT* f_;
161  int* count_;
162  bool builtFromStore_;
163  short int deviceIndex_;
164 
165 # ifdef ENABLE_THREADS
166 
169  inline static boost::detail::spinlock& get_spin_lock() {static boost::detail::spinlock s; return s;}
170 # endif
171 };
172 
207 
208 public:
209 
222  template<typename FieldT>
223  inline static SpatFldPtr<FieldT>
224  get_from_window( const MemoryWindow& w,
225  const BoundaryCellInfo& bc,
226  const GhostData& ghost,
227  const short int deviceIndex = CPU_INDEX );
228 
240  template< typename FieldT, typename ProtoT >
241  inline static SpatFldPtr<FieldT>
242  get( const ProtoT& f, short int deviceIndex = -9999 )
243  {
244  if( deviceIndex == -9999 ) deviceIndex = f.active_device_index();
245 
246  if( is_same_type<FieldT,SpatialField<SingleValue> >() ){
247  return get_from_window<FieldT>( MemoryWindow( IntVec(1,1,1) ),
248  BoundaryCellInfo::build<SpatialField<SingleValue> >(),
249  GhostData(0),
250  deviceIndex );
251  }
252 
253  return get_from_window<FieldT>( create_new_memory_window<FieldT,ProtoT>(f),
254  create_new_boundary_cell_info<FieldT,ProtoT>(f),
255  f.get_ghost_data(),
256  deviceIndex );
257  }
258 
268  template<typename FieldT>
269  inline static void restore_field(const short int deviceIndex, FieldT& f);
270 
271 private:
272 
273 #ifdef ENABLE_THREADS
274 
277  inline static boost::mutex& get_mutex() {static boost::mutex m; return m;}
278 #endif
279 
280 };
281 
282 //==================================================================
283 
284 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285 //
286 // Implementation
287 //
288 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289 
290 //=================================================================
291 
292 template<typename FieldT>
294  : f_(f),
295  count_(new int),
296  builtFromStore_(false),
297  deviceIndex_( ( f != NULL ? f->active_device_index() : CPU_INDEX ) )
298 {
299  *count_ = 1;
300 }
301 
302 //------------------------------------------------------------------
303 
304 template<typename FieldT>
305 SpatFldPtr<FieldT>::SpatFldPtr( FieldT* const f, const bool builtFromStore )
306  : f_(f),
307  count_(new int),
308  builtFromStore_(builtFromStore),
309  deviceIndex_( ( f != NULL ? f->active_device_index() : CPU_INDEX ) )
310 {
311  *count_ = 1;
312 }
313 
314 //------------------------------------------------------------------
315 
316 template<typename FieldT>
318  : f_(p.f_),
319  count_(p.count_),
320  builtFromStore_( p.builtFromStore_ ),
321  deviceIndex_( p.deviceIndex_)
322 {
323  // Only increment count on valid pointers. If we are copying an empty pointer, count_ may be null.
324 # ifdef ENABLE_THREADS
325  boost::lock_guard<boost::detail::spinlock> lock( get_spin_lock() );
326 # endif
327  if( count_ ) ++(*count_);
328 }
329 
330 //------------------------------------------------------------------
331 
332 template<typename FieldT>
334  : f_( NULL ),
335  count_( NULL ),
336  builtFromStore_( false ),
337  deviceIndex_( CPU_INDEX )
338 {}
339 
340 //------------------------------------------------------------------
341 
342 template<typename FieldT>
345 {
346  detach();
347 
348 # ifdef ENABLE_THREADS
349  boost::lock_guard<boost::detail::spinlock> lock( get_spin_lock() );
350 # endif
351 
352  f_ = p.f_;
353  count_ = p.count_;
354  builtFromStore_ = p.builtFromStore_;
355  deviceIndex_ = p.deviceIndex_;
356 
357  // Only increment count on valid pointers. If we are copying an empty pointer, count_ may be null.
358  if( count_ ) ++(*count_);
359 
360  return *this;
361 }
362 
363 //------------------------------------------------------------------
364 
365 template<typename FieldT>
368 {
369  detach();
370 
371 # ifdef ENABLE_THREADS
372  boost::lock_guard<boost::detail::spinlock> lock( get_spin_lock() );
373 # endif
374 
375  f_ = f;
376  count_ = new int;
377  *count_ = 1;
378  builtFromStore_ = false;
379  if( deviceIndex_ != f->active_device_index() ){
380  std::ostringstream msg;
381  msg << "SpatFldPtr deviceIndex "
382  << DeviceTypeTools::get_memory_type_description(deviceIndex_)
383  << " is different to that of assigning Spatial Field deviceIndex, \n"
384  << DeviceTypeTools::get_memory_type_description(f->active_device_index())
385  << "\t - " << __FILE__ << " : " << __LINE__ << std::endl;
386  throw(std::runtime_error(msg.str()));
387  }
388 
389  return *this;
390 }
391 
392 //------------------------------------------------------------------
393 
394 template<typename FieldT>
396 {
397 # ifdef ENABLE_THREADS
398  boost::lock_guard<boost::detail::spinlock> lock( get_spin_lock() );
399 # endif
400  // was this an active SpatFldPtr?
401  if( count_ != NULL ){
402  // this one is dying so decrement the count.
403  --(*count_);
404  if( *count_ == 0 ){
405  // kill the old one if needed
406  if( builtFromStore_ ){
407  SpatialFieldStore::restore_field(deviceIndex_, *f_);
408  }
409  delete count_;
410  delete f_;
411  }
412  }
413  count_ = NULL;
414  f_ = NULL;
415 }
416 
417 //------------------------------------------------------------------
418 
419 template<typename FieldT>
421  detach();
422 }
423 
424 //------------------------------------------------------------------
425 
426 //====================================================================
427 
428 //------------------------------------------------------------------
429 
430 template<typename FieldT>
431 inline
433 SpatialFieldStore::
434 get_from_window( const MemoryWindow& window,
435  const BoundaryCellInfo& bc,
436  const GhostData& ghost,
437  const short int deviceIndex )
438 {
439  typedef typename FieldT::value_type ValT;
440  const MemoryWindow mw( window.extent(),
441  IntVec(0,0,0),
442  window.extent() );
443  const size_t npts = mw.glob_npts();
444 
445 # ifndef NDEBUG
446  assert( window.sanity_check() );
447  assert( mw.sanity_check() );
448 # endif
449 
450  // Allocate from a store
451  if( deviceIndex == CPU_INDEX ) {
452  ValT* fnew = Pool<ValT>::get(deviceIndex,npts);
453  return SpatFldPtr<FieldT>( new FieldT( mw,bc,ghost,fnew,
454  ExternalStorage),
455  true );
456  }
457 # ifdef ENABLE_CUDA
458  else if( IS_GPU_INDEX(deviceIndex) ){
459  ValT* fnew = Pool<ValT>::get(deviceIndex, npts);
460  return SpatFldPtr<FieldT>( new FieldT( mw, bc, ghost, fnew,
461  ExternalStorage,
462  deviceIndex ),
463  true );
464  }
465 # endif
466  else {
467  std::ostringstream msg;
468  msg << "Attempt to create Spatial Field Pointer wrapping ( "
469  << DeviceTypeTools::get_memory_type_description(deviceIndex)
470  << " ) field type, without supporting libraries included\n";
471  msg << "\t " << __FILE__ << " : " << __LINE__;
472  throw(std::runtime_error(msg.str()));
473  }
474 }
475 
476 //------------------------------------------------------------------
477 
478 template<typename FieldT>
479 inline
480 void SpatialFieldStore::restore_field( const short int deviceIndex, FieldT& field )
481 {
482  typedef typename FieldT::value_type ValT;
483  ValT * values = const_cast<ValT *>((const_cast<FieldT const &>(field)).field_values(deviceIndex));
484 # ifndef NDEBUG
485  if( !IS_VALID_INDEX(deviceIndex) ){
486  std::ostringstream msg;
487  msg << "Invalid device Index passed to SpatialFieldStore::restore_field() : "
488  << deviceIndex <<std::endl
489  << " \t - " << __FILE__ << " : " << __LINE__ << std::endl;
490  throw( std::runtime_error(msg.str()));
491  }
492 # endif
493  Pool<ValT>::put( deviceIndex, values );
494 }
495 
496 } // namespace SpatialOps
497 
498 #endif
Provides tools to index into a sub-block of memory.
Definition: MemoryWindow.h:63
bool sanity_check() const
performs basic sanity checks to see if there is anything obviously wrong with this window...
bool is_same_type()
convenience function to obtain at runtime whether two types are equivalent or not ...
Provides a common interface to obtain temporary (work) fields.
size_t glob_npts() const
obtain the global number of points in the field. Note that this is not necessarily contiguous memory ...
Definition: MemoryWindow.h:155
Holds information about the number of ghost cells on each side of the domain.
Definition: GhostData.h:54
SpatFldPtr & operator=(const SpatFldPtr &p)
Assignment operator.
Abstracts a field.
Definition: SpatialField.h:132
SpatFldPtr()
Skeletal constructor.
Provides information about boundary cells for various fields.
Wrapper for pointers to SpatialField objects. Provides reference counting.