void ConjugateGradient::initialize(PatchData &pd, MsqError &err) { if (get_parallel_size()) MSQ_DBGOUT(2) << "\nP[" << get_parallel_rank() << "] " << "o Performing Conjugate Gradient optimization.\n"; else MSQ_DBGOUT(2) << "\no Performing Conjugate Gradient optimization.\n"; pMemento=pd.create_vertices_memento(err); }
std::string process_itaps_error( int ierr ) { std::string result( "ITAPS ERROR: " ); switch (ierr) { case iBase_MESH_ALREADY_LOADED: result += "File Already Loaded"; break; case iBase_NO_MESH_DATA: result += "No Mesh"; break; case iBase_FILE_NOT_FOUND: result += "File Not Found"; break; case iBase_FILE_WRITE_ERROR: result += "File Write Error"; break; case iBase_NIL_ARRAY: result += "NULL Array"; break; case iBase_BAD_ARRAY_SIZE: result += "Bad Array Size"; break; case iBase_BAD_ARRAY_DIMENSION: result += "Bad Array Dimension"; break; case iBase_INVALID_ENTITY_HANDLE: result += "Invalid Handle"; break; case iBase_INVALID_ENTITY_COUNT: result += "Invalid Count"; break; case iBase_INVALID_ENTITY_TYPE: result += "Invalid Type"; break; case iBase_INVALID_ENTITY_TOPOLOGY: result += "Invalid Topology"; break; case iBase_BAD_TYPE_AND_TOPO: result += "Invalid Type"; break; case iBase_ENTITY_CREATION_ERROR: result += "Creation Failed"; break; case iBase_INVALID_TAG_HANDLE: result += "Invalid Tag"; break; case iBase_TAG_NOT_FOUND: result += "Tag Not Found"; break; case iBase_TAG_ALREADY_EXISTS: result += "Tag Exists"; break; case iBase_TAG_IN_USE: result += "Tag In Use"; break; case iBase_INVALID_ENTITYSET_HANDLE: result += "Invalid Handle"; break; case iBase_INVALID_ITERATOR_HANDLE: result += "Invalid Iterator"; break; case iBase_INVALID_ARGUMENT: result += "Invalid Argument"; break; case iBase_MEMORY_ALLOCATION_FAILED: result += "Out of Memory"; break; case iBase_NOT_SUPPORTED: result += "Not Supported"; break; default: result += "Uknown/Internal Error"; break; } MSQ_DBGOUT(1) << result << std::endl; return result; }
void ShapeImprovementWrapper::run_wrapper( Mesh* mesh, ParallelMesh* pmesh, MeshDomain* domain, Settings* settings, QualityAssessor* qa, MsqError& err ) { // Define an untangler UntangleBetaQualityMetric untangle_metric( untBeta ); LPtoPTemplate untangle_func( 2, &untangle_metric ); ConjugateGradient untangle_global( &untangle_func ); TerminationCriterion untangle_inner, untangle_outer; untangle_global.use_global_patch(); untangle_inner.add_absolute_quality_improvement( 0.0 ); untangle_inner.add_absolute_successive_improvement( successiveEps ); untangle_outer.add_iteration_limit( 1 ); untangle_global.set_inner_termination_criterion( &untangle_inner ); untangle_global.set_outer_termination_criterion( &untangle_outer ); // define shape improver IdealWeightInverseMeanRatio inverse_mean_ratio; inverse_mean_ratio.set_averaging_method( QualityMetric::LINEAR ); LPtoPTemplate obj_func( 2, &inverse_mean_ratio ); FeasibleNewton feas_newt( &obj_func ); TerminationCriterion term_inner, term_outer; feas_newt.use_global_patch(); qa->add_quality_assessment( &inverse_mean_ratio ); term_inner.add_absolute_gradient_L2_norm( gradNorm ); term_inner.add_relative_successive_improvement( successiveEps ); term_outer.add_iteration_limit( pmesh ? parallelIterations : 1 ); feas_newt.set_inner_termination_criterion( &term_inner ); feas_newt.set_outer_termination_criterion( &term_outer ); // Apply CPU time limit to untangler if (maxTime > 0.0) untangle_inner.add_cpu_time( maxTime ); // Run untangler InstructionQueue q1; Timer totalTimer; q1.set_master_quality_improver( &untangle_global, err ); MSQ_ERRRTN(err); q1.add_quality_assessor( qa, err ); MSQ_ERRRTN(err); q1.run_common( mesh, pmesh, domain, settings, err ); MSQ_ERRRTN(err); // If limited by CPU time, limit next step to remaning time if (maxTime > 0.0) { double remaining = maxTime - totalTimer.since_birth(); if (remaining <= 0.0 ){ MSQ_DBGOUT(2) << "Optimization is terminating without perfoming shape improvement." << std::endl; remaining = 0.0; } term_inner.add_cpu_time( remaining ); } // Run shape improver InstructionQueue q2; q2.set_master_quality_improver( &feas_newt, err ); MSQ_ERRRTN(err); q2.add_quality_assessor( qa, err ); MSQ_ERRRTN(err); q2.run_common( mesh, pmesh, domain, settings, err ); MSQ_ERRRTN(err); }
/*!Performs Conjugate gradient minimization on the PatchData, pd.*/ void ConjugateGradient::optimize_vertex_positions(PatchData &pd, MsqError &err){ // pd.reorder(); MSQ_FUNCTION_TIMER( "ConjugateGradient::optimize_vertex_positions" ); Timer c_timer; size_t num_vert=pd.num_free_vertices(); if(num_vert<1){ MSQ_DBGOUT(1) << "\nEmpty free vertex list in ConjugateGradient\n"; return; } /* //zero out arrays int zero_loop=0; while(zero_loop<arraySize){ fGrad[zero_loop].set(0,0,0); pGrad[zero_loop].set(0,0,0); fNewGrad[zero_loop].set(0,0,0); ++zero_loop; } */ // get OF evaluator OFEvaluator& objFunc = get_objective_function_evaluator(); size_t ind; //Michael cull list: possibly set soft_fixed flags here //MsqFreeVertexIndexIterator free_iter(pd, err); MSQ_ERRRTN(err); double f=0; //Michael, this isn't equivalent to CUBIT because we only want to check //the objective function value of the 'bad' elements //if invalid initial patch set an error. bool temp_bool = objFunc.update(pd, f, fGrad, err); assert(fGrad.size() == num_vert); if(MSQ_CHKERR(err)) return; if( ! temp_bool){ MSQ_SETERR(err)("Conjugate Gradient not able to get valid gradient " "and function values on intial patch.", MsqError::INVALID_MESH); return; } double grad_norm=MSQ_MAX_CAP; if(conjGradDebug>0){ MSQ_PRINT(2)("\nCG's DEGUB LEVEL = %i \n",conjGradDebug); grad_norm=Linf(arrptr(fGrad),fGrad.size()); MSQ_PRINT(2)("\nCG's FIRST VALUE = %f,grad_norm = %f",f,grad_norm); MSQ_PRINT(2)("\n TIME %f",c_timer.since_birth()); grad_norm=MSQ_MAX_CAP; } //Initializing pGrad (search direction). pGrad.resize(fGrad.size()); for (ind = 0; ind < num_vert; ++ind) pGrad[ind]=(-fGrad[ind]); int j=0; // total nb of step size changes ... not used much int i=0; // iteration counter unsigned m=0; // double alp=MSQ_MAX_CAP; // alp: scale factor of search direction //we know inner_criterion is false because it was checked in //loop_over_mesh before being sent here. TerminationCriterion* term_crit=get_inner_termination_criterion(); //while ((i<maxIteration && alp>stepBound && grad_norm>normGradientBound) // && !inner_criterion){ while(!term_crit->terminate()){ ++i; //std::cout<<"\Michael delete i = "<<i; int k=0; alp=get_step(pd,f,k,err); j+=k; if(conjGradDebug>2){ MSQ_PRINT(2)("\n Alp initial, alp = %20.18f",alp); } // if alp == 0, revert to steepest descent search direction if(alp==0){ for (m = 0; m < num_vert; ++m) { pGrad[m]=(-fGrad[m]); } alp=get_step(pd,f,k,err); j+=k; if(conjGradDebug>1){ MSQ_PRINT(2)("\n CG's search direction reset."); if(conjGradDebug>2) MSQ_PRINT(2)("\n Alp was zero, alp = %20.18f",alp); } } if(alp!=0){ pd.move_free_vertices_constrained( arrptr(pGrad), num_vert, alp, err ); MSQ_ERRRTN(err); if (! objFunc.update(pd, f, fNewGrad, err)){ MSQ_SETERR(err)("Error inside Conjugate Gradient, vertices moved " "making function value invalid.", MsqError::INVALID_MESH); return; } assert(fNewGrad.size() == (unsigned)num_vert); if(conjGradDebug>0){ grad_norm=Linf(arrptr(fNewGrad),num_vert); MSQ_PRINT(2)("\nCG's VALUE = %f, iter. = %i, grad_norm = %f, alp = %f",f,i,grad_norm,alp); MSQ_PRINT(2)("\n TIME %f",c_timer.since_birth()); } double s11=0; double s12=0; double s22=0; //free_iter.reset(); //while (free_iter.next()) { // m=free_iter.value(); for (m = 0; m < num_vert; ++m) { s11+=fGrad[m]%fGrad[m]; s12+=fGrad[m]%fNewGrad[m]; s22+=fNewGrad[m]%fNewGrad[m]; } // Steepest Descent (takes 2-3 times as long as P-R) //double bet=0; // Fletcher-Reeves (takes twice as long as P-R) //double bet = s22/s11; // Polack-Ribiere double bet; if (!divide( s22-s12, s11, bet )) return; // gradient is zero //free_iter.reset(); //while (free_iter.next()) { // m=free_iter.value(); for (m = 0; m < num_vert; ++m) { pGrad[m]=(-fNewGrad[m]+(bet*pGrad[m])); fGrad[m]=fNewGrad[m]; } if(conjGradDebug>2){ MSQ_PRINT(2)(" \nSEARCH DIRECTION INFINITY NORM = %e", Linf(arrptr(fNewGrad),num_vert)); } }//end if on alp == 0 term_crit->accumulate_patch( pd, err ); MSQ_ERRRTN(err); term_crit->accumulate_inner( pd, f, arrptr(fGrad), err ); MSQ_ERRRTN(err); }//end while if(conjGradDebug>0){ MSQ_PRINT(2)("\nConjugate Gradient complete i=%i ",i); MSQ_PRINT(2)("\n- FINAL value = %f, alp=%4.2e grad_norm=%4.2e",f,alp,grad_norm); MSQ_PRINT(2)("\n FINAL TIME %f",c_timer.since_birth()); } }
/*! This function evaluates the needed information and then evaluates the termination criteria. If any of the selected criteria are satisfied, the function returns true. Otherwise, the function returns false. */ bool TerminationCriterion::terminate( ) { bool return_flag = false; //std::cout<<"\nInside terminate(pd,of,err): flag = "<<terminationCriterionFlag << std::endl; int type=0; //First check for an interrupt signal if (MsqInterrupt::interrupt()) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- INTERRUPTED" << " " << std::endl; return true; } //if terminating on numbering of inner iterations if (NUMBER_OF_ITERATES & terminationCriterionFlag && iterationCounter >= iterationBound) { return_flag = true; type=1; MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- Reached " << " " << iterationBound << " iterations." << std::endl; } if (CPU_TIME & terminationCriterionFlag && mTimer.since_birth()>=timeBound) { return_flag=true; type=2; MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- Exceeded CPU time. " << " " << std::endl; } if (MOVEMENT_FLAGS & terminationCriterionFlag && maxSquaredMovement >= 0.0) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o Info -- Maximum vertex movement: " << " " << RPM(sqrt(maxSquaredMovement)) << std::endl; if (VERTEX_MOVEMENT_ABSOLUTE & terminationCriterionFlag && maxSquaredMovement <= vertexMovementAbsoluteEps) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- VERTEX_MOVEMENT_ABSOLUTE: " << " " << RPM(sqrt(maxSquaredMovement)) << std::endl; return_flag = true; type=3; } if (VERTEX_MOVEMENT_RELATIVE & terminationCriterionFlag && maxSquaredMovement <= vertexMovementRelativeEps*maxSquaredInitialMovement) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- VERTEX_MOVEMENT_RELATIVE: " << " " << RPM(sqrt(maxSquaredMovement)) << std::endl; return_flag = true; type=4; } if (VERTEX_MOVEMENT_ABS_EDGE_LENGTH & terminationCriterionFlag) { assert( vertexMovementAbsoluteAvgEdge > -1e-12 ); // make sure value actually got calculated if (maxSquaredMovement <= vertexMovementAbsoluteAvgEdge) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- VERTEX_MOVEMENT_ABS_EDGE_LENGTH: " << " " << RPM(sqrt(maxSquaredMovement)) << std::endl; return_flag = true; type=5; } } } if (GRADIENT_L2_NORM_ABSOLUTE & terminationCriterionFlag && currentGradL2NormSquared <= gradL2NormAbsoluteEpsSquared) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- GRADIENT_L2_NORM_ABSOLUTE: " << " " << RPM(currentGradL2NormSquared) << std::endl; return_flag = true; type=6; } if (GRADIENT_INF_NORM_ABSOLUTE & terminationCriterionFlag && currentGradInfNorm <= gradInfNormAbsoluteEps) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- GRADIENT_INF_NORM_ABSOLUTE: " << " " << RPM(currentGradInfNorm) << std::endl; return_flag = true; type=7; } if (GRADIENT_L2_NORM_RELATIVE & terminationCriterionFlag && currentGradL2NormSquared <= (gradL2NormRelativeEpsSquared * initialGradL2NormSquared)) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- GRADIENT_L2_NORM_RELATIVE: " << " " << RPM(currentGradL2NormSquared) << std::endl; return_flag = true; type=8; } if (GRADIENT_INF_NORM_RELATIVE & terminationCriterionFlag && currentGradInfNorm <= (gradInfNormRelativeEps * initialGradInfNorm)) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- GRADIENT_INF_NORM_RELATIVE: " << " " << RPM(currentGradInfNorm) << std::endl; return_flag = true; type=9; } //Quality Improvement and Successive Improvements are below. // The relative forms are only valid after the first iteration. if ((QUALITY_IMPROVEMENT_ABSOLUTE & terminationCriterionFlag) && currentOFValue <= qualityImprovementAbsoluteEps) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- QUALITY_IMPROVEMENT_ABSOLUTE: " << " " << RPM(currentOFValue) << std::endl; return_flag = true; type=10; } //only valid if an iteration has occurred, see above. if(iterationCounter > 0){ if (SUCCESSIVE_IMPROVEMENTS_ABSOLUTE & terminationCriterionFlag && (previousOFValue - currentOFValue) <= successiveImprovementsAbsoluteEps) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- SUCCESSIVE_IMPROVEMENTS_ABSOLUTE: previousOFValue= " << " " << previousOFValue << " currentOFValue= " << RPM(currentOFValue) << " successiveImprovementsAbsoluteEps= " << successiveImprovementsAbsoluteEps << std::endl; return_flag = true; type=11; } if (QUALITY_IMPROVEMENT_RELATIVE & terminationCriterionFlag && (currentOFValue - lowerOFBound) <= qualityImprovementRelativeEps * (initialOFValue - lowerOFBound)) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- QUALITY_IMPROVEMENT_RELATIVE: " << " " << std::endl; return_flag = true; type=12; } if (SUCCESSIVE_IMPROVEMENTS_RELATIVE & terminationCriterionFlag && (previousOFValue - currentOFValue) <= successiveImprovementsRelativeEps * (initialOFValue - currentOFValue)) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- SUCCESSIVE_IMPROVEMENTS_RELATIVE: previousOFValue= " << " " << previousOFValue << " currentOFValue= " << RPM(currentOFValue) << " successiveImprovementsRelativeEps= " << successiveImprovementsRelativeEps << std::endl; return_flag = true; type=13; } } if (BOUNDED_VERTEX_MOVEMENT & terminationCriterionFlag && vertexMovementExceedsBound) { return_flag = true; type=14; MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- " << " " << vertexMovementExceedsBound << " vertices out of bounds." << std::endl; } if (UNTANGLED_MESH & terminationCriterionFlag) { if (innerOuterType==TYPE_OUTER) { //MSQ_DBGOUT_P0_ONLY(debugLevel) MSQ_DBGOUT(debugLevel) << par_string() << " o Num Inverted: " << " " << globalInvertedCount << std::endl; } if (!globalInvertedCount) { MSQ_DBGOUT_P0_ONLY(debugLevel) << par_string() << " o TermCrit -- UNTANGLED_MESH: "<< " " << std::endl; return_flag = true; type=15; } } // clear this value at the end of each iteration vertexMovementExceedsBound = 0; maxSquaredMovement = -1.0; if (timeStepFileType == GNUPLOT && return_flag) { MsqError err; MeshWriter::write_gnuplot_overlay( iterationCounter, timeStepFileName.c_str(), err ); } if (0 && return_flag && MSQ_DBG(2)) std::cout << "P[" << get_parallel_rank() << "] tmp TerminationCriterion::terminate: " << moniker << " return_flag= " << return_flag << " type= " << type << " terminationCriterionFlag= " << terminationCriterionFlag << " debugLevel= " << debugLevel << std::endl; //if none of the criteria were satisfied return return_flag; }
void SteepestDescent::optimize_vertex_positions(PatchData &pd, MsqError &err) { MSQ_FUNCTION_TIMER( "SteepestDescent::optimize_vertex_positions" ); const int SEARCH_MAX = 100; const double c1 = 1e-4; //std::vector<Vector3D> unprojected(pd.num_free_vertices()); std::vector<Vector3D> gradient(pd.num_free_vertices()); bool feasible=true;//bool for OF values double min_edge_len, max_edge_len; double step_size=0, original_value=0, new_value=0; double norm_squared=0; PatchDataVerticesMemento* pd_previous_coords; TerminationCriterion* term_crit=get_inner_termination_criterion(); OFEvaluator& obj_func = get_objective_function_evaluator(); // get vertex memento so we can restore vertex coordinates for bad steps. pd_previous_coords = pd.create_vertices_memento( err ); MSQ_ERRRTN(err); // use auto_ptr to automatically delete memento when we exit this function std::auto_ptr<PatchDataVerticesMemento> memento_deleter( pd_previous_coords ); // Evaluate objective function. // // Always use 'update' version when beginning optimization so that // if doing block coordinate descent the OF code knows the set of // vertices we are modifying during the optimziation (the subset // of the mesh contained in the current patch.) This has to be // done up-front because typically an OF will just store the portion // of the OF value (e.g. the numeric contribution to the sum for an // averaging OF) for the initial patch. feasible = obj_func.update( pd, original_value, gradient, err ); MSQ_ERRRTN(err); // calculate gradient dotted with itself norm_squared = length_squared( gradient ); //set an error if initial patch is invalid. if(!feasible){ MSQ_SETERR(err)("SteepestDescent passed invalid initial patch.", MsqError::INVALID_ARG); return; } // use edge length as an initial guess for for step size pd.get_minmax_edge_length( min_edge_len, max_edge_len ); //step_size = max_edge_len / std::sqrt(norm_squared); //if (!finite(step_size)) // zero-length gradient // return; // if (norm_squared < DBL_EPSILON) // return; if (norm_squared >= DBL_EPSILON) step_size = max_edge_len / std::sqrt(norm_squared) * pd.num_free_vertices(); // The steepest descent loop... // We loop until the user-specified termination criteria are met. while (!term_crit->terminate()) { MSQ_DBGOUT(3) << "Iteration " << term_crit->get_iteration_count() << std::endl; MSQ_DBGOUT(3) << " o original_value: " << original_value << std::endl; MSQ_DBGOUT(3) << " o grad norm suqared: " << norm_squared << std::endl; // Save current vertex coords so that they can be restored if // the step was bad. pd.recreate_vertices_memento( pd_previous_coords, err ); MSQ_ERRRTN(err); // Reduce step size until it satisfies Armijo condition int counter = 0; for (;;) { if (++counter > SEARCH_MAX || step_size < DBL_EPSILON) { MSQ_DBGOUT(3) << " o No valid step found. Giving Up." << std::endl; return; } // Move vertices to new positions. // Note: step direction is -gradient so we pass +gradient and // -step_size to achieve the same thing. pd.move_free_vertices_constrained( arrptr(gradient), gradient.size(), -step_size, err ); MSQ_ERRRTN(err); // Evaluate objective function for new vertices. We call the // 'evaluate' form here because we aren't sure yet if we want to // keep these vertices. Until we call 'update', we have the option // of reverting a block coordinate decent objective function's state // to that of the initial vertex coordinates. However, for block // coordinate decent to work correctly, we will need to call an // 'update' form if we decide to keep the new vertex coordinates. feasible = obj_func.evaluate( pd, new_value, err ); if (err.error_code() == err.BARRIER_VIOLATED) err.clear(); // barrier violated does not represent an actual error here MSQ_ERRRTN(err); MSQ_DBGOUT(3) << " o step_size: " << step_size << std::endl; MSQ_DBGOUT(3) << " o new_value: " << new_value << std::endl; if (!feasible) { // OF value is invalid, decrease step_size a lot step_size *= 0.2; } else if (new_value > original_value - c1 * step_size * norm_squared) { // Armijo condition not met. step_size *= 0.5; } else { // Armijo condition met, stop break; } // undo previous step : restore vertex coordinates pd.set_to_vertices_memento( pd_previous_coords, err ); MSQ_ERRRTN(err); } // Re-evaluate objective function to get gradient. // Calling the 'update' form here incorporates the new vertex // positions into the 'accumulated' value if we are doing a // block coordinate descent optimization. obj_func.update(pd, original_value, gradient, err ); MSQ_ERRRTN(err); if (projectGradient) { //if (cosineStep) { // unprojected = gradient; // pd.project_gradient( gradient, err ); MSQ_ERRRTN(err); // double dot = inner_product( arrptr(gradient), arrptr(unprojected), gradient.size() ); // double lensqr1 = length_squared( gradient ); // double lensqr2 = length_squared( unprojected ); // double cossqr = dot * dot / lensqr1 / lensqr2; // step_size *= sqrt(cossqr); //} //else { pd.project_gradient( gradient, err ); MSQ_ERRRTN(err); //} } // Update terination criterion for next iteration. // This is necessary for efficiency. Some values can be adjusted // for each iteration so we don't need to re-caculate the value // over the entire mesh. term_crit->accumulate_patch( pd, err ); MSQ_ERRRTN(err); term_crit->accumulate_inner( pd, original_value, arrptr(gradient), err ); MSQ_ERRRTN(err); // Calculate initial step size for next iteration using step size // from this iteration step_size *= norm_squared; norm_squared = length_squared( gradient ); // if (norm_squared < DBL_EPSILON) // break; if (norm_squared >= DBL_EPSILON) step_size /= norm_squared; } }
bool IdealWeightInverseMeanRatio::evaluate_with_Hessian( PatchData& pd, size_t handle, double& m, std::vector<size_t>& indices, std::vector<Vector3D>& g, std::vector<Matrix3D>& h, MsqError& err ) { const MsqMeshEntity* e = &pd.element_by_index(handle); EntityTopology topo = e->get_element_type(); if (!analytical_average_hessian() && topo != TRIANGLE && topo != TETRAHEDRON) { static bool print = true; if (print) { MSQ_DBGOUT(1) << "Analyical gradient not available for selected averaging scheme. " << "Using (possibly much slower) numerical approximation of gradient" << " of quality metric. " << std::endl; print = false; } return QualityMetric::evaluate_with_Hessian( pd, handle, m, indices, g, h, err ); } const MsqVertex *vertices = pd.get_vertex_array(err); MSQ_ERRZERO(err); const size_t *v_i = e->get_vertex_index_array(); Vector3D n; // Surface normal for 2D objects // Prism and Hex element descriptions static const int locs_pri[6][4] = {{0, 1, 2, 3}, {1, 2, 0, 4}, {2, 0, 1, 5}, {3, 5, 4, 0}, {4, 3, 5, 1}, {5, 4, 3, 2}}; static const int locs_hex[8][4] = {{0, 1, 3, 4}, {1, 2, 0, 5}, {2, 3, 1, 6}, {3, 0, 2, 7}, {4, 7, 5, 0}, {5, 4, 6, 1}, {6, 5, 7, 2}, {7, 6, 4, 3}}; const Vector3D d_con(1.0, 1.0, 1.0); int i; bool metric_valid = false; const uint32_t fm = fixed_vertex_bitmap( pd, e, indices ); m = 0.0; switch(topo) { case TRIANGLE: pd.get_domain_normal_at_element(e, n, err); MSQ_ERRZERO(err); n /= n.length(); // Need unit normal mCoords[0] = vertices[v_i[0]]; mCoords[1] = vertices[v_i[1]]; mCoords[2] = vertices[v_i[2]]; g.resize(3); h.resize(6); if (!h_fcn_2e(m, arrptr(g), arrptr(h), mCoords, n, a2Con, b2Con, c2Con)) return false; break; case QUADRILATERAL: pd.get_domain_normal_at_element(e, n, err); MSQ_ERRZERO(err); n /= n.length(); // Need unit normal for (i = 0; i < 4; ++i) { mCoords[0] = vertices[v_i[locs_hex[i][0]]]; mCoords[1] = vertices[v_i[locs_hex[i][1]]]; mCoords[2] = vertices[v_i[locs_hex[i][2]]]; if (!h_fcn_2i(mMetrics[i], mGradients+3*i, mHessians+6*i, mCoords, n, a2Con, b2Con, c2Con, d_con)) return false; } g.resize(4); h.resize(10); m = average_corner_hessians( QUADRILATERAL, fm, 4, mMetrics, mGradients, mHessians, arrptr(g), arrptr(h), err ); MSQ_ERRZERO( err ); break; case TETRAHEDRON: mCoords[0] = vertices[v_i[0]]; mCoords[1] = vertices[v_i[1]]; mCoords[2] = vertices[v_i[2]]; mCoords[3] = vertices[v_i[3]]; g.resize(4); h.resize(10); metric_valid = h_fcn_3e(m, arrptr(g), arrptr(h), mCoords, a3Con, b3Con, c3Con); if (!metric_valid) return false; break; case PYRAMID: for (i = 0; i < 4; ++i) { mCoords[0] = vertices[v_i[ i ]]; mCoords[1] = vertices[v_i[(i+1)%4]]; mCoords[2] = vertices[v_i[(i+3)%4]]; mCoords[3] = vertices[v_i[ 4 ]]; metric_valid = h_fcn_3p(mMetrics[i], mGradients+4*i, mHessians+10*i, mCoords, a3Con, b3Con, c3Con); if (!metric_valid) return false; } g.resize(5); h.resize(15); m = average_corner_hessians( PYRAMID, fm, 4, mMetrics, mGradients, mHessians, arrptr(g), arrptr(h), err ); MSQ_ERRZERO( err ); break; case PRISM: for (i = 0; i < 6; ++i) { mCoords[0] = vertices[v_i[locs_pri[i][0]]]; mCoords[1] = vertices[v_i[locs_pri[i][1]]]; mCoords[2] = vertices[v_i[locs_pri[i][2]]]; mCoords[3] = vertices[v_i[locs_pri[i][3]]]; if (!h_fcn_3w(mMetrics[i], mGradients+4*i, mHessians+10*i, mCoords, a3Con, b3Con, c3Con)) return false; } g.resize(6); h.resize(21); m = average_corner_hessians( PRISM, fm, 6, mMetrics, mGradients, mHessians, arrptr(g), arrptr(h), err ); MSQ_ERRZERO( err ); break; case HEXAHEDRON: for (i = 0; i < 8; ++i) { mCoords[0] = vertices[v_i[locs_hex[i][0]]]; mCoords[1] = vertices[v_i[locs_hex[i][1]]]; mCoords[2] = vertices[v_i[locs_hex[i][2]]]; mCoords[3] = vertices[v_i[locs_hex[i][3]]]; if (!h_fcn_3i(mMetrics[i], mGradients+4*i, mHessians+10*i, mCoords, a3Con, b3Con, c3Con, d_con)) return false; } g.resize(8); h.resize(36); m = average_corner_hessians( HEXAHEDRON, fm, 8, mMetrics, mGradients, mHessians, arrptr(g), arrptr(h), err ); MSQ_ERRZERO( err ); break; default: MSQ_SETERR(err)(MsqError::UNSUPPORTED_ELEMENT, "Element type (%d) not supported in IdealWeightInverseMeanRatio", (int)topo); return false; } // end switch over element type remove_fixed_gradients( topo, fm, g ); remove_fixed_hessians( topo, fm, h ); return true; }