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