]> git.donarmstrong.com Git - mothur.git/blob - newcommandtemplate.cpp
Merge remote-tracking branch 'origin/master'
[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","outputType",false,false); parameters.push_back(pphylip);
20                 CommandParameter pname("name", "InputTypes", "", "", "none", "none", "ColumnName","outputType",false,false); parameters.push_back(pname);
21                 CommandParameter pcolumn("column", "InputTypes", "", "", "PhylipColumn", "PhylipColumn", "ColumnName","outputType",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","outputType",false,false); parameters.push_back(pfasta);
24         CommandParameter pshared("shared", "InputTypes", "", "", "none", "none", "none","outputType",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::getOutputPattern(string type) {
68     try {
69         string pattern = "";
70         
71         if (type == "fileType1") {  pattern = "[filename],tag1"; }
72         else if (type == "fileType2") {  pattern = "[filename],tag2"; }
73         else if (type == "fileType3") {  pattern = "[filename],tag3"; }
74         else { m->mothurOut("[ERROR]: No definition for type " + type + " output pattern.\n"); m->control_pressed = true;  }
75         
76         return pattern;
77     }
78     catch(exception& e) {
79         m->errorOut(e, "NewCommand", "getOutputPattern");
80         exit(1);
81     }
82 }
83 //**********************************************************************************************************************
84 NewCommand::NewCommand(){       
85         try {
86                 abort = true; calledHelp = true;
87                 setParameters();
88         vector<string> tempOutNames;
89                 outputTypes["fileType1"] = tempOutNames; //filetypes should be things like: shared, fasta, accnos...
90                 outputTypes["fileType2"] = tempOutNames;
91                 outputTypes["FileType3"] = tempOutNames;
92         }
93         catch(exception& e) {
94                 m->errorOut(e, "NewCommand", "NewCommand");
95                 exit(1);
96         }
97 }
98 //**********************************************************************************************************************
99 NewCommand::NewCommand(string option)  {
100         try {
101 ////////////////////////////////////////////////////////
102 /////////////////// start leave alone block ////////////
103 ////////////////////////////////////////////////////////
104                 abort = false; calledHelp = false;   
105                 
106                 //allow user to run help
107                 if(option == "help") { help(); abort = true; calledHelp = true; }
108                 else if(option == "citation") { citation(); abort = true; calledHelp = true;}
109                 
110                 else {
111                         //valid paramters for this command
112                         vector<string> myArray = setParameters();
113                         
114                         OptionParser parser(option);
115                         map<string,string> parameters = parser.getParameters();
116                         
117                         ValidParameters validParameter;
118                         map<string,string>::iterator it;
119                         //check to make sure all parameters are valid for command
120                         for (it = parameters.begin(); it != parameters.end(); it++) { 
121                                 if (validParameter.isValidParameter(it->first, myArray, it->second) != true) {  abort = true;  }
122                         }
123                         
124                         
125                         //if the user changes the input directory command factory will send this info to us in the output parameter 
126                         string inputDir = validParameter.validFile(parameters, "inputdir", false);              
127                         if (inputDir == "not found"){   inputDir = "";          }
128                         else {
129                 
130 ///////////////////////////////////////////////////////////////
131 //////////////// stop leave alone block ///////////////////////
132 ///////////////////////////////////////////////////////////////
133                 
134 //edit file types below to include only the types you added as parameters
135                 
136                                 string path;
137                                 it = parameters.find("phylip");
138                                 //user has given a template file
139                                 if(it != parameters.end()){ 
140                                         path = m->hasPath(it->second);
141                                         //if the user has not given a path then, add inputdir. else leave path alone.
142                                         if (path == "") {       parameters["phylip"] = inputDir + it->second;           }
143                                 }
144                                 
145                                 it = parameters.find("column");
146                                 //user has given a template file
147                                 if(it != parameters.end()){ 
148                                         path = m->hasPath(it->second);
149                                         //if the user has not given a path then, add inputdir. else leave path alone.
150                                         if (path == "") {       parameters["column"] = inputDir + it->second;           }
151                                 }
152                                 
153                                 it = parameters.find("fasta");
154                                 //user has given a template file
155                                 if(it != parameters.end()){ 
156                                         path = m->hasPath(it->second);
157                                         //if the user has not given a path then, add inputdir. else leave path alone.
158                                         if (path == "") {       parameters["fasta"] = inputDir + it->second;            }
159                                 }
160                                                                 
161                                 it = parameters.find("name");
162                                 //user has given a template file
163                                 if(it != parameters.end()){ 
164                                         path = m->hasPath(it->second);
165                                         //if the user has not given a path then, add inputdir. else leave path alone.
166                                         if (path == "") {       parameters["name"] = inputDir + it->second;             }
167                                 }
168                 
169                 it = parameters.find("shared");
170                                 //user has given a template file
171                                 if(it != parameters.end()){ 
172                                         path = m->hasPath(it->second);
173                                         //if the user has not given a path then, add inputdir. else leave path alone.
174                                         if (path == "") {       parameters["shared"] = inputDir + it->second;           }
175                                 }
176             }
177 ///////////////////////////////////////////////////////////////////////////////
178 /////////// example of getting filenames and checking dependancies ////////////
179 // the validParameter class will make sure file exists, fill with correct    //
180 // and name is current is given ///////////////////////////////////////////////
181 ///////////////////////////////////////////////////////////////////////////////
182             
183             
184             ///variables for examples below that you will most likely want to put in the header for 
185             //use by the other class functions.
186             string phylipfile, columnfile, namefile, fastafile, sharedfile, method;
187             int processors;
188             bool useTiming, allLines;
189             vector<string> Estimators, Groups;
190             set<string> labels;
191             //if allLines is used it should be initialized to 1 above.
192             
193             
194                         //check for parameters
195             phylipfile = validParameter.validFile(parameters, "phylip", true);
196                         if (phylipfile == "not open") { phylipfile = ""; abort = true; }
197                         else if (phylipfile == "not found") { phylipfile = ""; }        
198                         else {  m->setPhylipFile(phylipfile); }
199                         
200                         columnfile = validParameter.validFile(parameters, "column", true);
201                         if (columnfile == "not open") { columnfile = ""; abort = true; }        
202                         else if (columnfile == "not found") { columnfile = ""; }
203                         else {   m->setColumnFile(columnfile);  }
204                         
205                         namefile = validParameter.validFile(parameters, "name", true);
206                         if (namefile == "not open") { abort = true; }   
207                         else if (namefile == "not found") { namefile = ""; }
208                         else { m->setNameFile(namefile); }
209             
210             //get fastafile - it is not required
211             fastafile = validParameter.validFile(parameters, "fasta", true);
212                         if (fastafile == "not open") { fastafile = ""; abort=true;  }
213                         else if (fastafile == "not found") {  fastafile = "";  }
214                         if (fastafile != "") { m->setFastaFile(fastafile); }
215
216                         
217                         if ((phylipfile == "") && (columnfile == "")) { 
218                                 //is there are current file available for either of these?
219                                 //give priority to column, then phylip
220                                 columnfile = m->getColumnFile(); 
221                                 if (columnfile != "") {   m->mothurOut("Using " + columnfile + " as input file for the column parameter."); m->mothurOutEndLine(); }
222                                 else { 
223                                         phylipfile = m->getPhylipFile(); 
224                                         if (phylipfile != "") {  m->mothurOut("Using " + phylipfile + " as input file for the phylip parameter."); m->mothurOutEndLine(); }
225                                         else { 
226                                                 m->mothurOut("No valid current files. You must provide a phylip or column file before you can use the cluster command."); m->mothurOutEndLine(); 
227                                                 abort = true;
228                                         }
229                                 }
230                         }
231                         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; }
232                         
233                         if (columnfile != "") {
234                                 if (namefile == "") { 
235                                         namefile = m->getNameFile(); 
236                                         if (namefile != "") {  m->mothurOut("Using " + namefile + " as input file for the name parameter."); m->mothurOutEndLine(); }
237                                         else { 
238                                                 m->mothurOut("You need to provide a namefile if you are going to use the column format."); m->mothurOutEndLine(); 
239                                                 abort = true; 
240                                         }       
241                                 }
242                         }
243             
244             //get shared file, it is required
245                         sharedfile = validParameter.validFile(parameters, "shared", true);
246                         if (sharedfile == "not open") { sharedfile = ""; abort = true; }        
247                         else if (sharedfile == "not found") { 
248                                 //if there is a current shared file, use it
249                                 sharedfile = m->getSharedFile(); 
250                                 if (sharedfile != "") { m->mothurOut("Using " + sharedfile + " as input file for the shared parameter."); m->mothurOutEndLine(); }
251                                 else {  m->mothurOut("You have no current sharedfile and the shared parameter is required."); m->mothurOutEndLine(); abort = true; }
252                         }else { m->setSharedFile(sharedfile); }
253             
254             //if the user changes the output directory command factory will send this info to us in the output parameter 
255                         outputDir = validParameter.validFile(parameters, "outputdir", false);           if (outputDir == "not found"){  
256                                 outputDir = m->hasPath(sharedfile); //if user entered a file with a path then preserve it       
257                         }
258
259                         
260 //////////////////////////////////////////////////////////////////////
261 ////////// example of getting other types of parameters //////////////
262 //////////////////////////////////////////////////////////////////////
263             
264                         //use only one Mutliple type
265                         method = validParameter.validFile(parameters, "method", false);
266                         if (method == "not found") { method = "average"; }
267                         
268                         if ((method == "furthest") || (method == "nearest") || (method == "average") || (method == "weighted")) { }
269                         else { m->mothurOut("Not a valid clustering method.  Valid clustering algorithms are furthest, nearest, average, and weighted."); m->mothurOutEndLine(); abort = true; }
270             
271             //use more than one multiple type. do not check to make sure the entry is valid.
272             string calc = validParameter.validFile(parameters, "calc", false);                  
273                         if (calc == "not found") { calc = "sobs-chao-ace-jack-shannon-npshannon-simpson";  }
274                         else { 
275                 if (calc == "default")  {  calc = "sobs-chao-ace-jack-shannon-npshannon-simpson";  }
276                         }
277                         m->splitAtDash(calc, Estimators);
278             
279             //Boolean type - m->isTrue looks for t, true, f or false and is case insensitive
280                         string timing = validParameter.validFile(parameters, "timing", false);
281                         if (timing == "not found") { timing = "F"; }
282             useTiming = m->isTrue(timing);
283                         
284             //Number type - mothurConvert makes sure the convert can happen to avoid a crash.
285             string temp = validParameter.validFile(parameters, "processors", false);    if (temp == "not found"){       temp = m->getProcessors();      }
286                         m->setProcessors(temp);
287                         m->mothurConvert(temp, processors);
288             
289             //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?
290             string groups = validParameter.validFile(parameters, "groups", false);                      
291                         if (groups == "not found") { groups = ""; }
292                         else { m->splitAtDash(groups, Groups); }
293                         m->setGroups(Groups);
294             
295             //Commonly used to process list, rabund, sabund, shared and relabund files.  Look at "smart distancing" examples below in the execute function.
296             string label = validParameter.validFile(parameters, "label", false);                        
297                         if (label == "not found") { label = ""; }
298                         else { 
299                                 if(label != "all") {  m->splitAtDash(label, labels);  allLines = 0;  }
300                                 else { allLines = 1;  }
301                         }
302             
303             //if your command has a namefile as an option, you may want ot check to see if there is a current namefile
304             //saved by mothur that is associated with the other files you are using as inputs.  
305             //You can do so by adding the files associated with the namefile to the files vector and then asking parser to check.  
306             //This saves our users headaches over file mismatches because they forgot to include the namefile, :)
307             if (namefile == "") {
308                                 vector<string> files; files.push_back(fastafile);
309                                 parser.getNameFile(files);
310                         }
311                         
312                 }
313                 
314         }
315         catch(exception& e) {
316                 m->errorOut(e, "NewCommand", "NewCommand");
317                 exit(1);
318         }
319 }
320 //**********************************************************************************************************************
321
322 int NewCommand::execute(){
323         try {
324                 
325                 if (abort == true) { if (calledHelp) { return 0; }  return 2;   }
326         
327         // reading and processing a shared file code example
328         // 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.
329         // 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.
330          
331          //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.
332         
333         /*
334          InputData input(sharedfile, "sharedfile");
335          vector<SharedRAbundVector*> lookup = input.getSharedRAbundVectors();
336          string lastLabel = lookup[0]->getLabel();
337          
338          //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
339          set<string> processedLabels;
340          set<string> userLabels = labels;
341          
342                   
343          //as long as you are not at the end of the file or done wih the lines you want
344          while((lookup[0] != NULL) && ((allLines == 1) || (userLabels.size() != 0))) {
345          
346          if (m->control_pressed) { for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }  return 0; }
347          
348          if(allLines == 1 || labels.count(lookup[0]->getLabel()) == 1){                 
349          
350          m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
351          
352          ///////////////////////////////////////////////////////////////////////////////////
353          //// Call your function to process specific distance in sharedfile, ie lookup /////
354          ///////////////////////////////////////////////////////////////////////////////////
355          
356          processedLabels.insert(lookup[0]->getLabel());
357          userLabels.erase(lookup[0]->getLabel());
358          }
359          
360          if ((m->anyLabelsToProcess(lookup[0]->getLabel(), userLabels, "") == true) && (processedLabels.count(lastLabel) != 1)) {
361          string saveLabel = lookup[0]->getLabel();
362          
363          for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }  
364          lookup = input.getSharedRAbundVectors(lastLabel);
365          m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
366          
367          ///////////////////////////////////////////////////////////////////////////////////
368          //// Call your function to process specific distance in sharedfile, ie lookup /////
369          ///////////////////////////////////////////////////////////////////////////////////
370
371          
372          processedLabels.insert(lookup[0]->getLabel());
373          userLabels.erase(lookup[0]->getLabel());
374          
375          //restore real lastlabel to save below
376          lookup[0]->setLabel(saveLabel);
377          }
378          
379          lastLabel = lookup[0]->getLabel();
380          //prevent memory leak
381          for (int i = 0; i < lookup.size(); i++) {  delete lookup[i]; lookup[i] = NULL; }
382          
383          if (m->control_pressed) { return 0; }
384          
385          //get next line to process
386          lookup = input.getSharedRAbundVectors();                               
387          }
388          
389          if (m->control_pressed) {  return 0; }
390          
391          //output error messages about any remaining user labels
392          set<string>::iterator it;
393          bool needToRun = false;
394          for (it = userLabels.begin(); it != userLabels.end(); it++) {  
395          m->mothurOut("Your file does not include the label " + *it); 
396          if (processedLabels.count(lastLabel) != 1) {
397          m->mothurOut(". I will use " + lastLabel + "."); m->mothurOutEndLine();
398          needToRun = true;
399          }else {
400          m->mothurOut(". Please refer to " + lastLabel + "."); m->mothurOutEndLine();
401          }
402          }
403          
404          //run last label if you need to
405          if (needToRun == true)  {
406          for (int i = 0; i < lookup.size(); i++) { if (lookup[i] != NULL) { delete lookup[i]; } }  
407          lookup = input.getSharedRAbundVectors(lastLabel);
408          
409          m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
410          
411          ///////////////////////////////////////////////////////////////////////////////////
412          //// Call your function to process specific distance in sharedfile, ie lookup /////
413          ///////////////////////////////////////////////////////////////////////////////////
414
415          
416          for (int i = 0; i < lookup.size(); i++) {  delete lookup[i];  }
417          }
418          */
419         
420         
421         
422         //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.
423                 string currentFasta = "";
424                 itTypes = outputTypes.find("fasta");
425                 if (itTypes != outputTypes.end()) {
426                         if ((itTypes->second).size() != 0) { currentFasta = (itTypes->second)[0]; m->setFastaFile(currentFasta); }
427                 }
428                 
429         //output files created by command
430                 m->mothurOutEndLine();
431                 m->mothurOut("Output File Names: "); m->mothurOutEndLine();
432                 for (int i = 0; i < outputNames.size(); i++) {  m->mothurOut(outputNames[i]); m->mothurOutEndLine();    }
433                 m->mothurOutEndLine();
434         return 0;
435                 
436     }
437         catch(exception& e) {
438                 m->errorOut(e, "NewCommand", "NewCommand");
439                 exit(1);
440         }
441 }
442 //**********************************************************************************************************************
443
444