From d13cb4bbf2f4229ff44a9e72f0d840aa6dcf0f0e Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Sat, 9 Jul 2022 16:18:39 +0200
Subject: [PATCH] Add Conditions any tests

---
 DDCore/include/DD4hep/ConditionAny.h          |  25 +++-
 DDCore/include/DD4hep/Conditions.h            |   3 +-
 .../include/DD4hep/detail/DetectorInterna.h   |   8 --
 DDCore/src/ConditionAny.cpp                   |  66 +++++++---
 doc/usermanuals/DD4hep/chapters/basics.tex    |  35 ++++-
 doc/usermanuals/DD4hep/references.bib         |   9 ++
 examples/Conditions/CMakeLists.txt            |  17 +++
 .../src/ConditionAnyExampleObjects.cpp        | 120 +++++++++++++++++-
 .../src/ConditionAnyExampleObjects.h          |  42 +++++-
 .../src/ConditionExampleObjects.cpp           |   1 -
 .../Conditions/src/Conditions_any_basic.cpp   |   2 +
 11 files changed, 289 insertions(+), 39 deletions(-)

diff --git a/DDCore/include/DD4hep/ConditionAny.h b/DDCore/include/DD4hep/ConditionAny.h
index 093fd185b..c95b49469 100644
--- a/DDCore/include/DD4hep/ConditionAny.h
+++ b/DDCore/include/DD4hep/ConditionAny.h
@@ -10,8 +10,8 @@
 // Author     : M.Frank
 //
 //==========================================================================
-#ifndef DD4HEP_CONDITIONSANY_H
-#define DD4HEP_CONDITIONSANY_H
+#ifndef DD4HEP_CONDITIONANY_H
+#define DD4HEP_CONDITIONANY_H
 
 // Framework include files
 #include "DD4hep/Conditions.h"
