bool MAST::NonlinearImplicitAssembly:: sensitivity_assemble (const libMesh::ParameterVector& parameters, const unsigned int i, libMesh::NumericVector<Real>& sensitivity_rhs) { libMesh::NonlinearImplicitSystem& nonlin_sys = dynamic_cast<libMesh::NonlinearImplicitSystem&>(_system->system()); sensitivity_rhs.zero(); // iterate over each element, initialize it and get the relevant // analysis quantities RealVectorX vec, sol; RealMatrixX mat; std::vector<libMesh::dof_id_type> dof_indices; const libMesh::DofMap& dof_map = nonlin_sys.get_dof_map(); std::auto_ptr<MAST::ElementBase> physics_elem; std::auto_ptr<libMesh::NumericVector<Real> > localized_solution; localized_solution.reset(_build_localized_vector(nonlin_sys, *nonlin_sys.solution).release()); // if a solution function is attached, initialize it if (_sol_function) _sol_function->init_for_system_and_solution(*_system, *nonlin_sys.solution); libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); for ( ; el != end_el; ++el) { const libMesh::Elem* elem = *el; dof_map.dof_indices (elem, dof_indices); physics_elem.reset(_build_elem(*elem).release()); // get the solution unsigned int ndofs = (unsigned int)dof_indices.size(); sol.setZero(ndofs); vec.setZero(ndofs); mat.setZero(ndofs, ndofs); for (unsigned int i=0; i<dof_indices.size(); i++) sol(i) = (*localized_solution)(dof_indices[i]); physics_elem->sensitivity_param = _discipline->get_parameter(parameters[i]); physics_elem->set_solution(sol); if (_sol_function) physics_elem->attach_active_solution_function(*_sol_function); // perform the element level calculations _elem_sensitivity_calculations(*physics_elem, vec); physics_elem->detach_active_solution_function(); // copy to the libMesh matrix for further processing DenseRealVector v; MAST::copy(v, vec); // constrain the quantities to account for hanging dofs, // Dirichlet constraints, etc. nonlin_sys.get_dof_map().constrain_element_vector(v, dof_indices); // add to the global matrices sensitivity_rhs.add_vector(v, dof_indices); } // if a solution function is attached, initialize it if (_sol_function) _sol_function->clear(); sensitivity_rhs.close(); return true; }
void MAST::LevelSetReinitializationTransientAssembly:: residual_and_jacobian (const libMesh::NumericVector<Real>& X, libMesh::NumericVector<Real>* R, libMesh::SparseMatrix<Real>* J, libMesh::NonlinearImplicitSystem& S) { libmesh_assert(_system); libmesh_assert(_discipline); libmesh_assert(_elem_ops); MAST::TransientSolverBase &solver = dynamic_cast<MAST::TransientSolverBase&>(*_elem_ops); MAST::NonlinearSystem &transient_sys = _system->system(); MAST::LevelSetTransientAssemblyElemOperations &level_set_elem_ops = dynamic_cast<MAST::LevelSetTransientAssemblyElemOperations&> (solver.get_elem_operation_object()); // make sure that the system for which this object was created, // and the system passed through the function call are the same libmesh_assert_equal_to(&S, &transient_sys); if (R) R->zero(); if (J) J->zero(); // iterate over each element, initialize it and get the relevant // analysis quantities RealVectorX vec, ref_sol; RealMatrixX mat; std::vector<libMesh::dof_id_type> dof_indices; const libMesh::DofMap& dof_map = transient_sys.get_dof_map(); // stores the localized solution, velocity, acceleration, etc. vectors. // These pointers will have to be deleted std::vector<libMesh::NumericVector<Real>*> local_qtys; std::unique_ptr<libMesh::NumericVector<Real> > localized_solution; localized_solution.reset(build_localized_vector(transient_sys, *_ref_sol).release()); // if a solution function is attached, initialize it if (_sol_function) _sol_function->init( X); // ask the solver to localize the relevant solutions solver.build_local_quantities(X, local_qtys); libMesh::MeshBase::const_element_iterator el = transient_sys.get_mesh().active_local_elements_begin(); const libMesh::MeshBase::const_element_iterator end_el = transient_sys.get_mesh().active_local_elements_end(); for ( ; el != end_el; ++el) { const libMesh::Elem* elem = *el; dof_map.dof_indices (elem, dof_indices); solver.init(*elem); // get the solution unsigned int ndofs = (unsigned int)dof_indices.size(); vec.setZero(ndofs); ref_sol.setZero(ndofs); mat.setZero(ndofs, ndofs); for (unsigned int i=0; i<dof_indices.size(); i++) ref_sol(i) = (*localized_solution)(dof_indices[i]); solver.set_element_data(dof_indices, local_qtys); level_set_elem_ops.set_elem_reference_solution(ref_sol); // if (_sol_function) // physics_elem->attach_active_solution_function(*_sol_function); // perform the element level calculations solver.elem_calculations(J!=nullptr?true:false, vec, mat); solver.clear_elem(); // copy to the libMesh matrix for further processing DenseRealVector v; DenseRealMatrix m; if (R) MAST::copy(v, vec); if (J) MAST::copy(m, mat); // constrain the quantities to account for hanging dofs, // Dirichlet constraints, etc. if (R && J) dof_map.constrain_element_matrix_and_vector(m, v, dof_indices); else if (R) dof_map.constrain_element_vector(v, dof_indices); else dof_map.constrain_element_matrix(m, dof_indices); // add to the global matrices if (R) R->add_vector(v, dof_indices); if (J) J->add_matrix(m, dof_indices); } // delete pointers to the local solutions for (unsigned int i=0; i<local_qtys.size(); i++) delete local_qtys[i]; // if a solution function is attached, clear it if (_sol_function) _sol_function->clear(); if (R) R->close(); if (J) J->close(); }
void MAST::NonlinearImplicitAssembly:: residual_and_jacobian (const libMesh::NumericVector<Real>& X, libMesh::NumericVector<Real>* R, libMesh::SparseMatrix<Real>* J, libMesh::NonlinearImplicitSystem& S) { libMesh::NonlinearImplicitSystem& nonlin_sys = dynamic_cast<libMesh::NonlinearImplicitSystem&>(_system->system()); // make sure that the system for which this object was created, // and the system passed through the function call are the same libmesh_assert_equal_to(&S, &(nonlin_sys)); if (R) R->zero(); if (J) J->zero(); // iterate over each element, initialize it and get the relevant // analysis quantities RealVectorX vec, sol; RealMatrixX mat; std::vector<libMesh::dof_id_type> dof_indices; const libMesh::DofMap& dof_map = _system->system().get_dof_map(); std::auto_ptr<MAST::ElementBase> physics_elem; std::auto_ptr<libMesh::NumericVector<Real> > localized_solution; localized_solution.reset(_build_localized_vector(nonlin_sys, X).release()); // if a solution function is attached, initialize it if (_sol_function) _sol_function->init_for_system_and_solution(*_system, X); libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); for ( ; el != end_el; ++el) { const libMesh::Elem* elem = *el; dof_map.dof_indices (elem, dof_indices); physics_elem.reset(_build_elem(*elem).release()); // get the solution unsigned int ndofs = (unsigned int)dof_indices.size(); sol.setZero(ndofs); vec.setZero(ndofs); mat.setZero(ndofs, ndofs); for (unsigned int i=0; i<dof_indices.size(); i++) sol(i) = (*localized_solution)(dof_indices[i]); physics_elem->set_solution(sol); if (_sol_function) physics_elem->attach_active_solution_function(*_sol_function); //_check_element_numerical_jacobian(*physics_elem, sol); // perform the element level calculations _elem_calculations(*physics_elem, J!=NULL?true:false, vec, mat); physics_elem->detach_active_solution_function(); // copy to the libMesh matrix for further processing DenseRealVector v; DenseRealMatrix m; if (R) MAST::copy(v, vec); if (J) MAST::copy(m, mat); // constrain the quantities to account for hanging dofs, // Dirichlet constraints, etc. if (R && J) nonlin_sys.get_dof_map().constrain_element_matrix_and_vector(m, v, dof_indices); else if (R) nonlin_sys.get_dof_map().constrain_element_vector(v, dof_indices); else nonlin_sys.get_dof_map().constrain_element_matrix(m, dof_indices); // add to the global matrices if (R) R->add_vector(v, dof_indices); if (J) J->add_matrix(m, dof_indices); } // if a solution function is attached, clear it if (_sol_function) _sol_function->clear(); if (R) R->close(); if (J) J->close(); }
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; }