2017-09-09 4 views
0

J'ai un programme de simulation de physique qui génère un fichier avec six colonnes, une pour l'heure, et cinq autres pour les propriétés physiques. J'ai besoin de faire un programme Fortran 90 qui lit ce fichier, et génère cinq fichiers avec deux colonnes, une pour l'heure et une autre pour une propriété physique. J'ai déjà utilisé F90 auparavant, mais je ne sais comment générer des fichiers et écrire dessus, mais je ne sais pas comment modifier un fichier et générer plus de fichiers avec les données d'un fichier.Comment diviser un fichier avec plusieurs colonnes en plusieurs fichiers avec deux colonnes chacun en utilisant Fortran 90

Je ne m'attends pas à avoir le problème résolu, je veux juste savoir où trouver des informations. Tout conseil sera utile.

I don't know a priori how many rows the program will generate

Répondre

0

La première étape est de lire les données. Dans les instructions suivantes, nous allons d'abord boucler le fichier et compter le nombre de lignes, nrows. Cette valeur sera utilisée pour allouer un tableau de données à la taille nécessaire. Nous revenons ensuite au début du fichier et lisons dans nos données dans une deuxième boucle. Déclarer une variable entière pour agir en tant que gestionnaire/référence de fichier.

  1. Déclarez un tableau allouable de réels (flottants) pour contenir les données.
  2. En boucle sur le fichier à count the number of lines in the file. Supprimer les lignes d'en-tête du compte. Allouer le tableau de données à la taille appropriée, (nrows,nvalues).
  3. Retour au début du fichier. Répétez la boucle sur chacune des lignes, en lisant toutes les valeurs de la ligne dans votre tableau de données.
  4. Fermez le fichier.

L'étape suivante est de créer 5 nouveaux fichiers, contenant chacun le temps et l'une des 5 mesures de propriété:

  1. boucle sur chacune des 5 propriétés contenues dans data.
  2. Pour chaque propriété j th, ouvrez un nouveau fichier.
  3. Parcourez le tableau data en écrivant l'heure et la propriété j th sur une nouvelle ligne.
  4. Fermez le fichier.

Voici le code de travail, vous pouvez utiliser ou modifier selon vos besoins:

program SO 
    implicit none 
    integer :: i, j, nrows, nvalues, funit, ios 
    real, allocatable, dimension(:,:) :: data 
    character(len=10), dimension(5) :: outfiles 

    !! begin 
    nvalues = 5 
    nrows = 0 
    open(newunit=funit, file='example.txt', status='old', iostat=ios) 
    if (ios /= 0) then 
     print *, 'File could not be opened.' 
     call exit 
    else 
     do 
      read(funit,*,iostat=ios) 
      if (ios == 0) then 
       nrows = nrows + 1 
      elseif (ios < 0) then    !! End of file (EOF). 
       exit       !! The 'exit' stmt breaks out of the loop. 
      else        !! Error if > 0. 
       print *, 'Read error at line ', nrows + 1 
       call exit()      !! The 'exit' intrinsic ends the program. 
      endif        !! We we may pass an optional exit code. 
     enddo 
    endif 

    nrows = nrows - 1       !! 'nrows-1': Remove column headers from count. 
    if (allocated(data)) deallocate(data)  !! This test follows standard "best practices". 
    allocate(data(nrows,nvalues+1)) 

    rewind(funit) 
    read(funit, *)        !! Skip column headers. 
    do i = 1,nrows 
     read(funit, *) data(i,:)    !! Read values into array. 
    enddo 
    close(funit) 

    !! Output file names. 
    outfiles = ['prop1.txt', 'prop2.txt', 'prop3.txt', 'prop4.txt', 'prop5.txt'] 
    do j = 1,nvalues 
     open(newunit=funit, file=outfiles(j), status='replace', iostat=ios) 
     if (ios /= 0) then 
      print *, 'Could not open output file: ',outfiles(j) 
      call exit() 
     endif 
     write(funit,"(a)") "time   "//outfiles(j)(1:5) 
     do i = 1,nrows 
      write(funit,"(f0.0,t14,es14.6)") data(i,1), data(i,j+1) 
     enddo 
     close(funit) 
    enddo 
end program SO 
0

