From 3227e43ded8a45eaa3d92794546c2bb426aa8cc3 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Thu, 9 Jun 2022 14:35:22 +0200
Subject: [PATCH] Improve error reporting if derived condition dependencies
 cannot be resolved and add example

---
 .../DDCond/ConditionsDependencyHandler.h      | 12 ++-
 DDCond/src/ConditionsDependencyHandler.cpp    | 64 ++++++++++++---
 DDCore/include/DD4hep/ConditionDerived.h      |  6 +-
 DDCore/include/DD4hep/Conditions.h            | 49 ++++++++++++
 DDCore/src/ConditionDerived.cpp               |  2 +-
 DDCore/src/Conditions.cpp                     | 79 ++++++++++++++++---
 examples/Conditions/CMakeLists.txt            | 10 ++-
 .../src/ConditionExampleObjects.cpp           | 35 +++++++-
 .../Conditions/src/ConditionExampleObjects.h  | 22 +++++-
 .../Conditions/src/ConditionExample_load.cpp  |  8 +-
 .../src/ConditionExample_populate.cpp         |  8 +-
 11 files changed, 257 insertions(+), 38 deletions(-)

diff --git a/DDCond/include/DDCond/ConditionsDependencyHandler.h b/DDCond/include/DDCond/ConditionsDependencyHandler.h
index 0fafb9427..73d27a1e1 100644
--- a/DDCond/include/DDCond/ConditionsDependencyHandler.h
+++ b/DDCond/include/DDCond/ConditionsDependencyHandler.h
@@ -139,14 +139,20 @@ namespace dd4hep {
       /// Accessor for the current conditons mapping
       virtual ConditionsMap& conditionsMap() const override   { return m_pool;              }
       /// ConditionResolver implementation: Interface to access conditions.
-      virtual Condition get(const ConditionKey& key) override { return get(key.hash, true); }
+      virtual Condition get(const ConditionKey& key) override
+      {  return get(key.hash, nullptr, true);                                               }
       /// Interface to access conditions by conditions key
       virtual Condition get(const ConditionKey& key, bool throw_if_not)  override
-      {  return get(key.hash, throw_if_not);                                                }
+      {  return get(key.hash, nullptr, throw_if_not);                                       }
       /// ConditionResolver implementation: Interface to access conditions
-      virtual Condition get(Condition::key_type key) override { return get(key, true);      }
+      virtual Condition get(Condition::key_type key) override
+      {  return get(key, nullptr, true);                                                    }
       /// Interface to access conditions by hash value
       virtual Condition get(Condition::key_type key, bool throw_if_not)  override;
+      /// Interface to access conditions by hash value
+      virtual Condition get(Condition::key_type key,
+                            const ConditionDependency* dependency,
+                            bool throw_if_not)  override;
       /// Interface to access conditions by hash value of the DetElement (only valid at resolve!)
       virtual std::vector<Condition> get(DetElement de)    override;
       /// Interface to access conditions by hash value of the DetElement (only valid at resolve!)
diff --git a/DDCond/src/ConditionsDependencyHandler.cpp b/DDCond/src/ConditionsDependencyHandler.cpp
index e210df43b..5671c849b 100644
--- a/DDCond/src/ConditionsDependencyHandler.cpp
+++ b/DDCond/src/ConditionsDependencyHandler.cpp
@@ -23,7 +23,7 @@ using namespace dd4hep::cond;
 
 namespace {
   std::string dependency_name(const ConditionDependency* d)  {
-#ifdef DD4HEP_CONDITIONS_DEBUG
+#if defined(DD4HEP_CONDITIONS_HAVE_NAME)
     return d->target.name;
 #else
     char text[64];
@@ -51,7 +51,7 @@ Condition ConditionsDependencyHandler::Work::resolve(Work*& current)   {
   current = this;
   state = RESOLVED;
   if ( !condition )   {
-    printout(ERROR,"ConditionsDependency","ERROR: Cannot resolve not existing conditions.");
+    printout(ERROR,"DependencyHandler","ERROR: Cannot resolve not existing conditions.");
   }
   context.dependency->callback->resolve(condition, context);
   previous->do_intersection(iov);
@@ -97,8 +97,8 @@ void ConditionsDependencyHandler::compute()   {
     if ( !i.second->condition )  {
       do_callback(i.second);
       if ( !i.second->condition )  {
-	except("ConditionsDependencyHandler",
-	       "Derived condition was not created after calling the creation callback!");
+        except("DependencyHandler",
+               "Derived condition was not created after calling the creation callback!");
       }
     }
     // printout(INFO,"UserPool","Already calcluated: %s",d->name());
@@ -191,7 +191,7 @@ std::vector<Condition> ConditionsDependencyHandler::getByItem(Condition::itemkey
     for (auto c : proc.conditions ) m_currentWork->do_intersection(c->iov);
     return proc.conditions;
   }
-  except("ConditionsDependencyHandler",
+  except("DependencyHandler",
          "Conditions bulk accesses are only possible during conditions resolution!");
   return std::vector<Condition>();
 }
@@ -205,13 +205,21 @@ std::vector<Condition> ConditionsDependencyHandler::get(Condition::detkey_type d
     for (auto c : conditions ) m_currentWork->do_intersection(c->iov);
     return conditions;
   }
-  except("ConditionsDependencyHandler",
+  except("DependencyHandler",
          "Conditions bulk accesses are only possible during conditions resolution!");
   return std::vector<Condition>();
 }
 
 /// ConditionResolver implementation: Interface to access conditions
 Condition ConditionsDependencyHandler::get(Condition::key_type key, bool throw_if_not)  {
+  return this->get(key, nullptr, throw_if_not);
+}
+
+/// ConditionResolver implementation: Interface to access conditions
+Condition ConditionsDependencyHandler::get(Condition::key_type key,
+                                           const ConditionDependency* dependency,
+                                           bool throw_if_not)
+{
   /// If we are not already resolving here, we follow the normal procedure
   Condition c = m_pool.get(key);
   if ( c.isValid() )  {
@@ -236,6 +244,40 @@ Condition ConditionsDependencyHandler::get(Condition::key_type key, bool throw_i
     }
   }
   if ( throw_if_not )  {
+    if ( dependency )    {
+      // We need here more elaborate printout to ease debugging capabilities
+      std::string de_path   = dependency->detector.path();
+#if 0 // defined(DD4HEP_CONDITIONS_HAVE_NAME)
+      std::string cond_from = dependency->target.name;
+      std::string cond_to   = "UNKNOWN";
+      for(const auto& d : dependency->dependencies)    {
+        if ( d.hash == key )    {
+          cond_to = d.name;
+          break;
+        }
+      }
+      printout(ERROR,"DependencyHandler",
+               "Failed to resolve conditon:%016lX for DetElement: %s",
+               key, de_path.c_str());
+      printout(ERROR,"DependencyHandler",
+               "Condition: %s dependent on missing condition: %s",
+               cond_from.c_str(), cond_to.c_str());
+#else
+      if ( detail::have_condition_item_inventory(-1) )   {
+        std::string item_from = detail::get_condition_item_name(dependency->target.hash);
+        std::string item_to   = detail::get_condition_item_name(key);
+        printout(ERROR,"DependencyHandler",
+                 "Failed to resolve conditon:%016lX for DetElement: %s",
+                 key, de_path.c_str());
+        printout(ERROR,"DependencyHandler",
+                 "Condition: %s#%s dependent on missing condition item: %s",
+                 de_path.c_str(), item_from.c_str(), item_to.c_str());
+      }
+#endif
+      except("DependencyHandler",
+             "Failed to resolve conditon:%016lX for DetElement: %s",
+             key,de_path.c_str());
+    }
     except("ConditionsDependencyHandler","Failed to resolve conditon:%016lX",key);
   }
   return Condition();
@@ -281,7 +323,7 @@ void ConditionsDependencyHandler::do_callback(Work* work)   {
       ++num_callback;
     }
     else   {
-      printout(ERROR,"ConditionDependency",
+      printout(ERROR,"DependencyHandler",
 	       "+++ Callback handler returned invalid condition.  Key:%s %c%s%c",
 	       work->context.dependency->target.toString().c_str(),
 #if defined(DD4HEP_CONDITIONS_DEBUG)
@@ -295,18 +337,18 @@ void ConditionsDependencyHandler::do_callback(Work* work)   {
     return;
   }
   catch(const std::exception& e)   {
-    printout(ERROR,"ConditionDependency",
+    printout(ERROR,"DependencyHandler",
              "+++ Exception while creating dependent Condition %s:",
              dependency_name(dep).c_str());
-    printout(ERROR,"ConditionDependency","\t\t%s", e.what());
+    printout(ERROR,"DependencyHandler","\t\t%s", e.what());
   }
   catch(...)   {
-    printout(ERROR,"ConditionDependency",
+    printout(ERROR,"DependencyHandler",
              "+++ UNKNOWN exception while creating dependent Condition %s.",
              dependency_name(dep).c_str());
   }
   m_pool.print("*");
-  except("ConditionDependency",
+  except("DependencyHandler",
          "++ Exception while creating dependent Condition %s.",
          dependency_name(dep).c_str());
 }
diff --git a/DDCore/include/DD4hep/ConditionDerived.h b/DDCore/include/DD4hep/ConditionDerived.h
index a0818bb6c..fda5de81a 100644
--- a/DDCore/include/DD4hep/ConditionDerived.h
+++ b/DDCore/include/DD4hep/ConditionDerived.h
@@ -78,6 +78,10 @@ namespace dd4hep {
       virtual Condition get(Condition::key_type key) = 0;
       /// Interface to access conditions by hash value
       virtual Condition get(Condition::key_type key, bool throw_if_not) = 0;
+      /// Interface to access conditions by hash value
+      virtual Condition get(Condition::key_type key,
+                            const ConditionDependency* dependency,
+                            bool throw_if_not) = 0;
       /// Interface to access conditions by hash value of the DetElement (only valid at resolve!)
       virtual std::vector<Condition> get(DetElement de) = 0;
       /// Interface to access conditions by hash value of the DetElement (only valid at resolve!)
@@ -389,7 +393,7 @@ namespace dd4hep {
     /// Access to dependency keys
     inline const ConditionKey&
     ConditionUpdateContext::key(size_t which)  const  {
-      return dependency->dependencies[which];
+      return dependency->dependencies.at(which);
     }
 
     /// Access of other conditions data from the resolver
diff --git a/DDCore/include/DD4hep/Conditions.h b/DDCore/include/DD4hep/Conditions.h
index 86acba07f..624cce177 100644
--- a/DDCore/include/DD4hep/Conditions.h
+++ b/DDCore/include/DD4hep/Conditions.h
@@ -233,6 +233,9 @@ namespace dd4hep {
     template <typename T> T& as();
     /// Generic getter (const version). Resolves polymorph types. It is mandatory that the datatype is polymorph!
     template <typename T> const T& as() const;
+
+    /// Allow to trace condition names from keys for debugging
+    static int haveInventory(int value = -1);
   };
 
   /// Initializing constructor
@@ -490,6 +493,52 @@ namespace dd4hep {
 
   // Utility type definitions
   typedef std::vector<Condition>          RangeConditions;
+
+  /// Conditions internal namespace
+  namespace detail  {
+    /// Setup conditions item name inventory for debugging
+    /** Populate a conditions item name inventory to ease debugging
+     *  missing dependencies for derived conditions, which otherwise is
+     *  difficult in optimized mode where all string values are suppressed.
+     *
+     *  Note: the inventory gets populated while creating item dependencies etc.
+     *  Enabling afterwards has no effect.
+     *
+     *  value < 0  Return current value
+     *  value = 0  Disable inventory for performance issues
+     *  value > 0  Enable inventory population
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_CONDITIONS
+     */
+    int have_condition_item_inventory(int value = -1);
+
+    
+    /// Resolve key from conditions item name inventory for debugging
+    /** The functionhave_condition_item_inventory must be called
+     *  before items get populated to fill the inventory.....
+     *
+     *  key: conditions item key
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_CONDITIONS
+     */
+    std::string get_condition_item_name(Condition::itemkey_type key);
+
+    /// Resolve key from conditions item name inventory for debugging
+    /** The functionhave_condition_item_inventory must be called
+     *  before items get populated to fill the inventory.....
+     *
+     *  key: full condition item hash
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_CONDITIONS
+     */
+    std::string get_condition_item_name(Condition::key_type key);
+  }
   
 }          /* End namespace dd4hep                   */
 #endif // DD4HEP_CONDITIONS_H
diff --git a/DDCore/src/ConditionDerived.cpp b/DDCore/src/ConditionDerived.cpp
index 59b877205..1ebd6c2ba 100644
--- a/DDCore/src/ConditionDerived.cpp
+++ b/DDCore/src/ConditionDerived.cpp
@@ -49,7 +49,7 @@ std::vector<Condition> ConditionUpdateContext::getByItem(Condition::itemkey_type
 
 /// Access to condition object by dependency key
 Condition ConditionUpdateContext::condition(const ConditionKey& key_value)  const  {
-  Condition c = resolver->get(key_value);
+  Condition c = this->resolver->get(key_value, this->dependency, true);
   if ( c.isValid() )  {
     /// Update result IOV according by and'ing the new iov structure
     iov->iov_intersection(c.iov());
diff --git a/DDCore/src/Conditions.cpp b/DDCore/src/Conditions.cpp
index d7a96453d..93d694a1f 100644
--- a/DDCore/src/Conditions.cpp
+++ b/DDCore/src/Conditions.cpp
@@ -23,6 +23,45 @@
 using namespace std;
 using namespace dd4hep;
 
+namespace {
+  int s_have_inventory = 0;
+  struct KeyTracer    {
+    map<Condition::itemkey_type,string> item_names;
+    mutex lock;
+    void add(Condition::itemkey_type key,const string& item)   {
+      if ( s_have_inventory > 0 )   {
+        std::lock_guard<mutex> protect(lock);
+        item_names.emplace(key, item);
+      }
+    }
+    std::string get(Condition::itemkey_type key)    const    {
+      auto i = item_names.find(key);
+      if( i != item_names.end() )  {
+        return (*i).second;
+      }
+      char text[32];
+      ::snprintf(text,sizeof(text),"%08X",key);
+      return text;
+    }
+  } s_key_tracer;
+}
+
+/// Setup conditions item name inventory for debugging
+int dd4hep::detail::have_condition_item_inventory(int value)     {
+  if ( value >= 0 )   {
+    s_have_inventory = value;
+  }
+  return s_have_inventory;
+}
+
+std::string dd4hep::detail::get_condition_item_name(Condition::key_type key)    {
+  return s_key_tracer.get(ConditionKey::KeyMaker(key).values.item_key);
+}
+
+std::string dd4hep::detail::get_condition_item_name(Condition::itemkey_type key)    {
+  return s_key_tracer.get(key);
+}
+
 /// Initializing constructor for a pure, undecorated conditions object
 Condition::Condition(key_type hash_key) : Handle<Object>()
 {
@@ -36,7 +75,7 @@ Condition::Condition(key_type hash_key) : Handle<Object>()
 }
 
 /// Initializing constructor for a pure, undecorated conditions object
-Condition::Condition(const std::string& nam, const std::string& typ) : Handle<Object>()
+Condition::Condition(const string& nam, const string& typ) : Handle<Object>()
 {
   Object* o = new Object();
   assign(o,nam,typ);
@@ -181,8 +220,10 @@ ConditionsSelect::~ConditionsSelect()   {
 }
 
 /// Constructor from string
-ConditionKey::KeyMaker::KeyMaker(DetElement detector, const std::string& value)   {
-  hash = KeyMaker(detector.key(), detail::hash32(value)).hash;
+ConditionKey::KeyMaker::KeyMaker(DetElement detector, const string& value)   {
+  KeyMaker m(detector.key(), detail::hash32(value));
+  hash = m.hash;
+  s_key_tracer.add(m.values.item_key, value);
 }
 
 /// Constructor from detector element and item sub-key
@@ -191,13 +232,17 @@ ConditionKey::KeyMaker::KeyMaker(DetElement detector, Condition::itemkey_type it
 }
 
 /// Constructor from string
-ConditionKey::KeyMaker::KeyMaker(Condition::detkey_type det, const std::string& value)   {
-  hash = KeyMaker(det, detail::hash32(value)).hash;
+ConditionKey::KeyMaker::KeyMaker(Condition::detkey_type det_key, const string& value)   {
+  KeyMaker m(det_key, detail::hash32(value));
+  hash = m.hash;
+  s_key_tracer.add(m.values.item_key, value);
 }
 
 /// Constructor from string
 ConditionKey::ConditionKey(DetElement detector, const string& value)  {
-  hash = KeyMaker(detector,value).hash;
+  KeyMaker m(detector.key(), value);
+  hash = m.hash;
+  s_key_tracer.add(m.values.item_key, value);
 #ifdef DD4HEP_CONDITIONS_HAVE_NAME
   name = detector.path()+"#"+value;
 #endif
@@ -205,7 +250,9 @@ ConditionKey::ConditionKey(DetElement detector, const string& value)  {
 
 /// Constructor from detector element key and item sub-key
 ConditionKey::ConditionKey(Condition::detkey_type det_key, const string& value)    {
-  hash = KeyMaker(det_key,value).hash;
+  KeyMaker m(det_key, value);
+  s_key_tracer.add(m.values.item_key, value);
+  hash = m.hash;
 #ifdef DD4HEP_CONDITIONS_HAVE_NAME
   char text[32];
   ::snprintf(text,sizeof(text),"%08X#",det_key);
@@ -225,22 +272,30 @@ ConditionKey::ConditionKey(DetElement detector, Condition::itemkey_type item_key
 
 /// Hash code generation from input string
 Condition::key_type ConditionKey::hashCode(DetElement detector, const char* value)  {
-  return KeyMaker(detector.key(), value).hash;
+  KeyMaker m(detector.key(), value);
+  s_key_tracer.add(m.values.item_key, value);
+  return m.hash;
 }
 
 /// Hash code generation from input string
 Condition::key_type ConditionKey::hashCode(DetElement detector, const string& value)  {
-  return KeyMaker(detector, value).hash;
+  KeyMaker m(detector.key(), value);
+  s_key_tracer.add(m.values.item_key, value);
+  return m.hash;
 }
 
 /// 32 bit hashcode of the item
 Condition::itemkey_type ConditionKey::itemCode(const char* value)  {
-  return detail::hash32(value);
+  Condition::itemkey_type code = detail::hash32(value);
+  s_key_tracer.add(code, value);
+  return code;
 }
 
 /// 32 bit hashcode of the item
-Condition::itemkey_type ConditionKey::itemCode(const std::string& value)   {
-  return detail::hash32(value);
+Condition::itemkey_type ConditionKey::itemCode(const string& value)   {
+  Condition::itemkey_type code = detail::hash32(value);
+  s_key_tracer.add(code, value);
+  return code;
 }
 
 /// Conversion to string
diff --git a/examples/Conditions/CMakeLists.txt b/examples/Conditions/CMakeLists.txt
index 114368481..41bec538c 100644
--- a/examples/Conditions/CMakeLists.txt
+++ b/examples/Conditions/CMakeLists.txt
@@ -134,7 +134,7 @@ dd4hep_add_test_reg( Conditions_Telescope_root_load_usr
   REGEX_FAIL " ERROR ;EXCEPTION;Exception"
   )
 #
-#---Testing: Save conditions to ROOT file
+#---Testing: Load conditions from ROOT file
 dd4hep_add_test_reg( Conditions_Telescope_root_load_pool
   COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_Conditions.sh"
   EXEC_ARGS  geoPluginRun -print WARNING -destroy -plugin DD4hep_ConditionExample_load
@@ -145,6 +145,14 @@ dd4hep_add_test_reg( Conditions_Telescope_root_load_pool
   REGEX_FAIL " ERROR ;EXCEPTION;Exception"
   )
 #
+#---Testing: Attempt to build unresolved conditions object
+dd4hep_add_test_reg( Conditions_Telescope_unresolved
+  COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_Conditions.sh"
+  EXEC_ARGS  geoPluginRun  -destroy -plugin DD4hep_ConditionExample_populate
+      -input file:${CMAKE_INSTALL_PREFIX}/examples/AlignDet/compact/Telescope.xml -iovs 1 -extend 100
+  REGEX_PASS "Condition: /world/Telescope/module_6#Unresolved_dependency dependent on missing condition: /world/Telescope#unresolved_data"
+  )
+#
 #---Testing: Simple stress: Load CLICSiD geometry and have multiple runs on IOVs
 dd4hep_add_test_reg( Conditions_CLICSiD_stress_LONGTEST
   COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_Conditions.sh"
diff --git a/examples/Conditions/src/ConditionExampleObjects.cpp b/examples/Conditions/src/ConditionExampleObjects.cpp
index bf67f244a..df6862d34 100644
--- a/examples/Conditions/src/ConditionExampleObjects.cpp
+++ b/examples/Conditions/src/ConditionExampleObjects.cpp
@@ -54,6 +54,27 @@ void ConditionNonDefaultCtorUpdate1::resolve(Condition target, ConditionUpdateCo
   data.set(cond0.get<int>());
 }
 
+/// Interface to client Callback in order to update the condition
+Condition ConditionUpdateUnresolved::operator()(const ConditionKey& key, ConditionUpdateContext&)  {
+#ifdef DD4HEP_CONDITIONS_DEBUG
+  printout(printLevel,"ConditionUpdateUnresolved","++ Building dependent condition: %016llX  [%s]",key.hash, key.name.c_str());
+  Condition    target(key.name,"derived");
+#else
+  printout(printLevel,"ConditionUpdateUnresolved","++ Building dependent condition: %016llX",key.hash);
+  Condition    target(key.hash);
+#endif
+  target.construct<vector<int> >();
+  return target;
+}
+
+/// Interface to client Callback in order to update the condition
+void ConditionUpdateUnresolved::resolve(Condition target, ConditionUpdateContext& context)  {
+  vector<int>& data  = target.get<vector<int> >();
+  Condition    cond0 = context.condition(context.key(0));
+  data.emplace_back(cond0.get<int>());
+  data.emplace_back(cond0.get<int>()*2);
+}
+
 /// Interface to client Callback in order to update the condition
 Condition ConditionUpdate1::operator()(const ConditionKey& key, ConditionUpdateContext&)  {
 #ifdef DD4HEP_CONDITIONS_DEBUG
@@ -238,6 +259,7 @@ ConditionsDependencyCreator::ConditionsDependencyCreator(ConditionsContent& c, P
   call4  = std::shared_ptr<ConditionUpdateCall>(new ConditionUpdate4(printLevel));
   call5  = std::shared_ptr<ConditionUpdateCall>(new ConditionUpdate5(printLevel));
   call6  = std::shared_ptr<ConditionUpdateCall>(new ConditionUpdate6(printLevel));
+  callUnresolved = std::shared_ptr<ConditionUpdateCall>(new ConditionUpdateUnresolved(printLevel));
 }
 
 /// Destructor
@@ -288,13 +310,18 @@ int ConditionsDependencyCreator::operator()(DetElement de, int)  const  {
     content.addDependency(build_5.release());
   }
   if ( extended >= 3 )   {
-    DependencyBuilder build(de, key_path.item_key(), call6);
+    DependencyBuilder build_6(de, key_path.item_key(), call6);
     if ( de.parent().isValid() )
-      build.add(ConditionKey(de.parent(),"de_path"));
+      build_6.add(ConditionKey(de.parent(),"de_path"));
     for(const auto& c : de.children())   {
-      build.add(ConditionKey(c.second,"de_path"));
+      build_6.add(ConditionKey(c.second,"de_path"));
     }
-    content.addDependency(build.release());
+    content.addDependency(build_6.release());
+  }
+  if ( extended >= 4 )   {
+    DependencyBuilder build_7(de, "Unresolved_dependency", callUnresolved);
+    build_7.add(ConditionKey(de.parent(),"unresolved_data"));
+    content.addDependency(build_7.release());
   }
   if ( !persist_conditions )  {
     content.addDependency(sbuild_1.release());
diff --git a/examples/Conditions/src/ConditionExampleObjects.h b/examples/Conditions/src/ConditionExampleObjects.h
index 96a08d6fc..5763f6a6c 100644
--- a/examples/Conditions/src/ConditionExampleObjects.h
+++ b/examples/Conditions/src/ConditionExampleObjects.h
@@ -108,6 +108,26 @@ namespace dd4hep {
       virtual void resolve(Condition condition, ConditionUpdateContext& context) override  final;
     };
 
+    /// Specialized conditions update callback with an unresolvable reference
+    /**
+     *  Used by clients to update a condition.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_CONDITIONS
+     */
+    class ConditionUpdateUnresolved : public ConditionUpdateCall, public OutputLevel  {
+    public:
+      /// Initializing constructor
+      ConditionUpdateUnresolved(PrintLevel p) : OutputLevel(p) {    }
+      /// Default destructor
+      virtual ~ConditionUpdateUnresolved() = default;
+      /// Interface to client Callback in order to update the condition
+      virtual Condition operator()(const ConditionKey& key, ConditionUpdateContext& context) override  final;
+      /// Interface to client Callback in order to update the condition
+      virtual void resolve(Condition condition, ConditionUpdateContext& context) override  final;
+    };
+
     /// Specialized conditions update callback 
     /**
      *  Used by clients to update a condition.
@@ -254,7 +274,7 @@ namespace dd4hep {
       /// Content object to be filled
       ConditionsContent&   content;
       /// Three different update call types
-      std::shared_ptr<ConditionUpdateCall> scall1, call1, call2, call3, call4, call5, call6;
+      std::shared_ptr<ConditionUpdateCall> scall1, call1, call2, call3, call4, call5, call6, callUnresolved;
       /// Flag for special setup for ROOT persistency
       bool persist_conditions;
       /// Flag to indicate increased complexity
diff --git a/examples/Conditions/src/ConditionExample_load.cpp b/examples/Conditions/src/ConditionExample_load.cpp
index 4adebf84b..fbaabe7e7 100644
--- a/examples/Conditions/src/ConditionExample_load.cpp
+++ b/examples/Conditions/src/ConditionExample_load.cpp
@@ -58,7 +58,7 @@ static void help(int argc, char** argv)  {
  */
 static int condition_example (Detector& description, int argc, char** argv)  {
   string input, conditions, restore="iovpool";
-  int    num_iov = 10;
+  int    num_iov = 10, extend = 0;
   bool   arg_error = false;
   for(int i=0; i<argc && argv[i]; ++i)  {
     if ( 0 == ::strncmp("-input",argv[i],4) )
@@ -69,6 +69,8 @@ static int condition_example (Detector& description, int argc, char** argv)  {
       restore = argv[++i];
     else if ( 0 == ::strncmp("-iovs",argv[i],4) )
       num_iov = ::atol(argv[++i]);
+    else if ( 0 == ::strncmp("-extend",argv[i],4) )
+      extend = ::atol(argv[++i]);
     else
       arg_error = true;
   }
@@ -77,12 +79,14 @@ static int condition_example (Detector& description, int argc, char** argv)  {
   // First we load the geometry
   description.fromXML(input);
 
+  detail::have_condition_item_inventory(1);
+  
   /******************** Initialize the conditions manager *****************/
   ConditionsManager manager = installManager(description);
   shared_ptr<ConditionsContent> content(new ConditionsContent());
   shared_ptr<ConditionsSlice>   slice(new ConditionsSlice(manager,content));
   Scanner(ConditionsKeys(*content,INFO),description.world());
-  Scanner(ConditionsDependencyCreator(*content,DEBUG),description.world());
+  Scanner(ConditionsDependencyCreator(*content,DEBUG,false,extend),description.world());
 
   /******************** Load the conditions from file *********************/
   printout(INFO,"ConditionsExample","+  Start conditions import from ROOT object(s): %s",
diff --git a/examples/Conditions/src/ConditionExample_populate.cpp b/examples/Conditions/src/ConditionExample_populate.cpp
index b960ff7ab..0caeeaa17 100644
--- a/examples/Conditions/src/ConditionExample_populate.cpp
+++ b/examples/Conditions/src/ConditionExample_populate.cpp
@@ -42,13 +42,15 @@ using namespace dd4hep::ConditionExamples;
 static int condition_example (Detector& description, int argc, char** argv)  {
 
   string input;
-  int    num_iov = 10;
+  int    num_iov = 10, extend = 0;
   bool   arg_error = false;
   for(int i=0; i<argc && argv[i]; ++i)  {
     if ( 0 == ::strncmp("-input",argv[i],4) )
       input = argv[++i];
     else if ( 0 == ::strncmp("-iovs",argv[i],4) )
       num_iov = ::atol(argv[++i]);
+    else if ( 0 == ::strncmp("-extend",argv[i],4) )
+      extend = ::atol(argv[++i]);
     else
       arg_error = true;
   }
@@ -66,6 +68,8 @@ static int condition_example (Detector& description, int argc, char** argv)  {
   // First we load the geometry
   description.fromXML(input);
 
+  detail::have_condition_item_inventory(1);
+  
   /******************** Initialize the conditions manager *****************/
   ConditionsManager manager = installManager(description);
   const IOVType*    iov_typ = manager.registerIOVType(0,"run").second;
@@ -76,7 +80,7 @@ static int condition_example (Detector& description, int argc, char** argv)  {
   shared_ptr<ConditionsContent> content(new ConditionsContent());
   shared_ptr<ConditionsSlice>   slice(new ConditionsSlice(manager,content));
   Scanner(ConditionsKeys(*content,INFO),description.world());
-  Scanner(ConditionsDependencyCreator(*content,DEBUG),description.world());
+  Scanner(ConditionsDependencyCreator(*content,DEBUG,false,extend),description.world());
 
   /******************** Populate the conditions store *********************/
   // Have 10 run-slices [11,20] .... [91,100]
-- 
GitLab