Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

ManuelC

Executar um programa externo e actualizar uns ficheiros de texto

Mensagens Recomendadas

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

Editado por ManuelC
GeSHi

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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

Editado por ManuelC

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros 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".

Editado por Pedro C.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
ManuelC

Obrigado pela ajuda, está perfeito.

Nunca aprendi tanto em tão pouco tempo.

Com os melhores cumprimentos

Manuel Almeida

Editado por ManuelC

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.