SpatialOps
SpatialField.h
Go to the documentation of this file.
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  * Available debugging flags:
23  *
24  * DEBUG_SF_ALL -- Enable all Spatial Field debugging flags.
25  *
26  */
27 //#define DEBUG_SF_ALL
28 
29 #ifndef SpatialOps_SpatialField_h
30 #define SpatialOps_SpatialField_h
31 
32 #include <stdexcept>
33 #include <sstream>
34 
35 // Boost includes //
36 #include <boost/shared_ptr.hpp>
37 #include <boost/enable_shared_from_this.hpp>
38 
39 #include <spatialops/SpatialOpsConfigure.h>
41 #include <spatialops/structured/FieldInfo.h>
42 
47 namespace SpatialOps{
48 
63  template<typename Location>
65  static inline void check( MemoryWindow const & window,
66  GhostData const & ghosts ) {}
67  };
68 
69  template<>
71  static inline void check( MemoryWindow const & window,
72  GhostData const & ghosts )
73  {
74 # ifndef NDEBUG
75  if( (window.extent(0) > 1) &&
76  (window.extent(1) > 1) &&
77  (window.extent(2) > 1) )
78  {
79  std::ostringstream msg;
80  msg << "Single Value Field does not support window extents larger than 1\n"
81  << "\t - " << __FILE__ << " : " << __LINE__ << std::endl;
82  throw(std::runtime_error(msg.str()));
83  }
84 
85  if( (ghosts.get_minus(0) > 0) &&
86  (ghosts.get_minus(1) > 0) &&
87  (ghosts.get_minus(2) > 0) &&
88  (ghosts.get_plus (0) > 0) &&
89  (ghosts.get_plus (1) > 0) &&
90  (ghosts.get_plus (2) > 0) )
91  {
92  std::ostringstream msg;
93  msg << "Single Value Field does not support non-zero ghosts\n"
94  << "\t - " << __FILE__ << " : " << __LINE__ << std::endl;
95  throw(std::runtime_error(msg.str()));
96  }
97 # endif
98  }
99  };
100 
101 //------------------------------------------------------------------
102 
131  template< typename FieldLocation, typename T=double >
132  class SpatialField {
133  private:
134  bool matchGlobalWindow_;
135  MemoryWindow localWindow_;
136  BoundaryCellInfo bcInfo_;
137  GhostData localValidGhosts_;
138  boost::shared_ptr<FieldInfo<T> > info_;
139 
140  public:
142  typedef FieldLocation Location;
143  typedef T value_type;
147 
158  inline SpatialField( const MemoryWindow window,
159  const BoundaryCellInfo bc,
160  const GhostData ghosts,
161  T* const fieldValues = NULL,
162  const StorageMode mode = InternalStorage,
163  const short int devIdx = CPU_INDEX )
164  : matchGlobalWindow_( true ),
165  localWindow_( window ),
166  bcInfo_( bc.limit_by_extent(window.extent()) ),
167  localValidGhosts_( ghosts.limit_by_extent(window.extent()) ),
168  info_( new FieldInfo<T>( window, bc, ghosts, fieldValues, mode, devIdx ) )
169  {
170  SingleValueCheck<Location>::check( localWindow_, ghosts );
171 # ifndef NDEBUG
172  // ensure that we have a consistent BoundaryCellInfo object
173  for( int i=0; i<3; ++i ){
174  if( localWindow_.extent(i)>1 && bcInfo_.has_bc(i,PLUS_SIDE) ){
175  assert( bcInfo_.num_extra(i) == Location::BCExtra::int_vec()[i] );
176  }
177  }
178 # endif // NDEBUG
179  }
180 
189  inline SpatialField( const SpatialField& other )
190  : matchGlobalWindow_( other.matchGlobalWindow_ ),
191  localWindow_( other.localWindow_ ),
192  bcInfo_( other.bcInfo_ ),
193  localValidGhosts_( other.localValidGhosts_ ),
194  info_( other.info_ )
195  {}
196 
213  inline SpatialField( const MemoryWindow window,
214  const SpatialField& other )
215  : matchGlobalWindow_( window.fits_between(other.info_->window_without_ghost(),
216  other.info_->window_with_all_ghost()) ),
217  localWindow_( window ),
218  bcInfo_( other.info_->boundary_info() ),
219  localValidGhosts_( other.localValidGhosts_.limit_by_extent(window.extent()) ),
220  info_( other.info_ )
221  {
222  SingleValueCheck<Location>::check(window, localValidGhosts_);
223  }
224 
230  void swap( SpatialField& other ){
231  SpatialField tmp(other);
232  other.matchGlobalWindow_ = matchGlobalWindow_;
233  other.localWindow_ = localWindow_;
234  other.bcInfo_ = bcInfo_;
235  other.localValidGhosts_ = localValidGhosts_;
236  other.info_ = info_;
237  matchGlobalWindow_ = tmp.matchGlobalWindow_;
238  localWindow_ = tmp.localWindow_;
239  bcInfo_ = tmp.bcInfo_;
240  localValidGhosts_ = tmp.localValidGhosts_;
241  info_ = tmp.info_;
242  }
243 
244  ~SpatialField() {};
245 
246  const MemoryWindow& window_with_ghost() const{ return localWindow_; }
247 
248  const MemoryWindow window_without_ghost() const {
249  if( matchGlobalWindow_ ) return info_->window_without_ghost();
250  else return localWindow_.remove_ghosts(localValidGhosts_);
251  }
252 
256  const BoundaryCellInfo& boundary_info() const { return bcInfo_; }
257 
261  const GhostData& get_ghost_data() const { return info_->get_ghost_data(); }
262 
267  if( matchGlobalWindow_ )
268  return info_->get_valid_ghost_data();
269  else
270  return localValidGhosts_;
271  }
272 
278  inline void reset_valid_ghosts( const GhostData& input ){
279  const GhostData ghosts = input.limit_by_extent( localWindow_.extent() );
280  localWindow_ = localWindow_.reset_ghosts( localValidGhosts_, ghosts );
281  localValidGhosts_ = ghosts;
282  if( matchGlobalWindow_ ) info_->reset_valid_ghosts(ghosts);
283  }
284 
288  unsigned int allocated_bytes() const{ return info_->allocated_bytes(); }
289 
290 # ifdef ENABLE_THREADS
291 
296  void set_partition_count( const int count) { info_->set_partition_count(count); }
297 
301  int get_partition_count() const { return info_->get_partition_count(); }
302 # endif
303 
304 # ifdef ENABLE_CUDA
305 
310  void set_stream( const cudaStream_t& stream ) { info_->set_stream(stream); }
311 
315  cudaStream_t const & get_stream() const { return info_->get_stream(); }
316 
320  cudaEvent_t const & get_last_event() const { return info_->get_last_event(); }
321 # endif
322 
326  inline void wait_for_synchronization() { info_->wait_for_synchronization(); }
327 
331  short int active_device_index() const { return info_->active_device_index(); }
332 
354  inline void add_device( short int deviceIndex ) { info_->add_device( deviceIndex ); }
355 
377  inline void add_device_async( short int deviceIndex ) { info_->add_device_async( deviceIndex ); }
378 
390  inline void validate_device( short int deviceIndex ){
391  info_->validate_device( deviceIndex );
392  }
393 
405  inline void validate_device_async( short int deviceIndex ){
406  info_->validate_device_async( deviceIndex );
407  }
408 
419  inline void set_device_as_active( const short int deviceIndex ){
420  info_->set_device_as_active( deviceIndex );
421  }
422 
433  inline void set_device_as_active_async( const short int deviceIndex ){
434  info_->set_device_as_active_async( deviceIndex );
435  }
436 
442  bool is_valid( const short int deviceIndex ) const{
443  return info_->is_valid( deviceIndex );
444  }
445 
451  bool is_available( const short int deviceIndex ) const{
452  return info_->is_available( deviceIndex );
453  }
454 
462  inline T* field_values( const short int deviceIndex = CPU_INDEX ){
463  return info_->field_values( deviceIndex );
464  }
465 
471  inline const T* field_values( const short int deviceIndex = CPU_INDEX ) const{
472  return info_->const_field_values( deviceIndex );
473  }
474 
478  inline const_iterator begin() const{
479  return const_iterator( info_->const_field_values( CPU_INDEX ), window_with_ghost() );
480  }
481 
485  inline iterator begin(){
486  return iterator( info_->field_values( CPU_INDEX ), window_with_ghost() );
487  }
488 
492  inline const_iterator end() const{
493  const MemoryWindow & w = window_with_ghost();
494  return begin() + w.extent(0) * w.extent(1) * w.extent(2);
495  }
496 
500  inline iterator end(){
501  const MemoryWindow & w = window_with_ghost();
502  return begin() + w.extent(0) * w.extent(1) * w.extent(2);
503  }
504 
508  inline const_iterator interior_begin() const{
509  return const_iterator( info_->const_field_values( CPU_INDEX ), window_without_ghost() );
510  }
511 
515  inline iterator interior_begin(){
516  return iterator( info_->field_values( CPU_INDEX ), window_without_ghost() );
517  }
518 
522  inline const_iterator interior_end() const{
523  const MemoryWindow & w = window_without_ghost();
524  return interior_begin() + w.extent(0) * w.extent(1) * w.extent(2);
525  }
526 
530  inline iterator interior_end(){
531  const MemoryWindow & w = window_without_ghost();
532  return interior_begin() + w.extent(0) * w.extent(1) * w.extent(2);
533  }
534 
546  const T& operator[](const size_t i) const {
547  return info_->const_field_values(CPU_INDEX)[i];
548  }
549 
561  inline T& operator[](const size_t i) {
562  return info_->field_values(CPU_INDEX)[i];
563  }
564 
576  T& operator()(const IntVec& ijk) {
577  return (*this)[window_with_ghost().flat_index(ijk)];
578  }
579 
591  const T& operator()(const IntVec& ijk) const {
592  return (*this)[window_with_ghost().flat_index(ijk)];
593  }
594 
608  T& operator()(const size_t i, const size_t j, const size_t k) {
609  return (*this)(IntVec(i,j,k));
610  }
611 
625  const T& operator()(const size_t i, const size_t j, const size_t k) const {
626  return (*this)(IntVec(i,j,k));
627  }
628 
629  inline field_type& operator =(const field_type&);
630  }; // SpatialField
631 
632 //==================================================================
633 //
634 // Implementation
635 //
636 //==================================================================
637 
652  template<typename Location, typename T>
655  //check windows to be equal
656  if( info_->window_with_ghost() != other.info_->window_with_ghost() ) {
657  std::ostringstream msg;
658  msg << "Error : Attempted assignment between fields of unequal size!\n"
659  << "\t - " << __FILE__ << " : " << __LINE__ << std::endl;
660  throw(std::runtime_error(msg.str()));
661  }
662 
663  short int thisIdx = active_device_index();
664  short int otherIdx = other.active_device_index();
665 
666 # ifdef ENABLE_CUDA
667  ema::cuda::CUDADeviceInterface& CDI = ema::cuda::CUDADeviceInterface::self();
668 # endif
669 
670  if( IS_CPU_INDEX(thisIdx) ) {
671  if( IS_CPU_INDEX(otherIdx) ){
672  // CPU -> CPU
673  // check for self assignment
674  if( field_values(CPU_INDEX) != other.field_values(CPU_INDEX) )
675  std::copy( other.field_values(CPU_INDEX),
676  other.field_values(CPU_INDEX) + other.info_->window_with_ghost().glob_npts(),
677  field_values(CPU_INDEX) );
678  }
679 # ifdef ENABLE_CUDA
680  else if( IS_GPU_INDEX(otherIdx) ) {
681  // GPU -> CPU
682  CDI.memcpy_from( field_values(CPU_INDEX),
683  other.field_values(otherIdx),
684  info_->allocated_bytes(),
685  otherIdx,
686  get_stream() );
687  }
688 # endif
689  else {
690  // ??? -> CPU
691  std::ostringstream msg;
692  msg << "Attempted unsupported copy operation, at n\t"
693  << __FILE__ << " : " << __LINE__ << std::endl
694  << "\t - "
695  << DeviceTypeTools::get_memory_type_description(thisIdx) << " = "
696  << DeviceTypeTools::get_memory_type_description(otherIdx) << std::endl;
697  throw(std::runtime_error(msg.str()));
698  }
699  }
700 # ifdef ENABLE_CUDA
701  else if( IS_GPU_INDEX(thisIdx) ) {
702  if( IS_CPU_INDEX(otherIdx) ) {
703  // CPU -> GPU
704  CDI.memcpy_to( field_values(thisIdx),
705  other.field_values(CPU_INDEX),
706  info_->allocated_bytes(),
707  thisIdx,
708  get_stream() );
709  }
710  else if( IS_GPU_INDEX( otherIdx ) ){
711  // GPU -> GPU
712  // Check for self assignment
713  if( thisIdx != otherIdx ||
714  field_values(otherIdx) != other.field_values(otherIdx) ) {
715  CDI.memcpy_peer( field_values(thisIdx),
716  thisIdx,
717  other.field_values(otherIdx),
718  otherIdx,
719  info_->allocated_bytes() );
720  }
721  }
722  else {
723  // GPU -> ???
724  std::ostringstream msg;
725  msg << "Attempted unsupported copy operation, at " << std::endl
726  << "\t" << __FILE__ << " : " << __LINE__ << std::endl
727  << "\t - " << DeviceTypeTools::get_memory_type_description(thisIdx) << " = "
728  << DeviceTypeTools::get_memory_type_description(otherIdx) << std::endl;
729  throw( std::runtime_error ( msg.str() ));
730  }
731  }
732 # endif // ENABLE_CUDA
733  else{
734  // ??? -> ___
735  std::ostringstream msg;
736  msg << "Attempted unsupported copy operation, at \n\t"
737  << __FILE__ << " : " << __LINE__ << std::endl
738  << "\t - " << DeviceTypeTools::get_memory_type_description(thisIdx)
739  << " = "
740  << DeviceTypeTools::get_memory_type_description(otherIdx) << std::endl;
741  throw(std::runtime_error(msg.str()));
742  }
743 
744  return *this;
745  }
746 
747 //------------------------------------------------------------------
748 
758  template<typename FieldType, typename PrototypeType>
759  inline BoundaryCellInfo create_new_boundary_cell_info( const PrototypeType& prototype ){
760  return BoundaryCellInfo::build<FieldType>( prototype.boundary_info().has_bc(MINUS_SIDE),
761  prototype.boundary_info().has_bc( PLUS_SIDE) );
762  }
763 
764 //------------------------------------------------------------------
765 
775  template<typename FieldType, typename PrototypeType>
776  inline MemoryWindow create_new_memory_window( const PrototypeType& prototype )
777  {
778  const BoundaryCellInfo newBC = create_new_boundary_cell_info<FieldType,PrototypeType>(prototype);
779  const MemoryWindow& prototypeWindow = prototype.window_with_ghost();
781  return MemoryWindow( prototypeWindow.glob_dim() + inc,
782  prototypeWindow.offset(),
783  prototypeWindow.extent() + inc );
784  }
785 
786 } // namespace SpatialOps
787 
788 #endif // SpatialOps_SpatialField_h
SpatialField(const MemoryWindow window, const SpatialField &other)
SpatialField shallow copy constructor with new window.
Definition: SpatialField.h:213
const T & operator[](const size_t i) const
return constant reference to cell at given flat index on CPU
Definition: SpatialField.h:546
MemoryWindow remove_ghosts(GhostData const &ghosts) const
return the current memory window with given ghosts removed
Definition: MemoryWindow.h:214
Provides tools to index into a sub-block of memory.
Definition: MemoryWindow.h:63
int num_extra(const int dir) const
obtain the number of extra cells potentially present on this field due to presence of physical bounda...
void validate_device(short int deviceIndex)
populate memory on the given device (deviceIndex) with values from the active device SYNCHRONOUS VERS...
Definition: SpatialField.h:390
T & operator[](const size_t i)
return non-constant reference to cell at given flat index on CPU
Definition: SpatialField.h:561
Perform compile-time subtraction over a list of IndexTriplet types.
Definition: IndexTriplet.h:314
Type traits for a single value field.
bool has_bc(const int dir, const BCSide side) const
query to see if a physical boundary is present in the given direction (0=x, 1=y, 2=z) and the specifi...
FieldLocation Location
this field&#39;s location
Definition: SpatialField.h:142
MemoryWindow memory_window
the window type for this field
Definition: SpatialField.h:144
ConstFieldIterator< field_type > const_iterator
const iterator type
Definition: SpatialField.h:146
SpatialField< FieldLocation, T > field_type
this field&#39;s type
Definition: SpatialField.h:141
iterator begin()
return a non-constant iterator for CPU with valid ghost cells
Definition: SpatialField.h:485
void add_device_async(short int deviceIndex)
add device memory to this field for given device and populate it with values from current active devi...
Definition: SpatialField.h:377
const T & operator()(const size_t i, const size_t j, const size_t k) const
return constant reference to cell at given index (i,j,k) on CPU
Definition: SpatialField.h:625
void set_device_as_active(const short int deviceIndex)
set given device (deviceIndex) as active SYNCHRONOUS VERSION
Definition: SpatialField.h:419
void validate_device_async(short int deviceIndex)
populate memory on the given device (deviceIndex) with values from the active device ASYNCHRONOUS VER...
Definition: SpatialField.h:405
T & operator()(const size_t i, const size_t j, const size_t k)
return non-constant reference to cell at given index (i,j,k) on CPU
Definition: SpatialField.h:608
MemoryWindow reset_ghosts(GhostData const &oldGhosts, GhostData const &newGhosts) const
return the current memory window with oldGhosts removed and newGhosts added
Definition: MemoryWindow.h:198
SpatialField(const MemoryWindow window, const BoundaryCellInfo bc, const GhostData ghosts, T *const fieldValues=NULL, const StorageMode mode=InternalStorage, const short int devIdx=CPU_INDEX)
SpatialField constructor.
Definition: SpatialField.h:158
const GhostData & get_ghost_data() const
return the number of total ghost cells
Definition: SpatialField.h:261
T * field_values(const short int deviceIndex=CPU_INDEX)
return a non-constant pointer to memory on the given device
Definition: SpatialField.h:462
const BoundaryCellInfo & boundary_info() const
return the boundary cell information
Definition: SpatialField.h:256
short int active_device_index() const
return the index of the current active device
Definition: SpatialField.h:331
const T & operator()(const IntVec &ijk) const
return constant reference to cell at given index (ijk) on CPU
Definition: SpatialField.h:591
void swap(SpatialField &other)
Performs a swap of the two fields. Note that this does not do a deep copy - it is essentially a point...
Definition: SpatialField.h:230
T value_type
the underlying value type for this field (nominally double)
Definition: SpatialField.h:143
const GhostData & get_valid_ghost_data() const
return the number of current valid ghost cells
Definition: SpatialField.h:266
IntVec get_plus() const
obtain the IntVec containing the number of ghost cells on the (+) faces
Definition: GhostData.h:145
const_iterator end() const
return a constant iterator to end for CPU with valid ghost cells
Definition: SpatialField.h:492
StorageMode
Specifies how memory should be treated in a SpatialField.
Definition: FieldInfo.h:65
Holds information about the number of ghost cells on each side of the domain.
Definition: GhostData.h:54
const_iterator begin() const
return a constant iterator for CPU with valid ghost cells
Definition: SpatialField.h:478
SpatialField(const SpatialField &other)
SpatialField shallow copy constructor.
Definition: SpatialField.h:189
iterator end()
return a non-constant iterator to end for CPU with valid ghost cells
Definition: SpatialField.h:500
bool is_valid(const short int deviceIndex) const
check if the device (deviceIndex) is available and valid
Definition: SpatialField.h:442
T & operator()(const IntVec &ijk)
return non-constant reference to cell at given index (ijk) on CPU
Definition: SpatialField.h:576
unsigned int allocated_bytes() const
returns the number of allocated bytes (for copying memory)
Definition: SpatialField.h:288
iterator interior_begin()
return a non-constant iterator for CPU without ghost cells
Definition: SpatialField.h:515
void wait_for_synchronization()
wait until the current stream is done with all work
Definition: SpatialField.h:326
provides iterator support for SpatialField. Only works for CPU.
Definition: MemoryWindow.h:334
void add_device(short int deviceIndex)
add device memory to this field for given device and populate it with values from current active devi...
Definition: SpatialField.h:354
bool is_available(const short int deviceIndex) const
check if the device (deviceIndex) is available
Definition: SpatialField.h:451
field_type & operator=(const field_type &)
copies the contents of one field into another
Definition: SpatialField.h:654
void set_device_as_active_async(const short int deviceIndex)
set given device (deviceIndex) as active ASYNCHRONOUS VERSION
Definition: SpatialField.h:433
FieldIterator< field_type > iterator
the iterator type
Definition: SpatialField.h:145
void reset_valid_ghosts(const GhostData &input)
set the number of valid ghost cells to given ghosts
Definition: SpatialField.h:278
provides iterator support for SpatialField. Only works for CPU.
Definition: MemoryWindow.h:326
Abstracts checking if a SingleValueField is correctly sized.
Definition: SpatialField.h:64
iterator interior_end()
return a non-constant iterator to end for CPU without ghost cells
Definition: SpatialField.h:530
const_iterator interior_end() const
return a constant iterator to end for CPU without ghost cells
Definition: SpatialField.h:522
const T * field_values(const short int deviceIndex=CPU_INDEX) const
return a constant pointer to memory on the given device
Definition: SpatialField.h:471
Abstracts a field.
Definition: SpatialField.h:132
IntVec get_minus() const
obtain the IntVec containing the number of ghost cells on the (-) faces
Definition: GhostData.h:135
const_iterator interior_begin() const
return a constant iterator for CPU without ghost cells
Definition: SpatialField.h:508
Abstracts the internals of a field.
Definition: FieldInfo.h:92
Provides information about boundary cells for various fields.