Changes between Initial Version and Version 1 of HTCondor


Ignore:
Timestamp:
08/03/2024 10:57:58 (4 months ago)
Author:
lambert
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • HTCondor

    v1 v1  
     1= Utilisation du système de batch HT-Condor =
     2
     3== Machines pour la soumission de tâches ==
     4
     5Quatre machines de soumission sont à votre disposition pour soumettre vos tâches avec le système de batch HTCondor:
     6- lpsc-batch-almalinux et lpsc-batch-almalinux2 (!AlmaLinux release 9.2)
     7- lpsc-batch-fedora (Fedora 39)
     8- lpsc-batch-centos7 (CentOS Linux release 7.4)
     9
     10== Prérequis pour soumettre une tâche ==
     11
     12Pour soumettre une tâche sur HTCondor il faut :
     13- un *exécutable* qui pourra dans un premier temps être testé en interactif sur les machines de soumission
     14- un *fichier de description* qui sera lu par le système HTCondor et qui définira les ressources et le type d'environnement dont a besoin votre exécutable.
     15
     16== Commandes utiles ==
     17
     18- [xxx@lpsc-cyy] condor_submit <description.submit> : soumet une tâche décrite par un fichier <description.submit>
     19- [xxx@lpsc-cyy] condor_q (-long)? (-run)? : Voir l'avancement de vos tâches soumises
     20- [xxx@lpsc-cyy] condor_rm -all : Supprime toutes vos tâches de la file d'attente
     21- [xxx@lpsc-cyy] condor_status -avail : Voir toutes les machines disponibles dans le batch
     22- [xxx@lpsc-cyy] condor_status -avail : Voir toutes les machines disponibles dans le batch
     23- [xxx@lpsc-cyy] condor_status (-long)? (<machine>)? : Voir tous les attributs "!ClassAd" de l'ensemble des machines ou d'une machine donnée. (voir [https://htcondor.readthedocs.io/en/latest/users-manual/matchmaking-with-classads.html documentation]).
     24  Cela permets de sélectionner les machines avec les ressources nécessaires pour exécuter une tâche en ajoutant une ligne "+Requirements" dans un fichier de soumission (voir exemples ci-dessous)
     25
     26==  Liens utiles ==
     27 - https://htcondor.readthedocs.io/en/latest/
     28 - http://www.iac.es/sieinvens/siepedia/pmwiki.php?n=HOWTOs.CondorHowTo#howto_nestloop
     29 - https://www-auth.cs.wisc.edu/lists/htcondor-users/2016-August/msg00034.shtml
     30 - http://www.iac.es/sieinvens/siepedia/pmwiki.php?n=HOWTOs.CondorSubmitFile
     31
     32== Le concept d'univers ==
     33
     34Un [https://htcondor.readthedocs.io/en/23.0/users-manual/choosing-an-htcondor-universe.html univers pour HTCondor] est un environnement d’exécution pour une tâche.
     35HTCondor définit plusieurs univers, plusieurs d'entre-eux ont été configurés sur la ferme de calcul du LPSC :
     36
     37- [#Universvanilla vanilla], l'univers "par défaut" avec lequel vous pouvez soumettre la plupart de vos tâches
     38- [#Universparallel parallel], l'univers qui prend en charge les tâches qui s'étendent sur plusieurs machines, où les multiples processus d'une tâche s'exécutent simultanément, éventuellement en communiquant entre eux.
     39- [#Universdocker docker], l'univers qui permet d'utiliser des containers docker depuis [https://hub.docker.com/ DockerHub] pour faire s’exécuter vos tâches
     40- [#Universjava java], l'univers pour les tâches à base d'exécutables Java
     41
     42D'autres univers existent et pourront être proposés au besoin.
     43
     44=== Univers vanilla ===
     45
     46==== Python  ====
     47
     48**test_python.submit**
     49
     50{{{
     51
     52  # Définition de l'univers
     53  universe = vanilla
     54
     55  # Chemin vers l'exécutable
     56  executable = ./test_python.py
     57
     58  # Fichiers à produire en sortie
     59  output = test_python.out
     60  log = test_python.log
     61  error = test_python.err
     62 
     63  # directive pour le transfert des fichiers de sortie depuis le nœud d’exécution
     64  should_transfer_files = YES
     65  when_to_transfer_output = ON_EXIT
     66 
     67  queue
     68}}}
     69
     70**test_python.py**
     71
     72{{{
     73#!/usr/bin/env python3
     74
     75import platform
     76from datetime import datetime
     77
     78def afficher_informations_systeme():
     79    # Obtenir le nom de la machine
     80    nom_machine = platform.node()
     81
     82    # Obtenir la date et l'heure actuelles
     83    date_heure_actuelles = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
     84
     85    # Afficher les informations
     86    print(f"Nom de la machine: {nom_machine}")
     87    print(f"Date et heure actuelles: {date_heure_actuelles}")
     88
     89# Appeler la fonction pour afficher les informations
     90afficher_informations_systeme()
     91
     92}}}
     93
     94==== Shell ====
     95
     96**nombresPremiers.submit**
     97
     98{{{
     99  universe = vanilla
     100
     101  executable = nombresPremiers.sh
     102
     103  # Arguments à passer à l'executable
     104  arguments = 100
     105
     106  # Fichier de sortie à rappatrier depuis les nœuds d'execution
     107  output=results.output.$(Process)
     108  error=results.error.$(Process)
     109  log=results.log
     110
     111  should_transfer_files=YES
     112  when_to_transfer_output = ON_EXIT
     113
     114  queue
     115
     116}}}
     117
     118**nombresPremiers.sh**
     119
     120{{{
     121#!/bin/sh
     122
     123limit=${1}
     124echo "Les nombres premiers entre 1 et ${limit} sont :"
     125
     126# Utilisation du crible d'Ératosthène pour trouver les nombres premiers jusqu'à "limit"
     127sieve=( $(seq 2 $limit) )
     128count=0
     129
     130for ((i=2; i*i<=limit; i++))
     131do
     132    if [ ${sieve[$i-2]} -ne 0 ]
     133    then
     134        for ((j=i*i; j<=limit; j+=i))
     135        do
     136            sieve[$j-2]=0
     137        done
     138    fi
     139done
     140
     141# Affichage des nombres premiers restants
     142for num in "${sieve[@]}"
     143do
     144    if [ $num -ne 0 ]
     145    then
     146        echo -n "$num "
     147        count=$((count + 1))
     148
     149        if [ $count -eq 50 ]
     150        then
     151            echo
     152            count=0
     153        fi
     154    fi
     155done
     156
     157echo  # Saut de ligne final si nécessaire
     158
     159}}}
     160
     161==== MPI avec OpenMPI ====
     162
     163Dans l'univers vanilla, les tâches MPI ne tourne que sur une seule machine en utilisant tous les cœurs et processeurs demandés dans la limite des capacités de la machine hôte.
     164
     165**run.sh**
     166
     167run.sh est un script shell pour faire le setup de l'environnement.
     168
     169{{{
     170#!/bin/bash
     171
     172export LD_LIBRARY_PATH=/usr/lib64/openmpi/lib/:${LD_LIBRARY_PATH}
     173export PATH=/usr/lib64/openmpi/bin/:${PATH}
     174
     175mpirun $*
     176
     177}}}
     178
     179L'executable est compilé au préalable avec : {{{/usr/lib64/mpi/bin/mpicc simple.c -o simple}}}
     180
     181**simple.c**
     182
     183{{{
     184#include <stdio.h>
     185#include <mpi.h>
     186
     187int main(int argc, char** argv) {
     188    int rank, size;
     189
     190    // Initialisation de l'environnement MPI
     191    MPI_Init(&argc, &argv);
     192
     193    // Obtention du rang du processus
     194    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
     195
     196    // Obtention de la taille du communicateur
     197    MPI_Comm_size(MPI_COMM_WORLD, &size);
     198
     199    // Affichage du rang et de la taille
     200    printf("Hello from process %d of %d\n", rank, size);
     201
     202    // Finalisation de l'environnement MPI
     203    MPI_Finalize();
     204
     205    return 0;
     206}
     207
     208}}}
     209
     210**simple.submit**
     211{{{
     212universe              = vanilla
     213executable            = run.sh
     214arguments             = -np 8 simple
     215
     216output                = simple.out
     217error                 = simple.err
     218log                   = simple.log
     219
     220should_transfer_files = yes
     221when_to_transfer_output = on_exit
     222transfer_input_files = simple
     223
     224# Spécifiez le nombre de slots (processus MPI) requis
     225request_cpus = 1
     226request_memory = 1024M
     227request_disk   = 10240K
     228
     229#+Requirements           = OpSysAndVer =?= "AlmaLinux"
     230#+Requirements           = machine     =?= "lpsc-c21.in2p3.fr"
     231+Requirements            = member(machine, {"lpsc-c22.in2p3.fr", "lpsc-c23.in2p3.fr"})
     232
     233queue
     234
     235}}}
     236
     237==== MPI avec MPICH ====
     238
     239Dans l'univers vanilla, les tâches MPI ne tourne que sur une seule machine en utilisant tous les cœurs et processeurs demandés dans la limite des capacités de la machine hôte.
     240
     241**run.sh**
     242
     243run.sh est un script shell pour faire le setup de l'environnement.
     244
     245{{{
     246#!/bin/bash
     247
     248export LD_LIBRARY_PATH=/usr/lib64/mpich/lib/:${LD_LIBRARY_PATH}
     249export PATH=/usr/lib64/mpich/bin/:${PATH}
     250
     251mpirun $*
     252
     253
     254}}}
     255
     256L'executable est compilé au préalable avec : {{{/usr/lib64/mpich/bin/mpicc simple.c -o simple}}}
     257
     258**simple.c**
     259
     260{{{
     261#include <stdio.h>
     262#include <mpi.h>
     263
     264int main(int argc, char** argv) {
     265    int rank, size;
     266
     267    // Initialisation de l'environnement MPI
     268    MPI_Init(&argc, &argv);
     269
     270    // Obtention du rang du processus
     271    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
     272
     273    // Obtention de la taille du communicateur
     274    MPI_Comm_size(MPI_COMM_WORLD, &size);
     275
     276    // Affichage du rang et de la taille
     277    printf("Hello from process %d of %d\n", rank, size);
     278
     279    // Finalisation de l'environnement MPI
     280    MPI_Finalize();
     281
     282    return 0;
     283}
     284}}}
     285
     286**simple.submit**
     287{{{
     288universe              = vanilla
     289executable            = run.sh
     290
     291# Attention au chemin relatif pour l'executable avec MPICH: ./simple et pas simple
     292arguments             = -np 8 ./simple
     293
     294output                = simple.out
     295error                 = simple.err
     296log                   = simple.log
     297
     298should_transfer_files = yes
     299when_to_transfer_output = on_exit
     300transfer_input_files = simple
     301
     302# Spécifiez le nombre de slots (processus MPI) requis
     303request_cpus = 1
     304request_memory = 1024M
     305request_disk   = 10240K
     306
     307#+Requirements           = OpSysAndVer =?= "AlmaLinux"
     308#+Requirements           = machine     =?= "lpsc-c21.in2p3.fr"
     309+Requirements            = member(machine, {"lpsc-c22.in2p3.fr", "lpsc-c23.in2p3.fr"})
     310
     311queue
     312
     313}}}
     314
     315
     316=== Univers parallel ===
     317
     318==== Shell ====
     319
     320**parallel.submit**
     321{{{
     322#!/bin/sh
     323
     324echo "Hello I am ${HOSTNAME} and I am node ${1}"
     325
     326}}}
     327
     328**parallel.submit**
     329{{{
     330universe                 = parallel
     331executable               = parallel.sh
     332arguments                = $(Node)
     333
     334machine_count            = 2
     335
     336output                   = parallel.$(Node).out
     337error                    = parallel.$(Node).err
     338# Il n'est pas possible de faire un fichier de log par nœuds
     339log                      = parallel.log
     340
     341should_transfer_files    = yes
     342when_to_transfer_output  = on_exit
     343
     344+Requirements             = member(machine,  {"lpsc-c21.in2p3.fr","lpsc-c22.in2p3.fr"})
     345
     346queue
     347
     348}}}
     349
     350==== MPI avec OpenMPI ====
     351
     352Pour soumettre une tâche avec OpenMPI dans l'univers parallel, vous pouvez utiliser un script fourni par HTCondor et qui se trouve sur les machines de soumission sous : /usr/share/doc/condor/examples/openmpiscript.
     353
     354Dans l'exemple qui suit, on execute un fichier example préalablement compilé à partir d'un fichier source example.c : {{{/usr/lib64/openmpi/bin/mpicc example.c -o example}}}
     355
     356**example.c**
     357{{{
     358#include <stdio.h>
     359#include <mpi.h>
     360
     361int main(int argc, char **argv) {
     362    int rank, size;
     363    int local_array[5] = {1, 2, 3, 4, 5};
     364    int global_sum[5] = {0, 0, 0, 0, 0};
     365
     366    MPI_Init(&argc, &argv);
     367    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
     368    MPI_Comm_size(MPI_COMM_WORLD, &size);
     369
     370    // Chaque processus ajoute son tableau local à global_sum
     371
     372    MPI_Reduce(local_array, global_sum, 5, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
     373
     374    // Seul le processus de rang 0 affiche le résultat
     375    if (rank == 0) {
     376        printf("Résultat de la somme globale : ");
     377        for (int i = 0; i < 5; i++) {
     378            printf("%d ", global_sum[i]);
     379        }
     380        printf("\n");
     381    }
     382
     383    MPI_Finalize();
     384    return 0;
     385}
     386
     387}}}
     388
     389**example.submit**
     390{{{
     391universe                 = parallel
     392
     393executable               = /usr/share/doc/condor/examples/openmpiscript
     394arguments                = example
     395
     396machine_count            = 2
     397
     398output                   = example.out
     399error                    = example.err
     400log                      = example.log
     401
     402should_transfer_files    = yes
     403when_to_transfer_output  = on_exit
     404transfer_input_files     = example
     405want_io_proxy            = True
     406
     407request_cpus             = 8
     408#request_memory           = 1024M
     409#request_disk             = 10240K
     410
     411#+Requirements            = OpSysAndVer =?= "AlmaLinux"
     412+Requirements             = member(machine,  {"lpsc-c21.in2p3.fr","lpsc-c22.in2p3.fr"})
     413
     414queue
     415
     416}}}
     417==== MPI avec MPICH ====
     418
     419Non disponible dans l'univers parallèle...
     420
     421=== Univers java ===
     422
     423Les programmes Java peuvent être exécutés après avoir été préalablement "compilés" avec un JDK (Java Devlopment Kit) normalement présent sur les machines de soumission:
     424* génération d'un fichier .class
     425{{{
     426javac !MachineDate.java
     427}}}
     428* génération d'une archive exécutable .jar (optionnel)
     429{{{
     430jar cf !MachineDate.jar ./!MachineDate.class
     431}}}
     432
     433**!MachineDate.java**
     434
     435{{{
     436import java.net.InetAddress;
     437import java.util.Date;
     438
     439public class MachineDate {
     440    public static void main(String[] args) {
     441        try {
     442            InetAddress localMachine = InetAddress.getLocalHost();
     443            System.out.println("Machine: " + localMachine.getHostName());
     444            System.out.println("Date: " + new Date());
     445        } catch (Exception e) {
     446            e.printStackTrace();
     447        }
     448    }
     449}
     450}}}
     451
     452
     453**Option 1 : !MachineDate.class**
     454
     455{{{
     456universe = java
     457
     458executable              = MachineDate.class
     459arguments               = MachineDate
     460transfer_input_files    = ${PWD}/MachineDate.class
     461
     462log                     = MachineDateClass.log
     463output                  = MachineDateClass.out
     464error                   = MachineDateClass.err
     465
     466should_transfer_files   = YES
     467when_to_transfer_output = ON_EXIT
     468
     469request_cpus            = 1
     470request_memory          = 1024M
     471request_disk            = 10240K
     472
     473queue
     474
     475}}}
     476
     477**Option 2 : !MachineDate.jar**
     478
     479{{{
     480universe = java
     481
     482executable              = MachineDate.class
     483jar_files               = MachineDate.jar
     484arguments               = MachineDate
     485
     486log                     = MachineDateJar.log
     487output                  = MachineDateJar.out
     488error                   = MachineDateJar.err
     489
     490transfer_input_files = ${PWD}/MachineDate.jar
     491should_transfer_files   = YES
     492when_to_transfer_output = ON_EXIT
     493
     494queue
     495}}}
     496
     497=== Univers docker ===
     498
     499Docker est déployé sur les machines de la ferme locale. Il est possible d'utiliser n'importe quelle image pour définir un environnement d’exécution pour vos tâches.
     500Les images docker peuvent être trouvées sur le site [https://hub.docker.com/ DockerHub]
     501
     502==== Exécuter "cat" sur Debian ====
     503
     504**docker.submit**
     505
     506{{{
     507  #universe = docker is optional
     508  universe                = docker
     509 
     510  # nom de l'image sur dockerHub
     511  docker_image            = debian
     512
     513  # programme à exécuter dans l'environnement debian avec ses arguments
     514  executable              = /bin/cat
     515  arguments               = /etc/hosts
     516
     517  # fichiers de sortie à rapatrier depuis le nœud d’exécution de la ferme locale
     518  should_transfer_files   = YES
     519  when_to_transfer_output = ON_EXIT
     520  output                  = out.$(Process)
     521  error                   = err.$(Process)
     522  log                     = log.$(Process)
     523
     524  # pré-requis pour sélection d'un nœud de la ferme locale où faire tourner la tâche
     525  request_cpus   = 1
     526  request_memory = 1024M
     527  request_disk   = 10240K
     528
     529  queue 1
     530}}}
     531
     532==== Génération d'un histogramme avec ROOT ====
     533
     534ROOT est un programme d'analyse qui n'est pas forcément installé ou configuré sur les machines de la ferme locale.
     535Il est cependant possible de l'utiliser via une image docker.
     536
     537**Candle Histo.C** : le fichier root à exécuter
     538{{{
     539#include <TROOT.h>
     540#include <TCanvas.h>
     541#include <TH2I.h>
     542#include <TRandom.h>
     543
     544void candlehisto()
     545{
     546    // Définissez la taille du canevas avec une résolution plus élevée
     547    TCanvas *c1 = new TCanvas("c1", "Candle Presets", 1920, 1080);
     548    c1->Divide(3, 2);
     549
     550    TRandom *rng = new TRandom();
     551    TH2I *h1 = new TH2I("h1", "Sin", 18, 0, 360, 100, -1.5, 1.5);
     552    h1->GetXaxis()->SetTitle("Deg");
     553
     554    float myRand;
     555    for (int i = 0; i < 360; i += 10)
     556    {
     557        for (int j = 0; j < 100; j++)
     558        {
     559            myRand = rng->Gaus(sin(i * 3.14 / 180), 0.2);
     560            h1->Fill(i, myRand);
     561        }
     562    }
     563
     564    c1->cd(1);
     565    for (int i = 1; i < 7; i++)
     566    {
     567        c1->cd(i);
     568        TString title = TString::Format("CANDLEX%d", i);
     569        TH2I *myhist = (TH2I *)h1->DrawCopy(title);
     570        myhist->SetTitle(title);
     571    }
     572
     573    // Sauvegardez dans un seul fichier image dans le répertoire courant
     574    TString imgFileName = "output.png";
     575    c1->SaveAs(imgFileName);
     576}
     577
     578int main()
     579{
     580    candlehisto();
     581    return 0;
     582}
     583
     584}}}
     585
     586**candlehisto.submit** : le fichier de soumission
     587
     588{{{
     589  #universe = docker is optional
     590  universe                = docker
     591 
     592  # nom de l'image sur dockerHub
     593  docker_image            = rootproject/root
     594
     595  # programme à exécuter dans l'environnement ROOT avec ses arguments
     596  executable              = /opt/root/bin/root.exe
     597  arguments               = -b -q -l candlehisto.C
     598
     599  # Fichier d'input à transférer sur le nœud où va tourner la tâche
     600  transfer_input_files = candlehisto.C
     601
     602  # Fichier de résultat à transférer depuis le nœud ou a tourner la tâche en fin d’exécution
     603  transfer_output_files   = output.png
     604
     605  should_transfer_files   = YES
     606  when_to_transfer_output = ON_EXIT
     607
     608  # Fichier de logs
     609  output                  = out.$(ClusterId).$(ProcId)
     610  error                   = err.$(ClusterId).$(ProcId)
     611  log                     = log.$(ClusterId).$(ProcId)
     612
     613  # Pré-requis pour la sélection du nœud local ou faire tourner la tâche
     614  # mémoire requise
     615  request_memory          = 2000M
     616  # type de système requis
     617  +Requirements           = OpSysAndVer =?= "AlmaLinux"
     618  # nom du nœud d’exécution de la ferme locale
     619  +Requirements           = machine     =?= "lpsc-c27.in2p3.fr"
     620
     621  queue 1
     622
     623}}}
     624
     625== Le concept de jobset ==
     626
     627HTCondor permet la soumission d'ensemble de tâches. La syntaxe du fichier de soumission est légèrement différente que pour une tâche simple, vous pouvez trouver la documentation [https://htcondor.readthedocs.io/en/23.0/users-manual/job-sets.html#submitting-a-job-set ici]
     628
     629La commande HTcondor diffère également, elle est de la forme suivante : {{{htcondor jobset submit jobs.set}}}
     630
     631=== Soumission d'un ensemble de tâches OpenMPI ===
     632
     633On retrouve dans le fichier jobs.set le contenu d'un fichier de soumission de l'univers vanilla. La différence réside dans son "encapsulation" dans un itérateur dans le ficher de soumission du jobset.
     634
     635**jobs.set**
     636{{{
     637name = ExampleJobSet
     638
     639# Définition d'un itérateur: un tableau contenant des items qui sont des liste d'arguments (dans notre cas, un seul argument par item, le nom d'une machine)
     640
     641iterator = table machine {
     642    lpsc-c0.in2p3.fr
     643    lpsc-c8.in2p3.fr
     644    lpsc-c12.in2p3.fr
     645    lpsc-c13.in2p3.fr
     646    lpsc-c15.in2p3.fr
     647    lpsc-c16.in2p3.fr
     648    lpsc-c17.in2p3.fr
     649    lpsc-c18.in2p3.fr
     650    lpsc-c19.in2p3.fr
     651    lpsc-c20.in2p3.fr
     652    lpsc-c21.in2p3.fr
     653    lpsc-c22.in2p3.fr
     654    lpsc-c23.in2p3.fr
     655    lpsc-c24.in2p3.fr
     656    lpsc-c25.in2p3.fr
     657    lpsc-c26.in2p3.fr
     658    lpsc-c27.in2p3.fr
     659}
     660
     661# définition de la tâche de base qui va être "itérée"
     662
     663job {
     664
     665    universe                = vanilla
     666    executable              = run.sh
     667    arguments               = -np 8 example
     668
     669    output                  = example_$(machine).out
     670    error                   = example_$(machine).err
     671    log                     = example.log
     672
     673    should_transfer_files   = yes
     674    when_to_transfer_output = on_exit
     675    transfer_input_files    = example
     676
     677    # renommage du fichier de sortie en fonction du nom de la machine
     678    transfer_output_remaps = "example_$(machine).out=$(machine)/example_$(machine).out ; example_$(machine).err=$(machine)/example_$(machine).err"
     679
     680    # Spécifiez le nombre de slots (processus MPI) requis
     681    request_cpus            = 1
     682    request_memory          = 1024M
     683    request_disk            = 10240K
     684
     685    +Requirements           = machine =?= "$(machine)"
     686    +WantParallelSchedulingGroups = True
     687
     688    queue
     689}
     690
     691}}}
     692
     693
     694== Autre exemples ==
     695{{{
     696 more testprog01.sh
     697#! /bin/sh
     698echo "HT-condor testprog01"
     699echo "I'm process id $$ on" `hostname`
     700echo "This is sent to standard error" 1>&2
     701date
     702echo "Running as binary $0" "$@"
     703echo "My name (argument 1) is $1"
     704echo "My sleep duration (argument 2) is $2"
     705sleep $2
     706echo "Sleep of $2 seconds finished.  Exiting"
     707exit 0
     708}}}
     709
     710==== exemple d'un fichier de description de soumission: ====
     711{{{
     712more testprog01.submit
     713executable=testprog01.sh
     714universe=vanilla
     715arguments=Example.$(Cluster).$(Process) 100
     716output=results.output.$(Process)
     717error=results.error.$(Process)
     718log=results.log
     719notification=never
     720should_transfer_files=YES
     721when_to_transfer_output = ON_EXIT
     722queue
     723}}}
     724
     725==== exemple d'un fichier de description de soumission en sélectionnant !AlmaLinux9 comme Operating System:====
     726{{{
     727more testprog2.submit
     728executable=testprog01.sh
     729universe=vanilla
     730arguments=Example.$(Cluster).$(Process) 100
     731output=results.output.$(Process)
     732error=results.error.$(Process)
     733log=results.log
     734notification=never
     735should_transfer_files=YES
     736when_to_transfer_output = ON_EXIT
     737requirements = (OpSysAndVer =?= "AlmaLinux9")
     738queue
     739}}}
     740
     741Pour choisir Centos7: 
     742{{{
     743requirements = (OpSysAndVer =?= "CentOS7")
     744}}}
     745Pour choisir Fedora39: 
     746{{{
     747requirements = (OpSysAndVer =?= "Fedora39")
     748}}}
     749L'utilisateur définit lui-même le groupe auxquel il appartient via une instruction de type :
     750{{{
     751accounting_group = informatique
     752}}}