USGS

Isis 3.0 Object Programmers' Reference

Home

Pipeline.cpp
1 #include <iostream>
2 
3 #include <QFile>
4 
5 #include "Pipeline.h"
6 #include "PipelineApplication.h"
7 #include "ProgramLauncher.h"
8 #include "IException.h"
9 #include "Application.h"
10 #include "Preference.h"
11 #include "Progress.h"
12 #include "TextFile.h"
13 #include "FileName.h"
14 
15 using namespace Isis;
16 using namespace std;
17 
18 namespace Isis {
19 
20 
30  Pipeline::Pipeline(const QString &procAppName) {
31  p_pausePosition = -1;
32  p_procAppName = procAppName;
33  p_addedCubeatt = false;
34  p_outputListNeedsModifiers = false;
35  p_continue = false;
36  }
37 
38 
44  for (int i = 0; i < (int)p_apps.size(); i++) {
45  delete p_apps[i];
46  }
47 
48  p_apps.clear();
49  }
50 
51 
64  // Nothing in the pipeline? quit
65  if (p_apps.size() == 0) return;
66 
67  // We might have to modify the pipeline and try again, so keep track of if this is necessary
68  bool successfulPrepare = false;
69 
70  while (!successfulPrepare) {
71  // Assume we'll be successful
72  successfulPrepare = true;
73  bool foundFirst = false;
74 
75  // Keep track of whether or not we must remove virtual bands
76  bool mustElimBands = false;
77 
78  // Look to see if we need to eliminate virtual bands...
79  for (unsigned int i = 0; i < p_virtualBands.size(); i++) {
80  mustElimBands |= !p_virtualBands[i].isEmpty();
81  }
82 
83  // Keep track of temp files for conflicts
84  vector<QString> tmpFiles;
85 
86  // Loop through all the pipeline apps, look for a good place to remove virtual
87  // bands and tell the apps the prepare themselves. Double check the first program
88  // is not branched (expecting multiple inputs).
89  for (int i = 0; i < (int)p_apps.size() && successfulPrepare; i++) {
90  if (p_apps[i] == NULL) continue;
91  if (mustElimBands && p_apps[i]->SupportsVirtualBands()) {
92  if (i != 0 && p_virtualBands.size() != 1) {
93  QString message = "If multiple original inputs were set in the pipeline, the first application must support virtual bands.";
95  }
96 
97  p_apps[i]->SetVirtualBands(p_virtualBands);
98  mustElimBands = false;
99 
100  // We might have added the "cubeatt" program to eliminate bands,
101  // remove it if we found something else to do the virtual bands.
102  // **This causes a failure in our calculations, start over.
103  if (p_addedCubeatt && i != (int)p_apps.size() - 1) {
104  delete p_apps[p_apps.size() - 1];
105  p_apps.resize(p_apps.size() - 1);
106  p_appIdentifiers.resize(p_appIdentifiers.size() - 1);
107  p_apps[p_apps.size() - 1]->SetNext(NULL);
108  p_addedCubeatt = false;
109  successfulPrepare = false;
110  continue;
111  }
112  }
113  else {
114  // Pipeline is responsible for the virtual bands, reset any apps
115  // who have an old virtual bands setting.
116  vector<QString> empty;
117  p_apps[i]->SetVirtualBands(empty);
118  }
119 
120  // This instructs the pipeline app to prepare itself; all previous pipeline apps must
121  // be already prepared. Future pipeline apps do not have to be.
122  p_apps[i]->BuildParamString();
123 
124  // keep track of tmp files
125  vector<QString> theseTempFiles = p_apps[i]->TemporaryFiles();
126  for (int tmpFile = 0; tmpFile < (int)theseTempFiles.size(); tmpFile++) {
127  // no need to delete blank files
128  if (theseTempFiles[tmpFile].contains("blank")) {
129  tmpFiles.push_back(theseTempFiles[tmpFile]);
130  }
131  }
132 
133  if (!foundFirst && p_apps[i]->Enabled()) {
134  foundFirst = true;
135 
136  if (p_apps[i]->InputBranches().size() != OriginalBranches().size()) {
137  QString msg = "The program [" + p_apps[i]->Name() + "] can not be the first in the pipeline";
138  msg += " because it must be run multiple times with unspecified varying inputs";
140  }
141  }
142  }
143 
144  // Make sure we found an app!
145  if (!foundFirst) {
146  string msg = "No applications are enabled in the pipeline";
148  }
149 
150  // Make sure all tmp files are unique!
151  for (int i = 0; successfulPrepare && i < (int)tmpFiles.size(); i++) {
152  for (int j = i + 1; j < (int)tmpFiles.size(); j++) {
153  if (tmpFiles[i] == tmpFiles[j]) {
154  QString msg = "There is a conflict with the temporary file naming. The temporary file [";
155  msg += tmpFiles[i] + "] is created twice.";
157  }
158  }
159  }
160 
161  // We failed at eliminating bands, add stretch to our programs and try again
162  if (successfulPrepare && mustElimBands) {
163  AddToPipeline("cubeatt", "~PIPELINE_RESERVED_FOR_BANDS~");
164  Application("~PIPELINE_RESERVED_FOR_BANDS~").SetInputParameter("FROM", true);
165  Application("~PIPELINE_RESERVED_FOR_BANDS~").SetOutputParameter("TO", "final");
166  p_addedCubeatt = true;
167  successfulPrepare = false;
168  }
169 
170  int lastApp = p_apps.size()-1;
171  if (p_apps[p_apps.size()-1] == NULL)
172  lastApp = p_apps.size() - 2;
173 
174  if (p_apps[lastApp]->GetOutputs().size() == 0) {
175  string msg = "There are no outputted files in the pipeline. At least one program must generate an output file.";
177  }
178  }
179  }
180 
181 
193  void Pipeline::Run() {
194  // Prepare the pipeline programs
195  Prepare();
196 
197  // Get the starting point
198  p_pausePosition++;
199 
200  Progress pipelineProg;
201  pipelineProg.SetText(p_procAppName);
202  pipelineProg.SetMaximumSteps(1);
203  pipelineProg.CheckStatus();
204 
205  // Go through these programs, executing them
206  for (int i = p_pausePosition; i < Size(); i++) {
207 
208  // Return to caller for a pause
209  if (p_apps[i] == NULL) {
210  p_pausePosition = i;
211  return;
212  }
213 
214  if (Application(i).Enabled()) {
215  Progress appName;
216  appName.SetText("Running " + Application(i).Name());
217  appName.SetMaximumSteps(1);
218  appName.CheckStatus();
219 
220  // grab the sets of parameters this program needs to be run with
221  const vector<QString> &params = Application(i).ParamString();
222  for (int j = 0; j < (int)params.size(); j++) {
223 
224  // check for non-program run special strings
225  QString special(params[j].mid(0, 7));
226 
227  // If ">>LIST", then we need to make a list file
228  if (special == ">>LIST ") {
229  QString cmd = params[j].mid(7);
230 
231  QStringList listData = cmd.split(" ");
232  QString listFileName = listData.takeFirst();
233  TextFile listFile(listFileName, "overwrite");
234 
235  while (!listData.isEmpty()) {
236  listFile.PutLine(listData.takeFirst());
237  }
238 
239  listFile.Close();
240  }
241  else {
242  // Nothing special is happening, just execute the program
243  try {
244  ProgramLauncher::RunIsisProgram(Application(i).Name(), params[j]);
245  }
246  catch (IException &e) {
247  if (!p_continue && !Application(i).Continue()) {
248  throw;
249  }
250  else {
251  e.print();
252  cerr << "Continuing ......" << endl;
253  }
254  }
255  }
256  }
257  }
258  }
259 
260  // Remove temporary files now
261  if (!KeepTemporaryFiles()) {
262  for (int i = 0; i < Size(); i++) {
263  if (p_apps[i] == NULL) continue;
264  if (Application(i).Enabled()) {
265  vector<QString> tmpFiles = Application(i).TemporaryFiles();
266  for (int file = 0; file < (int)tmpFiles.size(); file++) {
267  QFile::remove(tmpFiles[file]);
268  }
269  }
270  }
271  }
272 
273  // Reset pause position
274  p_pausePosition = -1;
275  }
276 
277 
286  void Pipeline::SetInputFile(const char *inputParam) {
287  SetInputFile(QString(inputParam));
288  }
289 
290 
301  void Pipeline::SetInputFile(const QString &inputParam) {
303  p_originalInput.push_back(ui.GetFileName(inputParam));
304  p_inputBranches.push_back(inputParam);
305  p_virtualBands.push_back(ui.GetInputAttribute(inputParam).toString());
306  }
307 
308 
318  void Pipeline::SetInputFile(const FileName &inputFile) {
319  p_originalInput.push_back(inputFile.original());
320  p_inputBranches.push_back(inputFile.original());
321  p_virtualBands.push_back("");
322  }
323 
324 
333  void Pipeline::SetInputListFile(const char *inputParam) {
334  SetInputListFile(QString(inputParam));
335  }
336 
337 
348  void Pipeline::SetInputListFile(const QString &inputParam) {
350 
351  TextFile filelist(FileName(ui.GetFileName(inputParam)).expanded());
352  QString filename;
353  int branch = 1;
354 
355  while (filelist.GetLineNoFilter(filename)) {
356  p_originalInput.push_back(filename);
357  p_inputBranches.push_back(inputParam + toString(branch));
358  p_virtualBands.push_back("");
359  p_finalOutput.push_back(FileName(filename).name());
360 
361  branch ++;
362  }
363 
364  p_outputListNeedsModifiers = true;
365  }
366 
367 
376  void Pipeline::SetInputListFile(const FileName &inputFileName) {
377  TextFile filelist(inputFileName.expanded());
378  QString filename;
379  int branch = 1;
380 
381  while (filelist.GetLineNoFilter(filename)) {
382  p_originalInput.push_back(filename);
383  p_inputBranches.push_back(FileName(inputFileName).expanded() + " " + QString(branch));
384  p_finalOutput.push_back(FileName(filename).name());
385  p_virtualBands.push_back("");
386 
387  branch ++;
388  }
389 
390  p_outputListNeedsModifiers = true;
391  }
392 
393 
405  void Pipeline::SetInputFile(const char *inputParam, const char *virtualBandsParam) {
406  SetInputFile(QString(inputParam), QString(virtualBandsParam));
407  }
408 
409 
423  void Pipeline::SetInputFile(const QString &inputParam, const QString &virtualBandsParam) {
425  p_originalInput.push_back(ui.GetAsString(inputParam));
426  p_inputBranches.push_back(inputParam);
427 
428  if (!virtualBandsParam.isEmpty() && ui.WasEntered(virtualBandsParam)) {
429  p_virtualBands.push_back(ui.GetAsString(virtualBandsParam));
430  }
431  else {
432  p_virtualBands.push_back("");
433  }
434  }
435 
436 
446  void Pipeline::SetOutputFile(const char *outputParam) {
447  SetOutputFile(QString(outputParam));
448  }
449 
450 
460  void Pipeline::SetOutputFile(const QString &outputParam) {
462  p_finalOutput.clear();
463 
464  if (ui.WasEntered(outputParam)) {
465  p_finalOutput.push_back(ui.GetAsString(outputParam));
466  }
467  }
468 
469 
478  void Pipeline::SetOutputFile(const FileName &outputFile) {
479  p_finalOutput.clear();
480  p_finalOutput.push_back(outputFile.expanded());
481  }
482 
483 
492  void Pipeline::SetOutputListFile(const char *outputFileNameParam) {
493  SetOutputListFile(QString(outputFileNameParam));
494  }
495 
496 
505  void Pipeline::SetOutputListFile(const QString &outputFileNameParam) {
507 
508  if (ui.WasEntered(outputFileNameParam)) {
509  SetOutputListFile(FileName(ui.GetFileName(outputFileNameParam)));
510  }
511  else {
512  p_finalOutput.clear();
513 
514  // Calculate output files
515  for (unsigned int i = 0; i < p_originalInput.size(); i++) {
516  p_finalOutput.push_back(FileName(p_originalInput[i]).name());
517  }
518 
519  p_outputListNeedsModifiers = true;
520  }
521  }
522 
523 
530  void Pipeline::SetOutputListFile(const FileName &outputFileNameList) {
531  p_finalOutput.clear();
532 
533  TextFile filelist(outputFileNameList.expanded());
534  QString filename;
535 
536  while (filelist.GetLineNoFilter(filename)) {
537  p_finalOutput.push_back(filename);
538  }
539 
540  p_outputListNeedsModifiers = false;
541  }
542 
543 
551  p_keepTemporary = keep;
552  }
553 
554 
563  // Add the pause
564  QString pauseAppId = "";
565  PipelineApplication *pauseApp = NULL;
566 
567  p_apps.push_back(pauseApp);
568  p_appIdentifiers.push_back(pauseAppId);
569  }
570 
571 
585  void Pipeline::AddToPipeline(const QString &appname, const QString &identifier) {
586  // Check uniqueness first
587  for (unsigned int appIdentifier = 0; appIdentifier < p_appIdentifiers.size(); appIdentifier++) {
588  if (p_appIdentifiers[appIdentifier] == identifier) {
589  QString message = "The application identifier [" + identifier + "] is not unique. " +
590  "Please providing a unique identifier";
592  }
593  }
594 
595  // If we've got cubeatt on our list of applications for band eliminating, take it away temporarily
596  PipelineApplication *cubeAtt = NULL;
597  QString cubeAttId = "";
598  if (p_addedCubeatt) {
599  cubeAtt = p_apps[p_apps.size()-1];
600  cubeAttId = p_appIdentifiers[p_appIdentifiers.size()-1];
601  p_apps.resize(p_apps.size() - 1);
602  p_appIdentifiers.resize(p_appIdentifiers.size() - 1);
603  p_apps[p_apps.size()-1]->SetNext(NULL);
604  }
605 
606  //Check for non nulls instead of size ie. find last non null or use this
607  int appsSize = 0;
608  QString pauseAppId = "";
609 
610  for (int iapp = 0; iapp < (int) p_apps.size(); iapp++)
611  if (p_apps[iapp] != NULL) appsSize++;
612 
613  // Add the new application
614  if (p_apps.size() == 0) {
615  p_apps.push_back(new PipelineApplication(appname, this));
616  }
617  else {
618  if (p_apps[p_apps.size()-1] != NULL)
619  p_apps.push_back(new PipelineApplication(appname, p_apps[p_apps.size()-1]));
620  else // We know we have app NULL before this new app
621  p_apps.push_back(new PipelineApplication(appname, p_apps[p_apps.size()-2]));
622  }
623 
624  p_appIdentifiers.push_back(identifier);
625 
626  // If we have stretch, put it back where it belongs
627  if (cubeAtt) {
628  p_apps[p_apps.size()-1]->SetNext(cubeAtt);
629  cubeAtt->SetPrevious(p_apps[p_apps.size()-1]);
630  p_apps.push_back(cubeAtt);
631  p_appIdentifiers.push_back(cubeAttId);
632  }
633  }
634 
635 
647  void Pipeline::AddToPipeline(const QString &appname) {
648  // Check uniqueness first
649  for (unsigned int appIdentifier = 0; appIdentifier < p_appIdentifiers.size(); appIdentifier++) {
650  if (p_appIdentifiers[appIdentifier] == appname) {
651  QString message = "The application identifier [" + appname + "] is not unique. Please use " +
652  "the other AddToPipeline method providing a unique identifier";
654  }
655  }
656 
657  // If we've got cubeatt on our list of applications for band eliminating, take it away temporarily
658  PipelineApplication *cubeAtt = NULL;
659  QString cubeAttId = "";
660  if (p_addedCubeatt) {
661  cubeAtt = p_apps[p_apps.size()-1];
662  cubeAttId = p_appIdentifiers[p_appIdentifiers.size()-1];
663  p_apps.resize(p_apps.size() - 1);
664  p_appIdentifiers.resize(p_appIdentifiers.size() - 1);
665  p_apps[p_apps.size()-1]->SetNext(NULL);
666  }
667 
668  // Add the new application
669  if (p_apps.size() == 0) {
670  p_apps.push_back(new PipelineApplication(appname, this));
671  }
672  else {
673  if (p_apps[p_apps.size()-1] != NULL)
674  p_apps.push_back(new PipelineApplication(appname, p_apps[p_apps.size()-1]));
675  else // We know we have app NULL before this new app
676  p_apps.push_back(new PipelineApplication(appname, p_apps[p_apps.size()-2]));
677  }
678 
679  p_appIdentifiers.push_back(appname);
680 
681  // If we have stretch, put it back where it belongs
682  if (cubeAtt) {
683  p_apps[p_apps.size()-1]->SetNext(cubeAtt);
684  cubeAtt->SetPrevious(p_apps[p_apps.size()-1]);
685  p_apps.push_back(cubeAtt);
686  p_appIdentifiers.push_back(cubeAttId);
687  }
688  }
689 
690 
700  PipelineApplication &Pipeline::Application(const QString &identifier) {
701  int index = 0;
702  bool found = false;
703 
704  while (!found && index < Size()) {
705  if (p_appIdentifiers[index] == identifier) {
706  found = true;
707  }
708  else {
709  index ++;
710  }
711  }
712 
713  if (!found) {
714  QString msg = "Application identified by [" + identifier + "] has not been added to the pipeline";
716  }
717 
718  return *p_apps[index];
719  }
720 
721 
731  if (index > Size()) {
732  QString msg = "Index [" + QString(index) + "] out of bounds";
734  }
735 
736  return *p_apps[index];
737  }
738 
739 
752  void Pipeline::SetFirstApplication(const QString &appname) {
753  int appIndex = 0;
754  for (appIndex = 0; appIndex < (int)p_apps.size() &&
755  p_apps[appIndex]->Name() != appname; appIndex++) {
756  if (p_apps[appIndex] == NULL) continue;
757  p_apps[appIndex]->Disable();
758  }
759  // for (appIndex = 0; appIndex < (int)p_apps.size() && p_apps[appIndex]->Name() != appname; appIndex++) {
760  // p_apps[appIndex]->Disable();
761  // }
762 
763  if (appIndex >= (int)p_apps.size()) {
764  QString msg = "Pipeline could not find application [" + appname + "]";
766  }
767  }
768 
769 
782  void Pipeline::SetLastApplication(const QString &appname) {
783  int appIndex = p_apps.size() - 1;
784  for (appIndex = p_apps.size() - 1; appIndex >= 0 && p_apps[appIndex]->Name() != appname; appIndex --) {
785  if (p_apps[appIndex] == NULL) continue;
786  p_apps[appIndex]->Disable();
787  }
788 
789  if (appIndex < 0) {
790  QString msg = "Pipeline could not find application [" + appname + "]";
792  }
793  }
794 
795 
809  QString Pipeline::FinalOutput(int branch, bool addModifiers) {
810  QString output = ((p_finalOutput.size() != 0) ? p_finalOutput[0] : "");
811 
812  if (p_apps.size() == 0) return output;
813 
814  if (p_finalOutput.size() > 1) {
815  if ((unsigned int)branch >= p_finalOutput.size()) {
816  QString msg = "Output not set for branch [" + QString(branch) + "]";
818  }
819 
820  if (!p_outputListNeedsModifiers) {
821  return p_finalOutput[branch];
822  }
823  else {
824  output = p_finalOutput[branch];
825  addModifiers = true;
826  }
827  }
828 
829  PipelineApplication *last = p_apps[p_apps.size()-1];
830  if (last == NULL) last = p_apps[p_apps.size()-2];
831  if (!last->Enabled()) last = last->Previous();
832 
833  if (output == "" || p_finalOutput.size() > 1) {
834  if (output == "") {
835  output = "./" + FileName(p_originalInput[0]).baseName();
836  }
837  else {
838  output = "./" + FileName(p_originalInput[branch]).baseName();
839  }
840 
841  // Base filename off of first input file
842  if (!addModifiers || last->OutputBranches().size() == 1) {
843  if (addModifiers && p_finalOutput.size() > 1)
844  output += "." + last->OutputNameModifier();
845 
846  output += "." + last->OutputExtension();
847  }
848  else {
849  // If we have multiple final outputs, rely on them to
850  // differentiate the branches
851  if (p_finalOutput.size() <= 1) {
852  output += "." + last->OutputBranches()[branch];
853  }
854 
855  if (addModifiers && p_finalOutput.size() > 1)
856  output += "." + last->OutputNameModifier();
857 
858  output += "." + last->OutputExtension();
859  }
860  }
861  else if (addModifiers) {
862  PipelineApplication *last = p_apps[p_apps.size()-1];
863  if (!last->Enabled()) last = last->Previous();
864 
865  output = FileName(p_finalOutput[0]).path() + "/" +
866  FileName(p_finalOutput[0]).baseName() + "." +
867  last->OutputBranches()[branch] + ".";
868 
869  if (p_finalOutput.size() > 1) {
870  output += last->OutputNameModifier() + ".";
871  }
872 
873  output += last->OutputExtension();
874  }
875 
876  return output;
877  }
878 
879 
887  Pvl &pref = Preference::Preferences();
888  return pref.findGroup("DataDirectory")["Temporary"];
889  }
890 
891 
901  for (int i = 0; i < Size(); i++) {
902  if (p_apps[i] != NULL) p_apps[i]->Enable();
903  }
904  }
905 
906 
923  ostream &operator<<(ostream &os, Pipeline &pipeline) {
924  pipeline.Prepare();
925 
926  if (!pipeline.Name().isEmpty()) {
927  os << "PIPELINE -------> " << pipeline.Name() << " <------- PIPELINE" << endl;
928  }
929 
930  for (int i = 0; i < pipeline.Size(); i++) {
931  if (&(pipeline.Application(i)) == NULL) continue;
932  if (pipeline.Application(i).Enabled()) {
933  const vector<QString> &params = pipeline.Application(i).ParamString();
934  for (int j = 0; j < (int)params.size(); j++) {
935  QString special(params[j].mid(0, 7));
936  if (special == ">>LIST ") {
937  QString cmd = params[j].mid(7);
938 
939  QStringList listFileData = cmd.split(" ");
940  QString file = listFileData.takeFirst();
941  os << "echo -e \"" << listFileData.join("\\n") << "\" > " << file << endl;
942  }
943  else {
944  os << pipeline.Application(i).Name() << " " << params[j] << endl;
945  }
946  }
947  }
948  }
949 
950  if (!pipeline.KeepTemporaryFiles()) {
951  for (int i = 0; i < pipeline.Size(); i++) {
952  if (&(pipeline.Application(i)) == NULL) continue;
953  if (pipeline.Application(i).Enabled()) {
954  vector<QString> tmpFiles = pipeline.Application(i).TemporaryFiles();
955  for (int file = 0; file < (int)tmpFiles.size(); file++) {
956  if (!tmpFiles[file].contains("blank")) {
957  os << "rm " << tmpFiles[file] << endl;
958  }
959  }
960  }
961  }
962  }
963 
964  if (!pipeline.Name().isEmpty()) {
965  os << "PIPELINE -------> " << pipeline.Name() << " <------- PIPELINE" << endl;
966  }
967 
968  return os;
969  }
970 }