Repository: ESMCI/cime

Issue:
cime5.0.9 does not correctly use PES_PER_NODE when set in config_pes.xml
Although the value is set correctly in the case, the translation of NTASKS and ROOTPE from negative values (number of nodes) is using the default value instead of the one in config_pes.xml

Note that this is only a problem when you attempt to modify PES_PER_NODE in config_pes.xml 



Discussion:

Resolving patch:
diff --git a/utils/python/CIME/XML/env_mach_pes.py b/utils/python/CIME/XML/env_mach_pes.py
--- a/utils/python/CIME/XML/env_mach_pes.py
+++ b/utils/python/CIME/XML/env_mach_pes.py
@@ -15,28 +15,41 @@ def __init__(self, case_root=None, infile="env_mach_pes.xml"):
         """
         EnvBase.__init__(self, case_root, infile)
 
-    def get_value(self, vid, attribute=None, resolved=True, subgroup=None):
+    def get_value(self, vid, attribute=None, resolved=True, subgroup=None, pes_per_node=None): # pylint: disable=arguments-differ
         value = EnvBase.get_value(self, vid, attribute, resolved, subgroup)
-        if "NTASKS" in vid and value < 0:
-            value = -1*value*self.get_value("PES_PER_NODE")
-        if "NTHRDS" in vid and value < 0:
-            value = -1*value*self.get_value("PES_PER_NODE")
-        if "ROOTPE" in vid and value < 0:
-            value = -1*value*self.get_value("PES_PER_NODE")
+        if "NTASKS" in vid or "ROOTPE" in vid and pes_per_node is None:
+            pes_per_node = self.get_value("PES_PER_NODE")
+
+            if "NTASKS" in vid and value < 0:
+                value = -1*value*pes_per_node
+            if "ROOTPE" in vid and value < 0:
+                value = -1*value*pes_per_node
         return value
-    #
-    # We need a set value until we full transition from perl
-    #
 
-    def _set_value(self, node, value, vid=None, subgroup=None, ignore_type=False):
+    def set_value(self, vid, value, subgroup=None, ignore_type=False, pes_per_node=None): # pylint: disable=arguments-differ
+        """
+        Set the value of an entry-id field to value
+        Returns the value or None if not found
+        subgroup is ignored in the general routine and applied in specific methods
+        """
+        val = None
+        node = self.get_optional_node("entry", {"id":vid})
+        if node is not None:
+            val = self._set_value(node, value, vid, subgroup, ignore_type, pes_per_node=pes_per_node)
+        return val
+
+
+
+    def _set_value(self, node, value, vid=None, subgroup=None, ignore_type=False, pes_per_node=None): # pylint: disable=arguments-differ
         if vid is None:
             vid = node.get("id")
 
+        if "NTASKS" in vid or "ROOTPE" in vid and pes_per_node is None:
+            pes_per_node = self.get_value("PES_PER_NODE")
+
         if "NTASKS" in vid and value < 0:
-            value = -1*value*self.get_value("PES_PER_NODE")
-        if "NTHRDS" in vid and value < 0:
-            value = -1*value*self.get_value("PES_PER_NODE")
+            value = -1*value*pes_per_node
         if "ROOTPE" in vid and value < 0:
-            value = -1*value*self.get_value("PES_PER_NODE")
+            value = -1*value*pes_per_node
         val = EnvBase._set_value(self, node, value, vid, subgroup, ignore_type)
         return val
diff --git a/utils/python/CIME/case.py b/utils/python/CIME/case.py
--- a/utils/python/CIME/case.py
+++ b/utils/python/CIME/case.py
@@ -564,20 +564,22 @@ def configure(self, compset_name, grid_name, machine_name=None,
 
         mach_pes_obj = self.get_env("mach_pes")
         totaltasks = {}
+        # Since other items may include PES_PER_NODE we need to do this first
+        # we can get rid of this code when all of the perl is removed
+        for key, value in other.items():
+            self.set_value(key, value)
+        pes_per_node = self.get_value("PES_PER_NODE")
         for key, value in pes_ntasks.items():
             totaltasks[key[-3:]] = int(value)
-            mach_pes_obj.set_value(key,int(value))
+            mach_pes_obj.set_value(key,int(value), pes_per_node=pes_per_node)
         for key, value in pes_rootpe.items():
             totaltasks[key[-3:]] += int(value)
-            mach_pes_obj.set_value(key,int(value))
+            mach_pes_obj.set_value(key,int(value), pes_per_node=pes_per_node)
         for key, value in pes_nthrds.items():
             totaltasks[key[-3:]] *= int(value)
-            mach_pes_obj.set_value(key,int(value))
-        for key, value in other.items():
-            self.set_value(key, value)
+            mach_pes_obj.set_value(key,int(value), pes_per_node=pes_per_node)
 
         maxval = 1
-        pes_per_node = mach_pes_obj.get_value("PES_PER_NODE")
         for key, val in totaltasks.items():
             if val < 0:
                 val = -1*val*pes_per_node


Test patch: