Jump to content
ManuelC

Executar um programa externo e actualizar uns ficheiros de texto

Recommended Posts

ManuelC

Boa tarde, desde já obrigado pela atenção.

Não sei se alguém me pode ajudar.

Vou descrever o que pretendo que o meu código faça em cada intervalo do loop que em seguida descrevo:

PRIMEIRO PAÇO DO LOOP:

1 - Correr um programa externo;

2 - Abrir um dos ficheiros de texto do output desse programa (tsr_seg6.txt)

Exemplo do ficheiro tsr_seg6.txt ( os valores estão separados por espaços):

---------------------------------------------------------------------------------------------------------------------

CE-QUAL-W2

Lagoa das Furnas - 1 Ramo

Default hydraulic coefficients

Model run at 16:51:57 on 09/12/13

JDAY DLT PO4

1 0.07 0.02

2 0.06 0.03

3 0.05 0.01

3 – Copiar o primeiro valor que se encontra na coluna PO4 (0.02)

4 – Abrir um outro ficheiro do modelo (ctr_tr3.npt)

Exemplo do ficheiro ctr_tr3.npt (os valores estão separados por espaços):

---------------------------------------------------------------------------------------------------------------------

JDAY DLT PO4

1 0.08 0.01

2 0.05 0.02

3 0.01 0.05

4 – substituir o primeiro valor que se encontra na coluna PO4 pelo valor obtido no ficheiro (tsr_seg6.txt).

5- voltar a correr o modelo

6 – No paço seguinte do loop faço o mesmo mas desta vez é o segundo valor do ficheiro tsr_seg6.txt que vai substituir o segundo valor do ficheiro ctr_tr3.npt . Volto a correr o modelo…

7 - No paço seguinte do loop faço o mesmo mas desta vez é o terceiro valor do ficheiro tsr_seg6.txt que vai substituir o terceiro valor do ficheiro ctr_tr3.npt Volto a correr o modelo…

Tenho que fazer isto 20000 vezes….

Escrevi o seguinte código em Python que não funciona porque não consigo substituir os valores no ficheiro ctr_tr3.npt em cada intervalo do loop.

import numpy as np
import sys, string, os
import shutil

 
N=5
for i in xrange(N):
  os.chdir( 'c:\\Users\\Hidraulica\\Desktop\\w2furnas' )
  os.system( ""C:\\Users\\Hidraulica\\Desktop\\w2furnas\\w2.exe"' )
  shutil.move('tsr_1_seg6.opt', 'tsr_1_seg6.txt')

  data = np.genfromtxt('c:\\Users\\Hidraulica\\Desktop\\w2furnas\\tsr_1_seg6.txt', skip_header=11, names=True)
  input=np.array(data['PO4'])

  trib =np.genfromtxt('c:\\Users\\Hidraulica\\Desktop\\w2furnas\\ctr_tr3.npt', skip_header=2, names=True)
  out=np.array(trib['PO4'])
  out[i]= input[i]*0.75

   with open('c:\\Users\\Hidraulica\\Desktop\\w2furnas\\ctr_tr3.npt','w') as fw:
   fw.write(' '.join(out))

Obrigado

Manuel

Edited by ManuelC
GeSHi

Share this post


Link to post
Share on other sites
Pedro C.

Olá Manuel,

Geralmente quando a tarefa se torna dantesca vale a pena separar tudo em funções pequenas bem controláveis. Os passos que me parecem essenciais são:

1) Correr programa

2) Recuperar o valor de um ficheiro

3) Escreve-lo noutro (e recomeça o ciclo)

Penso que não precisas de todas as bibliotecas que estás a importar e por um motivo que não compreendo estás a multiplicar 0.75 pelo teu array. De qualquer maneira seguindo os passos dados acima e lendo e escrevendo ficheiros à maneira antiga terás qualquer coisa como isto.

import numpy as np
import os

def corre_processo(wdir,path):
 os.chdir(wdir) # ESTABELECO A DIRECTORIA DE TRABALHO
 os.system(path) # CORRO O PROCESSO EXTERIOR
 return True

def ler_ficheiro(path,header_number=5):
 fid = open(path,'r') # ESTOU A ABRIR O FICHEIRO PARA LEITURA
 header = [] # VARIAVEL QUE GUARDA O HEADER
 for i in xrange(header_number):
	  header.append(fid.readline()) # ESTOU A PASSAR PARA UMA LISTA
 data = np.loadtxt(fid) # ESTOU A PASSAR A MATRIZ PARA UMA VARIAVEL
 fid.close() # FECHO O FICHEIRO
 return header,data

def escrever_ficheiro(path,header,data):
 fid = open(path,'w') # ABRO O FICHEIRO PARA ESCRITA (w)
 for i in xrange(len(header)):
	  fid.write(header[i]) # EsCREVO O HEADER
 np.savetxt(fid,data,fmt='%10.3f') # ESTE FMT SIGNIFICA 10 CARACTERES COM 3 CASAS DECIMAIS
 fid.close() # FECHO O FICHEIRO
 return True

def recuperar_valor(path,index,column=2,header_number=5):
 header,data = ler_ficheiro(path,header_number)
 return data[index,column]

def troca_valor(value,index,path,column=2,header_number=5):
 """
 NAO E UMA OPERACAO VULGAR TROCAR UM VALOR NO FICHEIRO. NO TEU CASO (ASCII
 ou TEXTO) E PRECISO LER O FICHEIRO NA TOTALIDADE PARA VARIAVEIS, TROCAR
 O QUE TENS A TROCAR E VOLTAR A ESCREVER PARA A MESMA LOCALIZACAO.
 """
 header,data = ler_ficheiro(path,header_number) # LEIO O FICHEIRO
 data[index,column] = value # TROCO O VALOR NO INDEX PRETENDIDO
 escrever_ficheiro(path,header,data) # ESCREVO O FICHEIRO NO MESMO CAMINHO
 return True

def ciclo_principal(numero,wdir,ipath,opath,exepath,column=2,header_number=5):
 """
 SEGUINDO O PROCEDIMENTO PEDIDO POR TI...
 """
 for i in xrange(numero):
	  corre_processo(wdir,wdir+exepath) # 1 - Correr um programa externo;
	  value = recuperar_valor(wdir+ipath,i,column,header_number) # 2,3,4 -3 – Copiar o primeiro...
	  troca_valor(value,i,wdir+opath,column,header_number) # 4 – substituir o primeiro valor que...
	  print 'terminado CICLO ',i # ESTOU SO A AVISAR O UTILIZADOR QUE TERMINOU A VOLTA
 print 'TERMINADO' # ESTOU A AVISAR QUE O PROGRAMA TERMINOU
 return True

numero = 5 # numero de ciclos (loops que pretendes)
wdir = 'c:\\Users\\Hidraulica\\Desktop\\' # directoria de trabalho (onde tudo se processa)
ipath = 'tsr_seg6.txt' # ficheiro de onde se retira valores
opath = 'ctr_tr3.npt' # ficheiro onde se troca valores
exepath = 'w2.exe' # ficheiro do executavel
column = 2 # coluna onde se passam as trocas (python comeca em zero)
header_number = 5 # tamanho do header

ciclo_principal(numero,wdir,ipath,opath,exepath,column,header_number) # CORRER PROGRAMA

Penso que os comentários devem chegar para se compreender o código na totalidade. Não o testei mas à partida deve funcionar. Se não compreenderes alguma coisa avisa. Boa sorte.

Ah, uma coisa que é importante é a formatação dos ficheiro. Estou a usar um comando do numpy chamado savetxt que basicamente escreve números como os tem na variável para um ficheiro. No teu caso lê as três colunas para uma matrix "n por 3" e depois salva a matriz da mesma maneira. Por defeito penso que isto é feito como nomenclatura cientifica. Para evitar isto eu dei-lhe uma formatação especifica (o parâmetro "fmt"). Para mexeres com o "fmt" basta pensares na numeração que estás à espera e quantos caracteres (inclusive o ponto de separação decimal) vais precisar por cada numero. Assim se precisares de 10 caracteres, no máximo, e uma precisão de 3 casas decimais metes '%10.3f' e o numero 0.2343423543, por exemplo apareceria:

