#include "ManningUncertainity.h" #include "Channel.h" #include "Subbasin.h" #include "easylogging++.h" #include <iostream> #include <mpi.h> namespace math1d_cl { ManningUncertainity::ManningUncertainity(std::shared_ptr<AbstractRandom> random, UncertainityOptions options,std::shared_ptr<MatData> matData) : AbstractParam(random, options, matData) { m_channelValues.reserve(m_options.simulationCount); m_subbasinValues.reserve(m_options.simulationCount); /* Get original values */ std::vector<double> channelOrig, subbasinOrig; // Get channel's N //double chN = 0.0, subN = 0.0; for(std::vector<std::shared_ptr<Channel>>::const_iterator it = matData->getChannels().begin(); it != matData->getChannels().end(); ++it) { m_channelOriginalValues.push_back((*it)->getN()); //m_channelOriginalValues.push_back(chN++); } // Get subbasin's N for(std::vector<std::shared_ptr<Subbasin>>::const_iterator it = matData->getSubbasins().begin(); it != matData->getSubbasins().end(); ++it) { m_subbasinOriginalValues.push_back((*it)->getN()); //m_subbasinOriginalValues.push_back(subN++); } } void ManningUncertainity::setParam(MatData &matData) { /*int rank = -1, numProc = -1; // Holds rank of current process and total number of processes MPI_Comm_size(MPI_COMM_WORLD, &numProc); MPI_Comm_rank(MPI_COMM_WORLD, &rank);*/ if((m_currentIterationNumber > m_channelValues.size()) || (m_currentIterationNumber > m_subbasinValues.size())) { std::cerr << "ERROR: Manning uncertainity: Current iteration number bigger than generated values."; std::exit(-1); } else { for(size_t i = 0; i < matData.getChannels().size(); ++i) { //CLOG(INFO,"montecarlo") << "[Rank " << rank <<"]N Channel - Orig: " << m_channelOriginalValues[i] << " New: " << m_channelValues[m_currentIterationNumber][i]; matData.getChannels()[i]->setN(m_channelValues[m_currentIterationNumber][i]); } for(size_t i = 0; i < matData.getSubbasins().size(); ++i) { //CLOG(INFO,"montecarlo") << "[Rank " << rank <<"]N Subbasin - Orig: " << m_subbasinOriginalValues[i] << " New: " << m_subbasinValues[m_currentIterationNumber][i]; matData.getSubbasins()[i]->setN(m_subbasinValues[m_currentIterationNumber][i]); } } /* Do not forget to increment iteration number after each setParam call !*/ m_currentIterationNumber++; } void ManningUncertainity::generateValues() { int rank = -1, numProc = -1; // Holds rank of current process and total number of processes MPI_Comm_size(MPI_COMM_WORLD, &numProc); MPI_Comm_rank(MPI_COMM_WORLD, &rank); const size_t chunkSize = m_options.simulationCount / numProc; // Monte Carlo iterations per chunk const size_t valuesPerChunk = (m_subbasinOriginalValues.size() + m_channelOriginalValues.size()) * chunkSize; // Values per chunk // One chunk of values for one process // Allocate array for one chunk double *randomizedValuesChunk = new double[valuesPerChunk]; // Allocate array for each process //m_subbasinValuesChunk = new double[m_subbasinOriginalValues.size() * chunkSize]; int slaveRank = 1; if(rank == 0) { /* Generate randomized values */ /* Data are origanised as follows: CH0: N CH1: N . . . CH48: N CH49: N Iteration 0 ------- SUB0: N SUB1: N . . . SUB48: N SUB49: N ------------------------ CH0: N CH1: N . . . CH48: N CH49: N Iteration 1 ------- SUB0: N SUB1: N . . . SUB48: N SUB49: N etc... */ CLOG(INFO,"montecarlo") << "Randomizing Manning's coefficients..."; CLOG(INFO,"montecarlo") << "[MPI]Total chunk count: " << m_options.simulationCount/chunkSize; CLOG(INFO,"montecarlo") << "[MPI]Chunksize: " << chunkSize; for(size_t mc = 0; mc < (size_t)m_options.simulationCount; ++mc) { double min = 0.0, max = 0.0; std::vector<double> randomChannel, randomSubbasin; // Channels for(size_t i = 0; i < m_channelOriginalValues.size(); ++i) { int chunkNum = i + ((mc % chunkSize) *(m_subbasinOriginalValues.size() + m_channelOriginalValues.size())); // Compute index //CLOG(INFO,"montecarlo") << "[MPI]ChunkNum: " << chunkNum; if(m_channelOriginalValues[i] >= 0 && m_options.nDeviation != 0) // Skip not defined values (-999.999) { switch(m_options.nRandType) { case RandomType::KERNEL_DENSITY : std::cerr << "ERROR: N cannot be modeled by kernel density."; std::exit(-1); break; case RandomType::UNIFORM : // Lower and upper boundary of selected deviation // Mind limits given in options min = keepLimits(m_channelOriginalValues[i] - (m_channelOriginalValues[i] * m_options.nDeviation), m_options.nLimits); max = keepLimits(m_channelOriginalValues[i] + (m_channelOriginalValues[i] * m_options.nDeviation), m_options.nLimits); // Sample random value within computed boundaries //randomchannel.push_back(m_random->getRandDouble(min, max)); randomizedValuesChunk[chunkNum] = m_random->getRandDouble(min, max); break; case RandomType::NORMAL : { double mean = 0.0; double stddev = (m_channelOriginalValues[i] * 0.02) / 3; randomizedValuesChunk[chunkNum] = keepLimits(m_channelOriginalValues[i] + m_random->getRandDouble(mean, stddev), m_options.nLimits); } break; default: std::cerr << "ERROR: Bad random function, check random function options."; std::exit(-1); break; } } else { randomizedValuesChunk[chunkNum] = m_channelOriginalValues[i]; } } //m_channelValues.push_back(randomChannel); //randomChannel.clear(); // Subbasins for(size_t i = 0; i < m_subbasinOriginalValues.size(); ++i) { int chunkNum = i + m_channelOriginalValues.size() + ((mc % chunkSize) * (m_subbasinOriginalValues.size() + m_channelOriginalValues.size())); // Compute index if(m_subbasinOriginalValues[i] >= 0 && m_options.nDeviation != 0) // Skip not defined values (-999.999) { switch(m_options.nRandType) { case RandomType::KERNEL_DENSITY : std::cerr << "ERROR: N cannot be modeled by kernel density."; std::exit(-1); break; case RandomType::UNIFORM : // Lower and upper boundary of selected deviation // Mind limits given in options min = keepLimits(m_subbasinOriginalValues[i] - (m_subbasinOriginalValues[i] * m_options.nDeviation), m_options.nLimits); max = keepLimits(m_subbasinOriginalValues[i] + (m_subbasinOriginalValues[i] * m_options.nDeviation), m_options.nLimits); // Sample random value within computed boundaries //randomsubbasin.push_back(m_random->getRandDouble(min, max)); randomizedValuesChunk[chunkNum] = m_random->getRandDouble(min, max); break; case RandomType::NORMAL : { double mean = 0.0; double stddev = (m_subbasinOriginalValues[i] * 1.5) / 3; randomizedValuesChunk[chunkNum] = keepLimits(m_subbasinOriginalValues[i] + m_random->getRandDouble(mean, stddev), m_options.nLimits); } break; default: std::cerr << "ERROR: Bad random function, check random function options."; std::exit(-1); break; } } else { randomizedValuesChunk[chunkNum] = m_subbasinOriginalValues[i]; //randomSubbasin.push_back(m_subbasinOriginalValues[i]); } } //m_subbasinValues.push_back(randomSubbasin); //randomSubbasin.clear(); if(((mc+1) % chunkSize) == 0) // One chunk generated, send it to its process { if((mc+1) == chunkSize) // Keep first chunk to root process { //std::copy(&randomizedValuesChunk[0], &randomizedValuesChunk[(chunkSize-1)], std::back_inserter(m_subbasinValues)); //memcpy(randomizedValuesChunk, m_subbasinValuesChunk, chunkSize); for(size_t iter = 0; iter < chunkSize; ++iter) { std::vector<double> iterationBuffer; for(size_t ch = 0; ch < m_channelOriginalValues.size(); ++ch) { iterationBuffer.push_back(randomizedValuesChunk[ch + (iter * (m_subbasinOriginalValues.size() + m_channelOriginalValues.size()))]); } m_channelValues.push_back(iterationBuffer); iterationBuffer.clear(); for(size_t sub = 0; sub < m_subbasinOriginalValues.size(); ++sub) { iterationBuffer.push_back(randomizedValuesChunk[sub + m_channelOriginalValues.size() + (iter * (m_subbasinOriginalValues.size() + m_channelOriginalValues.size()))]); } m_subbasinValues.push_back(iterationBuffer); iterationBuffer.clear(); } CLOG(INFO,"montecarlo") << "[MPI]Root rank: Got " << m_subbasinValues.size() << " iterations in chunk"; } else { // Send chunk to its respective process //int slaveRank = (int) ((mc+1) / chunkSize); // Determine destination chunk CLOG(INFO,"montecarlo") << "[MPI]Sent chunk no." << mc/chunkSize << " to slave rank: " << slaveRank; MPI_Send(randomizedValuesChunk, valuesPerChunk, MPI_DOUBLE, slaveRank, m_tag, MPI_COMM_WORLD); // Increment slave rank to next process slaveRank++; } } } CLOG(INFO,"montecarlo") << "DONE."; } /* Receive values from slave */ if(rank > 0) { // Receive values from root MPI_Status mpiStat; MPI_Recv(randomizedValuesChunk, valuesPerChunk, MPI_DOUBLE , 0, m_tag, MPI_COMM_WORLD, &mpiStat); CLOG(INFO,"montecarlo") << "[MPI]Slave rank " << rank << ": Received chunk from " << mpiStat.MPI_SOURCE << slaveRank; // Copy received values to memeber vector std::vector<double> iterationBuffer; // Channels for(size_t iter = 0; iter < chunkSize; ++iter) { for(size_t ch = 0; ch < m_channelOriginalValues.size(); ++ch) { iterationBuffer.push_back(randomizedValuesChunk[ch + (iter * (m_subbasinOriginalValues.size() + m_channelOriginalValues.size()))]); } m_channelValues.push_back(iterationBuffer); iterationBuffer.clear(); for(size_t sub = 0; sub < m_subbasinOriginalValues.size(); ++sub) { iterationBuffer.push_back(randomizedValuesChunk[sub + m_channelOriginalValues.size() + (iter * (m_subbasinOriginalValues.size() + m_channelOriginalValues.size()))]); } m_subbasinValues.push_back(iterationBuffer); iterationBuffer.clear(); } iterationBuffer.clear(); // Print first element of each iteration in received chunk /*for(std::vector<std::vector<double>>::const_iterator it = m_subbasinValues.begin(); it != m_subbasinValues.end(); ++it) { CLOG(INFO,"montecarlo") << (*it).at(0); }*/ delete[] randomizedValuesChunk; } } }