diff --git a/CG_Parallel/CG_MPI b/CG_Parallel/CG_MPI deleted file mode 100755 index 9e97426..0000000 Binary files a/CG_Parallel/CG_MPI and /dev/null differ diff --git a/CG_Parallel/CG_Parallel.cpp b/CG_Parallel/CG_Parallel.cpp index 33923fe..805fd7c 100644 --- a/CG_Parallel/CG_Parallel.cpp +++ b/CG_Parallel/CG_Parallel.cpp @@ -1,209 +1,210 @@ // // Created by shernand on 29/05/19. // /** * @file CG_Serial.cpp * @author Sergio Hernandez * This file is part of the Conjugate Gradient Project * * This class implements the parallel version of the Conjugate Gradient * */ #include #include #include #include #include "CG_Parallel.hpp" /** * Complete constructor of the CG solver. * @param matrixA std::vector NxN symmetric definite positive * @param vectorB Nx1 std::vector right side vector * @param tol double Tolerance for our stopping criterion * @param maxIter int Maximum number of iterations of the stopping criterion */ CG_Parallel::CG_Parallel(std::vector const &matrixA, std::vector const &vectorB, double const &tol, int const &maxIter) { setMatrixA(matrixA); setVectorB(vectorB); setTol(tol); setMaxIterations(maxIter); + std::vector timings(3,0.0); } /** * Computes the CG solver * @param x_0 Nx1 std::vecotr the initial guess for the solution * @return std::tuple x, int n_iterations> The tuple ,int> CG_Parallel::computeCG(std::vector &x_0) { std::vector b = getVectorB(); std::vector mA = getMatrixA(); int max_iter = getMaxIterations(); double tol = getTol(); std::vector x_k = x_0; std::vector r_k = matrixVector(mA,x_k); r_k = vectorScalarMul(r_k,-1.0); r_k = vectorVectorSum(b,r_k); std::vector d_k = r_k; double norm_res = vectorVectorDot(r_k,r_k); int k = 0; while ((norm_res>tol)&&(k A_dk = matrixVector(mA,d_k); double dk_A_dk = vectorVectorDot(d_k,A_dk); double alpha_k = norm_res/dk_A_dk; x_k = vectorVectorSum(x_k,vectorScalarMul(d_k,alpha_k)); A_dk = vectorScalarMul(A_dk,-alpha_k); r_k= vectorVectorSum(r_k,A_dk); double norm_r_k_1 = vectorVectorDot(r_k,r_k); double beta_k_1 = norm_r_k_1/norm_res; d_k = vectorVectorSum(r_k,vectorScalarMul(d_k,beta_k_1)); norm_res=norm_r_k_1; k+=1; } return std::make_tuple(x_k,k); } /** * The operation scalar*vector * @param pVector1 Nx1 std::vector * @param pScalar double * @return mul_vector Nx1 std::vector mult element wise of the scalar and the vector */ std::vector CG_Parallel::vectorScalarMul(const std::vector &pVector1, const double pScalar) { int size,rank; MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); int n = pVector1.size(); int batchSize = n / size; std::vector mul_vector(n,0.0); std::vector subVec1(batchSize, 0.0); std::vector subMul(batchSize, 0.0); double scalar = pScalar; MPI_Bcast(&scalar, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Scatter(pVector1.data(), batchSize, MPI_DOUBLE, subVec1.data(), batchSize, MPI_DOUBLE, 0, MPI_COMM_WORLD); for(int i=0;i * @param pVector2 Nx1 std::vector * @return sum_vector Nx1 std::vector sum element wise of the two vectors */ std::vector CG_Parallel::vectorVectorSum(const std::vector &pVector1, const std::vector pVector2) { int size,rank; MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); int n = pVector1.size(); std::vector sum_vector(n,0.0); int batchSize = n / size; //Should manage the offset if n is not exactly divisible bz size. // if (n % size) { // batchSize++; //} std::vector subVec1(batchSize, 0.0); std::vector subVec2(batchSize, 0.0); std::vector subSum(batchSize, 0.0); MPI_Scatter(pVector1.data(), batchSize, MPI_DOUBLE, subVec1.data(), batchSize, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Scatter(pVector2.data(), batchSize, MPI_DOUBLE, subVec2.data(), batchSize, MPI_DOUBLE, 0, MPI_COMM_WORLD); for (int i = 0;i * @param pVector2 Nx1 std::vector * @return double the resulting dot product */ double CG_Parallel::vectorVectorDot(const std::vector &pVector1, const std::vector pVector2) { int size, rank; MPI_Status status; MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); int const batchSize = pVector1.size()/size; std::vector subVec1(batchSize, 0.0); std::vector subVec2(batchSize, 0.0); MPI_Scatter(pVector1.data(), batchSize, MPI_DOUBLE, subVec1.data(), batchSize, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Scatter(pVector2.data(), batchSize, MPI_DOUBLE, subVec2.data(), batchSize, MPI_DOUBLE, 0, MPI_COMM_WORLD); double partial_dot_product = 0.0; double total_dot_product = 0.0; for (int i=0;i * @param pVector Nx1 vector std::vector * @return prod_vecotr Nx1 std::vector */ std::vector CG_Parallel::matrixVector(const std::vector &pMatrix, const std::vector pVector) { int size, rank; MPI_Status status; MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); int n = pVector.size(); int nRows = n/size; std::vector vector =pVector; MPI_Bcast(vector.data(), n, MPI_DOUBLE, 0, MPI_COMM_WORLD); std::vector subMatrix(n*nRows,0.0); MPI_Scatter(pMatrix.data(), n*nRows, MPI_DOUBLE, subMatrix.data(), n*nRows, MPI_DOUBLE, 0, MPI_COMM_WORLD); std::vector prod_vector(n,0.0); std::vector subProd(nRows, 0.0); for(int i=0;i &CG_Parallel::getMatrixA() const { return matrixA; } void CG_Parallel::setMatrixA(const std::vector &matrixA) { CG_Parallel::matrixA = matrixA; } const std::vector &CG_Parallel::getVectorB() const { return vectorB; } void CG_Parallel::setVectorB(const std::vector &vectorB) { CG_Parallel::vectorB = vectorB; } double CG_Parallel::getTol() const { return tol; } void CG_Parallel::setTol(double tol) { CG_Parallel::tol = tol; } int CG_Parallel::getMaxIterations() const { return max_iterations; } void CG_Parallel::setMaxIterations(int maxIterations) { max_iterations = maxIterations; } diff --git a/CG_Parallel/CMakeLists.txt b/CG_Parallel/CMakeLists.txt index 2d88509..d6b9797 100644 --- a/CG_Parallel/CMakeLists.txt +++ b/CG_Parallel/CMakeLists.txt @@ -1,29 +1,29 @@ cmake_minimum_required(VERSION 3.14) project(CG_Parallel) set(CMAKE_CXX_STANDARD 14) set(DOC_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/doc) find_package(MPI REQUIRED) include_directories(/usr/include/mpi/) SET(CMAKE_C_COMPILER mpicc) SET(CMAKE_CXX_COMPILER mpicxx) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-pie -Wall -pg -Wextra -pedantic -std=c++11 -O2") #Profiling set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -std=c++14 -O2") -set(SOURCE_FILES main.cpp CG_Parallel.cpp CG_Parallel.hpp) +set(SOURCE_FILES main.cpp CG_Parallel.cpp CG_Parallel.hpp ConfigFileParser.cpp ConfigFileParser.hpp FileParserException.h FileNotFoundException.h) add_executable(CG_Parallel ${SOURCE_FILES}) #ConfigFileParser.cpp Writter.cpp #Copies files for Doxygen and test running file(COPY "Doxyfile" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) file(COPY "atom_icon_192.ico" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) file(MAKE_DIRECTORY ${DOC_FOLDER}) find_package(Doxygen) add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM ) file(COPY ${DOC_FOLDER} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/CG_Parallel/ConfigFileParser.cpp b/CG_Parallel/ConfigFileParser.cpp index fa753cf..992184a 100644 --- a/CG_Parallel/ConfigFileParser.cpp +++ b/CG_Parallel/ConfigFileParser.cpp @@ -1,92 +1,86 @@ /** @file ConfigFileParser.cpp * @author Sergio Hernandez * * This file is part of the Conjugate Gradient Project * * * This class performs the parsing of a standard configuration file. * */ #include "ConfigFileParser.hpp" ConfigFileParser::ConfigFileParser() { defaultKeys.push_back("type_input"); - defaultKeys.push_back("newton_g"); - defaultKeys.push_back("timestep"); - defaultKeys.push_back("box_size"); - defaultKeys.push_back("softening"); - defaultKeys.push_back("tree_thres"); - defaultKeys.push_back("display_f"); - defaultKeys.push_back("n_particles"); - defaultKeys.push_back("scale_radius"); - defaultKeys.push_back("n_time_steps"); + defaultKeys.push_back("N"); + defaultKeys.push_back("tol"); + defaultKeys.push_back("max_iter"); defaultKeys.push_back("type_output"); defaultKeys.push_back("outputFile"); defaultKeys.push_back("number_outputs"); } ConfigFileParser::~ConfigFileParser(){} std::map ConfigFileParser::getData(){ return data; } void ConfigFileParser::setData(std::map pData) { data=pData; } std::string ConfigFileParser::getFName(){ return fName; } void ConfigFileParser::parseFile(std::string pFname){ fName = pFname; std::cout<<"Parsing file: " << fName << std::endl; std::ifstream file; file.open(fName.c_str()); if (!file) throw FileNotFoundException(); std::string line; while (std::getline(file, line)) { std::string temp = line; if (temp.empty()) //Empty Line continue; if(temp.front() =='#') //Comment Line continue; std::istringstream str_line(temp); std::string key; if( std::getline(str_line, key, '=') ) { std::string value; if( std::getline(str_line, value) ){ if (!key.empty() && !value.empty()) { //Verify that the two values exist data[key] = value; //std::cout << "key: " << key << std::endl; //std::cout << "value: " << value << std::endl; } else throw FileParserException(); } } } file.close(); } void ConfigFileParser::verify(){ for(int i=0;i #include #include "CG_Parallel.hpp" #include +#include "ConfigFileParser.hpp" +/** + * Constant to inform the user the correct usage of the program in case of a misuse. + */ +#define USAGE "Please enter correctly one argument (a config file). Example: ./CG_Parallel configFile.txt" +/** + * Constant which defines the correct number of arguments the program can receive. + */ +#define N_ARGS 2 + int main(int argc, char* argv[]) { MPI_Init(&argc, &argv); - //TODO Temporal - using Tridiagonal matrix - int N = 100; - std::vector A(N*N,0.0);//Filled with 0.0 - std::vector b(N, 1.0);//Filled with 1.0 - for (int i=0; i 0 ){ - A[i+N*j] = 1.0; //Downer + int rank, size; + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + if(argc!=N_ARGS){ + std::cout< A;//Filled with 0.0 + std::vector b;//Filled with 1.0 + + std::string fName = argv[1]; + ConfigFileParser parser = ConfigFileParser(); + parser.parseFile(fName); + parser.verify(); + std::cout << "Finished parsing the file " << std::endl; + //This could be an executer + std::map data = parser.getData(); + //Size of the matrix + std::string tempKey = "N"; + N = stoi(data[tempKey]); + std::cout << " N = " << N << std::endl; + //Tolerance + tempKey = "tol"; + tol = stof(data[tempKey]); + std::cout << " tol = " << tol << std::endl; + //max iterations + tempKey = "max_iter"; + max_iter = stoi(data[tempKey]); + std::cout << " max_iter = " << max_iter << std::endl; + //type input + tempKey = "type_input"; + type_input = data[tempKey]; + //number_outputs + tempKey = "number_outputs"; + number_outputs = stoi(data[tempKey]); + tempKey = "type_output"; + type_output = data[tempKey]; + tempKey = "outputFile"; + outputFile = data[tempKey]; + if (type_input=="tridiagonal") { + std::cout<<"Matrix A is: "< 0) { + A[i + N * j] = 1.0; //Downer + } + } + if (j == i) { + A[i + N * j] = -2.0; //Main diagonal + } } } - if (j == i){ - A[i+N*j] = -2.0; //Main diagonal + } + std::vector x_0 (N,0.0); + std::cout<< "Preparing to solve"<,int> result = solver.computeCG(x_0); + std::vector x = std::get<0>(result); + int k = std::get<1>(result); + if(rank==0){ + std::cout << "Solution was found after : "< x_0 (N,0.0); - CG_Parallel solver = CG_Parallel(A,b,tol,max_iter); - std::tuple,int> result = solver.computeCG(x_0); - std::vector x = std::get<0>(result); - int k = std::get<1>(result); - MPI_Finalize(); - std::cout << "Solution was found after : "<