.....0.234 (o espaço em branco antes do número, que represento aqui como pontos) é importante porque aparece também no ficheiro visto que pedimos 10 caracteres mas o número em causa só tem 5).

Isto ajuda a que os teus ficheiro se mantenham organizados.

Qualquer linguagem conseguirá lidar com diferentes tipos de dados. Agora se precisares mesmo que a primeira coluna seja de inteiros e as outras decimais (talvez por causa do executável que estás a correr) tens de começar a fabricar as tuas próprias funções de escrita (eu pelo menos não conheço nenhuma que faça já isto). A título de exemplo se eu no array numpy "data" tivesse uma matriz com 5 linhas e 3 colunas poderia escrever desta maneira:

for i in xrange(5):
 fid.write('%i	 %10.3f	 %10.3f'%(data[i,0],data[i,1],data[i,2]))

E assim estaria a precisar à coluna a maneira como queria o meu ficheiro formatado.

Share this post


Link to post
Share on other sites
ManuelC

Muito obrigado, pela ajuda.

Consigo perceber o teu código. Vou usá-lo daqui em diante como um exemplo, para tudo o que tiver que fazer em python.

Sem querer parecer abusador, há duas questões que ainda não sei bem como resolver.

1- o ficheiro 'tsr_seg6.txt' é um ficheiro que se encontra inicialmente como 'tsr_seg6.opt'. é gerado pelo modelo cada vez que este corre. Não tenho que lhe alterar a extensão?. Por isso utilizei: shutil.move('tsr_1_seg6.opt', 'tsr_1_seg6.txt').

2- tenho que multiplicar cada valor que copio por 0.75. Pode ser aqui?

data[index,column] = value *0.75

Obrigado mais uma vez.

Manuel

Share this post


Link to post
Share on other sites
icemonster2

1- o ficheiro 'tsr_seg6.txt' é um ficheiro que se encontra inicialmente como 'tsr_seg6.opt'. é gerado pelo modelo cada vez que este corre. Não tenho que lhe alterar a extensão?. Por isso utilizei: shutil.move('tsr_1_seg6.opt', 'tsr_1_seg6.txt').

Não seria mais facil abrires o ficheiro.opt normalmente? A informação é a mesma. Nesse caso estar com a extensão .txt ou .opt é a mesma coisa por isso se não precisares de ter o ficheiro como texto, podes fazer isso

Share this post


Link to post
Share on other sites
ManuelC

Depois de todo o trabalho que tive e acima de tudo que tu tiveste não vou desistir de colocar isto a funcionar.

Ao correr o código obtenho o seguinte erro:

data = np.loadtxt(fid) # ESTOU A PASSAR A MATRIZ PARA UMA VARIAVEL

File "C:\Python27\lib\site-packages\numpy\lib\npyio.py", line 796, in loadtxt

items = [conv(val) for (conv, val) in zip(converters, vals)]

ValueError: could not convert string to float: Lagoa

O ficheiro tsr_seg6.opt tem 11 linhas com frases que não interessam antes de aparecerem os headers de cada coluna. Podes ajudar-me com isto? Não percebo com é que posso alterar a função ler_ficheiro...para que esta, tenho isto em consideração...

Exemplo do ficheiro tsr_seg6.opt

------------------------------------------------------------------------------

Version 3.6

CE-QUAL-W2

Lagoa das Furnas - 1 Ramo

Default hydraulic coefficients

Default light absorption/extinction coeffients

Lagoa das Furnas

Simulação ANO 2008

GDHI, Setembro de 2009

Model run at 13:33:37 on 09/13/13

JDAY DLT PO4

1 0.07 0.02

