]> git.donarmstrong.com Git - mothur.git/blob - subsamplecommand.cpp
Merge remote-tracking branch 'mothur/master'
[mothur.git] / subsamplecommand.cpp
1 /*
2  *  subsamplecommand.cpp
3  *  Mothur
4  *
5  *  Created by westcott on 10/27/10.
6  *  Copyright 2010 Schloss Lab. All rights reserved.
7  *
8  */
9
10 #include "subsamplecommand.h"
11 #include "sharedutilities.h"
12 #include "deconvolutecommand.h"
13 #include "subsample.h"
14
15 //**********************************************************************************************************************
16 vector<string> SubSampleCommand::setParameters(){       
17         try {           
18                 CommandParameter pfasta("fasta", "InputTypes", "", "", "none", "FLSSR", "none",false,false); parameters.push_back(pfasta);
19         CommandParameter pname("name", "InputTypes", "", "", "NameCount", "none", "none",false,false); parameters.push_back(pname);
20         CommandParameter pcount("count", "InputTypes", "", "", "NameCount-CountGroup", "none", "none",false,false); parameters.push_back(pcount);
21                 CommandParameter pgroup("group", "InputTypes", "", "", "CountGroup", "none", "none",false,false); parameters.push_back(pgroup);
22                 CommandParameter plist("list", "InputTypes", "", "", "none", "FLSSR", "none",false,false); parameters.push_back(plist);
23                 CommandParameter pshared("shared", "InputTypes", "", "", "none", "FLSSR", "none",false,false); parameters.push_back(pshared);
24                 CommandParameter prabund("rabund", "InputTypes", "", "", "none", "FLSSR", "none",false,false); parameters.push_back(prabund);
25                 CommandParameter psabund("sabund", "InputTypes", "", "", "none", "FLSSR", "none",false,false); parameters.push_back(psabund);
26                 CommandParameter plabel("label", "String", "", "", "", "", "",false,false); parameters.push_back(plabel);
27                 CommandParameter pgroups("groups", "String", "", "", "", "", "",false,false); parameters.push_back(pgroups);
28                 CommandParameter psize("size", "Number", "", "0", "", "", "",false,false); parameters.push_back(psize);
29                 CommandParameter ppersample("persample", "Boolean", "", "F", "", "", "",false,false); parameters.push_back(ppersample);
30                 CommandParameter pinputdir("inputdir", "String", "", "", "", "", "",false,false); parameters.push_back(pinputdir);
31                 CommandParameter poutputdir("outputdir", "String", "", "", "", "", "",false,false); parameters.push_back(poutputdir);
32                 
33                 vector<string> myArray;
34                 for (int i = 0; i < parameters.size(); i++) {   myArray.push_back(parameters[i].name);          }
35                 return myArray;
36         }
37         catch(exception& e) {
38                 m->errorOut(e, "SubSampleCommand", "setParameters");
39                 exit(1);
40         }
41 }
42 //**********************************************************************************************************************
43 string SubSampleCommand::getHelpString(){       
44         try {
45                 string helpString = "";
46                 helpString += "The sub.sample command is designed to be used as a way to normalize your data, or create a smaller set from your original set.\n";
47                 helpString += "The sub.sample command parameters are fasta, name, list, group, count, rabund, sabund, shared, groups, size, persample and label.  You must provide a fasta, list, sabund, rabund or shared file as an input file.\n";
48                 helpString += "The namefile is only used with the fasta file, not with the listfile, because the list file should contain all sequences.\n";
49                 helpString += "The groups parameter allows you to specify which of the groups in your groupfile you would like included. The group names are separated by dashes.\n";
50                 helpString += "The label parameter allows you to select what distance levels you would like, and are also separated by dashes.\n";
51                 helpString += "The size parameter allows you indicate the size of your subsample.\n";
52                 helpString += "The persample parameter allows you indicate you want to select subsample of the same size from each of your groups, default=false. It is only used with the list and fasta files if a groupfile is given.\n";
53                 helpString += "persample=false will select a random set of sequences of the size you select, but the number of seqs from each group may differ.\n";
54                 helpString += "The size parameter is not set: with shared file size=number of seqs in smallest sample, with all other files if a groupfile is given and persample=true, then size=number of seqs in smallest sample, otherwise size=10% of number of seqs.\n";
55                 helpString += "The sub.sample command should be in the following format: sub.sample(list=yourListFile, group=yourGroupFile, groups=yourGroups, label=yourLabels).\n";
56                 helpString += "Example sub.sample(list=abrecovery.fn.list, group=abrecovery.groups, groups=B-C, size=20).\n";
57                 helpString += "The default value for groups is all the groups in your groupfile, and all labels in your inputfile will be used.\n";
58                 helpString += "The sub.sample command outputs a .subsample file.\n";
59                 helpString += "Note: No spaces between parameter labels (i.e. groups), '=' and parameters (i.e.yourGroups).\n";
60                 return helpString;
61         }
62         catch(exception& e) {
63                 m->errorOut(e, "SubSampleCommand", "getHelpString");
64                 exit(1);
65         }
66 }
67 //**********************************************************************************************************************
68 string SubSampleCommand::getOutputFileNameTag(string type, string inputName=""){        
69         try {
70         string outputFileName = "";
71                 map<string, vector<string> >::iterator it;
72         
73         //is this a type this command creates
74         it = outputTypes.find(type);
75         if (it == outputTypes.end()) {  m->mothurOut("[ERROR]: this command doesn't create a " + type + " output file.\n"); }
76         else {
77             if (type == "fasta")            {   outputFileName =  "subsample" + m->getExtension(inputName);   }
78             else if (type == "sabund")    {   outputFileName =  "subsample" + m->getExtension(inputName);   }
79             else if (type == "name")        {   outputFileName =  "subsample" + m->getExtension(inputName);   }
80             else if (type == "count")        {   outputFileName =  "subsample" + m->getExtension(inputName);   }
81             else if (type == "group")       {   outputFileName =  "subsample" + m->getExtension(inputName);   }
82             else if (type == "list")        {   outputFileName =  "subsample" + m->getExtension(inputName);   }
83             else if (type == "rabund")       {   outputFileName =  "subsample" + m->getExtension(inputName);   }
84             else if (type == "shared") {   outputFileName =  "subsample" + m->getExtension(inputName);        }
85             else { m->mothurOut("[ERROR]: No definition for type " + type + " output file tag.\n"); m->control_pressed = true;  }
86         }
87         return outputFileName;
88         }
89         catch(exception& e) {
90                 m->errorOut(e, "SubSampleCommand", "getOutputFileNameTag");
91                 exit(1);
92         }
93 }
94
95 //**********************************************************************************************************************
96 SubSampleCommand::SubSampleCommand(){   
97         try {
98                 abort = true; calledHelp = true; 
99                 setParameters();
100                 vector<string> tempOutNames;
101                 outputTypes["shared"] = tempOutNames;
102                 outputTypes["list"] = tempOutNames;
103                 outputTypes["rabund"] = tempOutNames;
104                 outputTypes["sabund"] = tempOutNames;
105                 outputTypes["fasta"] = tempOutNames;
106                 outputTypes["name"] = tempOutNames;
107                 outputTypes["group"] = tempOutNames;
108         outputTypes["count"] = tempOutNames;
109         }
110         catch(exception& e) {
111                 m->errorOut(e, "SubSampleCommand", "GetRelAbundCommand");
112                 exit(1);
113         }
114 }
115 //**********************************************************************************************************************
116 SubSampleCommand::SubSampleCommand(string option) {
117         try {
118                 abort = false; calledHelp = false;   
119                 allLines = 1;
120                 
121                 //allow user to run help
122                 if(option == "help") { help(); abort = true; calledHelp = true; }
123                 else if(option == "citation") { citation(); abort = true; calledHelp = true;}
124                 
125                 else {
126                         vector<string> myArray = setParameters();
127                         
128                         OptionParser parser(option);
129                         map<string,string> parameters = parser.getParameters();
130                         
131                         ValidParameters validParameter;
132                         
133                         //check to make sure all parameters are valid for command
134                         map<string,string>::iterator it;
135                         for (it = parameters.begin(); it != parameters.end(); it++) { 
136                                 if (validParameter.isValidParameter(it->first, myArray, it->second) != true) {  abort = true;  }
137                         }
138                         
139                         //initialize outputTypes
140                         vector<string> tempOutNames;
141                         outputTypes["shared"] = tempOutNames;
142                         outputTypes["list"] = tempOutNames;
143                         outputTypes["rabund"] = tempOutNames;
144                         outputTypes["sabund"] = tempOutNames;
145                         outputTypes["fasta"] = tempOutNames;
146                         outputTypes["name"] = tempOutNames;
147                         outputTypes["group"] = tempOutNames;
148             outputTypes["count"] = tempOutNames;
149                                         
150                         //if the user changes the output directory command factory will send this info to us in the output parameter 
151                         outputDir = validParameter.validFile(parameters, "outputdir", false);           if (outputDir == "not found"){  outputDir = ""; }
152                         
153                         //if the user changes the input directory command factory will send this info to us in the output parameter 
154                         string inputDir = validParameter.validFile(parameters, "inputdir", false);              
155                         if (inputDir == "not found"){   inputDir = "";          }
156                         else {
157                                 string path;
158                                 it = parameters.find("list");
159                                 //user has given a template file
160                                 if(it != parameters.end()){ 
161                                         path = m->hasPath(it->second);
162                                         //if the user has not given a path then, add inputdir. else leave path alone.
163                                         if (path == "") {       parameters["list"] = inputDir + it->second;             }
164                                 }
165                                 
166                                 it = parameters.find("fasta");
167                                 //user has given a template file
168                                 if(it != parameters.end()){ 
169                                         path = m->hasPath(it->second);
170                                         //if the user has not given a path then, add inputdir. else leave path alone.
171                                         if (path == "") {       parameters["fasta"] = inputDir + it->second;            }
172                                 }
173                                 
174                                 it = parameters.find("shared");
175                                 //user has given a template file
176                                 if(it != parameters.end()){ 
177                                         path = m->hasPath(it->second);
178                                         //if the user has not given a path then, add inputdir. else leave path alone.
179                                         if (path == "") {       parameters["shared"] = inputDir + it->second;           }
180                                 }
181                                 
182                                 it = parameters.find("group");
183                                 //user has given a template file
184                                 if(it != parameters.end()){ 
185                                         path = m->hasPath(it->second);
186                                         //if the user has not given a path then, add inputdir. else leave path alone.
187                                         if (path == "") {       parameters["group"] = inputDir + it->second;            }
188                                 }
189                                 
190                                 it = parameters.find("sabund");
191                                 //user has given a template file
192                                 if(it != parameters.end()){ 
193                                         path = m->hasPath(it->second);
194                                         //if the user has not given a path then, add inputdir. else leave path alone.
195                                         if (path == "") {       parameters["sabund"] = inputDir + it->second;           }
196                                 }
197                                 
198                                 it = parameters.find("rabund");
199                                 //user has given a template file
200                                 if(it != parameters.end()){ 
201                                         path = m->hasPath(it->second);
202                                         //if the user has not given a path then, add inputdir. else leave path alone.
203                                         if (path == "") {       parameters["rabund"] = inputDir + it->second;           }
204                                 }
205                                 
206                                 it = parameters.find("name");
207                                 //user has given a template file
208                                 if(it != parameters.end()){ 
209                                         path = m->hasPath(it->second);
210                                         //if the user has not given a path then, add inputdir. else leave path alone.
211                                         if (path == "") {       parameters["name"] = inputDir + it->second;             }
212                                 }
213                 
214                 it = parameters.find("count");
215                                 //user has given a template file
216                                 if(it != parameters.end()){ 
217                                         path = m->hasPath(it->second);
218                                         //if the user has not given a path then, add inputdir. else leave path alone.
219                                         if (path == "") {       parameters["count"] = inputDir + it->second;            }
220                                 }
221                         }
222                         
223                         //check for required parameters
224                         listfile = validParameter.validFile(parameters, "list", true);
225                         if (listfile == "not open") { listfile = ""; abort = true; }
226                         else if (listfile == "not found") { listfile = ""; }
227                         else { m->setListFile(listfile); }
228                         
229                         sabundfile = validParameter.validFile(parameters, "sabund", true);
230                         if (sabundfile == "not open") { sabundfile = ""; abort = true; }        
231                         else if (sabundfile == "not found") { sabundfile = ""; }
232                         else { m->setSabundFile(sabundfile); }
233                         
234                         rabundfile = validParameter.validFile(parameters, "rabund", true);
235                         if (rabundfile == "not open") { rabundfile = ""; abort = true; }        
236                         else if (rabundfile == "not found") { rabundfile = ""; }
237                         else { m->setRabundFile(rabundfile); }
238                         
239                         fastafile = validParameter.validFile(parameters, "fasta", true);
240                         if (fastafile == "not open") { fastafile = ""; abort = true; }  
241                         else if (fastafile == "not found") { fastafile = ""; }
242                         else { m->setFastaFile(fastafile); }
243                         
244                         sharedfile = validParameter.validFile(parameters, "shared", true);
245                         if (sharedfile == "not open") { sharedfile = ""; abort = true; }        
246                         else if (sharedfile == "not found") { sharedfile = ""; }
247                         else { m->setSharedFile(sharedfile); }
248                         
249                         namefile = validParameter.validFile(parameters, "name", true);
250                         if (namefile == "not open") { namefile = ""; abort = true; }    
251                         else if (namefile == "not found") { namefile = ""; }
252                         else { m->setNameFile(namefile); }
253                         
254                         groupfile = validParameter.validFile(parameters, "group", true);
255                         if (groupfile == "not open") { groupfile = ""; abort = true; }  
256                         else if (groupfile == "not found") { groupfile = ""; }
257                         else { m->setGroupFile(groupfile); }
258                         
259             countfile = validParameter.validFile(parameters, "count", true);
260                         if (countfile == "not open") { countfile = ""; abort = true; }
261                         else if (countfile == "not found") { countfile = "";  } 
262                         else {
263                 m->setCountTableFile(countfile); 
264                 ct.readTable(countfile);
265             }
266             
267             if ((namefile != "") && (countfile != "")) {
268                 m->mothurOut("[ERROR]: you may only use one of the following: name or count."); m->mothurOutEndLine(); abort = true;
269             }
270                         
271             if ((groupfile != "") && (countfile != "")) {
272                 m->mothurOut("[ERROR]: you may only use one of the following: group or count."); m->mothurOutEndLine(); abort=true;
273             }
274             
275                         //check for optional parameter and set defaults
276                         // ...at some point should added some additional type checking...
277                         label = validParameter.validFile(parameters, "label", false);                   
278                         if (label == "not found") { label = ""; }
279                         else { 
280                                 if(label != "all") {  m->splitAtDash(label, labels);  allLines = 0;  }
281                                 else { allLines = 1;  }
282                         }
283                         
284                         groups = validParameter.validFile(parameters, "groups", false);                 
285                         if (groups == "not found") { groups = ""; pickedGroups = false; }
286                         else { 
287                                 pickedGroups = true;
288                                 m->splitAtDash(groups, Groups);
289                                 m->setGroups(Groups);
290                         }
291                         
292                         string temp = validParameter.validFile(parameters, "size", false);              if (temp == "not found"){       temp = "0";             }
293                         m->mothurConvert(temp, size);  
294                         
295                         temp = validParameter.validFile(parameters, "persample", false);                if (temp == "not found"){       temp = "f";             }
296                         persample = m->isTrue(temp);
297                         
298                         if ((groupfile == "") && (countfile == "")) { persample = false; }
299             if (countfile != "") {
300                 if (!ct.hasGroupInfo()) { 
301                     persample = false; 
302                     if (pickedGroups) { m->mothurOut("You cannot pick groups without group info in your count file."); m->mothurOutEndLine(); abort = true; }
303                 }
304             }
305                         
306                         if ((namefile != "") && (fastafile == "")) { m->mothurOut("You may only use a namefile with a fastafile."); m->mothurOutEndLine(); abort = true; }
307                         
308                         if ((fastafile == "") && (listfile == "") && (sabundfile == "") && (rabundfile == "") && (sharedfile == "")) {
309                                 m->mothurOut("You must provide a fasta, list, sabund, rabund or shared file as an input file."); m->mothurOutEndLine(); abort = true; }
310                         
311                         if (pickedGroups && ((groupfile == "") && (sharedfile == "") && (countfile == ""))) { 
312                                 m->mothurOut("You cannot pick groups without a valid group, count or shared file."); m->mothurOutEndLine(); abort = true; }
313                         
314                         if (((groupfile != "") || (countfile != "")) && ((fastafile == "") && (listfile == ""))) { 
315                                 m->mothurOut("Group or count files are only valid with listfile or fastafile."); m->mothurOutEndLine(); abort = true; }
316                         
317                         if (((groupfile != "") || (countfile != "")) && ((fastafile != "") && (listfile != ""))) { 
318                                 m->mothurOut("A new group or count file can only be made from the subsample of a listfile or fastafile, not both. Please correct."); m->mothurOutEndLine(); abort = true; }
319                         
320             if (countfile == "") {
321                 if ((fastafile != "") && (namefile == "")) {
322                     vector<string> files; files.push_back(fastafile);
323                     parser.getNameFile(files);
324                 }
325             }
326                 }
327
328         }
329         catch(exception& e) {
330                 m->errorOut(e, "SubSampleCommand", "SubSampleCommand");
331                 exit(1);
332         }
333 }
334 //**********************************************************************************************************************
335
336 int SubSampleCommand::execute(){
337         try {
338         
339                 if (abort == true) { if (calledHelp) { return 0; }  return 2;   }
340                 
341                 if (sharedfile != "")   {   getSubSampleShared();       }
342                 if (m->control_pressed) {  for (int i = 0; i < outputNames.size(); i++) {       m->mothurRemove(outputNames[i]); return 0; } }
343                 
344                 if (listfile != "")             {   getSubSampleList();         }
345                 if (m->control_pressed) {  for (int i = 0; i < outputNames.size(); i++) {       m->mothurRemove(outputNames[i]); return 0; } }
346                 
347                 if (rabundfile != "")   {   getSubSampleRabund();       }
348                 if (m->control_pressed) {  for (int i = 0; i < outputNames.size(); i++) {       m->mothurRemove(outputNames[i]); return 0; } }
349                 
350                 if (sabundfile != "")   {   getSubSampleSabund();       }
351                 if (m->control_pressed) {  for (int i = 0; i < outputNames.size(); i++) {       m->mothurRemove(outputNames[i]); return 0; } }
352                 
353                 if (fastafile != "")    {   getSubSampleFasta();        }
354                 if (m->control_pressed) {  for (int i = 0; i < outputNames.size(); i++) {       m->mothurRemove(outputNames[i]); return 0; } }
355                         
356                 //set fasta file as new current fastafile
357                 string current = "";
358                 itTypes = outputTypes.find("fasta");
359                 if (itTypes != outputTypes.end()) {
360                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setFastaFile(current); }
361                 }
362                 
363                 itTypes = outputTypes.find("name");
364                 if (itTypes != outputTypes.end()) {
365                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setNameFile(current); }
366                 }
367                 
368                 itTypes = outputTypes.find("group");
369                 if (itTypes != outputTypes.end()) {
370                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setGroupFile(current); }
371                 }
372                 
373                 itTypes = outputTypes.find("list");
374                 if (itTypes != outputTypes.end()) {
375                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setListFile(current); }
376                 }
377                 
378                 itTypes = outputTypes.find("shared");
379                 if (itTypes != outputTypes.end()) {
380                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setSharedFile(current); }
381                 }
382                 
383                 itTypes = outputTypes.find("rabund");
384                 if (itTypes != outputTypes.end()) {
385                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setRabundFile(current); }
386                 }
387                 
388                 itTypes = outputTypes.find("sabund");
389                 if (itTypes != outputTypes.end()) {
390                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setSabundFile(current); }
391                 }
392         
393         itTypes = outputTypes.find("count");
394                 if (itTypes != outputTypes.end()) {
395                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setCountTableFile(current); }
396                 }
397                 
398                 
399                 m->mothurOutEndLine();
400                 m->mothurOut("Output File Names: "); m->mothurOutEndLine();
401                 for (int i = 0; i < outputNames.size(); i++) {  m->mothurOut(outputNames[i]); m->mothurOutEndLine();    }
402                 m->mothurOutEndLine();
403                 
404                 return 0;
405         }
406         catch(exception& e) {
407                 m->errorOut(e, "SubSampleCommand", "execute");
408                 exit(1);
409         }
410 }
411 //**********************************************************************************************************************
412 int SubSampleCommand::getSubSampleFasta() {
413         try {
414                 
415                 if (namefile != "") { readNames(); }    //fills names with all names in namefile.
416                 else { getNames(); }//no name file, so get list of names to pick from
417                 
418                 GroupMap groupMap;
419                 if (groupfile != "") {
420                         groupMap.readMap(groupfile);
421                         
422                         //takes care of user setting groupNames that are invalid or setting groups=all
423                         SharedUtil util;
424                         vector<string> namesGroups = groupMap.getNamesOfGroups();
425                         util.setGroups(Groups, namesGroups);
426                         
427                         //file mismatch quit
428                         if (names.size() != groupMap.getNumSeqs()) { 
429                                 m->mothurOut("[ERROR]: your fasta file contains " + toString(names.size()) + " sequences, and your groupfile contains " + toString(groupMap.getNumSeqs()) + ", please correct."); 
430                                 m->mothurOutEndLine();
431                                 return 0;
432                         }                       
433                 }else if (countfile != "") {
434             if (ct.hasGroupInfo()) {
435                 SharedUtil util;
436                 vector<string> namesGroups = ct.getNamesOfGroups();
437                 util.setGroups(Groups, namesGroups);
438             }
439             
440             //file mismatch quit
441                         if (names.size() != ct.getNumUniqueSeqs()) { 
442                                 m->mothurOut("[ERROR]: your fasta file contains " + toString(names.size()) + " sequences, and your count file contains " + toString(ct.getNumUniqueSeqs()) + " unique sequences, please correct."); 
443                                 m->mothurOutEndLine();
444                                 return 0;
445                         }       
446         }
447                 
448                 if (m->control_pressed) { return 0; }
449                 
450                 //make sure that if your picked groups size is not too big
451                 int thisSize = 0;
452         if (countfile == "") { thisSize = names.size();  }
453         else {  thisSize = ct. getNumSeqs();  }  //all seqs not just unique
454         
455                 if (persample) { 
456                         if (size == 0) { //user has not set size, set size = smallest samples size
457                                 if (countfile == "") { size = groupMap.getNumSeqs(Groups[0]); }
458                 else {  size = ct.getGroupCount(Groups[0]);  }
459                 
460                                 for (int i = 1; i < Groups.size(); i++) {
461                                         int thisSize = 0;
462                     if (countfile == "") { thisSize = groupMap.getNumSeqs(Groups[i]); }
463                     else {  thisSize = ct.getGroupCount(Groups[i]);  }
464                                         
465                                         if (thisSize < size) {  size = thisSize;        }
466                                 }
467                         }else { //make sure size is not too large
468                                 vector<string> newGroups;
469                                 for (int i = 0; i < Groups.size(); i++) {
470                                         int thisSize = 0;
471                     if (countfile == "") { thisSize = groupMap.getNumSeqs(Groups[i]); }
472                     else {  thisSize = ct.getGroupCount(Groups[i]);  }
473                                         
474                                         if (thisSize >= size) { newGroups.push_back(Groups[i]); }
475                                         else {  m->mothurOut("You have selected a size that is larger than " + Groups[i] + " number of sequences, removing " + Groups[i] + "."); m->mothurOutEndLine(); }
476                                 }
477                                 Groups = newGroups;
478                 if (newGroups.size() == 0) {  m->mothurOut("[ERROR]: all groups removed."); m->mothurOutEndLine(); m->control_pressed = true; }
479                         }
480                         
481                         m->mothurOut("Sampling " + toString(size) + " from each group."); m->mothurOutEndLine();                        
482                 }else {
483                         if (pickedGroups) {
484                                 int total = 0;
485                                 for(int i = 0; i < Groups.size(); i++) {
486                     if (countfile == "") { total += groupMap.getNumSeqs(Groups[i]); }
487                     else {  total += ct.getGroupCount(Groups[i]);  }
488                                 }
489                                 
490                                 if (size == 0) { //user has not set size, set size = 10% samples size
491                                         size = int (total * 0.10);
492                                 }
493                                 
494                                 if (total < size) { 
495                                         if (size != 0) { 
496                                                 m->mothurOut("Your size is too large for the number of groups you selected. Adjusting to " + toString(int (total * 0.10)) + "."); m->mothurOutEndLine();
497                                         }
498                                         size = int (total * 0.10);
499                                 }
500                                 
501                                 m->mothurOut("Sampling " + toString(size) + " from " + toString(total) + "."); m->mothurOutEndLine();
502                         }
503                         
504                         if (size == 0) { //user has not set size, set size = 10% samples size
505                                 if (countfile == "") {  size = int (names.size() * 0.10); }
506                 else {  size = int (ct.getNumSeqs() * 0.10); }
507                         }
508                         
509             
510             if (size > thisSize) { m->mothurOut("Your fasta file only contains " + toString(thisSize) + " sequences. Setting size to " + toString(thisSize) + "."); m->mothurOutEndLine();
511                     size = thisSize;
512             }
513             
514             if (!pickedGroups) { m->mothurOut("Sampling " + toString(size) + " from " + toString(thisSize) + "."); m->mothurOutEndLine(); }
515
516                 }
517                 random_shuffle(names.begin(), names.end());
518                 
519                 set<string> subset; //dont want repeat sequence names added
520                 if (persample) {
521             if (countfile == "") {
522                 //initialize counts
523                 map<string, int> groupCounts;
524                 map<string, int>::iterator itGroupCounts;
525                 for (int i = 0; i < Groups.size(); i++) { groupCounts[Groups[i]] = 0; }
526                         
527                 for (int j = 0; j < names.size(); j++) {
528                                         
529                     if (m->control_pressed) { return 0; }
530                                                                                                 
531                     string group = groupMap.getGroup(names[j]);
532                     if (group == "not found") { m->mothurOut("[ERROR]: " + names[j] + " is not in your groupfile. please correct."); m->mothurOutEndLine(); group = "NOTFOUND"; }
533                     else{
534                         itGroupCounts = groupCounts.find(group);
535                         if (itGroupCounts != groupCounts.end()) {
536                             if (groupCounts[group] < size) {    subset.insert(names[j]);        groupCounts[group]++; }
537                         }
538                     }                           
539                 }
540             }else {
541                 SubSample sample;
542                 CountTable sampledCt = sample.getSample(ct, size, Groups);
543                 vector<string> sampledSeqs = sampledCt.getNamesOfSeqs();
544                 for (int i = 0; i < sampledSeqs.size(); i++) { subset.insert(sampledSeqs[i]); }
545                 
546                 string countOutputDir = outputDir;
547                 if (outputDir == "") {  countOutputDir += m->hasPath(countfile);  }
548                 string countOutputFileName = countOutputDir + m->getRootName(m->getSimpleName(countfile)) + getOutputFileNameTag("count", countfile);
549                 outputTypes["count"].push_back(countOutputFileName);  outputNames.push_back(countOutputFileName);
550                 sampledCt.printTable(countOutputFileName);
551             }
552                 }else {
553                         if (countfile == "") {
554                 //randomly select a subset of those names to include in the subsample
555                 //since names was randomly shuffled just grab the next one
556                 for (int j = 0; j < names.size(); j++) {
557                     
558                     if (m->control_pressed) { return 0; }
559                     
560                     if (groupfile != "") { //if there is a groupfile given fill in group info
561                         string group = groupMap.getGroup(names[j]);
562                         if (group == "not found") { m->mothurOut("[ERROR]: " + names[j] + " is not in your groupfile. please correct."); m->mothurOutEndLine(); group = "NOTFOUND"; }
563                         
564                         if (pickedGroups) { //if hte user picked groups, we only want to keep the names of sequences from those groups
565                             if (m->inUsersGroups(group, Groups)) {  subset.insert(names[j]); }
566                         }else{  subset.insert(names[j]); }
567                     }else{ //save everyone, group
568                         subset.insert(names[j]); 
569                     }                                   
570                     
571                     //do we have enough??
572                     if (subset.size() == size) { break; }
573                 }
574             }else {
575                 SubSample sample;
576                 CountTable sampledCt = sample.getSample(ct, size, Groups, pickedGroups);
577                 vector<string> sampledSeqs = sampledCt.getNamesOfSeqs();
578                 for (int i = 0; i < sampledSeqs.size(); i++) { subset.insert(sampledSeqs[i]); }
579                 
580                 string countOutputDir = outputDir;
581                 if (outputDir == "") {  countOutputDir += m->hasPath(countfile);  }
582                 string countOutputFileName = countOutputDir + m->getRootName(m->getSimpleName(countfile)) + getOutputFileNameTag("count", countfile);
583                 outputTypes["count"].push_back(countOutputFileName);  outputNames.push_back(countOutputFileName);
584                 sampledCt.printTable(countOutputFileName);
585             }
586                 }
587                 
588                 if (subset.size() == 0) {  m->mothurOut("The size you selected is too large, skipping fasta file."); m->mothurOutEndLine();  return 0; }
589                 
590                 string thisOutputDir = outputDir;
591                 if (outputDir == "") {  thisOutputDir += m->hasPath(fastafile);  }
592                 string outputFileName = thisOutputDir + m->getRootName(m->getSimpleName(fastafile)) + getOutputFileNameTag("fasta", fastafile);         
593                 ofstream out;
594                 m->openOutputFile(outputFileName, out);
595                 
596                 //read through fasta file outputting only the names on the subsample list
597                 ifstream in;
598                 m->openInputFile(fastafile, in);
599                 
600                 string thisname;
601                 int count = 0;
602                 map<string, vector<string> >::iterator itNameMap;
603                 
604                 while(!in.eof()){
605                         
606                         if (m->control_pressed) { in.close(); out.close();  return 0; }
607                         
608                         Sequence currSeq(in);
609                         thisname = currSeq.getName();
610                         
611                         if (thisname != "") {
612                                 
613                                 //does the subset contain a sequence that this sequence represents
614                                 itNameMap = nameMap.find(thisname);
615                                 if (itNameMap != nameMap.end()) {
616                                         vector<string> nameRepresents = itNameMap->second;
617                                 
618                                         for (int i = 0; i < nameRepresents.size(); i++){
619                                                 if (subset.count(nameRepresents[i]) != 0) {
620                                                         out << ">" << nameRepresents[i] << endl << currSeq.getAligned() << endl;
621                                                         count++;
622                                                 }
623                                         }
624                                 }else{
625                                         m->mothurOut("[ERROR]: " + thisname + " is not in your namefile, please correct."); m->mothurOutEndLine();
626                                 }
627                         }
628                         m->gobble(in);
629                 }
630                 in.close();     
631                 out.close();
632                 
633                 if (count != subset.size()) {
634                         m->mothurOut("[ERROR]: The subset selected contained " + toString(subset.size()) + " sequences, but I only found " + toString(count) + " of those in the fastafile."); m->mothurOutEndLine();
635                 }
636                 
637                 if (namefile != "") {
638                         m->mothurOut("Deconvoluting subsampled fasta file... "); m->mothurOutEndLine();
639                         
640             string outputNameFileName = thisOutputDir + m->getRootName(m->getSimpleName(namefile)) + getOutputFileNameTag("name", namefile);
641                         //use unique.seqs to create new name and fastafile
642                         string inputString = "fasta=" + outputFileName;
643                         m->mothurOut("/******************************************/"); m->mothurOutEndLine(); 
644                         m->mothurOut("Running command: unique.seqs(" + inputString + ")"); m->mothurOutEndLine(); 
645                         m->mothurCalling = true;
646             
647                         Command* uniqueCommand = new DeconvoluteCommand(inputString);
648                         uniqueCommand->execute();
649                         
650                         map<string, vector<string> > filenames = uniqueCommand->getOutputFiles();
651                         
652                         delete uniqueCommand;
653                         m->mothurCalling = false;
654             
655             m->renameFile(filenames["name"][0], outputNameFileName); 
656             m->renameFile(filenames["fasta"][0], outputFileName);  
657             
658                         outputTypes["name"].push_back(outputNameFileName);  outputNames.push_back(outputNameFileName);
659
660                         m->mothurOut("/******************************************/"); m->mothurOutEndLine(); 
661                         
662                         m->mothurOut("Done."); m->mothurOutEndLine();
663                 }
664                 
665                 outputTypes["fasta"].push_back(outputFileName);  outputNames.push_back(outputFileName);
666                 
667                 //if a groupfile is provided read through the group file only outputting the names on the subsample list
668                 if (groupfile != "") {
669                         
670                         string groupOutputDir = outputDir;
671                         if (outputDir == "") {  groupOutputDir += m->hasPath(groupfile);  }
672                         string groupOutputFileName = groupOutputDir + m->getRootName(m->getSimpleName(groupfile)) + getOutputFileNameTag("group", groupfile);
673                         
674                         ofstream outGroup;
675                         m->openOutputFile(groupOutputFileName, outGroup);
676                         outputTypes["group"].push_back(groupOutputFileName);  outputNames.push_back(groupOutputFileName);
677                         
678                         ifstream inGroup;
679                         m->openInputFile(groupfile, inGroup);
680                         string name, group;
681                         
682                         while(!inGroup.eof()){
683                                 
684                                 if (m->control_pressed) { inGroup.close(); outGroup.close(); return 0; }
685                                 
686                                 inGroup >> name;        m->gobble(inGroup);                     //read from first column
687                                 inGroup >> group;                       //read from second column
688                                 
689                                 //if this name is in the accnos file
690                                 if (subset.count(name) != 0) {
691                                         outGroup << name << '\t' << group << endl;
692                                         subset.erase(name);
693                                 }
694                                 
695                                 m->gobble(inGroup);
696                         }
697                         inGroup.close();
698                         outGroup.close();       
699                         
700                         //sanity check
701                         if (subset.size() != 0) {  
702                                 m->mothurOut("Your groupfile does not match your fasta file."); m->mothurOutEndLine();
703                                 for (set<string>::iterator it = subset.begin(); it != subset.end(); it++) {
704                                         m->mothurOut("[ERROR]: " + *it + " is missing from your groupfile."); m->mothurOutEndLine();
705                                 }
706                         }
707                 }
708                         
709                 return 0;
710                 
711         }
712         catch(exception& e) {
713                 m->errorOut(e, "SubSampleCommand", "getSubSampleFasta");
714                 exit(1);
715         }
716 }
717 //**********************************************************************************************************************
718 int SubSampleCommand::getNames() {
719         try {
720                 
721                 ifstream in;
722                 m->openInputFile(fastafile, in);
723                 
724                 string thisname;
725                 while(!in.eof()){
726                         
727                         if (m->control_pressed) { in.close(); return 0; }
728                         
729                         Sequence currSeq(in);
730                         thisname = currSeq.getName();
731                         
732                         if (thisname != "") {
733                                 vector<string> temp; temp.push_back(thisname);
734                                 nameMap[thisname] = temp;
735                                 names.push_back(thisname);
736                         }
737                         m->gobble(in);
738                 }
739                 in.close();     
740                 
741                 return 0;
742                 
743         }
744         catch(exception& e) {
745                 m->errorOut(e, "SubSampleCommand", "getNames");
746                 exit(1);
747         }
748 }       
749 //**********************************************************************************************************************
750 int SubSampleCommand::readNames() {
751         try {
752                 
753         nameMap.clear();
754         m->readNames(namefile, nameMap);
755         
756         //save names of all sequences
757         map<string, vector<string> >::iterator it;
758         for (it = nameMap.begin(); it != nameMap.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { names.push_back((it->second)[i]); } }
759         
760                 return 0;
761                 
762         }
763         catch(exception& e) {
764                 m->errorOut(e, "SubSampleCommand", "readNames");
765                 exit(1);
766         }
767 }               
768 //**********************************************************************************************************************
769 int SubSampleCommand::getSubSampleShared() {
770         try {
771                 
772                 InputData* input = new InputData(sharedfile, "sharedfile");
773                 vector<SharedRAbundVector*> lookup = input->getSharedRAbundVectors();
774                 string lastLabel = lookup[0]->getLabel();
775                 
776                 //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
777                 set<string> processedLabels;
778                 set<string> userLabels = labels;
779                 
780                 if (size == 0) { //user has not set size, set size = smallest samples size
781                         size = lookup[0]->getNumSeqs();
782                         for (int i = 1; i < lookup.size(); i++) {
783                                 int thisSize = lookup[i]->getNumSeqs();
784                                 
785                                 if (thisSize < size) {  size = thisSize;        }
786                         }
787                 }else {
788                         m->clearGroups();
789                         Groups.clear();
790                         vector<SharedRAbundVector*> temp;
791                         for (int i = 0; i < lookup.size(); i++) {
792                                 if (lookup[i]->getNumSeqs() < size) { 
793                                         m->mothurOut(lookup[i]->getGroup() + " contains " + toString(lookup[i]->getNumSeqs()) + ". Eliminating."); m->mothurOutEndLine();
794                                         delete lookup[i];
795                                 }else { 
796                                         Groups.push_back(lookup[i]->getGroup()); 
797                                         temp.push_back(lookup[i]);
798                                 }
799                         } 
800                         lookup = temp;
801                         m->setGroups(Groups);
802                 }
803                 
804                 if (lookup.size() == 0) {  m->mothurOut("The size you selected is too large, skipping shared file."); m->mothurOutEndLine(); delete input; return 0; }
805                 
806                 m->mothurOut("Sampling " + toString(size) + " from each group."); m->mothurOutEndLine();
807                 
808                 //as long as you are not at the end of the file or done wih the lines you want
809                 while((lookup[0] != NULL) && ((allLines == 1) || (userLabels.size() != 0))) {
810                         if (m->control_pressed) {  delete input; for (int i = 0; i < lookup.size(); i++) {  delete lookup[i]; lookup[i] = NULL; }  return 0;  }
811                         
812                         if(allLines == 1 || labels.count(lookup[0]->getLabel()) == 1){                  
813                                 
814                                 m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
815                                 
816                                 processShared(lookup);
817                                 
818                                 processedLabels.insert(lookup[0]->getLabel());
819                                 userLabels.erase(lookup[0]->getLabel());
820                         }
821                         
822                         if ((m->anyLabelsToProcess(lookup[0]->getLabel(), userLabels, "") == true) && (processedLabels.count(lastLabel) != 1)) {
823                                 string saveLabel = lookup[0]->getLabel();
824                                 
825                                 for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }  
826                                 
827                                 lookup = input->getSharedRAbundVectors(lastLabel);
828                                 m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
829                                 
830                                 processShared(lookup);
831                                 
832                                 processedLabels.insert(lookup[0]->getLabel());
833                                 userLabels.erase(lookup[0]->getLabel());
834                                 
835                                 //restore real lastlabel to save below
836                                 lookup[0]->setLabel(saveLabel);
837                         }
838                         
839                         lastLabel = lookup[0]->getLabel();
840                         //prevent memory leak
841                         for (int i = 0; i < lookup.size(); i++) {  delete lookup[i]; lookup[i] = NULL; }
842                         
843                         //get next line to process
844                         lookup = input->getSharedRAbundVectors();                               
845                 }
846                 
847                 
848                 if (m->control_pressed) {   return 0;  }
849                 
850                 //output error messages about any remaining user labels
851                 set<string>::iterator it;
852                 bool needToRun = false;
853                 for (it = userLabels.begin(); it != userLabels.end(); it++) {  
854                         m->mothurOut("Your file does not include the label " + *it); 
855                         if (processedLabels.count(lastLabel) != 1) {
856                                 m->mothurOut(". I will use " + lastLabel + "."); m->mothurOutEndLine();
857                                 needToRun = true;
858                         }else {
859                                 m->mothurOut(". Please refer to " + lastLabel + "."); m->mothurOutEndLine();
860                         }
861                 }
862                 
863                 //run last label if you need to
864                 if (needToRun == true)  {
865                         for (int i = 0; i < lookup.size(); i++) { if (lookup[i] != NULL) { delete lookup[i]; } }  
866                         lookup = input->getSharedRAbundVectors(lastLabel);
867                         
868                         m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
869                         
870                         processShared(lookup);
871                         
872                         for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }
873                 }
874                 
875                 delete input;
876                 
877                 return 0;
878                 
879         }
880         catch(exception& e) {
881                 m->errorOut(e, "SubSampleCommand", "getSubSampleShared");
882                 exit(1);
883         }
884 }
885 //**********************************************************************************************************************
886 int SubSampleCommand::processShared(vector<SharedRAbundVector*>& thislookup) {
887         try {
888                 
889                 //save mothurOut's binLabels to restore for next label
890                 vector<string> saveBinLabels = m->currentBinLabels;
891                 
892                 string thisOutputDir = outputDir;
893                 if (outputDir == "") {  thisOutputDir += m->hasPath(sharedfile);  }
894                 string outputFileName = thisOutputDir + m->getRootName(m->getSimpleName(sharedfile)) + thislookup[0]->getLabel() + "." +getOutputFileNameTag("shared", sharedfile);        
895         SubSample sample;
896         vector<string> subsampledLabels = sample.getSample(thislookup, size);
897         
898         if (m->control_pressed) {  return 0; }
899         
900         ofstream out;
901                 m->openOutputFile(outputFileName, out);
902                 outputTypes["shared"].push_back(outputFileName);  outputNames.push_back(outputFileName);
903                 
904         m->currentBinLabels = subsampledLabels;
905         
906                 thislookup[0]->printHeaders(out);
907                 
908                 for (int i = 0; i < thislookup.size(); i++) {
909                         out << thislookup[i]->getLabel() << '\t' << thislookup[i]->getGroup() << '\t';
910                         thislookup[i]->print(out);
911                 }
912                 out.close();
913         
914         
915         //save mothurOut's binLabels to restore for next label
916                 m->currentBinLabels = saveBinLabels;
917                 
918                 return 0;
919                 
920         }
921         catch(exception& e) {
922                 m->errorOut(e, "SubSampleCommand", "processShared");
923                 exit(1);
924         }
925 }                       
926 //**********************************************************************************************************************
927 int SubSampleCommand::getSubSampleList() {
928         try {
929                 
930                 string thisOutputDir = outputDir;
931                 if (outputDir == "") {  thisOutputDir += m->hasPath(listfile);  }
932                 string outputFileName = thisOutputDir + m->getRootName(m->getSimpleName(listfile)) + getOutputFileNameTag("list", listfile);            
933                 ofstream out;
934                 m->openOutputFile(outputFileName, out);
935                 outputTypes["list"].push_back(outputFileName);  outputNames.push_back(outputFileName);
936                 
937                 InputData* input = new InputData(listfile, "list");
938                 ListVector* list = input->getListVector();
939                 string lastLabel = list->getLabel();
940                 
941                 //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
942                 set<string> processedLabels;
943                 set<string> userLabels = labels;
944
945                 ofstream outGroup;
946                 GroupMap groupMap;
947                 if (groupfile != "") {
948                         groupMap.readMap(groupfile);
949                         
950                         //takes care of user setting groupNames that are invalid or setting groups=all
951                         SharedUtil util; vector<string> namesGroups = groupMap.getNamesOfGroups(); util.setGroups(Groups, namesGroups);
952                         
953                         //create outputfiles
954                         string groupOutputDir = outputDir;
955                         if (outputDir == "") {  groupOutputDir += m->hasPath(groupfile);  }
956                         string groupOutputFileName = groupOutputDir + m->getRootName(m->getSimpleName(groupfile)) + "subsample" + m->getExtension(groupfile);
957                         m->openOutputFile(groupOutputFileName, outGroup);
958                         outputTypes["group"].push_back(groupOutputFileName);  outputNames.push_back(groupOutputFileName);
959                         
960                         //file mismatch quit
961                         if (list->getNumSeqs() != groupMap.getNumSeqs()) { 
962                                 m->mothurOut("[ERROR]: your list file contains " + toString(list->getNumSeqs()) + " sequences, and your groupfile contains " + toString(groupMap.getNumSeqs()) + ", please correct."); 
963                                 m->mothurOutEndLine(); delete list; delete input; out.close(); outGroup.close(); return 0;
964                         }                       
965                 }else if (countfile != "") {
966             if (ct.hasGroupInfo()) {
967                 SharedUtil util;
968                 vector<string> namesGroups = ct.getNamesOfGroups();
969                 util.setGroups(Groups, namesGroups);
970             }
971             
972             //file mismatch quit
973                         if (list->getNumSeqs() != ct.getNumUniqueSeqs()) { 
974                                 m->mothurOut("[ERROR]: your list file contains " + toString(list->getNumSeqs()) + " sequences, and your count file contains " + toString(ct.getNumUniqueSeqs()) + " unique sequences, please correct."); 
975                                 m->mothurOutEndLine();
976                                 return 0;
977                         }       
978         }
979
980                 //make sure that if your picked groups size is not too big
981                 if (persample) {
982                         if (size == 0) { //user has not set size, set size = smallest samples size
983                                 if (countfile == "") { size = groupMap.getNumSeqs(Groups[0]); }
984                 else {  size = ct.getGroupCount(Groups[0]);  }
985                 
986                                 for (int i = 1; i < Groups.size(); i++) {
987                                         int thisSize = 0;
988                     if (countfile == "") { thisSize = groupMap.getNumSeqs(Groups[i]); }
989                     else {  thisSize = ct.getGroupCount(Groups[i]);  }
990                                         
991                                         if (thisSize < size) {  size = thisSize;        }
992                                 }
993                         }else { //make sure size is not too large
994                                 vector<string> newGroups;
995                                 for (int i = 0; i < Groups.size(); i++) {
996                                         int thisSize = 0;
997                     if (countfile == "") { thisSize = groupMap.getNumSeqs(Groups[i]); }
998                     else {  thisSize = ct.getGroupCount(Groups[i]);  }
999                                         
1000                                         if (thisSize >= size) { newGroups.push_back(Groups[i]); }
1001                                         else {  m->mothurOut("You have selected a size that is larger than " + Groups[i] + " number of sequences, removing " + Groups[i] + "."); m->mothurOutEndLine(); }
1002                                 }
1003                                 Groups = newGroups;
1004                 if (newGroups.size() == 0) {  m->mothurOut("[ERROR]: all groups removed."); m->mothurOutEndLine(); m->control_pressed = true; }
1005                         }
1006                         
1007                         m->mothurOut("Sampling " + toString(size) + " from each group."); m->mothurOutEndLine();                
1008                 }else{
1009             if (pickedGroups) {
1010                                 int total = 0;
1011                                 for(int i = 0; i < Groups.size(); i++) {
1012                     if (countfile == "") { total += groupMap.getNumSeqs(Groups[i]); }
1013                     else {  total += ct.getGroupCount(Groups[i]);  }
1014                                 }
1015                                 
1016                                 if (size == 0) { //user has not set size, set size = 10% samples size
1017                                         size = int (total * 0.10);
1018                                 }
1019                                 
1020                                 if (total < size) { 
1021                                         if (size != 0) { 
1022                                                 m->mothurOut("Your size is too large for the number of groups you selected. Adjusting to " + toString(int (total * 0.10)) + "."); m->mothurOutEndLine();
1023                                         }
1024                                         size = int (total * 0.10);
1025                                 }
1026                                 
1027                                 m->mothurOut("Sampling " + toString(size) + " from " + toString(total) + "."); m->mothurOutEndLine();
1028                         }else {
1029                 if (size == 0) { //user has not set size, set size = 10% samples size
1030                                         if (countfile == "") {  size = int (list->getNumSeqs() * 0.10);  }
1031                     else { size = int (ct.getNumSeqs() * 0.10);  }
1032                                 }
1033                                 
1034                                 int thisSize = 0;
1035                 if (countfile == "") { thisSize = list->getNumSeqs();  }
1036                 else { thisSize = ct.getNumSeqs(); }
1037                 
1038                                 if (size > thisSize) { m->mothurOut("Your list file only contains " + toString(thisSize) + " sequences. Setting size to " + toString(thisSize) + "."); m->mothurOutEndLine();
1039                                         size = thisSize;
1040                                 }
1041                                 
1042                                 m->mothurOut("Sampling " + toString(size) + " from " + toString(thisSize) + "."); m->mothurOutEndLine();
1043             }
1044         }
1045                 
1046         set<string> subset; //dont want repeat sequence names added
1047                 if (countfile == "") {
1048             //fill names
1049             for (int i = 0; i < list->getNumBins(); i++) {
1050                 string binnames = list->get(i);
1051                 vector<string> thisBin;
1052                 m->splitAtComma(binnames, thisBin);
1053                 
1054                 for(int j=0;j<thisBin.size();j++){
1055                     if (groupfile != "") { //if there is a groupfile given fill in group info
1056                         string group = groupMap.getGroup(thisBin[j]);
1057                         if (group == "not found") { m->mothurOut("[ERROR]: " + thisBin[j] + " is not in your groupfile. please correct."); m->mothurOutEndLine(); group = "NOTFOUND"; }
1058                         
1059                                                 //if hte user picked groups, we only want to keep the names of sequences from those groups
1060                                                 if (pickedGroups) { if (m->inUsersGroups(group, Groups)) { names.push_back(thisBin[j]); }  }
1061                                                 else{ names.push_back(thisBin[j]); } 
1062                     }//save everyone, group
1063                     else{ names.push_back(thisBin[j]); }
1064                 }
1065             }
1066             
1067             random_shuffle(names.begin(), names.end());
1068                         
1069             //randomly select a subset of those names to include in the subsample
1070             if (persample) {
1071                 //initialize counts
1072                 map<string, int> groupCounts;
1073                 map<string, int>::iterator itGroupCounts;
1074                 for (int i = 0; i < Groups.size(); i++) { groupCounts[Groups[i]] = 0; }
1075                 
1076                 for (int j = 0; j < names.size(); j++) {
1077                     
1078                     if (m->control_pressed) { delete list; delete input;  return 0; }
1079                     
1080                     string group = groupMap.getGroup(names[j]);
1081                     if (group == "not found") { m->mothurOut("[ERROR]: " + names[j] + " is not in your groupfile. please correct."); m->mothurOutEndLine(); group = "NOTFOUND"; }
1082                     else{
1083                         itGroupCounts = groupCounts.find(group);
1084                         if (itGroupCounts != groupCounts.end()) {
1085                             if (groupCounts[group] < size) {    subset.insert(names[j]);        groupCounts[group]++; }
1086                         }
1087                     }                           
1088                 }
1089             }else{
1090                 for (int j = 0; j < size; j++) {
1091                     if (m->control_pressed) { break; }
1092                     subset.insert(names[j]); 
1093                 }       
1094             }
1095             
1096             if (groupfile != "") { 
1097                 //write out new groupfile
1098                 for (set<string>::iterator it = subset.begin(); it != subset.end(); it++) {
1099                     string group = groupMap.getGroup(*it);
1100                     if (group == "not found") { group = "NOTFOUND"; }
1101                     outGroup << *it << '\t' << group << endl;
1102                 }
1103                 outGroup.close(); 
1104             }
1105                 }else {
1106             SubSample sample; CountTable sampledCt;
1107             
1108             if (persample)  { sampledCt = sample.getSample(ct, size, Groups);               }
1109             else            { sampledCt = sample.getSample(ct, size, Groups, pickedGroups); }
1110             
1111             vector<string> sampledSeqs = sampledCt.getNamesOfSeqs();
1112             for (int i = 0; i < sampledSeqs.size(); i++) { subset.insert(sampledSeqs[i]); }
1113         
1114             string countOutputDir = outputDir;
1115             if (outputDir == "") {  countOutputDir += m->hasPath(countfile);  }
1116             string countOutputFileName = countOutputDir + m->getRootName(m->getSimpleName(countfile)) + getOutputFileNameTag("count", countfile);
1117             outputTypes["count"].push_back(countOutputFileName);  outputNames.push_back(countOutputFileName);
1118             sampledCt.printTable(countOutputFileName);
1119         }
1120                                                 
1121                 //as long as you are not at the end of the file or done wih the lines you want
1122                 while((list != NULL) && ((allLines == 1) || (userLabels.size() != 0))) {
1123                         
1124                         if (m->control_pressed) {  delete list; delete input;  out.close();  return 0;  }
1125                         
1126                         if(allLines == 1 || labels.count(list->getLabel()) == 1){                       
1127                                 
1128                                 m->mothurOut(list->getLabel()); m->mothurOutEndLine();
1129                                 
1130                                 processList(list, out, subset);
1131                                 
1132                                 processedLabels.insert(list->getLabel());
1133                                 userLabels.erase(list->getLabel());
1134                         }
1135                         
1136                         if ((m->anyLabelsToProcess(list->getLabel(), userLabels, "") == true) && (processedLabels.count(lastLabel) != 1)) {
1137                                 string saveLabel = list->getLabel();
1138                                 
1139                                 delete list; 
1140                                 
1141                                 list = input->getListVector(lastLabel);
1142                                 m->mothurOut(list->getLabel()); m->mothurOutEndLine();
1143                                 
1144                                 processList(list, out, subset);
1145                                 
1146                                 processedLabels.insert(list->getLabel());
1147                                 userLabels.erase(list->getLabel());
1148                                 
1149                                 //restore real lastlabel to save below
1150                                 list->setLabel(saveLabel);
1151                         }
1152                         
1153                         lastLabel = list->getLabel();
1154                         
1155                         delete list; list = NULL;
1156                         
1157                         //get next line to process
1158                         list = input->getListVector();                          
1159                 }
1160                 
1161                 
1162                 if (m->control_pressed) {  if (list != NULL) { delete list; } delete input; out.close(); return 0;  }
1163                 
1164                 //output error messages about any remaining user labels
1165                 set<string>::iterator it;
1166                 bool needToRun = false;
1167                 for (it = userLabels.begin(); it != userLabels.end(); it++) {  
1168                         m->mothurOut("Your file does not include the label " + *it); 
1169                         if (processedLabels.count(lastLabel) != 1) {
1170                                 m->mothurOut(". I will use " + lastLabel + "."); m->mothurOutEndLine();
1171                                 needToRun = true;
1172                         }else {
1173                                 m->mothurOut(". Please refer to " + lastLabel + "."); m->mothurOutEndLine();
1174                         }
1175                 }
1176                 
1177                 //run last label if you need to
1178                 if (needToRun == true)  {
1179                         if (list != NULL) { delete list; }
1180                         
1181                         list = input->getListVector(lastLabel);
1182                         
1183                         m->mothurOut(list->getLabel()); m->mothurOutEndLine();
1184                         
1185                         processList(list, out, subset);
1186                         
1187                         delete list; list = NULL;
1188                 }
1189                 
1190                 out.close();  
1191                 if (list != NULL) { delete list; }
1192                 delete input;
1193                                                 
1194                 return 0;
1195  
1196         }
1197         catch(exception& e) {
1198                 m->errorOut(e, "SubSampleCommand", "getSubSampleList");
1199                 exit(1);
1200         }
1201 }
1202 //**********************************************************************************************************************
1203 int SubSampleCommand::processList(ListVector*& list, ofstream& out, set<string>& subset) {
1204         try {
1205                                 
1206                 int numBins = list->getNumBins();
1207
1208                 ListVector* temp = new ListVector();
1209                 temp->setLabel(list->getLabel());
1210                 
1211                 for (int i = 0; i < numBins; i++) {
1212                         
1213                         if (m->control_pressed) { break; }
1214                         
1215                         string bin = list->get(i);
1216             vector<string> binnames;
1217             m->splitAtComma(bin, binnames);
1218                         
1219             string newNames = "";
1220                         for(int j=0;j<binnames.size();j++){ if (subset.count(binnames[j]) != 0) {  newNames += binnames[j] + ",";  } }
1221                         
1222                         //if there are names in this bin add to new list
1223                         if (newNames != "") { 
1224                                 newNames = newNames.substr(0, newNames.length()-1); //rip off extra comma
1225                                 temp->push_back(newNames);
1226                         }
1227                 }
1228                 
1229                 delete list;
1230                 list = temp;
1231                 
1232                 if (m->control_pressed) { return 0; }
1233                 
1234                 list->print(out);
1235                 
1236                 return 0;
1237                 
1238         }
1239         catch(exception& e) {
1240                 m->errorOut(e, "SubSampleCommand", "processList");
1241                 exit(1);
1242         }
1243 }
1244 //**********************************************************************************************************************
1245 int SubSampleCommand::getSubSampleRabund() {
1246         try {
1247                 InputData* input = new InputData(rabundfile, "rabund");
1248                 RAbundVector* rabund = input->getRAbundVector();
1249                 string lastLabel = rabund->getLabel();
1250                 
1251                 //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
1252                 set<string> processedLabels;
1253                 set<string> userLabels = labels;
1254                 
1255                 if (size == 0) { //user has not set size, set size = 10%
1256                         size = int((rabund->getNumSeqs()) * 0.10);
1257                 }else if (size > rabund->getNumSeqs()) { m->mothurOut("The size you selected is too large, skipping rabund file."); m->mothurOutEndLine(); delete input; delete rabund; return 0; }
1258                 
1259                 m->mothurOut("Sampling " + toString(size) + " from " + toString(rabund->getNumSeqs()) + "."); m->mothurOutEndLine();
1260                 
1261                 string thisOutputDir = outputDir;
1262                 if (outputDir == "") {  thisOutputDir += m->hasPath(rabundfile);  }
1263                 string outputFileName = thisOutputDir + m->getRootName(m->getSimpleName(rabundfile)) + getOutputFileNameTag("rabund", rabundfile);              
1264                 ofstream out;
1265                 m->openOutputFile(outputFileName, out);
1266                 outputTypes["rabund"].push_back(outputFileName);  outputNames.push_back(outputFileName);
1267                 
1268                 //as long as you are not at the end of the file or done wih the lines you want
1269                 while((rabund != NULL) && ((allLines == 1) || (userLabels.size() != 0))) {
1270                         if (m->control_pressed) {  delete input; delete rabund; out.close(); return 0;  }
1271                         
1272                         if(allLines == 1 || labels.count(rabund->getLabel()) == 1){                     
1273                                 
1274                                 m->mothurOut(rabund->getLabel()); m->mothurOutEndLine();
1275                                 
1276                                 processRabund(rabund, out);
1277                                 
1278                                 processedLabels.insert(rabund->getLabel());
1279                                 userLabels.erase(rabund->getLabel());
1280                         }
1281                         
1282                         if ((m->anyLabelsToProcess(rabund->getLabel(), userLabels, "") == true) && (processedLabels.count(lastLabel) != 1)) {
1283                                 string saveLabel = rabund->getLabel();
1284                                 
1285                                 delete rabund; 
1286                                 
1287                                 rabund = input->getRAbundVector(lastLabel);
1288                                 m->mothurOut(rabund->getLabel()); m->mothurOutEndLine();
1289                                 
1290                                 processRabund(rabund, out);
1291                                 
1292                                 processedLabels.insert(rabund->getLabel());
1293                                 userLabels.erase(rabund->getLabel());
1294                                 
1295                                 //restore real lastlabel to save below
1296                                 rabund->setLabel(saveLabel);
1297                         }
1298                         
1299                         lastLabel = rabund->getLabel();
1300                         
1301                         //prevent memory leak
1302                         delete rabund; rabund = NULL;
1303                         
1304                         //get next line to process
1305                         rabund = input->getRAbundVector();                              
1306                 }
1307                 
1308                 
1309                 if (m->control_pressed) {  out.close(); return 0;  }
1310                 
1311                 //output error messages about any remaining user labels
1312                 set<string>::iterator it;
1313                 bool needToRun = false;
1314                 for (it = userLabels.begin(); it != userLabels.end(); it++) {  
1315                         m->mothurOut("Your file does not include the label " + *it); 
1316                         if (processedLabels.count(lastLabel) != 1) {
1317                                 m->mothurOut(". I will use " + lastLabel + "."); m->mothurOutEndLine();
1318                                 needToRun = true;
1319                         }else {
1320                                 m->mothurOut(". Please refer to " + lastLabel + "."); m->mothurOutEndLine();
1321                         }
1322                 }
1323                 
1324                 //run last label if you need to
1325                 if (needToRun == true)  {
1326                         if (rabund != NULL) { delete rabund; }
1327                         
1328                         rabund = input->getRAbundVector(lastLabel);
1329                         
1330                         m->mothurOut(rabund->getLabel()); m->mothurOutEndLine();
1331                         
1332                         processRabund(rabund, out);
1333                         
1334                         delete rabund;
1335                 }
1336                 
1337                 delete input;
1338                 out.close();  
1339                 
1340                 return 0;
1341                 
1342         }
1343         catch(exception& e) {
1344                 m->errorOut(e, "SubSampleCommand", "getSubSampleRabund");
1345                 exit(1);
1346         }
1347 }
1348 //**********************************************************************************************************************
1349 int SubSampleCommand::processRabund(RAbundVector*& rabund, ofstream& out) {
1350         try {
1351                 
1352                 int numBins = rabund->getNumBins();
1353                 int thisSize = rabund->getNumSeqs();
1354                         
1355                 if (thisSize != size) {
1356                                 
1357                         OrderVector* order = new OrderVector();
1358                         for(int p=0;p<numBins;p++){
1359                                 for(int j=0;j<rabund->get(p);j++){
1360                                         order->push_back(p);
1361                                 }
1362                         }
1363                         random_shuffle(order->begin(), order->end());
1364                         
1365                         RAbundVector* temp = new RAbundVector(numBins);
1366                         temp->setLabel(rabund->getLabel());
1367                         
1368                         delete rabund;
1369                         rabund = temp;
1370                         
1371                         for (int j = 0; j < size; j++) {
1372                                 
1373                                 if (m->control_pressed) { delete order; return 0; }
1374                                 
1375                                 int bin = order->get(j);
1376                                 
1377                                 int abund = rabund->get(bin);
1378                                 rabund->set(bin, (abund+1));
1379                         }
1380                         
1381                         delete order;
1382                 }
1383                 
1384                 if (m->control_pressed) { return 0; }
1385                 
1386                 rabund->print(out);
1387                 
1388                 return 0;
1389                 
1390         }
1391         catch(exception& e) {
1392                 m->errorOut(e, "SubSampleCommand", "processRabund");
1393                 exit(1);
1394         }
1395 }       
1396 //**********************************************************************************************************************
1397 int SubSampleCommand::getSubSampleSabund() {
1398         try {
1399                                 
1400                 InputData* input = new InputData(sabundfile, "sabund");
1401                 SAbundVector* sabund = input->getSAbundVector();
1402                 string lastLabel = sabund->getLabel();
1403                 
1404                 //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
1405                 set<string> processedLabels;
1406                 set<string> userLabels = labels;
1407                 
1408                 if (size == 0) { //user has not set size, set size = 10%
1409                         size = int((sabund->getNumSeqs()) * 0.10);
1410                 }else if (size > sabund->getNumSeqs()) { m->mothurOut("The size you selected is too large, skipping sabund file."); m->mothurOutEndLine(); delete input; delete sabund; return 0; }
1411                 
1412                 
1413                 m->mothurOut("Sampling " + toString(size) + " from " + toString(sabund->getNumSeqs()) + "."); m->mothurOutEndLine();
1414                 
1415                 string thisOutputDir = outputDir;
1416                 if (outputDir == "") {  thisOutputDir += m->hasPath(sabundfile);  }
1417                 string outputFileName = thisOutputDir + m->getRootName(m->getSimpleName(sabundfile)) + getOutputFileNameTag("sabund", sabundfile);              
1418                 ofstream out;
1419                 m->openOutputFile(outputFileName, out);
1420                 outputTypes["sabund"].push_back(outputFileName);  outputNames.push_back(outputFileName);
1421                 
1422                 
1423                 //as long as you are not at the end of the file or done wih the lines you want
1424                 while((sabund != NULL) && ((allLines == 1) || (userLabels.size() != 0))) {
1425                         if (m->control_pressed) {  delete input; delete sabund; out.close(); return 0;  }
1426                         
1427                         if(allLines == 1 || labels.count(sabund->getLabel()) == 1){                     
1428                                 
1429                                 m->mothurOut(sabund->getLabel()); m->mothurOutEndLine();
1430                                 
1431                                 processSabund(sabund, out);
1432                                 
1433                                 processedLabels.insert(sabund->getLabel());
1434                                 userLabels.erase(sabund->getLabel());
1435                         }
1436                         
1437                         if ((m->anyLabelsToProcess(sabund->getLabel(), userLabels, "") == true) && (processedLabels.count(lastLabel) != 1)) {
1438                                 string saveLabel = sabund->getLabel();
1439                                 
1440                                 delete sabund; 
1441                                 
1442                                 sabund = input->getSAbundVector(lastLabel);
1443                                 m->mothurOut(sabund->getLabel()); m->mothurOutEndLine();
1444                                 
1445                                 processSabund(sabund, out);
1446                                 
1447                                 processedLabels.insert(sabund->getLabel());
1448                                 userLabels.erase(sabund->getLabel());
1449                                 
1450                                 //restore real lastlabel to save below
1451                                 sabund->setLabel(saveLabel);
1452                         }
1453                         
1454                         lastLabel = sabund->getLabel();
1455                         
1456                         //prevent memory leak
1457                         delete sabund; sabund = NULL;
1458                         
1459                         //get next line to process
1460                         sabund = input->getSAbundVector();                              
1461                 }
1462                 
1463                 
1464                 if (m->control_pressed) {  out.close(); return 0;  }
1465                 
1466                 //output error messages about any remaining user labels
1467                 set<string>::iterator it;
1468                 bool needToRun = false;
1469                 for (it = userLabels.begin(); it != userLabels.end(); it++) {  
1470                         m->mothurOut("Your file does not include the label " + *it); 
1471                         if (processedLabels.count(lastLabel) != 1) {
1472                                 m->mothurOut(". I will use " + lastLabel + "."); m->mothurOutEndLine();
1473                                 needToRun = true;
1474                         }else {
1475                                 m->mothurOut(". Please refer to " + lastLabel + "."); m->mothurOutEndLine();
1476                         }
1477                 }
1478                 
1479                 //run last label if you need to
1480                 if (needToRun == true)  {
1481                         if (sabund != NULL) { delete sabund; }
1482                         
1483                         sabund = input->getSAbundVector(lastLabel);
1484                         
1485                         m->mothurOut(sabund->getLabel()); m->mothurOutEndLine();
1486                         
1487                         processSabund(sabund, out);
1488                         
1489                         delete sabund;
1490                 }
1491                 
1492                 delete input;
1493                 out.close();  
1494                 
1495                 return 0;
1496                 
1497         }
1498         catch(exception& e) {
1499                 m->errorOut(e, "SubSampleCommand", "getSubSampleSabund");
1500                 exit(1);
1501         }
1502 }
1503 //**********************************************************************************************************************
1504 int SubSampleCommand::processSabund(SAbundVector*& sabund, ofstream& out) {
1505         try {
1506                 
1507                 RAbundVector* rabund = new RAbundVector();
1508                 *rabund = sabund->getRAbundVector();
1509                 
1510                 int numBins = rabund->getNumBins();
1511                 int thisSize = rabund->getNumSeqs();
1512         
1513                 if (thisSize != size) {
1514                         
1515                         OrderVector* order = new OrderVector();
1516                         for(int p=0;p<numBins;p++){
1517                                 for(int j=0;j<rabund->get(p);j++){
1518                                         order->push_back(p);
1519                                 }
1520                         }
1521                         random_shuffle(order->begin(), order->end());
1522                         
1523                         RAbundVector* temp = new RAbundVector(numBins);
1524                         temp->setLabel(rabund->getLabel());
1525                         
1526                         delete rabund;
1527                         rabund = temp;
1528                         
1529                         for (int j = 0; j < size; j++) {
1530         
1531                                 if (m->control_pressed) { delete order; return 0; }
1532                                 
1533                                 int bin = order->get(j);
1534                                 
1535                                 int abund = rabund->get(bin);
1536                                 rabund->set(bin, (abund+1));
1537                         }
1538                         
1539                         delete order;
1540                 }
1541                 
1542                 if (m->control_pressed) { return 0; }
1543
1544                 delete sabund;
1545                 sabund = new SAbundVector();
1546                 *sabund = rabund->getSAbundVector();
1547                 delete rabund;
1548         
1549                 sabund->print(out);
1550                 
1551                 return 0;
1552                 
1553         }
1554         catch(exception& e) {
1555                 m->errorOut(e, "SubSampleCommand", "processSabund");
1556                 exit(1);
1557         }
1558 }                       
1559 //**********************************************************************************************************************
1560
1561
1562