USGS

Isis 3.0 Object Programmers' Reference

Home

PipelineApplication.cpp
1 #include <iostream>
2 
3 #include "PipelineApplication.h"
4 #include "Pipeline.h"
5 #include "IException.h"
6 #include "Application.h"
7 
8 using namespace Isis;
9 using namespace std;
10 
11 namespace Isis {
20  p_name = appName;
21  p_enabled = true;
22  p_previous = NULL;
23  p_next = NULL;
24  p_pipeline = pipe;
25  p_continue = false;
26 
27  if(p_pipeline->OriginalBranches().size() == 1) {
28  p_inBranches.push_back("");
29  p_outBranches.push_back("");
30  p_enableBranch.push_back(true);
31  }
32  else {
33  p_inBranches = p_pipeline->OriginalBranches();
34  p_outBranches = p_pipeline->OriginalBranches();
35  for(int i=0; i<(int)p_outBranches.size(); i++) {
36  p_enableBranch.push_back(true);
37  }
38  }
39  };
40 
41 
50  p_name = appName;
51  p_enabled = true;
52  p_previous = previous;
53  p_next = NULL;
54  p_pipeline = p_previous->GetPipeline();
55 
56  p_inBranches = p_previous->OutputBranches();
57  p_outBranches = p_previous->OutputBranches();
58  for(int i=0; i<(int)p_outBranches.size(); i++) {
59  p_enableBranch.push_back(true);
60  }
61  p_previous->SetNext(this);
62  }
63 
64 
73  void PipelineApplication::SetInputParameter(const QString &inputParamName, bool supportsVirtualBands) {
74  p_input.clear();
75  p_input.push_back(PipelineParameter(inputParamName));
76  p_supportsVirtualBands = supportsVirtualBands;
77  }
78 
79 
90  void PipelineApplication::SetInputParameter(const QString &inputParamName, CustomParameterValue value, bool supportsVirtualBands) {
91  if(value == LastAppOutputList) {
92  // Merge
93  p_outBranches.clear();
94  p_outBranches.push_back("");
95  }
96  else if(value == LastAppOutputListNoMerge) {
97  // No merge
98  value = LastAppOutputList;
99  }
100 
101  p_input.push_back(PipelineParameter(inputParamName, value));
102  p_supportsVirtualBands = supportsVirtualBands;
103  }
104 
105 
116  void PipelineApplication::SetOutputParameter(const QString &branch, const QString &outputParamName,
117  const QString &outNameModifier, const QString &outFileExtension) {
118  p_output.push_back(PipelineParameter(FindBranch(branch, false), outputParamName));
119  p_outputMod = outNameModifier;
120  p_outputExtension = outFileExtension;
121  }
122 
123 
131  void PipelineApplication::SetOutputParameter(const QString &outputParamName, const QString &outNameModifier, const QString &outFileExtension) {
132  p_output.clear();
133  p_output.push_back(PipelineParameter(outputParamName));
134  p_outputMod = outNameModifier;
135  p_outputExtension = outFileExtension;
136  }
137 
138 
157  void PipelineApplication::AddBranch(const QString &modString, NameModifierType type) {
158  if(modString == "") {
159  string msg = "Can not add empty branch to pipeline";
161  }
162 
163  //if(p_inBranches.size() != 1 || p_inBranches[0] != "") {
164  // string msg = "Can not branch an already branched pipeline";
165  // throw iException::Message(iException::Programmer, msg, _FILEINFO_);
166  //}
167 
168  if(p_outBranches[0] == "") {
169  p_outBranches.clear();
170  p_enableBranch.clear();
171  }
172 
173  if(p_inBranches.size() == 1) {
174  p_outBranches.push_back(modString);
175  p_enableBranch.push_back(true);
176  }
177  else if(p_inBranches.size() == p_outBranches.size()) {
178  for(int outBranch = p_outBranches.size() - 1; outBranch >= 0; outBranch --) {
179  if(p_inBranches[outBranch] == p_outBranches[outBranch]) {
180  p_outBranches[outBranch] = p_inBranches[outBranch] + "." + modString;
181  }
182  else {
183  p_outBranches.push_back(p_inBranches[outBranch] + "." + modString);
184  p_enableBranch.push_back(true);
185  }
186  }
187  }
188  else {
189  for(unsigned int inBranch = 0; inBranch < p_inBranches.size(); inBranch ++) {
190  p_outBranches.push_back(p_inBranches[inBranch] + "." + modString);
191  p_enableBranch.push_back(true);
192  }
193  }
194  }
195 
196 
204  void PipelineApplication::AddParameter(const QString &inputParamName, const QString &appParamName) {
206 
207  if(ui.WasEntered(inputParamName)) {
208  p_params.push_back(PipelineParameter(appParamName, ui.GetAsString(inputParamName)));
209  }
210  }
211 
212 
222  void PipelineApplication::AddParameter(const QString &branch, const QString &inputParamName, const QString &appParamName) {
224 
225  if(ui.WasEntered(inputParamName)) {
226  p_params.push_back(PipelineParameter(FindBranch(branch, false), appParamName, ui.GetAsString(inputParamName)));
227  }
228  }
229 
230 
238  void PipelineApplication::AddConstParameter(const QString &appParamName, const QString &appParamValue) {
239  bool added = false;
240 
241  for(unsigned int i = 0; !added && i < p_params.size(); i++) {
242  if(p_params[i].Name() == appParamName) {
243  p_params[i] = PipelineParameter(appParamName, appParamValue);
244  added = true;
245  }
246  }
247 
248  if(!added) {
249  p_params.push_back(PipelineParameter(appParamName, appParamValue));
250  added = true;
251  }
252  }
253 
254 
264  void PipelineApplication::AddConstParameter(const QString &branch, const QString &appParamName, const QString &appParamValue) {
265  p_params.push_back(PipelineParameter(FindBranch(branch, false), appParamName, appParamValue));
266  }
267 
268 
276  void PipelineApplication::AddParameter(const QString &appParamName, CustomParameterValue value) {
277  p_params.push_back(PipelineParameter(appParamName, value));
278  }
279 
280 
289  void PipelineApplication::AddParameter(const QString &branch, const QString &appParamName, CustomParameterValue value) {
290  p_params.push_back(PipelineParameter(FindBranch(branch, false), appParamName, value));
291  }
292 
293 
303  p_paramString.clear();
304  p_outputs.clear();
305  p_tempFiles.clear();
306 
307  if(!Enabled()) return;
308 
309  // These are used if the pipeline needs a list file; must be out here in case multiple branches use
310  // the list file.
311  bool needList = false;
312  QString listFile;
313 
314  bool runOnce = Merges() && !Branches();
315 
316  /*cerr << "***BuildParamString App " << p_name << " RunOnce="<< runOnce << "***\nInput Branches Size=" << p_inBranches.size() << endl;
317  for(int i=0; i<(int)p_inBranches.size(); i++) {
318  cerr << "Branch" << i << " = " << p_inBranches[i] << endl;
319  }
320 
321  cerr << "Output Branches Size=" << p_outBranches.size() << endl;
322  for(int i=0; i<(int)p_outBranches.size(); i++) {
323  cerr << "Branch" << i << " = " << p_outBranches[i] << " Enabled=" << p_enableBranch[i] << endl;
324  }*/
325 
326  // Make sure we have different inputs for different runs...
327  if(!runOnce && p_input.size() == 1) {
328  PipelineParameter &inputParam = p_input[0];
329  if(inputParam.IsSpecial() && inputParam.Special() == LastAppOutputList) {
330  runOnce = true;
331 
332  for(int param = 0; param < (int)p_params.size() && runOnce; param++) {
333  runOnce = (p_params[param].IsSpecial() && p_params[param].Special() == LastAppOutputList) ||
334  (!p_params[param].IsSpecial() && p_params[param].AffectsAllBranches());
335  }
336  }
337  }
338 
339  // We need to build execute calls for all of the branches
340  for(int branch = 0; branch < (int)p_inBranches.size(); branch ++) {
341  if(runOnce && branch > 0) {
342  return;
343  }
344 
345  if(!BranchEnabled(branch)) {
346  QString tmpBranch(branch);
347  p_outputs.push_back(p_name + "." +tmpBranch + ".blank");
348  continue;
349  }
350 
351 
352  // Figure out the input file; could throw an exception if the user didnt set it
353  QString inputFile = CalculateInputFile(branch);
354  // Figure out the output file; This adds the output to the output list*
355  QString outputFile = CalculateOutputFile(branch);
356  // This parameter gives us more detail about the input parameter
357  PipelineParameter &inputParam = GetInputParameter(branch);
358 
359  QString params = "";
360 
361  // If we havent needed a list yet, let's see if we need one now
362  if(!needList) {
363  // We need to know if we need a list file ahead of time; look at input and parameters
364  needList = (inputParam.IsSpecial() && inputParam.Special() == LastAppOutputList);
365 
366  for(int param = 0; param < (int)p_params.size() && !needList; param++) {
367  needList = (p_params[param].IsSpecial() && p_params[param].Special() == LastAppOutputList);
368  }
369 
370  // If we need a list file, create a parameter that starts with ">>LIST" to say it's a list file.
371  // The first element is the list file, the rest is the contents of the list file.
372  if(needList) {
373  QString listName = outputFile;
374 
375  if(listName.isEmpty()) {
376  // This might have to become more robust in the future, we
377  // have an input list but no outputs to the program for
378  // this case. This is the naming of the list.
379  listName = Name();
380  }
381 
382  QString input = p_pipeline->TemporaryFolder() + "/" + FileName(listName).baseName() + ".lis";
383  params = ">>LIST " + input + " ";
384 
385  PipelineApplication * prev = Previous();
386  int infile = 0;
387  while(prev != NULL && infile < (int)p_inBranches.size()) {
388  for(int i = 0; i < (int)prev->OutputBranches().size(); i++) {
389  if(prev->BranchEnabled(i)) {
390  params += " " + prev->GetOutputs()[i];
391  infile++;
392  }
393  }
394  prev = prev->Previous();
395  }
396 
397  p_tempFiles.push_back(input);
398  p_paramString.push_back(params);
399  params = "";
400  listFile = input;
401  }
402  }
403 
404  // If the input is a list file, set it to the list file
405  if(inputParam.IsSpecial() && inputParam.Special() == LastAppOutputList) {
406  params = GetInputParameter(branch).Name() + "=\"" + listFile + "\"";
407  }
408  else {
409  // Otherwise it's the input file. Try to add virtual bands.
410  // Pipeline will set p_virtualBands to an empty string if we are to not apply it.
411  params = GetInputParameter(branch).Name() + "=\"" + inputFile;
412  if(p_virtualBands.size() == 1) {
413  params += "+" + p_virtualBands[0];
414  }
415  else if(p_virtualBands.size() == p_inBranches.size() && !p_virtualBands[branch].isEmpty()) {
416  params += "+" + p_virtualBands[branch];
417  }
418 
419  params += "\"";
420  }
421 
422  // If we have output, add it on to our parameters
423  if(p_output.size() != 0) {
424  if(Branches() && p_output.size() != 1) {
425  // Set output variable for every branch
426  for(unsigned int outBranch = 0; outBranch < p_outBranches.size(); outBranch ++) {
427  // Each branch should have at least 1 output file
428  bool outputSet = false;
429 
430  // ... unless there is a split, look for the split (check name start)
431  if(p_inBranches.size() > 1) {
432  if(!StringStartsWith(p_outBranches[outBranch], p_inBranches[branch])) {
433  continue;
434  }
435  }
436 
437  // Match the output variable with it's param name
438  for(unsigned int outParam = 0; outParam < p_output.size(); outParam++) {
439  if(p_output[outParam].AppliesToBranch(outBranch)) {
440  params += " " + p_output[outParam].Name() + "=\"" + p_outputs[outBranch] + "\"";
441 
442  if(outputSet) {
443  QString message = "Application [" + Name() + "] in the pipeline branches with an ";
444  message += "output parameter for each branch, but branch [" + p_outBranches[outBranch];
445  message += "] has multiple output files specified.";
447  }
448 
449  outputSet = true;
450  }
451  }
452 
453  if(!outputSet) {
454  QString message = "Application [" + Name() + "] in the pipeline branches with an ";
455  message += "output parameter for each branch, but branch [" + p_outBranches[outBranch];
456  message += "] has no output files specified.";
458  }
459  }
460  }
461  else {
462  bool foundBranch = false;
463 
464  // Find the output parameter name that is acceptable. If we cant find an output branch, then there isnt one!
465  for(unsigned int outputParam = 0; outputParam < p_output.size(); outputParam++) {
466  if(p_output[outputParam].AppliesToBranch(branch)) {
467  params += " " + p_output[0].Name() + "=\"" + outputFile + "\"";
468  foundBranch = true;
469  }
470  }
471 
472  if(!foundBranch) continue;
473  }
474  }
475 
476  // Add the remaining parameters
477  for(int i = 0; i < (int)p_params.size() && i < (int)p_params.size(); i++) {
478  if(p_params[i].AppliesToBranch(branch)) {
479  if(!p_params[i].IsSpecial()) {
480  params += " " + p_params[i].Name() + "=\"" + p_params[i].Value() + "\"";
481  }
482  else if(p_params[i].Special() == LastOutput) {
483  params += " " + p_params[i].Name() + "=\"" + GetRealLastOutput(true) + "\"";
484  }
485  else if(p_params[i].Special() == LastAppOutputList) {
486  params += " " + p_params[i].Name() + "=\"" + listFile + "\"";
487  }
488  }
489  }
490 
491  if(inputFile.isEmpty()) {
492  QString message = "There was a problem with calculating the inputs for program [" + Name();
493  message += "]. Please verify your program is not setting outputs for branches that ";
494  message += "don't have input.";
496  }
497 
498  // Remember this parameter string
499  p_paramString.push_back(params);
500  }
501  }
502 
503 
514  QString file = "";
515 
516  PipelineApplication *prev = Previous();
517 
518  if(prev != NULL) {
519  // The last app exists, look for output on this branch
520  if(branch < (int)prev->GetOutputs().size() && prev->BranchEnabled(branch)) {
521  file = prev->GetOutputs()[branch];
522  }
523  else {
524  while (prev != NULL && file=="") {
525  if(prev->Branches()){
526  if (!prev->BranchEnabled(branch)) {
527  string msg = "Application branches but branch is disabled";
529  }
530  }
531  /* else {
532  vector<QString> inputs = prev->GetInputs();
533  if((int)inputs.size() > branch) {
534  file = inputs[branch];
535  }
536  else {
537  file = inputs[0];
538  }
539  break;
540  }
541  } */
542  //else {
543  if(prev->BranchEnabled(branch)) {
544  if(branch < (int)prev->GetOutputs().size()) {
545  file = prev->GetOutputs()[branch];
546  break;
547  }
548  }
549  // }
550  prev = prev->Previous();
551  }
552  }
553  }
554 
555  // We're either the first program, or nothing has generated output yet.
556  if(file.isEmpty()){
557  file = p_pipeline->OriginalInput(branch);
558  if (file.isEmpty()) {
559  int index = branch / (p_pipeline->OriginalBranchesSize() / p_pipeline->OriginalInputSize());
560  file = p_pipeline->OriginalInput(index);
561  }
562  }
563 
564  // deal with special cases
565  for(int i = 0; i < (int)p_input.size(); i++) {
566  if(p_input[i].AppliesToBranch(branch) && p_input[i].IsSpecial()) {
567  if(p_input[i].Special() == LastOutput) {
568  file = GetRealLastOutput();
569  break;
570  }
571  }
572  }
573  return file;
574  }
575 
576 
585  QString outputFile;
586  QString outFolder = p_pipeline->TemporaryFolder();
587 
588  // We need to know this to know if we actually need to add modifiers to the
589  // output name
590  bool usedBranch = false;
591  unsigned int usedBranchIndex = 0;
592  unsigned int numUsedBranches = 0;
593 
594  for(unsigned int outputBranch = 0; outputBranch < p_outBranches.size(); outputBranch++) {
595  bool outBranchUsed = false;
596 
597  for(unsigned int outputParam = 0; outputParam < p_output.size(); outputParam ++) {
598  if(p_output[outputParam].AppliesToBranch(outputBranch)) {
599  outBranchUsed = true;
600  }
601  }
602 
603  if(outBranchUsed) {
604  if(outputBranch < (unsigned int)branch) {
605  usedBranchIndex ++;
606  }
607 
608  if((unsigned int)branch == outputBranch) {
609  usedBranch = true;
610  }
611 
612  numUsedBranches ++;
613  }
614  }
615 
616  if(!usedBranch) return "";
617 
618  if(!LastApplicationWithOutput()) {
619  QString lastOutput = p_pipeline->FinalOutput(branch, false);
620  outputFile = outFolder + "/" +
621  FileName(lastOutput).baseName() + "." + p_outputMod + "." + p_outputExtension;
622 
623  if(p_outputMod.isEmpty()) {
624  outputFile = outFolder + "/" +
625  FileName(lastOutput).baseName() + "." + p_outputExtension;
626  }
627  }
628  else {
629  outputFile = p_pipeline->FinalOutput(branch, numUsedBranches > 1);
630  outFolder = FileName(outputFile).path();
631  }
632 
633  if(!LastApplicationWithOutput() && numUsedBranches != 1 && !p_outputMod.isEmpty()) {
634  FileName outfile(outputFile);
635 
636  QString realOut(outFolder + "/" + outfile.baseName() + "." + p_outBranches[branch] + "." + p_outputExtension);
637 
638  if(usedBranch) {
639 
640  // This assumes CalculateOutputFile is called in order (branch 0,1,2...n)
641  if(p_outputs.size() == usedBranchIndex) {
642  p_outputs.push_back(realOut);
643  }
644 
645  // If we're only run once, but we branch, we need to store the rest of these real output files...
646  // recursively call to get them stored away. Also we could be run twice, but really have 4 outputs,
647  // so always do this if we branch.
648  if(branch == 0 && Branches()) {
649  for(unsigned int i = 1; i < OutputBranches().size(); i++) {
650  CalculateOutputFile(i);
651  }
652  }
653 
654  // If branches is false, then we need to tell the truth about the output file.
655  // REASONING: thm2isis needs to be lied to (Branches() == true), for example,
656  // because it modifies output names on its own.
657  if(!Branches()) {
658  // tell the truth
659  outputFile = realOut;
660  }
661  }
662  }
663  else if(!p_outputMod.isEmpty()) {
664  if(p_outputs.size() == usedBranchIndex) {
665  p_outputs.push_back(outputFile);
666  }
667 
668  // If we're only run once, but we branch, we need to store the rest of these real output files...
669  // recursively call to get them stored away. Also we could be run twice, but really have 4 outputs,
670  // so always do this if we branch.
671  if(branch == 0 && Branches()) {
672  for(unsigned int i = 1; i < OutputBranches().size(); i++) {
673  CalculateOutputFile(i);
674  }
675  }
676  }
677 
678  return outputFile;
679  }
680 
681 
689  if(!Next() && !p_output.empty()) {
690  return true;
691  }
692  if(!Next() && p_output.empty()) {
693  return false;
694  }
695 
696  // If any future app creates output, then I'm not last
697  return !Next()->FutureOutputFileCreated();
698  }
699 
700 
708  if(!p_output.empty()) {
709  return true;
710  }
711 
712  if(!Next() && p_output.empty()) {
713  return false;
714  }
715 
716  return Next()->FutureOutputFileCreated();
717  }
718 
719 
728  for(int i = 0; i < (int)p_input.size(); i++) {
729  if(p_input[i].AppliesToBranch(branch)) {
730  return p_input[i];
731  }
732  }
733 
734  if(p_inBranches[0] != "") {
735  QString msg = "Application [" + Name() + "] in the pipeline does not have an input for branch [" + p_inBranches[branch] + "]";
737  }
738  else {
739  QString msg = "Application [" + Name() + "] in the pipeline does not have an input";
741  }
742  }
743 
744 
753  int PipelineApplication::FindBranch(QString name, bool input) {
754  int branchIndex = 0;
755  bool found = false;
756 
757  if(input) {
758  while(!found && branchIndex < (int)p_inBranches.size()) {
759  if(p_inBranches[branchIndex] == name) {
760  found = true;
761  }
762  else {
763  branchIndex ++;
764  }
765  }
766  }
767  else {
768  while(!found && branchIndex < (int)p_outBranches.size()) {
769  if(p_outBranches[branchIndex] == name) {
770  found = true;
771  }
772  else {
773  branchIndex ++;
774  }
775  }
776  }
777 
778  if(!found) {
779  QString msg = "Branch [" + name + "] does not exist in the pipeline application [" + Name() + "]";
781  }
782 
783  return branchIndex;
784  }
785 
786 
794  vector<QString> tmp;
795 
796  if(!LastApplicationWithOutput()) {
797  for(int i = 0; i < (int)p_outputs.size(); i++) {
798  tmp.push_back(p_outputs[i]);
799  }
800  }
801 
802  for(int i = 0; i < (int)p_tempFiles.size(); i++) {
803  tmp.push_back(p_tempFiles[i]);
804  }
805 
806  return tmp;
807  }
808 
809 
820  if(!skipOne) {
821  return GetOutputs()[GetOutputs().size()-1];
822  }
823 
824  if(p_outputs.size() > 1) {
825  return GetOutputs()[GetOutputs().size()-2];
826  }
827 
828  return Previous()->GetOutputs()[Previous()->GetOutputs().size()-1];
829  }
830 
831 
839  if(!Enabled()) return false;
840  return p_supportsVirtualBands;
841  }
842 
843 
850  void PipelineApplication::SetVirtualBands(vector<QString> bands) {
851  p_virtualBands = bands;
852  }
853 
855  vector<QString> &PipelineApplication::GetOutputs() {
856  if(Enabled() && p_outputs.size() != 0) {
857  return p_outputs;
858  }
859  else if(Previous()) {
860  return Previous()->GetOutputs();
861  }
862  else {
863  // no outputs yet... not sure if an exception should be thrown, sometimes
864  // things such as list files will fail when this returns nothing.
865  return p_outputs;
866  }
867  }
868 }; // end namespace Isis