moab
|
00001 #include <limits> 00002 00003 #include "moab/ElemEvaluator.hpp" 00004 #include "moab/CartVect.hpp" 00005 #include "moab/Matrix3.hpp" 00006 00007 // need to include eval set types here to support get_eval_set; alternative would be to have some 00008 // type of registration, but we'd still need static registration for the built-in types 00009 #include "moab/LinearTri.hpp" 00010 #include "moab/LinearQuad.hpp" 00011 #include "moab/LinearTet.hpp" 00012 #include "moab/LinearHex.hpp" 00013 #include "moab/QuadraticHex.hpp" 00014 //#include "moab/SpectralQuad.hpp" 00015 //#include "moab/SpectralHex.hpp" 00016 00017 namespace moab { 00018 ErrorCode EvalSet::evaluate_reverse(EvalFcn eval, JacobianFcn jacob, InsideFcn inside_f, 00019 const double *posn, const double *verts, const int nverts, 00020 const int ndim, const double iter_tol, const double inside_tol, 00021 double *work, double *params, int *inside) { 00022 // TODO: should differentiate between epsilons used for 00023 // Newton Raphson iteration, and epsilons used for curved boundary geometry errors 00024 // right now, fix the tolerance used for NR 00025 const double error_tol_sqr = iter_tol*iter_tol; 00026 CartVect *cvparams = reinterpret_cast<CartVect*>(params); 00027 const CartVect *cvposn = reinterpret_cast<const CartVect*>(posn); 00028 00029 // initialize to center of element 00030 *cvparams = CartVect(-.4); 00031 00032 CartVect new_pos; 00033 // evaluate that first guess to get a new position 00034 ErrorCode rval = (*eval)(cvparams->array(), verts, ndim, 00035 3, // hardwire to num_tuples to 3 since the field is coords 00036 work, new_pos.array()); 00037 if (MB_SUCCESS != rval) return rval; 00038 00039 // residual is diff between old and new pos; need to minimize that 00040 CartVect res = new_pos - *cvposn; 00041 Matrix3 J; 00042 int dum, *tmp_inside = (inside ? inside : &dum); 00043 00044 int iters=0; 00045 // while |res| larger than tol 00046 while (res % res > error_tol_sqr) { 00047 if(++iters>10) { 00048 // if we haven't converged but we're outside, that's defined as success 00049 *tmp_inside = (*inside_f)(params, ndim, inside_tol); 00050 if (!(*tmp_inside)) return MB_SUCCESS; 00051 else return MB_FAILURE; 00052 } 00053 00054 // get jacobian at current params 00055 rval = (*jacob)(cvparams->array(), verts, nverts, ndim, work, J[0]); 00056 double det = J.determinant(); 00057 if (det < std::numeric_limits<double>::epsilon()) { 00058 *tmp_inside = (*inside_f)(params, ndim, inside_tol); 00059 if (!(*tmp_inside)) return MB_SUCCESS; 00060 else return MB_INDEX_OUT_OF_RANGE; 00061 } 00062 00063 // new params tries to eliminate residual 00064 *cvparams -= J.inverse(1.0/det) * res; 00065 00066 // get the new forward-evaluated position, and its difference from the target pt 00067 rval = (*eval)(params, verts, ndim, 00068 3, // hardwire to num_tuples to 3 since the field is coords 00069 work, new_pos.array()); 00070 if (MB_SUCCESS != rval) return rval; 00071 res = new_pos - *cvposn; 00072 } 00073 00074 if (inside) 00075 *inside = (*inside_f)(params, ndim, inside_tol); 00076 00077 return MB_SUCCESS; 00078 }// Map::evaluate_reverse() 00079 00080 int EvalSet::inside_function(const double *params, const int ndims, const double tol) 00081 { 00082 if (params[0] >= -1-tol && params[0] <= 1+tol && 00083 (ndims < 2 || (params[1] >= -1-tol && params[1] <= 1+tol)) && 00084 (ndims < 3 || (params[2] >= -1-tol && params[2] <= 1+tol))) 00085 return true; 00086 else return false; 00087 } 00088 00090 ErrorCode EvalSet::get_eval_set(EntityType tp, unsigned int num_vertices, EvalSet &eval_set) 00091 { 00092 switch (tp) { 00093 case MBEDGE: 00094 break; 00095 case MBTRI: 00096 if (LinearTri::compatible(tp, num_vertices, eval_set)) return MB_SUCCESS; 00097 break; 00098 case MBQUAD: 00099 if (LinearQuad::compatible(tp, num_vertices, eval_set)) return MB_SUCCESS; 00100 // if (SpectralQuad::compatible(tp, num_vertices, eval_set)) return MB_SUCCESS; 00101 break; 00102 case MBTET: 00103 if (LinearTet::compatible(tp, num_vertices, eval_set)) return MB_SUCCESS; 00104 break; 00105 case MBHEX: 00106 if (LinearHex::compatible(tp, num_vertices, eval_set)) return MB_SUCCESS; 00107 if (QuadraticHex::compatible(tp, num_vertices, eval_set)) return MB_SUCCESS; 00108 // if (SpectralHex::compatible(tp, num_vertices, eval_set)) return MB_SUCCESS; 00109 break; 00110 default: 00111 break; 00112 } 00113 00114 return MB_NOT_IMPLEMENTED; 00115 } 00116 00117 ErrorCode ElemEvaluator::find_containing_entity(Range &entities, const double *point, const double iter_tol, 00118 const double inside_tol, EntityHandle &containing_ent, 00119 double *params, unsigned int *num_evals) 00120 { 00121 int is_inside; 00122 ErrorCode rval = MB_SUCCESS; 00123 unsigned int nevals = 0; 00124 Range::iterator i; 00125 for(i = entities.begin(); i != entities.end(); i++) { 00126 nevals++; 00127 set_ent_handle(*i); 00128 rval = reverse_eval(point, iter_tol, inside_tol, params, &is_inside); 00129 if (MB_SUCCESS != rval) return rval; 00130 if (is_inside) break; 00131 } 00132 containing_ent = (i == entities.end() ? 0 : *i); 00133 if (num_evals) *num_evals += nevals; 00134 return MB_SUCCESS; 00135 } 00136 } // namespace moab