prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  floating point mpiprocs when running ./case.setup with python3
  I noticed that when running with python3, mpiprocs is set to be a float, i.e.,
  
  $ python3 ./case.setup # will create the following in .case.run:
  #PBS  -l select=5:ncpus=36:mpiprocs=36.0:ompthreads=1
  
  $ python2 ./case.setup # will create the following .case.run:
  #PBS  -l select=5:ncpus=36:mpiprocs=36:ompthreads=1
  
  NOTE: You'll need to rm .case.run, in between ./case.setup executions to see the difference.
  
  I haven't looked this into depth, but I bet it has to do with "true division" that comes with python3.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `scripts/lib/CIME/XML/env_mach_pes.py`
  Content:
  ```
  1 """
  2 Interface to the env_mach_pes.xml file.  This class inherits from EntryID
  3 """
  4 from CIME.XML.standard_module_setup import *
  5 from CIME.XML.env_base import EnvBase
  6 import math
  7 
  8 logger = logging.getLogger(__name__)
  9 
  10 class EnvMachPes(EnvBase):
  11 
  12     def __init__(self, case_root=None, infile="env_mach_pes.xml", components=None):
  13         """
  14         initialize an object interface to file env_mach_pes.xml in the case directory
  15         """
  16         self._components = components
  17         schema = os.path.join(get_cime_root(), "config", "xml_schemas", "env_mach_pes.xsd")
  18         EnvBase.__init__(self, case_root, infile, schema=schema)
  19 
  20     def add_comment(self, comment):
  21         if comment is not None:
  22             node = self.make_child("comment", text=comment)
  23             # make_child adds to the end of the file but we want it to follow the header
  24             # so we need to remove it and add it in the correct position
  25             self.remove_child(node)
  26             self.add_child(node, position=1)
  27 
  28     def get_value(self, vid, attribute=None, resolved=True, subgroup=None, max_mpitasks_per_node=None): # pylint: disable=arguments-differ
  29         # Special variable NINST_MAX is used to determine the number of
  30         # drivers in multi-driver mode.
  31         if vid == "NINST_MAX":
  32             value = 1
  33             for comp in self._components:
  34                 if comp != "CPL":
  35                     value = max(value, self.get_value("NINST_{}".format(comp)))
  36             return value
  37 
  38         value = EnvBase.get_value(self, vid, attribute, resolved, subgroup)
  39 
  40         if "NTASKS" in vid or "ROOTPE" in vid:
  41             if max_mpitasks_per_node is None:
  42                 max_mpitasks_per_node = self.get_value("MAX_MPITASKS_PER_NODE")
  43             if value is not None and value < 0:
  44                 value = -1*value*max_mpitasks_per_node
  45 
  46         return value
  47 
  48     def set_value(self, vid, value, subgroup=None, ignore_type=False):
  49         """
  50         Set the value of an entry-id field to value
  51         Returns the value or None if not found
  52         subgroup is ignored in the general routine and applied in specific methods
  53         """
  54         if vid == "MULTI_DRIVER" and value:
  55             ninst_max = self.get_value("NINST_MAX")
  56             for comp in self._components:
  57                 if comp == "CPL":
  58                     continue
  59                 ninst = self.get_value("NINST_{}".format(comp))
  60                 expect(ninst == ninst_max,
  61                        "All components must have the same NINST value in multi_driver mode.  NINST_{}={} shoud be {}".format(comp,ninst,ninst_max))
  62         if "NTASKS" in vid or "NTHRDS" in vid:
  63             expect(value != 0, "Cannot set NTASKS or NTHRDS to 0")
  64 
  65 
  66         return EnvBase.set_value(self, vid, value, subgroup=subgroup, ignore_type=ignore_type)
  67 
  68 
  69     def get_max_thread_count(self, comp_classes):
  70         ''' Find the maximum number of openmp threads for any component in the case '''
  71         max_threads = 1
  72         for comp in comp_classes:
  73             threads = self.get_value("NTHRDS",attribute={"compclass":comp})
  74             expect(threads is not None, "Error no thread count found for component class {}".format(comp))
  75             if threads > max_threads:
  76                 max_threads = threads
  77         return max_threads
  78 
  79     def get_total_tasks(self, comp_classes):
  80         total_tasks = 0
  81         maxinst = 1
  82         for comp in comp_classes:
  83             ntasks = self.get_value("NTASKS", attribute={"compclass":comp})
  84             rootpe = self.get_value("ROOTPE", attribute={"compclass":comp})
  85             pstrid = self.get_value("PSTRID", attribute={"compclass":comp})
  86             if comp != "CPL":
  87                 ninst = self.get_value("NINST", attribute={"compclass":comp})
  88                 maxinst = max(maxinst, ninst)
  89             tt = rootpe + (ntasks - 1) * pstrid + 1
  90             total_tasks = max(tt, total_tasks)
  91         if self.get_value("MULTI_DRIVER"):
  92             total_tasks *= maxinst
  93         return total_tasks
  94 
  95     def get_tasks_per_node(self, total_tasks, max_thread_count):
  96         expect(total_tasks > 0,"totaltasks > 0 expected, totaltasks = {}".format(total_tasks))
  97         tasks_per_node = min(self.get_value("MAX_TASKS_PER_NODE")/ max_thread_count,
  98                              self.get_value("MAX_MPITASKS_PER_NODE"), total_tasks)
  99         return tasks_per_node if tasks_per_node > 0 else 1
  100 
  101     def get_total_nodes(self, total_tasks, max_thread_count):
  102         """
  103         Return (num_active_nodes, num_spare_nodes)
  104         """
  105         tasks_per_node = self.get_tasks_per_node(total_tasks, max_thread_count)
  106         num_nodes = int(math.ceil(float(total_tasks) / tasks_per_node))
  107         return num_nodes, self.get_spare_nodes(num_nodes)
  108 
  109     def get_spare_nodes(self, num_nodes):
  110         force_spare_nodes = self.get_value("FORCE_SPARE_NODES")
  111         if force_spare_nodes != -999:
  112             return force_spare_nodes
  113 
  114         if self.get_value("ALLOCATE_SPARE_NODES"):
  115             ten_pct = int(math.ceil(float(num_nodes) * 0.1))
  116             if ten_pct < 1:
  117                 return 1 # Always provide at lease one spare node
  118             elif ten_pct > 10:
  119                 return 10 # Never provide more than 10 spare nodes
  120             else:
  121                 return ten_pct
  122         else:
  123             return 0
  124
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/scripts/lib/CIME/XML/env_mach_pes.py b/scripts/lib/CIME/XML/env_mach_pes.py
  --- a/scripts/lib/CIME/XML/env_mach_pes.py
  +++ b/scripts/lib/CIME/XML/env_mach_pes.py
  @@ -94,7 +94,7 @@
   
       def get_tasks_per_node(self, total_tasks, max_thread_count):
           expect(total_tasks > 0,"totaltasks > 0 expected, totaltasks = {}".format(total_tasks))
  -        tasks_per_node = min(self.get_value("MAX_TASKS_PER_NODE")/ max_thread_count,
  +        tasks_per_node = min(self.get_value("MAX_TASKS_PER_NODE")// max_thread_count,
                                self.get_value("MAX_MPITASKS_PER_NODE"), total_tasks)
           return tasks_per_node if tasks_per_node > 0 else 1
  
verification_info: {"golden_diff": "diff --git a/scripts/lib/CIME/XML/env_mach_pes.py b/scripts/lib/CIME/XML/env_mach_pes.py\n--- a/scripts/lib/CIME/XML/env_mach_pes.py\n+++ b/scripts/lib/CIME/XML/env_mach_pes.py\n@@ -94,7 +94,7 @@\n \n     def get_tasks_per_node(self, total_tasks, max_thread_count):\n         expect(total_tasks > 0,\"totaltasks > 0 expected, totaltasks = {}\".format(total_tasks))\n-        tasks_per_node = min(self.get_value(\"MAX_TASKS_PER_NODE\")/ max_thread_count,\n+        tasks_per_node = min(self.get_value(\"MAX_TASKS_PER_NODE\")// max_thread_count,\n                              self.get_value(\"MAX_MPITASKS_PER_NODE\"), total_tasks)\n         return tasks_per_node if tasks_per_node > 0 else 1\n", "issue": "floating point mpiprocs when running ./case.setup with python3\nI noticed that when running with python3, mpiprocs is set to be a float, i.e.,\r\n\r\n$ python3 ./case.setup # will create the following in .case.run:\r\n#PBS  -l select=5:ncpus=36:mpiprocs=36.0:ompthreads=1\r\n\r\n$ python2 ./case.setup # will create the following .case.run:\r\n#PBS  -l select=5:ncpus=36:mpiprocs=36:ompthreads=1\r\n\r\nNOTE: You'll need to rm .case.run, in between ./case.setup executions to see the difference.\r\n\r\nI haven't looked this into depth, but I bet it has to do with \"true division\" that comes with python3.\n", "before_files": [{"content": "\"\"\"\nInterface to the env_mach_pes.xml file.  This class inherits from EntryID\n\"\"\"\nfrom CIME.XML.standard_module_setup import *\nfrom CIME.XML.env_base import EnvBase\nimport math\n\nlogger = logging.getLogger(__name__)\n\nclass EnvMachPes(EnvBase):\n\n    def __init__(self, case_root=None, infile=\"env_mach_pes.xml\", components=None):\n        \"\"\"\n        initialize an object interface to file env_mach_pes.xml in the case directory\n        \"\"\"\n        self._components = components\n        schema = os.path.join(get_cime_root(), \"config\", \"xml_schemas\", \"env_mach_pes.xsd\")\n        EnvBase.__init__(self, case_root, infile, schema=schema)\n\n    def add_comment(self, comment):\n        if comment is not None:\n            node = self.make_child(\"comment\", text=comment)\n            # make_child adds to the end of the file but we want it to follow the header\n            # so we need to remove it and add it in the correct position\n            self.remove_child(node)\n            self.add_child(node, position=1)\n\n    def get_value(self, vid, attribute=None, resolved=True, subgroup=None, max_mpitasks_per_node=None): # pylint: disable=arguments-differ\n        # Special variable NINST_MAX is used to determine the number of\n        # drivers in multi-driver mode.\n        if vid == \"NINST_MAX\":\n            value = 1\n            for comp in self._components:\n                if comp != \"CPL\":\n                    value = max(value, self.get_value(\"NINST_{}\".format(comp)))\n            return value\n\n        value = EnvBase.get_value(self, vid, attribute, resolved, subgroup)\n\n        if \"NTASKS\" in vid or \"ROOTPE\" in vid:\n            if max_mpitasks_per_node is None:\n                max_mpitasks_per_node = self.get_value(\"MAX_MPITASKS_PER_NODE\")\n            if value is not None and value < 0:\n                value = -1*value*max_mpitasks_per_node\n\n        return value\n\n    def set_value(self, vid, value, subgroup=None, ignore_type=False):\n        \"\"\"\n        Set the value of an entry-id field to value\n        Returns the value or None if not found\n        subgroup is ignored in the general routine and applied in specific methods\n        \"\"\"\n        if vid == \"MULTI_DRIVER\" and value:\n            ninst_max = self.get_value(\"NINST_MAX\")\n            for comp in self._components:\n                if comp == \"CPL\":\n                    continue\n                ninst = self.get_value(\"NINST_{}\".format(comp))\n                expect(ninst == ninst_max,\n                       \"All components must have the same NINST value in multi_driver mode.  NINST_{}={} shoud be {}\".format(comp,ninst,ninst_max))\n        if \"NTASKS\" in vid or \"NTHRDS\" in vid:\n            expect(value != 0, \"Cannot set NTASKS or NTHRDS to 0\")\n\n\n        return EnvBase.set_value(self, vid, value, subgroup=subgroup, ignore_type=ignore_type)\n\n\n    def get_max_thread_count(self, comp_classes):\n        ''' Find the maximum number of openmp threads for any component in the case '''\n        max_threads = 1\n        for comp in comp_classes:\n            threads = self.get_value(\"NTHRDS\",attribute={\"compclass\":comp})\n            expect(threads is not None, \"Error no thread count found for component class {}\".format(comp))\n            if threads > max_threads:\n                max_threads = threads\n        return max_threads\n\n    def get_total_tasks(self, comp_classes):\n        total_tasks = 0\n        maxinst = 1\n        for comp in comp_classes:\n            ntasks = self.get_value(\"NTASKS\", attribute={\"compclass\":comp})\n            rootpe = self.get_value(\"ROOTPE\", attribute={\"compclass\":comp})\n            pstrid = self.get_value(\"PSTRID\", attribute={\"compclass\":comp})\n            if comp != \"CPL\":\n                ninst = self.get_value(\"NINST\", attribute={\"compclass\":comp})\n                maxinst = max(maxinst, ninst)\n            tt = rootpe + (ntasks - 1) * pstrid + 1\n            total_tasks = max(tt, total_tasks)\n        if self.get_value(\"MULTI_DRIVER\"):\n            total_tasks *= maxinst\n        return total_tasks\n\n    def get_tasks_per_node(self, total_tasks, max_thread_count):\n        expect(total_tasks > 0,\"totaltasks > 0 expected, totaltasks = {}\".format(total_tasks))\n        tasks_per_node = min(self.get_value(\"MAX_TASKS_PER_NODE\")/ max_thread_count,\n                             self.get_value(\"MAX_MPITASKS_PER_NODE\"), total_tasks)\n        return tasks_per_node if tasks_per_node > 0 else 1\n\n    def get_total_nodes(self, total_tasks, max_thread_count):\n        \"\"\"\n        Return (num_active_nodes, num_spare_nodes)\n        \"\"\"\n        tasks_per_node = self.get_tasks_per_node(total_tasks, max_thread_count)\n        num_nodes = int(math.ceil(float(total_tasks) / tasks_per_node))\n        return num_nodes, self.get_spare_nodes(num_nodes)\n\n    def get_spare_nodes(self, num_nodes):\n        force_spare_nodes = self.get_value(\"FORCE_SPARE_NODES\")\n        if force_spare_nodes != -999:\n            return force_spare_nodes\n\n        if self.get_value(\"ALLOCATE_SPARE_NODES\"):\n            ten_pct = int(math.ceil(float(num_nodes) * 0.1))\n            if ten_pct < 1:\n                return 1 # Always provide at lease one spare node\n            elif ten_pct > 10:\n                return 10 # Never provide more than 10 spare nodes\n            else:\n                return ten_pct\n        else:\n            return 0\n", "path": "scripts/lib/CIME/XML/env_mach_pes.py"}], "after_files": [{"content": "\"\"\"\nInterface to the env_mach_pes.xml file.  This class inherits from EntryID\n\"\"\"\nfrom CIME.XML.standard_module_setup import *\nfrom CIME.XML.env_base import EnvBase\nimport math\n\nlogger = logging.getLogger(__name__)\n\nclass EnvMachPes(EnvBase):\n\n    def __init__(self, case_root=None, infile=\"env_mach_pes.xml\", components=None):\n        \"\"\"\n        initialize an object interface to file env_mach_pes.xml in the case directory\n        \"\"\"\n        self._components = components\n        schema = os.path.join(get_cime_root(), \"config\", \"xml_schemas\", \"env_mach_pes.xsd\")\n        EnvBase.__init__(self, case_root, infile, schema=schema)\n\n    def add_comment(self, comment):\n        if comment is not None:\n            node = self.make_child(\"comment\", text=comment)\n            # make_child adds to the end of the file but we want it to follow the header\n            # so we need to remove it and add it in the correct position\n            self.remove_child(node)\n            self.add_child(node, position=1)\n\n    def get_value(self, vid, attribute=None, resolved=True, subgroup=None, max_mpitasks_per_node=None): # pylint: disable=arguments-differ\n        # Special variable NINST_MAX is used to determine the number of\n        # drivers in multi-driver mode.\n        if vid == \"NINST_MAX\":\n            value = 1\n            for comp in self._components:\n                if comp != \"CPL\":\n                    value = max(value, self.get_value(\"NINST_{}\".format(comp)))\n            return value\n\n        value = EnvBase.get_value(self, vid, attribute, resolved, subgroup)\n\n        if \"NTASKS\" in vid or \"ROOTPE\" in vid:\n            if max_mpitasks_per_node is None:\n                max_mpitasks_per_node = self.get_value(\"MAX_MPITASKS_PER_NODE\")\n            if value is not None and value < 0:\n                value = -1*value*max_mpitasks_per_node\n\n        return value\n\n    def set_value(self, vid, value, subgroup=None, ignore_type=False):\n        \"\"\"\n        Set the value of an entry-id field to value\n        Returns the value or None if not found\n        subgroup is ignored in the general routine and applied in specific methods\n        \"\"\"\n        if vid == \"MULTI_DRIVER\" and value:\n            ninst_max = self.get_value(\"NINST_MAX\")\n            for comp in self._components:\n                if comp == \"CPL\":\n                    continue\n                ninst = self.get_value(\"NINST_{}\".format(comp))\n                expect(ninst == ninst_max,\n                       \"All components must have the same NINST value in multi_driver mode.  NINST_{}={} shoud be {}\".format(comp,ninst,ninst_max))\n        if \"NTASKS\" in vid or \"NTHRDS\" in vid:\n            expect(value != 0, \"Cannot set NTASKS or NTHRDS to 0\")\n\n\n        return EnvBase.set_value(self, vid, value, subgroup=subgroup, ignore_type=ignore_type)\n\n\n    def get_max_thread_count(self, comp_classes):\n        ''' Find the maximum number of openmp threads for any component in the case '''\n        max_threads = 1\n        for comp in comp_classes:\n            threads = self.get_value(\"NTHRDS\",attribute={\"compclass\":comp})\n            expect(threads is not None, \"Error no thread count found for component class {}\".format(comp))\n            if threads > max_threads:\n                max_threads = threads\n        return max_threads\n\n    def get_total_tasks(self, comp_classes):\n        total_tasks = 0\n        maxinst = 1\n        for comp in comp_classes:\n            ntasks = self.get_value(\"NTASKS\", attribute={\"compclass\":comp})\n            rootpe = self.get_value(\"ROOTPE\", attribute={\"compclass\":comp})\n            pstrid = self.get_value(\"PSTRID\", attribute={\"compclass\":comp})\n            if comp != \"CPL\":\n                ninst = self.get_value(\"NINST\", attribute={\"compclass\":comp})\n                maxinst = max(maxinst, ninst)\n            tt = rootpe + (ntasks - 1) * pstrid + 1\n            total_tasks = max(tt, total_tasks)\n        if self.get_value(\"MULTI_DRIVER\"):\n            total_tasks *= maxinst\n        return total_tasks\n\n    def get_tasks_per_node(self, total_tasks, max_thread_count):\n        expect(total_tasks > 0,\"totaltasks > 0 expected, totaltasks = {}\".format(total_tasks))\n        tasks_per_node = min(self.get_value(\"MAX_TASKS_PER_NODE\")// max_thread_count,\n                             self.get_value(\"MAX_MPITASKS_PER_NODE\"), total_tasks)\n        return tasks_per_node if tasks_per_node > 0 else 1\n\n    def get_total_nodes(self, total_tasks, max_thread_count):\n        \"\"\"\n        Return (num_active_nodes, num_spare_nodes)\n        \"\"\"\n        tasks_per_node = self.get_tasks_per_node(total_tasks, max_thread_count)\n        num_nodes = int(math.ceil(float(total_tasks) / tasks_per_node))\n        return num_nodes, self.get_spare_nodes(num_nodes)\n\n    def get_spare_nodes(self, num_nodes):\n        force_spare_nodes = self.get_value(\"FORCE_SPARE_NODES\")\n        if force_spare_nodes != -999:\n            return force_spare_nodes\n\n        if self.get_value(\"ALLOCATE_SPARE_NODES\"):\n            ten_pct = int(math.ceil(float(num_nodes) * 0.1))\n            if ten_pct < 1:\n                return 1 # Always provide at lease one spare node\n            elif ten_pct > 10:\n                return 10 # Never provide more than 10 spare nodes\n            else:\n                return ten_pct\n        else:\n            return 0\n", "path": "scripts/lib/CIME/XML/env_mach_pes.py"}]}