Voici un exemple qui est pas été testé ... Il est un peu d'une approche de la maternelle, mais ça peut être utile. Vous pouvez éviter complètement le tableau 6, mais il est souvent préférable d'avoir les variables sous forme de tableaux séparés, car cela permet de mieux vectoriser avec une disposition de mémoire contiguë. On pourrait aussi lire ceux dans les 6 tableaux, et éviter le tableau 6xN.

PROGRAM ABC 
IMPLICIT NONE 
REAL, DIMENSION(:,:) :: My_File_Data 
REAL, DIMENSION(:) :: My_Data1 
REAL, DIMENSION(:) :: My_Data2 
REAL, DIMENSION(:) :: My_Data3 
REAL, DIMENSION(:) :: My_Data4 
REAL, DIMENSION(:) :: My_Data5 
REAL, DIMENSION(:) :: My_Data6 
INTEGER    :: Index, LUN, I, IO_Status 

OPEN(NEWUNIT=LUN, FILE='abc.dat') 
Index = 0 
FirstPass: DO WHILE(.TRUE.) 
    READ(UNIT=LUN,*, IO_Status) 
    IF(IO_Status /= 0) EXIT 
    Index = Index + 1 
ENDDO FirstPass 

REWIND(LUN) 
ALLOCATE(My_File_Data(Index)) 
ALLOCATE(My_Data1(Index)) 
ALLOCATE(My_Data2(Index)) 
ALLOCATE(My_Data3(Index)) 
ALLOCATE(My_Data4(Index)) 
ALLOCATE(My_Data5(Index)) 
ALLOCATE(My_Data6(Index)) 

SecondPass: DO I = 1, Index 
    READ(UNIT=LUN,*) My_File_Data(:,I) 
    Index = Index + 1 
ENDDO SecondPass 

DO I = 1, Index 
    Data1(I) = My_File_Data(1,I) 
ENDDO 

! What follows is more elegant... 
Data2(:) = My_File_Data(2,:) !Where the first (:) is redundant... It seems more readable, but there are some reasons not to use it... (LTR) 
Data3 = My_File_Data(3,:) 
Data4 = My_File_Data(4,:) 
Data5 = My_File_Data(5,:) 
Data6 = My_File_Data(6,:) 

DEALLOCATE(My_File_Data) 

!Etc 
0

Toutes les autres réponses veulent lire tout en même temps. Je pense que c'est trop dérangeant.Premièrement, je vérifierais si j'avais même besoin de Fortran pour cela. La commande Linux cut peut être utilisée très efficacement ici. Par exemple, si vos données sont séparées par des virgules, vous pouvez simplement utiliser

for i in {1..5}; do 
    cut -d, -f1,$((i+1)) data.txt > data${i}.txt; 
done 

pour faire le tout.

Si vous avez besoin Fortran, voici comment je vais à ce sujet:

  1. ouvrir tous les fichiers
  2. Dans une boucle permanente, lu dans toute la ligne à la fois.
  3. Si vous rencontrez une erreur, c'est probablement EOF, alors quittez la boucle
  4. Ecrivez les données dans les fichiers de sortie.

Voici quelques code de base:

program split 

    implicit none 
    integer :: t, d(5), u_in, u_out(5) 
    integer :: i 
    integer :: ios 

    open(newunit=u_in, file='data.txt', status="old", action="read") 

    open(newunit=u_out(1), file='temperature.txt', status='unknown', action='write') 
    open(newunit=u_out(2), file='pressure.txt', status='unknown', action='write') 
    open(newunit=u_out(3), file='pair_energy.txt', status='unknown', action='write') 
    open(newunit=u_out(4), file='ewald_energy.txt', status='unknown', action='write') 
    open(newunit=u_out(5), file='pppm_energy.txt', status='unknown', action='write') 

    read(u_in, *) ! omit the column names 
    write(u_out(1), *) "Time  Temperature"  
    write(u_out(2), *) "Time  Pressure"  
    write(u_out(3), *) "Time  Pair Energy"  
    write(u_out(4), *) "Time  Ewald Energy"  
    write(u_out(5), *) "Time  PPPM Energy" 

    do 
     read(u_in, *, iostat=ios) t, d 
     if (ios /= 0) exit 
     do i = 1, 5 
      write(u_out(i), *) t, d(i) 
     end do 
    end do 

    close(u_in) 
    do i = 1, 5 
     close(u_out(i)) 
    end do 

end program split 

Vive