]> git.donarmstrong.com Git - mothur.git/blob - makecontigscommand.cpp
added modify names parameter to set.dir
[mothur.git] / makecontigscommand.cpp
1 //
2 //  makecontigscommand.cpp
3 //  Mothur
4 //
5 //  Created by Sarah Westcott on 5/15/12.
6 //  Copyright (c) 2012 Schloss Lab. All rights reserved.
7 //
8
9 #include "makecontigscommand.h"
10
11 //**********************************************************************************************************************
12 vector<string> MakeContigsCommand::setParameters(){     
13         try {
14                 CommandParameter pfastq("ffastq", "InputTypes", "", "", "FastaFastqFile", "FastaFastqFile", "fastqGroup","fasta-qfile",false,false,true); parameters.push_back(pfastq);
15         CommandParameter prfastq("rfastq", "InputTypes", "", "", "none", "none", "fastqGroup","fasta-qfile",false,false,true); parameters.push_back(prfastq);
16         CommandParameter pfasta("ffasta", "InputTypes", "", "", "FastaFastqFile", "FastaFastqFile", "fastaGroup","fasta",false,false,true); parameters.push_back(pfasta);
17         CommandParameter prfasta("rfasta", "InputTypes", "", "", "none", "none", "none","fastaGroup",false,false,true); parameters.push_back(prfasta);
18         CommandParameter pfqual("fqfile", "InputTypes", "", "", "none", "none", "qfileGroup","",false,false,true); parameters.push_back(pfqual);
19         CommandParameter prqual("rqfile", "InputTypes", "", "", "none", "none", "qfileGroup","",false,false,true); parameters.push_back(prqual);
20         CommandParameter pfile("file", "InputTypes", "", "", "FastaFastqFile", "FastaFastqFile", "none","fasta-qfile",false,false,true); parameters.push_back(pfile);
21         CommandParameter poligos("oligos", "InputTypes", "", "", "none", "none", "none","group",false,false,true); parameters.push_back(poligos);
22                 CommandParameter ppdiffs("pdiffs", "Number", "", "0", "", "", "","",false,false,true); parameters.push_back(ppdiffs);
23                 CommandParameter pbdiffs("bdiffs", "Number", "", "0", "", "", "","",false,false,true); parameters.push_back(pbdiffs);
24         CommandParameter ptdiffs("tdiffs", "Number", "", "0", "", "", "","",false,false); parameters.push_back(ptdiffs);
25
26         CommandParameter palign("align", "Multiple", "needleman-gotoh", "needleman", "", "", "","",false,false); parameters.push_back(palign);
27         CommandParameter pallfiles("allfiles", "Boolean", "", "F", "", "", "","",false,false); parameters.push_back(pallfiles);
28         CommandParameter ptrimoverlap("trimoverlap", "Boolean", "", "F", "", "", "","",false,false); parameters.push_back(ptrimoverlap);
29                 CommandParameter pmatch("match", "Number", "", "1.0", "", "", "","",false,false); parameters.push_back(pmatch);
30                 CommandParameter pmismatch("mismatch", "Number", "", "-1.0", "", "", "","",false,false); parameters.push_back(pmismatch);
31                 CommandParameter pgapopen("gapopen", "Number", "", "-2.0", "", "", "","",false,false); parameters.push_back(pgapopen);
32                 CommandParameter pgapextend("gapextend", "Number", "", "-1.0", "", "", "","",false,false); parameters.push_back(pgapextend);
33         CommandParameter pthreshold("insert", "Number", "", "20", "", "", "","",false,false); parameters.push_back(pthreshold);
34         CommandParameter pdeltaq("deltaq", "Number", "", "6", "", "", "","",false,false); parameters.push_back(pdeltaq);
35                 CommandParameter pprocessors("processors", "Number", "", "1", "", "", "","",false,false,true); parameters.push_back(pprocessors);
36         CommandParameter pformat("format", "Multiple", "sanger-illumina-solexa-illumina1.8+", "illumina1.8+", "", "", "","",false,false,true); parameters.push_back(pformat);
37                 CommandParameter pinputdir("inputdir", "String", "", "", "", "", "","",false,false); parameters.push_back(pinputdir);
38                 CommandParameter poutputdir("outputdir", "String", "", "", "", "", "","",false,false); parameters.push_back(poutputdir);
39                 
40                 vector<string> myArray;
41                 for (int i = 0; i < parameters.size(); i++) {   myArray.push_back(parameters[i].name);          }
42                 return myArray;
43         }
44         catch(exception& e) {
45                 m->errorOut(e, "MakeContigsCommand", "setParameters");
46                 exit(1);
47         }
48 }
49 //**********************************************************************************************************************
50 string MakeContigsCommand::getHelpString(){     
51         try {
52                 string helpString = "";
53                 helpString += "The make.contigs command reads a file, forward fastq file and a reverse fastq file or forward fasta and reverse fasta files and outputs new fasta.  It will also provide new quality files if the fastq or file parameter is used.\n";
54         helpString += "If an oligos file is provided barcodes and primers will be trimmed, and a group file will be created.\n";
55                 helpString += "The make.contigs command parameters are file, ffastq, rfastq, ffasta, rfasta, fqfile, rqfile, oligos, format, tdiffs, bdiffs, pdiffs, align, match, mismatch, gapopen, gapextend, insert, deltaq, allfiles and processors.\n";
56                 helpString += "The ffastq and rfastq, file, or ffasta and rfasta parameters are required.\n";
57         helpString += "The file parameter is 2 or 3 column file containing the forward fastq files in the first column and their matching reverse fastq files in the second column, or a groupName then forward fastq file and reverse fastq file.  Mothur will process each pair and create a combined fasta and report file with all the sequences.\n";
58         helpString += "The ffastq and rfastq parameters are used to provide a forward fastq and reverse fastq file to process.  If you provide one, you must provide the other.\n";
59         helpString += "The ffasta and rfasta parameters are used to provide a forward fasta and reverse fasta file to process.  If you provide one, you must provide the other.\n";
60         helpString += "The fqfile and rqfile parameters are used to provide a forward quality and reverse quality files to process with the ffasta and rfasta parameters.  If you provide one, you must provide the other.\n";
61                 helpString += "The format parameter is used to indicate whether your sequences are sanger, solexa, illumina1.8+ or illumina, default=illumina1.8+.\n";
62         helpString += "The align parameter allows you to specify the alignment method to use.  Your options are: gotoh and needleman. The default is needleman.\n";
63         helpString += "The tdiffs parameter is used to specify the total number of differences allowed in the sequence. The default is pdiffs + bdiffs + sdiffs + ldiffs.\n";
64                 helpString += "The bdiffs parameter is used to specify the number of differences allowed in the barcode. The default is 0.\n";
65                 helpString += "The pdiffs parameter is used to specify the number of differences allowed in the primer. The default is 0.\n";
66         //helpString += "The ldiffs parameter is used to specify the number of differences allowed in the linker. The default is 0.\n";
67                 //helpString += "The sdiffs parameter is used to specify the number of differences allowed in the spacer. The default is 0.\n";
68                 helpString += "The match parameter allows you to specify the bonus for having the same base. The default is 1.0.\n";
69                 helpString += "The mistmatch parameter allows you to specify the penalty for having different bases.  The default is -1.0.\n";
70         helpString += "The deltaq parameter allows you to specify the delta allowed between quality scores of a mismatched base.  For example in the overlap, if deltaq=5 and in the alignment seqA, pos 200 has a quality score of 30 and the same position in seqB has a quality score of 20, you take the base from seqA (30-20 >= 5).  If the quality score in seqB is 28 then the base in the consensus will be an N (30-28<5) The default is 6.\n";
71                 helpString += "The gapopen parameter allows you to specify the penalty for opening a gap in an alignment. The default is -2.0.\n";
72                 helpString += "The gapextend parameter allows you to specify the penalty for extending a gap in an alignment.  The default is -1.0.\n";
73         helpString += "The insert parameter allows you to set a quality scores threshold. In the case where we are trying to decide whether to keep a base or remove it because the base is compared to a gap in the other fragment, if the base has a quality score equal to or below the threshold we eliminate it. Default=20.\n";
74         helpString += "The processors parameter allows you to specify how many processors you would like to use.  The default is 1. \n";
75         helpString += "The allfiles parameter will create separate group and fasta file for each grouping. The default is F.\n";
76
77         helpString += "The trimoverlap parameter allows you to trim the sequences to only the overlapping section. The default is F.\n";
78         helpString += "The make.contigs command should be in the following format: \n";
79                 helpString += "make.contigs(ffastq=yourForwardFastqFile, rfastq=yourReverseFastqFile, align=yourAlignmentMethod) \n";
80                 helpString += "Note: No spaces between parameter labels (i.e. ffastq), '=' and parameters (i.e.yourForwardFastqFile).\n";
81                 return helpString;
82         }
83         catch(exception& e) {
84                 m->errorOut(e, "MakeContigsCommand", "getHelpString");
85                 exit(1);
86         }
87 }
88 //**********************************************************************************************************************
89 string MakeContigsCommand::getOutputPattern(string type) {
90     try {
91         string pattern = "";
92         
93         if (type == "fasta") {  pattern = "[filename],[tag],contigs.fasta"; } 
94         else if (type == "group") {  pattern = "[filename],[tag],contigs.groups"; }
95         else if (type == "report") {  pattern = "[filename],[tag],contigs.report"; }
96         else { m->mothurOut("[ERROR]: No definition for type " + type + " output pattern.\n"); m->control_pressed = true;  }
97         
98         return pattern;
99     }
100     catch(exception& e) {
101         m->errorOut(e, "MakeContigsCommand", "getOutputPattern");
102         exit(1);
103     }
104 }
105 //**********************************************************************************************************************
106 MakeContigsCommand::MakeContigsCommand(){       
107         try {
108                 abort = true; calledHelp = true; 
109                 setParameters();
110                 vector<string> tempOutNames;
111                 outputTypes["fasta"] = tempOutNames;
112         outputTypes["group"] = tempOutNames;
113         outputTypes["report"] = tempOutNames;
114     }
115         catch(exception& e) {
116                 m->errorOut(e, "MakeContigsCommand", "MakeContigsCommand");
117                 exit(1);
118         }
119 }
120 //**********************************************************************************************************************
121 MakeContigsCommand::MakeContigsCommand(string option)  {
122         try {
123                 abort = false; calledHelp = false;
124         createFileGroup = false; createOligosGroup = false;
125         
126                 //allow user to run help
127                 if(option == "help") { help(); abort = true; calledHelp = true; }
128                 else if(option == "citation") { citation(); abort = true; calledHelp = true;}
129                 
130                 else {
131                         vector<string> myArray = setParameters();
132                         
133                         OptionParser parser(option);
134                         map<string, string> parameters = parser.getParameters(); 
135                         
136                         ValidParameters validParameter("pairwise.seqs");
137                         map<string, string>::iterator it;
138                         
139                         //check to make sure all parameters are valid for command
140                         for (it = parameters.begin(); it != parameters.end(); it++) { 
141                                 if (validParameter.isValidParameter(it->first, myArray, it->second) != true) {  abort = true;  }
142                         }
143                         
144                         //initialize outputTypes
145                         vector<string> tempOutNames;
146                         outputTypes["fasta"] = tempOutNames;
147             outputTypes["report"] = tempOutNames;
148             outputTypes["group"] = tempOutNames;
149                         
150             
151                         //if the user changes the input directory command factory will send this info to us in the output parameter 
152                         string inputDir = validParameter.validFile(parameters, "inputdir", false);              
153                         if (inputDir == "not found"){   inputDir = "";          }
154                         else { 
155                                 string path;
156                 it = parameters.find("ffastq");
157                                 //user has given a template file
158                                 if(it != parameters.end()){ 
159                                         path = m->hasPath(it->second);
160                                         //if the user has not given a path then, add inputdir. else leave path alone.
161                                         if (path == "") {       parameters["ffastq"] = inputDir + it->second;           }
162                                 }
163                 
164                 it = parameters.find("rfastq");
165                                 //user has given a template file
166                                 if(it != parameters.end()){ 
167                                         path = m->hasPath(it->second);
168                                         //if the user has not given a path then, add inputdir. else leave path alone.
169                                         if (path == "") {       parameters["rfastq"] = inputDir + it->second;           }
170                                 }
171                 
172                 it = parameters.find("ffasta");
173                                 //user has given a template file
174                                 if(it != parameters.end()){ 
175                                         path = m->hasPath(it->second);
176                                         //if the user has not given a path then, add inputdir. else leave path alone.
177                                         if (path == "") {       parameters["ffasta"] = inputDir + it->second;           }
178                                 }
179                 
180                 it = parameters.find("rfasta");
181                                 //user has given a template file
182                                 if(it != parameters.end()){ 
183                                         path = m->hasPath(it->second);
184                                         //if the user has not given a path then, add inputdir. else leave path alone.
185                                         if (path == "") {       parameters["rfasta"] = inputDir + it->second;           }
186                                 }
187                 
188                 it = parameters.find("fqfile");
189                                 //user has given a template file
190                                 if(it != parameters.end()){ 
191                                         path = m->hasPath(it->second);
192                                         //if the user has not given a path then, add inputdir. else leave path alone.
193                                         if (path == "") {       parameters["fqfile"] = inputDir + it->second;           }
194                                 }
195                 
196                 it = parameters.find("rqfile");
197                                 //user has given a template file
198                                 if(it != parameters.end()){ 
199                                         path = m->hasPath(it->second);
200                                         //if the user has not given a path then, add inputdir. else leave path alone.
201                                         if (path == "") {       parameters["rqfile"] = inputDir + it->second;           }
202                                 }
203                 
204                 it = parameters.find("file");
205                                 //user has given a template file
206                                 if(it != parameters.end()){ 
207                                         path = m->hasPath(it->second);
208                                         //if the user has not given a path then, add inputdir. else leave path alone.
209                                         if (path == "") {       parameters["file"] = inputDir + it->second;             }
210                                 }
211                 
212                 it = parameters.find("oligos");
213                                 //user has given a template file
214                                 if(it != parameters.end()){ 
215                                         path = m->hasPath(it->second);
216                                         //if the user has not given a path then, add inputdir. else leave path alone.
217                                         if (path == "") {       parameters["oligos"] = inputDir + it->second;           }
218                                 }
219             }
220             
221             ffastqfile = validParameter.validFile(parameters, "ffastq", true);
222                         if (ffastqfile == "not open") {  abort = true; }        
223                         else if (ffastqfile == "not found") { ffastqfile = ""; }
224                         
225                         rfastqfile = validParameter.validFile(parameters, "rfastq", true);
226                         if (rfastqfile == "not open") {  abort = true; }        
227                         else if (rfastqfile == "not found") { rfastqfile = "";  }
228             
229             ffastafile = validParameter.validFile(parameters, "ffasta", true);
230                         if (ffastafile == "not open") {  abort = true; }        
231                         else if (ffastafile == "not found") { ffastafile = ""; }
232                         
233                         rfastafile = validParameter.validFile(parameters, "rfasta", true);
234                         if (rfastafile == "not open") {  abort = true; }        
235                         else if (rfastafile == "not found") { rfastafile = "";  }
236             
237             fqualfile = validParameter.validFile(parameters, "fqfile", true);
238                         if (fqualfile == "not open") {  abort = true; } 
239                         else if (fqualfile == "not found") { fqualfile = ""; }
240                         
241                         rqualfile = validParameter.validFile(parameters, "rqfile", true);
242                         if (rqualfile == "not open") {  abort = true; } 
243                         else if (rqualfile == "not found") { rqualfile = "";  }
244             
245             file = validParameter.validFile(parameters, "file", true);
246                         if (file == "not open") {  abort = true; }      
247                         else if (file == "not found") { file = "";  }
248             
249             //provide at least
250             if ((file == "") && (ffastafile == "") && (ffastqfile == "")) { abort = true; m->mothurOut("[ERROR]: The file, ffastq and rfastq or ffasta and rfasta parameters are required.\n"); }
251             if ((file != "") && ((ffastafile != "") || (ffastqfile != ""))) { abort = true; m->mothurOut("[ERROR]: The file, ffastq and rfastq or ffasta and rfasta parameters are required.\n"); }
252             if ((ffastqfile != "") && (rfastqfile == "")) {  abort = true; m->mothurOut("[ERROR]: If you provide use the ffastq, you must provide a rfastq file.\n"); }
253             if ((ffastqfile == "") && (rfastqfile != "")) {  abort = true; m->mothurOut("[ERROR]: If you provide use the rfastq, you must provide a ffastq file.\n"); }
254             if ((ffastafile != "") && (rfastafile == "")) {  abort = true; m->mothurOut("[ERROR]: If you provide use the ffasta, you must provide a rfasta file.\n"); }
255             if ((ffastafile == "") && (rfastafile != "")) {  abort = true; m->mothurOut("[ERROR]: If you provide use the rfasta, you must provide a ffasta file.\n"); }
256             if ((fqualfile != "") && (rqualfile == "")) {  abort = true; m->mothurOut("[ERROR]: If you provide use the fqfile, you must provide a rqfile file.\n"); }
257             if ((fqualfile == "") && (rqualfile != "")) {  abort = true; m->mothurOut("[ERROR]: If you provide use the rqfile, you must provide a fqfile file.\n"); }
258             if (((fqualfile != "") || (rqualfile != "")) && ((ffastafile == "") || (rfastafile == ""))) {
259                 abort = true; m->mothurOut("[ERROR]: If you provide use the rqfile or fqfile file, you must provide the ffasta and rfasta parameters.\n");
260             }
261             
262             oligosfile = validParameter.validFile(parameters, "oligos", true);
263                         if (oligosfile == "not found")      {   oligosfile = "";        }
264                         else if(oligosfile == "not open")   {   abort = true;       } 
265                         else {   m->setOligosFile(oligosfile);          }
266             
267             //if the user changes the output directory command factory will send this info to us in the output parameter 
268                         outputDir = validParameter.validFile(parameters, "outputdir", false);           if (outputDir == "not found"){  
269                  outputDir = ""; 
270             }
271                         
272
273                         //check for optional parameter and set defaults
274                         // ...at some point should added some additional type checking...
275                         string temp;
276                         temp = validParameter.validFile(parameters, "match", false);            if (temp == "not found"){       temp = "1.0";                   }
277                         m->mothurConvert(temp, match);  
278                         
279                         temp = validParameter.validFile(parameters, "mismatch", false);         if (temp == "not found"){       temp = "-1.0";                  }
280                         m->mothurConvert(temp, misMatch);  
281             if (misMatch > 0) { m->mothurOut("[ERROR]: mismatch must be negative.\n"); abort=true; }
282                         
283                         temp = validParameter.validFile(parameters, "gapopen", false);          if (temp == "not found"){       temp = "-2.0";                  }
284                         m->mothurConvert(temp, gapOpen);  
285             if (gapOpen > 0) { m->mothurOut("[ERROR]: gapopen must be negative.\n"); abort=true; }
286                         
287                         temp = validParameter.validFile(parameters, "gapextend", false);        if (temp == "not found"){       temp = "-1.0";                  }
288                         m->mothurConvert(temp, gapExtend); 
289             if (gapExtend > 0) { m->mothurOut("[ERROR]: gapextend must be negative.\n"); abort=true; }
290                         
291             temp = validParameter.validFile(parameters, "insert", false);       if (temp == "not found"){       temp = "20";                    }
292                         m->mothurConvert(temp, insert); 
293             if ((insert < 0) || (insert > 40)) { m->mothurOut("[ERROR]: insert must be between 0 and 40.\n"); abort=true; }
294
295             temp = validParameter.validFile(parameters, "deltaq", false);       if (temp == "not found"){       temp = "6";                     }
296                         m->mothurConvert(temp, deltaq);
297             
298                         temp = validParameter.validFile(parameters, "processors", false);       if (temp == "not found"){       temp = m->getProcessors();      }
299                         m->setProcessors(temp);
300                         m->mothurConvert(temp, processors);
301             
302             temp = validParameter.validFile(parameters, "bdiffs", false);               if (temp == "not found") { temp = "0"; }
303                         m->mothurConvert(temp, bdiffs);
304                         
305                         temp = validParameter.validFile(parameters, "pdiffs", false);           if (temp == "not found") { temp = "0"; }
306                         m->mothurConvert(temp, pdiffs);
307             
308   //          temp = validParameter.validFile(parameters, "ldiffs", false);             if (temp == "not found") { temp = "0"; }
309 //                      m->mothurConvert(temp, ldiffs);
310             ldiffs = 0;
311             
312  //           temp = validParameter.validFile(parameters, "sdiffs", false);             if (temp == "not found") { temp = "0"; }
313  //           m->mothurConvert(temp, sdiffs);
314             sdiffs = 0;
315                         
316                         temp = validParameter.validFile(parameters, "tdiffs", false);           if (temp == "not found") { int tempTotal = pdiffs + bdiffs;  temp = toString(tempTotal); }
317                         m->mothurConvert(temp, tdiffs);
318                         
319                         if(tdiffs == 0){        tdiffs = bdiffs + pdiffs;       }  //+ ldiffs + sdiffs;
320
321             temp = validParameter.validFile(parameters, "allfiles", false);             if (temp == "not found") { temp = "F"; }
322                         allFiles = m->isTrue(temp);
323             
324             
325             temp = validParameter.validFile(parameters, "trimoverlap", false);          if (temp == "not found") { temp = "F"; }
326                         trimOverlap = m->isTrue(temp);
327                         
328                         align = validParameter.validFile(parameters, "align", false);           if (align == "not found"){      align = "needleman";    }
329                         if ((align != "needleman") && (align != "gotoh")) { m->mothurOut(align + " is not a valid alignment method. Options are needleman or gotoh. I will use needleman."); m->mothurOutEndLine(); align = "needleman"; }
330             
331             format = validParameter.validFile(parameters, "format", false);             if (format == "not found"){     format = "illumina1.8+";        }
332             
333             if ((format != "sanger") && (format != "illumina") && (format != "illumina1.8+") && (format != "solexa"))  { 
334                                 m->mothurOut(format + " is not a valid format. Your format choices are sanger, solexa, illumina1.8+ and illumina, aborting." ); m->mothurOutEndLine();
335                                 abort=true;
336                         }
337             
338             //fill convert table - goes from solexa to sanger. Used fq_all2std.pl as a reference.
339             for (int i = -64; i < 65; i++) { 
340                 char temp = (char) ((int)(33 + 10*log(1+pow(10,(i/10.0)))/log(10)+0.499));
341                 convertTable.push_back(temp);
342             }
343         }
344                 
345         }
346         catch(exception& e) {
347                 m->errorOut(e, "MakeContigsCommand", "MakeContigsCommand");
348                 exit(1);
349         }
350 }
351 //**********************************************************************************************************************
352 int MakeContigsCommand::execute(){
353         try {
354                 if (abort == true) { if (calledHelp) { return 0; }  return 2;   }
355         
356         //read ffastq and rfastq files creating fasta and qual files.
357         //this function will create a forward and reverse, fasta and qual files for each processor.
358         //files has an entry for each processor. files[i][0] = forwardFasta, files[i][1] = forwardQual, files[i][2] = reverseFasta, files[i][3] = reverseQual.  filesToProcess is for each filepair in the file parameter file.  for ffastq and rfastq this will be size 1.
359         unsigned long int numReads = 0;
360         int start = time(NULL);
361         longestBase = 1000;
362         m->mothurOut("Reading fastq data...\n"); 
363         vector < vector< vector<string> > > filesToProcess = preProcessData(numReads);
364         m->mothurOut("Done.\n");
365        
366         if (m->control_pressed) { return 0; }
367         
368         map<string, string> cvars;
369         string compOutputDir = outputDir;
370         if (outputDir == "") { compOutputDir = m->hasPath(file); }
371         cvars["[filename]"] = compOutputDir + m->getRootName(m->getSimpleName(file));
372         cvars["[tag]"] = "";
373         string compositeGroupFile = getOutputFileName("group",cvars);
374         cvars["[tag]"] = "trim";
375         string compositeFastaFile = getOutputFileName("fasta",cvars);
376         cvars["[tag]"] = "scrap";
377         string compositeScrapFastaFile = getOutputFileName("fasta",cvars);
378         cvars["[tag]"] = "";
379         string compositeMisMatchFile = getOutputFileName("report",cvars);
380         
381         if (filesToProcess.size() > 1) { //clear files for append below
382             ofstream outCTFasta, outCTQual, outCSFasta, outCSQual, outCMisMatch;
383             m->openOutputFile(compositeFastaFile, outCTFasta); outCTFasta.close();
384             m->openOutputFile(compositeScrapFastaFile, outCSFasta); outCSFasta.close();
385             m->openOutputFile(compositeMisMatchFile, outCMisMatch); outCMisMatch.close();
386             outputNames.push_back(compositeFastaFile); outputTypes["fasta"].push_back(compositeFastaFile);
387             outputNames.push_back(compositeMisMatchFile); outputTypes["report"].push_back(compositeMisMatchFile);
388             outputNames.push_back(compositeScrapFastaFile); outputTypes["fasta"].push_back(compositeScrapFastaFile);
389         }
390         
391         map<string, int> totalGroupCounts;
392         
393         for (int l = 0; l < filesToProcess.size(); l++) {
394             
395             m->mothurOut("\n>>>>>\tProcessing " + filesToProcess[l][0][0] + " (file " + toString(l+1) + " of " + toString(filesToProcess.size()) + ")\t<<<<<\n");
396             
397             groupCounts.clear();
398             groupMap.clear();
399             vector<vector<string> > fastaFileNames;
400             createOligosGroup = false;
401             string outputGroupFileName;
402             map<string, string> variables; 
403             string thisOutputDir = outputDir;
404             if (outputDir == "") {  thisOutputDir = m->hasPath(filesToProcess[l][0][0]); }
405             variables["[filename]"] = thisOutputDir + m->getRootName(m->getSimpleName(filesToProcess[l][0][0]));
406             variables["[tag]"] = "";
407             if(oligosfile != ""){  createOligosGroup = getOligos(fastaFileNames, variables["[filename]"]);  }
408             if (createOligosGroup || createFileGroup) {
409                 outputGroupFileName = getOutputFileName("group",variables);
410             }
411             
412             //give group in file file precedence
413             if (createFileGroup) {  createOligosGroup = false; }
414             
415             variables["[tag]"] = "trim";
416             string outFastaFile = getOutputFileName("fasta",variables);
417             variables["[tag]"] = "scrap";
418             string outScrapFastaFile = getOutputFileName("fasta",variables);
419             variables["[tag]"] = "";
420             string outMisMatchFile = getOutputFileName("report",variables);
421                         
422             m->mothurOut("Making contigs...\n"); 
423             createProcesses(filesToProcess[l], outFastaFile, outScrapFastaFile, outMisMatchFile, fastaFileNames, l);
424              m->mothurOut("Here...\n"); 
425             
426             //remove temp fasta and qual files
427             for (int i = 0; i < processors; i++) { for(int j = 0; j < filesToProcess[l][i].size(); j++) { m->mothurRemove(filesToProcess[l][i][j]); }  }
428             
429             if (m->control_pressed) { for (int i = 0; i < outputNames.size(); i++) {    m->mothurRemove(outputNames[i]); }  return 0; }
430             
431             if(allFiles){
432                 map<string, string> uniqueFastaNames;// so we don't add the same groupfile multiple times
433                 map<string, string>::iterator it;
434                 set<string> namesToRemove;
435                 for(int i=0;i<fastaFileNames.size();i++){
436                     for(int j=0;j<fastaFileNames[0].size();j++){
437                         if (fastaFileNames[i][j] != "") {
438                             if (namesToRemove.count(fastaFileNames[i][j]) == 0) {
439                                 if(m->isBlank(fastaFileNames[i][j])){
440                                     m->mothurRemove(fastaFileNames[i][j]);
441                                     namesToRemove.insert(fastaFileNames[i][j]);
442                                 }else{  
443                                     it = uniqueFastaNames.find(fastaFileNames[i][j]);
444                                     if (it == uniqueFastaNames.end()) { 
445                                         uniqueFastaNames[fastaFileNames[i][j]] = barcodeNameVector[i];  
446                                     }   
447                                 }
448                             }
449                         }
450                     }
451                 }
452                 
453                 //remove names for outputFileNames, just cleans up the output
454                 vector<string> outputNames2;
455                 for(int i = 0; i < outputNames.size(); i++) { if (namesToRemove.count(outputNames[i]) == 0) { outputNames2.push_back(outputNames[i]); } }
456                 outputNames = outputNames2;
457                 
458                 for (it = uniqueFastaNames.begin(); it != uniqueFastaNames.end(); it++) {
459                     ifstream in;
460                     m->openInputFile(it->first, in);
461                     
462                     ofstream out;
463                     string thisGroupName = thisOutputDir + m->getRootName(m->getSimpleName(it->first));
464                     thisGroupName += getOutputFileName("group",variables); outputNames.push_back(thisGroupName); outputTypes["group"].push_back(thisGroupName);
465                     m->openOutputFile(thisGroupName, out);
466                     
467                     while (!in.eof()){
468                         if (m->control_pressed) { break; }
469                         
470                         Sequence currSeq(in); m->gobble(in);
471                         out << currSeq.getName() << '\t' << it->second << endl;
472                     }
473                     out.close();
474                     in.close();
475                 }
476             }
477             
478             if (createFileGroup || createOligosGroup) {
479                 ofstream outGroup;
480                 m->openOutputFile(outputGroupFileName, outGroup);
481                 for (map<string, string>::iterator itGroup = groupMap.begin(); itGroup != groupMap.end(); itGroup++) {
482                     outGroup << itGroup->first << '\t' << itGroup->second << endl;
483                 }
484                 outGroup.close();
485             }
486             
487             if (filesToProcess.size() > 1) { //merge into large combo files
488                 if (createFileGroup || createOligosGroup) {
489                     if (l == 0) {
490                         ofstream outCGroup;
491                         m->openOutputFile(compositeGroupFile, outCGroup); outCGroup.close();
492                         outputNames.push_back(compositeGroupFile); outputTypes["group"].push_back(compositeGroupFile);
493                     }
494                     m->appendFiles(outputGroupFileName, compositeGroupFile);
495                     if (!allFiles) { m->mothurRemove(outputGroupFileName);  }
496                     else { outputNames.push_back(outputGroupFileName); outputTypes["group"].push_back(outputGroupFileName); }
497                     
498                     for (map<string, int>::iterator itGroups = groupCounts.begin(); itGroups != groupCounts.end(); itGroups++) {
499                         map<string, int>::iterator itTemp = totalGroupCounts.find(itGroups->first);
500                         if (itTemp == totalGroupCounts.end()) { totalGroupCounts[itGroups->first] = itGroups->second; } //new group create it in totalGroups
501                         else { itTemp->second += itGroups->second; } //existing group, update total
502                     }
503                 }
504                 if (l == 0) {  m->appendFiles(outMisMatchFile, compositeMisMatchFile);  }
505                 else {  m->appendFilesWithoutHeaders(outMisMatchFile, compositeMisMatchFile);  }
506                 m->appendFiles(outFastaFile, compositeFastaFile);
507                 m->appendFiles(outScrapFastaFile, compositeScrapFastaFile);
508                 if (!allFiles) {
509                     m->mothurRemove(outMisMatchFile);
510                     m->mothurRemove(outFastaFile);
511                     m->mothurRemove(outScrapFastaFile);
512                 }else {
513                     outputNames.push_back(outFastaFile); outputTypes["fasta"].push_back(outFastaFile);
514                     outputNames.push_back(outScrapFastaFile); outputTypes["fasta"].push_back(outScrapFastaFile);
515                     outputNames.push_back(outMisMatchFile); outputTypes["report"].push_back(outMisMatchFile);
516                 }
517             }else {
518                 totalGroupCounts = groupCounts;
519                 outputNames.push_back(outFastaFile); outputTypes["fasta"].push_back(outFastaFile);
520                 outputNames.push_back(outScrapFastaFile); outputTypes["fasta"].push_back(outScrapFastaFile);
521                 outputNames.push_back(outMisMatchFile); outputTypes["report"].push_back(outMisMatchFile);
522                 if (createFileGroup || createOligosGroup) {
523                      outputNames.push_back(outputGroupFileName); outputTypes["group"].push_back(outputGroupFileName); 
524                 }
525             }
526             m->mothurOut("Done.\n");
527         }
528         
529         m->mothurOut("It took " + toString(time(NULL) - start) + " secs to process " + toString(numReads) + " sequences.\n");
530         
531         if (m->control_pressed) {       for (int i = 0; i < outputNames.size(); i++) {  m->mothurRemove(outputNames[i]); } return 0;    }
532         
533                 //output group counts
534                 m->mothurOutEndLine();
535                 int total = 0;
536                 if (totalGroupCounts.size() != 0) {  m->mothurOut("Group count: \n");  }
537                 for (map<string, int>::iterator it = totalGroupCounts.begin(); it != totalGroupCounts.end(); it++) {
538             total += it->second; m->mothurOut(it->first + "\t" + toString(it->second)); m->mothurOutEndLine(); 
539                 }
540                 if (total != 0) { m->mothurOut("Total of all groups is " + toString(total)); m->mothurOutEndLine(); }
541                 
542                 if (m->control_pressed) {       for (int i = 0; i < outputNames.size(); i++) {  m->mothurRemove(outputNames[i]); } return 0;    }
543         
544         string currentFasta = "";
545                 itTypes = outputTypes.find("fasta");
546                 if (itTypes != outputTypes.end()) {
547                         if ((itTypes->second).size() != 0) { currentFasta = (itTypes->second)[0]; m->setFastaFile(currentFasta); }
548                 }
549         
550         string currentGroup = "";
551                 itTypes = outputTypes.find("group");
552                 if (itTypes != outputTypes.end()) {
553                         if ((itTypes->second).size() != 0) { currentGroup = (itTypes->second)[0]; m->setGroupFile(currentGroup); }
554                 }
555                 
556         //output files created by command
557                 m->mothurOutEndLine();
558                 m->mothurOut("Output File Names: "); m->mothurOutEndLine();
559                 for (int i = 0; i < outputNames.size(); i++) {  m->mothurOut(outputNames[i]); m->mothurOutEndLine();    }
560                 m->mothurOutEndLine();
561
562         return 0;
563     }
564         catch(exception& e) {
565                 m->errorOut(e, "MakeContigsCommand", "execute");
566                 exit(1);
567         }
568 }
569 //**********************************************************************************************************************
570 vector< vector< vector<string> > > MakeContigsCommand::preProcessData(unsigned long int& numReads) {
571         try {
572         vector< vector< vector<string> > > filesToProcess;
573         
574         if (ffastqfile != "") { //reading one file
575             vector< vector<string> > files = readFastqFiles(numReads, ffastqfile, rfastqfile); 
576             //adjust for really large processors or really small files
577             if (numReads == 0) {  m->mothurOut("[ERROR]: no good reads.\n"); m->control_pressed = true; }
578             if (numReads < processors) { 
579                 for (int i = numReads; i < processors; i++) { for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); } files[i].clear(); }
580                 files.resize(numReads);
581                 processors = numReads; 
582             }
583             filesToProcess.push_back(files);
584         }else if (file != "") { //reading multiple files
585             //return only valid pairs
586             vector< vector<string> > filePairsToProcess = readFileNames(file);
587             
588             if (m->control_pressed) { return filesToProcess; }
589             
590             if (filePairsToProcess.size() != 0) {
591                 for (int i = 0; i < filePairsToProcess.size(); i++) {
592                     
593                     if (m->control_pressed) { for (int l = 0; l < filesToProcess.size(); l++) { for (int k = 0; k < filesToProcess[l].size(); k++) { for(int j = 0; j < filesToProcess[l][k].size(); j++) { m->mothurRemove(filesToProcess[l][k][j]); } filesToProcess[l][k].clear(); } return filesToProcess; } }
594                     
595                     unsigned long int thisFilesReads;
596                     vector< vector<string> > files = readFastqFiles(thisFilesReads, filePairsToProcess[i][0], filePairsToProcess[i][1]); 
597                     
598                     //adjust for really large processors or really small files
599                     if (thisFilesReads < processors) { 
600                         m->mothurOut("[ERROR]: " + filePairsToProcess[i][0] + " has less than " + toString(processors) + " good reads, skipping\n"); 
601                         for (int k = 0; k < files.size(); k++) { for(int j = 0; j < files[k].size(); j++) { m->mothurRemove(files[k][j]); } files[k].clear(); }
602                     }else {
603                         filesToProcess.push_back(files);
604                         numReads += thisFilesReads;
605                     }
606                 }
607                 //all files are bad
608                 if (numReads == 0) {  m->control_pressed = true; }
609             }
610         }else if (ffastafile != "") {
611             vector< vector<string> > files = readFastaFiles(numReads, ffastafile, rfastafile);
612             //adjust for really large processors or really small files
613             if (numReads == 0) {  m->mothurOut("[ERROR]: no good reads.\n"); m->control_pressed = true; }
614             if (numReads < processors) { 
615                 for (int i = numReads; i < processors; i++) { for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); } files[i].clear(); }
616                 files.resize(numReads);
617                 processors = numReads; 
618             }
619             filesToProcess.push_back(files);
620         }else { m->control_pressed = true; } //should not get here
621         
622         return filesToProcess;
623     }
624         catch(exception& e) {
625                 m->errorOut(e, "MakeContigsCommand", "preProcessData");
626                 exit(1);
627         }
628 }
629 //**********************************************************************************************************************
630 int MakeContigsCommand::createProcesses(vector< vector<string> > files, string outputFasta, string outputScrapFasta, string outputMisMatches, vector<vector<string> > fastaFileNames, int index) {
631         try {
632                 int num = 0;
633                 vector<int> processIDS;
634         string group = "";
635         map<int, string>::iterator it = file2Group.find(index);
636         if (it != file2Group.end()) { group = it->second; }
637         
638 #if defined (__APPLE__) || (__MACH__) || (linux) || (__linux) || (__linux__) || (__unix__) || (__unix)
639                 int process = 0;
640                 
641                 //loop through and create all the processes you want
642                 while (process != processors-1) {
643                         int pid = fork();
644                         
645                         if (pid > 0) {
646                                 processIDS.push_back(pid);  //create map from line number to pid so you can append files in correct order later
647                                 process++;
648                         }else if (pid == 0){
649                 vector<vector<string> > tempFASTAFileNames = fastaFileNames;
650                 
651                                 if(allFiles){
652                                         ofstream temp;
653                     
654                                         for(int i=0;i<tempFASTAFileNames.size();i++){
655                                                 for(int j=0;j<tempFASTAFileNames[i].size();j++){
656                                                         if (tempFASTAFileNames[i][j] != "") {
657                                                                 tempFASTAFileNames[i][j] += toString(getpid()) + ".temp";
658                                                                 m->openOutputFile(tempFASTAFileNames[i][j], temp);                      temp.close();
659                                                         }
660                                                 }
661                                         }
662                                 }
663                 
664                                 num = driver(files[process], 
665                              outputFasta + toString(getpid()) + ".temp", 
666                              outputScrapFasta + toString(getpid()) + ".temp", 
667                              outputMisMatches + toString(getpid()) + ".temp",
668                              tempFASTAFileNames, process, group);
669                                 
670                                 //pass groupCounts to parent
671                 ofstream out;
672                 string tempFile = toString(getpid()) + ".num.temp";
673                 m->openOutputFile(tempFile, out);
674                 out << num << endl;
675                                 if (createFileGroup || createOligosGroup) {
676                                         out << groupCounts.size() << endl;
677                                         
678                                         for (map<string, int>::iterator it = groupCounts.begin(); it != groupCounts.end(); it++) {
679                                                 out << it->first << '\t' << it->second << endl;
680                                         }
681                     
682                     out << groupMap.size() << endl;
683                     for (map<string, string>::iterator it = groupMap.begin(); it != groupMap.end(); it++) {
684                                                 out << it->first << '\t' << it->second << endl;
685                                         }
686                                 }
687                 out.close();
688                                 
689                                 exit(0);
690                         }else { 
691                                 m->mothurOut("[ERROR]: unable to spawn the necessary processes."); m->mothurOutEndLine(); 
692                                 for (int i = 0; i < processIDS.size(); i++) { kill (processIDS[i], SIGINT); }
693                                 exit(0);
694                         }
695                 }
696                 
697         ofstream temp;
698                 m->openOutputFile(outputFasta, temp);           temp.close();
699         m->openOutputFile(outputScrapFasta, temp);              temp.close();
700                 
701                 //do my part
702                 num = driver(files[processors-1], outputFasta, outputScrapFasta,  outputMisMatches, fastaFileNames, processors-1, group);
703                 
704                 //force parent to wait until all the processes are done
705                 for (int i=0;i<processIDS.size();i++) { 
706                         int temp = processIDS[i];
707                         wait(&temp);
708                 }
709         
710                 for (int i = 0; i < processIDS.size(); i++) {
711             ifstream in;
712             string tempFile = toString(processIDS[i]) + ".num.temp";
713             m->openInputFile(tempFile, in);
714             int tempNum;
715             in >> tempNum; num += tempNum; m->gobble(in);
716             
717                         if (createFileGroup || createOligosGroup) {
718                                 string group;
719                                 in >> tempNum; m->gobble(in);
720                                 
721                                 if (tempNum != 0) {
722                                         for (int j = 0; j < tempNum; j++) { 
723                         int groupNum;
724                                                 in >> group >> groupNum; m->gobble(in);
725                         
726                                                 map<string, int>::iterator it = groupCounts.find(group);
727                                                 if (it == groupCounts.end()) {  groupCounts[group] = groupNum; }
728                                                 else { groupCounts[it->first] += groupNum; }
729                                         }
730                                 }
731                 in >> tempNum; m->gobble(in);
732                 if (tempNum != 0) {
733                                         for (int j = 0; j < tempNum; j++) { 
734                         string group, seqName;
735                                                 in >> seqName >> group; m->gobble(in);
736                         
737                                                 map<string, string>::iterator it = groupMap.find(seqName);
738                                                 if (it == groupMap.end()) {     groupMap[seqName] = group; }
739                                                 else { m->mothurOut("[ERROR]: " + seqName + " is in your fasta file more than once. Sequence names must be unique. please correct.\n");  }
740                                         }
741                                 }
742                         }
743             in.close(); m->mothurRemove(tempFile);
744         }
745     #else
746         
747         //////////////////////////////////////////////////////////////////////////////////////////////////////
748                 //Windows version shared memory, so be careful when passing variables through the contigsData struct. 
749                 //Above fork() will clone, so memory is separate, but that's not the case with windows, 
750                 //////////////////////////////////////////////////////////////////////////////////////////////////////
751                 
752                 vector<contigsData*> pDataArray; 
753                 DWORD   dwThreadIdArray[processors-1];
754                 HANDLE  hThreadArray[processors-1]; 
755                 
756                 //Create processor worker threads.
757                 for( int h=0; h<processors-1; h++ ){
758                         string extension = "";
759                         if (h != 0) { extension = toString(h) + ".temp"; processIDS.push_back(h); }
760             vector<vector<string> > tempFASTAFileNames = fastaFileNames;
761                         
762             if(allFiles){
763                 ofstream temp;
764                 
765                 for(int i=0;i<tempFASTAFileNames.size();i++){
766                     for(int j=0;j<tempFASTAFileNames[i].size();j++){
767                         if (tempFASTAFileNames[i][j] != "") {
768                             tempFASTAFileNames[i][j] += extension;
769                             m->openOutputFile(tempFASTAFileNames[i][j], temp);                  temp.close();
770                         }
771                     }
772                 }
773             }
774                                  
775                         contigsData* tempcontig = new contigsData(group, files[h], (outputFasta + extension), (outputScrapFasta + extension), (outputMisMatches + extension), align, m, match, misMatch, gapOpen, gapExtend, insert, deltaq, barcodes, primers, tempFASTAFileNames, barcodeNameVector, primerNameVector, pdiffs, bdiffs, tdiffs, createOligosGroup, createFileGroup, allFiles, trimOverlap, h);
776                         pDataArray.push_back(tempcontig);
777             
778                         hThreadArray[h] = CreateThread(NULL, 0, MyContigsThreadFunction, pDataArray[h], 0, &dwThreadIdArray[h]);   
779                 }
780         
781         vector<vector<string> > tempFASTAFileNames = fastaFileNames;
782
783         if(allFiles){
784             ofstream temp;
785             string extension = toString(processors-1) + ".temp";
786             
787             for(int i=0;i<tempFASTAFileNames.size();i++){
788                 for(int j=0;j<tempFASTAFileNames[i].size();j++){
789                     if (tempFASTAFileNames[i][j] != "") {
790                         tempFASTAFileNames[i][j] += extension;
791                         m->openOutputFile(tempFASTAFileNames[i][j], temp);                      temp.close();
792                     }
793                 }
794             }
795         }
796
797                 //parent do my part
798                 ofstream temp;
799                 m->openOutputFile(outputFasta, temp);           temp.close();
800         m->openOutputFile(outputScrapFasta, temp);              temp.close();
801         
802         //do my part
803         processIDS.push_back(processors-1);
804                 num = driver(files[processors-1], (outputFasta+ toString(processors-1) + ".temp"),  (outputScrapFasta+ toString(processors-1) + ".temp"),  (outputMisMatches+ toString(processors-1) + ".temp"), tempFASTAFileNames, processors-1, group);
805         
806                 //Wait until all threads have terminated.
807                 WaitForMultipleObjects(processors-1, hThreadArray, TRUE, INFINITE);
808                 
809                 //Close all thread handles and free memory allocations.
810                 for(int i=0; i < pDataArray.size(); i++){
811                         num += pDataArray[i]->count;
812             if (!pDataArray[i]->done) {
813                 m->mothurOut("[ERROR]: process " + toString(i) + " only processed " + toString(pDataArray[i]->count) + " of sequences assigned to it, quitting. \n"); m->control_pressed = true; 
814             }
815             for (map<string, int>::iterator it = pDataArray[i]->groupCounts.begin(); it != pDataArray[i]->groupCounts.end(); it++) {
816                 map<string, int>::iterator it2 = groupCounts.find(it->first);
817                 if (it2 == groupCounts.end()) { groupCounts[it->first] = it->second; }
818                 else { groupCounts[it->first] += it->second; }
819             }
820             for (map<string, string>::iterator it = pDataArray[i]->groupMap.begin(); it != pDataArray[i]->groupMap.end(); it++) {
821                 map<string, string>::iterator it2 = groupMap.find(it->first);
822                 if (it2 == groupMap.end()) {    groupMap[it->first] = it->second; }
823                 else { m->mothurOut("[ERROR]: " + it->first + " is in your fasta file more than once. Sequence names must be unique. please correct.\n");  }
824             }
825             CloseHandle(hThreadArray[i]);
826                         delete pDataArray[i];
827         }
828                                 
829     #endif      
830         
831         for (int i = 0; i < processIDS.size(); i++) {
832                         m->appendFiles((outputFasta + toString(processIDS[i]) + ".temp"), outputFasta);
833                         m->mothurRemove((outputFasta + toString(processIDS[i]) + ".temp"));
834                         
835                         m->appendFiles((outputScrapFasta + toString(processIDS[i]) + ".temp"), outputScrapFasta);
836                         m->mothurRemove((outputScrapFasta + toString(processIDS[i]) + ".temp"));
837             
838             m->appendFilesWithoutHeaders((outputMisMatches + toString(processIDS[i]) + ".temp"), outputMisMatches);
839                         m->mothurRemove((outputMisMatches + toString(processIDS[i]) + ".temp"));
840             
841             if(allFiles){
842                                 for(int j=0;j<fastaFileNames.size();j++){
843                                         for(int k=0;k<fastaFileNames[j].size();k++){
844                                                 if (fastaFileNames[j][k] != "") {
845                                                         m->appendFiles((fastaFileNames[j][k] + toString(processIDS[i]) + ".temp"), fastaFileNames[j][k]);
846                                                         m->mothurRemove((fastaFileNames[j][k] + toString(processIDS[i]) + ".temp"));
847                                                 }
848                                         }
849                                 }
850                         }
851                 }
852                 
853                 return num;
854         }
855         catch(exception& e) {
856                 m->errorOut(e, "MakeContigsCommand", "createProcesses");
857                 exit(1);
858         }
859 }
860 //**********************************************************************************************************************
861 int MakeContigsCommand::driver(vector<string> files, string outputFasta, string outputScrapFasta, string outputMisMatches, vector<vector<string> > fastaFileNames, int process, string group){
862     try {
863         
864         Alignment* alignment;
865         if(align == "gotoh")                    {       alignment = new GotohOverlap(gapOpen, gapExtend, match, misMatch, longestBase);                 }
866                 else if(align == "needleman")   {       alignment = new NeedlemanOverlap(gapOpen, match, misMatch, longestBase);                                }
867         
868         int num = 0;
869         string thisffastafile = files[0];
870         string thisfqualfile = files[1];
871         string thisrfastafile = files[2];
872         string thisrqualfile = files[3];
873         
874         if (m->debug) {  m->mothurOut("[DEBUG]: ffasta = " + thisffastafile + ".\n[DEBUG]: fqual = " + thisfqualfile + ".\n[DEBUG]: rfasta = " + thisrfastafile + ".\n[DEBUG]: rqual = " + thisrqualfile + ".\n"); }
875         
876         ifstream inFFasta, inRFasta, inFQual, inRQual;
877         ofstream outFasta, outMisMatch, outScrapFasta;
878         m->openInputFile(thisffastafile, inFFasta);
879         m->openInputFile(thisrfastafile, inRFasta);
880         if (thisfqualfile != "") {
881             m->openInputFile(thisfqualfile, inFQual);
882             m->openInputFile(thisrqualfile, inRQual);
883         }
884         m->openOutputFile(outputFasta, outFasta);
885         m->openOutputFile(outputScrapFasta, outScrapFasta);
886         m->openOutputFile(outputMisMatches, outMisMatch);
887         outMisMatch << "Name\tLength\tOverlap_Length\tOverlap_Start\tOverlap_End\tMisMatches\tNum_Ns\n";  
888         
889         TrimOligos trimOligos(pdiffs, bdiffs, 0, 0, primers, barcodes);
890         
891         while ((!inFFasta.eof()) && (!inRFasta.eof())) {
892             
893             if (m->control_pressed) { break; }
894             
895             int success = 1;
896             string trashCode = "";
897             int currentSeqsDiffs = 0;
898
899             //read seqs and quality info
900             Sequence fSeq(inFFasta); m->gobble(inFFasta);
901             Sequence rSeq(inRFasta); m->gobble(inRFasta);
902             QualityScores* fQual = NULL; QualityScores* rQual = NULL;
903             if (thisfqualfile != "") {
904                 fQual = new QualityScores(inFQual); m->gobble(inFQual);
905                 rQual = new QualityScores(inRQual); m->gobble(inRQual);
906             }
907             
908             int barcodeIndex = 0;
909             int primerIndex = 0;
910             
911             if(barcodes.size() != 0){
912                 if (thisfqualfile != "") {
913                     success = trimOligos.stripBarcode(fSeq, rSeq, *fQual, *rQual, barcodeIndex);
914                 }else {
915                     success = trimOligos.stripBarcode(fSeq, rSeq, barcodeIndex);
916                 }
917                 if(success > bdiffs)            {       trashCode += 'b';       }
918                 else{ currentSeqsDiffs += success;  }
919             }
920             
921             if(primers.size() != 0){
922                 if (thisfqualfile != "") {
923                     success = trimOligos.stripForward(fSeq, rSeq, *fQual, *rQual, primerIndex);
924                 }else {
925                     success = trimOligos.stripForward(fSeq, rSeq, primerIndex);
926                 }
927                 if(success > pdiffs)            {       trashCode += 'f';       }
928                 else{ currentSeqsDiffs += success;  }
929             }
930             
931             if (currentSeqsDiffs > tdiffs)      {       trashCode += 't';   }
932             
933             //flip the reverse reads
934             rSeq.reverseComplement();
935             if (thisfqualfile != "") { rQual->flipQScores(); }
936
937             //pairwise align
938             alignment->align(fSeq.getUnaligned(), rSeq.getUnaligned());
939             map<int, int> ABaseMap = alignment->getSeqAAlnBaseMap();
940             map<int, int> BBaseMap = alignment->getSeqBAlnBaseMap();
941             fSeq.setAligned(alignment->getSeqAAln());
942             rSeq.setAligned(alignment->getSeqBAln());
943             int length = fSeq.getAligned().length();
944             
945             //traverse alignments merging into one contiguous seq
946             string contig = "";
947             int numMismatches = 0;
948             string seq1 = fSeq.getAligned();
949             string seq2 = rSeq.getAligned();
950             vector<int> scores1, scores2; 
951             if (thisfqualfile != "") {
952                 scores1 = fQual->getQualityScores();
953                 scores2 = rQual->getQualityScores();
954                 delete fQual; delete rQual;
955             }
956             
957             // if (num < 5) {  cout << fSeq.getStartPos() << '\t' << fSeq.getEndPos() << '\t' << rSeq.getStartPos() << '\t' << rSeq.getEndPos() << endl; }
958             int overlapStart = fSeq.getStartPos();
959             int seq2Start = rSeq.getStartPos();
960             
961             //bigger of the 2 starting positions is the location of the overlapping start
962             if (overlapStart < seq2Start) { //seq2 starts later so take from 0 to seq2Start from seq1
963                 overlapStart = seq2Start; 
964                 for (int i = 0; i < overlapStart; i++) { contig += seq1[i];  }
965             }else { //seq1 starts later so take from 0 to overlapStart from seq2
966                 for (int i = 0; i < overlapStart; i++) {  contig += seq2[i]; }
967             }
968             
969             int seq1End = fSeq.getEndPos();
970             int seq2End = rSeq.getEndPos();
971             int overlapEnd = seq1End;
972             if (seq2End < overlapEnd) { overlapEnd = seq2End; }  //smallest end position is where overlapping ends
973             
974             int oStart = contig.length();
975             for (int i = overlapStart; i < overlapEnd; i++) {
976                 if (seq1[i] == seq2[i]) { //match, add base and choose highest score
977                     contig += seq1[i];
978                 }else if (((seq1[i] == '.') || (seq1[i] == '-')) && ((seq2[i] != '-') && (seq2[i] != '.'))) { //seq1 is a gap and seq2 is a base, choose seq2, unless quality score for base is below insert. In that case eliminate base
979                     if (thisfqualfile != "") {
980                         if (scores2[BBaseMap[i]] <= insert) { } //
981                         else { contig += seq2[i];  }
982                     }else { contig += seq2[i]; } //with no quality info, then we keep it?
983                 }else if (((seq2[i] == '.') || (seq2[i] == '-')) && ((seq1[i] != '-') && (seq1[i] != '.'))) { //seq2 is a gap and seq1 is a base, choose seq1, unless quality score for base is below insert. In that case eliminate base
984                     if (thisfqualfile != "") {
985                         if (scores1[ABaseMap[i]] <= insert) { } //
986                         else { contig += seq1[i];  }
987                     }else { contig += seq1[i]; } //with no quality info, then we keep it?
988                 }else if (((seq1[i] != '-') && (seq1[i] != '.')) && ((seq2[i] != '-') && (seq2[i] != '.'))) { //both bases choose one with better quality
989                     if (thisfqualfile != "") {
990                         if (abs(scores1[ABaseMap[i]] - scores2[BBaseMap[i]]) >= deltaq) { //is the difference in qual scores >= deltaq, if yes choose base with higher score
991                             char c = seq1[i];
992                             if (scores1[ABaseMap[i]] < scores2[BBaseMap[i]]) { c = seq2[i]; }
993                             contig += c;
994                         }else { //if no, base becomes n
995                             contig += 'N';
996                         }
997                         numMismatches++;
998                     }else { numMismatches++; } //cant decide, so eliminate and mark as mismatch
999                 }else { //should never get here
1000                     m->mothurOut("[ERROR]: case I didn't think of seq1 = " + toString(seq1[i]) + " and seq2 = " + toString(seq2[i]) + "\n");
1001                 }
1002             }
1003             int oend = contig.length();
1004             if (seq1End < seq2End) { //seq1 ends before seq2 so take from overlap to length from seq2
1005                 for (int i = overlapEnd; i < length; i++) { contig += seq2[i];  }
1006             }else { //seq2 ends before seq1 so take from overlap to length from seq1
1007                 for (int i = overlapEnd; i < length; i++) {  contig += seq1[i]; }
1008             }
1009             
1010             if (trimOverlap) { contig = contig.substr(overlapStart-1, oend-oStart);  if (contig.length() == 0) { trashCode += "l"; } }
1011             
1012             if(trashCode.length() == 0){
1013                 bool ignore = false;
1014                 
1015                 if (m->debug) { m->mothurOut(fSeq.getName()); }
1016                 
1017                 if (createOligosGroup) {
1018                     if(barcodes.size() != 0){
1019                         string thisGroup = barcodeNameVector[barcodeIndex];
1020                         if (primers.size() != 0) { 
1021                             if (primerNameVector[primerIndex] != "") { 
1022                                 if(thisGroup != "") {
1023                                     thisGroup += "." + primerNameVector[primerIndex]; 
1024                                 }else {
1025                                     thisGroup = primerNameVector[primerIndex]; 
1026                                 }
1027                             } 
1028                         }
1029                         
1030                         if (m->debug) { m->mothurOut(", group= " + thisGroup + "\n"); }
1031                         
1032                         int pos = thisGroup.find("ignore");
1033                         if (pos == string::npos) {
1034                             groupMap[fSeq.getName()] = thisGroup; 
1035                         
1036                             map<string, int>::iterator it = groupCounts.find(thisGroup);
1037                             if (it == groupCounts.end()) {      groupCounts[thisGroup] = 1; }
1038                             else { groupCounts[it->first] ++; }
1039                         }else { ignore = true; }
1040                         
1041                     }
1042                 }else if (createFileGroup) {
1043                     int pos = group.find("ignore");
1044                     if (pos == string::npos) {
1045                         groupMap[fSeq.getName()] = group;
1046                         
1047                         map<string, int>::iterator it = groupCounts.find(group);
1048                         if (it == groupCounts.end()) {  groupCounts[group] = 1; }
1049                         else { groupCounts[it->first] ++; }
1050                     }else { ignore = true; }
1051                 }
1052                 if (m->debug) { m->mothurOut("\n"); }
1053                 
1054                 if(allFiles && !ignore){
1055                     ofstream output;
1056                     m->openOutputFileAppend(fastaFileNames[barcodeIndex][primerIndex], output);
1057                     output << ">" << fSeq.getName() << endl << contig << endl;
1058                     output.close();
1059                 }
1060                 
1061                 //output
1062                 outFasta << ">" << fSeq.getName() << endl << contig << endl;
1063                 int numNs = 0;
1064                 for (int i = 0; i < contig.length(); i++) { if (contig[i] == 'N') { numNs++; }  }
1065                 outMisMatch << fSeq.getName() << '\t' << contig.length() << '\t' << (oend-oStart) << '\t' << oStart << '\t' << oend << '\t' << numMismatches << '\t' << numNs << endl;
1066             }else {
1067                 //output
1068                 outScrapFasta << ">" << fSeq.getName() << " | " << trashCode << endl << contig << endl;
1069             }
1070             num++;
1071             
1072                         //report progress
1073                         if((num) % 1000 == 0){  m->mothurOut(toString(num)); m->mothurOutEndLine();             }
1074                 }
1075         
1076                 //report progress
1077                 if((num) % 1000 != 0){  m->mothurOut(toString(num)); m->mothurOutEndLine();             }
1078         
1079         inFFasta.close();
1080         inRFasta.close();
1081         outFasta.close();
1082         outScrapFasta.close();
1083         outMisMatch.close();
1084         if (thisfqualfile != "") {
1085             inFQual.close();
1086             inRQual.close();
1087         }
1088         delete alignment;
1089         
1090         if (m->control_pressed) {  m->mothurRemove(outputFasta); m->mothurRemove(outputScrapFasta);m->mothurRemove(outputMisMatches);  }
1091     
1092         return num;
1093     }
1094         catch(exception& e) {
1095                 m->errorOut(e, "MakeContigsCommand", "driver");
1096                 exit(1);
1097         }
1098 }
1099 //**********************************************************************************************************************
1100 vector< vector<string> > MakeContigsCommand::readFastqFiles(unsigned long int& count, string ffastq, string rfastq){
1101     try {
1102         vector< vector<string> > files;
1103         //maps processors number to file pointer
1104         map<int, vector<ofstream*> > tempfiles;  //tempfiles[0] = forwardFasta, [1] = forwardQual, [2] = reverseFasta, [3] = reverseQual
1105         map<int, vector<ofstream*> >::iterator it;
1106         
1107         //create files to write to
1108         for (int i = 0; i < processors; i++) {
1109             vector<ofstream*> temp;
1110             ofstream* outFF = new ofstream;     temp.push_back(outFF);
1111             ofstream* outFQ = new ofstream;     temp.push_back(outFQ);
1112             ofstream* outRF = new ofstream;     temp.push_back(outRF);
1113             ofstream* outRQ = new ofstream;     temp.push_back(outRQ);
1114             tempfiles[i] = temp;
1115             
1116             vector<string> names;
1117             string thisOutputDir = outputDir;
1118             if (outputDir == "") { thisOutputDir = m->hasPath(ffastq); }
1119             string ffastafilename = thisOutputDir + m->getRootName(m->getSimpleName(ffastq)) + toString(i) + "ffastatemp";
1120             string rfastafilename = thisOutputDir + m->getRootName(m->getSimpleName(rfastq)) + toString(i) + "rfastatemp";
1121             string fqualfilename = thisOutputDir + m->getRootName(m->getSimpleName(ffastq)) + toString(i) + "fqualtemp";
1122             string rqualfilename = thisOutputDir + m->getRootName(m->getSimpleName(rfastq)) + toString(i) + "rqualtemp";
1123             names.push_back(ffastafilename); names.push_back(fqualfilename);
1124             names.push_back(rfastafilename); names.push_back(rqualfilename);
1125             files.push_back(names);
1126             
1127             m->openOutputFile(ffastafilename, *outFF);
1128             m->openOutputFile(rfastafilename, *outRF);
1129             m->openOutputFile(fqualfilename, *outFQ);
1130             m->openOutputFile(rqualfilename, *outRQ);
1131         }
1132         
1133         if (m->control_pressed) {
1134             //close files, delete ofstreams
1135             for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } }
1136             //remove files
1137             for (int i = 0; i < files.size(); i++) {  
1138                 for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); }
1139             }
1140         }
1141         
1142         ifstream inForward;
1143         m->openInputFile(ffastq, inForward);
1144         
1145         ifstream inReverse;
1146         m->openInputFile(rfastq, inReverse);
1147         
1148         count = 0;
1149         map<string, fastqRead> uniques;
1150         map<string, fastqRead>::iterator itUniques;
1151         while ((!inForward.eof()) || (!inReverse.eof())) {
1152             
1153             if (m->control_pressed) { for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } } for (int i = 0; i < files.size(); i++) {  for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); } } inForward.close(); inReverse.close(); return files; }
1154             
1155             //get a read from forward and reverse fastq files
1156             bool ignoref, ignorer;
1157             fastqRead thisFread, thisRread;
1158             if (!inForward.eof()) {  thisFread = readFastq(inForward, ignoref); }
1159             else { ignoref = true; }
1160             if (!inReverse.eof()) { thisRread = readFastq(inReverse, ignorer);  }
1161             else { ignorer = true; }
1162             
1163             vector<pairFastqRead> reads = getReads(ignoref, ignorer, thisFread, thisRread, uniques);
1164            
1165             for (int i = 0; i < reads.size(); i++) {
1166                 fastqRead fread = reads[i].forward;
1167                 fastqRead rread = reads[i].reverse;
1168                 
1169                 if (m->debug) { m->mothurOut(toString(count) + '\t' + fread.name + '\t' + rread.name + '\n'); }
1170                
1171                 //if (checkReads(fread, rread, ffastq, rfastq)) {
1172                     if (m->control_pressed) { for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } } for (int i = 0; i < files.size(); i++) {  for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); } } inForward.close(); inReverse.close(); return files; }
1173                     
1174                     //if the reads are okay write to output files
1175                     int process = count % processors;
1176                     
1177                     *(tempfiles[process][0]) << ">" << fread.name << endl << fread.sequence << endl;
1178                     *(tempfiles[process][1]) << ">" << fread.name << endl;
1179                     for (int i = 0; i < fread.scores.size(); i++) { *(tempfiles[process][1]) << fread.scores[i] << " "; }
1180                     *(tempfiles[process][1]) << endl;
1181                     *(tempfiles[process][2]) << ">" << rread.name << endl << rread.sequence << endl;
1182                     *(tempfiles[process][3]) << ">" << rread.name << endl;
1183                     for (int i = 0; i < rread.scores.size(); i++) { *(tempfiles[process][3]) << rread.scores[i] << " "; }
1184                     *(tempfiles[process][3]) << endl;
1185                     
1186                     count++;
1187                     
1188                     //report progress
1189                     if((count) % 10000 == 0){   m->mothurOut(toString(count)); m->mothurOutEndLine();           }
1190                 //}
1191             }
1192                 }
1193                 //report progress
1194                 if((count) % 10000 != 0){       m->mothurOut(toString(count)); m->mothurOutEndLine();           }
1195         
1196         if (uniques.size() != 0) {
1197             for (itUniques = uniques.begin(); itUniques != uniques.end(); itUniques++) {
1198                 m->mothurOut("[WARNING]: did not find paired read for " + itUniques->first + ", ignoring.\n");
1199             }
1200             m->mothurOutEndLine();
1201         }
1202         
1203         //close files, delete ofstreams
1204         for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } }
1205         inForward.close();
1206         inReverse.close();
1207         
1208         return files;
1209     }
1210     catch(exception& e) {
1211         m->errorOut(e, "MakeContigsCommand", "readFastqFiles");
1212         exit(1);
1213     }
1214 }
1215 //**********************************************************************************************************************
1216 vector< vector<string> > MakeContigsCommand::readFastaFiles(unsigned long int& count, string ffasta, string rfasta){
1217     try {
1218         vector< vector<string> > files;
1219         //maps processors number to file pointer
1220         map<int, vector<ofstream*> > tempfiles;  //tempfiles[0] = forwardFasta, [1] = forwardQual, [2] = reverseFasta, [3] = reverseQual
1221         map<int, vector<ofstream*> >::iterator it;
1222         
1223         //create files to write to
1224         for (int i = 0; i < processors; i++) {
1225             vector<ofstream*> temp;
1226             ofstream* outFF = new ofstream;     temp.push_back(outFF);
1227             ofstream* outFQ = new ofstream;     temp.push_back(outFQ);
1228             ofstream* outRF = new ofstream;     temp.push_back(outRF);
1229             ofstream* outRQ = new ofstream;     temp.push_back(outRQ);
1230             tempfiles[i] = temp;
1231             
1232             vector<string> names;
1233             string thisOutputDir = outputDir;
1234             if (outputDir == "") { thisOutputDir = m->hasPath(ffasta); }
1235             string ffastafilename = thisOutputDir + m->getRootName(m->getSimpleName(ffasta)) + toString(i) + "ffastatemp";
1236             string rfastafilename = thisOutputDir + m->getRootName(m->getSimpleName(rfasta)) + toString(i) + "rfastatemp";
1237             string fqualfilename = "";
1238             if (fqualfile != "") { fqualfilename = thisOutputDir + m->getRootName(m->getSimpleName(fqualfile)) + toString(i) + "fqual.temp";  m->openOutputFile(fqualfilename, *outFQ); }
1239             string rqualfilename = "";
1240             if (rqualfile != "") { rqualfilename = thisOutputDir + m->getRootName(m->getSimpleName(rqualfile)) + toString(i) + "rqual.temp"; m->openOutputFile(rqualfilename, *outRQ); }
1241             names.push_back(ffastafilename); names.push_back(fqualfilename);
1242             names.push_back(rfastafilename); names.push_back(rqualfilename);
1243             files.push_back(names);
1244             
1245             m->openOutputFile(ffastafilename, *outFF);
1246             m->openOutputFile(rfastafilename, *outRF);
1247         }
1248         
1249         if (m->control_pressed) {
1250             //close files, delete ofstreams
1251             for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } }
1252             //remove files
1253             for (int i = 0; i < files.size(); i++) {  
1254                 for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); }
1255             }
1256         }
1257         
1258         ifstream inForwardFasta;
1259         m->openInputFile(ffasta, inForwardFasta);
1260         
1261         ifstream inReverseFasta;
1262         m->openInputFile(rfasta, inReverseFasta);
1263         
1264         ifstream inForwardQual, inReverseQual;
1265         if (fqualfile != "") { m->openInputFile(fqualfile, inForwardQual); m->openInputFile(rqualfile, inReverseQual); }
1266         
1267         count = 0;
1268         map<string, fastqRead> uniques;
1269         map<string, fastqRead>::iterator itUniques;
1270         while ((!inForwardFasta.eof()) || (!inReverseFasta.eof())) {
1271             
1272             if (m->control_pressed) { for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } } for (int i = 0; i < files.size(); i++) {  for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); } } inReverseFasta.close(); inForwardFasta.close(); if (fqualfile != "") { inReverseQual.close(); inReverseQual.close(); } return files; }
1273             
1274             //get a reads from forward and reverse fasta files
1275             bool ignoref, ignorer;
1276             fastqRead thisFread, thisRread;
1277             if (!inForwardFasta.eof()) {  
1278                 ignoref = false; 
1279                 Sequence temp(inForwardFasta); m->gobble(inForwardFasta);
1280                 thisFread.name = temp.getName();
1281                 thisFread.sequence = temp.getUnaligned();
1282             }else { ignoref = true; }
1283             if (!inReverseFasta.eof()) {  
1284                 ignorer = false; 
1285                 Sequence temp(inReverseFasta); m->gobble(inReverseFasta);
1286                 thisRread.name = temp.getName();
1287                 thisRread.sequence = temp.getUnaligned();  
1288             }else { ignorer = true; }
1289             
1290             //get qual reads if given
1291             if (fqualfile != "") {
1292                 if (!inForwardQual.eof() && !ignoref) {  
1293                     QualityScores temp(inForwardQual); m->gobble(inForwardQual);
1294                     //if forward files dont match ignore read
1295                     if (thisFread.name != temp.getName()) { ignoref = true; } 
1296                     else { thisFread.scores = temp.getQualityScores(); }
1297                 }else { ignoref = true; }
1298                 if (!inReverseQual.eof() && !ignorer) {  
1299                     QualityScores temp(inReverseQual); m->gobble(inReverseQual);
1300                     //if reverse files dont match ignore read
1301                     if (thisRread.name != temp.getName()) { ignorer = true; } 
1302                     else { thisRread.scores = temp.getQualityScores(); }
1303                 }else { ignorer = true; }
1304             }
1305             
1306             vector<pairFastqRead> reads = getReads(ignoref, ignorer, thisFread, thisRread, uniques);
1307             
1308             for (int i = 0; i < reads.size(); i++) {
1309                 fastqRead fread = reads[i].forward;
1310                 fastqRead rread = reads[i].reverse;
1311                 
1312                 if (m->debug) { m->mothurOut(toString(count) + '\t' + fread.name + '\t' + rread.name + '\n'); }
1313                 
1314                // if (checkReads(fread, rread, ffasta, rfasta)) {
1315                     if (m->control_pressed) { for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } } for (int i = 0; i < files.size(); i++) {  for(int j = 0; j < files[i].size(); j++) { m->mothurRemove(files[i][j]); } } inReverseFasta.close(); inForwardFasta.close(); if (fqualfile != "") { inReverseQual.close(); inReverseQual.close(); } return files; }
1316                     
1317                     //if the reads are okay write to output files
1318                     int process = count % processors;
1319                     
1320                     *(tempfiles[process][0]) << ">" << fread.name << endl << fread.sequence << endl;
1321                     *(tempfiles[process][2]) << ">" << rread.name << endl << rread.sequence << endl;
1322                     if (fqualfile != "") { //if you have quality info, print it
1323                         *(tempfiles[process][1]) << ">" << fread.name << endl;
1324                         for (int i = 0; i < fread.scores.size(); i++) { *(tempfiles[process][1]) << fread.scores[i] << " "; }
1325                         *(tempfiles[process][1]) << endl;
1326                         *(tempfiles[process][3]) << ">" << rread.name << endl;
1327                         for (int i = 0; i < rread.scores.size(); i++) { *(tempfiles[process][3]) << rread.scores[i] << " "; }
1328                         *(tempfiles[process][3]) << endl;
1329                     }
1330                     count++;
1331                     
1332                     //report progress
1333                     if((count) % 10000 == 0){   m->mothurOut(toString(count)); m->mothurOutEndLine();           }
1334                 //}
1335             }
1336                 }
1337                 //report progress
1338                 if((count) % 10000 != 0){       m->mothurOut(toString(count)); m->mothurOutEndLine();           }
1339         
1340         if (uniques.size() != 0) {
1341             for (itUniques = uniques.begin(); itUniques != uniques.end(); itUniques++) {
1342                 m->mothurOut("[WARNING]: did not find paired read for " + itUniques->first + ", ignoring.\n");
1343             }
1344             m->mothurOutEndLine();
1345         }
1346         
1347         //close files, delete ofstreams
1348         for (it = tempfiles.begin(); it!=tempfiles.end(); it++) { for (int i = 0; i < (it->second).size(); i++) { (*(it->second)[i]).close();  delete (it->second)[i]; } }
1349         inReverseFasta.close(); 
1350         inForwardFasta.close(); 
1351         if (fqualfile != "") { inReverseQual.close(); inReverseQual.close(); }
1352         
1353         return files;
1354     }
1355     catch(exception& e) {
1356         m->errorOut(e, "MakeContigsCommand", "readFastaFiles");
1357         exit(1);
1358     }
1359 }
1360 //**********************************************************************************************************************
1361 vector<pairFastqRead> MakeContigsCommand::getReads(bool ignoref, bool ignorer, fastqRead forward, fastqRead reverse, map<string, fastqRead>& uniques){
1362     try {
1363         vector<pairFastqRead> reads;
1364         map<string, fastqRead>::iterator itUniques;
1365             
1366         if (!ignoref && !ignorer) {
1367             if (forward.name == reverse.name) { 
1368                 pairFastqRead temp(forward, reverse);
1369                 reads.push_back(temp);
1370             }else {
1371                 bool match = false;
1372                 //if no match are the names only different by 1 and 2?
1373                 string tempFRead = forward.name.substr(0, forward.name.length()-1);
1374                 string tempRRead = reverse.name.substr(0, reverse.name.length()-1);
1375                 if (tempFRead == tempRRead) {
1376                     if ((forward.name[forward.name.length()-1] == '1') && (reverse.name[reverse.name.length()-1] == '2')) {
1377                         forward.name = tempFRead;
1378                         reverse.name = tempRRead;
1379                         pairFastqRead temp(forward, reverse);
1380                         reads.push_back(temp);
1381                         match = true;
1382                     }
1383                 }
1384                 
1385                 if (!match) {
1386                     //look for forward pair
1387                     itUniques = uniques.find(forward.name);
1388                     if (itUniques != uniques.end()) {  //we have the pair for this read
1389                         pairFastqRead temp(forward, itUniques->second);
1390                         reads.push_back(temp);
1391                         uniques.erase(itUniques);
1392                     }else { //save this read for later
1393                         uniques[forward.name] = forward;
1394                     }
1395                     
1396                     //look for reverse pair
1397                     itUniques = uniques.find(reverse.name);
1398                     if (itUniques != uniques.end()) {  //we have the pair for this read
1399                         pairFastqRead temp(itUniques->second, reverse);
1400                         reads.push_back(temp);
1401                         uniques.erase(itUniques);
1402                     }else { //save this read for later
1403                         uniques[reverse.name] = reverse;
1404                     }
1405                 }
1406                                 
1407             }
1408         }else if (!ignoref && ignorer) { //ignore reverse keep forward
1409             //look for forward pair
1410             itUniques = uniques.find(forward.name);
1411             if (itUniques != uniques.end()) {  //we have the pair for this read
1412                 pairFastqRead temp(forward, itUniques->second);
1413                 reads.push_back(temp);
1414                 uniques.erase(itUniques);
1415             }else { //save this read for later
1416                 uniques[forward.name] = forward;
1417             }
1418
1419         }else if (ignoref && !ignorer) { //ignore forward keep reverse
1420             //look for reverse pair
1421             itUniques = uniques.find(reverse.name);
1422             if (itUniques != uniques.end()) {  //we have the pair for this read
1423                 pairFastqRead temp(itUniques->second, reverse);
1424                 reads.push_back(temp);
1425                 uniques.erase(itUniques);
1426             }else { //save this read for later
1427                 uniques[reverse.name] = reverse;
1428             }
1429         }//else ignore both and do nothing
1430         
1431         return reads;
1432     }
1433     catch(exception& e) {
1434         m->errorOut(e, "MakeContigsCommand", "readFastqFiles");
1435         exit(1);
1436     }
1437 }
1438 //**********************************************************************************************************************
1439 fastqRead MakeContigsCommand::readFastq(ifstream& in, bool& ignore){
1440     try {
1441         fastqRead read;
1442         
1443         ignore = false;
1444         
1445         //read sequence name
1446         string line = m->getline(in); m->gobble(in);
1447         vector<string> pieces = m->splitWhiteSpace(line);
1448         string name = "";  if (pieces.size() != 0) { name = pieces[0]; }
1449         if (name == "") {  m->mothurOut("[WARNING]: Blank fasta name, ignoring read."); m->mothurOutEndLine(); ignore=true;  }
1450         else if (name[0] != '@') { m->mothurOut("[WARNING]: reading " + name + " expected a name with @ as a leading character, ignoring read."); m->mothurOutEndLine(); ignore=true; }
1451         else { name = name.substr(1); }
1452         
1453         //read sequence
1454         string sequence = m->getline(in); m->gobble(in);
1455         if (sequence == "") {  m->mothurOut("[WARNING]: missing sequence for " + name + ", ignoring."); ignore=true; }
1456         
1457         //read sequence name
1458         line = m->getline(in); m->gobble(in);
1459         pieces = m->splitWhiteSpace(line);
1460         string name2 = "";  if (pieces.size() != 0) { name2 = pieces[0]; }
1461         if (name2 == "") {  m->mothurOut("[WARNING]: expected a name with + as a leading character, ignoring."); ignore=true; }
1462         else if (name2[0] != '+') { m->mothurOut("[WARNING]: reading " + name2 + " expected a name with + as a leading character, ignoring."); ignore=true; }
1463         else { name2 = name2.substr(1); if (name2 == "") { name2 = name; } }
1464         
1465         //read quality scores
1466         string quality = m->getline(in); m->gobble(in);
1467         if (quality == "") {  m->mothurOut("[WARNING]: missing quality for " + name2 + ", ignoring."); ignore=true; }
1468          
1469         //sanity check sequence length and number of quality scores match
1470         if (name2 != "") { if (name != name2) { m->mothurOut("[WARNING]: names do not match. read " + name + " for fasta and " + name2 + " for quality, ignoring."); ignore=true; } }
1471         if (quality.length() != sequence.length()) { m->mothurOut("[WARNING]: Lengths do not match for sequence " + name + ". Read " + toString(sequence.length()) + " characters for fasta and " + toString(quality.length()) + " characters for quality scores, ignoring read."); ignore=true; }
1472         
1473         vector<int> qualScores = convertQual(quality);
1474         
1475         read.name = name;
1476         read.sequence = sequence;
1477         read.scores = qualScores;
1478
1479         return read;
1480     }
1481     catch(exception& e) {
1482         m->errorOut(e, "MakeContigsCommand", "readFastq");
1483         exit(1);
1484     }
1485 }
1486 /**********************************************************************************************************************
1487 bool MakeContigsCommand::checkReads(fastqRead& forward, fastqRead& reverse, string ffile, string rfile){
1488     try {
1489         bool good = true;
1490         
1491         //do sequence lengths match
1492         if (forward.sequence.length() != reverse.sequence.length()) {
1493             m->mothurOut("[WARNING]: For sequence " + forward.name + " I read a sequence of length " + toString(forward.sequence.length()) + " from " + ffile + ", but read a sequence of length " + toString(reverse.sequence.length()) + " from " + rfile + ", ignoring.\n");
1494             good = false; 
1495         }
1496         
1497         //do number of qual scores match 
1498         if (forward.scores.size() != reverse.scores.size()) {
1499             m->mothurOut("[WARNING]: For sequence " + forward.name + " I read " + toString(forward.scores.size()) + " quality scores from " + ffile + ", but read  " + toString(reverse.scores.size()) + " quality scores from " + rfile + ", ignoring.\n");
1500             good = false; 
1501         }
1502
1503         return good;
1504     }
1505     catch(exception& e) {
1506         m->errorOut(e, "MakeContigsCommand", "checkReads");
1507         exit(1);
1508     }
1509 }*/
1510 //***************************************************************************************************************
1511 vector< vector<string> > MakeContigsCommand::readFileNames(string filename){
1512         try {
1513         vector< vector<string> > files;
1514         string forward, reverse;
1515         
1516         ifstream in;
1517         m->openInputFile(filename, in);
1518         
1519         while(!in.eof()) {
1520             
1521             if (m->control_pressed) { return files; }
1522             
1523             in >> forward; m->gobble(in);
1524             in >> reverse;
1525             
1526             string group = "";
1527             while (!in.eof())   { //do we have a group assigned to this pair
1528                 char c = in.get();
1529                 if (c == 10 || c == 13 || c == -1){     break;  }
1530                 else if (c == 32 || c == 9){;} //space or tab
1531                 else {  group += c;  }
1532             }
1533             
1534             if (group != "") {
1535                 //line in file look like: group forward reverse
1536                 string temp = forward;
1537                 forward = reverse;
1538                 reverse = group;
1539                 group = temp;
1540                 createFileGroup = true;
1541             }
1542             m->gobble(in);
1543             
1544             
1545             //check to make sure both are able to be opened
1546             ifstream in2;
1547             int openForward = m->openInputFile(forward, in2, "noerror");
1548             
1549             //if you can't open it, try default location
1550             if (openForward == 1) {
1551                 if (m->getDefaultPath() != "") { //default path is set
1552                     string tryPath = m->getDefaultPath() + m->getSimpleName(forward);
1553                     m->mothurOut("Unable to open " + forward + ". Trying default " + tryPath); m->mothurOutEndLine();
1554                     ifstream in3;
1555                     openForward = m->openInputFile(tryPath, in3, "noerror");
1556                     in3.close();
1557                     forward = tryPath;
1558                 }
1559             }
1560             
1561             //if you can't open it, try output location
1562             if (openForward == 1) {
1563                 if (m->getOutputDir() != "") { //default path is set
1564                     string tryPath = m->getOutputDir() + m->getSimpleName(forward);
1565                     m->mothurOut("Unable to open " + forward + ". Trying output directory " + tryPath); m->mothurOutEndLine();
1566                     ifstream in4;
1567                     openForward = m->openInputFile(tryPath, in4, "noerror");
1568                     forward = tryPath;
1569                     in4.close();
1570                 }
1571             }
1572             
1573             if (openForward == 1) { //can't find it
1574                 m->mothurOut("[WARNING]: can't find " + forward + ", ignoring pair.\n"); 
1575             }else{  in2.close();  }
1576             
1577             ifstream in3;
1578             int openReverse = m->openInputFile(reverse, in3, "noerror");
1579             
1580             //if you can't open it, try default location
1581             if (openReverse == 1) {
1582                 if (m->getDefaultPath() != "") { //default path is set
1583                     string tryPath = m->getDefaultPath() + m->getSimpleName(reverse);
1584                     m->mothurOut("Unable to open " + reverse + ". Trying default " + tryPath); m->mothurOutEndLine();
1585                     ifstream in3;
1586                     openReverse = m->openInputFile(tryPath, in3, "noerror");
1587                     in3.close();
1588                     reverse = tryPath;
1589                 }
1590             }
1591             
1592             //if you can't open it, try output location
1593             if (openReverse == 1) {
1594                 if (m->getOutputDir() != "") { //default path is set
1595                     string tryPath = m->getOutputDir() + m->getSimpleName(reverse);
1596                     m->mothurOut("Unable to open " + reverse + ". Trying output directory " + tryPath); m->mothurOutEndLine();
1597                     ifstream in4;
1598                     openReverse = m->openInputFile(tryPath, in4, "noerror");
1599                     reverse = tryPath;
1600                     in4.close();
1601                 }
1602             }
1603             
1604             if (openReverse == 1) { //can't find it
1605                 m->mothurOut("[WARNING]: can't find " + reverse + ", ignoring pair.\n"); 
1606             }else{  in3.close();  }
1607             
1608             if ((openForward != 1) && (openReverse != 1)) { //good pair
1609                 file2Group[files.size()] = group;
1610                 vector<string> pair;
1611                 pair.push_back(forward);
1612                 pair.push_back(reverse);
1613                 files.push_back(pair);
1614             }
1615         }
1616         in.close();
1617         
1618         return files;
1619     }
1620     catch(exception& e) {
1621         m->errorOut(e, "MakeContigsCommand", "checkReads");
1622         exit(1);
1623     }
1624 }
1625 //***************************************************************************************************************
1626 //illumina data requires paired forward and reverse data
1627 //BARCODE   atgcatgc   atgcatgc    groupName 
1628 //PRIMER   atgcatgc   atgcatgc    groupName  
1629 //PRIMER   atgcatgc   atgcatgc  
1630 bool MakeContigsCommand::getOligos(vector<vector<string> >& fastaFileNames, string rootname){
1631         try {
1632                 ifstream in;
1633                 m->openInputFile(oligosfile, in);
1634                 
1635                 ofstream test;
1636                 
1637                 string type, foligo, roligo, group;
1638         
1639                 int indexPrimer = 0;
1640                 int indexBarcode = 0;
1641         set<string> uniquePrimers;
1642         set<string> uniqueBarcodes;
1643                 
1644                 while(!in.eof()){
1645             
1646                         in >> type; 
1647     
1648                         if (m->debug) { m->mothurOut("[DEBUG]: reading type - " + type + ".\n"); }      
1649             
1650                         if(type[0] == '#'){
1651                                 while (!in.eof())       {       char c = in.get();  if (c == 10 || c == 13){    break;  }       } // get rest of line if there's any crap there
1652                                 m->gobble(in);
1653                         }
1654                         else{
1655                                 m->gobble(in);
1656                                 //make type case insensitive
1657                                 for(int i=0;i<type.length();i++){       type[i] = toupper(type[i]);  }
1658                                 
1659                                 in >> foligo;
1660                 
1661                 if (m->debug) { m->mothurOut("[DEBUG]: reading - " + foligo + ".\n"); }
1662                                 
1663                                 for(int i=0;i<foligo.length();i++){
1664                                         foligo[i] = toupper(foligo[i]);
1665                                         if(foligo[i] == 'U')    {       foligo[i] = 'T';        }
1666                                 }
1667                                 
1668                                 if(type == "PRIMER"){
1669                                         m->gobble(in);
1670                                         
1671                     in >> roligo;
1672                     
1673                     for(int i=0;i<roligo.length();i++){
1674                         roligo[i] = toupper(roligo[i]);
1675                         if(roligo[i] == 'U')    {       roligo[i] = 'T';        }
1676                     }
1677                     //roligo = reverseOligo(roligo);
1678                     
1679                     group = "";
1680                     
1681                                         // get rest of line in case there is a primer name
1682                                         while (!in.eof())       {       
1683                                                 char c = in.get(); 
1684                                                 if (c == 10 || c == 13 || c == -1){     break;  }
1685                                                 else if (c == 32 || c == 9){;} //space or tab
1686                                                 else {  group += c;  }
1687                                         } 
1688                     
1689                     oligosPair newPrimer(foligo, roligo);
1690                                         
1691                                         //check for repeat barcodes
1692                     string tempPair = foligo+roligo;
1693                     if (uniquePrimers.count(tempPair) != 0) { m->mothurOut("primer pair " + newPrimer.forward + " " + newPrimer.reverse + " is in your oligos file already."); m->mothurOutEndLine();  }
1694                     else { uniquePrimers.insert(tempPair); }
1695                                         
1696                     if (m->debug) {  if (group != "") { m->mothurOut("[DEBUG]: reading group " + group + ".\n"); }else{ m->mothurOut("[DEBUG]: no group for primer pair " + newPrimer.forward + " " + newPrimer.reverse + ".\n"); }  }
1697                     
1698                                         primers[indexPrimer]=newPrimer; indexPrimer++;          
1699                                         primerNameVector.push_back(group);
1700                                 }else if(type == "BARCODE"){
1701                                         m->gobble(in);
1702                                         
1703                     in >> roligo;
1704                     
1705                     for(int i=0;i<roligo.length();i++){
1706                         roligo[i] = toupper(roligo[i]);
1707                         if(roligo[i] == 'U')    {       roligo[i] = 'T';        }
1708                     }
1709                     //roligo = reverseOligo(roligo);
1710                     
1711                     oligosPair newPair(foligo, roligo);
1712                     
1713                     group = "";
1714                     while (!in.eof())   {       
1715                                                 char c = in.get(); 
1716                                                 if (c == 10 || c == 13 || c == -1){     break;  }
1717                                                 else if (c == 32 || c == 9){;} //space or tab
1718                                                 else {  group += c;  }
1719                                         } 
1720                                         
1721                     if (m->debug) { m->mothurOut("[DEBUG]: barcode pair " + newPair.forward + " " + newPair.reverse + ", and group = " + group + ".\n"); }
1722                         
1723                     //check for repeat barcodes
1724                     string tempPair = foligo+roligo;
1725                     if (uniqueBarcodes.count(tempPair) != 0) { m->mothurOut("barcode pair " + newPair.forward + " " + newPair.reverse +  " is in your oligos file already, disregarding."); m->mothurOutEndLine();  }
1726                     else { uniqueBarcodes.insert(tempPair); }
1727                         
1728                     barcodes[indexBarcode]=newPair; indexBarcode++;
1729                                         barcodeNameVector.push_back(group);
1730                                 }else if(type == "LINKER"){
1731                                         linker.push_back(foligo);
1732                     m->mothurOut("[WARNING]: make.contigs is not setup to remove linkers, ignoring.\n");
1733                                 }else if(type == "SPACER"){
1734                                         spacer.push_back(foligo);
1735                     m->mothurOut("[WARNING]: make.contigs is not setup to remove spacers, ignoring.\n");
1736                                 }
1737                                 else{   m->mothurOut("[WARNING]: " + type + " is not recognized as a valid type. Choices are primer, barcode, linker and spacer. Ignoring " + foligo + "."); m->mothurOutEndLine(); }
1738                         }
1739                         m->gobble(in);
1740                 }       
1741                 in.close();
1742                 
1743                 if(barcodeNameVector.size() == 0 && primerNameVector[0] == ""){ allFiles = 0;   }
1744                 
1745                 //add in potential combos
1746                 if(barcodeNameVector.size() == 0){
1747             oligosPair temp("", "");
1748                         barcodes[0] = temp;
1749                         barcodeNameVector.push_back("");                        
1750                 }
1751                 
1752                 if(primerNameVector.size() == 0){
1753             oligosPair temp("", "");
1754                         primers[0] = temp;
1755                         primerNameVector.push_back("");                 
1756                 }
1757                 
1758                 fastaFileNames.resize(barcodeNameVector.size());
1759                 for(int i=0;i<fastaFileNames.size();i++){
1760                         fastaFileNames[i].assign(primerNameVector.size(), "");
1761                 }
1762                 
1763                 if(allFiles){
1764                         set<string> uniqueNames; //used to cleanup outputFileNames
1765                         for(map<int, oligosPair>::iterator itBar = barcodes.begin();itBar != barcodes.end();itBar++){
1766                                 for(map<int, oligosPair>::iterator itPrimer = primers.begin();itPrimer != primers.end(); itPrimer++){
1767                                         
1768                                         string primerName = primerNameVector[itPrimer->first];
1769                                         string barcodeName = barcodeNameVector[itBar->first];
1770                     
1771                     if ((primerName == "ignore") || (barcodeName == "ignore")) { } //do nothing 
1772                                         else {
1773                         string comboGroupName = "";
1774                         string fastaFileName = "";
1775                         string qualFileName = "";
1776                         string nameFileName = "";
1777                         string countFileName = "";
1778                         
1779                         if(primerName == ""){
1780                             comboGroupName = barcodeNameVector[itBar->first];
1781                         }
1782                         else{
1783                             if(barcodeName == ""){
1784                                 comboGroupName = primerNameVector[itPrimer->first];
1785                             }
1786                             else{
1787                                 comboGroupName = barcodeNameVector[itBar->first] + "." + primerNameVector[itPrimer->first];
1788                             }
1789                         }
1790                         
1791                         
1792                         ofstream temp;
1793                         fastaFileName = rootname + comboGroupName + ".fasta";
1794                         if (uniqueNames.count(fastaFileName) == 0) {
1795                             outputNames.push_back(fastaFileName);
1796                             outputTypes["fasta"].push_back(fastaFileName);
1797                             uniqueNames.insert(fastaFileName);
1798                         }
1799                         
1800                         fastaFileNames[itBar->first][itPrimer->first] = fastaFileName;
1801                         m->openOutputFile(fastaFileName, temp);         temp.close();
1802                     }
1803                                 }
1804                         }
1805                 }
1806                 
1807                 bool allBlank = true;
1808                 for (int i = 0; i < barcodeNameVector.size(); i++) {
1809                         if (barcodeNameVector[i] != "") {
1810                                 allBlank = false;
1811                                 break;
1812                         }
1813                 }
1814                 for (int i = 0; i < primerNameVector.size(); i++) {
1815                         if (primerNameVector[i] != "") {
1816                                 allBlank = false;
1817                                 break;
1818                         }
1819                 }
1820         
1821                 if (allBlank) {
1822                         m->mothurOut("[WARNING]: your oligos file does not contain any group names.  mothur will not create a groupfile."); m->mothurOutEndLine();
1823                         allFiles = false;
1824                         return false;
1825                 }
1826                 
1827                 return true;
1828                 
1829         }
1830         catch(exception& e) {
1831                 m->errorOut(e, "MakeContigsCommand", "getOligos");
1832                 exit(1);
1833         }
1834 }
1835 //********************************************************************/
1836 string MakeContigsCommand::reverseOligo(string oligo){
1837         try {
1838         string reverse = "";
1839         
1840         for(int i=oligo.length()-1;i>=0;i--){
1841             
1842             if(oligo[i] == 'A')         {       reverse += 'T'; }
1843             else if(oligo[i] == 'T'){   reverse += 'A'; }
1844             else if(oligo[i] == 'U'){   reverse += 'A'; }
1845             
1846             else if(oligo[i] == 'G'){   reverse += 'C'; }
1847             else if(oligo[i] == 'C'){   reverse += 'G'; }
1848             
1849             else if(oligo[i] == 'R'){   reverse += 'Y'; }
1850             else if(oligo[i] == 'Y'){   reverse += 'R'; }
1851             
1852             else if(oligo[i] == 'M'){   reverse += 'K'; }
1853             else if(oligo[i] == 'K'){   reverse += 'M'; }
1854             
1855             else if(oligo[i] == 'W'){   reverse += 'W'; }
1856             else if(oligo[i] == 'S'){   reverse += 'S'; }
1857             
1858             else if(oligo[i] == 'B'){   reverse += 'V'; }
1859             else if(oligo[i] == 'V'){   reverse += 'B'; }
1860             
1861             else if(oligo[i] == 'D'){   reverse += 'H'; }
1862             else if(oligo[i] == 'H'){   reverse += 'D'; }
1863             
1864             else                                                {       reverse += 'N'; }
1865         }
1866         
1867         
1868         return reverse;
1869     }
1870         catch(exception& e) {
1871                 m->errorOut(e, "MakeContigsCommand", "reverseOligo");
1872                 exit(1);
1873         }
1874 }
1875 //**********************************************************************************************************************
1876 vector<int> MakeContigsCommand::convertQual(string qual) {
1877         try {
1878                 vector<int> qualScores;
1879         bool negativeScores = false;
1880                 
1881                 for (int i = 0; i < qual.length(); i++) { 
1882             
1883             int temp = 0;
1884             temp = int(qual[i]);
1885             if (format == "illumina") {
1886                 temp -= 64; //char '@'
1887             }else if (format == "illumina1.8+") {
1888                     temp -= int('!'); //char '!'
1889             }else if (format == "solexa") {
1890                 temp = int(convertTable[temp]); //convert to sanger
1891                 temp -= int('!'); //char '!'
1892             }else {
1893                 temp -= int('!'); //char '!'
1894             }
1895             
1896             if (temp < -5) { negativeScores = true; }
1897                         qualScores.push_back(temp);
1898                 }
1899                 
1900         if (negativeScores) { m->mothurOut("[ERROR]: finding negative quality scores, do you have the right format selected? http://en.wikipedia.org/wiki/FASTQ_format#Encoding \n");  m->control_pressed = true;  }
1901         
1902                 return qualScores;
1903         }
1904         catch(exception& e) {
1905                 m->errorOut(e, "MakeContigsCommand", "convertQual");
1906                 exit(1);
1907         }
1908 }
1909
1910 //**********************************************************************************************************************
1911
1912
1913
1914