|
| 1 | +import { describe, expect, it } from 'vitest'; |
| 2 | +import { parseAirfoilDat, prepareImportedAirfoil } from './airfoilImport'; |
| 3 | + |
| 4 | +const CLARK_Y = `CLARK Y AIRFOIL |
| 5 | + 1.000000 0.000599 |
| 6 | + 0.990000 0.002969 |
| 7 | + 0.980000 0.005333 |
| 8 | + 0.970000 0.007687 |
| 9 | + 0.960000 0.010023 |
| 10 | + 0.940000 0.014624 |
| 11 | + 0.920000 0.019116 |
| 12 | + 0.900000 0.023502 |
| 13 | + 0.880000 0.027789 |
| 14 | + 0.860000 0.031974 |
| 15 | + 0.840000 0.036054 |
| 16 | + 0.820000 0.040024 |
| 17 | + 0.800000 0.043884 |
| 18 | + 0.780000 0.047628 |
| 19 | + 0.760000 0.051257 |
| 20 | + 0.740000 0.054767 |
| 21 | + 0.720000 0.058160 |
| 22 | + 0.700000 0.061433 |
| 23 | + 0.680000 0.064584 |
| 24 | + 0.660000 0.067605 |
| 25 | + 0.640000 0.070482 |
| 26 | + 0.620000 0.073206 |
| 27 | + 0.600000 0.075763 |
| 28 | + 0.580000 0.078145 |
| 29 | + 0.560000 0.080348 |
| 30 | + 0.540000 0.082371 |
| 31 | + 0.520000 0.084214 |
| 32 | + 0.500000 0.085877 |
| 33 | + 0.480000 0.087357 |
| 34 | + 0.460000 0.088643 |
| 35 | + 0.440000 0.089718 |
| 36 | + 0.420000 0.090566 |
| 37 | + 0.400000 0.091171 |
| 38 | + 0.380000 0.091521 |
| 39 | + 0.360000 0.091627 |
| 40 | + 0.340000 0.091508 |
| 41 | + 0.320000 0.091186 |
| 42 | + 0.300000 0.090680 |
| 43 | + 0.280000 0.090002 |
| 44 | + 0.260000 0.089084 |
| 45 | + 0.240000 0.087831 |
| 46 | + 0.220000 0.086143 |
| 47 | + 0.200000 0.083920 |
| 48 | + 0.180000 0.081069 |
| 49 | + 0.160000 0.077571 |
| 50 | + 0.140000 0.073436 |
| 51 | + 0.120000 0.068620 |
| 52 | + 0.100000 0.062998 |
| 53 | + 0.080000 0.056431 |
| 54 | + 0.060000 0.048757 |
| 55 | + 0.050000 0.044275 |
| 56 | + 0.040000 0.039128 |
| 57 | + 0.030000 0.033022 |
| 58 | + 0.020000 0.025374 |
| 59 | + 0.012000 0.017858 |
| 60 | + 0.008000 0.013735 |
| 61 | + 0.004000 0.008924 |
| 62 | + 0.002000 0.005803 |
| 63 | + 0.001000 0.003727 |
| 64 | + 0.000500 0.002339 |
| 65 | + 0.000000 0.000000 |
| 66 | + 0.000500 -0.004670 |
| 67 | + 0.001000 -0.005942 |
| 68 | + 0.002000 -0.007811 |
| 69 | + 0.004000 -0.010513 |
| 70 | + 0.008000 -0.014286 |
| 71 | + 0.012000 -0.016973 |
| 72 | + 0.020000 -0.020272 |
| 73 | + 0.030000 -0.022606 |
| 74 | + 0.040000 -0.024521 |
| 75 | + 0.050000 -0.026045 |
| 76 | + 0.060000 -0.027128 |
| 77 | + 0.080000 -0.028459 |
| 78 | + 0.100000 -0.029379 |
| 79 | + 0.120000 -0.029963 |
| 80 | + 0.140000 -0.030240 |
| 81 | + 0.160000 -0.030255 |
| 82 | + 0.180000 -0.030049 |
| 83 | + 0.200000 -0.029666 |
| 84 | + 0.220000 -0.029145 |
| 85 | + 0.240000 -0.028518 |
| 86 | + 0.260000 -0.027816 |
| 87 | + 0.280000 -0.027070 |
| 88 | + 0.300000 -0.026308 |
| 89 | + 0.320000 -0.025556 |
| 90 | + 0.340000 -0.024818 |
| 91 | + 0.360000 -0.024087 |
| 92 | + 0.380000 -0.023361 |
| 93 | + 0.400000 -0.022634 |
| 94 | + 0.420000 -0.021904 |
| 95 | + 0.440000 -0.021171 |
| 96 | + 0.460000 -0.020435 |
| 97 | + 0.480000 -0.019699 |
| 98 | + 0.500000 -0.018962 |
| 99 | + 0.520000 -0.018226 |
| 100 | + 0.540000 -0.017491 |
| 101 | + 0.560000 -0.016757 |
| 102 | + 0.580000 -0.016023 |
| 103 | + 0.600000 -0.015289 |
| 104 | + 0.620000 -0.014555 |
| 105 | + 0.640000 -0.013821 |
| 106 | + 0.660000 -0.013086 |
| 107 | + 0.680000 -0.012351 |
| 108 | + 0.700000 -0.011617 |
| 109 | + 0.720000 -0.010882 |
| 110 | + 0.740000 -0.010148 |
| 111 | + 0.760000 -0.009413 |
| 112 | + 0.780000 -0.008679 |
| 113 | + 0.800000 -0.007944 |
| 114 | + 0.820000 -0.007210 |
| 115 | + 0.840000 -0.006475 |
| 116 | + 0.860000 -0.005741 |
| 117 | + 0.880000 -0.005006 |
| 118 | + 0.900000 -0.004272 |
| 119 | + 0.920000 -0.003537 |
| 120 | + 0.940000 -0.002803 |
| 121 | + 0.960000 -0.002068 |
| 122 | + 0.970000 -0.001701 |
| 123 | + 0.980000 -0.001334 |
| 124 | + 0.990000 -0.000967 |
| 125 | + 1.000000 -0.000599 |
| 126 | +`; |
| 127 | + |
| 128 | +const E205 = `E205 (10.48%) |
| 129 | + 1.000000 0.000000 |
| 130 | + 0.996550 0.000390 |
| 131 | + 0.986490 0.001740 |
| 132 | + 0.970490 0.004270 |
| 133 | + 0.949160 0.007780 |
| 134 | + 0.922850 0.011960 |
| 135 | + 0.891750 0.016680 |
| 136 | + 0.856240 0.021990 |
| 137 | + 0.816840 0.027860 |
| 138 | + 0.774120 0.034190 |
| 139 | + 0.728660 0.040880 |
| 140 | + 0.681080 0.047770 |
| 141 | + 0.632040 0.054700 |
| 142 | + 0.582180 0.061470 |
| 143 | + 0.532170 0.067820 |
| 144 | + 0.482650 0.073420 |
| 145 | + 0.434100 0.077850 |
| 146 | + 0.386800 0.080810 |
| 147 | + 0.341010 0.082140 |
| 148 | + 0.296990 0.081770 |
| 149 | + 0.254960 0.079700 |
| 150 | + 0.215080 0.076060 |
| 151 | + 0.177640 0.071110 |
| 152 | + 0.143020 0.065070 |
| 153 | + 0.111570 0.058110 |
| 154 | + 0.083600 0.050400 |
| 155 | + 0.059370 0.042110 |
| 156 | + 0.039090 0.033440 |
| 157 | + 0.022920 0.024610 |
| 158 | + 0.010970 0.015890 |
| 159 | + 0.003310 0.007660 |
| 160 | + 0.000020 0.000550 |
| 161 | + 0.002330 -0.005060 |
| 162 | + 0.010650 -0.009880 |
| 163 | + 0.024190 -0.014200 |
| 164 | + 0.042910 -0.017760 |
| 165 | + 0.066690 -0.020530 |
| 166 | + 0.095340 -0.022520 |
| 167 | + 0.128640 -0.023780 |
| 168 | + 0.166270 -0.024360 |
| 169 | + 0.207830 -0.024350 |
| 170 | + 0.252900 -0.023840 |
| 171 | + 0.300970 -0.022920 |
| 172 | + 0.351490 -0.021680 |
| 173 | + 0.403880 -0.020210 |
| 174 | + 0.457510 -0.018590 |
| 175 | + 0.511740 -0.016890 |
| 176 | + 0.565910 -0.015160 |
| 177 | + 0.619380 -0.013450 |
| 178 | + 0.671490 -0.011800 |
| 179 | + 0.721600 -0.010230 |
| 180 | + 0.769110 -0.008760 |
| 181 | + 0.813430 -0.007400 |
| 182 | + 0.854000 -0.006140 |
| 183 | + 0.890340 -0.004970 |
| 184 | + 0.921950 -0.003800 |
| 185 | + 0.948600 -0.002520 |
| 186 | + 0.970170 -0.001250 |
| 187 | + 0.986350 -0.000360 |
| 188 | + 0.996510 -0.000030 |
| 189 | + 1.000000 0.000000 |
| 190 | +`; |
| 191 | + |
| 192 | +const NACA_2412 = `NACA 2412 |
| 193 | + 1.000000 0.001300 |
| 194 | + 0.950000 0.011400 |
| 195 | + 0.900000 0.020800 |
| 196 | + 0.800000 0.037500 |
| 197 | + 0.700000 0.051800 |
| 198 | + 0.600000 0.063600 |
| 199 | + 0.500000 0.072400 |
| 200 | + 0.400000 0.078000 |
| 201 | + 0.300000 0.078800 |
| 202 | + 0.250000 0.076700 |
| 203 | + 0.200000 0.072600 |
| 204 | + 0.150000 0.066100 |
| 205 | + 0.100000 0.056300 |
| 206 | + 0.075000 0.049600 |
| 207 | + 0.050000 0.041300 |
| 208 | + 0.025000 0.029900 |
| 209 | + 0.012500 0.021500 |
| 210 | + 0.000000 0.000000 |
| 211 | + 0.012500 -0.016500 |
| 212 | + 0.025000 -0.022700 |
| 213 | + 0.050000 -0.030100 |
| 214 | + 0.075000 -0.034600 |
| 215 | + 0.100000 -0.037500 |
| 216 | + 0.150000 -0.041000 |
| 217 | + 0.200000 -0.042300 |
| 218 | + 0.250000 -0.042200 |
| 219 | + 0.300000 -0.041200 |
| 220 | + 0.400000 -0.038000 |
| 221 | + 0.500000 -0.033400 |
| 222 | + 0.600000 -0.027600 |
| 223 | + 0.700000 -0.021400 |
| 224 | + 0.800000 -0.015000 |
| 225 | + 0.900000 -0.008200 |
| 226 | + 0.950000 -0.004800 |
| 227 | + 1.000000 -0.001300 |
| 228 | +`; |
| 229 | + |
| 230 | +describe('parseAirfoilDat', () => { |
| 231 | + it.each([ |
| 232 | + ['Clark Y', CLARK_Y, 'clarky.dat', 'CLARK Y AIRFOIL'], |
| 233 | + ['E205', E205, 'e205.dat', 'E205 (10.48%)'], |
| 234 | + ['NACA 2412', NACA_2412, 'naca2412.dat', 'NACA 2412'], |
| 235 | + ])('parses real Airfoil Tools %s data', (_label, text, fileName, expectedName) => { |
| 236 | + const parsed = parseAirfoilDat(text, fileName); |
| 237 | + |
| 238 | + expect(parsed.name).toBe(expectedName); |
| 239 | + expect(parsed.coordinates.length).toBeGreaterThan(20); |
| 240 | + |
| 241 | + const leIndex = parsed.coordinates.findIndex((point) => point.x === Math.min(...parsed.coordinates.map((p) => p.x))); |
| 242 | + expect(leIndex).toBeGreaterThan(0); |
| 243 | + expect(leIndex).toBeLessThan(parsed.coordinates.length - 1); |
| 244 | + |
| 245 | + expect(parsed.coordinates[0].surface).toBe('upper'); |
| 246 | + expect(parsed.coordinates[leIndex].surface).toBe('upper'); |
| 247 | + expect(parsed.coordinates.at(-1)?.surface).toBe('lower'); |
| 248 | + expect(parsed.coordinates[0].y).toBeGreaterThanOrEqual(-0.001); |
| 249 | + expect(parsed.coordinates.at(-1)?.y ?? 0).toBeLessThanOrEqual(0.001); |
| 250 | + }); |
| 251 | + |
| 252 | + it('falls back to the file name when the header is missing', () => { |
| 253 | + const parsed = parseAirfoilDat('1.0 0.0\n0.0 0.1\n1.0 -0.0\n', 'my-foil.dat'); |
| 254 | + expect(parsed.name).toBe('my foil'); |
| 255 | + }); |
| 256 | +}); |
| 257 | + |
| 258 | +describe('prepareImportedAirfoil', () => { |
| 259 | + it('uses repaneled output when a repaneler is provided', () => { |
| 260 | + const parsed = parseAirfoilDat(NACA_2412, 'naca2412.dat'); |
| 261 | + const imported = prepareImportedAirfoil(parsed, 160, () => [ |
| 262 | + { x: 1, y: 0.01 }, |
| 263 | + { x: 0, y: 0 }, |
| 264 | + { x: 1, y: -0.01 }, |
| 265 | + ]); |
| 266 | + |
| 267 | + expect(imported.coordinates).toEqual(parsed.coordinates); |
| 268 | + expect(imported.panels).toEqual([ |
| 269 | + { x: 1, y: 0.01, surface: 'upper' }, |
| 270 | + { x: 0, y: 0, surface: 'upper' }, |
| 271 | + { x: 1, y: -0.01, surface: 'lower' }, |
| 272 | + ]); |
| 273 | + }); |
| 274 | + |
| 275 | + it('falls back to raw coordinates when repaneling is unavailable', () => { |
| 276 | + const parsed = parseAirfoilDat(E205, 'e205.dat'); |
| 277 | + const imported = prepareImportedAirfoil(parsed, 160); |
| 278 | + |
| 279 | + expect(imported.panels).toEqual(parsed.coordinates); |
| 280 | + }); |
| 281 | +}); |
0 commit comments