5 * Created by westcott on 12/11/09.
6 * Copyright 2009 Schloss Lab. All rights reserved.
10 #include "mgclustercommand.h"
12 //**********************************************************************************************************************
13 vector<string> MGClusterCommand::setParameters(){
15 CommandParameter pblast("blast", "InputTypes", "", "", "none", "none", "none",false,true); parameters.push_back(pblast);
16 CommandParameter pname("name", "InputTypes", "", "", "none", "none", "none",false,false); parameters.push_back(pname);
17 CommandParameter plength("length", "Number", "", "5", "", "", "",false,false); parameters.push_back(plength);
18 CommandParameter ppenalty("penalty", "Number", "", "0.10", "", "", "",false,false); parameters.push_back(ppenalty);
19 CommandParameter pcutoff("cutoff", "Number", "", "0.70", "", "", "",false,false); parameters.push_back(pcutoff);
20 CommandParameter pprecision("precision", "Number", "", "100", "", "", "",false,false); parameters.push_back(pprecision);
21 CommandParameter pmethod("method", "Multiple", "furthest-nearest-average", "average", "", "", "",false,false); parameters.push_back(pmethod);
22 CommandParameter phard("hard", "Boolean", "", "T", "", "", "",false,false); parameters.push_back(phard);
23 CommandParameter pmin("min", "Boolean", "", "T", "", "", "",false,false); parameters.push_back(pmin);
24 CommandParameter pmerge("merge", "Boolean", "", "T", "", "", "",false,false); parameters.push_back(pmerge);
25 CommandParameter phcluster("hcluster", "Boolean", "", "F", "", "", "",false,false); parameters.push_back(phcluster);
26 CommandParameter pinputdir("inputdir", "String", "", "", "", "", "",false,false); parameters.push_back(pinputdir);
27 CommandParameter poutputdir("outputdir", "String", "", "", "", "", "",false,false); parameters.push_back(poutputdir);
29 vector<string> myArray;
30 for (int i = 0; i < parameters.size(); i++) { myArray.push_back(parameters[i].name); }
34 m->errorOut(e, "MGClusterCommand", "setParameters");
38 //**********************************************************************************************************************
39 string MGClusterCommand::getHelpString(){
41 string helpString = "";
42 helpString += "The mgcluster command parameter options are blast, name, cutoff, precision, hard, method, merge, min, length, penalty and hcluster. The blast parameter is required.\n";
43 helpString += "The mgcluster command reads a blast and name file and clusters the sequences into OPF units similiar to the OTUs.\n";
44 helpString += "This command outputs a .list, .rabund and .sabund file that can be used with mothur other commands to estimate richness.\n";
45 helpString += "The cutoff parameter is used to specify the maximum distance you would like to cluster to. The default is 0.70.\n";
46 helpString += "The precision parameter's default value is 100. \n";
47 helpString += "The acceptable mgcluster methods are furthest, nearest and average. If no method is provided then average is assumed.\n";
48 helpString += "The min parameter allows you to specify is you want the minimum or maximum blast score ratio used in calculating the distance. The default is true, meaning you want the minimum.\n";
49 helpString += "The length parameter is used to specify the minimum overlap required. The default is 5.\n";
50 helpString += "The penalty parameter is used to adjust the error rate. The default is 0.10.\n";
51 helpString += "The merge parameter allows you to shut off merging based on overlaps and just cluster. By default merge is true, meaning you want to merge.\n";
52 helpString += "The hcluster parameter allows you to use the hcluster algorithm when clustering. This may be neccessary if your file is too large to fit into RAM. The default is false.\n";
53 helpString += "The mgcluster command should be in the following format: \n";
54 helpString += "mgcluster(blast=yourBlastfile, name=yourNameFile, cutoff=yourCutOff).\n";
55 helpString += "Note: No spaces between parameter labels (i.e. balst), '=' and parameters (i.e.yourBlastfile).\n";
59 m->errorOut(e, "MGClusterCommand", "getHelpString");
63 //**********************************************************************************************************************
64 MGClusterCommand::MGClusterCommand(){
66 abort = true; calledHelp = true;
68 vector<string> tempOutNames;
69 outputTypes["list"] = tempOutNames;
70 outputTypes["rabund"] = tempOutNames;
71 outputTypes["sabund"] = tempOutNames;
74 m->errorOut(e, "MGClusterCommand", "MGClusterCommand");
78 //**********************************************************************************************************************
79 MGClusterCommand::MGClusterCommand(string option) {
81 abort = false; calledHelp = false;
83 //allow user to run help
84 if(option == "help") { help(); abort = true; calledHelp = true; }
85 else if(option == "citation") { citation(); abort = true; calledHelp = true;}
88 vector<string> myArray = setParameters();
90 OptionParser parser(option);
91 map<string, string> parameters = parser.getParameters();
93 ValidParameters validParameter;
94 map<string,string>::iterator it;
96 //check to make sure all parameters are valid for command
97 for (it = parameters.begin(); it != parameters.end(); it++) {
98 if (validParameter.isValidParameter(it->first, myArray, it->second) != true) { abort = true; }
101 //initialize outputTypes
102 vector<string> tempOutNames;
103 outputTypes["list"] = tempOutNames;
104 outputTypes["rabund"] = tempOutNames;
105 outputTypes["sabund"] = tempOutNames;
107 //if the user changes the input directory command factory will send this info to us in the output parameter
108 string inputDir = validParameter.validFile(parameters, "inputdir", false);
109 if (inputDir == "not found"){ inputDir = ""; }
112 it = parameters.find("blast");
113 //user has given a template file
114 if(it != parameters.end()){
115 path = m->hasPath(it->second);
116 //if the user has not given a path then, add inputdir. else leave path alone.
117 if (path == "") { parameters["blast"] = inputDir + it->second; }
120 it = parameters.find("name");
121 //user has given a template file
122 if(it != parameters.end()){
123 path = m->hasPath(it->second);
124 //if the user has not given a path then, add inputdir. else leave path alone.
125 if (path == "") { parameters["name"] = inputDir + it->second; }
130 //check for required parameters
131 blastfile = validParameter.validFile(parameters, "blast", true);
132 if (blastfile == "not open") { blastfile = ""; abort = true; }
133 else if (blastfile == "not found") { blastfile = ""; }
135 //if the user changes the output directory command factory will send this info to us in the output parameter
136 outputDir = validParameter.validFile(parameters, "outputdir", false); if (outputDir == "not found"){
138 outputDir += m->hasPath(blastfile); //if user entered a file with a path then preserve it
141 namefile = validParameter.validFile(parameters, "name", true);
142 if (namefile == "not open") { abort = true; }
143 else if (namefile == "not found") { namefile = ""; }
144 else { m->setNameFile(namefile); }
146 if ((blastfile == "")) { m->mothurOut("When executing a mgcluster command you must provide a blastfile."); m->mothurOutEndLine(); abort = true; }
148 //check for optional parameter and set defaults
150 temp = validParameter.validFile(parameters, "precision", false); if (temp == "not found") { temp = "100"; }
151 precisionLength = temp.length();
152 convert(temp, precision);
154 temp = validParameter.validFile(parameters, "cutoff", false); if (temp == "not found") { temp = "0.70"; }
155 convert(temp, cutoff);
156 cutoff += (5 / (precision * 10.0));
158 method = validParameter.validFile(parameters, "method", false);
159 if (method == "not found") { method = "average"; }
161 if ((method == "furthest") || (method == "nearest") || (method == "average")) { }
162 else { m->mothurOut("Not a valid clustering method. Valid clustering algorithms are furthest, nearest or average."); m->mothurOutEndLine(); abort = true; }
164 temp = validParameter.validFile(parameters, "length", false); if (temp == "not found") { temp = "5"; }
165 convert(temp, length);
167 temp = validParameter.validFile(parameters, "penalty", false); if (temp == "not found") { temp = "0.10"; }
168 convert(temp, penalty);
170 temp = validParameter.validFile(parameters, "min", false); if (temp == "not found") { temp = "true"; }
171 minWanted = m->isTrue(temp);
173 temp = validParameter.validFile(parameters, "merge", false); if (temp == "not found") { temp = "true"; }
174 merge = m->isTrue(temp);
176 temp = validParameter.validFile(parameters, "hcluster", false); if (temp == "not found") { temp = "false"; }
177 hclusterWanted = m->isTrue(temp);
179 temp = validParameter.validFile(parameters, "hard", false); if (temp == "not found") { temp = "T"; }
180 hard = m->isTrue(temp);
184 catch(exception& e) {
185 m->errorOut(e, "MGClusterCommand", "MGClusterCommand");
189 //**********************************************************************************************************************
190 int MGClusterCommand::execute(){
193 if (abort == true) { if (calledHelp) { return 0; } return 2; }
196 if (namefile != "") {
197 nameMap = new NameAssignment(namefile);
199 }else{ nameMap= new NameAssignment(); }
201 string fileroot = outputDir + m->getRootName(m->getSimpleName(blastfile));
204 float previousDist = 0.00000;
205 float rndPreviousDist = 0.00000;
207 //read blastfile - creates sparsematrices for the distances and overlaps as well as a listvector
208 //must remember to delete those objects here since readBlast does not
209 read = new ReadBlast(blastfile, cutoff, penalty, length, minWanted, hclusterWanted);
212 list = new ListVector(nameMap->getListVector());
213 RAbundVector* rabund = new RAbundVector(list->getRAbundVector());
215 if (m->control_pressed) { outputTypes.clear(); delete nameMap; delete read; delete list; delete rabund; return 0; }
219 map<string, int> Seq2Bin;
220 map<string, int> oldSeq2Bin;
222 if (method == "furthest") { tag = "fn"; }
223 else if (method == "nearest") { tag = "nn"; }
227 m->openOutputFile(fileroot+ tag + ".list", listFile);
228 m->openOutputFile(fileroot+ tag + ".rabund", rabundFile);
229 m->openOutputFile(fileroot+ tag + ".sabund", sabundFile);
231 if (m->control_pressed) {
232 delete nameMap; delete read; delete list; delete rabund;
233 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
238 double saveCutoff = cutoff;
240 if (!hclusterWanted) {
241 //get distmatrix and overlap
242 SparseMatrix* distMatrix = read->getDistMatrix();
243 overlapMatrix = read->getOverlapMatrix(); //already sorted by read
247 if (method == "furthest") { cluster = new CompleteLinkage(rabund, list, distMatrix, cutoff, method); }
248 else if(method == "nearest"){ cluster = new SingleLinkage(rabund, list, distMatrix, cutoff, method); }
249 else if(method == "average"){ cluster = new AverageLinkage(rabund, list, distMatrix, cutoff, method); }
250 cluster->setMapWanted(true);
251 Seq2Bin = cluster->getSeqtoBin();
252 oldSeq2Bin = Seq2Bin;
254 if (m->control_pressed) {
255 delete nameMap; delete distMatrix; delete list; delete rabund; delete cluster;
256 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
261 //cluster using cluster classes
262 while (distMatrix->getSmallDist() < cutoff && distMatrix->getNNodes() > 0){
264 cluster->update(cutoff);
266 if (m->control_pressed) {
267 delete nameMap; delete distMatrix; delete list; delete rabund; delete cluster;
268 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
273 float dist = distMatrix->getSmallDist();
276 rndDist = m->ceilDist(dist, precision);
278 rndDist = m->roundDist(dist, precision);
281 if(previousDist <= 0.0000 && dist != previousDist){
282 oldList.setLabel("unique");
285 else if(rndDist != rndPreviousDist){
287 ListVector* temp = mergeOPFs(oldSeq2Bin, rndPreviousDist);
289 if (m->control_pressed) {
290 delete nameMap; delete distMatrix; delete list; delete rabund; delete cluster; delete temp;
291 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
296 temp->setLabel(toString(rndPreviousDist, precisionLength-1));
300 oldList.setLabel(toString(rndPreviousDist, precisionLength-1));
306 rndPreviousDist = rndDist;
308 Seq2Bin = cluster->getSeqtoBin();
309 oldSeq2Bin = Seq2Bin;
312 if(previousDist <= 0.0000){
313 oldList.setLabel("unique");
316 else if(rndPreviousDist<cutoff){
318 ListVector* temp = mergeOPFs(oldSeq2Bin, rndPreviousDist);
320 if (m->control_pressed) {
321 delete nameMap; delete distMatrix; delete list; delete rabund; delete cluster; delete temp;
322 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
327 temp->setLabel(toString(rndPreviousDist, precisionLength-1));
331 oldList.setLabel(toString(rndPreviousDist, precisionLength-1));
337 overlapMatrix.clear();
341 }else { //use hcluster to cluster
342 //get distmatrix and overlap
343 overlapFile = read->getOverlapFile();
344 distFile = read->getDistFile();
347 //sort the distance and overlap files
348 sortHclusterFiles(distFile, overlapFile);
350 if (m->control_pressed) {
351 delete nameMap; delete list; delete rabund;
352 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
358 hcluster = new HCluster(rabund, list, method, distFile, nameMap, cutoff);
359 hcluster->setMapWanted(true);
360 Seq2Bin = cluster->getSeqtoBin();
361 oldSeq2Bin = Seq2Bin;
363 vector<seqDist> seqs; seqs.resize(1); // to start loop
364 //ifstream inHcluster;
365 //m->openInputFile(distFile, inHcluster);
367 if (m->control_pressed) {
368 delete nameMap; delete list; delete rabund; delete hcluster;
369 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
374 while (seqs.size() != 0){
376 seqs = hcluster->getSeqs();
378 //to account for cutoff change in average neighbor
379 if (seqs.size() != 0) {
380 if (seqs[0].dist > cutoff) { break; }
383 if (m->control_pressed) {
384 delete nameMap; delete list; delete rabund; delete hcluster;
385 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
386 m->mothurRemove(distFile);
387 m->mothurRemove(overlapFile);
392 for (int i = 0; i < seqs.size(); i++) { //-1 means skip me
394 if (seqs[i].seq1 != seqs[i].seq2) {
396 cutoff = hcluster->update(seqs[i].seq1, seqs[i].seq2, seqs[i].dist);
398 if (m->control_pressed) {
399 delete nameMap; delete list; delete rabund; delete hcluster;
400 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
401 m->mothurRemove(distFile);
402 m->mothurRemove(overlapFile);
409 rndDist = m->ceilDist(seqs[i].dist, precision);
411 rndDist = m->roundDist(seqs[i].dist, precision);
414 if((previousDist <= 0.0000) && (seqs[i].dist != previousDist)){
415 oldList.setLabel("unique");
418 else if((rndDist != rndPreviousDist)){
420 ListVector* temp = mergeOPFs(oldSeq2Bin, rndPreviousDist);
422 if (m->control_pressed) {
423 delete nameMap; delete list; delete rabund; delete hcluster; delete temp;
424 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
425 m->mothurRemove(distFile);
426 m->mothurRemove(overlapFile);
431 temp->setLabel(toString(rndPreviousDist, precisionLength-1));
435 oldList.setLabel(toString(rndPreviousDist, precisionLength-1));
440 previousDist = seqs[i].dist;
441 rndPreviousDist = rndDist;
443 Seq2Bin = cluster->getSeqtoBin();
444 oldSeq2Bin = Seq2Bin;
448 //inHcluster.close();
450 if(previousDist <= 0.0000){
451 oldList.setLabel("unique");
454 else if(rndPreviousDist<cutoff){
456 ListVector* temp = mergeOPFs(oldSeq2Bin, rndPreviousDist);
458 if (m->control_pressed) {
459 delete nameMap; delete list; delete rabund; delete hcluster; delete temp;
460 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
461 m->mothurRemove(distFile);
462 m->mothurRemove(overlapFile);
467 temp->setLabel(toString(rndPreviousDist, precisionLength-1));
471 oldList.setLabel(toString(rndPreviousDist, precisionLength-1));
477 m->mothurRemove(distFile);
478 m->mothurRemove(overlapFile);
487 if (m->control_pressed) {
489 listFile.close(); rabundFile.close(); sabundFile.close(); m->mothurRemove((fileroot+ tag + ".list")); m->mothurRemove((fileroot+ tag + ".rabund")); m->mothurRemove((fileroot+ tag + ".sabund"));
494 m->mothurOutEndLine();
495 m->mothurOut("Output File Names: "); m->mothurOutEndLine();
496 m->mothurOut(fileroot+ tag + ".list"); m->mothurOutEndLine(); outputNames.push_back(fileroot+ tag + ".list"); outputTypes["list"].push_back(fileroot+ tag + ".list");
497 m->mothurOut(fileroot+ tag + ".rabund"); m->mothurOutEndLine(); outputNames.push_back(fileroot+ tag + ".rabund"); outputTypes["rabund"].push_back(fileroot+ tag + ".rabund");
498 m->mothurOut(fileroot+ tag + ".sabund"); m->mothurOutEndLine(); outputNames.push_back(fileroot+ tag + ".sabund"); outputTypes["sabund"].push_back(fileroot+ tag + ".sabund");
499 m->mothurOutEndLine();
501 if (saveCutoff != cutoff) {
502 if (hard) { saveCutoff = m->ceilDist(saveCutoff, precision); }
503 else { saveCutoff = m->roundDist(saveCutoff, precision); }
505 m->mothurOut("changed cutoff to " + toString(cutoff)); m->mothurOutEndLine();
508 //set list file as new current listfile
510 itTypes = outputTypes.find("list");
511 if (itTypes != outputTypes.end()) {
512 if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setListFile(current); }
515 //set rabund file as new current rabundfile
516 itTypes = outputTypes.find("rabund");
517 if (itTypes != outputTypes.end()) {
518 if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setRabundFile(current); }
521 //set sabund file as new current sabundfile
522 itTypes = outputTypes.find("sabund");
523 if (itTypes != outputTypes.end()) {
524 if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setSabundFile(current); }
528 m->mothurOut("It took " + toString(time(NULL) - start) + " seconds to cluster."); m->mothurOutEndLine();
532 catch(exception& e) {
533 m->errorOut(e, "MGClusterCommand", "execute");
537 //**********************************************************************************************************************
538 void MGClusterCommand::printData(ListVector* mergedList){
540 mergedList->print(listFile);
541 mergedList->getRAbundVector().print(rabundFile);
543 SAbundVector sabund = mergedList->getSAbundVector();
546 sabund.print(sabundFile);
548 catch(exception& e) {
549 m->errorOut(e, "MGClusterCommand", "printData");
553 //**********************************************************************************************************************
554 //this merging is just at the reporting level, after this info is printed to the file it is gone and does not effect the datastructures
555 //that are used to cluster by distance. this is done so that the overlapping data does not have more influenece than the distance data.
556 ListVector* MGClusterCommand::mergeOPFs(map<string, int> binInfo, float dist){
558 //create new listvector so you don't overwrite the clustering
559 ListVector* newList = new ListVector(oldList);
565 if (hclusterWanted) {
566 m->openInputFile(overlapFile, inOverlap);
567 if (inOverlap.eof()) { done = true; }
568 }else { if (overlapMatrix.size() == 0) { done = true; } }
571 if (m->control_pressed) {
572 if (hclusterWanted) { inOverlap.close(); }
578 if (!hclusterWanted) {
579 if (count < overlapMatrix.size()) { //do we have another node in the matrix
580 overlapNode = overlapMatrix[count];
584 if (!inOverlap.eof()) {
585 string firstName, secondName;
586 float overlapDistance;
587 inOverlap >> firstName >> secondName >> overlapDistance; m->gobble(inOverlap);
589 //commented out because we check this in readblast already
590 //map<string,int>::iterator itA = nameMap->find(firstName);
591 //map<string,int>::iterator itB = nameMap->find(secondName);
592 //if(itA == nameMap->end()){ cerr << "AAError: Sequence '" << firstName << "' was not found in the names file, please correct\n"; exit(1); }
593 //if(itB == nameMap->end()){ cerr << "ABError: Sequence '" << secondName << "' was not found in the names file, please correct\n"; exit(1); }
595 //overlapNode.seq1 = itA->second;
596 //overlapNode.seq2 = itB->second;
597 overlapNode.seq1 = nameMap->get(firstName);
598 overlapNode.seq2 = nameMap->get(secondName);
599 overlapNode.dist = overlapDistance;
600 }else { inOverlap.close(); break; }
603 if (overlapNode.dist < dist) {
604 //get names of seqs that overlap
605 string name1 = nameMap->get(overlapNode.seq1);
606 string name2 = nameMap->get(overlapNode.seq2);
608 //use binInfo to find out if they are already in the same bin
609 //map<string, int>::iterator itBin1 = binInfo.find(name1);
610 //map<string, int>::iterator itBin2 = binInfo.find(name2);
612 //if(itBin1 == binInfo.end()){ cerr << "AAError: Sequence '" << name1 << "' does not have any bin info.\n"; exit(1); }
613 //if(itBin2 == binInfo.end()){ cerr << "ABError: Sequence '" << name2 << "' does not have any bin info.\n"; exit(1); }
615 //int binKeep = itBin1->second;
616 //int binRemove = itBin2->second;
618 int binKeep = binInfo[name1];
619 int binRemove = binInfo[name2];
621 //if not merge bins and update binInfo
622 if(binKeep != binRemove) {
624 //save names in old bin
625 string names = newList->get(binRemove);
627 //merge bins into name1s bin
628 newList->set(binKeep, newList->get(binRemove)+','+newList->get(binKeep));
629 newList->set(binRemove, "");
632 while (names.find_first_of(',') != -1) {
634 string name = names.substr(0,names.find_first_of(','));
635 //save name and bin number
636 binInfo[name] = binKeep;
637 names = names.substr(names.find_first_of(',')+1, names.length());
641 binInfo[names] = binKeep;
644 }else { done = true; }
651 catch(exception& e) {
652 m->errorOut(e, "MGClusterCommand", "mergeOPFs");
656 //**********************************************************************************************************************
657 void MGClusterCommand::sortHclusterFiles(string unsortedDist, string unsortedOverlap) {
660 string sortedDistFile = m->sortFile(unsortedDist, outputDir);
661 m->mothurRemove(unsortedDist); //delete unsorted file
662 distFile = sortedDistFile;
665 string sortedOverlapFile = m->sortFile(unsortedOverlap, outputDir);
666 m->mothurRemove(unsortedOverlap); //delete unsorted file
667 overlapFile = sortedOverlapFile;
669 catch(exception& e) {
670 m->errorOut(e, "MGClusterCommand", "sortHclusterFiles");
675 //**********************************************************************************************************************