![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "DataCoupler.hpp"
00002 #include "moab/Tree.hpp"
00003 #include "moab/TupleList.hpp"
00004 #include "moab/SpatialLocator.hpp"
00005 #include "moab/ElemEvaluator.hpp"
00006 #include "moab/Error.hpp"
00007
00008 #ifdef MOAB_HAVE_MPI
00009 #include "moab/ParallelComm.hpp"
00010 #endif
00011
00012 #include "iostream"
00013 #include
00014 #include
00015
00016 #include
00017 #include
00018
00019 namespace moab
00020 {
00021
00022 DataCoupler::DataCoupler( Interface* impl,
00023 Range& source_ents,
00024 int coupler_id,
00025 ParallelComm* pc,
00026 bool init_locator,
00027 int dim )
00028 : mbImpl( impl ), myPcomm( pc ), myId( coupler_id ), myDim( dim )
00029 {
00030 assert( NULL != mbImpl && ( myPcomm || !source_ents.empty() ) );
00031
00032 // Now initialize the tree
00033 if( init_locator )
00034 {
00035 myLocator = new SpatialLocator( mbImpl, source_ents );
00036 myLocator->elem_eval( new ElemEvaluator( mbImpl ) );
00037
00038 // Initialize element evaluator with the default for the entity types in source_ents;
00039 // can be replaced later by application if desired
00040 if( !source_ents.empty() )
00041 {
00042 Range::pair_iterator pit = source_ents.pair_begin();
00043 EntityType last_type = MBMAXTYPE;
00044 for( ; pit != source_ents.pair_end(); ++pit )
00045 {
00046 EntityType this_type = mbImpl->type_from_handle( pit->first );
00047 if( last_type == this_type ) continue;
00048 ErrorCode rval = myLocator->elem_eval()->set_eval_set( pit->first );
00049 if( MB_SUCCESS != rval ) throw( rval );
00050 last_type = this_type;
00051 }
00052 }
00053 }
00054
00055 if( -1 == dim && !source_ents.empty() ) myDim = mbImpl->dimension_from_handle( *source_ents.rbegin() );
00056 }
00057
00058 /* Destructor
00059 */
00060 DataCoupler::~DataCoupler()
00061 {
00062 delete myLocator->elem_eval();
00063 delete myLocator;
00064 }
00065
00066 ErrorCode DataCoupler::locate_points( Range& targ_ents,
00067 const double rel_iter_tol,
00068 const double abs_iter_tol,
00069 const double inside_tol )
00070 {
00071 targetEnts = targ_ents;
00072
00073 #ifdef MOAB_HAVE_MPI
00074 if( myPcomm && myPcomm->size() > 1 )
00075 return myLocator->par_locate_points( myPcomm, targ_ents, rel_iter_tol, abs_iter_tol, inside_tol );
00076 #endif
00077
00078 return myLocator->locate_points( targ_ents, rel_iter_tol, abs_iter_tol, inside_tol );
00079 }
00080
00081 ErrorCode DataCoupler::locate_points( double* xyz,
00082 int num_points,
00083 const double rel_iter_tol,
00084 const double abs_iter_tol,
00085 const double inside_tol )
00086 {
00087 #ifdef MOAB_HAVE_MPI
00088 if( myPcomm && myPcomm->size() > 1 )
00089 return myLocator->par_locate_points( myPcomm, xyz, num_points, rel_iter_tol, abs_iter_tol, inside_tol );
00090 #endif
00091
00092 return myLocator->locate_points( xyz, num_points, rel_iter_tol, abs_iter_tol, inside_tol );
00093 }
00094
00095 ErrorCode DataCoupler::interpolate( /*DataCoupler::Method*/ int method,
00096 const std::string& interp_tag,
00097 double* interp_vals,
00098 std::vector< int >* point_indices,
00099 bool normalize )
00100 {
00101 // Tag name input, translate to tag handle and pass down the chain
00102
00103 Tag tag;
00104 ErrorCode result = mbImpl->tag_get_handle( interp_tag.c_str(), tag );MB_CHK_SET_ERR( result, "Failed to get handle for interpolation tag \"" << interp_tag << "\"" );
00105
00106 return interpolate( method, tag, interp_vals, point_indices, normalize );
00107 }
00108
00109 ErrorCode DataCoupler::interpolate( /*DataCoupler::Method*/ int* /* methods */,
00110 Tag* tags,
00111 int* points_per_method,
00112 int num_methods,
00113 double* interp_vals,
00114 std::vector< int >* point_indices,
00115 bool /*normalize*/ )
00116 {
00117 // Lowest-level interpolate function, does actual interpolation using calls to ElemEvaluator
00118
00119 ErrorCode result = MB_SUCCESS;
00120
00121 unsigned int pts_total = 0;
00122 for( int i = 0; i < num_methods; i++ )
00123 pts_total += ( points_per_method ? points_per_method[i] : targetEnts.size() );
00124
00125 unsigned int num_indices = ( point_indices ? point_indices->size() : targetEnts.size() );
00126 // # points and indices should be identical
00127 if( pts_total != num_indices ) return MB_FAILURE;
00128
00129 // Since each tuple contains one interpolated tag, if we're interpolating multiple tags, every
00130 // tuple needs to be able to store up to max tag size
00131 int max_tsize = -1;
00132 for( int i = 0; i < num_methods; i++ )
00133 {
00134 int tmp_tsize;
00135 result = mbImpl->tag_get_length( tags[i], tmp_tsize );
00136 if( MB_SUCCESS != result ) return MB_FAILURE;
00137 max_tsize = std::max( max_tsize, tmp_tsize );
00138 }
00139
00140 if( myPcomm && myPcomm->size() > 1 )
00141 {
00142 // Build up the tuple list to distribute from my target points; assume that
00143 // all procs use same method/tag input
00144 TupleList TLob; // TLob structure: (pto_i, ridx_i, lidx_i, meth_tagidx_i)
00145 TLob.initialize( 4, 0, 0, 0, num_indices );
00146 int tn = 0; // The tuple number we're currently on
00147 TLob.enableWriteAccess();
00148 for( int m = 0; m < num_methods; m++ )
00149 {
00150 int num_points = ( points_per_method ? points_per_method[m] : targetEnts.size() );
00151 for( int j = 0; j < num_points; j++ )
00152 {
00153 int idx = ( point_indices ? ( *point_indices )[j]
00154 : j ); // The index in my targetEnts for this interpolation point
00155
00156 // Remote proc/idx from myLocator->parLocTable
00157 TLob.vi_wr[4 * tn] = myLocator->par_loc_table().vi_rd[2 * idx]; // proc
00158 TLob.vi_wr[4 * tn + 1] = myLocator->par_loc_table().vi_rd[2 * idx + 1]; // Remote idx
00159
00160 // Local entity index, tag/method index from my data
00161 TLob.vi_wr[4 * tn + 2] = idx;
00162 TLob.vi_wr[4 * tn + 3] = m;
00163 TLob.inc_n();
00164 tn++;
00165 }
00166 }
00167
00168 // Scatter/gather interpolation points
00169 myPcomm->proc_config().crystal_router()->gs_transfer( 1, TLob, 0 );
00170
00171 // Perform interpolation on local source mesh; put results into TLinterp
00172 TupleList TLinterp; // TLinterp structure: (pto_i, ridx_i, vals[max_tsize]_d)
00173 TLinterp.initialize( 2, 0, 0, max_tsize, TLob.get_n() );
00174 TLinterp.set_n( TLob.get_n() ); // Set the size right away
00175 TLinterp.enableWriteAccess();
00176
00177 for( unsigned int i = 0; i < TLob.get_n(); i++ )
00178 {
00179 int lidx = TLob.vi_rd[4 * i + 1]; // Index into myLocator's local table
00180 // Method and tag indexed with same index
00181 ///*Method*/ int method = methods[TLob.vi_rd[4*i + 3]];
00182 Tag tag = tags[TLob.vi_rd[4 * i + 3]];
00183 // Copy proc/remote index from TLob
00184 TLinterp.vi_wr[2 * i] = TLob.vi_rd[4 * i];
00185 TLinterp.vi_wr[2 * i + 1] = TLob.vi_rd[4 * i + 2];
00186
00187 // Set up the evaluator for the tag and entity, then interpolate, putting result in
00188 // TLinterp
00189 myLocator->elem_eval()->set_tag_handle( tag );
00190 myLocator->elem_eval()->set_ent_handle( myLocator->loc_table().vul_rd[lidx] );
00191 result =
00192 myLocator->elem_eval()->eval( myLocator->loc_table().vr_rd + 3 * lidx, TLinterp.vr_rd + i * max_tsize );
00193 if( MB_SUCCESS != result ) return result;
00194 }
00195
00196 // Scatter/gather interpolation data
00197 myPcomm->proc_config().crystal_router()->gs_transfer( 1, TLinterp, 0 );
00198
00199 // Copy the interpolated field as a unit
00200 std::copy( TLinterp.vr_rd, TLinterp.vr_rd + TLinterp.get_n() * max_tsize, interp_vals );
00201 }
00202 else
00203 {
00204 // If called serially, interpolate directly from local locations/entities,
00205 // into either interp_vals or by setting data directly on tags on those entities
00206 std::vector< double > tmp_vals;
00207 std::vector< EntityHandle > tmp_ents;
00208 double* tmp_dbl = interp_vals;
00209 for( int i = 0; i < num_methods; i++ )
00210 {
00211 int num_points = ( points_per_method ? points_per_method[i] : targetEnts.size() );
00212
00213 // Interpolated data is tsize long, which is either max size (if data passed back to
00214 // caller in interp_vals) or tag size (if data will be set on entities, in which case it
00215 // shouldn't have padding) set sizes here, inside loop over methods, to reduce memory
00216 // usage
00217 int tsize = max_tsize, tsize_bytes = 0;
00218 if( !interp_vals )
00219 {
00220 tmp_vals.resize( num_points * max_tsize );
00221 tmp_dbl = &tmp_vals[0];
00222 tmp_ents.resize( num_points );
00223 result = mbImpl->tag_get_length( tags[i], tsize );
00224 if( MB_SUCCESS != result ) return result;
00225 result = mbImpl->tag_get_bytes( tags[i], tsize_bytes );
00226 if( MB_SUCCESS != result ) return result;
00227 }
00228
00229 for( int j = 0; j < num_points; j++ )
00230 {
00231 int lidx;
00232 if( point_indices )
00233 lidx = ( *point_indices )[j];
00234 else
00235 lidx = j;
00236
00237 myLocator->elem_eval()->set_tag_handle( tags[i] );
00238 myLocator->elem_eval()->set_ent_handle( myLocator->loc_table().vul_rd[lidx] );
00239 if( !interp_vals ) tmp_ents[j] = targetEnts[lidx]; // Could be performance-sensitive, thus the if test
00240 result = myLocator->elem_eval()->eval( myLocator->loc_table().vr_rd + 3 * lidx, tmp_dbl );
00241 tmp_dbl += tsize;
00242 if( MB_SUCCESS != result ) return result;
00243 } // for j over points
00244
00245 if( !interp_vals )
00246 {
00247 // Set tags on tmp_ents; data is already w/o padding, due to tsize setting above
00248 result = mbImpl->tag_set_data( tags[i], &tmp_ents[0], tmp_ents.size(), &tmp_vals[0] );
00249 if( MB_SUCCESS != result ) return result;
00250 }
00251
00252 } // for i over methods
00253 } // if myPcomm
00254
00255 // Done
00256 return MB_SUCCESS;
00257 }
00258
00259 } // namespace moab