int main(int argc, char *argv[]) { unsigned short iZone, nZone = SINGLE_ZONE; su2double StartTime = 0.0, StopTime = 0.0, UsedTime = 0.0; char config_file_name[MAX_STRING_SIZE], *cstr = NULL; ofstream Gradient_file; su2double** Gradient; unsigned short iDV, iDV_Value; int rank, size; /*--- MPI initialization, and buffer setting ---*/ #ifdef HAVE_MPI SU2_MPI::Init(&argc,&argv); SU2_MPI::Comm MPICommunicator(MPI_COMM_WORLD); #else SU2_Comm MPICommunicator(0); #endif rank = SU2_MPI::GetRank(); size = SU2_MPI::GetSize(); /*--- Pointer to different structures that will be used throughout the entire code ---*/ CConfig **config_container = NULL; CGeometry **geometry_container = NULL; CSurfaceMovement **surface_movement = NULL; CVolumetricMovement **grid_movement = NULL; COutput *output = NULL; /*--- Load in the number of zones and spatial dimensions in the mesh file (if no config file is specified, default.cfg is used) ---*/ if (argc == 2) { strcpy(config_file_name,argv[1]); } else { strcpy(config_file_name, "default.cfg"); } /*--- Read the name and format of the input mesh file to get from the mesh file the number of zones and dimensions from the numerical grid (required for variables allocation) ---*/ CConfig *config = NULL; config = new CConfig(config_file_name, SU2_DEF); nZone = CConfig::GetnZone(config->GetMesh_FileName(), config->GetMesh_FileFormat(), config); /*--- Definition of the containers per zones ---*/ config_container = new CConfig*[nZone]; geometry_container = new CGeometry*[nZone]; surface_movement = new CSurfaceMovement*[nZone]; grid_movement = new CVolumetricMovement*[nZone]; for (iZone = 0; iZone < nZone; iZone++) { config_container[iZone] = NULL; geometry_container[iZone] = NULL; grid_movement [iZone] = NULL; surface_movement[iZone] = NULL; } /*--- Loop over all zones to initialize the various classes. In most cases, nZone is equal to one. This represents the solution of a partial differential equation on a single block, unstructured mesh. ---*/ for (iZone = 0; iZone < nZone; iZone++) { /*--- Definition of the configuration option class for all zones. In this constructor, the input configuration file is parsed and all options are read and stored. ---*/ config_container[iZone] = new CConfig(config_file_name, SU2_DOT, iZone, nZone, 0, VERB_HIGH); /*--- Set the MPI communicator ---*/ config_container[iZone]->SetMPICommunicator(MPICommunicator); /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ CGeometry *geometry_aux = NULL; /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ geometry_aux->SetColorGrid_Parallel(config_container[iZone]); /*--- Allocate the memory of the current domain, and divide the grid between the nodes ---*/ geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); /*--- Deallocate the memory of geometry_aux ---*/ delete geometry_aux; /*--- Add the Send/Receive boundaries ---*/ geometry_container[iZone]->SetSendReceive(config_container[iZone]); /*--- Add the Send/Receive boundaries ---*/ geometry_container[iZone]->SetBoundaries(config_container[iZone]); } /*--- Set up a timer for performance benchmarking (preprocessing time is included) ---*/ #ifdef HAVE_MPI StartTime = MPI_Wtime(); #else StartTime = su2double(clock())/su2double(CLOCKS_PER_SEC); #endif for (iZone = 0; iZone < nZone; iZone++){ if (rank == MASTER_NODE) cout << endl <<"----------------------- Preprocessing computations ----------------------" << endl; /*--- Compute elements surrounding points, points surrounding points ---*/ if (rank == MASTER_NODE) cout << "Setting local point connectivity." <<endl; geometry_container[iZone]->SetPoint_Connectivity(); /*--- Check the orientation before computing geometrical quantities ---*/ geometry_container[iZone]->SetBoundVolume(); if (config_container[iZone]->GetReorientElements()) { if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the elements." <<endl; geometry_container[iZone]->Check_IntElem_Orientation(config_container[iZone]); geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); } /*--- Create the edge structure ---*/ if (rank == MASTER_NODE) cout << "Identify edges and vertices." <<endl; geometry_container[iZone]->SetEdges(); geometry_container[iZone]->SetVertex(config_container[iZone]); /*--- Compute center of gravity ---*/ if (rank == MASTER_NODE) cout << "Computing centers of gravity." << endl; geometry_container[iZone]->SetCoord_CG(); /*--- Create the dual control volume structures ---*/ if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; geometry_container[iZone]->SetBoundControlVolume(config_container[ZONE_0], ALLOCATE); /*--- Store the global to local mapping after preprocessing. ---*/ if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; geometry_container[iZone]->SetGlobal_to_Local_Point(); /*--- Load the surface sensitivities from file. This is done only once: if this is an unsteady problem, a time-average of the surface sensitivities at each node is taken within this routine. ---*/ if (!config_container[iZone]->GetDiscrete_Adjoint()){ if (rank == MASTER_NODE) cout << "Reading surface sensitivities at each node from file." << endl; geometry_container[iZone]->SetBoundSensitivity(config_container[iZone]); } else { if (rank == MASTER_NODE) cout << "Reading volume sensitivities at each node from file." << endl; grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone], config_container[iZone]); geometry_container[iZone]->SetSensitivity(config_container[iZone]); if (rank == MASTER_NODE) cout << endl <<"---------------------- Mesh sensitivity computation ---------------------" << endl; grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone], config_container[iZone], false, true); } } if (config_container[ZONE_0]->GetDiscrete_Adjoint()){ if (rank == MASTER_NODE) cout << endl <<"------------------------ Mesh sensitivity Output ------------------------" << endl; output = new COutput(config_container[ZONE_0]); output->SetSensitivity_Files(geometry_container, config_container, nZone); } if (config_container[ZONE_0]->GetDesign_Variable(0) != NONE){ /*--- Initialize structure to store the gradient ---*/ Gradient = new su2double*[config_container[ZONE_0]->GetnDV()]; for (iDV = 0; iDV < config_container[ZONE_0]->GetnDV(); iDV++){ Gradient[iDV] = new su2double[config_container[ZONE_0]->GetnDV_Value(iDV)]; for (iDV_Value = 0; iDV_Value < config_container[ZONE_0]->GetnDV_Value(iDV); iDV_Value++){ Gradient[iDV][iDV_Value] = 0.0; } } if (rank == MASTER_NODE) cout << endl <<"---------- Start gradient evaluation using sensitivity information ----------" << endl; /*--- Write the gradient in a external file ---*/ if (rank == MASTER_NODE) { cstr = new char [config_container[ZONE_0]->GetObjFunc_Grad_FileName().size()+1]; strcpy (cstr, config_container[ZONE_0]->GetObjFunc_Grad_FileName().c_str()); Gradient_file.open(cstr, ios::out); } /*--- Loop through each zone and add it's contribution to the gradient array ---*/ for (iZone = 0; iZone < nZone; iZone++){ /*--- Definition of the Class for surface deformation ---*/ surface_movement[iZone] = new CSurfaceMovement(); /*--- Copy coordinates to the surface structure ---*/ surface_movement[iZone]->CopyBoundary(geometry_container[iZone], config_container[iZone]); /*--- If AD mode is enabled we can use it to compute the projection, * otherwise we use finite differences. ---*/ if (config_container[iZone]->GetAD_Mode()){ SetProjection_AD(geometry_container[iZone], config_container[iZone], surface_movement[iZone] , Gradient); }else{ SetProjection_FD(geometry_container[iZone], config_container[iZone], surface_movement[iZone] , Gradient); } } /*--- Print gradients to screen and file ---*/ OutputGradient(Gradient, config_container[ZONE_0], Gradient_file); if (rank == MASTER_NODE) Gradient_file.close(); for (iDV = 0; iDV < config_container[ZONE_0]->GetnDV(); iDV++){ delete [] Gradient[iDV]; } delete [] Gradient; } if (rank == MASTER_NODE) cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; if (geometry_container != NULL) { for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != NULL) { delete geometry_container[iZone]; } } delete [] geometry_container; } if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; if (surface_movement != NULL) { for (iZone = 0; iZone < nZone; iZone++) { if (surface_movement[iZone] != NULL) { delete surface_movement[iZone]; } } delete [] surface_movement; } if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; if (grid_movement != NULL) { for (iZone = 0; iZone < nZone; iZone++) { if (grid_movement[iZone] != NULL) { delete grid_movement[iZone]; } } delete [] grid_movement; } if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; delete config; config = NULL; if (config_container != NULL) { for (iZone = 0; iZone < nZone; iZone++) { if (config_container[iZone] != NULL) { delete config_container[iZone]; } } delete [] config_container; } if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; if (output != NULL) delete output; if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; if (cstr != NULL) delete cstr; /*--- Synchronization point after a single solver iteration. Compute the wall clock time required. ---*/ #ifdef HAVE_MPI StopTime = MPI_Wtime(); #else StopTime = su2double(clock())/su2double(CLOCKS_PER_SEC); #endif /*--- Compute/print the total time for performance benchmarking. ---*/ UsedTime = StopTime-StartTime; if (rank == MASTER_NODE) { cout << "\nCompleted in " << fixed << UsedTime << " seconds on "<< size; if (size == 1) cout << " core." << endl; else cout << " cores." << endl; } /*--- Exit the solver cleanly ---*/ if (rank == MASTER_NODE) cout << endl <<"------------------------- Exit Success (SU2_DOT) ------------------------" << endl << endl; /*--- Finalize MPI parallelization ---*/ #ifdef HAVE_MPI SU2_MPI::Finalize(); #endif return EXIT_SUCCESS; }