Real Compute_dObjdQ_dQdBeta(Real* dQdB, SolutionSpace<Real>& space) { RCmplx perturb (0.0, 1.0e-11); RCmplx Obj; EqnSet<Real>* eqnset = space.eqnset; Mesh<Real>* m = space.m; Param<Real>* param = space.param; BoundaryConditions<Real>* bc = space.bc; SolutionSpace<RCmplx> cspace(space); Mesh<RCmplx>* cm = cspace.m; PObj<RCmplx>* cp = cspace.p; EqnSet<RCmplx>* ceqnset = cspace.eqnset; Int cnnode = cm->GetNumNodes(); Real dObjdBeta; Int i, j; Int neqn = eqnset->neqn; Int nauxvars = eqnset->nauxvars; //replace all Q values in mesh by dQdB*perturb and compute cost function for(i = 0; i < cnnode; i++){ for(j = 0; j < neqn; j++){ cspace.q[i*(neqn+nauxvars) + j] += dQdB[i*neqn + j]*perturb; } ceqnset->ComputeAuxiliaryVariables(&cspace.q[i*(neqn+nauxvars)]); } cp->UpdateGeneralVectors(cspace.q, neqn+nauxvars); UpdateBCs(&cspace); cp->UpdateGeneralVectors(cspace.q, neqn+nauxvars); ComputeSurfaceAreas(&cspace, 0); Obj = Compute_Obj_Function(cspace); dObjdBeta = imag(Obj)/imag(perturb); return dObjdBeta; }
void Compute_dObjdQ(Real* dIdQ, SolutionSpace<Real>& space) { RCmplx perturb (0.0, 1.0e-11); Int i, j; EqnSet<Real>* eqnset = space.eqnset; Mesh<Real>* rm = space.m; Param<Real>* param = space.param; BoundaryConditions<Real>* bc = space.bc; Int node; Int nnode = rm->GetNumNodes(); Int gnode = rm->GetNumParallelNodes(); Int nbnode = rm->GetNumBoundaryNodes(); Int neqn = eqnset->neqn; Int nvars = neqn + eqnset->nauxvars; MPI_Datatype mpit = MPI_GetType(nnode); //get global number of nodes since processes need to be synced //build lookup maps from local to global id Int* globalToLocal; Int* localToGlobal; Int globalNodes = space.p->BuildGlobalMaps(&localToGlobal, &globalToLocal); RCmplx Obj; std::cout << "\n\nCOMPUTING dI/dQ\n\n" << std::endl; SolutionSpace<RCmplx> cspace(space); Mesh<RCmplx>* cm = cspace.m; PObj<RCmplx>* cp = cspace.p; EqnSet<RCmplx>* ceqnset = cspace.eqnset; //init dIdQ MemBlank(dIdQ, neqn*nnode); //compute surface areas once to ensure they are valid ComputeSurfaceAreas(&cspace, 0); for(i = 0; i < globalNodes; i++){ node = globalToLocal[i]; for(j = 0; j < neqn; j++){ //perturb q value if node is local to process if(node >= 0){ cspace.q[node*nvars + j] += perturb; ceqnset->ComputeAuxiliaryVariables(&cspace.q[node*nvars + 0]); } //compute perturbed objective function //no need for a call to compute_surface_areas here since we aren't changing them cp->UpdateGeneralVectors(cspace.q, nvars); Obj = Compute_Obj_Function(cspace); if(node >= 0){ if(node < nnode){ dIdQ[node*neqn + j] = imag(Obj) / imag(perturb); } //reset q value cspace.q[node*nvars + j] = space.q[node*nvars + j]; //compute aux vars one last time for all values reset to original ceqnset->ComputeAuxiliaryVariables(&cspace.q[node*nvars + 0]); } } } delete [] localToGlobal; delete [] globalToLocal; return; }
void Compute_dRdQ_Product_MatrixFree(SolutionSpace<RCmplx>& cspace, Real* vector, Real* prod) { RCmplx perturb(0.0, 1.0e-11); Mesh<RCmplx>* cm = cspace.m; Param<RCmplx>* param = cspace.param; EqnSet<RCmplx>* ceqnset = cspace.eqnset; RCmplx* q = cspace.q; PObj<RCmplx>* p = cspace.p; Int cnnode = cm->GetNumNodes(); Int cgnode = cm->GetNumParallelNodes(); Int cnbnode = cm->GetNumBoundaryNodes(); Int neqn = ceqnset->neqn; Int nvars = ceqnset->nauxvars + neqn; for(Int i = 0; i < cnnode; i++){ RCmplx* iq = &q[i*nvars + 0]; for(Int j = 0; j < neqn; j++){ iq[j] += vector[i*neqn + j]*perturb; } ceqnset->ComputeAuxiliaryVariables(iq); } p->UpdateGeneralVectors(q, nvars); //the gaussian source is sometimes used to modify boundary velocities, etc. //pre-compute it for bc call if(cspace.param->gaussianSource){ cspace.gaussian->ApplyToResidual(); } UpdateBCs(&cspace); p->UpdateGeneralVectors(q, nvars); //now, compute gradients and limiters if(param->sorder > 1 || param->viscous){ for(Int i = 0; i < (cnnode+cnbnode+cgnode); i++){ ceqnset->NativeToExtrapolated(&q[i*nvars]); } cspace.grad->Compute(); cspace.limiter->Compute(&cspace); for(Int i = 0; i < (cnnode+cnbnode+cgnode); i++){ ceqnset->ExtrapolatedToNative(&q[i*nvars]); } } //it is assumed that this routine is going to be called iteratively, //therefore, calling the turbulence model here, will slowly converge the //turbulence model towards the correct sensitivity //This should theoretically be converged here at every call to this routine, //but that is horribly costly.... so we cheat //WARNING: ---- for now, we assume frozen turbulence models if(param->viscous && false){ cspace.turb->Compute(); if(param->gcl){ std::cout << "MATRIX FREE: COMPUTE GCL FOR TURB MODEL!" << std::endl; } } //Now compute residual, this only works for spatial residual right now SpatialResidual(&cspace); ExtraSourceResidual(&cspace); //Now do the CTSE derivative part for(Int i = 0; i < cnnode; i++){ for(Int j = 0; j < neqn; j++){ prod[i*neqn + j] = imag(cspace.crs->b[i*neqn + j])/imag(perturb); } } //re-zero the complex part of the q vector in case we reuse the cspace for(Int i = 0; i < cnnode; i++){ RCmplx* iq = &q[i*nvars + 0]; for(Int j = 0; j < neqn; j++){ iq[j] = real(iq[j]); } ceqnset->ComputeAuxiliaryVariables(iq); } p->UpdateGeneralVectors(q, nvars); return; }