X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=distancecommand.cpp;h=c615b8068ae1576b07f2e64a2742bfcb36e3e9b3;hb=9c23307c583d4e8595f75278c13e708788f2f058;hp=67b87f10e21ab5524a090241e442b388c03306aa;hpb=bede5752eaeedb5a7e339439b6ba2f6670bca2b9;p=mothur.git diff --git a/distancecommand.cpp b/distancecommand.cpp index 67b87f1..c615b80 100644 --- a/distancecommand.cpp +++ b/distancecommand.cpp @@ -16,99 +16,174 @@ //********************************************************************************************************************** -DistanceCommand::DistanceCommand(){ +DistanceCommand::DistanceCommand(string option){ try { - globaldata = GlobalData::getInstance(); - validCalculator = new ValidCalculators(); - countends = globaldata->getCountEnds(); - convert(globaldata->getProcessors(), processors); - convert(globaldata->getCutOff(), cutoff); - phylip = globaldata->getPhylipFile(); + abort = false; + Estimators.clear(); - //open file - string filename = globaldata->getFastaFile(); - openInputFile(filename, in); + //allow user to run help + if(option == "help") { help(); abort = true; } - + else { + //valid paramters for this command + string Array[] = {"fasta", "output", "calc", "countends", "cutoff", "processors", "outputdir","inputdir"}; + vector myArray (Array, Array+(sizeof(Array)/sizeof(string))); + + OptionParser parser(option); + map parameters = parser.getParameters(); + + ValidParameters validParameter; + map::iterator it2; - int i; - if (isTrue(countends) == true) { - for (i=0; iEstimators.size(); i++) { - if (validCalculator->isValidCalculator("distance", globaldata->Estimators[i]) == true) { - if (globaldata->Estimators[i] == "nogaps") { - distCalculator = new ignoreGaps(); - }else if (globaldata->Estimators[i] == "eachgap") { - distCalculator = new eachGapDist(); - }else if (globaldata->Estimators[i] == "onegap") { - distCalculator = new oneGapDist(); } + //check to make sure all parameters are valid for command + for (it2 = parameters.begin(); it2 != parameters.end(); it2++) { + if (validParameter.isValidParameter(it2->first, myArray, it2->second) != true) { abort = true; } + } + + //if the user changes the input directory command factory will send this info to us in the output parameter + string inputDir = validParameter.validFile(parameters, "inputdir", false); + if (inputDir == "not found"){ inputDir = ""; } + else { + string path; + it2 = parameters.find("fasta"); + //user has given a template file + if(it2 != parameters.end()){ + path = hasPath(it2->second); + //if the user has not given a path then, add inputdir. else leave path alone. + if (path == "") { parameters["fasta"] = inputDir + it2->second; } } } - }else { - for (i=0; iEstimators.size(); i++) { - if (validCalculator->isValidCalculator("distance", globaldata->Estimators[i]) == true) { - if (globaldata->Estimators[i] == "nogaps") { - distCalculator = new ignoreGaps(); - }else if (globaldata->Estimators[i] == "eachgap") { - distCalculator = new eachGapIgnoreTermGapDist(); - }else if (globaldata->Estimators[i] == "onegap") { - distCalculator = new oneGapIgnoreTermGapDist(); + + //check for required parameters + fastafile = validParameter.validFile(parameters, "fasta", true); + if (fastafile == "not found") { mothurOut("fasta is a required parameter for the dist.seqs command."); mothurOutEndLine(); abort = true; } + else if (fastafile == "not open") { abort = true; } + else{ + ifstream inFASTA; + openInputFile(fastafile, inFASTA); + alignDB = SequenceDB(inFASTA); + inFASTA.close(); + } + + //if the user changes the output directory command factory will send this info to us in the output parameter + outputDir = validParameter.validFile(parameters, "outputdir", false); if (outputDir == "not found"){ + outputDir = ""; + outputDir += hasPath(fastafile); //if user entered a file with a path then preserve it + } + + //check for optional parameter and set defaults + // ...at some point should added some additional type checking... + calc = validParameter.validFile(parameters, "calc", false); + if (calc == "not found") { calc = "onegap"; } + else { + if (calc == "default") { calc = "onegap"; } + } + splitAtDash(calc, Estimators); + + string temp; + temp = validParameter.validFile(parameters, "countends", false); if(temp == "not found"){ temp = "T"; } + convert(temp, countends); + + temp = validParameter.validFile(parameters, "cutoff", false); if(temp == "not found"){ temp = "1.0"; } + convert(temp, cutoff); + + temp = validParameter.validFile(parameters, "processors", false); if(temp == "not found"){ temp = "1"; } + convert(temp, processors); + + output = validParameter.validFile(parameters, "output", false); if(output == "not found"){ output = "column"; } + + if ((output != "column") && (output != "lt") && (output != "square")) { mothurOut(output + " is not a valid output form. Options are column, lt and square. I will use column."); mothurOutEndLine(); output = "column"; } + + ValidCalculators validCalculator; + + if (isTrue(countends) == true) { + for (int i=0; isetCalc(""); + } catch(exception& e) { - cout << "Standard Error: " << e.what() << " has occurred in the DistanceCommand class Function DistanceCommand. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; + errorOut(e, "DistanceCommand", "DistanceCommand"); exit(1); } - catch(...) { - cout << "An unknown error has occurred in the DistanceCommand class function DistanceCommand. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; +} + +//********************************************************************************************************************** + +DistanceCommand::~DistanceCommand(){ + + for(int i=0;iend = int (sqrt(float(i+1)/float(processors)) * numSeqs); } - cout << lines[0]->start << '\t' << lines[0]->end << endl; - cout << lines[1]->start << '\t' << lines[1]->end << endl; - createProcesses(outputFile); + map::iterator it = processIDS.begin(); + rename((outputFile + toString(it->second) + ".temp").c_str(), outputFile.c_str()); + it++; + //append and remove temp files - for (it = processIDS.begin(); it != processIDS.end(); it++) { + for (; it != processIDS.end(); it++) { appendFiles((outputFile + toString(it->second) + ".temp"), outputFile); remove((outputFile + toString(it->second) + ".temp").c_str()); } } #else - driver(distCalculator, seqDB, 0, numSeqs, outputFile + ".temp", cutoff); - appendFiles((outputFile + ".temp"), outputFile); - remove((outputFile + ".temp").c_str()); + ifstream inFASTA; + driver(0, numSeqs, outputFile, cutoff); #endif + if (output == "square") { convertMatrix(outputFile); } + delete distCalculator; return 0; } catch(exception& e) { - cout << "Standard Error: " << e.what() << " has occurred in the DistanceCommand class Function execute. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; + errorOut(e, "DistanceCommand", "execute"); exit(1); } - catch(...) { - cout << "An unknown error has occurred in the DistanceCommand class function execute. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; - exit(1); - } } /**************************************************************************************************/ void DistanceCommand::createProcesses(string filename) { try { +#if defined (__APPLE__) || (__MACH__) || (linux) || (__linux) int process = 0; processIDS.clear(); @@ -162,31 +236,27 @@ void DistanceCommand::createProcesses(string filename) { processIDS[lines[process]->end] = pid; //create map from line number to pid so you can append files in correct order later process++; }else if (pid == 0){ - driver(distCalculator, seqDB, lines[process]->start, lines[process]->end, filename + toString(getpid()) + ".temp", cutoff); + driver(lines[process]->start, lines[process]->end, filename + toString(getpid()) + ".temp", cutoff); exit(0); - }else { cout << "unable to spawn the necessary processes." << endl; exit(0); } + }else { mothurOut("unable to spawn the necessary processes."); mothurOutEndLine(); exit(0); } } //force parent to wait until all the processes are done - for (it = processIDS.begin(); it != processIDS.end(); it++) { + for (map::iterator it = processIDS.begin(); it != processIDS.end(); it++) { int temp = it->second; wait(&temp); } - +#endif } catch(exception& e) { - cout << "Standard Error: " << e.what() << " has occurred in the DistanceCommand class Function createProcesses. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; + errorOut(e, "DistanceCommand", "createProcesses"); exit(1); } - catch(...) { - cout << "An unknown error has occurred in the DistanceCommand class function createProcesses. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; - exit(1); - } } /**************************************************************************************************/ /////// need to fix to work with calcs and sequencedb -int DistanceCommand::driver(Dist* distCalculator, SequenceDB* align, int startLine, int endLine, string dFileName, float cutoff){ +int DistanceCommand::driver(int startLine, int endLine, string dFileName, float cutoff){ try { int startTime = time(NULL); @@ -196,45 +266,135 @@ int DistanceCommand::driver(Dist* distCalculator, SequenceDB* align, int startLi outFile.setf(ios::fixed, ios::showpoint); outFile << setprecision(4); + if((output == "lt") && startLine == 0){ outFile << alignDB.getNumSeqs() << endl; } + for(int i=startLine;icalcDist(*(align->get(i)), *(align->get(j))); + distCalculator->calcDist(alignDB.get(i), alignDB.get(j)); double dist = distCalculator->getDist(); if(dist <= cutoff){ - if (isTrue(phylip) != true) { outFile << align->get(i)->getName() << ' ' << align->get(j)->getName() << ' ' << dist << endl; } + if (output == "column") { outFile << alignDB.get(i).getName() << ' ' << alignDB.get(j).getName() << ' ' << dist << endl; } } - if (isTrue(phylip) == true) { outFile << dist << '\t'; } + if (output == "lt") { outFile << dist << '\t'; } + if (output == "square") { //make a square column you can convert to square phylip + outFile << alignDB.get(i).getName() << '\t' << alignDB.get(j).getName() << '\t' << dist << endl; + outFile << alignDB.get(j).getName() << '\t' << alignDB.get(i).getName() << '\t' << dist << endl; + } + } - if (isTrue(phylip) == true) { outFile << endl; } + if (output == "lt") { outFile << endl; } if(i % 100 == 0){ - cout << i << '\t' << time(NULL) - startTime << endl; + mothurOut(toString(i) + "\t" + toString(time(NULL) - startTime)); mothurOutEndLine(); } } - cout << endLine-1 << '\t' << time(NULL) - startTime << endl; + mothurOut(toString(endLine-1) + "\t" + toString(time(NULL) - startTime)); mothurOutEndLine(); - //philFile.close(); - //distFile.close(); + outFile.close(); return 1; } catch(exception& e) { - cout << "Standard Error: " << e.what() << " has occurred in the DistanceCommand class Function driver. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; + errorOut(e, "DistanceCommand", "driver"); exit(1); } - catch(...) { - cout << "An unknown error has occurred in the DistanceCommand class function driver. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; - exit(1); - } - } - /**************************************************************************************************/ +void DistanceCommand::convertMatrix(string outputFile) { + try{ + + //sort file by first column so the distances for each row are together + string outfile = getRootName(outputFile) + "sorted.dist.temp"; + + //use the unix sort + #if defined (__APPLE__) || (__MACH__) || (linux) || (__linux) + string command = "sort -n " + outputFile + " -o " + outfile; + system(command.c_str()); + #else //sort using windows sort + string command = "sort " + outputFile + " /O " + outfile; + system(command.c_str()); + #endif + + + //output to new file distance for each row and save positions in file where new row begins + ifstream in; + openInputFile(outfile, in); + + ofstream out; + openOutputFile(outputFile, out); + + out.setf(ios::fixed, ios::floatfield); out.setf(ios::showpoint); + + out << alignDB.getNumSeqs() << endl; + + //get first currentRow + string first, currentRow, second; + float dist; + map rowDists; //take advantage of the fact that maps are already sorted by key + map::iterator it; + + in >> first; + currentRow = first; + + rowDists[first] = 0.00; //distance to yourself is 0.0 + + in.seekg(0); + //openInputFile(outfile, in); + + while(!in.eof()) { + in >> first >> second >> dist; gobble(in); + + if (first != currentRow) { + //print out last row + out << currentRow << '\t'; //print name + + //print dists + for (it = rowDists.begin(); it != rowDists.end(); it++) { + out << it->second << '\t'; + } + out << endl; + + //start new row + currentRow = first; + rowDists.clear(); + rowDists[first] = 0.00; + rowDists[second] = dist; + }else{ + rowDists[second] = dist; + } + } + //print out last row + out << currentRow << '\t'; //print name + + //print dists + for (it = rowDists.begin(); it != rowDists.end(); it++) { + out << it->second << '\t'; + } + out << endl; + + in.close(); + out.close(); + + remove(outfile.c_str()); + + } + catch(exception& e) { + errorOut(e, "DistanceCommand", "convertMatrix"); + exit(1); + } +} +/************************************************************************************************** void DistanceCommand::appendFiles(string temp, string filename) { try{ ofstream output; @@ -242,29 +402,21 @@ void DistanceCommand::appendFiles(string temp, string filename) { //open output file in append mode openOutputFileAppend(filename, output); - - //open temp file for reading openInputFile(temp, input); - string line; - //read input file and write to output file - while(input.eof() != true) { - getline(input, line); //getline removes the newline char - if (line != "") { - output << line << endl; // Appending back newline char - } - } + while(char c = input.get()){ + if(input.eof()) { break; } + else { output << c; } + } input.close(); output.close(); } catch(exception& e) { - cout << "Standard Error: " << e.what() << " has occurred in the DistanceCommand class Function appendFiles. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; + errorOut(e, "DistanceCommand", "appendFiles"); exit(1); } - catch(...) { - cout << "An unknown error has occurred in the DistanceCommand class function appendFiles. Please contact Pat Schloss at pschloss@microbio.umass.edu." << "\n"; - exit(1); - } } -/**************************************************************************************************/ \ No newline at end of file +/**************************************************************************************************/ + +