IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Fortran Discussion :

Imbrication de subroutines sur plusieurs niveaux


Sujet :

Fortran

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Par défaut Imbrication de subroutines sur plusieurs niveaux
    Bonjour à toutes et à tous,

    Je travaille sur un code en Fortran 90 issu d'un code en Fortran 77. Je n'avais pas eu à utiliser de propriétés spécifiques du Fortran 90 jusqu'alors car j'ai gardé la même structure de gestion mémoire initialement utilisée en 77 :

    On définit dans le programme principal un unique tableau T à une dimension. On appelle ensuite une subroutine avec en argument les (T(1),T(n1),....,T(ni),....) qui seront l'ensemble des tableaux utilisés par la suite. les ni sont des entiers correspondant à la taille des tableaux. Par exemple pour si le tableau 1 est de dimension 2 et de taille taille M*N (connue) alors n1=M*N et ainsi de suite. Cette première subroutine appelée contenant tous les tableaux sera une sorte de nouveau programme principal à partir duquel on travaillera. Ainsi toute la mémoire nécessaire au programme est allouée dès le début, et il n'y a aucun conflit.

    Cependant, mon programme est devenu beaucoup plus conséquent que le programme initial et possède des subroutines imbriquées sur 5 niveaux. Il y a une trentaine de tableaux à appeler, sans compter les variables simples. L'appel des subroutines est donc devenu extrêmement lourd et source d'erreurs quand je dois ajouter ou retirer des tableaux lors de la modification de ce programme. J'aimerais donc profiter de Fortran 95 pour réorganiser mon programme de manière plus "intelligente" compte tenu des nouveaux outils à ma disposition. J'ai épluché tous les cours de l'IDRIS (qui m'ont appris beaucoup de chose mais qui sont un peu compliqués à mon niveau pour ce qui m'intéresse) mais je n'arrive pas à trouver la solution qui m'aidera. J'ai saisi le principe de l'allocation dynamique dans les grandes lignes mais, dans mon programme, seules trois variables (m,n,k) lues en données d'entrées utilisateurs suffisent à définir toutes les dimensions de mes tableaux, donc je ne suis pas sûr que ce soit la bonne méthode.

    Pourriez-vous m'aiguiller sur cet aspect où me proposer d'autres solutions pour réorganiser ce programme et avoir une gestion de mémoire plus appropriée afin (entre autres) de ne plus avoir à mettre tous les arguments en appel dans les subroutines s'il-vous-plait ?

    Merci d'avance !

    Mathieu

  2. #2
    Membre éprouvé
    Homme Profil pro
    Ingénieur modélisation aérodynamique
    Inscrit en
    Juillet 2009
    Messages
    105
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur modélisation aérodynamique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juillet 2009
    Messages : 105
    Par défaut
    Bonjour,
    tu peux par exemple regrouper les variables dans des modules puis y faire appel via USE dans les routines où tu en as besoin.
    Le problème avec cette méthode est que les variables ne sont plus déclarées explicitement dans chaque subroutines ce qui peut être une source de confusion et d'erreur. Par ex :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    MODULE TABLEAU
    IMPLICIT NONE
     
    ! déclare ici tous tes tableaux
       INTEGER :: T1(1:8)
       REAL*8, ALLOCATABLE :: T1(:,:)
    !  ...
     
    END MODULE TABLEAU
    puis dans les subroutines où tu en a besoin :

    Les modifications que tu fais sur les variables définies dans le module sont stockées comme pour un passage par argument. De même l'allocation dynamique ne pose pas de problème (tant que tu déclare le tableau ALLOCATABLE dans ton module). Par contre, à la différence d'un passage par argument, tu es obligé d'utiliser le même nom de variable.

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Par défaut
    Citation Envoyé par bobbyboy Voir le message
    Par contre, à la différence d'un passage par argument, tu es obligé d'utiliser le même nom de variable.
    Il est possible de renommer une variable provenant d'un module. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    module MonModule
       integer T(10,10)
    end module
    program ABC
       use MonModule, A => T
       ...
       A = ...
    Fort utile quand on restructure un programme existant pour éviter des conflits de noms...

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Par défaut
    Tout d'abord merci à tous les deux pour votre aide.

    Si je comprend bien, en utilisant USE, j'ai tous mes tableaux contenu dans un seul MODULE, et si je modifie ces tableaux dans une subroutine, ils seront actualisés dans le MODULE, que je pourrai ensuite réutiliser dans une autre subroutine, etc., sans avoir à tout mettre en argument dans mes appels et subroutines, ou à tout déclarer depuis le début puisqu'on est en allocation dynamique de mémoire. Est-ce bien cela?

    Pourrais-tu rajouter dans ton exemple la forme qu'aurait alors le CALL XXX() et SUROUTINE XXX() avec les déclarations de variables associée s'il-te-plait (j'ai mal saisi la notion de variables qui ne sont plus déclarées explicitement... :/)

    En tout cas j'y vois déjà plus clair, merci !

    Mathieu

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Par défaut
    Si je comprends bien ta demande, tu devrais aboutir à quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    module Tableaux
      implicit none
      integer              :: m,n,k ! devraient être accessible par requête 
                                    ! (size(), ubound(),...) mais les modifs de 
                                    ! code seront probablement plus simples 
                                    ! si m,n,k sont directement disponibles...
      integer, allocatable :: T1(:,:)
      integer, allocatable :: T2(:,:)
      integer, allocatable :: T3(:,:)
    end module
    program Inconnu
      use Tableaux
      implicit none
      ...
      read(...) m, n, k
      allocate(T1(m,n), T2(m,k), T3(n,k))
      ...
      call ProchaineEtape()
      ...
    end program
    subroutine ProchaineEtape
      use Tableaux
      implicit none
      ...
      T1(...) = ...
      ...

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Par défaut
    C'est exactement ca. Je vais essayer de réorganiser mon code sur cette base. Je laisse le sujet ouvert en attendant d'avoir testé cette méthode.

    Merci encore !

    Mathieu

  7. #7
    Membre éprouvé
    Homme Profil pro
    Ingénieur modélisation aérodynamique
    Inscrit en
    Juillet 2009
    Messages
    105
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur modélisation aérodynamique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juillet 2009
    Messages : 105
    Par défaut
    Ah ! j'ignorais qu'on pouvais renomer localement une variable d'un module ! En sachant cela plus tôt, ca m'aurai éviter bien des casses-têtes !
    En tout cas merci Sylvain pour la précision.

    Pour en revenir au problème de mathieu1, voici un exemple très simple mais représentatif de ce que tu peux faire :
    (les fichiers sont à titre indicatif, tu peux tout regrouper dans un seul fichier mais je trouve que ça clarifie bien la structure du programme)

    Fichier "module_variables.f90" : ce sont tes variables
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    MODULE VARIABLES
    IMPLICIT NONE
     
       INTEGER :: N
       REAL*8 :: TAB_STAT(1:10)
       REAL*8, ALLOCATABLE :: TAB_DYNA(:)
     
    END MODULE VARIABLES
    Fichier "main.f90"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    PROGRAM MAIN
    USE VARIABLES
    IMPLICIT NONE
     
       ! Remplissage du tableau statique par 1,2,...,10
       CALL REMPLIR_TAB()
     
       ! On défini N et on alloue le tableau dynamique
       N = 10
       ALLOCATE(TAB_DYNA(1:N))
     
       ! On copie les valeurs du tableau statique dans le tableau dynamique
       CALL COPIE_TAB()
     
       ! On affiche les 2 tableaux
       CALL AFFICHE_TAB()
     
    END PROGRAM
    Fichier "routines.f90"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    ! ***************************
    ! * remplissage d'un tableau *
    ! ***************************
    SUBROUTINE REMPLIR_TAB
    USE VARIABLES
    IMPLICIT NONE
       INTEGER :: I
       DO I = 1 , N
          TAB_STAT(I) = REAL(I)
       ENDDO
       RETURN
    END SUBROUTINE REMPLIR_TAB
     
    ! **********************
    ! * Copie d'un tableau *
    ! **********************
    SUBROUTINE COPIE_TAB()
    USE VARIABLES
    IMPLICIT NONE
       TAB_DYNA(1:N) = TAB_STAT(1:N)
       RETURN
    END SUBROUTINE COPIE_TAB
     
    ! **************************
    ! * Affichage des tableaux *
    ! **************************
    SUBROUTINE AFFICHE_TAB()
    USE VARIABLES
    IMPLICIT NONE
       INTEGER :: I
       DO I = 1 , N
          WRITE(*,*) TAB_STAT(I) , TAB_DYNA(I)
       ENDDO
       RETURN
    END SUBROUTINE AFFICHE_TAB
    La compilation se fait par (ici avec gcc mais peu importe) :
    gcc -c module_variables.f90
    gcc -c routines.f90
    gcc -c main.f90
    gcc -o main *.o

    (Si tu as beaucoup de fichiers, une solution pour bien définir les dépendances entre les sous-programmes est de faire un makefile dont tu peux trouver moulte exemples sur le net)

    L'exemple est un peu débile mais tu vois que les tableaux sont manipulés en ne déclarant que les variables locales dans les subroutines (par ex l'indice I) et aucune déclaration dans le programme principal. De plus on ne passe aucun argument dans les subroutines. (sous réserves d'erreurs de frappes de ma part, ça doit normalement tourner)

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Par défaut
    J'aime les exemples "débiles" comme tu dis, c'est ceux que l'on comprend le mieux !

    Je pense qu'avec votre aide à tous les deux, je suis bien parti pour avoir un programme largement allégé qui me permettra de continuer le développement plus facilement. Je suis en train de modifier mon programme avec vos conseils.

    J'ai encore une question concernant ton exemple : On peut donc utiliser toutes ces fonctionnalités avec un tableau statique (ici TAB_STAT), même s'il y a des subroutines. ca ne pose pas de conflits dans la gestion de la mémoire ?
    Je connais mes dimensions par une entrée utilisateur en tout début de programme, qui ne changera pas jusqu'à la fin de ce dernier.
    Quel est le mieux dans mon cas : statique ou dynamique?

    Merci !

  9. #9
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Par défaut
    Citation Envoyé par mathieu1 Voir le message
    statique ou dynamique?
    Dynamique.

    Pour qu'une déclaration soit statique, il faut que tu connaisses les bornes à la compilation, alors que les tiennes ne sont connues qu'au début de l'exécution.

    Finalement, il y a une autre piste que tu pourrais utiliser en F90+ pour ton problème. Ça consiste à ne pas utiliser de module, mais à mettre toutes les routines dans une section "contains" à la fin du programme principale. Ces routines ont alors accès directement aux variables du programme principal. Suffit donc de mettre tes tableaux allocatables dans le programme principal et tout fonctionne... C'est une structure légère fort agréable pour les petits projets (moins de 2000 lignes), mais qui devient limitée à grande échelle.

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Par défaut
    Très bien, je suis en train de tester la solution des modules. Comme mon projet est de taille moyenne, je pense terminer cette méthode et voire ce que ca donne. J'essaierai ensuite la solution avec CONTAINS.

    Merci pour toute cette aide !

    Mathieu

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Par défaut
    Le programme réorganisé avec un module contenant les variables allouées en dynamique tourne parfaitement. C'est quand même bien moins lourd.

    Merci à tous pour votre aide rapide et précise.

    Mathieu

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. un menu géré avec javascript sur plusieurs niveaux (logique)
    Par polothentik dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 02/07/2008, 14h23
  2. [ZF 1.5] Suppression en cascade sur plusieurs niveaux
    Par Janitrix dans le forum Zend_Db
    Réponses: 12
    Dernier message: 12/05/2008, 02h38
  3. [SQL] Affichage sur plusieurs niveaux
    Par oim dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 10/12/2007, 14h52
  4. [Hibernate] Héritage sur plusieurs niveaux
    Par srvremi dans le forum Hibernate
    Réponses: 2
    Dernier message: 31/05/2006, 18h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo