Repository: ESMCI/cime

Issue:
create_clone cannot be called without case_setup
If create_clone is called before case.setup is called on a case bad things can happen.   
For example #1272 where the second case does not have the pio_typename set correctly.
I think that the correct action for this is to require case_setup is called on case1 before create_clone can be.  

This would require refactoring the system_tests_compare_two script so that case1 setup is done before the case clone.   


Discussion:
No this wouldn't solve the problem:  The problem is that the PIO_TYPENAME valid_values is set during the build phase depending on what supporting libraries pio found during it's build.  If create_clone is run prior to the first case being built AND --keepexe is used then the second case is never required to do a build and so the valid_values list for pio_typename is not updated.    When the case1 build is done there is no way to know that more than one case depends on the build and so no way to update clones with the correct valid_values.  

Resolving patch:
diff --git a/scripts/lib/CIME/XML/entry_id.py b/scripts/lib/CIME/XML/entry_id.py
--- a/scripts/lib/CIME/XML/entry_id.py
+++ b/scripts/lib/CIME/XML/entry_id.py
@@ -198,18 +198,22 @@ def _set_value(self, node, value, vid=None, subgroup=None, ignore_type=False):
         subgroup is ignored in the general routine and applied in specific methods
         """
         expect(subgroup is None, "Subgroup not supported")
+        str_value = self.get_valid_value_string(node, value, vid, ignore_type)
+        node.set("value", str_value)
+        return value
+
+    def get_valid_value_string(self, node, value,vid=None,  ignore_type=False):
         valid_values = self._get_valid_values(node)
         if ignore_type:
             expect(type(value) is str, "Value must be type string if ignore_type is true")
             str_value = value
-        else:
-            type_str = self._get_type_info(node)
-            str_value = convert_to_string(value, type_str, vid)
+            return str_value
+        type_str = self._get_type_info(node)
+        str_value = convert_to_string(value, type_str, vid)
+
         if valid_values is not None and not str_value.startswith('$'):
             expect(str_value in valid_values, "Did not find %s in valid values for %s: %s" % (value, vid, valid_values))
-        node.set("value", str_value)
-
-        return value
+        return str_value
 
     def set_value(self, vid, value, subgroup=None, ignore_type=False):
         """
diff --git a/scripts/lib/CIME/XML/env_base.py b/scripts/lib/CIME/XML/env_base.py
--- a/scripts/lib/CIME/XML/env_base.py
+++ b/scripts/lib/CIME/XML/env_base.py
@@ -114,10 +114,10 @@ def _set_value(self, node, value, vid=None, subgroup=None, ignore_type=False, co
 
         if iscompvar:
             attribute = {"component":component}
-            type_str = self._get_type_info(node)
-            val = self.set_element_text("value", convert_to_string(value, type_str, vid), attribute, root=node)
-            return val
-        val = EntryID._set_value(self, node, value, vid, subgroup, ignore_type)
+            str_value = self.get_valid_value_string(node, value, vid, ignore_type)
+            val = self.set_element_text("value", str_value, attribute, root=node)
+        else:
+            val = EntryID._set_value(self, node, value, vid, subgroup, ignore_type)
         return val
 
     def get_nodes_by_id(self, varid):
diff --git a/scripts/lib/CIME/case.py b/scripts/lib/CIME/case.py
--- a/scripts/lib/CIME/case.py
+++ b/scripts/lib/CIME/case.py
@@ -1007,6 +1007,10 @@ def create_clone(self, newcase, keepexe=False, mach_dir=None, project=None, cime
             orig_exeroot = self.get_value("EXEROOT")
             newcase.set_value("EXEROOT", orig_exeroot)
             newcase.set_value("BUILD_COMPLETE","TRUE")
+            orig_bld_complete = self.get_value("BUILD_COMPLETE")
+            if not orig_bld_complete:
+                logger.warn("\nWARNING: Creating a clone with --keepexe before building the original case may cause PIO_TYPENAME to be invalid in the clone")
+                logger.warn("Avoid this message by building case one before you clone.\n")
         else:
             newcase.set_value("BUILD_COMPLETE","FALSE")
 


Test patch:
diff --git a/scripts/lib/CIME/SystemTests/system_tests_compare_two.py b/scripts/lib/CIME/SystemTests/system_tests_compare_two.py
--- a/scripts/lib/CIME/SystemTests/system_tests_compare_two.py
+++ b/scripts/lib/CIME/SystemTests/system_tests_compare_two.py
@@ -144,6 +144,12 @@ def build_phase(self, sharedlib_only=False, model_only=False):
         else:
             self._activate_case1()
             self.build_indv(sharedlib_only=sharedlib_only, model_only=model_only)
+            # pio_typename may be changed during the build if the default is not a 
+            # valid value for this build, update case2 to reflect this change
+            for comp in self._case1.get_values("COMP_CLASSES"):
+                comp_pio_typename = "%s_PIO_TYPENAME"%comp
+                self._case2.set_value(comp_pio_typename, self._case1.get_value(comp_pio_typename))
+
             # The following is needed when _case_two_setup has a case_setup call
             # despite sharing the build (e.g., to change NTHRDS)
             self._case2.set_value("BUILD_COMPLETE",True)