Usando variáveis if e shell dentro de um script awk

0

Estou tentando obter dados de um arquivo assim:

  6   6   1   0
  0.1166667E+02  0.4826611E-09  0.4826611E-09  0.3004786E-09  0.5000000E-15
  1.000000000000000E-004
  CAR 
 system-001                       
     10.51965443    -34.96542345  301      1.95329810      1.00000000
-15.558  0.1631E+01  0.1597E+02
-15.407  0.1661E+02  0.1779E+02
-15.255  0.4253E+01  0.1990E+02
-15.104  0.0000E+00  0.2000E+02
-14.952  0.0000E+00  0.2000E+02
 -3.884  0.0000E+00  0.2000E+02
 -3.732  0.0000E+00  0.2000E+02
 -3.581  0.0000E+00  0.2000E+02
 -3.429  0.0000E+00  0.2000E+02
 -3.277  0.8214E-03  0.2000E+02
 -3.126  0.3543E+00  0.2002E+02
  1.726  0.1019E+01  0.4386E+02
  1.877  0.5581E+00  0.4399E+02
  2.029  0.0000E+00  0.4400E+02
  2.181  0.0000E+00  0.4400E+02
  2.332  0.0000E+00  0.4400E+02
  2.484  0.0000E+00  0.4400E+02
  2.636  0.0000E+00  0.4400E+02
  2.787  0.0000E+00  0.4400E+02
  2.939  0.0000E+00  0.4400E+02
  3.090  0.0000E+00  0.4400E+02
  3.242  0.0000E+00  0.4400E+02
  3.394  0.0000E+00  0.4400E+02
  3.545  0.0000E+00  0.4400E+02
  3.697  0.0000E+00  0.4400E+02
  3.849  0.0000E+00  0.4400E+02
  4.000  0.0000E+00  0.4400E+02
  4.152  0.6271E-01  0.4400E+02
  4.303  0.4520E+01  0.4433E+02
  4.455  0.5040E+01  0.4511E+02

Eu quero levar sempre a quarta coluna da linha 6 (1.95329810 neste caso), então procure por seu valor mais próximo nas linhas a seguir, da primeira coluna (1.877 neste caso). Isso só para referenciamento, após fundar isso, quero extrair a próxima linha que sua segunda coluna é diferente de zero (4.152).

Então eu gostaria de obter 1.95329810 e 4.152 como saída, para que eu possa subtraí-los e obter:

band_gap=4.152-$fermi_energy

Ao considerar a resposta do @DopeGhoti, usei o código dele com uma declaração if:

#!/bin/bash
fermi_energy=$(awk 'NR==6 {printf $4}' DOSCAR-62.4902421.st)
awk -f go.awk DOSCAR-62.4902421.st

Onde o arquivo go.awk é:

BEGIN { 
test=0
}
NF == 3 && test == 0 && $2 != "0.0000E+00" {
   keptvalue=$1
}
NF == 3 && test == 0 && $2 == "0.0000E+00" {
   #print keptvalue
   test=1
}
NF == 3 && test == 1 && $2 != "0.0000E+00" {
   if ( sqrt(($fermi_energy-$1)**2) < 0.5 ) 
   {
       print $1
       test=0
   }
}

Mas acho que não é o jeito certo de usar variáveis bash dentro de um script awk.

P.D. Caso você esteja se perguntando , os dados representam os cálculos da Densidade de estados do elétrons de um óxido. A primeira coluna representa as energias do elétron, a segunda a quantidade do elétron nesse nível de energia. Portanto, ao procurar o próximo valor não '0.0000E + 00' desde o nível mais próximo da Energia Fermi , podemos calcular a energia necessária para fazer os elétrons saltarem e conduzirem eletricidade. (Metais têm gap zero, portanto não precisam de entrada de energia para conduzir eletricidade)

    
por Joshua Salazar 28.02.2018 / 00:44

2 respostas

3

A resposta abaixo faz várias alterações na sua técnica.

  1. Faça tudo em um único programa awk em vez de dois. Você pode fazer isso porque sua segunda execução lida apenas com linhas após a linha 6:

  2. Atribua corretamente o valor de fermi_energy da linha 6.

  3. Não é mais necessário verificar se há NF==3 porque todas linhas após a linha 6 atendem a esse critério.

  4. Eliminar a variável test e, em vez disso, vamos manter uma guia em execução da diferença mínima entre fermi_energy e $1 . Para isso, vamos criar uma variável min que inicialmente terá um valor ridiculamente grande, garantido para falhar no primeiro teste. Também atribuiremos nomes compreensíveis às outras variáveis e imprimiremos apenas um resultado, após testar todas as linhas do arquivo.

  5. Substitua seu teste de valor absoluto pesado computacionalmente por um teste de zero de luz computacionalmente.

  6. Observe que awk suporta notação científica de ponto flutuante. Por exemplo, em um comando printf , pode-se usar o formato %E . Como de costume, consulte a página man ou seu mecanismo de pesquisa favorito para saber mais.

  7. Tudo isso feito sem nenhuma compreensão da física de partículas, então eu posso ter algo errado. Perdão. Se assim for, espero que pelo menos isso te coloque no caminho certo.

    awk '
        BEGIN  { min=1000 ; jump_energy="INIT" }
        function abs(v) {return v < 0 ? -v : v}
        NR==6 {fermi_energy=$4}
        NR>6 {
            if (jump_energy != 0) {
                this_diff=abs(fermi_energy-$1)
                if (this_diff < min) {
                    min=this_diff
                    energy_level=0
                    jump_energy=0
                    getline
                }
            }
            if (jump_energy == 0  && $2 != "0.0000E+00") {
                energy_level=$1
                jump_energy=$2
            }
        }
        END {
            printf "  Fermi Energy: %f\n  Energy Level: %f\n  Jump Energy: %E\n", fermi_energy, energy_level, jump_energy
        }'
    
por 28.02.2018 / 04:12
0
awk 'NR == 6 { fe = $4 }
     NR > 6 && $1 > fe && $2 > 0 { print fe, $1; exit }' file

Para os dados de entrada fornecidos em file , isso produzirá

1.95329810 4.152

O script awk ignora as cinco primeiras linhas de entrada. Na linha seis, ele seleciona o quarto campo e o atribui à variável fe (menor que "energia de Fermi".

O código então assume que os valores na coluna um estão aumentando e quando o primeiro desses valores da primeira coluna atinge um valor acima do valor armazenado em fe , e se a segunda coluna é diferente de zero, ela é impressa fe e o valor da primeira coluna e sai.

Infelizmente, não compreendo completamente o seu segmento de código mais longo, pois não há explicação sobre o que você realmente deseja fazer.

    
por 06.03.2018 / 10:53

Tags