1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3
4#-------------------------------------------------------------------------------
5
6# This file is part of Code_Saturne, a general-purpose CFD tool.
7#
8# Copyright (C) 1998-2021 EDF S.A.
9#
10# This program is free software; you can redistribute it and/or modify it under
11# the terms of the GNU General Public License as published by the Free Software
12# Foundation; either version 2 of the License, or (at your option) any later
13# version.
14#
15# This program is distributed in the hope that it will be useful, but WITHOUT
16# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18# details.
19#
20# You should have received a copy of the GNU General Public License along with
21# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22# Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
24#-------------------------------------------------------------------------------
25
26import configparser
27
28import sys
29import os, os.path, shutil, sys, string, types, re, subprocess
30
31#===============================================================================
32# Utility functions
33#===============================================================================
34
35def parse_wall_time_slurm(s):
36    """
37    Parse SLURM wall time
38    """
39    t = None
40
41    wt0 = s.split('-')
42    if len(wt0) == 2:
43        th = int(wt0[0])*3600*24
44        wt = wt0[1].split(':')
45    else:
46        th = 0
47        wt = wt0[0].split(':')
48    if len(wt) == 3:
49        t = th + int(wt[0])*3600 + int(wt[1])*60 + int(wt[2])
50    elif len(wt) == 2:
51        if len(wt0) == 2:
52            t = th + int(wt[0])*3600 + int(wt[1])*60
53        else:
54            t = th + int(wt[0])*60 + int(wt[1])
55    elif len(wt) == 1:
56        if len(wt0) == 2:
57            t = th + int(wt[0])*3600
58        else:
59            try:
60                t = th + int(wt[0])*60
61            except Exception:
62                pass
63
64    return t
65
66#-------------------------------------------------------------------------------
67
68def generate_header(batch_template=None, job_name=None, package=None):
69    """
70    Generate batch header lines based on batch template configuration
71    """
72
73    lines = []
74
75    if not package:
76        from code_saturne import cs_package
77        package = cs_package.package()
78
79    if not batch_template:
80        config = configparser.ConfigParser()
81        config.read(package.get_configfiles())
82        if config.has_option('install', 'batch'):
83            batch_template = config.get('install', 'batch')
84
85    if not batch_template:
86        return lines
87
88    if not job_name:
89        job_name = package.name + ':' + os.path.basename(os.getcwd())
90
91    # For some systems, name lengths may be limited.
92    # With SLURM 18.08, the max. length seems to be 37 characters.
93    job_name = job_name[:38]
94
95    if not os.path.isabs(batch_template):
96        batch_template = os.path.join(package.get_batchdir(),
97                                      'batch.' + batch_template)
98
99    fdt = open(batch_template, 'r')
100
101    import re, string
102    kwd1 = re.compile('nameandcase')
103
104    # Determine or build default names if required
105
106    for line in fdt:
107        line = line.rstrip()
108        line = re.sub(kwd1, job_name, line)
109        lines.append(line)
110
111    fdt.close()
112
113    return lines
114
115#===============================================================================
116# Class used to manage batch directives
117#===============================================================================
118
119#-------------------------------------------------------------------------------
120
121class batch:
122    """
123    Parse and modify special batch options in text file lines
124    """
125
126    #---------------------------------------------------------------------------
127
128    def __init__(self, package, install_config=None):
129        """
130        Constructor.
131        """
132
133        self.rm_type = None
134
135        self.submit_cmd = ''
136
137        self.params = {}
138
139        self.params['job_name'] = None
140        self.params['job_nodes'] = None
141        self.params['job_ppn'] = None
142        self.params['job_procs'] = None
143        self.params['job_threads'] = None
144        self.params['job_walltime'] = None
145        self.params['job_class'] = None
146        self.params['job_account'] = None
147        self.params['job_wckey'] = None
148
149        # Are we using a resource manager ?
150
151        self.rm_type = None
152        self.rm_template = None
153        self.submit_command = ''
154
155        submit_command = None
156
157        if install_config:
158            self.rm_template = install_config['batch']
159
160        elif package:
161            config = configparser.ConfigParser()
162            config.read(package.get_configfiles())
163
164            if config.has_option('install', 'batch'):
165                self.rm_template = config.get('install', 'batch')
166                if os.path.isabs(self.rm_template):
167                    i = self.rm_template.rfind(".")
168                    if i > -1:
169                        self.rm_template = self.rm_template[i+1:]
170
171            if config.has_option('install', 'submit_command'):
172                submit_command = config.get('install', 'submit_command')
173
174        if self.rm_template:
175            if self.rm_template[0:5] == 'SLURM':
176                self.rm_type = 'SLURM'
177                self.submit_command = 'sbatch'
178                for k in ('SBATCH_WCKEY', 'SLURM_WCKEY'):
179                    if k in os.environ:
180                        v = os.environ[k]
181                        if v:
182                            self.params['job_wckey'] = v
183            elif self.rm_template[0:3] == 'CCC':
184                self.rm_type = 'CCC'
185                self.submit_command = 'ccc_msub'
186            elif self.rm_template[0:3] == 'LSF':
187                self.rm_type = 'LSF'
188                self.submit_command = 'bsub'
189            elif self.rm_template[0:3] == 'OAR':
190                self.rm_type = 'OAR'
191                self.submit_command = 'oarsub'
192            elif self.rm_template[0:3] == 'PBS':
193                self.rm_type = 'PBS'
194                self.submit_command = 'qsub'
195            elif self.rm_template[0:3] == 'SGE':
196                self.rm_type = 'SGE'
197                self.submit_command = 'qsub'
198            else:
199                self.rm_type = os.path.basename(rm_template)
200
201        if submit_command:
202            self.submit_command = submit_command
203
204    #---------------------------------------------------------------------------
205
206    def __get_command_output__(self, cmd):
207        """
208        Run a command and return it's standard output.
209        """
210        p = subprocess.Popen(cmd,
211                             shell=True,
212                             stdout=subprocess.PIPE,
213                             stderr=subprocess.PIPE,
214                             universal_newlines=True)
215        lines = []
216        while True:
217            l = p.stdout.readline()
218            lines.append(l.strip())
219            if len(l) == 0 and p.poll() != None:
220                break
221        output = p.communicate()
222
223        if p.returncode == 0:
224            return lines
225        else:
226            print(output[1])
227            return []
228
229    #---------------------------------------------------------------------------
230
231    def __pre_parse__(self, s):
232        """
233        Pre-parse batch line
234        """
235        r = ' '
236        i = s.find('#')
237        if i > -1:
238            s = s[:i]
239        s = r.join(s.split())
240
241        return s
242
243    #---------------------------------------------------------------------------
244
245    def __parse_lines_env_vars__(self, lines):
246        """
247        Parse environment variables in batch file lines
248        """
249        batch_lines = lines
250
251        for i in range(len(batch_lines)):
252            j = batch_lines[i].find('#')
253            if j > -1:
254                toks = batch_lines[i][:j].split()
255            else:
256                toks = batch_lines[i].split()
257            if len(toks) > 1:
258                var = None
259                val = None
260                if toks[0] in ('set', 'export'):
261                    k = toks[1].find('=')
262                    if k > 1:
263                        var = toks[1][0:k]
264                        val = toks[1][k+1:]
265                elif toks[0] in ('setenv'):
266                    if len(toks) > 2:
267                        var = toks[1]
268                        val = toks[2]
269                if var == 'OMP_NUM_THREADS':
270                    try:
271                        self.params['job_threads'] = int(val)
272                    except Exception:
273                        pass
274
275    #---------------------------------------------------------------------------
276
277    def __update_lines_env_vars__(self, lines):
278        """
279        Update environment variables in batch file lines
280        """
281        if lines:
282            batch_lines = lines
283
284            for i in range(len(batch_lines)):
285                j = batch_lines[i].find('#')
286                if j > -1:
287                    toks = batch_lines[i][:j].split()
288                else:
289                    toks = batch_lines[i].split()
290                if len(toks) > 1:
291                    var = None
292                    val = None
293                    if toks[0] in ('set', 'export'):
294                        k = toks[1].find('=')
295                        if k > 1:
296                            var = toks[1][0:k]
297                            val = toks[1][k+1:]
298                    elif toks[0] in ('setenv'):
299                        if len(toks) > 2:
300                            var = toks[1]
301                            val = toks[2]
302                    if var == 'OMP_NUM_THREADS' and self.params['job_threads']:
303                        s_threads = str(self.params['job_threads'])
304                        if toks[0] in ('set', 'export'):
305                            s = toks[0] + ' ' + var + '=' + s_threads
306                        elif toks[0] in ('setenv'):
307                            s = toks[0] + ' ' + var + ' ' + s_threads
308                        if j > 1:
309                            s += ' ' + batch_lines[i][j:]
310                        batch_lines[i] = s
311
312    #---------------------------------------------------------------------------
313
314    def __parse_lines_slurm__(self, lines):
315        """
316        Parse SLURM batch file lines
317        """
318        batch_lines = lines
319
320        for i in range(len(batch_lines)):
321            if batch_lines[i][0:7] == '#SBATCH':
322                batch_args = self.__pre_parse__(batch_lines[i][7:])
323                if batch_args[0:2] == '--':
324                    tok = batch_args.split('=')
325                    if len(tok) < 2:
326                        continue
327                    kw = tok[0] + '='
328                    val = tok[1].split(',')[0].strip()
329                elif batch_args[0] == '-':
330                    kw = batch_args[0:2]
331                    val = batch_args[2:].split(',')[0].strip()
332                else:
333                    continue
334                if kw == '--job-name=' or kw == '-J':
335                    self.params['job_name'] = val
336                elif kw == '--ntasks=' or kw == '-n':
337                    self.params['job_procs'] = val
338                elif kw == '--nodes=' or kw == '-N':
339                    self.params['job_nodes'] = val
340                elif kw == '--ntasks-per-node=':
341                    self.params['job_ppn'] = val
342                elif kw == '--cpus-per-task=':
343                    self.params['job_threads'] = val
344                elif kw == '--time=' or kw == '-t':
345                    self.params['job_walltime'] = parse_wall_time_slurm(val)
346                elif kw == '--partition=' or kw == '-p':
347                    self.params['job_class'] = val
348                elif kw == '--account=' or kw == '-A':
349                    self.params['job_account'] = val
350                elif kw == '--wckey=':
351                    self.params['job_wckey'] = val
352
353    #---------------------------------------------------------------------------
354
355    def __update_lines_slurm__(self, lines):
356        """
357        Update the SLURM batch file from dictionary self.params.
358        """
359        batch_lines = lines
360
361        for i in range(len(batch_lines)):
362            if batch_lines[i][0:7] == '#SBATCH':
363                batch_args = self.__pre_parse__(batch_lines[i][7:])
364                if batch_args[0:2] == '--':
365                    tok = batch_args.split('=')
366                    if len(tok) < 2:
367                        continue
368                    kw = tok[0] + '='
369                    val = tok[1].split(',')[0].strip()
370                elif batch_args[0] == '-':
371                    kw = batch_args[0:2]
372                    val = batch_args[2:].split(',')[0].strip()
373                if kw == '--job-name=' or kw == '-J':
374                    val = str(self.params['job_name'])
375                elif kw == '--ntasks=' or kw == '-n':
376                    val = str(self.params['job_procs'])
377                elif kw == '--nodes=' or kw == '-N':
378                    val = str(self.params['job_nodes'])
379                elif kw == '--ntasks-per-node=':
380                    val = self.params['job_ppn']
381                elif kw == '--cpus-per-task=':
382                    val = self.params['job_threads']
383                elif kw == '--time=' or kw == '-t':
384                    wt = self.params['job_walltime']
385                    if wt > 86400: # 3600*24
386                        val = '%d-%d:%02d:%02d' % (wt//86400,
387                                                   (wt%86400)//3600,
388                                                   (wt%3600)//60,
389                                                   wt%60)
390                    else:
391                        val = '%d:%02d:%02d' % (wt//3600,
392                                                (wt%3600)//60,
393                                                wt%60)
394                elif kw == '--partition=' or kw == '-p':
395                    val = self.params['job_class']
396                elif kw == '--account=' or kw == '-A':
397                    val = self.params['job_account']
398                elif kw == '--wckey=':
399                    val = self.params['job_wckey']
400                else:
401                    continue
402                batch_lines[i] = '#SBATCH ' + kw + str(val)
403
404    #---------------------------------------------------------------------------
405
406    def __parse_lines_ccc__(self, lines):
407        """
408        Parse CCC (CCRT) batch file lines
409        """
410        batch_lines = lines
411
412        for i in range(len(batch_lines)):
413            if batch_lines[i][0:5] == '#MSUB':
414                batch_args = self.__pre_parse__(batch_lines[i][5:])
415                tok = batch_args.split()
416                if len(tok) < 2:
417                    continue
418                kw = tok[0]
419                val = tok[1].split(',')[0].strip()
420                if kw == '-r':
421                    self.params['job_name'] = val
422                elif kw == '-n':
423                    self.params['job_procs'] = int(val)
424                elif kw == '-N':
425                    self.params['job_nodes'] = int(val)
426                elif kw == '-T':
427                    self.params['job_walltime'] = int(val)
428                elif kw == '-q':
429                        self.params['job_class'] = val
430
431    #---------------------------------------------------------------------------
432
433    def __update_lines_ccc__(self, lines):
434        """
435        Update the Platform LSF batch file lines
436        """
437        batch_lines = lines
438
439        for i in range(len(batch_lines)):
440            if batch_lines[i][0:5] == '#MSUB':
441                batch_args = self.__pre_parse__(batch_lines[i][5:])
442                tok = batch_args.split()
443                if len(tok) < 2:
444                    continue
445                kw = tok[0]
446                if kw == '-r':
447                    val = str(self.params['job_name'])
448                elif kw == '-n':
449                    val = str(self.params['job_procs'])
450                elif kw == '-N':
451                    val = str(self.params['job_nodes'])
452                elif kw == '-T':
453                    val = str(self.params['job_walltime'])
454                elif kw == '-q':
455                    val = self.params['job_class']
456                else:
457                    continue
458                batch_lines[i] = '#MSUB ' + kw + ' ' + str(val)
459
460    #---------------------------------------------------------------------------
461
462    def __parse_lines_lsf__(self, lines):
463        """
464        Parse Platform LSF batch file lines
465        """
466        batch_lines = lines
467
468        for i in range(len(batch_lines)):
469            if batch_lines[i][0:5] == '#BSUB':
470                batch_args = self.__pre_parse__(batch_lines[i][5:])
471                tok = batch_args.split()
472                kw = tok[0]
473                val = tok[1].split(',')[0].strip()
474                if kw == '-J':
475                    self.params['job_name'] = val
476                elif kw == '-n':
477                    self.params['job_procs'] = int(val)
478                elif kw == '-W' or kw == '-wt' or kw == '-We':
479                    wt = val.split(':')
480                    if len(wt) == 1:
481                        self.params['job_walltime'] = int(wt[0])*60
482                    elif len(wt) == 2:
483                        self.params['job_walltime'] \
484                            = int(wt[0])*3600 + int(wt[1])*60
485                elif kw == '-q':
486                        self.params['job_class'] = val
487
488    #---------------------------------------------------------------------------
489
490    def __update_lines_lsf__(self, lines):
491        """
492        Update the Platform LSF batch file lines
493        """
494        batch_lines = lines
495
496        for i in range(len(batch_lines)):
497            if batch_lines[i][0:5] == '#BSUB':
498                batch_args = self.__pre_parse__(batch_lines[i][5:])
499                tok = batch_args.split()
500                kw = tok[0]
501                if kw == '-J':
502                    val = str(self.params['job_name'])
503                elif kw == '-n':
504                    val = str(self.params['job_procs'])
505                elif kw == '-W' or kw == '-wt' or kw == '-We':
506                    wt = self.params['job_walltime']
507                    val = '%d:%02d' % (wt//3600, (wt%3600)//60)
508                elif kw == '-q':
509                    val = self.params['job_class']
510                else:
511                    continue
512                batch_lines[i] = '#BSUB ' + kw + ' ' + str(val)
513
514    #---------------------------------------------------------------------------
515
516    def __parse_lines_pbs__(self, lines):
517        """
518        Parse PBS batch file lines
519        """
520        batch_lines = lines
521
522        # TODO: specialize for PBS Professional and TORQUE (OpenPBS has not been
523        # maintained since 2004, so we do not support it).
524        # The "-l nodes=N:ppn=P" syntax is common to all PBS variants,
525        # but PBS Pro considers the syntax depecated, and prefers its
526        # own "-l select=N:ncpus=P:mpiprocs=P" syntax.
527        # We do not have access to a PBS Professional system, but according to
528        # its documentation, it has commands such as "pbs-report" or "pbs_probe"
529        # which are not part of TORQUE, while the latter has "pbsnodelist" or
530        # #pbs-config". The presence of either could help determine which
531        # system is available.
532
533        for i in range(len(batch_lines)):
534            if batch_lines[i][0:4] == '#PBS':
535                batch_args = ' ' + self.__pre_parse__(batch_lines[i][4:])
536                index = batch_args.rfind(' -')
537                while index > -1:
538                    arg = batch_args[index+1:]
539                    batch_args = batch_args[0:index]
540                    if arg[0:2] == '-N':
541                        self.params['job_name'] = arg.split()[1]
542                    elif arg[0:9] == '-l nodes=':
543                        arg_tmp = arg[9:].split(':')
544                        self.params['job_nodes'] = arg_tmp[0]
545                        for s in arg_tmp[1:]:
546                            j = s.find('ppn=')
547                            if j > -1:
548                                self.params['job_ppn'] \
549                                    = s[j:].split('=')[1]
550                    elif arg[0:10] == '-l select=':
551                        arg_tmp = arg[10:].split(':')
552                        self.params['job_nodes'] = arg_tmp[0]
553                        for s in arg_tmp[1:]:
554                            j = s.find('ncpus=')
555                            if j > -1:
556                                self.params['job_ppn'] \
557                                    = s[j:].split('=')[1]
558                    elif arg[0:12] == '-l walltime=':
559                        wt = (arg.split('=')[1]).split(':')
560                        if len(wt) == 3:
561                            self.params['job_walltime'] \
562                                = int(wt[0])*3600 + int(wt[1])*60 + int(wt[2])
563                        elif len(wt) == 2:
564                            self.params['job_walltime'] \
565                                = int(wt[0])*60 + int(wt[1])
566                        elif len(wt) == 1:
567                            self.params['job_walltime'] \
568                                = int(wt[0])
569                    elif arg[0:2] == '-q':
570                            self.params['job_class'] = arg.split()[1]
571                    index = batch_args.rfind(' -')
572
573    #---------------------------------------------------------------------------
574
575    def __update_lines_pbs__(self, lines):
576        """
577        Update the PBS batch file from dictionary self.params.
578        """
579        batch_lines = lines
580
581        for i in range(len(batch_lines)):
582            if batch_lines[i][0:4] == '#PBS':
583                ch = ''
584                batch_args = ' ' + self.__pre_parse__(batch_lines[i][4:])
585                index = batch_args.rfind(' -')
586                while index > -1:
587                    arg = batch_args[index+1:]
588                    batch_args = batch_args[0:index]
589                    if arg[0:2] == '-N':
590                        ch = ' -N ' + self.params['job_name'] + ch
591                    elif arg[0:9] == '-l nodes=':
592                        arg_tmp = arg[9:].split(':')
593                        ch1 = ' -l nodes=' + self.params['job_nodes']
594                        for s in arg_tmp[1:]:
595                            j = s.find('ppn=')
596                            if j > -1:
597                                ch1 += ':' + s[0:j] \
598                                       + 'ppn=' + self.params['job_ppn']
599                            else:
600                                ch1 += ':' + s
601                        ch = ch1 + ch
602                    elif arg[0:10] == '-l select=':
603                        arg_tmp = arg[10:].split(':')
604                        ch1 = ' -l select=' + self.params['job_nodes']
605                        for s in arg_tmp[1:]:
606                            j = s.find('ncpus=')
607                            if j > -1:
608                                ch1 += ':' + s[0:j] \
609                                       + 'ncpus=' + self.params['job_ppn']
610                            else:
611                                ch1 += ':' + s
612                        ch = ch1 + ch
613                    elif arg[0:12] == '-l walltime=':
614                        wt = self.params['job_walltime']
615                        s_wt = '%d:%02d:%02d' % (wt//3600,
616                                                 (wt%3600)//60,
617                                                 wt%60)
618                        ch = ' -l walltime=' + s_wt + ch
619                    elif arg[0:2] == '-q':
620                        ch = ' -q ' + self.params['job_class'] + ch
621                    else:
622                        ch = ' ' + arg + ch
623                    index = batch_args.rfind(' -')
624                ch = '#PBS' + ch
625                batch_lines[i] = ch
626
627    #---------------------------------------------------------------------------
628
629    def __parse_lines_sge__(self, lines):
630        """
631        Parse Sun Grid Engine batch file lines
632        """
633        batch_lines = lines
634
635        for i in range(len(batch_lines)):
636            if batch_lines[i][0:2] == '#$':
637                batch_args = ' ' + self.__pre_parse__(batch_lines[i][2:])
638                index = batch_args.rfind(' -')
639                while index > -1:
640                    arg = batch_args[index+1:]
641                    batch_args = batch_args[0:index]
642                    if arg[0:2] == '-N':
643                        self.params['job_name'] = arg.split()[1]
644                    elif arg[0:3] == '-pe':
645                        try:
646                            arg_tmp = arg[3:].split(' ')
647                            self.params['job_procs'] = arg_tmp[2]
648                        except Exception:
649                            pass
650                    elif arg[0:8] == '-l h_rt=':
651                        wt = (arg.split('=')[1]).split(':')
652                        if len(wt) == 3:
653                            self.params['job_walltime'] \
654                                = int(wt[0])*3600 + int(wt[1])*60 + int(wt[2])
655                        elif len(wt) == 2:
656                            self.params['job_walltime'] \
657                                = int(wt[0])*60 + int(wt[1])
658                        elif len(wt) == 1:
659                            self.params['job_walltime'] = int(wt[0])
660                    elif arg[0:2] == '-q':
661                        self.params['job_class'] = arg.split()[1]
662                    index = batch_args.rfind(' -')
663
664    #---------------------------------------------------------------------------
665
666    def __update_lines_sge__(self, lines):
667        """
668        Update the Sun Grid Engine batch file lines
669        """
670        batch_lines = lines
671
672        for i in range(len(batch_lines)):
673            if batch_lines[i][0:2] == '#$':
674                ch = ''
675                batch_args = ' ' + self.__pre_parse__(batch_lines[i][2:])
676                index = batch_args.rfind(' -')
677                while index > -1:
678                    arg = batch_args[index+1:]
679                    batch_args = batch_args[0:index]
680                    if arg[0:2] == '-N':
681                        ch = ' -N ' + self.params['job_name'] + ch
682                    elif arg[0:3] == '-pe':
683                        try:
684                            arg_tmp = arg[3:].split(' ')
685                            ch = ' -pe ' + arg_tmp[1] + ' ' \
686                                + str(self.params['job_procs']) + ch
687                        except Exception:
688                            pass
689                    elif arg[0:8] == '-l h_rt=':
690                        wt = self.params['job_walltime']
691                        s_wt = '%d:%02d:%02d' % (wt//3600,
692                                                 (wt%3600)//60,
693                                                 wt%60)
694                        ch = ' -l h_rt=' + s_wt + ch
695                    elif arg[0:2] == '-q':
696                        ch = ' -q ' + self.params['job_class'] + ch
697                    else:
698                        ch = ' ' + arg + ch
699                    index = batch_args.rfind(' -')
700                    ch = '#$' + ch
701                    batch_lines[i] = ch
702
703    #---------------------------------------------------------------------------
704
705    def parse_lines(self, lines):
706        """
707        Fill self.params reading the job file.
708        """
709
710        if self.rm_type:
711            if self.rm_type == 'SLURM':
712                self.__parse_lines_slurm__(lines)
713            elif self.rm_type == 'CCC':
714                self.__parse_lines_ccc__(lines)
715            elif self.rm_type == 'LSF':
716                self.__parse_lines_lsf__(lines)
717            elif self.rm_type == 'PBS':
718                self.__parse_lines_pbs__(lines)
719            elif self.rm_type == 'SGE':
720                self.__parse_lines_sge__(lines)
721
722        self.__parse_lines_env_vars__(lines)
723
724    #---------------------------------------------------------------------------
725
726    def update_lines(self, lines, keyword=None):
727        """
728        Update the batch file from reading dictionary self.params.
729        If a keyword is given, its presence is checked.
730        """
731
732        if keyword != None:
733            if keyword not in self.params:
734                msg = str(keyword) + " is not in list " \
735                    + str(list(self.params.keys())) + os.linesep
736                raise ValueError(msg)
737
738        if self.rm_type:
739            if self.rm_type == 'SLURM':
740                self.__update_lines_slurm__(lines)
741            elif self.rm_type == 'CCC':
742                self.__update_lines_ccc__(lines)
743            elif self.rm_type == 'LSF':
744                self.__update_lines_lsf__(lines)
745            elif self.rm_type == 'PBS':
746                self.__update_lines_pbs__(lines)
747            elif self.rm_type == 'SGE':
748                self.__update_lines_sge__(lines)
749
750        self.__update_lines_env_vars__(lines)
751
752    #---------------------------------------------------------------------------
753
754    def submit_command_prefix(self):
755        """
756        Return the command prefix used to submit a job.
757        """
758
759        return self.submit_command + ' '
760
761    #---------------------------------------------------------------------------
762
763    def get_class_list(self):
764        """
765        Return the list of available classes
766        """
767
768        class_list = []
769
770        try:
771
772            rm_type = self.rm_type
773
774            if rm_type == 'SLURM':
775                output = self.__get_command_output__('sinfo -s')
776                for l in output[1:]:
777                    if len(l) == 0:
778                        break
779                    else:
780                        name = l.split(' ')[0]
781                        if name[-1:] == '*':
782                            name = name[:-1]
783                        class_list.append(name)
784
785            elif rm_type == 'CCC':
786                output = self.__get_command_output__('class')
787                for l in output[1:]:
788                    if len(l) == 0:
789                        break
790                    else:
791                        class_list.append(l.split(' ')[0])
792
793            elif rm_type == 'LSF':
794                output = self.__get_command_output__('bqueues')
795                ignore = True
796                for l in output[1:]:
797                    if len(l) == 0:
798                        break
799                    else:
800                        class_list.append(l.split(' ')[0])
801
802            elif rm_type == 'PBS':
803                output = self.__get_command_output__('qstat -q')
804                ignore = True
805                for l in output:
806                    if l[0:3] == '---':
807                        ignore = not ignore
808                    elif ignore == False:
809                        class_list.append(l.split(' ')[0])
810
811            elif self.case['batch_type'][0:3] == 'SGE':
812                output = self.__get_command_output__('qconf -sc')
813                for l in output:
814                    if l[0:1] != '#':
815                        class_list.append(l.split(' ')[0])
816
817        except Exception:
818            import traceback
819            exc_info = sys.exc_info()
820            bt = traceback.format_exception(*exc_info)
821            print(bt)
822            pass
823
824        return class_list
825
826#-------------------------------------------------------------------------------
827# End
828#-------------------------------------------------------------------------------
829
830