Skip to content

v0.2.49..v0.2.50 changeset ScoreMatchesCmd.cpp

Garret Voltz edited this page Nov 6, 2019 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/cmd/ScoreMatchesCmd.cpp b/hoot-core/src/main/cpp/hoot/core/cmd/ScoreMatchesCmd.cpp
index cc4efab..da5fcec 100644
--- a/hoot-core/src/main/cpp/hoot/core/cmd/ScoreMatchesCmd.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/cmd/ScoreMatchesCmd.cpp
@@ -35,18 +35,22 @@
 #include <hoot/core/ops/NamedOp.h>
 #include <hoot/core/scoring/MatchComparator.h>
 #include <hoot/core/scoring/MatchScoringMapPreparer.h>
-#include <hoot/core/scoring/MapScoringStatusAndRefTagValidator.h>
 #include <hoot/core/util/Log.h>
 #include <hoot/core/schema/MetadataTags.h>
 #include <hoot/core/elements/OsmUtils.h>
 #include <hoot/core/util/Settings.h>
-#include <hoot/core/util/IoUtils.h>
+#include <hoot/core/io/IoUtils.h>
 #include <hoot/core/visitors/CountManualMatchesVisitor.h>
 #include <hoot/core/util/ConfigUtils.h>
+#include <hoot/core/ops/ManualMatchValidator.h>
 
 // tgs
 #include <tgs/Optimization/NelderMead.h>
 
+// Qt
+#include <QElapsedTimer>
+#include <QFileInfo>
+
 using namespace std;
 using namespace Tgs;
 
@@ -62,6 +66,96 @@ public:
 
   ScoreMatchesCmd() { }
 
+  virtual QString getName() const override { return "score-matches"; }
+
+  virtual QString getDescription() const override
+  { return "Scores conflation performance against a manually matched map"; }
+
+  virtual int runSimple(QStringList& args) override
+  {
+    bool showConfusion = false;
+    if (args.contains("--confusion"))
+    {
+      args.removeAll("--confusion");
+      showConfusion = true;
+    }
+    bool optimizeThresholds = false;
+    if (args.contains("--optimize"))
+    {
+      args.removeAll("--optimize");
+      optimizeThresholds = true;
+    }
+    bool validateManualMatches = true;
+    if (args.contains("--validation-off"))
+    {
+      args.removeAll("--validation-off");
+      validateManualMatches = false;
+    }
+
+    if (args.size() < 3 || args.size() % 2 != 1)
+    {
+      LOG_VAR(args);
+      cout << getHelp() << endl << endl;
+      throw HootException(
+        QString("%1 takes at least three parameters: two or more input maps (even number) and an output map")
+          .arg(getName()));
+    }
+
+    ConfigUtils::checkForTagValueTruncationOverride();
+
+    vector<OsmMapPtr> maps;
+    QString output = args.last();
+    for (int i = 0; i < args.size() - 1; i += 2)
+    {
+      OsmMapPtr map(new OsmMap());
+      const QString map1Path = args[i];
+      const QString map2Path = args[i + 1];
+      IoUtils::loadMap(map, map1Path, false, Status::Unknown1);
+      IoUtils::loadMap(map, map2Path, false, Status::Unknown2);
+
+      // If any of the map files have errors, we'll print some out and terminate.
+      if (validateManualMatches && _validateMatches(map, map1Path, map2Path))
+      {
+        return 1;
+      }
+
+      MatchScoringMapPreparer().prepMap(map, ConfigOptions().getScoreMatchesRemoveNodes());
+      maps.push_back(map);
+    }
+    LOG_VARD(maps.size());
+
+    if (optimizeThresholds)
+    {
+      _optimize(maps, showConfusion);
+    }
+    else
+    {
+      double score;
+      std::shared_ptr<MatchThreshold> mt;
+      const QString result = evaluateThreshold(maps, output, mt, showConfusion, score);
+      cout << result;
+    }
+
+    return 0;
+  }
+
+  class ScoreFunction : public Tgs::NelderMead::Function
+  {
+  public:
+
+    virtual double f(Tgs::Vector v)
+    {
+      double score;
+      std::shared_ptr<MatchThreshold> mt(new MatchThreshold(v[0], v[1], v[2]));
+      _cmd->evaluateThreshold(_maps, "", mt, _showConfusion, score);
+      return score;
+    }
+
+    ScoreMatchesCmd* _cmd;
+    vector<OsmMapPtr> _maps;
+    bool _showConfusion;
+  };
+
   QString evaluateThreshold(vector<OsmMapPtr> maps, QString output,
                             std::shared_ptr<MatchThreshold> mt, bool showConfusion,
                             double& score)
@@ -120,29 +214,58 @@ public:
     return result;
   }
 
-  virtual QString getName() const override { return "score-matches"; }
-
-  virtual QString getDescription() const override
-  { return "Scores conflation performance against a manually matched map"; }
+private:
 
