]> git.donarmstrong.com Git - mothur.git/blob - newcommandtemplate.cpp
added load.logfile command. changed summary.single output for subsample=t.
[mothur.git] / newcommandtemplate.cpp
1 //
2 //  newcommandtemplate.cpp
3 //  Mothur
4 //
5 //  Created by Sarah Westcott on 5/3/12.
6 //  Copyright (c) 2012 Schloss Lab. All rights reserved.
7 //
8
9
10 #include "newcommandtemplate.h"
11
12 //**********************************************************************************************************************
13 vector<string> NewCommand::setParameters(){     
14         try {
15                 //eaxamples of each type of parameter. more info on the types of parameters can be found in commandparameter.h
16                 CommandParameter pprocessors("processors", "Number", "", "1", "", "", "",false,false); parameters.push_back(pprocessors);
17         
18         //files that have dependancies
19         CommandParameter pphylip("phylip", "InputTypes", "", "", "PhylipColumn", "PhylipColumn", "none",false,false); parameters.push_back(pphylip);
20                 CommandParameter pname("name", "InputTypes", "", "", "none", "none", "ColumnName",false,false); parameters.push_back(pname);
21                 CommandParameter pcolumn("column", "InputTypes", "", "", "PhylipColumn", "PhylipColumn", "ColumnName",false,false); parameters.push_back(pcolumn);              
22         //files that do not have dependancies - fasta is set to not be required whereas shared is set to be required
23                 CommandParameter pfasta("fasta", "InputTypes", "", "", "none", "none", "none",false,false); parameters.push_back(pfasta);
24         CommandParameter pshared("shared", "InputTypes", "", "", "none", "none", "none",false,true); parameters.push_back(pshared);             
25
26         
27         CommandParameter pgroups("groups", "String", "", "", "", "", "",false,false); parameters.push_back(pgroups);
28                 CommandParameter plabel("label", "String", "", "", "", "", "",false,false); parameters.push_back(plabel);
29                 
30         //choose more than one multiple options
31         CommandParameter pcalc("calc", "Multiple", "jabund-sorabund-jclass-sorclass-jest-sorest-thetayc-thetan-morisitahorn-braycurtis", "jest-thetayc", "", "", "",true,false); parameters.push_back(pcalc);
32         //choose only one multiple options
33         CommandParameter pdistance("distance", "Multiple", "column-lt-square", "column", "", "", "",false,false); parameters.push_back(pdistance);
34         
35         CommandParameter ptiming("timing", "Boolean", "", "F", "", "", "",false,false); parameters.push_back(ptiming);
36         
37         //every command must have inputdir and outputdir.  This allows mothur users to redirect input and output files.
38                 CommandParameter pinputdir("inputdir", "String", "", "", "", "", "",false,false); parameters.push_back(pinputdir);
39                 CommandParameter poutputdir("outputdir", "String", "", "", "", "", "",false,false); parameters.push_back(poutputdir);
40                 
41                 vector<string> myArray;
42                 for (int i = 0; i < parameters.size(); i++) {   myArray.push_back(parameters[i].name);          }
43                 return myArray;
44         }
45         catch(exception& e) {
46                 m->errorOut(e, "NewCommand", "setParameters");
47                 exit(1);
48         }
49 }
50 //**********************************************************************************************************************
51 string NewCommand::getHelpString(){     
52         try {
53                 string helpString = "";
54                 helpString += "The new command allows you to ....\n";
55                 helpString += "The new command parameters are: ....\n";
56                 helpString += "The whatever parameter is used to ....\n";
57                 helpString += "The new command should be in the following format: \n";
58                 helpString += "new(...)\n";
59                 return helpString;
60         }
61         catch(exception& e) {
62                 m->errorOut(e, "NewCommand", "getHelpString");
63                 exit(1);
64         }
65 }
66 //**********************************************************************************************************************
67 string NewCommand::getOutputFileNameTag(string type, string inputName=""){      
68         try {
69         string tag = "";
70                 map<string, vector<string> >::iterator it;
71         
72         //is this a type this command creates
73         it = outputTypes.find(type);
74         if (it == outputTypes.end()) {  m->mothurOut("[ERROR]: this command doesn't create a " + type + " output file.\n"); }
75         else {
76             if (type == "fileType1") {  tag = "tag1"; }
77             else if (type == "fileType2") {  tag = "tag2"; }
78             else if (type == "fileType3") {  tag = "tag3"; }
79             else { m->mothurOut("[ERROR]: No definition for type " + type + " output file tag.\n"); m->control_pressed = true;  }
80         }
81         return tag;
82         }
83         catch(exception& e) {
84                 m->errorOut(e, "NewCommand", "getOutputFileName");
85                 exit(1);
86         }
87 }
88 //**********************************************************************************************************************
89 NewCommand::NewCommand(){       
90         try {
91                 abort = true; calledHelp = true;
92                 setParameters();
93         vector<string> tempOutNames;
94                 outputTypes["fileType1"] = tempOutNames; //filetypes should be things like: shared, fasta, accnos...
95                 outputTypes["fileType2"] = tempOutNames;
96                 outputTypes["FileType3"] = tempOutNames;
97         }
98         catch(exception& e) {
99                 m->errorOut(e, "NewCommand", "NewCommand");
100                 exit(1);
101         }
102 }
103 //**********************************************************************************************************************
104 NewCommand::NewCommand(string option)  {
105         try {
106 ////////////////////////////////////////////////////////
107 /////////////////// start leave alone block ////////////
108 ////////////////////////////////////////////////////////
109                 abort = false; calledHelp = false;   
110                 
111                 //allow user to run help
112                 if(option == "help") { help(); abort = true; calledHelp = true; }
113                 else if(option == "citation") { citation(); abort = true; calledHelp = true;}
114                 
115                 else {
116                         //valid paramters for this command
117                         vector<string> myArray = setParameters();
118                         
119                         OptionParser parser(option);
120                         map<string,string> parameters = parser.getParameters();
121                         
122                         ValidParameters validParameter;
123                         map<string,string>::iterator it;
124                         //check to make sure all parameters are valid for command
125                         for (it = parameters.begin(); it != parameters.end(); it++) { 
126                                 if (validParameter.isValidParameter(it->first, myArray, it->second) != true) {  abort = true;  }
127                         }
128                         
129                         
130                         //if the user changes the input directory command factory will send this info to us in the output parameter 
131                         string inputDir = validParameter.validFile(parameters, "inputdir", false);              
132                         if (inputDir == "not found"){   inputDir = "";          }
133                         else {
134                 
135 ///////////////////////////////////////////////////////////////
136 //////////////// stop leave alone block ///////////////////////
137 ///////////////////////////////////////////////////////////////
138                 
139 //edit file types below to include only the types you added as parameters
140                 
141                                 string path;
142                                 it = parameters.find("phylip");
143                                 //user has given a template file
144                                 if(it != parameters.end()){ 
145                                         path = m->hasPath(it->second);
146                                         //if the user has not given a path then, add inputdir. else leave path alone.
147                                         if (path == "") {       parameters["phylip"] = inputDir + it->second;           }
148                                 }
149                                 
150                                 it = parameters.find("column");
151                                 //user has given a template file
152                                 if(it != parameters.end()){ 
153                                         path = m->hasPath(it->second);
154                                         //if the user has not given a path then, add inputdir. else leave path alone.
155                                         if (path == "") {       parameters["column"] = inputDir + it->second;           }
156                                 }
157                                 
158                                 it = parameters.find("fasta");
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["fasta"] = inputDir + it->second;            }
164                                 }
165                                                                 
166                                 it = parameters.find("name");
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["name"] = 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 ///////////////////////////////////////////////////////////////////////////////
183 /////////// example of getting filenames and checking dependancies ////////////
184 // the validParameter class will make sure file exists, fill with correct    //
185 // and name is current is given ///////////////////////////////////////////////
186 ///////////////////////////////////////////////////////////////////////////////
187             
188             
189             ///variables for examples below that you will most likely want to put in the header for 
190             //use by the other class functions.
191             string phylipfile, columnfile, namefile, fastafile, sharedfile, method;
192             int processors;
193             bool useTiming, allLines;
194             vector<string> Estimators, Groups;
195             set<string> labels;
196             //if allLines is used it should be initialized to 1 above.
197             
198             
199                         //check for parameters
200             phylipfile = validParameter.validFile(parameters, "phylip", true);
201                         if (phylipfile == "not open") { phylipfile = ""; abort = true; }
202                         else if (phylipfile == "not found") { phylipfile = ""; }        
203                         else {  m->setPhylipFile(phylipfile); }
204                         
205                         columnfile = validParameter.validFile(parameters, "column", true);
206                         if (columnfile == "not open") { columnfile = ""; abort = true; }        
207                         else if (columnfile == "not found") { columnfile = ""; }
208                         else {   m->setColumnFile(columnfile);  }
209                         
210                         namefile = validParameter.validFile(parameters, "name", true);
211                         if (namefile == "not open") { abort = true; }   
212                         else if (namefile == "not found") { namefile = ""; }
213                         else { m->setNameFile(namefile); }
214             
215             //get fastafile - it is not required
216             fastafile = validParameter.validFile(parameters, "fasta", true);
217                         if (fastafile == "not open") { fastafile = ""; abort=true;  }
218                         else if (fastafile == "not found") {  fastafile = "";  }
219                         if (fastafile != "") { m->setFastaFile(fastafile); }
220
221                         
222                         if ((phylipfile == "") && (columnfile == "")) { 
223                                 //is there are current file available for either of these?
224                                 //give priority to column, then phylip
225                                 columnfile = m->getColumnFile(); 
226                                 if (columnfile != "") {   m->mothurOut("Using " + columnfile + " as input file for the column parameter."); m->mothurOutEndLine(); }
227                                 else { 
228                                         phylipfile = m->getPhylipFile(); 
229                                         if (phylipfile != "") {  m->mothurOut("Using " + phylipfile + " as input file for the phylip parameter."); m->mothurOutEndLine(); }
230                                         else { 
231                                                 m->mothurOut("No valid current files. You must provide a phylip or column file before you can use the cluster command."); m->mothurOutEndLine(); 
232                                                 abort = true;
233                                         }
234                                 }
235                         }
236                         else if ((phylipfile != "") && (columnfile != "")) { m->mothurOut("When executing a cluster command you must enter ONLY ONE of the following: phylip or column."); m->mothurOutEndLine(); abort = true; }
237                         
238                         if (columnfile != "") {
239                                 if (namefile == "") { 
240                                         namefile = m->getNameFile(); 
241                                         if (namefile != "") {  m->mothurOut("Using " + namefile + " as input file for the name parameter."); m->mothurOutEndLine(); }
242                                         else { 
243                                                 m->mothurOut("You need to provide a namefile if you are going to use the column format."); m->mothurOutEndLine(); 
244                                                 abort = true; 
245                                         }       
246                                 }
247                         }
248             
249             //get shared file, it is required
250                         sharedfile = validParameter.validFile(parameters, "shared", true);
251                         if (sharedfile == "not open") { sharedfile = ""; abort = true; }        
252                         else if (sharedfile == "not found") { 
253                                 //if there is a current shared file, use it
254                                 sharedfile = m->getSharedFile(); 
255                                 if (sharedfile != "") { m->mothurOut("Using " + sharedfile + " as input file for the shared parameter."); m->mothurOutEndLine(); }
256                                 else {  m->mothurOut("You have no current sharedfile and the shared parameter is required."); m->mothurOutEndLine(); abort = true; }
257                         }else { m->setSharedFile(sharedfile); }
258             
259             //if the user changes the output directory command factory will send this info to us in the output parameter 
260                         outputDir = validParameter.validFile(parameters, "outputdir", false);           if (outputDir == "not found"){  
261                                 outputDir = m->hasPath(sharedfile); //if user entered a file with a path then preserve it       
262                         }
263
264                         
265 //////////////////////////////////////////////////////////////////////
266 ////////// example of getting other types of parameters //////////////
267 //////////////////////////////////////////////////////////////////////
268             
269                         //use only one Mutliple type
270                         method = validParameter.validFile(parameters, "method", false);
271                         if (method == "not found") { method = "average"; }
272                         
273                         if ((method == "furthest") || (method == "nearest") || (method == "average") || (method == "weighted")) { }
274                         else { m->mothurOut("Not a valid clustering method.  Valid clustering algorithms are furthest, nearest, average, and weighted."); m->mothurOutEndLine(); abort = true; }
275             
276             //use more than one multiple type. do not check to make sure the entry is valid.
277             string calc = validParameter.validFile(parameters, "calc", false);                  
278                         if (calc == "not found") { calc = "sobs-chao-ace-jack-shannon-npshannon-simpson";  }
279                         else { 
280                 if (calc == "default")  {  calc = "sobs-chao-ace-jack-shannon-npshannon-simpson";  }
281                         }
282                         m->splitAtDash(calc, Estimators);
283             
284             //Boolean type - m->isTrue looks for t, true, f or false and is case insensitive
285                         string timing = validParameter.validFile(parameters, "timing", false);
286                         if (timing == "not found") { timing = "F"; }
287             useTiming = m->isTrue(timing);
288                         
289             //Number type - mothurConvert makes sure the convert can happen to avoid a crash.
290             string temp = validParameter.validFile(parameters, "processors", false);    if (temp == "not found"){       temp = m->getProcessors();      }
291                         m->setProcessors(temp);
292                         m->mothurConvert(temp, processors);
293             
294             //Groups must be checked later to make sure they are valid. SharedUtilities has functions of check the validity, just make to so m->setGroups() after the checks.  If you are using these with a shared file no need to check the SharedRAbundVector class will call SharedUtilites for you, kinda nice, huh?
295             string groups = validParameter.validFile(parameters, "groups", false);                      
296                         if (groups == "not found") { groups = ""; }
297                         else { m->splitAtDash(groups, Groups); }
298                         m->setGroups(Groups);
299             
300             //Commonly used to process list, rabund, sabund, shared and relabund files.  Look at "smart distancing" examples below in the execute function.
301             string label = validParameter.validFile(parameters, "label", false);                        
302                         if (label == "not found") { label = ""; }
303                         else { 
304                                 if(label != "all") {  m->splitAtDash(label, labels);  allLines = 0;  }
305                                 else { allLines = 1;  }
306                         }
307             
308             //if your command has a namefile as an option, you may want ot check to see if there is a current namefile
309             //saved by mothur that is associated with the other files you are using as inputs.  
310             //You can do so by adding the files associated with the namefile to the files vector and then asking parser to check.  
311             //This saves our users headaches over file mismatches because they forgot to include the namefile, :)
312             if (namefile == "") {
313                                 vector<string> files; files.push_back(fastafile);
314                                 parser.getNameFile(files);
315                         }
316                         
317                 }
318                 
319         }
320         catch(exception& e) {
321                 m->errorOut(e, "NewCommand", "NewCommand");
322                 exit(1);
323         }
324 }
325 //**********************************************************************************************************************
326
327 int NewCommand::execute(){
328         try {
329                 
330                 if (abort == true) { if (calledHelp) { return 0; }  return 2;   }
331         
332         // reading and processing a shared file code example
333         // Note: As long as you set groups and labels as shown in the constructor, you can use this code without modification other than adding your function call which is passed the lookup vector.
334         // The classes used below will handle the checking of groups to make sure they are valid and returning only the groups you selected.  The while loop implements mothur "smart distancing" so as long as you filled label as shown above in the constructor the code below will handle bad labels or labels not included in the sharedfile.
335          
336          //Reads sharefile, binLabels are stored in m->currentBinLabels, lookup will be filled with groups in m->getGroups() or all groups in file if m->getGroups is empty. If groups are selected, some bins maybe eliminated if they only contained seqs from groups not included. No need to worry about the details of this, SharedRAbundVector takes care of it.  Just make sure to use m->currentBinLabels if you are outputting OTU labels so that if otus are eliminated you still have the correct names.
337         
338         /*
339          InputData input(sharedfile, "sharedfile");
340          vector<SharedRAbundVector*> lookup = input.getSharedRAbundVectors();
341          string lastLabel = lookup[0]->getLabel();
342          
343          //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
344          set<string> processedLabels;
345          set<string> userLabels = labels;
346          
347                   
348          //as long as you are not at the end of the file or done wih the lines you want
349          while((lookup[0] != NULL) && ((allLines == 1) || (userLabels.size() != 0))) {
350          
351          if (m->control_pressed) { for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }  return 0; }
352          
353          if(allLines == 1 || labels.count(lookup[0]->getLabel()) == 1){                 
354          
355          m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
356          
357          ///////////////////////////////////////////////////////////////////////////////////
358          //// Call your function to process specific distance in sharedfile, ie lookup /////
359          ///////////////////////////////////////////////////////////////////////////////////
360          
361          processedLabels.insert(lookup[0]->getLabel());
362          userLabels.erase(lookup[0]->getLabel());
363          }
364          
365          if ((m->anyLabelsToProcess(lookup[0]->getLabel(), userLabels, "") == true) && (processedLabels.count(lastLabel) != 1)) {
366          string saveLabel = lookup[0]->getLabel();
367          
368          for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }  
369          lookup = input.getSharedRAbundVectors(lastLabel);
370          m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
371          
372          ///////////////////////////////////////////////////////////////////////////////////
373          //// Call your function to process specific distance in sharedfile, ie lookup /////
374          ///////////////////////////////////////////////////////////////////////////////////
375
376          
377          processedLabels.insert(lookup[0]->getLabel());
378          userLabels.erase(lookup[0]->getLabel());
379          
380          //restore real lastlabel to save below
381          lookup[0]->setLabel(saveLabel);
382          }
383          
384          lastLabel = lookup[0]->getLabel();
385          //prevent memory leak
386          for (int i = 0; i < lookup.size(); i++) {  delete lookup[i]; lookup[i] = NULL; }
387          
388          if (m->control_pressed) { return 0; }
389          
390          //get next line to process
391          lookup = input.getSharedRAbundVectors();                               
392          }
393          
394          if (m->control_pressed) {  return 0; }
395          
396          //output error messages about any remaining user labels
397          set<string>::iterator it;
398          bool needToRun = false;
399          for (it = userLabels.begin(); it != userLabels.end(); it++) {  
400          m->mothurOut("Your file does not include the label " + *it); 
401          if (processedLabels.count(lastLabel) != 1) {
402          m->mothurOut(". I will use " + lastLabel + "."); m->mothurOutEndLine();
403          needToRun = true;
404          }else {
405          m->mothurOut(". Please refer to " + lastLabel + "."); m->mothurOutEndLine();
406          }
407          }
408          
409          //run last label if you need to
410          if (needToRun == true)  {
411          for (int i = 0; i < lookup.size(); i++) { if (lookup[i] != NULL) { delete lookup[i]; } }  
412          lookup = input.getSharedRAbundVectors(lastLabel);
413          
414          m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
415          
416          ///////////////////////////////////////////////////////////////////////////////////
417          //// Call your function to process specific distance in sharedfile, ie lookup /////
418          ///////////////////////////////////////////////////////////////////////////////////
419
420          
421          for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }
422          }
423          */
424         
425         
426         
427         //if you make a new file or a type that mothur keeps track of the current version, you can update it with something like the following.
428                 string currentFasta = "";
429                 itTypes = outputTypes.find("fasta");
430                 if (itTypes != outputTypes.end()) {
431                         if ((itTypes->second).size() != 0) { currentFasta = (itTypes->second)[0]; m->setFastaFile(currentFasta); }
432                 }
433                 
434         //output files created by command
435                 m->mothurOutEndLine();
436                 m->mothurOut("Output File Names: "); m->mothurOutEndLine();
437                 for (int i = 0; i < outputNames.size(); i++) {  m->mothurOut(outputNames[i]); m->mothurOutEndLine();    }
438                 m->mothurOutEndLine();
439         return 0;
440                 
441     }
442         catch(exception& e) {
443                 m->errorOut(e, "NewCommand", "NewCommand");
444                 exit(1);
445         }
446 }
447 //**********************************************************************************************************************
448
449