@@ -1021,8 +1021,18 @@ def _write58(fh, dset, mode='add', _filename=None, force_double=True):
1021
1021
raise Exception ('Error writing data-set #58' )
1022
1022
1023
1023
1024
- def _extract58 (block_data ):
1025
- """Extract function at nodal DOF - data-set 58."""
1024
+ def _extract58 (block_data , header_only = False ):
1025
+ """
1026
+ Extract function at nodal DOF - data-set 58.
1027
+
1028
+ :param header_only: False (default). If True the header data will be
1029
+ extracted, only (useful with large files).
1030
+ """
1031
+
1032
+
1033
+
1034
+
1035
+
1026
1036
dset = {'type' : 58 , 'binary' : 0 }
1027
1037
try :
1028
1038
binary = False
@@ -1067,70 +1077,78 @@ def _extract58(block_data):
1067
1077
'z_axis_axis_units_lab' ]))
1068
1078
# Body
1069
1079
# split_data = ''.join(split_data[13:])
1070
- if binary :
1071
- split_data = b'' .join (block_data .splitlines (True )[13 :])
1072
- if dset ['byte_ordering' ] == 1 :
1073
- bo = '<'
1074
- else :
1075
- bo = '>'
1076
- if (dset ['ord_data_type' ] == 2 ) or (dset ['ord_data_type' ] == 5 ):
1077
- # single precision - 4 bytes
1078
- values = np .asarray (struct .unpack ('%c%sf' % (bo , int (len (split_data ) / 4 )), split_data ), 'd' )
1079
- else :
1080
- # double precision - 8 bytes
1081
- values = np .asarray (struct .unpack ('%c%sd' % (bo , int (len (split_data ) / 8 )), split_data ), 'd' )
1080
+ if header_only :
1081
+ # If not reading data, just set placeholders
1082
+ dset ['x' ] = None
1083
+ dset ['data' ] = None
1082
1084
else :
1083
- values = []
1084
- split_data = block_data .decode ('utf-8' , errors = 'replace' ).splitlines (True )[13 :]
1085
- if (dset ['ord_data_type' ] == 2 ) or (dset ['ord_data_type' ] == 5 ):
1086
- for line in split_data [:- 1 ]: # '6E13.5'
1087
- values .extend ([float (line [13 * i :13 * (i + 1 )]) for i in range (len (line ) // 13 )])
1088
- else :
1089
- line = split_data [- 1 ]
1090
- values .extend ([float (line [13 * i :13 * (i + 1 )]) for i in range (len (line ) // 13 ) if line [13 * i :13 * (i + 1 )]!= ' ' ])
1091
- elif ((dset ['ord_data_type' ] == 4 ) or (dset ['ord_data_type' ] == 6 )) and (dset ['abscissa_spacing' ] == 1 ):
1092
- for line in split_data : # '4E20.12'
1093
- values .extend ([float (line [20 * i :20 * (i + 1 )]) for i in range (len (line ) // 20 )])
1094
- elif (dset ['ord_data_type' ] == 4 ) and (dset ['abscissa_spacing' ] == 0 ):
1095
- for line in split_data : # 2(E13.5,E20.12)
1096
- values .extend (
1097
- [float (line [13 * (i + j ) + 20 * (i ):13 * (i + 1 ) + 20 * (i + j )]) \
1098
- for i in range (len (line ) // 33 ) for j in [0 , 1 ]])
1099
- elif (dset ['ord_data_type' ] == 6 ) and (dset ['abscissa_spacing' ] == 0 ):
1100
- for line in split_data : # 1E13.5,2E20.12
1101
- values .extend ([float (line [0 :13 ]), float (line [13 :33 ]), float (line [33 :53 ])])
1102
- else :
1103
- raise Exception ('Error reading data-set #58b; not proper data case.' )
1104
-
1105
- values = np .asarray (values )
1106
- # values = np.asarray([float(str) for str in split_data],'d')
1107
- if (dset ['ord_data_type' ] == 2 ) or (dset ['ord_data_type' ] == 4 ):
1108
- # Non-complex ordinate data
1109
- if (dset ['abscissa_spacing' ] == 0 ):
1110
- # Uneven abscissa
1111
- dset ['x' ] = values [:- 1 :2 ].copy ()
1112
- dset ['data' ] = values [1 ::2 ].copy ()
1113
- else :
1114
- # Even abscissa
1115
- n_val = len (values )
1116
- min_val = dset ['abscissa_min' ]
1117
- d = dset ['abscissa_inc' ]
1118
- dset ['x' ] = min_val + np .arange (n_val ) * d
1119
- dset ['data' ] = values .copy ()
1120
- elif (dset ['ord_data_type' ] == 5 ) or (dset ['ord_data_type' ] == 6 ):
1121
- # Complex ordinate data
1122
- if (dset ['abscissa_spacing' ] == 0 ):
1123
- # Uneven abscissa
1124
- dset ['x' ] = values [:- 2 :3 ].copy ()
1125
- dset ['data' ] = values [1 :- 1 :3 ] + 1.j * values [2 ::3 ]
1085
+ if binary :
1086
+ try :
1087
+ split_data = b'' .join (block_data .splitlines (True )[13 :])
1088
+ if dset ['byte_ordering' ] == 1 :
1089
+ bo = '<'
1090
+ else :
1091
+ bo = '>'
1092
+ if (dset ['ord_data_type' ] == 2 ) or (dset ['ord_data_type' ] == 5 ):
1093
+ # single precision - 4 bytes
1094
+ values = np .asarray (struct .unpack ('%c%sf' % (bo , int (len (split_data ) / 4 )), split_data ), 'd' )
1095
+ else :
1096
+ # double precision - 8 bytes
1097
+ values = np .asarray (struct .unpack ('%c%sd' % (bo , int (len (split_data ) / 8 )), split_data ), 'd' )
1098
+ except :
1099
+ raise Exception ('Potentially wrong data format (common with binary files from some commercial softwares). Try using pyuff.fix_58b() to fix your file. For more information, see https://github.com/ladisk/pyuff/issues/61' )
1126
1100
else :
1127
- # Even abscissa
1128
- n_val = len (values ) / 2
1129
- min_val = dset ['abscissa_min' ]
1130
- d = dset ['abscissa_inc' ]
1131
- dset ['x' ] = min_val + np .arange (n_val ) * d
1132
- dset ['data' ] = values [0 :- 1 :2 ] + 1.j * values [1 ::2 ]
1133
- del values
1101
+ values = []
1102
+ split_data = block_data .decode ('utf-8' , errors = 'replace' ).splitlines (True )[13 :]
1103
+ if (dset ['ord_data_type' ] == 2 ) or (dset ['ord_data_type' ] == 5 ):
1104
+ for line in split_data [:- 1 ]: # '6E13.5'
1105
+ values .extend ([float (line [13 * i :13 * (i + 1 )]) for i in range (len (line ) // 13 )])
1106
+ else :
1107
+ line = split_data [- 1 ]
1108
+ values .extend ([float (line [13 * i :13 * (i + 1 )]) for i in range (len (line ) // 13 ) if line [13 * i :13 * (i + 1 )]!= ' ' ])
1109
+ elif ((dset ['ord_data_type' ] == 4 ) or (dset ['ord_data_type' ] == 6 )) and (dset ['abscissa_spacing' ] == 1 ):
1110
+ for line in split_data : # '4E20.12'
1111
+ values .extend ([float (line [20 * i :20 * (i + 1 )]) for i in range (len (line ) // 20 )])
1112
+ elif (dset ['ord_data_type' ] == 4 ) and (dset ['abscissa_spacing' ] == 0 ):
1113
+ for line in split_data : # 2(E13.5,E20.12)
1114
+ values .extend (
1115
+ [float (line [13 * (i + j ) + 20 * (i ):13 * (i + 1 ) + 20 * (i + j )]) \
1116
+ for i in range (len (line ) // 33 ) for j in [0 , 1 ]])
1117
+ elif (dset ['ord_data_type' ] == 6 ) and (dset ['abscissa_spacing' ] == 0 ):
1118
+ for line in split_data : # 1E13.5,2E20.12
1119
+ values .extend ([float (line [0 :13 ]), float (line [13 :33 ]), float (line [33 :53 ])])
1120
+ else :
1121
+ raise Exception ('Error reading data-set #58b; not proper data case.' )
1122
+
1123
+ values = np .asarray (values )
1124
+ # values = np.asarray([float(str) for str in split_data],'d')
1125
+ if (dset ['ord_data_type' ] == 2 ) or (dset ['ord_data_type' ] == 4 ):
1126
+ # Non-complex ordinate data
1127
+ if (dset ['abscissa_spacing' ] == 0 ):
1128
+ # Uneven abscissa
1129
+ dset ['x' ] = values [:- 1 :2 ].copy ()
1130
+ dset ['data' ] = values [1 ::2 ].copy ()
1131
+ else :
1132
+ # Even abscissa
1133
+ n_val = len (values )
1134
+ min_val = dset ['abscissa_min' ]
1135
+ d = dset ['abscissa_inc' ]
1136
+ dset ['x' ] = min_val + np .arange (n_val ) * d
1137
+ dset ['data' ] = values .copy ()
1138
+ elif (dset ['ord_data_type' ] == 5 ) or (dset ['ord_data_type' ] == 6 ):
1139
+ # Complex ordinate data
1140
+ if (dset ['abscissa_spacing' ] == 0 ):
1141
+ # Uneven abscissa
1142
+ dset ['x' ] = values [:- 2 :3 ].copy ()
1143
+ dset ['data' ] = values [1 :- 1 :3 ] + 1.j * values [2 ::3 ]
1144
+ else :
1145
+ # Even abscissa
1146
+ n_val = len (values ) / 2
1147
+ min_val = dset ['abscissa_min' ]
1148
+ d = dset ['abscissa_inc' ]
1149
+ dset ['x' ] = min_val + np .arange (n_val ) * d
1150
+ dset ['data' ] = values [0 :- 1 :2 ] + 1.j * values [1 ::2 ]
1151
+ del values
1134
1152
except :
1135
1153
raise Exception ('Error reading data-set #58b' )
1136
1154
return dset
@@ -1484,3 +1502,66 @@ def prepare_58(
1484
1502
1485
1503
1486
1504
return dataset
1505
+
1506
+
1507
+ def fix_58b (filename ,fixed_filename = None ):
1508
+ """
1509
+ Opens the UFF file, fixes a common formatting issue and saves the fixed file.
1510
+ Specifically, it fixes the instance, when closing ' -1' of the dataset is on its own line, and not right after the data.
1511
+
1512
+ :param filename: filename of the UFF file to be fixed
1513
+ :param filename: filename to write the fixed UFF file, if None, the fixed file will be saved as 'filename_fixed.uff'
1514
+ """
1515
+
1516
+ if not os .path .exists (filename ):
1517
+ raise Exception ('Filename does not exist' )
1518
+ try :
1519
+ # Open the file in binary read mode
1520
+ with open (filename , 'rb' ) as fh :
1521
+ data = fh .read ()
1522
+ except Exception as e :
1523
+ raise Exception (f'Cannot access the file { filename } : { e } ' )
1524
+ else :
1525
+ try :
1526
+ lines = data .splitlines (keepends = True )
1527
+
1528
+ # Fix 1: Adjust ending ' -1' line
1529
+ if len (lines ) >= 1 and lines [- 1 ].strip () == b'-1' :
1530
+ if len (lines ) >= 2 :
1531
+ # Move ' -1' up to the end of the previous line
1532
+ prev_line = lines [- 2 ].rstrip (b'\r \n ' )
1533
+ prev_line += b' -1' + lines [- 1 ][- 1 :] # Keep the newline character
1534
+ lines [- 2 ] = prev_line
1535
+ lines .pop () # Remove the last line
1536
+ else :
1537
+ pass
1538
+
1539
+ # Fix 2: Adjust 'data\n -1\n -1\n data' patterns
1540
+ i = 0
1541
+ while i < len (lines ) - 3 :
1542
+ if (lines [i + 1 ].strip () == b'-1' and lines [i + 2 ].strip () == b'-1' ):
1543
+ # Move ' -1' from lines[i+1] to the end of lines[i]
1544
+ data_line = lines [i ].rstrip (b'\r \n ' ) # Remove newline characters
1545
+ data_line += b' -1' + lines [i + 1 ][- 1 :] # Add ' -1' and newline
1546
+ lines [i ] = data_line
1547
+ del lines [i + 1 ] # Remove the now-empty line
1548
+ # Do not increment i to recheck the new line at position i
1549
+ else :
1550
+ i += 1 # Move to the next line
1551
+
1552
+ # Reassemble the data
1553
+ data = b'' .join (lines )
1554
+
1555
+
1556
+ # Write the fixed data back to the file
1557
+ if fixed_filename is None :
1558
+ base , ext = os .path .splitext (filename )
1559
+ new_filename = f"{ base } _fixed{ ext } " #default filename
1560
+ else :
1561
+ new_filename = fixed_filename #custom filename
1562
+ with open (new_filename , 'wb' ) as fh :
1563
+ fh .write (data )
1564
+ print ('fixed file saved as:' , new_filename )
1565
+ except Exception as e :
1566
+ raise Exception (f'Error fixing UFF file: { filename } : { e } ' )
1567
+
0 commit comments