-  class ScoreFunction : public Tgs::NelderMead::Function
+  bool _validateMatches(const OsmMapPtr& map, const QString& map1Path, const QString& map2Path)
   {
-  public:
+    QElapsedTimer timer;
+    timer.start();
+    LOG_INFO("Validating manual matches...");
 
-    virtual double f(Tgs::Vector v)
+    ManualMatchValidator inputValidator;
+    inputValidator.setRequireRef1(ConfigOptions().getScoreMatchesRequireRef1());
+    inputValidator.setAllowUuidManualMatchIds(ConfigOptions().getScoreMatchesAllowUuidsAsIds());
+    inputValidator.setFullDebugOutput(ConfigOptions().getScoreMatchesFullDebugOutput());
+    inputValidator.getInitStatusMessage();
+    inputValidator.apply(map);
+    inputValidator.getCompletedStatusMessage();
+
+    LOG_INFO("Validated manual matches in: " << StringUtils::millisecondsToDhms(timer.elapsed()));
+
+    _printIssues(inputValidator.getWarnings(), "warnings", map1Path, map2Path);
+    _printIssues(inputValidator.getErrors(), "errors", map1Path, map2Path);
+
+    return !inputValidator.getErrors().isEmpty();
+  }
+
+  void _printIssues(const QMap<ElementId, QString>& issues, const QString& type,
+                    const QString& map1Path, const QString& map2Path)
+  {
+    if (!issues.isEmpty())
     {
-      double score;
-      std::shared_ptr<MatchThreshold> mt(new MatchThreshold(v[0], v[1], v[2]));
-      _cmd->evaluateThreshold(_maps, "", mt, _showConfusion, score);
-      return score;
+      QFileInfo fileInfo1(map1Path);
+      QFileInfo fileInfo2(map2Path);
+      cout << "There are " << StringUtils::formatLargeNumber(issues.size()) <<
+              " manual match " << type << " for inputs " <<
+              fileInfo1.completeBaseName().right(30) <<
+              " and " << fileInfo2.completeBaseName().right(30) << ":\n\n";
+      int issueCount = 0;
+      for (QMap<ElementId, QString>::const_iterator itr = issues.begin();
+           itr != issues.end(); ++itr)
+      {
+        cout << itr.key().toString() + ": " + itr.value() + "\n";
+
+        issueCount++;
+        if (issueCount >= 10)
+        {
+          cout << "Printing " << type << " for the first 10 elements only..." << endl;
+          break;
+        }
+      }
     }
+  }
 
-    ScoreMatchesCmd* _cmd;
-    vector<OsmMapPtr> _maps;
-    bool _showConfusion;
-  };
-
-  void optimize(vector<OsmMapPtr> maps, bool showConfusion)
+  void _optimize(vector<OsmMapPtr> maps, bool showConfusion)
   {
     ScoreFunction* sf = new ScoreFunction();
     sf->_cmd = this;
@@ -171,71 +294,6 @@ public:
       LOG_VAR(result.getVector());
     }
   }
-
-  virtual int runSimple(QStringList& args) override
-  {
-    bool optimizeThresholds = false;
-    bool showConfusion = false;
-    if (args.contains("--confusion"))
-    {
-      args.removeAll("--confusion");
-      showConfusion = true;
-    }
-
-    if (args.contains("--optimize"))
-    {
-      args.removeAll("--optimize");
-      optimizeThresholds = true;
-    }
-
-    if (args.size() < 3 || args.size() % 2 != 1)
-    {
-      LOG_VAR(args);
-      cout << getHelp() << endl << endl;
-      throw HootException(
-        QString("%1 takes at least three parameters: two or more input maps (even number) and an output map")
-          .arg(getName()));
-    }
-
-    ConfigUtils::checkForTagValueTruncationOverride();
-
-    vector<OsmMapPtr> maps;
-    QString output = args.last();
-    for (int i = 0; i < args.size() - 1; i += 2)
-    {
-      OsmMapPtr map(new OsmMap());
-      IoUtils::loadMap(map, args[i], false, Status::Unknown1);
-      IoUtils::loadMap(map, args[i + 1], false, Status::Unknown2);
-
-      if (!MapScoringStatusAndRefTagValidator::allTagsAreValid(map))
-      {
-        throw HootException(
-          QString("score-matches requires that the first input file contains %1 tags (no %2 tags) "
-                  "and the second input file contains %2 tags (no %1 tags).")
-              .arg(MetadataTags::Ref1())
-              .arg(MetadataTags::Ref2()));
-      }
-
-      MatchScoringMapPreparer().prepMap(map, ConfigOptions().getScoreMatchesRemoveNodes());
-      maps.push_back(map);
-    }
-    LOG_VARD(maps.size());
-
-    if (optimizeThresholds)
-    {
-      optimize(maps, showConfusion);
-    }
-    else
-    {
-      double score;
-      std::shared_ptr<MatchThreshold> mt;
-      const QString result = evaluateThreshold(maps, output, mt, showConfusion, score);
-
-      cout << result;
-    }
-
-    return 0;
-  }
 };
 
 HOOT_FACTORY_REGISTER(Command, ScoreMatchesCmd)
Clone this wiki locally