2 // newcommandtemplate.cpp
5 // Created by Sarah Westcott on 5/3/12.
6 // Copyright (c) 2012 Schloss Lab. All rights reserved.
10 #include "newcommandtemplate.h"
12 //**********************************************************************************************************************
13 vector<string> NewCommand::setParameters(){
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);
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);
27 CommandParameter pgroups("groups", "String", "", "", "", "", "","",false,false); parameters.push_back(pgroups);
28 CommandParameter plabel("label", "String", "", "", "", "", "","",false,false); parameters.push_back(plabel);
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);
35 CommandParameter ptiming("timing", "Boolean", "", "F", "", "", "","",false,false); parameters.push_back(ptiming);
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);
41 vector<string> myArray;
42 for (int i = 0; i < parameters.size(); i++) { myArray.push_back(parameters[i].name); }
46 m->errorOut(e, "NewCommand", "setParameters");
50 //**********************************************************************************************************************
51 string NewCommand::getHelpString(){
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";
62 m->errorOut(e, "NewCommand", "getHelpString");
66 //**********************************************************************************************************************
67 string NewCommand::getOutputPattern(string type) {
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; }
79 m->errorOut(e, "NewCommand", "getOutputPattern");
83 //**********************************************************************************************************************
84 NewCommand::NewCommand(){
86 abort = true; calledHelp = true;
88 vector<string> tempOutNames;
89 outputTypes["fileType1"] = tempOutNames; //filetypes should be things like: shared, fasta, accnos...
90 outputTypes["fileType2"] = tempOutNames;
91 outputTypes["FileType3"] = tempOutNames;
94 m->errorOut(e, "NewCommand", "NewCommand");
98 //**********************************************************************************************************************
99 NewCommand::NewCommand(string option) {
101 ////////////////////////////////////////////////////////
102 /////////////////// start leave alone block ////////////
103 ////////////////////////////////////////////////////////
104 abort = false; calledHelp = false;
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;}
111 //valid paramters for this command
112 vector<string> myArray = setParameters();
114 OptionParser parser(option);
115 map<string,string> parameters = parser.getParameters();
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; }
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 = ""; }
130 ///////////////////////////////////////////////////////////////
131 //////////////// stop leave alone block ///////////////////////
132 ///////////////////////////////////////////////////////////////
134 //edit file types below to include only the types you added as parameters
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; }
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; }
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; }
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; }
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; }
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 ///////////////////////////////////////////////////////////////////////////////
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, countfile;
188 bool useTiming, allLines;
189 vector<string> Estimators, Groups;
191 //if allLines is used it should be initialized to 1 above.
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); }
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); }
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); }
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); }
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(); }
223 phylipfile = m->getPhylipFile();
224 if (phylipfile != "") { m->mothurOut("Using " + phylipfile + " as input file for the phylip parameter."); m->mothurOutEndLine(); }
226 m->mothurOut("No valid current files. You must provide a phylip or column file before you can use the cluster command."); m->mothurOutEndLine();
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; }
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(); }
238 m->mothurOut("You need to provide a namefile if you are going to use the column format."); m->mothurOutEndLine();
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); }
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
260 //////////////////////////////////////////////////////////////////////
261 ////////// example of getting other types of parameters //////////////
262 //////////////////////////////////////////////////////////////////////
264 //use only one Mutliple type
265 method = validParameter.validFile(parameters, "method", false);
266 if (method == "not found") { method = "average"; }
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; }
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"; }
275 if (calc == "default") { calc = "sobs-chao-ace-jack-shannon-npshannon-simpson"; }
277 m->splitAtDash(calc, Estimators);
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);
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);
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);
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 = ""; }
299 if(label != "all") { m->splitAtDash(label, labels); allLines = 0; }
300 else { allLines = 1; }
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 (countfile == "") {
308 if (namefile == "") {
309 vector<string> files; files.push_back(fastafile);
310 parser.getNameFile(files);
318 catch(exception& e) {
319 m->errorOut(e, "NewCommand", "NewCommand");
323 //**********************************************************************************************************************
325 int NewCommand::execute(){
328 if (abort == true) { if (calledHelp) { return 0; } return 2; }
330 // reading and processing a shared file code example
331 // 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.
332 // 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.
334 //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 InputData input(sharedfile, "sharedfile");
338 vector<SharedRAbundVector*> lookup = input.getSharedRAbundVectors();
339 string lastLabel = lookup[0]->getLabel();
341 //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
342 set<string> processedLabels;
343 set<string> userLabels = labels;
346 //as long as you are not at the end of the file or done wih the lines you want
347 while((lookup[0] != NULL) && ((allLines == 1) || (userLabels.size() != 0))) {
349 if (m->control_pressed) { for (int i = 0; i < lookup.size(); i++) { delete lookup[i]; } return 0; }
351 if(allLines == 1 || labels.count(lookup[0]->getLabel()) == 1){
353 m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
355 ///////////////////////////////////////////////////////////////////////////////////
356 //// Call your function to process specific distance in sharedfile, ie lookup /////
357 ///////////////////////////////////////////////////////////////////////////////////
359 processedLabels.insert(lookup[0]->getLabel());
360 userLabels.erase(lookup[0]->getLabel());
363 if ((m->anyLabelsToProcess(lookup[0]->getLabel(), userLabels, "") == true) && (processedLabels.count(lastLabel) != 1)) {
364 string saveLabel = lookup[0]->getLabel();
366 for (int i = 0; i < lookup.size(); i++) { delete lookup[i]; }
367 lookup = input.getSharedRAbundVectors(lastLabel);
368 m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
370 ///////////////////////////////////////////////////////////////////////////////////
371 //// Call your function to process specific distance in sharedfile, ie lookup /////
372 ///////////////////////////////////////////////////////////////////////////////////
375 processedLabels.insert(lookup[0]->getLabel());
376 userLabels.erase(lookup[0]->getLabel());
378 //restore real lastlabel to save below
379 lookup[0]->setLabel(saveLabel);
382 lastLabel = lookup[0]->getLabel();
383 //prevent memory leak
384 for (int i = 0; i < lookup.size(); i++) { delete lookup[i]; lookup[i] = NULL; }
386 if (m->control_pressed) { return 0; }
388 //get next line to process
389 lookup = input.getSharedRAbundVectors();
392 if (m->control_pressed) { return 0; }
394 //output error messages about any remaining user labels
395 set<string>::iterator it;
396 bool needToRun = false;
397 for (it = userLabels.begin(); it != userLabels.end(); it++) {
398 m->mothurOut("Your file does not include the label " + *it);
399 if (processedLabels.count(lastLabel) != 1) {
400 m->mothurOut(". I will use " + lastLabel + "."); m->mothurOutEndLine();
403 m->mothurOut(". Please refer to " + lastLabel + "."); m->mothurOutEndLine();
407 //run last label if you need to
408 if (needToRun == true) {
409 for (int i = 0; i < lookup.size(); i++) { if (lookup[i] != NULL) { delete lookup[i]; } }
410 lookup = input.getSharedRAbundVectors(lastLabel);
412 m->mothurOut(lookup[0]->getLabel()); m->mothurOutEndLine();
414 ///////////////////////////////////////////////////////////////////////////////////
415 //// Call your function to process specific distance in sharedfile, ie lookup /////
416 ///////////////////////////////////////////////////////////////////////////////////
419 for (int i = 0; i < lookup.size(); i++) { delete lookup[i]; }
425 //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.
426 string currentFasta = "";
427 itTypes = outputTypes.find("fasta");
428 if (itTypes != outputTypes.end()) {
429 if ((itTypes->second).size() != 0) { currentFasta = (itTypes->second)[0]; m->setFastaFile(currentFasta); }
432 //output files created by command
433 m->mothurOutEndLine();
434 m->mothurOut("Output File Names: "); m->mothurOutEndLine();
435 for (int i = 0; i < outputNames.size(); i++) { m->mothurOut(outputNames[i]); m->mothurOutEndLine(); }
436 m->mothurOutEndLine();
440 catch(exception& e) {
441 m->errorOut(e, "NewCommand", "NewCommand");
445 //**********************************************************************************************************************