void NonGradient::optimize_vertex_positions(PatchData &pd, MsqError &err) { MSQ_FUNCTION_TIMER( "NonGradient::optimize_vertex_positions" ); int numRow = getDimension(); int numCol = numRow+1; std::vector<double> height(numCol); for(int col = 0; col < numCol; col++) { height[col] = evaluate(&simplex[col*numRow], pd, err);// eval patch stuff } if(mNonGradDebug > 0) { printSimplex( simplex, height ); } // standardization TerminationCriterion* term_crit=get_inner_termination_criterion(); int maxNumEval = getMaxNumEval(); double threshold = getThreshold(); // double ftol = getTolerance(); int ilo = 0; //height[ilo]<=... int inhi = 0; //...<=height[inhi]<= int ihi = 0; //<=height[ihi] // double rtol = 2.*ftol; double ysave; double ytry; bool afterEvaluation = false; std::vector<double> rowSum(numRow); getRowSum( numRow, numCol, simplex, rowSum); while( !( term_crit->terminate() ) ) { if(mNonGradDebug > 0) { printSimplex( simplex, height ); } //std::cout << "rtol " << rtol << " ftol " << ftol << " MesquiteIter " << term_crit->get_iteration_count() << " Done " << term_crit->terminate() << std::endl; if( afterEvaluation ) { // reflect highPt through opposite face // height[0] may vanish /* if( !testRowSum( numRow, numCol, &simplex[0], &rowSum[0]) ) { // Before uncommenting here and ... //MSQ_SETERR(err)("Internal check sum test A failed", MsqError::INTERNAL_ERROR); //MSQ_ERRRTN(err); } */ ytry=amotry(simplex,height,&rowSum[0],ihi,-1.0, pd, err); /* if( !testRowSum( numRow, numCol, &simplex[0], &rowSum[0]) ) { // ... here, determine a maxVal majorizing the previous as well as the current simplex. //MSQ_SETERR(err)("Internal check sum test B failed", MsqError::INTERNAL_ERROR); //MSQ_ERRRTN(err); } */ /* if( height[0] == 0.) { MSQ_SETERR(err)("(B) Zero objective function value", MsqError::INTERNAL_ERROR); exit(-1); } */ if (ytry <= height[ilo]) { ytry=amotry(simplex,height,&rowSum[0],ihi,-2.0,pd,err); if( mNonGradDebug >= 3 ) { std::cout << "Reflect and Expand from highPt " << ytry << std::endl; } //MSQ_PRINT(3)("Reflect and Expand from highPt : %e\n",ytry); } else { if (ytry >= height[inhi]) { ysave=height[ihi]; // Contract along highPt ytry=amotry(simplex,height,&rowSum[0],ihi,0.5,pd,err); if (ytry >= ysave) { // contract all directions toward lowPt for (int col=0;col<numCol;col++) { if (col != ilo) { for (int row=0;row<numRow;row++) { rowSum[row]=0.5*(simplex[row+col*numRow]+simplex[row+ilo*numRow]); simplex[row+col*numRow]=rowSum[row]; } height[col] = evaluate(&rowSum[0], pd, err); if( mNonGradDebug >= 3 ) { std::cout << "Contract all directions toward lowPt value( " << col << " ) = " << height[col] << " ilo = " << ilo << std::endl; } //MSQ_PRINT(3)("Contract all directions toward lowPt value( %d ) = %e ilo = %d\n", col, height[col], ilo); } } } } } // ytri > h(ilo) } // after evaluation ilo=1; // conditional operator or inline if ihi = height[0] > height[1] ? (inhi=1,0) : (inhi=0,1); for (int col=0;col<numCol;col++) { if (height[col] <= height[ilo]) { ilo=col; // ilo := argmin height } if (height[col] > height[ihi]) { inhi=ihi; ihi=col; } else // height[ihi] >= height[col] if (col != ihi && height[col] > height[inhi] ) inhi=col; } // rtol=2.0*fabs( height[ihi]-height[ilo] )/ // ( fabs(height[ihi])+fabs(height[ilo])+threshold ); afterEvaluation = true; } // while not converged // Always set to current best mesh. { if( ilo != 0 ) { double yTemp = height[0]; height[0] = height[ilo]; // height dimension numCol height[ilo] = yTemp; for (int row=1;row<numRow;row++) { yTemp = simplex[row]; simplex[row] = simplex[row+ilo*numRow]; simplex[row+ilo*numRow] = yTemp; } } } if( pd.num_free_vertices() > 1 ) { MSQ_SETERR(err)("Only one free vertex per patch implemented", MsqError::NOT_IMPLEMENTED); } Vector3D newPoint( &simplex[0] ); size_t vertexIndex = 0; // fix c.f. freeVertexIndex pd.set_vertex_coordinates( newPoint, vertexIndex, err ); pd.snap_vertex_to_domain( vertexIndex, err ); if( term_crit->terminate() ) { if( mNonGradDebug >= 1 ) { std::cout << "Optimization Termination OptStatus: Max Iter Exceeded" << std::endl; } //MSQ_PRINT(1)("Optimization Termination OptStatus: Max Iter Exceeded\n"); } }
/*! \fn MeshSet::get_next_patch(PatchData &pd, MsqError &err ) \brief This function fills up a PatchData object with the mesh information necessary for optimization algorithms. The return value is true as long there exists a next patch, false otherwise. The list culling is performed in this function. This function is a friend of the PatchData class. Therefore the PatchData object passed as an argument is filled up directly. \param PatchData &pd: this is the PatchData object that will be filled up. */ bool MeshSet::get_next_patch(PatchData &pd, PatchDataParameters &pd_params, MsqError &err ) { MSQ_FUNCTION_TIMER( "MeshSet::get_next_patch" ); // get rid of previous Patch information (but keep memory allocated). pd.clear(); // Mark this MeshSet as the originator pd.meshSet = this; pd.domainSet = (mDomain != NULL); bool result = false; switch (pd_params.get_patch_type()) { case PatchData::ELEMENTS_ON_VERTEX_PATCH: result = get_next_elem_on_vert_patch( pd, pd_params, err ); break; case PatchData::GLOBAL_PATCH: result = get_next_global_patch( pd, pd_params, err ); break; default: MSQ_SETERR(err)( "no implementation for specified patch type.", MsqError::NOT_IMPLEMENTED ); result = false; break; } return !MSQ_CHKERR(err) && result; }
/*! */ void I_DFT_NoBarrierSmoother::optimize_vertex_positions(PatchData &pd, MsqError &err) { MSQ_FUNCTION_TIMER( "I_DFT_NoBarrierSmoother::optimize_vertex_positions" ); // does the I_DFT_NoBarrier smoothing MsqFreeVertexIndexIterator free_iter(pd, err); MSQ_ERRRTN(err); free_iter.reset(); free_iter.next(); //m is the free vertex. size_t m=free_iter.value(); //move vertex m i_dft_no_barrier_smooth_mesh(pd, m, err); MSQ_ERRRTN(err); //snap vertex m to domain pd.snap_vertex_to_domain(m,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()); } }
/*! \brief creates a sparse structure for a Hessian, based on the connectivity information contained in the PatchData. Only the upper triangular part of the Hessian is stored. */ void MsqHessian::initialize(PatchData &pd, MsqError &err) { MSQ_FUNCTION_TIMER( "MsqHession::initialize" ); delete[] mEntries; delete[] mRowStart; delete[] mColIndex; size_t num_vertices = pd.num_free_vertices(); size_t num_elements = pd.num_elements(); size_t const * vtx_list; size_t e, r, rs, re, c, cs, ce, nz, nnz, nve, i, j; MsqMeshEntity* patchElemArray = pd.get_element_array(err); MSQ_CHKERR(err); if (num_vertices == 0) { MSQ_SETERR( err )( "No vertices in PatchData", MsqError::INVALID_ARG); return; } mSize = num_vertices; // Calculate the offsets for a CSC representation of the accumulation // pattern. size_t* col_start = new size_t[num_vertices + 1]; //mAccumElemStart = new size_t[num_elements+1]; //mAccumElemStart[0] = 0; for (i = 0; i < num_vertices; ++i) { col_start[i] = 0; } for (e = 0; e < num_elements; ++e) { nve = patchElemArray[e].node_count(); vtx_list = patchElemArray[e].get_vertex_index_array(); int nfe = 0; for (i = 0; i < nve; ++i) { r = vtx_list[i]; if (r < num_vertices) ++nfe; for (j = i; j < nve; ++j) { c = vtx_list[j]; if (r <= c) { if (c < num_vertices) ++col_start[c]; } else { if (r < num_vertices) ++col_start[r]; } } } //mAccumElemStart[e+1] = mAccumElemStart[e] + (nfe+1)*nfe/2; } nz = 0; for (i = 0; i < num_vertices; ++i) { j = col_start[i]; col_start[i] = nz; nz += j; } col_start[i] = nz; // Finished putting matrix into CSC representation int* row_instr = new int[5*nz]; size_t* row_index = new size_t[nz]; nz = 0; for (e = 0; e < num_elements; ++e) { nve = patchElemArray[e].node_count(); vtx_list = patchElemArray[e].get_vertex_index_array(); for (i = 0; i < nve; ++i) { r = vtx_list[i]; for (j = i; j < nve; ++j) { c = vtx_list[j]; if (r <= c) { if (c < num_vertices) { row_index[col_start[c]] = r; row_instr[col_start[c]] = nz++; ++col_start[c]; } } else { if (r < num_vertices) { row_index[col_start[r]] = c; //can't use -nz, but can negate row_instr[col_start[r]] row_instr[col_start[r]] = nz++; row_instr[col_start[r]] = -row_instr[col_start[r]]; ++col_start[r]; } } } } } for (i = num_vertices-1; i > 0; --i) { col_start[i+1] = col_start[i]; } col_start[1] = col_start[0]; col_start[0] = 0; // cout << "col_start: "; // for (int t=0; t<num_vertices+1; ++t) // cout << col_start[t] << " "; // cout << endl; // cout << "row_index: "; // for (int t=0; t<nz; ++t) // cout << row_index[t] << " "; // cout << endl; // cout << "row_instr: "; // for (int t=0; t<nz; ++t) // cout << row_instr[t] << " "; // cout << endl; // Convert CSC to CSR // First calculate the offsets in the row size_t* row_start = new size_t[num_vertices + 1]; for (i = 0; i < num_vertices; ++i) { row_start[i] = 0; } for (i = 0; i < nz; ++i) { ++row_start[row_index[i]]; } nz = 0; for (i = 0; i < num_vertices; ++i) { j = row_start[i]; row_start[i] = nz; nz += j; } row_start[i] = nz; // Now calculate the pattern size_t* col_index = new size_t[nz]; int* col_instr = new int[nz]; for (i = 0; i < num_vertices; ++i) { cs = col_start[i]; ce = col_start[i+1]; while(cs < ce) { r = row_index[cs]; col_index[row_start[r]] = i; col_instr[row_start[r]] = row_instr[cs]; ++row_start[r]; ++cs; } } for (i = num_vertices-1; i > 0; --i) { row_start[i+1] = row_start[i]; } row_start[1] = row_start[0]; row_start[0] = 0; delete[] row_index; // Now that the matrix is CSR // Column indices for each row are sorted // Compaction -- count the number of nonzeros mRowStart = col_start; // don't need to reallocate //mAccumulation = row_instr; // don't need to reallocate delete [] row_instr; for (i = 0; i <= num_vertices; ++i) { mRowStart[i] = 0; } nnz = 0; for (i = 0; i < num_vertices; ++i) { rs = row_start[i]; re = row_start[i+1]; c = num_vertices; while(rs < re) { if (c != col_index[rs]) { // This is an unseen nonzero c = col_index[rs]; ++mRowStart[i]; ++nnz; } //if (col_instr[rs] >= 0) { // mAccumulation[col_instr[rs]] = nnz - 1; //} //else { // mAccumulation[-col_instr[rs]] = 1 - nnz; //} ++rs; } } nnz = 0; for (i = 0; i < num_vertices; ++i) { j = mRowStart[i]; mRowStart[i] = nnz; nnz += j; } mRowStart[i] = nnz; delete [] col_instr; // Fill in the compacted hessian matrix mColIndex = new size_t[nnz]; for (i = 0; i < num_vertices; ++i) { rs = row_start[i]; re = row_start[i+1]; c = num_vertices; while(rs < re) { if (c != col_index[rs]) { // This is an unseen nonzero c = col_index[rs]; mColIndex[mRowStart[i]] = c; mRowStart[i]++; } ++rs; } } for (i = num_vertices-1; i > 0; --i) { mRowStart[i+1] = mRowStart[i]; } mRowStart[1] = mRowStart[0]; mRowStart[0] = 0; delete [] row_start; delete [] col_index; mEntries = new Matrix3D[nnz]; // On Solaris, no initializer allowed for new of an array for (i=0;i<nnz;++i) mEntries[i] = 0.; // so we initialize all entries manually. //origin_pd = &pd; return; }
/*! uses the preconditionned conjugate gradient algebraic solver to find d in \f$ H * d = -g \f$ . \param x : the solution, usually the descent direction d. \param b : -b will be the right hand side. Usually b is the gradient. */ void MsqHessian::cg_solver(Vector3D x[], Vector3D b[], MsqError &err) { MSQ_FUNCTION_TIMER( "MsqHessian::cg_solver" ); // reallocates arrays if size of the Hessian has changed too much. if (mSize > cgArraySizes || mSize < cgArraySizes/10 ) { delete[] mR; delete[] mZ; delete[] mP; delete[] mW; mR = new Vector3D[mSize]; mZ = new Vector3D[mSize]; mP = new Vector3D[mSize]; mW = new Vector3D[mSize]; cgArraySizes = mSize; } size_t i; double alpha_, alpha, beta; double cg_tol = 1e-2; // 1e-2 will give a reasonably good solution (~1%). double norm_g = length(b, mSize); double norm_r = norm_g; double rzm1; // r^T_{k-1} z_{k-1} double rzm2; // r^T_{k-2} z_{k-2} this->compute_preconditioner(err); MSQ_CHKERR(err); // get M^{-1} for diagonal blocks for (i=0; i<mSize; ++i) x[i] = 0. ; for (i=0; i<mSize; ++i) mR[i] = -b[i] ; // r = -b because x_0 = 0 and we solve H*x = -b norm_g *= cg_tol; this->apply_preconditioner(mZ, mR, err); // solve Mz = r (computes z = M^-1 r) for (i=0; i<mSize; ++i) mP[i] = mZ[i] ; // p_1 = z_0 rzm1 = inner(mZ,mR,mSize); // inner product r_{k-1}^T z_{k-1} size_t cg_iter = 0; while ((norm_r > norm_g) && (cg_iter < maxCGiter)) { ++cg_iter; axpy(mW, mSize, *this, mP, mSize, 0,0,err); // w = A * p_k alpha_ = inner(mP,mW,mSize); // alpha_ = p_k^T A p_k if (alpha_ <= 0.0) { if (1 == cg_iter) { for (i=0; i<mSize; ++i) x[i] += mP[i]; // x_{k+1} = x_k + p_{k+1} } break; // Newton goes on with this direction of negative curvature } alpha = rzm1 / alpha_; for (i=0; i<mSize; ++i) x[i] += alpha*mP[i]; // x_{k+1} = x_k + alpha_{k+1} p_{k+1} for (i=0; i<mSize; ++i) mR[i] -= alpha*mW[i]; // r_{k+1} = r_k - alpha_{k+1} A p_{k+1} norm_r = length(mR, mSize); this->apply_preconditioner(mZ, mR, err); // solve Mz = r (computes z = M^-1 r) rzm2 = rzm1; rzm1 = inner(mZ,mR,mSize); // inner product r_{k-1}^T z_{k-1} beta = rzm1 / rzm2; for (i=0; i<mSize; ++i) mP[i] = mZ[i] + beta*mP[i]; // p_k = z_{k-1} + Beta_k * p_{k-1} } }
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; } }
// Currently, the only thing supported is updating each vertices // coordinates and flags. Connectivity changes aren't supported yet. void Mesquite::MeshSet::update_mesh(const PatchData &pd, MsqError &err) { MSQ_FUNCTION_TIMER( "MeshSet::update_mesh" ); if (pd.num_nodes() == 0) return; size_t i; switch (pd.type()) { // If the patch type is marked as local, // all handles belong to the currentMesh. case PatchData::ELEMENTS_ON_VERTEX_PATCH: // For each vertex, update the coordinates // and the "mesquite byte". for (i = 0; i < pd.num_nodes(); i++) { if(!pd.vertexArray[i].is_flag_set( MsqVertex::MSQ_HARD_FIXED)) { (*currentMesh)->vertex_set_coordinates(pd.vertexHandlesArray[i], pd.vertexArray[i], err); MSQ_ERRRTN(err); } (*currentMesh)->vertex_set_byte(pd.vertexHandlesArray[i], pd.vertexArray[i].vertexBitFlags, err); MSQ_ERRRTN(err); } break; // If the patch type is marked as global, // the handles may belong to more than // one Mesh. case PatchData::GLOBAL_PATCH: { list<Mesquite::Mesh*>::iterator mesh_itr = meshSet.begin(); assert( mesh_itr != meshSet.end() ); Mesquite::Mesh* cur_mesh = *mesh_itr; Mesquite::VertexIterator *vert_itr = cur_mesh->vertex_iterator(err); MSQ_ERRRTN(err); for (i = 0; i < pd.num_nodes(); i++) { if (vert_itr->is_at_end()) { mesh_itr++; if ( mesh_itr==meshSet.end() ) return; cur_mesh = *mesh_itr; delete vert_itr; vert_itr = cur_mesh->vertex_iterator(err); MSQ_ERRRTN(err); } if(!pd.vertexArray[i].is_flag_set( MsqVertex::MSQ_HARD_FIXED)) { cur_mesh->vertex_set_coordinates(pd.vertexHandlesArray[i], pd.vertexArray[i], err); MSQ_ERRRTN(err); } cur_mesh->vertex_set_byte(pd.vertexHandlesArray[i], pd.vertexArray[i].vertexBitFlags, err); MSQ_ERRRTN(err); } delete vert_itr; } break; default: { MSQ_SETERR(err)("PatchData Type not accepted yet.", MsqError::NOT_IMPLEMENTED); break; } } }