void Get_dXdB(std::string path, Real* dxdb, Mesh<Real>* m, Int beta) { std::ifstream fin; std::stringstream ss; Int i, b; PObj<Real>* p = m->p; Int rank = p->GetRank(); Int np = p->GetNp(); Int rankRead, npRead, nnodeRead; Int nnode = m->GetNumNodes(); ss.clear(); ss << rank; //read points to move from file and dxdb for them std::string Filename = path + "-DxDb." + (ss.str()) + ".dat"; fin.open(Filename.c_str()); if(!fin.is_open()){ std::cerr << "WARNING: opening file failed --> " << Filename << std::endl; return; } //read in header to check for mismatched process numbers fin >> npRead; fin >> rankRead; fin >> nnodeRead; //check that the state is sane if(npRead != np){ std::cerr << "WARNING: Get_dXdB() Mesh movement sensitivities were run with a " << "nonmatching number of processes, files not synced!" << std::endl; } if(rankRead != rank){ std::cerr << "WARNING: Get_dXdB() Mesh movement sensitivities opened with wrong rank!" << std::endl; } if(nnodeRead != nnode){ std::cerr << "WARNING: Get_dXdB() Mesh movement sensitivities opened with wrong number " << "of nodes!" << std::endl; } //read in globalnodes for each beta up until we have read //the beta we are looking for for(b = 0; b <= beta; b++){ for(i = 0; i < nnode*3; i++){ fin >> dxdb[i]; } } fin.close(); return; }
void Compute_dQdBeta_CTSE(Real* dQdB, SolutionSpace<Real>& space, Int beta) { RCmplx perturb(0.0, 1.0e-11); Mesh<Real>* rm = space.m; SolutionSpace<RCmplx> cspace(space); Mesh<RCmplx>* cm = cspace.m; PObj<RCmplx>* cp = cspace.p; EqnSet<RCmplx>* ceqnset = cspace.eqnset; std::vector<SolutionSpaceBase<RCmplx>*> cSolSpaces; cSolSpaces.push_back(&cspace); SolutionOrdering<RCmplx> operations; std::string name = cspace.name; operations.Insert("Iterate " + name); operations.Finalize(cSolSpaces); Int cnnode = cm->GetNumNodes(); Real* dxdb = new Real[cnnode*3]; Get_dXdB(space.param->path+space.param->spacename, dxdb, rm, beta); //perturb complex part by dxdb*perturb for(Int i = 0; i < cnnode; i++){ for(Int j = 0; j < 3; j++){ cm->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords cp->UpdateXYZ(cm->xyz); //calculate metrics with new grid positions cm->CalcMetrics(); //create a temporary operations vector with just a single space iterator on it //run solver Solve(cSolSpaces, operations); for(Int i = 0; i < cnnode; i++){ for(Int j = 0; j < ceqnset->neqn; j++){ dQdB[i*ceqnset->neqn + j] = imag(cspace.q[i*(ceqnset->neqn+ceqnset->nauxvars) + j]) / imag(perturb); } } delete [] dxdb; return; }
Real Compute_dObjdX_dXdBeta(SolutionSpace<Real>& space, Int beta) { RCmplx perturb (0.0, 1.0e-11); Real dObjdBeta; RCmplx Obj; Mesh<Real>* m = space.m; EqnSet<Real>* eqnset = space.eqnset; 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 nnode = m->GetNumNodes(); Int cnnode = cm->GetNumNodes(); Real* dxdb = new Real[nnode*3]; Get_dXdB(space.param->path+space.param->spacename, dxdb, m, beta); //perturb complex part by dxdb*perturb for(Int i = 0; i < cnnode; i++){ for(Int j = 0; j < 3; j++){ cm->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords cp->UpdateXYZ(cm->xyz); //calculate metrics with new grid positions cm->CalcMetrics(); ComputeSurfaceAreas(&cspace, 0); Obj = Compute_Obj_Function(cspace); dObjdBeta = imag(Obj) / imag(perturb); delete [] dxdb; return dObjdBeta; }
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_dXdB(SolutionSpace<Real>& space) { Mesh<Real>* m = space.m; BoundaryConditions<Real>* bc = space.bc; RCmplx h (0.0, 1.0e-11); Int i, j; Int nnode = m->GetNumNodes(); Int gnode = m->GetNumParallelNodes(); Int nbnode = m->GetNumBoundaryNodes(); Int beta; //this contains dxdb dydx and dzdb Real* dxdb = new Real[nnode*3]; RCmplx* dxdbSurfC = new RCmplx[nnode*3]; Mesh<RCmplx> cm(*m); PObj<RCmplx> cp; cm.SetParallelPointer(&cp); cp.BuildCommMaps(&cm); //check for parallel comm sanity cp.CheckSanityCoords(cm.xyz); Int cnnode = cm.GetNumNodes(); std::cout << "\n\nCOMPUTING dX/dB\n" << std::endl; std::string fullpath = space.param->path + space.param->spacename; Int ndv = GetNdvDesignFile(fullpath); std::cout << "\n\nFOUND " << ndv << " design variables\n" << std::endl; std::ofstream fout; std::stringstream ss; ss.clear(); ss.str(""); ss << cp.GetRank(); std::string dxdbFilename = space.param->path+space.param->spacename + "-DxDb." + (ss.str()) + ".dat"; fout.open(dxdbFilename.c_str()); fout << std::setprecision(16); Int np = m->p->GetNp(); Int rank = m->p->GetRank(); fout << np << " " << rank << " " << cnnode << std::endl; for(beta = 0; beta < ndv; beta++){ std::cout << "PERTURBING BETA: " << beta << std::endl; Compute_dXdB_Surface(space.param->path + space.param->spacename, m, bc, dxdb, beta); //perturb points by h * dxdb_surface for(i = 0; i < nnode; i++){ for(j = 0; j < 3; j++){ dxdbSurfC[i*3 + j] = dxdb[i*3 + j]*h; } } Int smoothingPasses = 1000; MoveMeshLinearElastic(&cm, bc, dxdbSurfC, smoothingPasses); //compute dxdb for(i = 0; i < cnnode*3; i++){ dxdb[i] = imag(cm.xyz[i])/imag(h); } //write dxdb dxdb dzdb to file for(i = 0; i < cnnode; i++){ for(j = 0; j < 3; j++){ fout << dxdb[i*3 + j] << " " ; } fout << std::endl; } //reset xyz coords for next pass for(i = 0; i < nnode*3; i++){ cm.xyz[i] = m->xyz[i]; } cp.UpdateXYZ(cm.xyz); } fout.close(); delete [] dxdb; delete [] dxdbSurfC; return; }
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_dQdBeta_FD(Real* dQdB, SolutionSpace<Real>& space, Int beta) { Real perturb = 1.0e-8; Int i ,j; EqnSet<Real>* eqnset = space.eqnset; Param<Real>* param = space.param; Mesh<Real>* m = space.m; PObj<Real>* p = space.p; Int nnode = m->GetNumNodes(); std::vector<SolutionSpaceBase<Real>*> solSpaces; solSpaces.push_back(&space); //create a temporary operations vector with just a single space iterator on it SolutionOrdering<Real> operations; std::string name = space.name; operations.Insert("Iterate " + name); operations.Finalize(solSpaces); //compute dq/db with finite difference Real* dQdB_up = new Real[nnode*eqnset->neqn]; Real* dQdB_down = new Real[nnode*eqnset->neqn]; Real* Qorig = new Real[nnode*eqnset->neqn]; for(i = 0; i < nnode; i++){ for(j = 0; j < eqnset->neqn; j++){ Qorig[i*eqnset->neqn + j] = space.q[i*(eqnset->neqn+eqnset->nauxvars) + j]; } } Real* dxdb = new Real[nnode*3]; Get_dXdB(space.param->path+space.param->spacename, dxdb, m, beta); //perturb by dxdb*perturb UP for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ m->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords p->UpdateXYZ(m->xyz); //recalculate metrics m->CalcMetrics(); //perturb any parameters as required for sensitivities Perturb_Param(beta, *param, 1); //reset any interesting field which might depend on perturbations space.RefreshForParam(); Solve(solSpaces, operations); for(i = 0; i < nnode; i++){ for(j = 0; j < eqnset->neqn; j++){ dQdB_up[i*eqnset->neqn + j] = space.q[i*(eqnset->neqn+eqnset->nauxvars) + j]; } } //perturb by dxdb*perturb DOWN for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ m->xyz[i*3 + j] -= 2.0*dxdb[i*3 + j]*perturb; } } //update xyz coords p->UpdateXYZ(m->xyz); //recalculate metrics m->CalcMetrics(); //perturb any parameters as required for sensitivities //back to original and then down Perturb_Param(beta, *param, -1); Perturb_Param(beta, *param, -1); //reset any interesting field which might depend on perturbations space.RefreshForParam(); Solve(solSpaces, operations); for(i = 0; i < nnode; i++){ for(j = 0; j < eqnset->neqn; j++){ dQdB_down[i*eqnset->neqn + j] = space.q[i*(eqnset->neqn+eqnset->nauxvars) + j]; } } //compute differences for(i = 0; i < nnode; i++){ for(j = 0; j < eqnset->neqn; j++){ //up dQdB_up[i*eqnset->neqn + j] -= Qorig[i*eqnset->neqn + j]; dQdB_up[i*eqnset->neqn + j] /= perturb; //down dQdB_down[i*eqnset->neqn + j] -= Qorig[i*eqnset->neqn + j]; dQdB_down[i*eqnset->neqn + j] /= -perturb; } } //average for central difference for(i = 0; i < nnode; i++){ for(j = 0; j < eqnset->neqn; j++){ dQdB[i*eqnset->neqn + j] = (dQdB_up[i*eqnset->neqn + j] + dQdB_down[i*eqnset->neqn + j]) / 2.0; } } //reset metrics in case we need them for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ m->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords p->UpdateXYZ(m->xyz); m->CalcMetrics(); //go back to original value Perturb_Param(beta, *param, 1); //reset any interesting field which might depend on perturbations space.RefreshForParam(); //the gaussian source is sometimes used to modify boundary velocities, etc. //pre-compute it for bc call if(space.param->gaussianSource){ space.gaussian->ApplyToResidual(); } //update boundary conditions UpdateBCs(&space); //reset Qorig in case we need it for(i = 0; i < nnode; i++){ for(j = 0; j < eqnset->neqn; j++){ space.q[i*(eqnset->neqn+eqnset->nauxvars) + j] = Qorig[i*eqnset->neqn + j]; eqnset->ComputeAuxiliaryVariables(&space.q[i*(eqnset->neqn+eqnset->nauxvars)]); } } delete [] Qorig; delete [] dQdB_up; delete [] dQdB_down; delete [] dxdb; return; }
void Compute_dRdBeta_CTSE(Real* dRdB, SolutionSpace<Real>& space, Int beta) { RCmplx perturb (0.0, 1.0e-11); Mesh<Real>* rm = space.m; Int nnode = rm->GetNumNodes(); Int gnode = rm->GetNumParallelNodes(); Int nbnode = rm->GetNumBoundaryNodes(); std::ifstream fin; SolutionSpace<RCmplx> cspace(space); Mesh<RCmplx>* cm = cspace.m; PObj<RCmplx>* cp = cspace.p; EqnSet<RCmplx>* ceqnset = cspace.eqnset; Param<RCmplx>* param = cspace.param; Int cnnode = cm->GetNumNodes(); Int cgnode = cm->GetNumParallelNodes(); Int cnbnode = cm->GetNumBoundaryNodes(); RCmplx* q = cspace.q; Int neqn = ceqnset->neqn; Int nvars = neqn + ceqnset->nauxvars; Real* dxdb = new Real[nnode*3]; Get_dXdB(space.param->path + space.param->spacename, dxdb, rm, beta); //perturb complex part by dxdb*perturb for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ cm->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords cp->UpdateXYZ(cm->xyz); //calculate metrics with new grid positions cm->CalcMetrics(); //compute gradient coefficients once ComputeNodeLSQCoefficients(&cspace); //perturb any parameters which we are getting sensitivities for Perturb_Param(beta, *cspace.param); //reset any interesting field which might depend on perturbations cspace.RefreshForParam(); //the gaussian source is sometimes used to modify boundary velocities, etc. //pre-compute it for bc call if(cspace.param->gaussianSource){ cspace.gaussian->ApplyToResidual(); } //update boundary conditions cspace.p->UpdateGeneralVectors(q, nvars); UpdateBCs(&cspace); 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]); } } //compute spatial residual SpatialResidual(&cspace); ExtraSourceResidual(&cspace); for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < ceqnset->neqn; j++){ dRdB[i*ceqnset->neqn + j] = imag(cspace.crs->b[i*ceqnset->neqn + j])/imag(perturb); } } delete [] dxdb; }
void ComputedQdBeta_HardsetBC(Int nnodes, Int* nodes, Real* dQdB, const SolutionSpace<Real>& space, Int beta) { Real h = 1.0e-11; RCmplx I(0.0, 1.0); RCmplx perturb = h*I; Mesh<Real>* rm = space.m; SolutionSpace<RCmplx> cspace(space); Mesh<RCmplx>* cm = cspace.m; PObj<RCmplx>* cp = cspace.p; EqnSet<RCmplx>* ceqnset = cspace.eqnset; Param<RCmplx>* param = cspace.param; RCmplx* q = cspace.q; Int nnode = rm->GetNumNodes(); Int neqn = ceqnset->neqn; Int nvars = neqn + ceqnset->nauxvars; Real* dxdb = new Real[nnode*3]; Get_dXdB(space.param->path + space.param->spacename, dxdb, rm, beta); //perturb complex part by dxdb*perturb for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ cm->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords cp->UpdateXYZ(cm->xyz); //calculate metrics with new grid positions cm->CalcMetrics(); //compute gradient coefficients once ComputeNodeLSQCoefficients(&cspace); //perturb any parameters which we are getting sensitivities for Perturb_Param(beta, *cspace.param); //reset any interesting field which might depend on perturbations cspace.RefreshForParam(); //the gaussian source is sometimes used to modify boundary velocities, etc. //pre-compute it for bc call if(cspace.param->gaussianSource){ cspace.gaussian->ApplyToResidual(); } //update boundary conditions cspace.p->UpdateGeneralVectors(q, nvars); UpdateBCs(&cspace); cspace.p->UpdateGeneralVectors(q, nvars); for(Int i = 0; i < nnodes; i++){ Int node = nodes[i]; for(Int j = 0; j < neqn; j++){ dQdB[i*neqn + j] = imag(q[node*nvars + j])/h; std::cout << "dqdb: " << i << ": -" << j << " " << dQdB[i*neqn + j] << std::endl; } } }
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; }
void Compute_dRdBeta_FD(Real* dRdB, SolutionSpace<Real>& space, Int beta) { Real perturb = 1.0e-8; EqnSet<Real>* eqnset = space.eqnset; Mesh<Real>* m = space.m; PObj<Real>* p = space.p; Param<Real>* param = space.param; Real* q = space.q; Int i; Int neqn = eqnset->neqn; Int nvars = neqn + eqnset->nauxvars; Int nnode = m->GetNumNodes(); Int gnode = m->GetNumParallelNodes(); Int nbnode = m->GetNumBoundaryNodes(); Real* Qorig = new Real[nnode*nvars]; Real* resOrig = new Real[nnode*neqn]; Real* resUp = new Real[nnode*neqn]; Real* resDown = new Real[nnode*neqn]; //store original q for(i = 0; i < (nnode*nvars); i++){ Qorig[i] = space.q[i]; } UpdateBCs(&space); //compute spatial residual SpatialResidual(&space); ExtraSourceResidual(&space); for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < eqnset->neqn; j++){ resOrig[i*eqnset->neqn + j] = space.crs->b[i*eqnset->neqn + j]; } } Real* dxdb = new Real[nnode*3]; Get_dXdB(space.param->path+space.param->spacename, dxdb, m, beta); //perturb complex part by dxdb*perturb UP for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ m->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords p->UpdateXYZ(m->xyz); //calculate metrics with new grid positions m->CalcMetrics(); //compute gradient coefficients once ComputeNodeLSQCoefficients(&space); //perturb parameters as required Perturb_Param(beta, *(space.param), 1); //reset any interesting field which might depend on perturbations space.RefreshForParam(); //the gaussian source is sometimes used to modify boundary velocities, etc. //pre-compute it for bc call if(space.param->gaussianSource){ space.gaussian->ApplyToResidual(); } //update boundary conditions UpdateBCs(&space); //now, compute gradients and limiters if(param->sorder > 1 || param->viscous){ for(Int i = 0; i < (nnode+nbnode+gnode); i++){ eqnset->NativeToExtrapolated(&q[i*nvars]); } space.grad->Compute(); space.limiter->Compute(&space); for(Int i = 0; i < (nnode+nbnode+gnode); i++){ eqnset->ExtrapolatedToNative(&q[i*nvars]); } } //compute spatial residual SpatialResidual(&space); ExtraSourceResidual(&space); for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < eqnset->neqn; j++){ resUp[i*eqnset->neqn + j] = (space.crs->b[i*eqnset->neqn + j]); } } //perturb parameters as required, call twice (move back to original value then perturb down) Perturb_Param(beta, *(space.param), -1); Perturb_Param(beta, *(space.param), -1); //reset any interesting field which might depend on perturbations space.RefreshForParam(); //the gaussian source is sometimes used to modify boundary velocities, etc. //pre-compute it for bc call if(space.param->gaussianSource){ space.gaussian->ApplyToResidual(); } //perturb complex part by dxdb*perturb DOWN for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ m->xyz[i*3 + j] -= 2.0*dxdb[i*3 + j]*perturb; } } //update xyz coords p->UpdateXYZ(m->xyz); //calculate metrics with new grid positions m->CalcMetrics(); //compute gradient coefficients once ComputeNodeLSQCoefficients(&space); //update boundary conditions UpdateBCs(&space); //now, compute gradients and limiters if(param->sorder > 1 || param->viscous){ for(Int i = 0; i < (nnode+nbnode+gnode); i++){ eqnset->NativeToExtrapolated(&q[i*nvars]); } space.grad->Compute(); space.limiter->Compute(&space); for(Int i = 0; i < (nnode+nbnode+gnode); i++){ eqnset->ExtrapolatedToNative(&q[i*nvars]); } } //compute spatial residual SpatialResidual(&space); ExtraSourceResidual(&space); for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < eqnset->neqn; j++){ resDown[i*eqnset->neqn + j] = (space.crs->b[i*eqnset->neqn + j]); } } for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < eqnset->neqn; j++){ //up resUp[i*eqnset->neqn + j] -= resOrig[i*eqnset->neqn + j]; resUp[i*eqnset->neqn + j] /= perturb; //down resDown[i*eqnset->neqn + j] -= resOrig[i*eqnset->neqn + j]; resDown[i*eqnset->neqn + j] /= (-perturb); //central dRdB[i*eqnset->neqn + j] = (resUp[i*eqnset->neqn + j] + resDown[i*eqnset->neqn +j]) / 2.0; } } //reset metrics in case we need them for(Int i = 0; i < nnode; i++){ for(Int j = 0; j < 3; j++){ m->xyz[i*3 + j] += dxdb[i*3 + j]*perturb; } } //update xyz coords p->UpdateXYZ(m->xyz); //recalculate metrics m->CalcMetrics(); //compute gradient coefficients once ComputeNodeLSQCoefficients(&space); //reset Qorig in case we need it for(i = 0; i < nnode*nvars; i++){ space.q[i] = Qorig[i]; } //go back to original values Perturb_Param(beta, *(space.param), 1); //reset any interesting field which might depend on perturbations space.RefreshForParam(); //the gaussian source is sometimes used to modify boundary velocities, etc. //pre-compute it for bc call if(space.param->gaussianSource){ space.gaussian->ApplyToResidual(); } //update boundary conditions UpdateBCs(&space); //now, compute gradients and limiters if(param->sorder > 1 || param->viscous){ for(Int i = 0; i < (nnode+nbnode+gnode); i++){ eqnset->NativeToExtrapolated(&q[i*nvars]); } space.grad->Compute(); space.limiter->Compute(&space); for(Int i = 0; i < (nnode+nbnode+gnode); i++){ eqnset->ExtrapolatedToNative(&q[i*nvars]); } } delete [] dxdb; delete [] resOrig; delete [] resUp; delete [] resDown; return; }
int main(int argc, char* argv[]){ #ifdef _DEBUG //enable exceptions so we can trap NaNs, etc. feenableexcept(FE_INVALID | FE_OVERFLOW); #endif Int rank, np; Int mode = 0; Int ndv = 0; Real* dObjdBeta = NULL; std::vector<Param<Real>* > paramList; SolutionOrdering<Real> operations; TemporalControl<Real> temporalControl; string tempname; stringstream temposs; TimerList timers(5); timers.CreateTimer("MPI_InitTimer"); timers.CreateTimer("SolveTimer"); timers.CreateTimer("DesignTimer"); timers.CreateTimer("MovementTimer"); //create parallel object for comms timers.StartTimer("MPI_InitTimer"); MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &np); timers.StopTimer("MPI_InitTimer"); PObj<Real> pobj; rank = pobj.GetRank(); //remove Abort.Log if its present if(rank == 0){ remove("Abort.Log"); } if(!((argc == 2) || (argc == 3))){ cerr << "Invalid arguments!!!" << endl; cerr << "USE: " << argv[0] << " <casename>" << endl; cerr << "OR" << endl; cerr << "USE: " << argv[0] << " <casename> <design type>" << endl; cerr << "<design type> - none = 0" << endl; cerr << "<design type> - objective f-n evaluation = 1" << endl; cerr << "<design type> - direct = 2" << endl; cerr << "<design type> - adjoint = 3" << endl; cerr << "<design type> - CTSE = 4" << endl; cerr << "<design type> - GRID SMOOTHING = 5" << endl; cerr << "<design type> - Compute Mesh Sensitivity = 6" << endl; cerr << "<design type> - Finite Difference = 7" << endl; //dumps all options in param file to output Param<Real> tmp; tmp.PrintAllParams(); MPI_Finalize(); return (1); } std::string casestring = argv[1]; size_t pos = casestring.rfind('/'); std::string pathname; if(pos != std::string::npos){ pathname = casestring.substr(0, pos+1); casestring = casestring.substr(pos); } else{ pathname = "./"; } //set pathname in abort class Abort.rootDirectory = pathname; if(argc == 3){ temposs.clear(); temposs.str(""); temposs << argv[2]; temposs >> mode; }