2 0.06 0.03

3 0.05 0.01

---------------------------------------------------------------------

Obrigado

Edited by ManuelC

Share this post


Link to post
Share on other sites
Pedro C.

Sim, é nessa linha de código o sitio onde deve ser feita a multiplicação.

E tal como disse o icemonster2 os ficheiros de texto (ASCII) não têm, geralmente, associação com o nome do próprio ficheiro ao qual pertence a extensão. A extensão serve para processos externos ao ficheiro como por exemplo o windows saber, por defeito, que deve abrir todos os ficheiros terminados em .docx com o word. Ou então que todos os ficheiros terminados em .exe são processos executáveis sem necessidade de outro software (haja parcimónia na interpretação desta afirmação:)). Podes até tentar enganar estes programas alterando a extensão dos teus ficheiros e por vezes até vão ocorrer extensões que são comuns a mais de um software e um deles não vai conseguir abrir o ficheiro porque não tem o formato necessário. Um exemplo disto é a extensão .MOD. É uma extensão que dá para um ficheiro de música no entanto tinha outro software aqui que lia esses ficheiros como informação de um modelo matemático (MODelo). Um procurava um formato ascii outro binário. Ambos pretendiam abrir o ficheiro e o mais chato é que era o errado que estava predefinido para abrir essa extensão com o duplo click do rato.

São as linhas de cabeçalho ou header. Um dos parâmetros do código é "header_number" em que meti 5 porque era o que aparecia no exemplo do teu primeiro post. Basicamente é o número de linhas do teu ficheiro que queres guardar para escrever novamente. Agora esse header_number está a ser utilizados para tanto o ficheiro tsr_seg6.opt como para o ctr_tr3.npt. Se ambos tiverem o mesmo número de linhas de cabeçalho basta mudar o parâmetro inicial. Caso contrário tens de mexer no código. Nomeadamente aqui:

def ciclo_principal(numero,wdir,ipath,opath,exepath,column=2,header_number=11,header_number_2=5): # FIZ UPDATE
        """
        SEGUINDO O PROCEDIMENTO PEDIDO POR TI...
        """
        for i in xrange(numero):
                 corre_processo(wdir,wdir+exepath)
                 value = recuperar_valor(wdir+ipath,i,column,header_number)
                 troca_valor(value,i,wdir+opath,column,header_number_2) # FIZ UPDATE
                 print 'terminado CICLO ',i
        print 'TERMINADO'
        return True

numero = 5
wdir = 'c:\\Users\\Hidraulica\\Desktop\\'
ipath = 'tsr_seg6.txt'
opath = 'ctr_tr3.npt'
exepath = 'w2.exe'
column = 2
header_number = 11 # tamanho do header do ficheiro de input (tsr_seg6.opt)
header_number_2 = 5 # tamanho do header do ficheiro de troca de valores (ctr_tr3.npt) FIZ UPDATE

ciclo_principal(numero,wdir,ipath,opath,exepath,column,header_number,header_number_2) # FIZ UPDATE

Está indicado no código as linhas onde fiz um update. Na prática temos uma variável nova de entrada chamada "header_number_2" que é o número de linhas de cabeçalho do ficheiro "ctr". A variável "header_number" agora só dá informação do número de linha para o ficheiro "tsr". Actualizei:

1) a linha onde está criada a variável (e onde tens de meter o valor correcto).

2) a linha de chamada da função ciclo_principal (onde meti mais este novo parâmetro)

3) a linha de inicio da função ciclo_principal (onde tenho de meter mais o novo parâmetro de entrada)

4) a linha da chamada da função troca_valor (dentro do ciclo_principal) onde tenho de dizer que a variável de tamanho de cabeçalho passou a ser "header_number_2".

Edited by Pedro C.

Share this post


Link to post
Share on other sites
ManuelC

Obrigado pela ajuda, está perfeito.

Nunca aprendi tanto em tão pouco tempo.

Com os melhores cumprimentos

Manuel Almeida

Edited by ManuelC

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.