@@ -42,11 +42,13 @@ namespace dd4hep {
   class ConditionAny : public Handle<detail::ConditionObject> {
   public:
     /// Forward definition of the key type
-    using key_type = Condition::key_type;
+    using key_type     = Condition::key_type;
     /// High part of the key identifies the detector element
-    using detkey_type = Condition::detkey_type;
+    using detkey_type  = Condition::detkey_type;
     /// Low part of the key identifies the item identifier
     using itemkey_type = Condition::itemkey_type;
+    /// Forward definition of the object properties
+    using mask_type    = Condition::mask_type;
 
   private:
     /// Verify that underlying data are either invalid of contain an instance of std::any.
@@ -104,15 +106,26 @@ namespace dd4hep {
     /// Item part of the identifier
     itemkey_type item_key()  const;
 
+    /// Flag operations: Get condition flags
+    mask_type flags()  const;
+    /// Flag operations: Set a conditons flag
+    void setFlag(mask_type option);
+    /// Flag operations: UN-Set a conditons flag
+    void unFlag(mask_type option);
+    /// Flag operations: Test for a given a conditons flag
+    bool testFlag(mask_type option) const;
+
     /// Generic getter. Specify the exact type, not a polymorph type
     std::any& get();
     /// Generic getter (const version). Specify the exact type, not a polymorph type
     const std::any& get() const;
 
-    /// Access to the type information
-    const std::type_info& any_type() const;
     /// Checks whether the object contains a value
     bool has_value()   const;
+    /// Access to the type information
+    const std::type_info& any_type() const;
+    /// Access to the type information as string
+    const std::string     any_type_name() const;
     /// Access the contained object inside std::any
     template <typename T> T& as();
     /// Access the contained object inside std::any
diff --git a/DDCore/include/DD4hep/Conditions.h b/DDCore/include/DD4hep/Conditions.h
index 624cce177..bc9d77f0a 100644
--- a/DDCore/include/DD4hep/Conditions.h
+++ b/DDCore/include/DD4hep/Conditions.h
@@ -178,10 +178,9 @@ namespace dd4hep {
     itemkey_type item_key()  const;
 
     /** Direct data items in string form */
+#if defined(DD4HEP_CONDITIONS_DEBUG) || !defined(DD4HEP_MINIMAL_CONDITIONS)
     /// Access the type field of the condition
     const std::string& type()  const;
-
-#if defined(DD4HEP_CONDITIONS_DEBUG) || !defined(DD4HEP_MINIMAL_CONDITIONS)
     /// Access the value field of the condition as a string
     const std::string& value()  const;
     /// Access the comment field of the condition
diff --git a/DDCore/include/DD4hep/detail/DetectorInterna.h b/DDCore/include/DD4hep/detail/DetectorInterna.h
index 56d4ca242..2086c885a 100644
--- a/DDCore/include/DD4hep/detail/DetectorInterna.h
+++ b/DDCore/include/DD4hep/detail/DetectorInterna.h
@@ -142,14 +142,6 @@ namespace dd4hep {
     Ref_t               global_alignment;
     //@}
 
-#if 0      
-    // To be removed!
-    /// Alignment entries for lower level volumes, which are NOT attached to daughter DetElements
-    std::vector<Alignment> volume_alignments;
-    /// Alignment entries for lower level volumes, which are NOT attached to daughter DetElements
-    std::vector<Alignment> volume_surveys;
-#endif
-
   private:
     friend class VolumeManager_Populator;
 
diff --git a/DDCore/src/ConditionAny.cpp b/DDCore/src/ConditionAny.cpp
index 30487f096..14ae22a9c 100644
--- a/DDCore/src/ConditionAny.cpp
+++ b/DDCore/src/ConditionAny.cpp
@@ -56,13 +56,14 @@ ConditionAny::ConditionAny(const string& nam, const string& typ) : Handle<Object
 void ConditionAny::use_data(detail::ConditionObject* obj)   {
   if ( obj )   {
     if ( !obj->data.grammar )   {
-      except("ConditionAny","+++ Cannot assign unbound conditions data to handle. [Invalid operation]");
+      except("ConditionAny",
+	     "+++ Cannot assign unbound conditions data to handle. [Invalid operation]");
     }
     if ( obj->data.grammar != any_grammar() )   {
       except("ConditionAny",
 	     "+++ Cannot assign data of type " +
 	     obj->data.grammar->type_name() +
-	     " to std::any. [Invalid operation]");
+	     " to handle holding std::any. [Invalid operation]");
     }
   }
   this->m_element = obj;
@@ -93,14 +94,42 @@ ConditionAny::itemkey_type ConditionAny::item_key()  const   {
   return ConditionKey::KeyMaker(access()->hash).values.item_key;
 }
 
+/// Flag operations: Get flags
+ConditionAny::mask_type ConditionAny::flags()  const    {
+  return access()->flags;
+}
+
+/// Flag operations: Set a conditons flag
+void ConditionAny::setFlag(mask_type option)   {
+  access()->setFlag(option);
+}
+
+/// Flag operations: UN-Set a conditons flag
+void ConditionAny::unFlag(mask_type option)   {
+  access()->unFlag(option);
+}
+
+/// Flag operations: Test for a given a conditons flag
+bool ConditionAny::testFlag(mask_type option) const {
+  return access()->testFlag(option);
+}
+
 /// Generic getter. Specify the exact type, not a polymorph type
 std::any& ConditionAny::get() {
-  return this->access()->data.get<std::any>();
+  auto& o = this->access()->data;
+  if ( o.grammar && (o.grammar == any_grammar()) )   {
+    return *(std::any*)o.ptr();
+  }
+  throw std::bad_cast();
 }
 
 /// Generic getter (const version). Specify the exact type, not a polymorph type
 const std::any& ConditionAny::get() const {
-  return this->access()->data.get<std::any>();
+  const auto& o = this->access()->data;
+  if ( o.grammar && (o.grammar == any_grammar()) )   {
+    return *(std::any*)o.ptr();
+  }
+  throw std::bad_cast();
 }
   
 /// Checks whether the object contains a value
@@ -110,19 +139,20 @@ bool ConditionAny::has_value()   const   {
 
 /// Access to the type information
 const type_info& ConditionAny::any_type() const   {
-  return this->get().type();
-}
-
-#if 0
-/// Access to the grammar type
-const dd4hep::BasicGrammar& ConditionAny::descriptor() const   {
-  const BasicGrammar* grammar = access()->data.grammar;
-  if ( !grammar ) {
-    invalidHandleError<ConditionAny>();
-    // This code is never reached, since function above throws exception!
-    // Needed to satisfay CppCheck
-    throw runtime_error("Null pointer in Grammar object");
+  const auto* o = this->ptr();
+  if ( o && o->data.grammar && (o->data.grammar == any_grammar()) )   {
+    const std::any* a = (const std::any*)o->data.ptr();
+    return a->type();
+  }
+  return typeid(void);
+}
+
+/// Access to the type information as string
+const std::string  ConditionAny::any_type_name() const   {
+  const auto* o = this->ptr();
+  if ( o && o->data.grammar && (o->data.grammar == any_grammar()) )   {
+    const std::any* a = (const std::any*)o->data.ptr();
+    return typeName(a->type());
   }
-  return *grammar;
+  return typeName(typeid(void));
 }
-#endif
diff --git a/doc/usermanuals/DD4hep/chapters/basics.tex b/doc/usermanuals/DD4hep/chapters/basics.tex
index 981bd2c5d..1066f3a09 100644
--- a/doc/usermanuals/DD4hep/chapters/basics.tex
+++ b/doc/usermanuals/DD4hep/chapters/basics.tex
@@ -129,7 +129,40 @@ NEEDS ADDITIONAL CLARIFICATION
 \section{DD4hep Handles}
 \label{sec:dd4hep-user-manual-handles}
 
-Handles are the means of clients accessing DD4hep detector description data. The data itself is not held by the handle itself, the handle only allows the access to the data typically held by a pointer. The template handle class (see for details the \href{https://dd4hep.web.cern.ch/dd4hep/reference/classdd4hep_1_1Handle.html}{\texttt{Handle.h}} header file) allows type safe assignment of other unrelated handles and supports standard data conversions to the underlying object in form of the raw pointer, a reference etc. The template handle class:
+Handles are the means of clients accessing DD4hep detector description data. Handles are an intrinsic ingredient to DD4hep meant to also support various views onto relatively simple structures. The data itself is not held by the handle itself, the handle only allows the access to the data typically held by a pointer.
+
+DD4hep internally prefers to expose data structures which are as simple as possible while at the same time being as complicated as necessary. These objects are then manipulated by Handles, smart pointer objects with sometimes specialized functionality depending on the contained data type. It is seen as a clear advantage that these smart pointer objects to not impose any restrictions on the underlying object except the accessibility of the contained data.
+
+The freedom to attach handle based facades to virtually any data item allows for optimized data views depending on the application type, such as special views for reconstruction, simulation, tracking, etc.
+
+For the importance of the functionality of this issue we repeat here the functionality described in~\ref{subsect:extesions-and-views} which is achieved by specializing the basic templated handle implementation:
+\begin{description}
+\item [Convenience Views] provide higher level abstractions and internally group complex calculations. Such views simplify the life of the end-users.
+\item [Optimization Views] allows end-users extend the data of the common detector detector element and store precomputed results, which would be expensive to obtain repeatedly.
+\item [Compatibility Views] help to ensure smooth periods of software redesign. During the life-time of the experiment often various software constructs are for functional reasons re-designed and re-engineered. Compatibility Views either adapt new data designs to existing application code or expose new behavior based on existing data.
+\end{description}
+
+Since the lifetime of DD4hep objects is mostly defined by the lifetime of the {\texttt{dd4hep::Detector}} object (in turn defining the lifetime of ROOT's {\texttt{TGeoManager}}) or for the conditions is managed by the ConditionsManager object under the steering of the embeding framework there is also no memory model imposed which would only lead to performance penalties. Hence, handles can be applied to data structures independent of their origin:
+\begin{itemize}
+\item allocated from the stack
+\item allocated from the heap
+\item allocated as single objects of in bulk by array constructors.
+\end{itemize}
+
+There is no restriction to allow toolkit users to extend any of the internally used DD4hep classes such as e.g. the {\texttt{dd4hep::DetElement}} data object {\texttt{dd4hep::detail::DetElementObject}} with their own implementation supporting further enhanced functionality both in terms of additional data and additional member functions provided the user specialized class inherits from the DD4hep provided base. Obviously such enhancements do not hold for the geometry classes provided by ROOT because here the ROOT framework internally calls its object constructors. Hence, though DD4hep internally uses templated handles to manipulate data objects, DD4hep allows for all freedom to extend any of the internally used objects and a priori no restrictions are imposed by the DD4hep framework besides the mentioned inheritance.
+
+The design approach of DD4hep to internally use handles to manipulate objects which is also offered to clients clearly has difficulties to support the Liskov substitution principle. This was a conscious decision when designing DD4hep.
+
+Frameworks which see the substitution principle for the implementation of the simple data structures mandatory for its functionality clearly limit the  benefits of the handles unless
+
+\begin{itemize}
+\item the depending frameworks provides handles which are a fully implemented facade or
+\item the depending framework use consistently the operator->() provided by all   handles to directly access the underlying object or
+\item the depending framework uses DD4hep and it is provided only internally and provide top level user code only with pointers/references to the data structures in their full object oriented glory.
+\end{itemize}
+
+The template handle class (see for details the \href{https://dd4hep.web.cern.ch/dd4hep/reference/classdd4hep_1_1Handle.html}{\texttt{Handle.h}} header file) allows type safe assignment of other unrelated handles and supports standard data conversions to the underlying object in form of the raw pointer, a reference etc.
+The template handle class:
 
 \begin{minted}[frame=single,framesep=3pt,breaklines=true,tabsize=2,linenos,fontsize=\small]{c++}
 template <typename T> class Handle {
diff --git a/doc/usermanuals/DD4hep/references.bib b/doc/usermanuals/DD4hep/references.bib
index bc1b7c4a3..358031558 100755
--- a/doc/usermanuals/DD4hep/references.bib
+++ b/doc/usermanuals/DD4hep/references.bib
@@ -119,6 +119,15 @@
     day = {16}
 }
 
+@article{Frank_et_al:2014_DDCore,
+      author         = "M. Frank et al.",
+      title          = "{DD4hep: A Detector Description Toolkit for High Energy Physics Experiments}",
+      journal        = "Journal of Physics: Conference Series",
+      volume         = "513",
+      year           = "2014",
+      pages          = "022010"
+}
+
 @article{Chytracek:2006be,
       author         = "Chytracek, R. and McCormick, J. and Pokorski, W. and
                         Santin, G.",
diff --git a/examples/Conditions/CMakeLists.txt b/examples/Conditions/CMakeLists.txt
index d5137b46d..85396422a 100644
--- a/examples/Conditions/CMakeLists.txt
+++ b/examples/Conditions/CMakeLists.txt
@@ -222,3 +222,20 @@ dd4hep_add_test_reg( Conditions_CLICSiD_root_load_cond_LONGTEST
   REGEX_PASS "\\+  Accessed a total of 1053210 conditions \\(S:947889,L:     0,C:105321,M:0\\)"
   REGEX_FAIL " ERROR ;EXCEPTION;Exception"
   )
+#
+#---Testing: Basic test using std::any as conditions payload
+dd4hep_add_test_reg( Conditions_any_basic
+  COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_Conditions.sh"
+  EXEC_ARGS  geoPluginRun -print INFO -destroy -plugin DD4hep_Conditions_any_basic
+  REGEX_PASS "Test PASSED"
+  REGEX_FAIL "Test FAILED"
+  )
+#
+#---Testing: Simple stress: Load Telescope geometry and have multiple runs on IOVs
+dd4hep_add_test_reg( Conditions_any_Telescope_populate
+  COMMAND    "${CMAKE_INSTALL_PREFIX}/bin/run_test_Conditions.sh"
+  EXEC_ARGS  geoPluginRun  -destroy -plugin DD4hep_ConditionAnyExample_populate
+      -input file:${CMAKE_INSTALL_PREFIX}/examples/AlignDet/compact/Telescope.xml -iovs 2
+  REGEX_PASS "\\+ Analyzed 1020 any object/elements"
+  REGEX_FAIL " ERROR ;EXCEPTION;Exception"
+  )
diff --git a/examples/Conditions/src/ConditionAnyExampleObjects.cpp b/examples/Conditions/src/ConditionAnyExampleObjects.cpp
index 09dcbeaa9..3d5525eb9 100644
--- a/examples/Conditions/src/ConditionAnyExampleObjects.cpp
+++ b/examples/Conditions/src/ConditionAnyExampleObjects.cpp
@@ -24,8 +24,12 @@ using cond::DependencyBuilder;
 using cond::ConditionsLoadInfo;
 
 namespace {
+  static int num_any_ingredients = 0;
   template <typename T> inline void __prt(ostream& os, const vector<T>& obj)   {
-    for(const auto& o : obj) os << o << " ";
+    for(const auto& o : obj)  {
+      os << o << " ";
+      ++num_any_ingredients;
+    }
   }
 }
 
@@ -75,12 +79,72 @@ void ConditionAnyUpdate2::resolve(Condition target, ConditionUpdateContext& cont
   vector<int>& c1 = cond1.as<vector<int> >();
   data.insert(data.end(), c1.begin(), c1.end());
 }
+
+
+/// Interface to client Callback in order to update the condition
+Condition ConditionAnyUpdate3::operator()(const ConditionKey& key, ConditionUpdateContext&)  {
+#ifdef DD4HEP_CONDITIONS_DEBUG
+  printout(printLevel,"ConditionUpdate3","++ Building dependent condition: %016llX  [%s]",key.hash, key.name.c_str());
+  return ConditionAny(key.name,"derived");
+#else
+  printout(printLevel,"ConditionUpdate3","++ Building dependent condition: %016llX",key.hash);
+  return ConditionAny(key.hash);
+#endif
+}
+
+/// Interface to client Callback in order to update the condition
+void ConditionAnyUpdate3::resolve(Condition target, ConditionUpdateContext& context)  {
+  vector<int>  data;
+  ConditionAny cond0 = context.condition(context.key(0));
+  ConditionAny cond1 = context.condition(context.key(1));
+  ConditionAny cond2 = context.condition(context.key(2));
+
+  data.push_back(cond0.as<int>());
+  data.push_back(cond0.as<int>()*2);
+  vector<int>& c1 = cond1.as<vector<int> >();
+  data.insert(data.end(), c1.begin(), c1.end());
+
+  vector<int>& c2 = cond2.as<vector<int> >();
+  data.insert(data.end(), c2.begin(), c2.end());
+  target.get<std::any>() = std::move(data);
+}
+
+/// Interface to client Callback in order to update the condition
+Condition ConditionAnyUpdate4::operator()(const ConditionKey& key, ConditionUpdateContext& context)  {
+#ifdef DD4HEP_CONDITIONS_DEBUG
+  printout(printLevel,"ConditionUpdate4","++ Building dependent condition: %016llX  [%s]",key.hash, key.name.c_str());
+  ConditionAny target(key.name,"derived", vector<int>());
+#else
+  printout(printLevel,"ConditionUpdate4","++ Building dependent condition: %016llX",key.hash);
+  ConditionAny target(key.hash, vector<int>());
+#endif
+  vector<int>& data  = target.as<std::vector<int> >();
+  ConditionAny cond3 = context.condition(context.key(0));
+  ConditionAny cond2 = context.condition(context.key(1));
+  ConditionAny cond0 = context.condition(context.key(2));
+  ConditionAny cond1 = context.condition(context.key(3));
+
+  data.push_back(cond0.as<int>());
+  data.push_back(cond0.as<int>()*2);
+  vector<int>& c1 = cond1.as<vector<int> >();
+  data.insert(data.end(), c1.begin(), c1.end());
+
+  vector<int>& c2 = cond2.as<vector<int> >();
+  data.insert(data.end(), c2.begin(), c2.end());
+
+  vector<int>& c3 = cond3.as<vector<int> >();
+  data.insert(data.end(), c3.begin(), c3.end());
+  return target;
+}
+
 /// Initializing constructor
 ConditionsAnyDependencyCreator::ConditionsAnyDependencyCreator(ConditionsContent& c, PrintLevel p, bool persist, int ex)
   : OutputLevel(p), content(c), persist_conditions(persist), extended(ex)
 {
   call1  = std::shared_ptr<ConditionUpdateCall>(new ConditionAnyUpdate1(printLevel));
   call2  = std::shared_ptr<ConditionUpdateCall>(new ConditionAnyUpdate2(printLevel));
+  call3  = std::shared_ptr<ConditionUpdateCall>(new ConditionAnyUpdate3(printLevel));
+  call4  = std::shared_ptr<ConditionUpdateCall>(new ConditionAnyUpdate4(printLevel));
 }
 
 /// Callback to process a single detector element
@@ -88,8 +152,11 @@ int ConditionsAnyDependencyCreator::operator()(DetElement de, int)  const  {
   ConditionKey      key     (de,"derived_data");
   ConditionKey      target1(de,"derived_data/derived_1");
   ConditionKey      target2(de,"derived_data/derived_2");
+  ConditionKey      target3(de,"derived_data/derived_3");
+  ConditionKey      target4(de,"derived_data/derived_4");
   DependencyBuilder build_1(de, target1.item_key(), call1);
   DependencyBuilder build_2(de, target2.item_key(), call2);
+  DependencyBuilder build_3(de, target3.item_key(), call3);
 
   // Compute the derived stuff
   build_1.add(key);
@@ -97,12 +164,33 @@ int ConditionsAnyDependencyCreator::operator()(DetElement de, int)  const  {
   build_2.add(key);
   build_2.add(target1);
   
+  
+  build_3.add(key);
+  build_3.add(target1);
+  build_3.add(target2);
+
+  if ( extended >= 1 )   {
+    DependencyBuilder build_4(de, target4.item_key(), call4);
+    build_4.add(target3);
+    build_4.add(target2);
+    build_4.add(key);
+    build_4.add(target1);
+    content.addDependency(build_4.release());
+  }
   content.addDependency(build_1.release());
   content.addDependency(build_2.release());
+  content.addDependency(build_3.release());
   printout(printLevel,"Example","++ Added derived conditions dependencies for %s",de.path().c_str());
   return 1;
 }
 
+/// Standard destructor
+ConditionsAnyDataAccess::~ConditionsAnyDataAccess()   {
+  printout(printLevel,"Example","+=========================================================================");
+  printout(printLevel,"Example","+ Analyzed %d any object/elements", num_any_ingredients);
+  printout(printLevel,"Example","+=========================================================================");
+}
+
 /// Callback to process a single detector element
 int ConditionsAnyDataAccess::operator()(DetElement de, int level)  const  {
   vector<Condition> conditions;
@@ -119,6 +207,8 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
   ConditionKey key_derived_data(de,"derived_data");
   ConditionKey key_derived1    (de,"derived_data/derived_1");
   ConditionKey key_derived2    (de,"derived_data/derived_2");
+  ConditionKey key_derived3    (de,"derived_data/derived_3");
+  ConditionKey key_derived4    (de,"derived_data/derived_4");
   ConditionKey key_path        (de,"de_path");
   int result = 0, count = 0;
 
@@ -138,6 +228,7 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(), 
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %s", cond.value<string>().c_str());
+      ++num_any_ingredients;
     }
     else if ( cond.item_key() == key_temperature.item_key() )  {
       result += int(cond.as<double>());
@@ -146,6 +237,7 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(), 
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %f", cond.as<double>());
+      ++num_any_ingredients;
     }
     else if ( cond.item_key() == key_pressure.item_key() )  {
       result += int(cond.as<double>());
@@ -154,6 +246,7 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(),
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %f", cond.as<double>());
+      ++num_any_ingredients;
     }
     else if ( cond.item_key() == key_double_table.item_key() )  {
       result += int(cond.as<vector<double> >().size());
@@ -163,6 +256,7 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(),
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %s", str.str().c_str());
+      ++num_any_ingredients;
     }
     else if ( cond.item_key() == key_int_table.item_key() )  {
       result += int(cond.as<vector<int> >().size());
@@ -172,6 +266,7 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(),
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %s", str.str().c_str());
+      ++num_any_ingredients;
     }
     else if ( cond.item_key() == key_derived_data.item_key() )  {
       result += int(cond.as<int>());
@@ -180,6 +275,7 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(),
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %d", cond.as<int>());
+      ++num_any_ingredients;
     }
     else if ( cond.item_key() == key_derived1.item_key() )  {
       result += int(cond.as<vector<int> >().size());
@@ -189,6 +285,7 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(),
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %s", str.str().c_str());
+      ++num_any_ingredients;
     }
     else if ( cond.item_key() == key_derived2.item_key() )  {
       result += int(cond.as<vector<int> >().size());
@@ -198,6 +295,27 @@ int ConditionsAnyDataAccess::accessConditions(DetElement de, const std::vector<C
 	       typeName(typeid(cond.get())).c_str(),
 	       typeName(cond.any_type()).c_str());
       printout(INFO,"accessConditions","           value: %s", str.str().c_str());
+      ++num_any_ingredients;
+    }
+    else if ( cond.item_key() == key_derived3.item_key() )  {
+      result += int(cond.as<vector<int> >().size());
+      __prt(str,cond.as<vector<int> >());
+      printout(INFO,"accessConditions","Condition: %s type: %s [%s]",
+	       key_derived3.toString().c_str(),
+	       typeName(typeid(cond.get())).c_str(),
+	       typeName(cond.any_type()).c_str());
+      printout(INFO,"accessConditions","           value: %s", str.str().c_str());
+      ++num_any_ingredients;
+    }
+    else if ( cond.item_key() == key_derived4.item_key() )  {
+      result += int(cond.as<vector<int> >().size());
+      __prt(str,cond.as<vector<int> >());
+      printout(INFO,"accessConditions","Condition: %s type: %s [%s]",
+	       key_derived4.toString().c_str(),
+	       typeName(typeid(cond.get())).c_str(),
+	       typeName(cond.any_type()).c_str());
+      printout(INFO,"accessConditions","           value: %s", str.str().c_str());
+      ++num_any_ingredients;
     }
     if ( !IOV::key_is_contained(iov.key(),cond.iov().key()) )  {
       printout(INFO,"CondAccess","++ IOV mismatch:%s <> %s",
diff --git a/examples/Conditions/src/ConditionAnyExampleObjects.h b/examples/Conditions/src/ConditionAnyExampleObjects.h
index 654bf77a1..31f6d1905 100644
--- a/examples/Conditions/src/ConditionAnyExampleObjects.h
+++ b/examples/Conditions/src/ConditionAnyExampleObjects.h
@@ -62,6 +62,44 @@ namespace dd4hep {
       virtual void resolve(Condition condition, ConditionUpdateContext& context) override  final;
     };
 
+    /// Specialized conditions update callback 
+    /**
+     *  Used by clients to update a condition.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_CONDITIONS
+     */
+    class ConditionAnyUpdate3 : public ConditionUpdateCall, public OutputLevel  {
+    public:
+      /// Initializing constructor
+      ConditionAnyUpdate3(PrintLevel p) : OutputLevel(p) {    }
+      /// Default destructor
+      virtual ~ConditionAnyUpdate3() = 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.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_CONDITIONS
+     */
+    class ConditionAnyUpdate4 : public ConditionUpdateCall, public OutputLevel  {
+    public:
+      /// Initializing constructor
+      ConditionAnyUpdate4(PrintLevel p) : OutputLevel(p) {    }
+      /// Default destructor
+      virtual ~ConditionAnyUpdate4() = default;
+      /// Interface to client Callback in order to update the condition
+      virtual Condition operator()(const ConditionKey& key, ConditionUpdateContext& context) override  final;
+    };
+    
     /// This is important, otherwise the register and forward calls won't find them!
     /**
      *  \author  M.Frank
@@ -91,7 +129,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, callUnresolved;
+      std::shared_ptr<ConditionUpdateCall> call1, call2, call3, call4;
       /// Flag for special setup for ROOT persistency
       bool persist_conditions;
       /// Flag to indicate increased complexity
@@ -155,7 +193,7 @@ namespace dd4hep {
       ConditionsAnyDataAccess(const IOV& i, ConditionsMap& m, PrintLevel l=DEBUG)
         : OutputLevel(l), iov(i), map(m) {}
       /// Destructor
-      virtual ~ConditionsAnyDataAccess() = default;
+      virtual ~ConditionsAnyDataAccess();
       /// Callback to process a single detector element
       virtual int operator()(DetElement de, int level)  const;
       /// Common call to access selected conditions
diff --git a/examples/Conditions/src/ConditionExampleObjects.cpp b/examples/Conditions/src/ConditionExampleObjects.cpp
index 5c319192b..6572c7d2d 100644
--- a/examples/Conditions/src/ConditionExampleObjects.cpp
+++ b/examples/Conditions/src/ConditionExampleObjects.cpp
@@ -121,7 +121,6 @@ void ConditionUpdate2::resolve(Condition target, ConditionUpdateContext& context
   data.insert(data.end(), c1.begin(), c1.end());
 }
 
-
 /// Interface to client Callback in order to update the condition
 Condition ConditionUpdate3::operator()(const ConditionKey& key, ConditionUpdateContext&)  {
 #ifdef DD4HEP_CONDITIONS_DEBUG
diff --git a/examples/Conditions/src/Conditions_any_basic.cpp b/examples/Conditions/src/Conditions_any_basic.cpp
index dfa09a4d0..7055450f4 100644
--- a/examples/Conditions/src/Conditions_any_basic.cpp
+++ b/examples/Conditions/src/Conditions_any_basic.cpp
@@ -95,6 +95,7 @@ static int condition_any_basic (Detector& /* description */, int /* argc */, cha
   try  {
     c1 = c2;
     cout << "Assigned:  ConditionAny = Condition(vector) . " << endl;
+    cout << "Test FAILED" << endl;
   }
   catch(const std::exception& e)   {
     cout << "Expected exception: ConditionAny = Condition(vector) : " << e.what() << endl;
@@ -118,6 +119,7 @@ static int condition_any_basic (Detector& /* description */, int /* argc */, cha
     ConditionAny c5(c2);
     cout << "Construct c5: ConditionAny( Condition(vector) ) Pointer: " 
 	 << (void*)c5.ptr() << " type:" << c5.any_type().name() << endl;
+    cout << "Test FAILED" << endl;
   }
   catch(const std::exception& e)   {
     cout << "Expected exception: Construct c5: ConditionAny( Condition(vector) ) : " << e.what() << endl;
-- 
GitLab