#include "migration.h" #include "readfunc.h" #include "readword.h" #include "errorhandler.h" #include "mathfunc.h" #include "migrationarea.h" #include "gadget.h" #include "global.h" // ******************************************************** // Functions for base Migration // ******************************************************** Migration::Migration(const IntVector& Areas, const char* givenname) : HasName(givenname), LivesOnAreas(Areas) { if (areas.Size() == 1) handle.logMessage(LOGWARN, "Warning in migration - only one area defined"); } // ******************************************************** // Functions for MigrationNumbers // ******************************************************** MigrationNumbers::MigrationNumbers(CommentStream& infile, const IntVector& Areas, const AreaClass* const Area, const TimeClass* const TimeInfo, const char* givenname, Keeper* const keeper) : Migration(Areas, givenname) { int i, j; ifstream subfile; CommentStream subcomment(subfile); char text[MaxStrLength]; char filename[MaxStrLength]; strncpy(text, "", MaxStrLength); strncpy(filename, "", MaxStrLength); keeper->addString("migrationmatrix"); // Open and read year and step information readWordAndValue(infile, "yearstepfile", filename); subfile.open(filename, ios::in); handle.checkIfFailure(subfile, filename); handle.Open(filename); this->readTimeStepData(subcomment, TimeInfo); handle.Close(); subfile.close(); subfile.clear(); // Open and read information about how the matrices are defined infile >> text >> filename >> ws; subfile.open(filename, ios::in); handle.checkIfFailure(subfile, filename); handle.Open(filename); if (strcasecmp(text, "definematrices") == 0) { this->readGivenMatrices(subcomment, keeper); } else if (strcasecmp(text, "defineratios") == 0) { this->readGivenRatios(subcomment, keeper, Area); } else handle.logFileUnexpected(LOGFAIL, "definematrices or defineratios", text); handle.Close(); subfile.close(); subfile.clear(); this->checkMatrixIndex(); handle.logMessage(LOGMESSAGE, "Read migration numbers file - number of migration matrices", readMigration.Size()); keeper->clearLast(); } MigrationNumbers::~MigrationNumbers() { int i; for (i = 0; i < timeindex.Size(); i++) if (timeindex[i] != -1) delete[] allmatrixnames[i]; for (i = 0; i < usedmatrixnames.Size(); i++) { delete[] usedmatrixnames[i]; delete readMigration[i]; delete calcMigration[i]; } } void MigrationNumbers::readTimeStepData(CommentStream& infile, const TimeClass* const TimeInfo) { int year, step, timeid, count; char text[MaxStrLength]; strncpy(text, "", MaxStrLength); // check the number of columns in the inputfile infile >> ws; if (countColumns(infile) != 3) handle.logFileMessage(LOGFAIL, "wrong number of columns in inputfile - should be 3"); year = step = count = 0; allmatrixnames.resizeBlank(TimeInfo->numTotalSteps() + 1); timeindex.resize(TimeInfo->numTotalSteps() + 1, -1); while (!infile.eof()) { infile >> year >> step >> text >> ws; if (TimeInfo->isWithinPeriod(year, step)) { timeid = TimeInfo->calcSteps(year, step); timeindex[timeid] = 0; allmatrixnames[timeid] = new char[strlen(text) + 1]; strcpy(allmatrixnames[timeid], text); count++; } } if (count == 0) handle.logMessage(LOGWARN, "Warning in migration - found no migration data"); if (count != TimeInfo->numTotalSteps()) handle.logMessage(LOGWARN, "Warning in migration - migration data doesnt span time range"); handle.logMessage(LOGMESSAGE, "Read migration time data - number of entries", count); } void MigrationNumbers::readGivenRatios(CommentStream& infile, Keeper* const keeper, const AreaClass* const Area) { int innerrow, innercol, fromArea, toArea; int i, j, k, count; int numAreas = areas.Size(); char text[MaxStrLength]; char name[MaxStrLength]; strncpy(text, "", MaxStrLength); strncpy(name, "", MaxStrLength); /* File format: [migrationmatrix] name matrixname fromarea toarea ratio [migrationmatrix] ... */ toArea = fromArea = 0; // Read ratio information from file while (!infile.eof() && !infile.fail()) { infile >> text >> ws; if (strcasecmp(text, "[migrationmatrix]") != 0) handle.logFileUnexpected(LOGFAIL, "[migrationmatrix]", text); readWordAndValue(infile, "name", name); if (this->useMatrix(name)) { this->setMatrixName(name); count = readMigration.Size(); checkvalues.AddRows(1, numAreas, 0); readMigration.resize(new FormulaMatrix(numAreas, numAreas, 0.0)); infile >> ws; while (!infile.eof() && !infile.fail() && (infile.peek() != '[')) { if (!(isdigit(infile.peek()))) { infile >> text >> ws; handle.logFileUnexpected(LOGFAIL, "[migrationmatrix] or area number", text); } infile >> fromArea >> toArea >> ws; innerrow = Area->getInnerArea(toArea); innercol = Area->getInnerArea(fromArea); if (!this->isInArea(innerrow) || !this->isInArea(innercol)) handle.logMessage(LOGFAIL, "Error in migration - invalid area for matrix", name); toArea = this->areaNum(innerrow); fromArea = this->areaNum(innercol); infile >> (*readMigration[count])[toArea][fromArea] >> ws; checkvalues[count][fromArea]++; } } else { handle.logMessage(LOGWARN, "Warning in migration - matrix not used in the simulation", name); infile >> ws; while (!infile.eof() && !infile.fail() && infile.peek() != '[') infile >> text >> ws; } } // Finished reading from file, now check the values Formula missing; missing.setValue(1.0); for (i = 0; i < readMigration.Size(); i++) { for (j = 0; j < readMigration[i]->Nrow(); j++) { if (checkvalues[i][j] == 0) { // no data read for migration from this area (*readMigration[i])[j][j].setValue(1.0); } else if (checkvalues[i][j] == numAreas) { // nothing to do - data read for migration from this area to every other area } else if (isZero((*readMigration[i])[j][j])) { // read data for migration from this area to other areas // so simply subtract the migration from 1 to find those that are left count = 0; vector checklist; for (k = 0; k < readMigration[i]->Ncol(); k++) { if (!(isZero((*readMigration[i])[k][j]))) { checklist.push_back(&(*readMigration[i])[k][j]); count++; } } if (count == 0) handle.logFileMessage(LOGFAIL, "missing data for migration matrix", usedmatrixnames[i]); checklist.insert(checklist.begin(), &missing); Formula* missingValue = new Formula(MINUS, checklist); (*readMigration[i])[j][j] = *missingValue; delete missingValue; } else if (checkvalues[i][j] == (numAreas - 1)) { // read migration data from this area to all other areas but 1 count = -1; vector checklist; for (k = 0; k < readMigration[i]->Ncol(); k++) { if (isZero((*readMigration[i])[k][j])) count = k; else checklist.push_back(&(*readMigration[i])[k][j]); } if (count == -1) handle.logFileMessage(LOGFAIL, "missing data for migration matrix", usedmatrixnames[i]); checklist.insert(checklist.begin(), &missing); Formula* missingValue = new Formula(MINUS, checklist); (*readMigration[i])[count][j] = *missingValue; delete missingValue; } else { // havent read enough information to reliably construct matrix handle.logFileMessage(LOGFAIL, "missing data for migration matrix", usedmatrixnames[i]); } } } // Inform keeper of the values and resize for (i = 0; i < readMigration.Size(); i++) { (*readMigration[i]).Inform(keeper); calcMigration.resize(new DoubleMatrix(numAreas, numAreas, 0.0)); } } void MigrationNumbers::readGivenMatrices(CommentStream& infile, Keeper* const keeper) { int i, j, count; int numAreas = areas.Size(); char text[MaxStrLength]; char name[MaxStrLength]; strncpy(text, "", MaxStrLength); strncpy(name, "", MaxStrLength); /* File format: [migrationmatrix] name matrixname x11 ... x1n ... xn1 ... xnn [migrationmatrix] ... */ // Read matrix information from file while (!infile.eof() && !infile.fail()) { infile >> text >> ws; if (strcasecmp(text, "[migrationmatrix]") != 0) handle.logFileUnexpected(LOGFAIL, "[migrationmatrix]", text); readWordAndValue(infile, "name", name); if (this->useMatrix(name)) { this->setMatrixName(name); count = readMigration.Size(); readMigration.resize(new FormulaMatrix(numAreas, numAreas, 0.0)); infile >> ws; if (infile.peek() == '[' || infile.eof()) { for (i = 0; i < numAreas; i++) (*readMigration[count])[i][i].setValue(1.0); } else if (isdigit(infile.peek()) || infile.peek() == '#' || infile.peek() == '(') { // look for a number or a formula as the next entry to be read for (i = 0; i < numAreas; i++) for (j = 0; j < numAreas; j++) if (!(infile >> (*readMigration[count])[i][j])) handle.logMessage(LOGFAIL, "Error in migration - failed to read matrix", name); infile >> ws; //JMB strip whitespace } else { infile >> text; handle.logFileUnexpected(LOGFAIL, "[migrationmatrix] or matrix value", text); } } else { handle.logMessage(LOGWARN, "Warning in migration - matrix not used in the simulation", name); infile >> ws; while (!infile.eof() && !infile.fail() && infile.peek() != '[') infile >> text >> ws; } } // Inform keeper of the values and resize for (i = 0; i < readMigration.Size(); i++) { (*readMigration[i]).Inform(keeper); calcMigration.resize(new DoubleMatrix(numAreas, numAreas, 0.0)); } } void MigrationNumbers::checkMatrixIndex() { int i, j, check; for (i = 0; i < timeindex.Size(); i++) { if (timeindex[i] == 0) { check = -1; for (j = 0; j < usedmatrixnames.Size(); j++) if (strcasecmp(allmatrixnames[i], usedmatrixnames[j]) == 0) check = j; if (check == -1) handle.logMessage(LOGFAIL, "Error in migration - failed to read matrix", allmatrixnames[i]); timeindex[i] = check; } else if (timeindex[i] != -1) { handle.logMessage(LOGFAIL, "Error in migration - repeated migration matrix", i); } } } void MigrationNumbers::Print(ofstream& outfile) { int i, j, k; outfile << "\nMigration\n\tNames of migration matrices:\n\t"; for (i = 0; i < timeindex.Size(); i++) if (timeindex[i] != -1) outfile << allmatrixnames[i] << sep; outfile << "\n\n\tMigration matrices"; for (i = 0; i < calcMigration.Size(); i++) { outfile << "\n\tMatrix name: " << usedmatrixnames[i] << "\n\t"; for (j = 0; j < calcMigration[i]->Nrow(); j++) { for (k = 0; k < calcMigration[i]->Ncol(j); k++) outfile << setw(smallwidth) << (*calcMigration[i])[j][k] << sep; outfile << "\n\t"; } } outfile.flush(); } const DoubleMatrix& MigrationNumbers::getMigrationMatrix(const TimeClass* const TimeInfo) { return (*calcMigration[timeindex[TimeInfo->getTime()]]); } void MigrationNumbers::setMatrixName(char* name) { int i; // check to ensure that this matrix name is unique for (i = 0; i < usedmatrixnames.Size(); i++) if (strcasecmp(usedmatrixnames[i], name) == 0) handle.logMessage(LOGFAIL, "Error in migration - repeated matrix", name); // store the new matrix name char* tempname = new char[strlen(name) + 1]; strcpy(tempname, name); usedmatrixnames.resize(tempname); } void MigrationNumbers::Reset() { //JMB need to reset the penalty vector first penalty.Reset(); int i, j, k; double colsum; for (i = 0; i < readMigration.Size(); i++) { for (k = 0; k < readMigration[i]->Ncol(); k++) { colsum = 0.0; for (j = 0; j < readMigration[i]->Nrow(); j++) { if (isZero((*readMigration[i])[j][k])) { (*calcMigration[i])[j][k] = 0.0; } else if ((*readMigration[i])[j][k] < 0.0) { penalty.resize(1, (*readMigration[i])[j][k]); (*calcMigration[i])[j][k] = 0.0; handle.logMessage(LOGWARN, "Warning in migration - value outside bounds", (*readMigration[i])[j][k]); } else if ((*readMigration[i])[j][k] > 1.0) { penalty.resize(1, (*readMigration[i])[j][k]); (*calcMigration[i])[j][k] = 1.0; handle.logMessage(LOGWARN, "Warning in migration - value outside bounds", (*readMigration[i])[j][k]); } else (*calcMigration[i])[j][k] = (*readMigration[i])[j][k]; colsum += (*calcMigration[i])[j][k]; } if (isZero(colsum)) { handle.logMessage(LOGWARN, "Warning in migration - column sum is zero"); // just putting anything here ... AJ 23.06.05, Needs to be changed!!!!! penalty.resize(1, 1.0); for (j = 0; j < readMigration[i]->Nrow(); j++) { if (k == j) (*calcMigration[i])[j][k] = 1.0; else (*calcMigration[i])[j][k] = 0.0; } } else if (isEqual(colsum, 1.0)) { // everything is OK ... } else { penalty.resize(1, colsum); colsum = 1.0 / colsum; for (j = 0; j < readMigration[i]->Nrow(); j++) (*calcMigration[i])[j][k] *= colsum; } } } if (handle.getLogLevel() >= LOGMESSAGE) handle.logMessage(LOGMESSAGE, "Reset migration data for stock", this->getName()); } int MigrationNumbers::useMatrix(char* name) { int i; for (i = 0; i < timeindex.Size(); i++) if ((timeindex[i] != -1) && (strcasecmp(allmatrixnames[i], name) == 0)) return 1; return 0; } int MigrationNumbers::isMigrationStep(const TimeClass* const TimeInfo) { if (timeindex[TimeInfo->getTime()] == -1) return 0; return 1; } // ******************************************************** // Functions for MigrationFunction // ******************************************************** MigrationFunction::MigrationFunction(CommentStream& infile, const IntVector& Areas, const AreaClass* const Area, const TimeClass* const TimeInfo, const char* givenname, Keeper* const keeper) : Migration(Areas, givenname) { int i; ifstream subfile; CommentStream subcomment(subfile); char text[MaxStrLength]; char filename[MaxStrLength]; strncpy(text, "", MaxStrLength); strncpy(filename, "", MaxStrLength); keeper->addString("migrationfunction"); readWordAndModelVariable(infile, "diffusion", diffusion, TimeInfo, keeper); readWordAndModelVariable(infile, "driftx", driftx, TimeInfo, keeper); readWordAndModelVariable(infile, "drifty", drifty, TimeInfo, keeper); readWordAndVariable(infile, "lambda", lambda); delta = TimeInfo->getTimeStepLength() / TimeInfo->numSubSteps(); // Open and read given year and step information readWordAndValue(infile, "areadefinition", filename); subfile.open(filename, ios::in); handle.checkIfFailure(subfile, filename); handle.Open(filename); this->readAreaData(subcomment, Area, TimeInfo, keeper); handle.Close(); subfile.close(); subfile.clear(); calcMigration.AddRows(oceanareas.Size(), oceanareas.Size(), 0.0); if (oceanareas.Size() != areas.Size()) handle.logMessage(LOGWARN, "Warning in migration - migration data doesnt cover all areas"); handle.logMessage(LOGMESSAGE, "Read migration function file - number of migration areas", oceanareas.Size()); keeper->clearLast(); } void MigrationFunction::readAreaData(CommentStream& infile, const AreaClass* const Area, const TimeClass* const TimeInfo, Keeper* const keeper) { int area, inarea; ifstream subfile; CommentStream subcomment(subfile); char text[MaxStrLength]; char filename[MaxStrLength]; char areaname[MaxStrLength]; strncpy(text, "", MaxStrLength); strncpy(filename, "", MaxStrLength); strncpy(areaname, "", MaxStrLength); /* File format: [area] name areaname number areanumber rectangles filename containing the rectangle information [area] ... */ // Read area information from file infile >> ws; while (!infile.eof() && !infile.fail()) { infile >> text >> ws; if (strcasecmp(text, "[area]") != 0) handle.logFileUnexpected(LOGFAIL, "[area]", text); readWordAndValue(infile, "name", areaname); readWordAndVariable(infile, "number", area); readWordAndValue(infile, "rectangles", filename); inarea = Area->getInnerArea(area); if (!this->isInArea(inarea)) handle.logMessage(LOGFAIL, "Error in migration - invalid area", area); subfile.open(filename, ios::in); handle.checkIfFailure(subfile, filename); handle.Open(filename); oceanareas.resize(new MigrationArea(subcomment, areaname, inarea)); handle.Close(); subfile.close(); subfile.clear(); } } MigrationFunction::~MigrationFunction() { int i; for (i = 0; i < oceanareas.Size(); i++) delete oceanareas[i]; } void MigrationFunction::Print(ofstream& outfile) { int i, j; outfile << "\nMigration\n\n\tMigration matrix\n\t"; for (i = 0; i < calcMigration.Nrow(); i++) { for (j = 0; j < calcMigration.Ncol(i); j++) outfile << setw(smallwidth) << calcMigration[i][j] << sep; outfile << "\n\t"; } outfile.flush(); } const DoubleMatrix& MigrationFunction::getMigrationMatrix(const TimeClass* const TimeInfo) { if (this->updateVariables(TimeInfo)) this->recalcMatrix(); return calcMigration; } void MigrationFunction::recalcMatrix() { int from, to, idfrom, idto, i, j; double mig, sa; double colsum, sum; for (from = 0; from < oceanareas.Size(); from++) { idfrom = this->areaNum(oceanareas[from]->getAreaID()); colsum = 0.0; for (to = 0; to < oceanareas.Size(); to++) { idto = this->areaNum(oceanareas[to]->getAreaID()); sum = 0.0; for (i = 0; i < oceanareas[from]->getNumRectangles(); i++) { sa = (oceanareas[from]->getRectangles()[i])->getArea(); if (!(isZero(sa))) { for (j = 0; j < oceanareas[to]->getNumRectangles(); j++) { mig = this->getMigrationFunction(oceanareas[from]->getRectangles()[i], oceanareas[to]->getRectangles()[j]); sum += (mig * sa); } } } calcMigration[idto][idfrom] = sum / oceanareas[from]->getArea(); colsum += calcMigration[idto][idfrom]; } if (isZero(colsum)) { handle.logMessage(LOGWARN, "Warning in migration - column sum is zero"); penalty.resize(1, 1.0); calcMigration[idfrom][idfrom] = 1.0; } else if (isEqual(colsum, 1.0)) { // everything is OK ... } else { handle.logMessage(LOGWARN, "Warning in migration - column sum", colsum); penalty.resize(1, colsum); colsum = 1.0 / colsum; for (i = 0; i < calcMigration.Ncol(); i++) calcMigration[i][idfrom] *= colsum; } } } void MigrationFunction::Reset() { //JMB need to reset the penalty vector penalty.Reset(); if (handle.getLogLevel() >= LOGMESSAGE) handle.logMessage(LOGMESSAGE, "Reset migration data for stock", this->getName()); } int MigrationFunction::isMigrationStep(const TimeClass* const TimeInfo) { return 1; } int MigrationFunction::updateVariables(const TimeClass* const TimeInfo) { //update the values of the variables that can change delta = TimeInfo->getTimeStepLength() / TimeInfo->numSubSteps(); diffusion.Update(TimeInfo); driftx.Update(TimeInfo); drifty.Update(TimeInfo); if ((TimeInfo->didStepSizeChange()) || (diffusion.didChange(TimeInfo)) || (driftx.didChange(TimeInfo)) || (drifty.didChange(TimeInfo))) return 1; return 0; } double MigrationFunction::getMigrationFunction(Rectangle* fromRec, Rectangle* toRec) { double fx, fy; double dx, dy; double xiL, yiL, xiU, yiU; double xfL, yfL, xfU, yfU; if (isZero(diffusion) || isZero(lambda)) // prevent divide by zero errors ... return 0.0; xiL = fromRec->getLowerX(); yiL = fromRec->getLowerY(); xiU = fromRec->getUpperX(); yiU = fromRec->getUpperY(); xfL = toRec->getLowerX(); yfL = toRec->getLowerY(); xfU = toRec->getUpperX(); yfU = toRec->getUpperY(); dx = delta * diffusion; dy = dx * lambda; // functions from Violeta ... fx = -f1x(xfU,xiU,dx,driftx) + f1x(xfU,xiL,dx,driftx) + f1x(xfL,xiU,dx,driftx) - f1x(xfL,xiL,dx,driftx) - f2x(xfU,xiU,dx,driftx) + f2x(xfU,xiL,dx,driftx) + f2x(xfL,xiU,dx,driftx) - f2x(xfL,xiL,dx,driftx); if (fx < verysmall) return 0.0; fy = -f1x(yfU,yiU,dy,drifty) + f1x(yfU,yiL,dy,drifty) + f1x(yfL,yiU,dy,drifty) - f1x(yfL,yiL,dy,drifty) - f2x(yfU,yiU,dy,drifty) + f2x(yfU,yiL,dy,drifty) + f2x(yfL,yiU,dy,drifty) - f2x(yfL,yiL,dy,drifty); if (fy < verysmall) return 0.0; return (0.5 * fx * fy); } double MigrationFunction::f1x(double w, double u, double D, double beta) { return ((2/sqrt(pivalue))*sqrt(D)*exp(-(w-(beta*delta)-u)*(w-(beta*delta)-u)/(4*D))); } double MigrationFunction::f2x(double w, double u, double D, double beta) { return ((w-(beta*delta)-u)*erf((w-(beta*delta)-u)/(2*sqrt(D)))); }