How do I interpret the .dat file to use some values as input?
Question:
I developed a code to interpret airfoil .dat files, in which I use one file at a time and do some mathematical operations.
Currrently, I define three values at the beginning of the code: the chord, the alpha (angle of attack), and the z-translation. Then I use those values to perform operations on a long series of data points read from the file. However, rather than hard coding the chord and alpha, I would like to read them from the first two lines of the .dat file. Once the inputs are used, I would like to save only the list of (modified) points to a new .dat file, discarding the parameters from the beginning of the original file.
I have attached my code and the .dat file I want to create. The idea is to use the two initial lines as input to use in math operations and save in the New.dat file with only the modified points.
import math
chord = 1.138
alpha = -3.427960
z_trans = -0.25*chord
with open('Airfoils/ffaw3241.dat') as data:
mylist = [line.rstrip('n') for line in data]
zs = []
ys = []
for line in mylist:
if len(line) > 1:
z, y = line.split(None, 2)
zs.append(float(z))
ys.append(float(y))
data = tuple(zip(zs, ys))
print(chord)
#Scale the foil with provided chord
zs = []
ys = []
for point in data:
z, y = point
zs.append(float(z)*chord)
ys.append(float(y)*chord)
data = tuple(zip(zs, ys))
#print (data)
#rotate the airfoil with provided alpha
oz, oy = (0, 0)
zs = []
ys = []
for point in data:
z, y = point
zs.append(oz + math.cos(math.radians(alpha)) * (float(z) - oz) - math.sin(math.radians(alpha)) * (float(y) - oy))
ys.append(oy + math.sin(math.radians(alpha)) * (float(z) - oz) + math.cos(math.radians(alpha)) * (float(y) - oy))
data = tuple(zip(zs, ys))
#translate the airfoil to the center of pressure (25% of chord)
zs = []
ys = []
for point in data:
z, y = point
zs.append(round (float(z),5) + z_trans)
#ys.append(round (float(y),5) + y_trans)
data = tuple(zip(zs, ys))
with open("Airfoils/ffaw3241New.dat", "w") as output:
output.write(str(data))
1.138 #chord
-3.427960 #alpha
1.00000 -0.00360
0.98338 -0.00140
0.96457 0.00096
0.94365 0.00311
0.92072 0.00466
0.89589 0.00528
0.86928 0.00473
0.84102 0.00291
0.81124 -0.00030
0.78010 -0.00514
0.74772 -0.01183
0.71428 -0.02024
0.67994 -0.03015
0.64485 -0.04127
0.60918 -0.05308
0.57311 -0.06502
0.53681 -0.07651
0.50045 -0.08706
0.46422 -0.09623
0.42827 -0.10370
0.39279 -0.10938
0.35794 -0.11324
0.32389 -0.11531
0.29081 -0.11567
0.25885 -0.11441
0.22817 -0.11167
0.19891 -0.10754
0.17121 -0.10213
0.14522 -0.09560
0.12104 -0.08811
0.09880 -0.07985
0.07861 -0.07104
0.06056 -0.06188
0.04474 -0.05258
0.03122 -0.04334
0.02006 -0.03427
0.01133 -0.02550
0.00507 -0.01700
0.00130 -0.00903
0.00000 0.00000
0.00130 0.00956
0.00507 0.02005
0.01133 0.03033
0.02006 0.04087
0.03122 0.05135
0.04474 0.06170
0.06056 0.07176
0.07861 0.08139
0.09880 0.09044
0.12104 0.09873
0.14522 0.10613
0.17121 0.11247
0.19891 0.11764
0.22817 0.12153
0.25885 0.12409
0.29081 0.12526
0.32389 0.12504
0.35794 0.12350
0.39279 0.12076
0.42827 0.11696
0.46422 0.11223
0.50045 0.10670
0.53681 0.10052
0.57311 0.09382
0.60918 0.08672
0.64485 0.07935
0.67994 0.07187
0.71428 0.06441
0.74772 0.05707
0.78010 0.04996
0.81124 0.04316
0.84102 0.03673
0.86928 0.03070
0.89589 0.02510
0.92072 0.01996
0.94365 0.01529
0.96457 0.01107
0.98338 0.00727
1.00000 0.00391
Answers:
You can use the next
function to "manually" consume the next item from a generator, such as a file. This is a handy way to grab the first (or in this case, first two) items before iterating through the rest. Here’s a fairly simple way to do it, based on your code:
with open('input.dat') as file:
chord = next(file).split()[0]
alpha = next(file).split()[0]
data = []
for line in file:
line = line.split()
z = float(line[0])
y = float(line[1])
data.append((z, y))
This could be further condensed with a couple of list comprehensions (okay, technically one list comprehension and one generator expression):
with open('input.dat') as file:
chord = next(file).split()[0]
alpha = next(file).split()[0]
data = [tuple(float(i) for i in line.split()) for line in file]
Personally I think this is a case where I’d use map
for the float
conversion, but tastes differ. map
is handy when all you want to do to multiple things is apply the same function to all of them.
with open('input.dat') as file:
chord = next(file).split()[0]
alpha = next(file).split()[0]
data = [tuple(map(float, line.split())) for line in file]
Notes:
- All these produce a list of tuples, rather than a tuple of tuples as in your code. It could be easily converted, but I think this makes more sense.
- There’s no need to first strip newlines if you’re also going to use
split()
, since that automatically removes any trailing whitespace.
- If your file may contain blank (newline-only) lines, you can add
if not line.isspace()
at the end of the list comprehension to skip those.
I developed a code to interpret airfoil .dat files, in which I use one file at a time and do some mathematical operations.
Currrently, I define three values at the beginning of the code: the chord, the alpha (angle of attack), and the z-translation. Then I use those values to perform operations on a long series of data points read from the file. However, rather than hard coding the chord and alpha, I would like to read them from the first two lines of the .dat file. Once the inputs are used, I would like to save only the list of (modified) points to a new .dat file, discarding the parameters from the beginning of the original file.
I have attached my code and the .dat file I want to create. The idea is to use the two initial lines as input to use in math operations and save in the New.dat file with only the modified points.
import math
chord = 1.138
alpha = -3.427960
z_trans = -0.25*chord
with open('Airfoils/ffaw3241.dat') as data:
mylist = [line.rstrip('n') for line in data]
zs = []
ys = []
for line in mylist:
if len(line) > 1:
z, y = line.split(None, 2)
zs.append(float(z))
ys.append(float(y))
data = tuple(zip(zs, ys))
print(chord)
#Scale the foil with provided chord
zs = []
ys = []
for point in data:
z, y = point
zs.append(float(z)*chord)
ys.append(float(y)*chord)
data = tuple(zip(zs, ys))
#print (data)
#rotate the airfoil with provided alpha
oz, oy = (0, 0)
zs = []
ys = []
for point in data:
z, y = point
zs.append(oz + math.cos(math.radians(alpha)) * (float(z) - oz) - math.sin(math.radians(alpha)) * (float(y) - oy))
ys.append(oy + math.sin(math.radians(alpha)) * (float(z) - oz) + math.cos(math.radians(alpha)) * (float(y) - oy))
data = tuple(zip(zs, ys))
#translate the airfoil to the center of pressure (25% of chord)
zs = []
ys = []
for point in data:
z, y = point
zs.append(round (float(z),5) + z_trans)
#ys.append(round (float(y),5) + y_trans)
data = tuple(zip(zs, ys))
with open("Airfoils/ffaw3241New.dat", "w") as output:
output.write(str(data))
1.138 #chord
-3.427960 #alpha
1.00000 -0.00360
0.98338 -0.00140
0.96457 0.00096
0.94365 0.00311
0.92072 0.00466
0.89589 0.00528
0.86928 0.00473
0.84102 0.00291
0.81124 -0.00030
0.78010 -0.00514
0.74772 -0.01183
0.71428 -0.02024
0.67994 -0.03015
0.64485 -0.04127
0.60918 -0.05308
0.57311 -0.06502
0.53681 -0.07651
0.50045 -0.08706
0.46422 -0.09623
0.42827 -0.10370
0.39279 -0.10938
0.35794 -0.11324
0.32389 -0.11531
0.29081 -0.11567
0.25885 -0.11441
0.22817 -0.11167
0.19891 -0.10754
0.17121 -0.10213
0.14522 -0.09560
0.12104 -0.08811
0.09880 -0.07985
0.07861 -0.07104
0.06056 -0.06188
0.04474 -0.05258
0.03122 -0.04334
0.02006 -0.03427
0.01133 -0.02550
0.00507 -0.01700
0.00130 -0.00903
0.00000 0.00000
0.00130 0.00956
0.00507 0.02005
0.01133 0.03033
0.02006 0.04087
0.03122 0.05135
0.04474 0.06170
0.06056 0.07176
0.07861 0.08139
0.09880 0.09044
0.12104 0.09873
0.14522 0.10613
0.17121 0.11247
0.19891 0.11764
0.22817 0.12153
0.25885 0.12409
0.29081 0.12526
0.32389 0.12504
0.35794 0.12350
0.39279 0.12076
0.42827 0.11696
0.46422 0.11223
0.50045 0.10670
0.53681 0.10052
0.57311 0.09382
0.60918 0.08672
0.64485 0.07935
0.67994 0.07187
0.71428 0.06441
0.74772 0.05707
0.78010 0.04996
0.81124 0.04316
0.84102 0.03673
0.86928 0.03070
0.89589 0.02510
0.92072 0.01996
0.94365 0.01529
0.96457 0.01107
0.98338 0.00727
1.00000 0.00391
You can use the next
function to "manually" consume the next item from a generator, such as a file. This is a handy way to grab the first (or in this case, first two) items before iterating through the rest. Here’s a fairly simple way to do it, based on your code:
with open('input.dat') as file:
chord = next(file).split()[0]
alpha = next(file).split()[0]
data = []
for line in file:
line = line.split()
z = float(line[0])
y = float(line[1])
data.append((z, y))
This could be further condensed with a couple of list comprehensions (okay, technically one list comprehension and one generator expression):
with open('input.dat') as file:
chord = next(file).split()[0]
alpha = next(file).split()[0]
data = [tuple(float(i) for i in line.split()) for line in file]
Personally I think this is a case where I’d use map
for the float
conversion, but tastes differ. map
is handy when all you want to do to multiple things is apply the same function to all of them.
with open('input.dat') as file:
chord = next(file).split()[0]
alpha = next(file).split()[0]
data = [tuple(map(float, line.split())) for line in file]
Notes:
- All these produce a list of tuples, rather than a tuple of tuples as in your code. It could be easily converted, but I think this makes more sense.
- There’s no need to first strip newlines if you’re also going to use
split()
, since that automatically removes any trailing whitespace. - If your file may contain blank (newline-only) lines, you can add
if not line.isspace()
at the end of the list comprehension to skip those.