1

I want to convert a Tecplot file into an array but I don't know how to do it. Here is an extract of the file:

TITLE = "Test"
VARIABLES = "x" "y"
ZONE I=18,  F=BLOCK
0.1294538E-01  0.1299554E-01  0.1303974E-01  0.1311453E-01  0.1313446E-01  0.1319080E-01
0.1322709E-01  0.1323904E-01  0.1331753E-01  0.1335821E-01  0.1340850E-01  0.1347061E-01
0.1350522E-01  0.1358302E-01  0.1359585E-01  0.1363086E-01  0.1368307E-01  0.1370017E-01
0.1377368E-01  0.1381353E-01  0.1386420E-01  0.1391916E-01  0.1395847E-01  0.1400548E-01
0.1405659E-01  0.1410006E-01  0.1417611E-01  0.1419149E-01  0.1420015E-01  0.1428019E-01
0.1434745E-01  0.1436735E-01  0.1439856E-01  0.1445430E-01  0.1448778E-01  0.1454278E-01

I want to retrieve x and y as array. So x should contain:

0.1294538E-01  0.1299554E-01  0.1303974E-01  0.1311453E-01  0.1313446E-01  0.1319080E-01
0.1322709E-01  0.1323904E-01  0.1331753E-01  0.1335821E-01  0.1340850E-01  0.1347061E-01
0.1350522E-01  0.1358302E-01  0.1359585E-01  0.1363086E-01  0.1368307E-01  0.1370017E-01

And y should contain:

0.1377368E-01  0.1381353E-01  0.1386420E-01  0.1391916E-01  0.1395847E-01  0.1400548E-01
0.1405659E-01  0.1410006E-01  0.1417611E-01  0.1419149E-01  0.1420015E-01  0.1428019E-01
0.1434745E-01  0.1436735E-01  0.1439856E-01  0.1445430E-01  0.1448778E-01  0.1454278E-01

I have seen np.loadtxt('./file.dat', skiprows=3) but I can't find the right options to say read all numbers and separate every 18 figures.

Also, I started something like this with no luck:

with open(file, 'r') as a:
    for line in a.readlines():
        A = re.match(r'TITLE = (.*$)', line, re.M | re.I)
        B = re.match(r'VARIABLES = (.*$)', line, re.M | re.I)
        C = re.match(r'ZONE (.*$)', line, re.M | re.I)
        if A or B or C:
                continue
        else:
            D = re.match(r'(.*$)', line, re.M | re.I)
            value = "{:.16}".format(D.group(1))
            y.append(float(value))
            j = j+1
            if j == 18:
                j = 0

Thank you for your help!

tupui
  • 5,738
  • 3
  • 31
  • 52
  • In you example, each row has exactly 6 columns. Will that always be the case, or will you have to handle cases where the final row has fewer fields than the previous rows? For example, what does the file look like if `I=17`? – Warren Weckesser Aug 17 '16 at 16:48
  • No it is not always 6 columns. If `I = 17`, it means that `x` will consist in the 17th first numbers. – tupui Aug 17 '16 at 16:54

2 Answers2

1

Solved it with the last option:

arrays = []
with open(file, 'r') as a:
    for line in a.readlines():
        A = re.match(r'TITLE = (.*$)', line, re.M | re.I)
        B = re.match(r'VARIABLES = (.*$)', line, re.M | re.I)
        C = re.match(r'ZONE (.*$)', line, re.M | re.I)
        if A or B or C:
                continue
        else:
            arrays.append([float(s) for s in line.split()])
arrays = np.concatenate(arrays)

len_var = len(arrays)
x = arrays[0:len_var/2-1]
y = arrays[len_var/2:len_var]

This answer was of great help for the creation of the array: https://stackoverflow.com/a/4289557/6522112 and also this one for traveling the array: https://stackoverflow.com/a/952952/6522112. But in the end using np.concatenate seems better.

For the record, I created this function in order to read any file:

def tecplot_reader(file, nb_var):
    """Tecplot reader."""
    arrays = []
    with open(file, 'r') as a:
        for idx, line in enumerate(a.readlines()):
            if idx < 3:
                continue
            else:
                arrays.append([float(s) for s in line.split()])

    arrays = np.concatenate(arrays)
    output = np.split(arrays, nb_var)

    return output

So just do: x, y, z = tecplot_reader('./file', 3)

Community
  • 1
  • 1
tupui
  • 5,738
  • 3
  • 31
  • 52
0

This maybe useful to others so I will post it here. I have modified @Y0da's code so that his function can output the result for multiple detectors in one go. That is to say you have a tecplot file of the form

 Title="test"
 Variables = "var1", "var2", "var3" ,
 "var4","var5"
 Zone T ="Detector =           1 "
  0.000000000000000E+000  0.000000000000000E+000  0.000000000000000E+000
  0.000000000000000E+000  0.000000000000000E+000
   50.0000000000000       0.000000000000000E+000  0.000000000000000E+000
  0.000000000000000E+000  0.000000000000000E+000

 Zone T ="Detector =           2 "
  0.000000000000000E+000  0.000000000000000E+000  0.000000000000000E+000
  0.000000000000000E+000  0.000000000000000E+000
   50.0000000000000       0.000000000000000E+000  0.000000000000000E+000
  0.000000000000000E+000  0.000000000000000E+000

Note that the format is intentionally ugly. That is because if your output is from a FORTRAN code, and you write to a file without explicit formatting, there is a finite number of columns used.

import re
import numpy as np
import matplotlib.pyplot as plt

path = 'path_to_file/file.plt'

def tecplot_reader(file, nb_var):
    """Tecplot reader for multiple detectors"""
    detectors = []
    with open(file, 'r') as a:
        lines = a.readlines()
        for idx, line in enumerate(lines):
            if (idx <= 3) : continue                        # If this is header line skip
            detec = re.match(r' ZONE (.*$)', line, re.M | re.I) # Determine if this is a new detector line
            if (type(detec)!=type(None)):                       # If this is a new detector line
                detector = int(line[20:-3])-1               # The detector index is between column 30 and -3 characters (counting starts at 1 for the output file)
                detectors.append([])                        # Add a new list for this detector
                continue
            else:
                detectors[detector].append([float(s) for s in line.split()])

    for i,detec in enumerate(detectors):    # For each detector
        detectors[i] = np.concatenate(np.array(detec))                            # Concatinate into one array
        detectors[i] = np.split(np.array(detectors[i]),len(detectors[i])/nb_var)  # Break into correct rows (each row has nb_vars)
        detectors[i] = np.hsplit(np.array(detectors[i]),nb_var)                   # Break up vertically
    return detectors

What this returns is a list of the variables for each detector.

arie64
  • 572
  • 6
  • 10
  • This would have been extremely useful for me, but I get an `local variable 'detector' referenced before assignment` error when using it. `nb_var` should be the number of variables I wanna read, right? – TomCho Feb 12 '19 at 23:02