void MAST::NoniterativeUGFlutterSolver::calculate_sensitivity(MAST::FlutterRootBase& root, const libMesh::ParameterVector& params, const unsigned int i) { // make sure that the aero_structural_model is a valid pointer libmesh_assert(aero_structural_model); libMesh::out << " ====================================================" << std::endl << "UG Sensitivity Solution" << std::endl << " k_red = " << std::setw(10) << root.k_red << std::endl << " V_ref = " << std::setw(10) << root.V << std::endl; Complex eig = root.root, sens = 0., k_sens = 0., vref_sens = 0., den = 0.; // matrix to store the sensitivity of constraint wrt kref and vref // first row is constraint f1(k,v) = g = im(lambda)/re(lambda) = 0 // second row is constraint f2(k,v) = vref*sqrt(re(lambda))-1. = 0 RealMatrixX jac; // residual vector for the sensitivity problem, and total derivative vec // first row is for constraint f1(k,v) // first row is for constraint f2(k,v) RealVectorX res, dsens; jac.setZero(2,2); res.setZero(2); // get the sensitivity of the matrices ComplexMatrixX mat_A, mat_B, mat_A_sens, mat_B_sens; ComplexVectorX v; // initialize the baseline matrices initialize_matrices(root.k_red_ref, root.V_ref, mat_A, mat_B); // calculate the eigenproblem sensitivity initialize_matrix_sensitivity_for_param(params, i, root.k_red_ref, root.V_ref, mat_A_sens, mat_B_sens); // the eigenproblem is A x - lambda B x = 0 // therefore, the denominator is obtained from the inner product of // x^T B x // sensitivity is // -dlambda/dp x^T B x = - x^T (dA/dp - lambda dB/dp) // or // dlambda/dp = [x^T (dA/dp - lambda dB/dp)]/(x^T B x) // now calculate the quotient for sensitivity // numerator = ( dA/dp - lambda dB/dp) mat_B_sens *= -eig; mat_B_sens += mat_A_sens; v = mat_B_sens*root.eig_vec_right; den = root.eig_vec_left.dot(mat_B*root.eig_vec_right); sens = root.eig_vec_left.dot(v)/den; // sensitivity of f1(k,v) = im(lambda)/re(lambda) = 0 res(0) = sens.imag()/eig.real() - eig.imag()/pow(eig.real(),2) * sens.real(); // sensitivity of f2(k,v) = vref*sqrt(real(lambda)) - 1 = 0 res(1) = root.V_ref*0.5*pow(eig.real(),-0.5)*sens.real(); // next we need the sensitivity of k_red before we can calculate // the sensitivity of flutter eigenvalue initialize_matrix_sensitivity_for_reduced_freq(root.k_red_ref, root.V_ref, mat_A_sens, mat_B_sens); // now calculate the quotient for sensitivity wrt k_red // calculate numerator mat_B_sens *= -eig; mat_B_sens += mat_A_sens; v = mat_B_sens*root.eig_vec_right; k_sens = root.eig_vec_left.dot(v) / den; // use this to calculate the partial derivative of f1 wrt k_red jac(0,0) = k_sens.imag()/eig.real() - eig.imag()/pow(eig.real(),2)*k_sens.real(); jac(1,0) = root.V_ref*0.5*pow(eig.real(),-0.5)*k_sens.real(); // next we need the sensitivity of Vref constraint before we can calculate // the sensitivity of flutter eigenvalue initialize_matrix_sensitivity_for_V_ref(root.k_red_ref, root.V_ref, mat_A_sens, mat_B_sens); // now calculate the quotient for sensitivity wrt k_red // calculate numerator mat_B_sens *= -eig; mat_B_sens += mat_A_sens; v = mat_B_sens*root.eig_vec_right; vref_sens = root.eig_vec_left.dot(v) / den; // use this to calculate the partial derivative of f2 wrt vref jac(0,1) = vref_sens.imag()/eig.real() - eig.imag()/pow(eig.real(),2)*vref_sens.real(); jac(1,1) = sqrt(eig.real()) + root.V_ref*0.5*pow(eig.real(),-0.5)*vref_sens.real(); // now invert the Jacobian to calculate the sensitivity dsens = -jac.inverse()*res; // finally add the correction to the flutter sensitivity sens += k_sens * dsens(0) + vref_sens * dsens(1); // set value in the return root root.has_sensitivity_data = true; root.root_sens = sens; root.V_sens = -.5*sens.real()/pow(eig.real(), 1.5); libMesh::out << "Finished UG Sensitivity Solution" << std::endl << " ====================================================" << std::endl; }
std::pair<bool, MAST::FlutterSolutionBase*> MAST::NoniterativeUGFlutterSolver::newton_search(const MAST::FlutterSolutionBase& init_sol, const unsigned int root_num, const Real tol, const unsigned int max_iters) { std::pair<bool, MAST::FlutterSolutionBase*> rval(false, NULL); // assumes that the upper k_val has +ve g val and lower k_val has -ve // k_val Real k_red, v_ref; unsigned int n_iters = 0; std::auto_ptr<MAST::FlutterSolutionBase> new_sol; RealVectorX res, sol, dsol; RealMatrixX jac; ComplexMatrixX mat_A, mat_B, mat_A_sens, mat_B_sens; ComplexVectorX v; res.resize(2); sol.resize(2); dsol.resize(2); jac.resize(2,2); // initialize the solution to the values of init_sol k_red = init_sol.get_root(root_num).k_red_ref; v_ref = init_sol.get_root(root_num).V_ref; sol(0) = k_red; sol(1) = v_ref; const MAST::FlutterSolutionBase* prev_sol = &init_sol; bool if_continue = true; while (if_continue) { // evaluate the residual and Jacobians std::auto_ptr<MAST::FlutterSolutionBase> ug_sol = this->analyze(k_red, v_ref, prev_sol); ug_sol->print(_output); // add the solution to this solver _insert_new_solution(v_ref, ug_sol.release()); // now get a pointer to the previous solution // get the solution from the database for this reduced frequency std::map<Real, MAST::FlutterSolutionBase*>::iterator it = _flutter_solutions.find(k_red); libmesh_assert(it != _flutter_solutions.end()); rval.second = it->second; prev_sol = it->second; // solve the Newton update problem const MAST::FlutterRootBase& root = prev_sol->get_root(root_num); Complex eig = root.root, eig_k_red_sens = 0., den = 0., eig_V_ref_sens = 0.; // initialize the baseline matrices initialize_matrices(k_red, v_ref, mat_A, mat_B); // solve the sensitivity problem // first with respect to k_red // next we need the sensitivity of k_red before we can calculate // the sensitivity of flutter eigenvalue initialize_matrix_sensitivity_for_reduced_freq(k_red, v_ref, mat_A_sens, mat_B_sens); // now calculate the quotient for sensitivity wrt k_red // calculate numerator mat_B_sens *= -eig; mat_B_sens += mat_A_sens; v = mat_B_sens*root.eig_vec_right; den = root.eig_vec_left.dot(mat_B*root.eig_vec_right); eig_k_red_sens = root.eig_vec_left.dot(v) / den; // next, sensitivity wrt V_ref initialize_matrix_sensitivity_for_V_ref(k_red, v_ref, mat_A_sens, mat_B_sens); // now calculate the quotient for sensitivity wrt V_ref // calculate numerator mat_B_sens *= -eig; mat_B_sens += mat_A_sens; v = mat_B_sens*root.eig_vec_right; den = root.eig_vec_left.dot(mat_B*root.eig_vec_right); eig_V_ref_sens = root.eig_vec_left.dot(v) / den; // residual res(0) = eig.imag()/eig.real(); res(1) = v_ref*sqrt(eig.real()) - 1.; // Jacobian jac(0,0) = eig_k_red_sens.imag()/eig.real() - eig.imag()*pow(eig.real(),-2)*eig_k_red_sens.real(); jac(0,1) = eig_V_ref_sens.imag()/eig.real() - eig.imag()*pow(eig.real(),-2)*eig_V_ref_sens.real(); jac(1,0) = 0.5*v_ref*pow(eig.real(),-0.5)*eig_k_red_sens.real(); jac(1,1) = sqrt(eig.real()) + 0.5*v_ref*pow(eig.real(),-0.5)*eig_V_ref_sens.real(); /*std::auto_ptr<MAST::FlutterSolutionBase> ug_dsol = this->analyze(k_red+.001, v_ref, prev_sol); Complex deig = ug_dsol->get_root(root_num).root; deig -= eig; deig /= .001; std::cout << "fd deig/dk: " << deig << std::endl; std::cout << "analytical: " << eig_k_red_sens << std::endl; ug_dsol.reset(this->analyze(k_red, v_ref+.001, prev_sol).release()); deig = ug_dsol->get_root(root_num).root; deig -= eig; deig /= .001; std::cout << "fd deig/dV: " << deig << std::endl; std::cout << "analytical: " << eig_V_ref_sens << std::endl;*/ // now calculate the updates // r0 + J *dx = 0 // => dx = - inv(J) * r0 // => x1 = x0 + dx dsol = -jac.inverse()*res; sol += dsol; // get the updated parameter values k_red = sol(0); v_ref = sol(1); // increment the iteration counter n_iters++; // set the flag if (fabs(root.g) < tol) { rval.first = true; return rval; } if (n_iters >= max_iters) if_continue = false; } // return false, along with the latest sol rval.first = false; return rval; }