From d598ee7864366000af38e1019bab4e0bce3428b0 Mon Sep 17 00:00:00 2001 From: jakezw Date: Fri, 14 Nov 2025 16:01:06 -0500 Subject: [PATCH 1/4] UFF58 Add binary read/write capability and uneven ASCII read/write. Other more minor changes mentioned in the modifications docx file. --- src/UFFFiles.jl | 7 +- src/datasets/dataset15.jl | 10 +- src/datasets/dataset151.jl | 91 +- src/datasets/dataset164.jl | 33 +- src/datasets/dataset18.jl | 16 +- src/datasets/dataset1858.jl | 366 ++++++++ src/datasets/dataset2411.jl | 25 +- src/datasets/dataset2412.jl | 8 +- src/datasets/dataset2414.jl | 9 +- src/datasets/dataset55.jl | 31 +- src/datasets/dataset58.jl | 498 +++++------ src/datasets/dataset58_original.jl | 1071 +++++++++++++++++++++++ src/datasets/dataset58b.jl | 423 +++++++++ src/datasets/dataset58common.jl | 172 ++++ src/datasets/dataset82.jl | 8 +- src/read_write_uff.jl | 49 +- src/uff_helpers.jl | 2 +- src/uff_utils.jl | 4 +- test/datasets/dataset15.unv | 2 +- test/datasets/dataset151&164.unv | 16 + test/datasets/dataset151_bad_format.unv | 10 + test/datasets/dataset1858.unv | 10 + test/datasets/dataset58_FRF.unv | 2 +- test/datasets/dataset58_FRF_UTF.unv | 548 ++++++++++++ test/datasets/pump1.ufb | Bin 0 -> 13728 bytes test/datasets/unsupported_dataset.unv | 4 +- test/runtests.jl | 22 + 27 files changed, 3025 insertions(+), 412 deletions(-) create mode 100644 src/datasets/dataset1858.jl create mode 100644 src/datasets/dataset58_original.jl create mode 100644 src/datasets/dataset58b.jl create mode 100644 src/datasets/dataset58common.jl create mode 100644 test/datasets/dataset151&164.unv create mode 100644 test/datasets/dataset151_bad_format.unv create mode 100644 test/datasets/dataset1858.unv create mode 100644 test/datasets/dataset58_FRF_UTF.unv create mode 100644 test/datasets/pump1.ufb diff --git a/src/UFFFiles.jl b/src/UFFFiles.jl index 8c035ae..55d809a 100644 --- a/src/UFFFiles.jl +++ b/src/UFFFiles.jl @@ -1,5 +1,7 @@ module UFFFiles - using FileIO, Printf + using Dates + using FileIO + using Printf # Base UFFDataset abstract type abstract type UFFDataset end @@ -23,10 +25,13 @@ module UFFFiles include("datasets/dataset15.jl") include("datasets/dataset18.jl") include("datasets/dataset55.jl") + include("datasets/dataset58common.jl") include("datasets/dataset58.jl") + include("datasets/dataset58b.jl") include("datasets/dataset82.jl") include("datasets/dataset151.jl") include("datasets/dataset164.jl") + include("datasets/dataset1858.jl") include("datasets/dataset2411.jl") include("datasets/dataset2412.jl") include("datasets/dataset2414.jl") diff --git a/src/datasets/dataset15.jl b/src/datasets/dataset15.jl index 81964eb..4a8f13d 100644 --- a/src/datasets/dataset15.jl +++ b/src/datasets/dataset15.jl @@ -46,8 +46,7 @@ Universal Dataset Number: 15 NOTE: Repeat record for each node """ -function parse_dataset15(block) - nlines = length(block) +function parse_dataset15(io) node_ID = Int[] def_cs_num = Int[] @@ -55,9 +54,8 @@ function parse_dataset15(block) color = Int[] coords = Vector{Float64}[] - i = 2 - while i ≤ nlines - r1 = split(block[i]) + while (line = readline(io)) != " -1" + r1 = split(line) nid, dcs, disp_cs, col = parse.(Int, strip.(r1[1:4])) x, y, z = parse.(Float64, strip.(r1[5:end])) @@ -66,8 +64,6 @@ function parse_dataset15(block) push!(disp_cs_num, disp_cs) push!(color, col) push!(coords, [x, y, z]) - - i += 1 end return Dataset15( diff --git a/src/datasets/dataset151.jl b/src/datasets/dataset151.jl index fd1acde..1c720c7 100644 --- a/src/datasets/dataset151.jl +++ b/src/datasets/dataset151.jl @@ -11,6 +11,7 @@ A struct containing UFF Dataset 151 (Header) data. - `application::String`: Program which created the dataset - `datetime_created::DateTime`: dataset creation date and time - `version::String`: version from dataset +- `version2::String`: version from dataset - `file_type::Int`: file type - `datetime_last_saved::DateTime`: dataset last saved date and time - `program::String`: program which created uff file @@ -24,7 +25,8 @@ A struct containing UFF Dataset 151 (Header) data. description::String # Record 2 - field 1 application::String # Record 3 - field 1 datetime_created::String # Record 4 - fields 1 and 2 - version::String # Record 4 - fields 3 and 4 + version::Int # Record 4 - fields 3 + version2::Int # Record 4 - fields 4 file_type::Int # Record 4 - field 5 datetime_last_saved::String # Record 5 - fields 1 and 2 program::String # Record 6 - field 1 @@ -35,12 +37,13 @@ A struct containing UFF Dataset 151 (Header) data. description = "", application = "", datetime_created = "", - version = "", + version = 0, + version2 = 0, file_type = 0, datetime_last_saved = "", program = "", datetime_written = "" - ) = new(:Dataset151, "Header", model_name, description, application, datetime_created, version, file_type, datetime_last_saved, program, datetime_written) + ) = new(:Dataset151, "Header", model_name, description, application, datetime_created, version, version2, file_type, datetime_last_saved, program, datetime_written) end """ @@ -78,24 +81,27 @@ Universal Dataset Number: 151 Field 1 -- date universal file written (DD-MMM-YY) Field 2 -- time universal file written (HH:MM:SS) """ -function parse_dataset151(block) - model_name = strip(block[2]) - description = strip(block[3]) - application = strip(block[4]) +function parse_dataset151(io) + model_name = strip(readline(io)) # Record 1 + description = strip(readline(io)) # Record 2 + application = strip(readline(io)) # Record 3 # Record 4 contains multiple fields in one line - line_creation = extend_line(strip(block[5])) - datetime_created = strip(line_creation[1:20]) - version = strip(line_creation[21:40]) - if isempty(strip(line_creation[41:end])) - file_type = 0 - else - file_type = parse(Int, strip(line_creation[41:end])) - end - - datetime_last_saved = strip(block[6]) - program = strip(block[7]) - datetime_written = strip(block[8]) + line_creation = extend_line(readline(io)) + datetime_created = strip(line_creation[1:20]) # Field 1 & 2 + # compensate for files that only have date in Record 4 + tmp = strip(line_creation[21:30]) + version = isempty(tmp) ? 0 : parse(Int, tmp) # Field 3 + tmp = strip(line_creation[31:40]) + version2 = isempty(tmp) ? 0 : parse(Int, tmp) # Field 4 + tmp = strip(line_creation[41:50]) + file_type = isempty(tmp) ? 0 : parse(Int, tmp) # Field 5 + + datetime_last_saved = strip(readline(io)) # Record 5 + program = strip(readline(io)) # Record 6 + datetime_written = strip(readline(io)) # Record 7 + + _ = readline(io) # Read trailing " -1" return Dataset151( model_name, @@ -103,6 +109,7 @@ function parse_dataset151(block) application, datetime_created, version, + version2, file_type, datetime_last_saved, program, @@ -129,35 +136,61 @@ function write_dataset(dataset::Dataset151) push!(lines, " 151") # Record 1: FORMAT(80A1) - model file name - push!(lines, dataset.model_name) + push!(lines, extend_line(dataset.model_name)) # Record 2: FORMAT(80A1) - model file description (empty line if no description) - push!(lines, dataset.description) + push!(lines, extend_line(dataset.description)) # Record 3: FORMAT(80A1) - program which created DB - push!(lines, dataset.application) + push!(lines, extend_line(dataset.application)) - # Record 4: FORMAT(10A1,10A1,3I10) - date/time created, version, file_type + # Record 4: FORMAT(10A1,10A1,3I10) - date/time created, version, version, file_type # The datetime_created field should already contain both date and time # The version field should be formatted as two 10-character fields # File type should be formatted as I10 record4 = dataset.datetime_created - if !isempty(dataset.version) - record4 *= dataset.version + # the commented out lines appear to compensate for a badly formatted dataset151 + #=if !isempty(dataset.version) + record4 *= dataset.datetime_created + end + if !isempty(dataset.version2) + record4 *= dataset.version2 end if dataset.file_type != 0 record4 *= @sprintf("%10d", dataset.file_type) - end + end=# + + record4 = @sprintf("%-10s%-10s%10i%10i%10i%30s", + split(dataset.datetime_created)[1], + split(dataset.datetime_created)[2], + dataset.version, + dataset.version2, + dataset.file_type, + " " + ) + push!(lines, record4) # Record 5: FORMAT(10A1,10A1) - date/time last saved - push!(lines, dataset.datetime_last_saved) + record5 = @sprintf("%-10s%-10s%60s", + split(dataset.datetime_last_saved)[1], + split(dataset.datetime_last_saved)[2], + " " + ) + + push!(lines, record5) # Record 6: FORMAT(80A1) - program which created universal file - push!(lines, dataset.program) + push!(lines, extend_line(dataset.program)) # Record 7: FORMAT(10A1,10A1) - date/time written - push!(lines, dataset.datetime_written) + record7 = @sprintf("%-10s%-10s%60s", + Dates.format(now(), "dd-uuu-yy"), + Dates.format(now(), "HH:MM:SS"), + " " + ) + + push!(lines, record7) # Write footer push!(lines, " -1") diff --git a/src/datasets/dataset164.jl b/src/datasets/dataset164.jl index ad988ec..862b1b7 100644 --- a/src/datasets/dataset164.jl +++ b/src/datasets/dataset164.jl @@ -9,10 +9,10 @@ A struct containing UFF Dataset 164 (Units) data. - `units::Int`: Units code - `description::String`: Units description - `temperature_mode::Int`: Temperature mode -- `conversion_length::Float64`: Length conversion factor -- `conversion_force::Float64`: Force conversion factor -- `conversion_temperature::Float64`: Temperature conversion factor -- `conversion_temperature_offset::Float64`: Temperature offset conversion factor +- `conversion_length::Float64`: Units factors for converting to SI units +- `conversion_force::Float64`: Units factors for converting to SI units +- `conversion_temperature::Float64`: Units factors for converting to SI units +- `conversion_temperature_offset::Float64`: Units factors for converting to SI units """ @show_data struct Dataset164 <: UFFDataset # Fields specific to Dataset164 @@ -30,8 +30,12 @@ A struct containing UFF Dataset 164 (Units) data. units = 1, description = "", temperature_mode = 0, - conversion_factor = [1., 1., 1., 0.] - ) = new(:Dataset164, "Units",units, description, temperature_mode, conversion_length, conversion_force, conversion_temperature, conversion_temperature_offset) + conversion_length = 1.0, + conversion_force = 1.0, + conversion_temperature = 1.0, + conversion_temperature_offset = 0.0 + ) = new(:Dataset164, "Units", units, description, temperature_mode, conversion_length, + conversion_force, conversion_temperature, conversion_temperature_offset) end """ @@ -65,14 +69,15 @@ Universal Dataset Number: 164 Field 3 -- temperature Field 4 -- temperature offset """ -function parse_dataset164(block) - record1 = extend_line(strip(block[2])) - units = parse(Int, record1[1]) - description = strip(record1[2:29]) - temperature_mode = parse(Int, strip(record1[31:end])) - - (conversion_length, conversion_force, conversion_temperature) .= parse.(Float64, split(replace(block[3], "D" => "E"))) - conversion_temperature_offset = parse(Float64, strip(replace(block[4], "D" => "E"))) +function parse_dataset164(io) + record1 = extend_line(readline(io)) + units = parse(Int, record1[1:10]) + description = strip(record1[11:30]) + temperature_mode = parse(Int, strip(record1[31:40])) + (conversion_length, conversion_force, conversion_temperature) = parse.(Float64, split(replace(readline(io), "D" => "E"))) + conversion_temperature_offset = parse(Float64, strip(replace(readline(io), "D" => "E"))) + + _ = readline(io) # Read trailing " -1" return Dataset164( units, diff --git a/src/datasets/dataset18.jl b/src/datasets/dataset18.jl index 0f6ad79..9ed80af 100644 --- a/src/datasets/dataset18.jl +++ b/src/datasets/dataset18.jl @@ -70,8 +70,7 @@ Universal Dataset Number: 18 Records 1 thru 3 are repeated for each coordinate system in the model. """ -function parse_dataset18(block) - nlines = length(block) +function parse_dataset18(io) cs_num = Int[] cs_type = Int[] @@ -83,10 +82,9 @@ function parse_dataset18(block) cs_x = Vector{Float64}[] cs_xz = Vector{Float64}[] - i = 2 # Start after the dataset type line - while i ≤ nlines + while (line = readline(io)) != " -1" # Parse record 1 - csn, cst, ref_csn, col, md = parse.(Int, split(strip(block[i]))) + csn, cst, ref_csn, col, md = parse.(Int, split(line)) push!(cs_num, csn) push!(cs_type, cst) push!(ref_cs_num, ref_csn) @@ -94,20 +92,18 @@ function parse_dataset18(block) push!(method_def, md) # Parse record 2 - i += 1 - push!(cs_name, strip(block[i])) + push!(cs_name, strip(readline(io))) # Parse record 3 _cs_params = Float64[] for _ in 1:2 - i += 1 - append!(_cs_params, parse.(Float64, split(strip(block[i])))) + append!(_cs_params, parse.(Float64, split(strip(readline(io))))) end push!(cs_origin, _cs_params[1:3]) push!(cs_x, _cs_params[4:6]) push!(cs_xz, _cs_params[7:9]) - i += 1 # Move to the next coordinate system + # Move to the next coordinate system end return Dataset18( diff --git a/src/datasets/dataset1858.jl b/src/datasets/dataset1858.jl new file mode 100644 index 0000000..1b814fc --- /dev/null +++ b/src/datasets/dataset1858.jl @@ -0,0 +1,366 @@ +""" + Dataset1858 + +A struct containing UFF Dataset 1858 (Dataset 58 qualifiers) data. + +**Fields** +- `type::Symbol`: Data set type +- `name::String`: Data set name +- `set_record_number::Int`: Set record number +- `octave_format::Int`: Set record number +- `meas_run::Int`: Measurement run number +- `octave_weighting::Int`: Octave format +- `window::Int`: Window type +- `amp_scaling::Int`: Unknown, half-peak, peak, rms +- `normalization::Int`: Unknown, auto-spectra, PSD, ESD +- `abs_data_type_qual::Int`: Translation, Rotation, Translation Squared, Rotation Squared +- `ord_num_data_type_qual::Int`: Ordinate Numerator Data Type Qualifier +- `ord_denom_data_type_qual::Int`: Ordinate Denominator Data Type Qualifier +- `z_axis_data_type_qual::Int`: Z-axis Data Type Qualifier +- `sampling_type::Int`: Dynamic, Static, RPM from tach, Frequency from tach +- `z_rpm_value::Float64`: Z rpm value +- `z_time_value::Float64`: Z time value +- `z_order_value::Float64`: Z order value +- `num_samples::Int`: Number of Sample +- `uv1::Float64`: User Value 1 +- `uv2::Float64`: User Value 2 +- `uv3::Float64`: User Value 3 +- `uv4::Float64`: User Value 4 +- `exp_window_damping::Float64`: Exponential window damping factor +- `resp_dir::String`: Response direction +- `ref_dir::String`: Reference direction +""" +@show_data struct Dataset1858 <: UFFDataset + # Fields specific to Dataset1858 + type::Symbol # Data set type + name::String # Data set name + set_record_number::Int # Record 1 - field 1 + octave_format::Int # Record 1 - field 2 + meas_run::Int # Record 1 - field 3 + octave_weighting::Int # Record 2 - field 1 + window::Int # Record 2 - field 2 + amp_scaling::Int # Record 2 - field 3 + normalization::Int # Record 2 - field 4 + abs_data_type_qual::Int # Record 2 - field 5 + ord_num_data_type_qual::Int # Record 2 - field 6 + ord_denom_data_type_qual::Int # Record 2 - field 7 + z_axis_data_type_qual::Int # Record 2 - field 8 + sampling_type::Int # Record 2 - field 9 + z_rpm_value::Float64 # Record 3 - field 1 + z_time_value::Float64 # Record 3 - field 2 + z_order_value::Float64 # Record 3 - field 3 + num_samples::Int # Record 3 - field 4 + uv1::Float64 # Record 4 - field 1 + uv2::Float64 # Record 4 - field 2 + uv3::Float64 # Record 4 - field 3 + uv4::Float64 # Record 4 - field 4 + exp_window_damping::Float64 # Record 4 - field 5 + resp_dir::String # Record 6 - field 1 + ref_dir::String # Record 6 - field 2 + + Dataset1858( + set_record_number = 0, + octave_format = 0, + meas_run = 0, + octave_weighting = 0, + window = 0, + amp_scaling = 0, + normalization = 0, + abs_data_type_qual = 0, + ord_num_data_type_qual = 0, + ord_denom_data_type_qual = 0, + z_axis_data_type_qual = 0, + sampling_type = 0, + z_rpm_value = 0.0, + z_time_value = 0.0, + z_order_value = 0.0, + num_samples = 0, + uv1 = 0.0, + uv2 = 0.0, + uv3 = 0.0, + uv4 = 0.0, + exp_window_damping = 0.0, + resp_dir = "x+", + ref_dir = "NONE" + ) = new(:Dataset164, "Units", set_record_number, octave_format, meas_run, + octave_weighting, window, amp_scaling, normalization, abs_data_type_qual, + ord_num_data_type_qual, ord_denom_data_type_qual, z_axis_data_type_qual, + sampling_type, z_rpm_value, z_time_value, z_order_value, num_samples, + uv1, uv2, uv3, uv4, exp_window_damping, resp_dir, ref_dir) +end + +""" +Universal Dataset Number: 1858 + +Name: Dataset 58 qualifiers +---------------------------------------------------------------------------- + +Record 1: FORMAT(6I12) + Field 1 - Set record number + Field 2 - Octave format + 0 - not in octave format (default) + 1 - octave + 3 - one third octave + n - 1/n octave + Field 3 - Measurement run number + Fields 4-6 - Not used (fill with zeros) + +Record 2: FORMAT(12I6) + Field 1 - Weighting Type + 0 - No weighting or Unknown (default) + 1 - A weighting + 2 - B weighting + 3 - C weighting + 4 - D weighting (not yet implemented) + Field 2 - Window Type + 0 - No window or unknown (default) + 1 - Hanning Narrow + 2 - Hanning Broad + 3 - Flattop + 4 - Exponential + 5 - Impact + 6 - Impact and Exponential + Field 3 - Amplitude units + 0 - unknown (default) + 1 - Half-peak scale + 2 - Peak scale + 3 - RMS + Field 4 - Normalization Method + 0 - unknown (default) + 1 - Units squared + 2 - Units squared per Hz (PSD) + 3 - Units squared seconds per Hz (ESD) + Field 5 - Abscissa Data Type Qualifier + 0 - Translation + 1 - Rotation + 2 - Translation Squared + 3 - Rotation Squared + Field 6 - Ordinate Numerator Data Type Qualifier + 0 - Translation + 1 - Rotation + 2 - Translation Squared + 3 - Rotation Squared + Field 7 - Ordinate Denominator Data Type Qualifier + 0 - Translation + 1 - Rotation + 2 - Translation Squared + 3 - Rotation Squared + Field 8 - Z-axis Data Type Qualifier + 0 - Translation + 1 - Rotation + 2 - Translation Squared + 3 - Rotation Squared + + Field 9 - Sampling Type + 0 - Dynamic + 1 - Static + 2 - RPM from Tach + 3 - Frequency from tach + Fields 10-12 - not used (fill with zeros) + +Record 3: FORMAT (1P5E15.7) + Field 1 - Z RPM value + Field 2 - Z Time value + Field 3 - Z Order value + Field 4 - Number of samples + Field 5 - not used (fill with zero) + +Record 4: FORMAT (1P5E15.7) + Field 1 - User value 1 + Field 2 - User value 2 + Field 3 - User value 3 + Field 4 - User value 4 + Field 5 - Exponential window damping factor + +Record 5: FORMAT (1P5E15.7) + Fields 1-5 - not used (fill with zeros) + +Record 6: FORMAT (2A2,2X,2A2) + Field 1 - Response direction + Field 2 - Reference direction + +Record 7: FORMAT (40A2) + Field 1 - not used + +---------------------------------------------------------------------------- + +""" +function parse_dataset1858(io) + # Record 1 + record1 = extend_line(readline(io)) + set_record_number = parse(Int, record1[1:12]) + octave_format = parse(Int, record1[13:24]) + meas_run = parse(Int, record1[25:36]) + # Record 2 + record2 = extend_line(readline(io)) + octave_weighting = parse(Int, record2[1:6]) + window = parse(Int, record2[7:12]) + amp_scaling = parse(Int, record2[13:18]) + normalization = parse(Int, record2[19:24]) + abs_data_type_qual = parse(Int, record2[25:30]) + ord_num_data_type_qual = parse(Int, record2[31:36]) + ord_denom_data_type_qual = parse(Int, record2[37:42]) + z_axis_data_type_qual = parse(Int, record2[43:48]) + sampling_type = parse(Int, record2[49:54]) + # Record 3 + record3 = extend_line(readline(io)) + z_rpm_value = parse(Float64, record3[1:15]) + z_time_value = parse(Float64, record3[16:30]) + z_order_value = parse(Float64, record3[31:45]) + num_samples = parse(Float64, record3[46:60]) |> Int # Single precision in data file but must be Int + # Record 4 + record4 = extend_line(readline(io)) + uv1 = parse(Float64, record4[1:15]) + uv2 = parse(Float64, record4[16:30]) + uv3 = parse(Float64, record4[31:45]) + uv4 = parse(Float64, record4[46:60]) + exp_window_damping = parse(Float64, record4[61:75]) + # Record 5 Unused + _ = readline(io) + # Record 6 + record6 = extend_line(readline(io)) + resp_dir = strip(record6[1:4]) + ref_dir = strip(record6[7:10]) + + _ = readline(io) # Read unused Record 7 + _ = readline(io) # Read trailing " -1" + + return Dataset1858( + set_record_number, + octave_format, + meas_run, + octave_weighting, + window, + amp_scaling, + normalization, + abs_data_type_qual, + ord_num_data_type_qual, + ord_denom_data_type_qual, + z_axis_data_type_qual, + sampling_type, + z_rpm_value, + z_time_value, + z_order_value, + num_samples, + uv1, + uv2, + uv3, + uv4, + exp_window_damping, + resp_dir, + ref_dir + ) +end + +""" + write_dataset1858(dataset::Dataset1858) -> Vector{String} + +Write a UFF Dataset 1858 (Dataset58 qualifiers) to a vector of strings. + +**Input** +- `dataset::Dataset1858`: The dataset structure containing units information + +**Output** +- `Vector{String}`: Vector of formatted strings representing the UFF file content +""" +function write_dataset(dataset::Dataset1858) #::Dataset1858) #the remainder is a copy from 164 and needs to be implemented + lines = String[] + + # Write header + push!(lines, " -1") + push!(lines, " 1858") + + # Write Record 1: FORMAT(6I12) + # Field 1 - Set record number + # Field 2 - Octave format + # Field 3 - Measurement run number + # Fields 4-6 - Not used (fill with zeros) + + line1 = @sprintf("%12i%12i%12i%12i%12i%12i ", + dataset.set_record_number, + dataset.octave_format, + dataset.meas_run, + 0, 0, 0 + ) + push!(lines, line1) + + # Write Record 2: FORMAT(12I6) + # Field 1 - Weighting Type + # Field 2 - Window Type + # Field 3 - Amplitude units + # Field 4 - Normalization Method + # Field 5 - Abscissa Data Type Qualifier + # Field 6 - Ordinate Numerator Data Type Qualifier + # Field 7 - Ordinate Denominator Data Type Qualifier + # Field 8 - Z-axis Data Type Qualifier + # Field 9 - Sampling Type + # Fields 10-12 - not used (fill with zeros) + line2 = @sprintf("%6i%6i%6i%6i%6i%6i%6i%6i%6i%6i%6i%6i ", + dataset.octave_weighting, + dataset.window, + dataset.amp_scaling, + dataset.normalization, + dataset.abs_data_type_qual, + dataset.ord_num_data_type_qual, + dataset.ord_denom_data_type_qual, + dataset.z_axis_data_type_qual, + dataset.sampling_type, + 0, 0, 0 + ) + push!(lines, line2) + +# Write Record 3: FORMAT (1P5E15.7) + # Field 1 - Z RPM value + # Field 2 - Z Time value + # Field 3 - Z Order value + # Field 4 - Number of samples + # Field 5 - not used (fill with zero) + + line3 = @sprintf("%15.8e%15.8e%15.8e%15.8e%15.8e ", + dataset.z_rpm_value, + dataset.z_time_value, + dataset.z_order_value, + dataset.num_samples, + 0.0 + ) + push!(lines, line3) + +# Write Record 4: FORMAT (1P5E15.7) + # Field 1 - User value 1 + # Field 2 - User value 2 + # Field 3 - User value 3 + # Field 4 - User value 4 + # Field 5 - Exponential window damping factor + line4 = @sprintf("%15.8e%15.8e%15.8e%15.8e%15.8e ", + dataset.uv1, + dataset.uv2, + dataset.uv3, + dataset.uv4, + dataset.exp_window_damping + ) +push!(lines, line4) + +# Write Record 5: FORMAT (1P5E15.7) + # Fields 1-5 - not used (fill with zeros) + line5 = @sprintf("%15.8e%15.8e%15.8e%15.8e%15.8e ", + 0.0, 0.0, 0.0, 0.0, 0.0) +push!(lines, line5) + +# Write Record 6: FORMAT (2A2,2X,2A2) + # Field 1 - Response direction + # Field 2 - Reference direction + line6 = @sprintf("%-4s %-74s", + dataset.resp_dir, + dataset.ref_dir) +push!(lines, line6) + +#Write Record 7: FORMAT (40A2) + # Field 1 - not used + line7 = @sprintf("%-80s","NONE") + push!(lines, line7) + + # Write footer + push!(lines, " -1") + + return lines +end \ No newline at end of file diff --git a/src/datasets/dataset2411.jl b/src/datasets/dataset2411.jl index 94ff6f2..7218106 100644 --- a/src/datasets/dataset2411.jl +++ b/src/datasets/dataset2411.jl @@ -48,21 +48,24 @@ Universal Dataset Number: 2411 Records 1 and 2 are repeated for each node in the model. """ -function parse_dataset2411(block) +function parse_dataset2411(io) # Initialize empty arrays to hold the parsed data - nnodes = (length(block) - 1) ÷ 2 - nodes_ID = zeros(Int, nnodes) + + nodes_ID = Int[] coord_system = similar(nodes_ID) disp_coord_system = similar(nodes_ID) color = similar(nodes_ID) - node_coords = zeros(nnodes, 3) - - record1 = block[2:2:end] - record2 = block[3:2:end] - - for (i, (r1, r2)) in enumerate(zip(record1, record2)) - nodes_ID[i], coord_system[i], disp_coord_system[i], color[i] = parse.(Int, split(r1)) - node_coords[i, :] = parse.(Float64, split(r2)) + node_coords = Matrix{Float64}(undef, 0, 3) + + while (r1 = readline(io)) != " -1" + tmp = parse.(Int, split(r1)) + push!(nodes_ID, tmp[1]) + push!(coord_system, tmp[2]) + push!(disp_coord_system, tmp[3]) + push!(color, tmp[4]) + + r2 = readline(io) + node_coords = vcat(node_coords, parse.(Float64, split(r2))') end return Dataset2411( diff --git a/src/datasets/dataset2412.jl b/src/datasets/dataset2412.jl index 5547ba4..c673c67 100644 --- a/src/datasets/dataset2412.jl +++ b/src/datasets/dataset2412.jl @@ -245,7 +245,13 @@ Universal Dataset Number: 2412 232 Axisymmetric parabolic rigid surface """ -function parse_dataset2412(block) +function parse_dataset2412(io) + + reset(io) + block = String[] + while (line = readline(io)) != " -1" + push!(block, line) + end elements_ID = Int[] fe_descriptor_id = Int[] diff --git a/src/datasets/dataset2414.jl b/src/datasets/dataset2414.jl index 5f65457..67eddce 100644 --- a/src/datasets/dataset2414.jl +++ b/src/datasets/dataset2414.jl @@ -800,7 +800,14 @@ Universal Dataset Number: 2414 Imaginary part of stiffness X ---------------------------------------------------------------------- """ -function parse_dataset2414(block) +function parse_dataset2414(io) + + reset(io) + block = String[] + while (line = readline(io)) != " -1" + push!(block, line) + end + nlines = length(block) analysis_dlabel = parse(Int, strip(block[2])) diff --git a/src/datasets/dataset55.jl b/src/datasets/dataset55.jl index bc3d5f2..7c7a6d7 100644 --- a/src/datasets/dataset55.jl +++ b/src/datasets/dataset55.jl @@ -429,22 +429,22 @@ Universal Dataset Number: 55 Translations Or 6 DOF Translation And Rotation With Unused Values = 0. """ -function parse_dataset55(block) +function parse_dataset55(io) # Parse Record 1 to 5 - id1 = strip(block[2]) - id2 = strip(block[3]) - id3 = strip(block[4]) - id4 = strip(block[5]) - id5 = strip(block[6]) + id1 = strip(readline(io)) + id2 = strip(readline(io)) + id3 = strip(readline(io)) + id4 = strip(readline(io)) + id5 = strip(readline(io)) # Parse Record 6 - model_type, analysis_type, data_charac, spec_dtype, dtype, ndv_per_node = parse.(Int, split(strip(block[7]))) + model_type, analysis_type, data_charac, spec_dtype, dtype, ndv_per_node = parse.(Int, split(strip(readline(io)))) # Parse Record 7 - r7_raw = parse.(Int, split(strip(block[8]))) + r7_raw = parse.(Int, split(strip(readline(io)))) # Parse Record 8 - r8_raw = parse.(Float64, split(strip(block[9]))) + r8_raw = parse.(Float64, split(strip(readline(io)))) # Parse Record 9 and 10 node_number = Int[] @@ -455,18 +455,16 @@ function parse_dataset55(block) end # Start parsing from Record 9 and 10 - i = 10 - nlines = length(block) - _data = similar(eltype(data), 0) - while i ≤ nlines + _data = similar(eltype(data), 0) + while (record09 = readline(io)) != " -1" # Record 9 - push!(node_number, parse(Int, strip(block[i]))) + push!(node_number, parse(Int, strip(record09))) # Record 10 + record10 = readline(io) nv = 0 while nv < ndv - i += 1 - r10 = parse.(Float64, split(strip(block[i]))) + r10 = parse.(Float64, split(strip(record10))) nv += length(r10) if dtype == 2 @@ -478,7 +476,6 @@ function parse_dataset55(block) push!(data, copy(_data)) empty!(_data) - i += 1 end return Dataset55( diff --git a/src/datasets/dataset58.jl b/src/datasets/dataset58.jl index 9d3bc82..d29d280 100644 --- a/src/datasets/dataset58.jl +++ b/src/datasets/dataset58.jl @@ -1,173 +1,3 @@ -""" - Dataset58 - -A struct containing UFF Dataset 58 (Function at nodal dof) data. - -**Fields** -- `type::Symbol`: Data set type -- `name::String`: Data set name -- `id1::String`: ID line 1 -- `id2::String`: ID line 2 -- `id3::String`: ID line 3 -- `id4::String`: ID line 4 -- `id5::String`: ID line 5 -- `func_type::Int`: Function type -- `func_id::Int`: Function ID -- `ver_num::Int`: Version number -- `load_case::Int`: Load case -- `resp_name::String`: Response name -- `resp_node::Int`: Response node -- `resp_dir::Int`: Response direction -- `ref_name::String`: Reference name -- `ref_node::Int`: Reference node -- `ref_dir::Int`: Reference direction -- `ord_dtype::Int`: Ordinate data type -- `num_pts::Int`: Number of points -- `abs_spacing_type::Int`: Abscissa spacing type -- `abs_start::Float64`: Abscissa start -- `abs_increment::Float64`: Abscissa increment -- `zval::Float64`: Z-axis value -- `abs_spec_dtype::Int`: Abscissa specification data type -- `abs_len_unit_exp::Int`: Abscissa length unit exponent -- `abs_force_unit_exp::Int`: Abscissa force unit exponent -- `abs_temp_unit_exp::Int`: Abscissa temperature unit exponent -- `abs_axis_label::String`: Abscissa axis label -- `abs_axis_unit_label::String`: Abscissa axis unit label -- `ord_spec_dtype::Int`: Ordinate specification data type -- `ord_len_unit_exp::Int`: Ordinate length unit exponent -- `ord_force_unit_exp::Int`: Ordinate force unit exponent -- `ord_temp_unit_exp::Int`: Ordinate temperature unit exponent -- `ord_axis_label::String`: Ordinate axis label -- `ord_axis_unit_label::String`: Ordinate axis unit label -- `ord_denom_spec_dtype::Int`: Ordinate denominator specification data type -- `ord_denom_len_unit_exp::Int`: Ordinate denominator length unit exponent -- `ord_denom_force_unit_exp::Int`: Ordinate denominator force unit exponent -- `ord_denom_temp_unit_exp::Int`: Ordinate denominator temperature unit exponent -- `ord_denom_axis_label::String`: Ordinate denominator axis label -- `ord_denom_axis_unit_label::String`: Ordinate denominator axis unit label -- `z_spec_dtype::Int`: Z-axis specification data type -- `z_len_unit_exp::Int`: Z-axis length unit exponent -- `z_force_unit_exp::Int`: Z-axis force unit exponent -- `z_temp_unit_exp::Int`: Z-axis temperature unit exponent -- `z_axis_label::String`: Z-axis label -- `z_axis_unit_label::String`: Z-axis unit label -- `data::AbstractVector`: Data values -""" -@show_data struct Dataset58 <: UFFDataset - # Fields specific to Dataset58 - type::Symbol # Data set type - name::String # Data set name - id1::String # Record 1 - field 1 - id2::String # Record 2 - field 1 - id3::String # Record 3 - field 1 - id4::String # Record 4 - field 1 - id5::String # Record 5 - field 1 - - #Record 6 fields - func_type::Int # Record 6 - field 1 - func_id::Int # Record 6 - field 2 - ver_num::Int # Record 6 - field 3 - load_case::Int # Record 6 - field 4 - resp_name::String # Record 6 - field 5 - resp_node::Int # Record 6 - field 6 - resp_dir::Int # Record 6 - field 7 - ref_name::String # Record 6 - field 8 - ref_node::Int # Record 6 - field 9 - ref_dir::Int # Record 6 - field 10 - - # Record 7 fields - ord_dtype::Int # Record 7 - field 1 - num_pts::Int # Record 7 - field 2 - abs_spacing_type::Int # Record 7 - field 3 - abs_min ::Float64 # Record 7 - field 4 - abs_increment ::Float64 # Record 7 - field 5 - zval::Float64 # Record 7 - field 6 - - # Record 8 fields - abs_spec_dtype::Int # Record 8 - field 1 - abs_len_unit_exp::Int # Record 8 - field 2 - abs_force_unit_exp::Int # Record 8 - field 3 - abs_temp_unit_exp::Int # Record 8 - field 4 - abs_axis_label::String # Record 8 - field 5 - abs_axis_unit_label::String # Record 8 - field 6 - - # Record 9 fields - ord_spec_dtype::Int # Record 9 - field 1 - ord_len_unit_exp::Int # Record 9 - field 2 - ord_force_unit_exp::Int # Record 9 - field 3 - ord_temp_unit_exp::Int # Record 9 - field 4 - ord_axis_label::String # Record 9 - field 5 - ord_axis_unit_label::String # Record 9 - field 6 - - # Record 10 fields - ord_denom_spec_dtype::Int # Record 10 - field 1 - ord_denom_len_unit_exp::Int # Record 10 - field 2 - ord_denom_force_unit_exp::Int # Record 10 - field 3 - ord_denom_temp_unit_exp::Int # Record 10 - field 4 - ord_denom_axis_label::String # Record 10 - field 5 - ord_denom_axis_unit_label::String # Record 10 - field 6 - - # Record 11 fields - z_spec_dtype::Int # Record 11 - field 1 - z_len_unit_exp::Int # Record 11 - field 2 - z_force_unit_exp::Int # Record 11 - field 3 - z_temp_unit_exp::Int # Record 11 - field 4 - z_axis_label::String # Record 11 - field 5 - z_axis_unit_label::String # Record 11 - field 6 - - # Record 12 fields - data::AbstractVector - - Dataset58( - id1 = "", - id2 = "", - id3 = "", - id4 = "", - id5 = "", - func_type = 0, - func_id = 0, - ver_num = 0, - load_case = 0, - resp_name = "", - resp_node = 0, - resp_dir = 0, - ref_name = "", - ref_node = 0, - ref_dir = 0, - ord_dtype = 0, - num_pts = 0, - abs_spacing_type = 0, - abs_min = 0.0, - abs_increment = 0.0, - zval = 0.0, - abs_spec_dtype = 0, - abs_len_unit_exp = 0, - abs_force_unit_exp = 0, - abs_temp_unit_exp = 0, - abs_axis_label = "", - abs_axis_unit_label = "", - ord_spec_dtype = 0, - ord_len_unit_exp = 0, - ord_force_unit_exp = 0, - ord_temp_unit_exp = 0, - ord_axis_label = "", - ord_axis_unit_label = "", - ord_denom_spec_dtype = 0, - ord_denom_len_unit_exp = 0, - ord_denom_force_unit_exp = 0, - ord_denom_temp_unit_exp = 0, - ord_denom_axis_label = "", - ord_denom_axis_unit_label = "", - z_spec_dtype = 0, - z_len_unit_exp = 0, - z_force_unit_exp = 0, - z_temp_unit_exp = 0, - z_axis_label = "", - z_axis_unit_label = "", - data = [], - ) = new(:Dataset58, "Function at nodal dof", id1, id2, id3, id4, id5, func_type, func_id, ver_num, load_case, resp_name, resp_node, resp_dir, ref_name, ref_node, ref_dir, ord_dtype, num_pts, abs_spacing_type, abs_min, abs_increment, zval, abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp, abs_axis_label, abs_axis_unit_label, ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp, ord_axis_label, ord_axis_unit_label, ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp, ord_denom_axis_label, ord_denom_axis_unit_label, z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp, z_axis_label, z_axis_unit_label, data) -end - """ Universal Dataset Number: 58 @@ -876,132 +706,207 @@ Universal Dataset Number: 58 . continued processing . """ -function parse_dataset58(block) - id1 = strip(block[2]) - id2 = strip(block[3]) - id3 = strip(block[4]) - id4 = strip(block[5]) - id5 = strip(block[6]) +function parse_dataset58(io) + + id1 = strip(readline(io)) + id2 = strip(readline(io)) + id3 = strip(readline(io)) + id4 = strip(readline(io)) + id5 = strip(readline(io)) + # @show(id1, id2, id3, id4, id5) # Record 6 - r6 = split(block[7]) + r6 = readline(io) len_r6 = length(r6) - func_type = parse(Int, strip(r6[1])) + #=func_type = parse(Int, strip(r6[1])) func_id = parse(Int, strip(r6[2])) version_num = parse(Int, strip(r6[3])) load_case_id = parse(Int, strip(r6[4])) response_entity = strip(r6[5]) response_node = parse(Int, strip(r6[6])) response_direction = parse(Int, strip(r6[7])) - reference_entity = strip(r6[8]) + reference_entity = strip(r6[8])=# + # This modified for the space in Sample_UFF58b_bin.uff record 6 field 5 + func_type = parse(Int, r6[1:5]) + func_id = parse(Int, r6[6:15]) + version_num = parse(Int, r6[16:20]) + load_case_id = parse(Int, r6[21:30]) + response_entity = r6[32:41] + response_node = parse(Int, r6[42:51]) + response_direction = parse(Int, r6[52:55]) + reference_entity = r6[57:66] if len_r6 > 8 - reference_node = parse(Int, strip(r6[9])) - reference_direction = parse(Int, strip(r6[10])) + reference_node = parse(Int, r6[67:76]) + reference_direction = parse(Int, r6[77:80]) else reference_node = 0 reference_direction = 0 end # Record 7 - r7 = split(block[8]) + r7 = split(readline(io)) ord_dtype, num_pts, abs_spacing_type = parse.(Int, strip.(r7[1:3])) abs_min, abs_increment, zval = parse.(Float64, strip.(r7[4:6])) # Record 8 - r8 = split(block[9]) + r8 = split(readline(io)) abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp = parse.(Int, strip.(r8[1:4])) abs_axis_label, abs_axis_unit_label = strip.(r8[5:6]) # Record 9 - r9 = split(block[10]) + r9 = split(readline(io)) ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp = parse.(Int, strip.(r9[1:4])) ord_axis_label, ord_axis_unit_label = strip.(r9[5:6]) # Record 10 - r10 = split(block[11]) + r10 = split(readline(io)) ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp = parse.(Int, strip.(r10[1:4])) ord_denom_axis_label, ord_denom_axis_unit_label = strip.(r10[5:6]) # Record 11 - r11 = split(block[12]) + r11 = split(readline(io)) z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp = parse.(Int, strip.(r11[1:4])) z_axis_label, z_axis_unit_label = strip.(r11[5:6]) # Record 12 - data_values = block[13:end] - - data, dtype = if ord_dtype == 2 - Float32[], Float32 - elseif ord_dtype == 4 - Float64[], Float64 - elseif ord_dtype == 5 - ComplexF32[], Float32 - elseif ord_dtype == 6 - ComplexF64[], Float64 - end - - # for dv in data_values - # entries = split(dv) - # _data = parse.(dtype, strip.(entries)) - # if ord_dtype < 5 - # append!(data, _data) - # elseif ord_dtype == 5 - # append!(data, complex.(_data[1:2:end], _data[2:2:end])) - # elseif ord_dtype == 6 - # append!(data, complex.(_data[1:2:end], _data[2:2:end])) - # end - # end - - for dv in data_values - # Check if line contains spaces (standard format) or fixed-width fields (UFF58 specification) - if occursin(r"\s+", strip(dv)) && !occursin(r"^[\s\-\+\d\.E]+$", dv) - # Format with spaces - use standard split - entries = split(dv) - _data = parse.(dtype, strip.(entries)) - else - # Format without spaces - use fixed-width positions according to UFF58 specification - entries = String[] - line = dv - - if ord_dtype == 2 || ord_dtype == 5 - # Single precision: E13.5 format (13 characters per value) - field_width = 13 - elseif ord_dtype == 4 || ord_dtype == 6 - # Double precision: E20.12 format (20 characters per value) - field_width = 20 - end - - # Extract fixed-width fields - pos = 1 - while pos <= length(line) - if pos + field_width - 1 <= length(line) - field = strip(line[pos:pos+field_width-1]) - if !isempty(field) - push!(entries, field) - end - pos += field_width - else - # Last field potentially shorter - field = strip(line[pos:end]) - if !isempty(field) - push!(entries, field) + if (ord_dtype == 2 && abs_spacing_type == 1) # Case 1 - Real, Single Precision, Even Spacing 6E13.5 + _data = Vector{Float32}(undef, num_pts) + n = 6 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = 13 # field width + for i in 1:n:num_pts + r12 = readline(io) + @show(i, r12) + for j in 1:n + i + j - 1 > num_pts && break # break if num_pts exceeded + _data[i+j-1] = parse(Float32, r12[(j-1)*fw+1:j*fw]) + end + @show(typeof(_data), size(_data)) + end + abscissa = Float32[] + data = _data + + elseif (ord_dtype == 2 && abs_spacing_type == 0) # Case 2 - Real, Single Precision, Uneven Spacing 6E13.5 + _data = Vector{Float32}(undef, 2num_pts) + n = 6 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = 13 # field width + for i in 1:n:2num_pts + r12 = readline(io) + #@show(i, r12) + for j in 1:n + i + j - 1 > num_pts && break # break if num_pts exceeded + _data[i+j-1] = parse(Float32, r12[(j-1)*fw+1:j*fw]) + end + #@show(typeof(data), size(data)) + end + tmp = reshape(reinterpret(Float32, _data), (2, :))' + abscissa = tmp[:, 1] + data = tmp[:, 2] + + elseif (ord_dtype == 5 && abs_spacing_type == 1) # Case 3 - Complex, Single Precision, Even Spacing 6E13.5 + _data = Vector{Float32}(undef, 2num_pts) + n = 6 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = 13 # field width + for i in 1:n:2num_pts + r12 = readline(io) + # @show(i , r12) + for j in 1:n + i + j - 1 > num_pts && break # break if num_pts exceeded + _data[i+j-1] = parse(Float32, r12[(j-1)*fw+1:j*fw]) + end + # @show(typeof(data), size(data)) + end + abscissa = Float32[] + data = reinterpret(ComplexF32, _data) + + elseif (ord_dtype == 5 && abs_spacing_type == 0) # Case 4 - Complex, Single Precision, Uneven Spacing 6E13.5 + _data = Vector{Float32}(undef, 3num_pts) + n = 6 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = 13 # field width + for i in 1:n:3num_pts + r12 = readline(io) + # @show(i , r12) + for j in 1:n + i + j - 1 > num_pts && break # break if num_pts exceeded + _data[i+j-1] = parse(Float32, r12[(j-1)*fw+1:j*fw]) + end + # @show(typeof(data), size(data)) + end + tmp = reshape(reinterpret(Float32, _data), (3, :))' + abscissa = tmp[:, 1] + data = reinterpret(ComplexF32, reshape(tmp[:, 2:3]', (:, 1))) + + elseif (ord_dtype == 2 && abs_spacing_type == 1) # Case 5 - Real, Double Precision, Even Spacing 4E20.12 + _data = Vector{Float64}(undef, num_pts) + n = 4 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = 20 # field width + for i in 1:n:num_pts + r12 = readline(io) + # @show(i , r12) + for j in 1:n + i + j - 1 > num_pts && break # break if num_pts exceeded + _data[i+j-1] = parse(Float64, r12[(j-1)*fw+1:j*fw]) + end + # @show(typeof(data), size(data)) + end + abscissa = Float64[] + data = reinterpret(Float64, _data) + + elseif (ord_dtype == 2 && abs_spacing_type == 0) # Case 6 - Real, Double Precision, Uneven Spacing 2(E13.5,E20.12) + _data = Vector{Float64}(undef, 2num_pts) + n = 4 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = [13, 20] # field width + for i in 1:n:2num_pts + r12 = readline(io) + # @show(i , r12) + _data[i] = parse(Float64, r12[1:13]) + _data[i+1] = parse(Float64, r12[14:33]) + i + 2 > num_pts && break # break if num_pts exceeded + _data[i] = parse(Float64, r12[34:46]) + _data[i+1] = parse(Float64, r12[47:66]) + # @show(typeof(data), size(data)) end - break - end - end - - _data = parse.(dtype, entries) + tmp = reshape(reinterpret(Float64, _data), (2, :))' + abscissa = tmp[:, 1] + data = tmp[:, 2] + + elseif (ord_dtype == 5 && abs_spacing_type == 1) # Case 7 - Complex, Double Precision, Even Spacing 4E20.12 + _data = Vector{Float64}(undef, num_pts) + n = 4 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = 20 # field width + for i in 1:n:num_pts + r12 = readline(io) + # @show(i , r12) + for j in 1:n + i + j - 1 > num_pts && break # break if num_pts exceeded + _data[i+j-1] = parse(Float64, r12[(j-1)*fw+1:j*fw]) end - - if ord_dtype < 5 - append!(data, _data) - elseif ord_dtype == 5 - append!(data, complex.(_data[1:2:end], _data[2:2:end])) - elseif ord_dtype == 6 - append!(data, complex.(_data[1:2:end], _data[2:2:end])) + # @show(typeof(data), size(data)) end + abscissa = Float64[] + data = reinterpret(Float64, _data) + abscissa = Float64[] + data = reinterpret(ComplexF64, _data) + + elseif (ord_dtype == 5 && abs_spacing_type == 0) # Case 8 - Complex, Double Precision, Uneven Spacing E13.5,2E20.12 + _data = Vector{Float64}(undef, 2num_pts) + n = 4 # number of data values or (x,y) or (x, Ry, Iy) sets per line + fw = [13, 20] # field width + for i in 1:n:2num_pts + r12 = readline(io) + # @show(i , r12) + _data[i] = parse(Float64, r12[1:13]) + _data[i+1] = parse(Float64, r12[14:33]) + i + 2 > num_pts && break # break if num_pts exceeded + _data[i] = parse(Float64, r12[34:46]) + _data[i+1] = parse(Float64, r12[47:66]) + # @show(typeof(data), size(data)) + end + _data = reshape(reinterpret(Float32, _data), (3, :))' + abscissa = _data[:, 1] + data = reinterpret(ComplexF64, reshape(_data[:, 2:3]', (:, 1))) + end nd = length(data) @@ -1010,6 +915,8 @@ function parse_dataset58(block) data = data[1:num_pts] end end + # Consume the trailing " -1" + readline(io) return Dataset58( id1, @@ -1057,6 +964,7 @@ function parse_dataset58(block) z_temp_unit_exp, z_axis_label, z_axis_unit_label, + abscissa, data ) end @@ -1184,39 +1092,53 @@ function write_dataset(dataset::Dataset58) end push!(lines, line) end - - elseif dataset.ord_dtype == 5 || dataset.ord_dtype == 6 - # Complex data (single or double precision) - if dataset.ord_dtype == 5 - # Complex single precision: 6E13.5 (3 complex values per line) - values_per_line = 3 - else - # Complex double precision: 4E20.12 (2 complex values per line) - values_per_line = 2 - end - - # Write data in chunks (real and imaginary parts interleaved) - for i in 1:values_per_line:length(dataset.data) - end_idx = min(i + values_per_line - 1, length(dataset.data)) - chunk = dataset.data[i:end_idx] - - if dataset.ord_dtype == 5 - # 6E13.5 format - parts = Float64[] - for c in chunk - push!(parts, real(c)) - push!(parts, imag(c)) - end - line = join([@sprintf(" %12.5E", v) for v in parts], "") - else - # 4E20.12 format - parts = Float64[] - for c in chunk - push!(parts, real(c)) - push!(parts, imag(c)) - end - line = join([@sprintf(" %19.12E", v) for v in parts], "") - end + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 3 - Complex, Single Precision, Even Spacing + # Complex single precision even: 6E13.5 (3 complex values per line) + y_pair_per_line = 3 + for i in 1:y_pair_per_line:length(dataset.data) + ie = min(i + y_pair_per_line - 1, length(dataset.abscissa)) + line = join([@sprintf(" %12.5E %12.5E", real(v), imag(v)) for v in dataset.data[i:ie]]) + push!(lines, line) + end + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 4 - Complex, Single Precision, Uneven Spacing + # Complex single precision uneven: 6E13.5 (3 complex values per line) + xy_pair_per_line = 2 + for i in 1:xy_pair_per_line:length(dataset.data) + ie = min(i + xy_pair_per_line - 1, length(dataset.abscissa)) + line = join([@sprintf(" %12.5E %12.5E %12.5E", a, real(o), imag(o)) for (a, o) in zip(dataset.abscissa[i:ie], dataset.data[i:ie])]) + push!(lines, line) + end + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 5 - Real, Double Precision, Even Spacing + # Real double precision even: 4E20.12 + y_values_per_line = 4 + for i in 1:y_values_per_line:length(dataset.data) + ie = min(i + y_values_per_line - 1, length(dataset.data)) + chunk = dataset.data[i:ie] + line = join([@sprintf(" %19.12E", v) for v in chunk], "") + push!(lines, line) + end + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 6 - Real, Double Precision, Uneven Spacing + # Real double precision uneven: 2(E13.5,E20.12) + xy_pair_per_line = 2 + for i in 1:xy_pair_per_line:length(dataset.data) + ie = min(i + xy_pair_per_line - 1, length(dataset.abscissa)) + line = join([@sprintf(" %12.5E %19.12E", a, o) for (a, o) in zip(dataset.abscissa[i:ie], dataset.data[i:ie])]) + push!(lines, line) + end + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 7 - Complex, Double Precision, Even Spacing + # Complex double precision even: 4E20.12 (2 complex values per line) + y_pair_per_line = 3 + for i in 1:y_pair_per_line:length(dataset.data) + ie = min(i + y_pair_per_line - 1, length(dataset.abscissa)) + line = join([@sprintf(" %19.12E %19.12E", real(v), imag(v)) for v in dataset.data[i:ie]]) + push!(lines, line) + end + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 8 - Complex, Double Precision, Uneven Spacing + # Complex double precision uneven: E13.5,2E20.12 (1 complex values per line) + xy_pair_per_line = 1 + for i in 1:xy_pair_per_line:length(dataset.data) + ie = min(i + xy_pair_per_line - 1, length(dataset.abscissa)) + line = join([@sprintf(" %12.5E %19.12E %19.12E", a, real(o), imag(o)) for (a, o) in zip(dataset.abscissa[i:ie], dataset.data[i:ie])]) push!(lines, line) end end diff --git a/src/datasets/dataset58_original.jl b/src/datasets/dataset58_original.jl new file mode 100644 index 0000000..66d14ba --- /dev/null +++ b/src/datasets/dataset58_original.jl @@ -0,0 +1,1071 @@ +""" +Universal Dataset Number: 58 + +**Name: Function at Nodal DOF** + + Record 1: Format(80A1) + Field 1 - ID Line 1 + + NOTE + + ID Line 1 is generally used for the function + description. + + + Record 2: Format(80A1) + Field 1 - ID Line 2 + + Record 3: Format(80A1) + Field 1 - ID Line 3 + + NOTE + + ID Line 3 is generally used to identify when the + function was created. The date is in the form + DD-MMM-YY, and the time is in the form HH:MM:SS, + with a general Format(9A1,1X,8A1). + + Record 4: Format(80A1) + Field 1 - ID Line 4 + + Record 5: Format(80A1) + Field 1 - ID Line 5 + + Record 6: Format(2(I5,I10),2(1X,10A1,I10,I4)) + DOF Identification + Field 1 - Function Type + 0 - General or Unknown + 1 - Time Response + 2 - Auto Spectrum + 3 - Cross Spectrum + 4 - Frequency Response Function + 5 - Transmissibility + 6 - Coherence + 7 - Auto Correlation + 8 - Cross Correlation + 9 - Power Spectral Density (PSD) + 10 - Energy Spectral Density (ESD) + 11 - Probability Density Function + 12 - Spectrum + 13 - Cumulative Frequency Distribution + 14 - Peaks Valley + 15 - Stress/Cycles + 16 - Strain/Cycles + 17 - Orbit + 18 - Mode Indicator Function + 19 - Force Pattern + 20 - Partial Power + 21 - Partial Coherence + 22 - Eigenvalue + 23 - Eigenvector + 24 - Shock Response Spectrum + 25 - Finite Impulse Response Filter + 26 - Multiple Coherence + 27 - Order Function + Field 2 - Function Identification Number + Field 3 - Version Number, or sequence number + Field 4 - Load Case Identification Number + 0 - Single Point Excitation + Field 5 - Response Entity Name ("NONE" if unused) + Field 6 - Response Node + Field 7 - Response Direction + 0 - Scalar + 1 - +X Translation 4 - +X Rotation + -1 - -X Translation -4 - -X Rotation + 2 - +Y Translation 5 - +Y Rotation + -2 - -Y Translation -5 - -Y Rotation + 3 - +Z Translation 6 - +Z Rotation + -3 - -Z Translation -6 - -Z Rotation + Field 8 - Reference Entity Name ("NONE" if unused) + Field 9 - Reference Node + Field 10 - Reference Direction (same as field 7) + + NOTE + + Fields 8, 9, and 10 are only relevant if field 4 + is zero. + + Record 7: Format(3I10,3E13.5) + Data Form + Field 1 - Ordinate Data Type + 2 - real, single precision + 4 - real, double precision + 5 - complex, single precision + 6 - complex, double precision + Field 2 - Number of data pairs for uneven abscissa + spacing, or number of data values for even + abscissa spacing + Field 3 - Abscissa Spacing + 0 - uneven + 1 - even (no abscissa values stored) + Field 4 - Abscissa minimum (0.0 if spacing uneven) + Field 5 - Abscissa increment (0.0 if spacing uneven) + Field 6 - Z-axis value (0.0 if unused) + + Record 8: Format(I10,3I5,2(1X,20A1)) + Abscissa Data Characteristics + Field 1 - Specific Data Type + 0 - unknown + 1 - general + 2 - stress + 3 - strain + 5 - temperature + 6 - heat flux + 8 - displacement + 9 - reaction force + 11 - velocity + 12 - acceleration + 13 - excitation force + 15 - pressure + 16 - mass + 17 - time + 18 - frequency + 19 - rpm + 20 - order + Field 2 - Length units exponent + Field 3 - Force units exponent + Field 4 - Temperature units exponent + + NOTE + + Fields 2, 3 and 4 are relevant only if the + Specific Data Type is General, or in the case of + ordinates, the response/reference direction is a + scalar, or the functions are being used for + nonlinear connectors in System Dynamics Analysis. + See Addendum 'A' for the units exponent table. + + Field 5 - Axis label ("NONE" if not used) + Field 6 - Axis units label ("NONE" if not used) + + NOTE + + If fields 5 and 6 are supplied, they take + precendence over program generated labels and + units. + + Record 9: Format(I10,3I5,2(1X,20A1)) + Ordinate (or ordinate numerator) Data Characteristics + + Record 10: Format(I10,3I5,2(1X,20A1)) + Ordinate Denominator Data Characteristics + + Record 11: Format(I10,3I5,2(1X,20A1)) + Z-axis Data Characteristics + + NOTE + + Records 9, 10, and 11 are always included and + have fields the same as record 8. If records 10 + and 11 are not used, set field 1 to zero. + + Record 12: + Data Values + + Ordinate Abscissa + Case Type Precision Spacing Format + ------------------------------------------------------------- + 1 real single even 6E13.5 + 2 real single uneven 6E13.5 + 3 complex single even 6E13.5 + 4 complex single uneven 6E13.5 + 5 real double even 4E20.12 + 6 real double uneven 2(E13.5,E20.12) + 7 complex double even 4E20.12 + 8 complex double uneven E13.5,2E20.12 + -------------------------------------------------------------- + + NOTE + + See Addendum 'B' for typical FORTRAN READ/WRITE + statements for each case. + + + General Notes: + + 1. ID lines may not be blank. If no information is required, + the word "NONE" must appear in columns 1 through 4. + + 2. ID line 1 appears on plots in Finite Element Modeling and is + used as the function description in System Dynamics Analysis. + + 3. Dataloaders use the following ID line conventions + ID Line 1 - Model Identification + ID Line 2 - Run Identification + ID Line 3 - Run Date and Time + ID Line 4 - Load Case Name + + 4. Coordinates codes from MODAL-PLUS and MODALX are decoded into + node and direction. + + 5. Entity names used in System Dynamics Analysis prior to I-DEAS + Level 5 have a 4 character maximum. Beginning with Level 5, + entity names will be ignored if this dataset is preceded by + dataset 259. If no dataset 259 precedes this dataset, then the + entity name will be assumed to exist in model bin number 1. + + 6. Record 10 is ignored by System Dynamics Analysis unless load + case = 0. Record 11 is always ignored by System Dynamics + Analysis. + + 7. In record 6, if the response or reference names are "NONE" + and are not overridden by a dataset 259, but the correspond- + ing node is non-zero, System Dynamics Analysis adds the node + and direction to the function description if space is sufficie + + 8. ID line 1 appears on XY plots in Test Data Analysis along + with ID line 5 if it is defined. If defined, the axis units + labels also appear on the XY plot instead of the normal + labeling based on the data type of the function. + + 9. For functions used with nonlinear connectors in System + Dynamics Analysis, the following requirements must be + adhered to: + + a) Record 6: For a displacement-dependent function, the + function type must be 0; for a frequency-dependent + function, it must be 4. In either case, the load case + identification number must be 0. + + b) Record 8: For a displacement-dependent function, the + specific data type must be 8 and the length units + exponent must be 0 or 1; for a frequency-dependent + function, the specific data type must be 18 and the + length units exponent must be 0. In either case, the + other units exponents must be 0. + + c) Record 9: The specific data type must be 13. The + temperature units exponent must be 0. For an ordinate + numerator of force, the length and force units + exponents must be 0 and 1, respectively. For an + ordinate numerator of moment, the length and force + units exponents must be 1 and 1, respectively. + + d) Record 10: The specific data type must be 8 for + stiffness and hysteretic damping; it must be 11 + for viscous damping. For an ordinate denominator of + translational displacement, the length units exponent + must be 1; for a rotational displacement, it must + be 0. The other units exponents must be 0. + + e) Dataset 217 must precede each function in order to + define the function's usage (i.e. stiffness, viscous + damping, hysteretic damping). + + Addendum A + + In order to correctly perform units conversion, length, force, and + temperature exponents must be supplied for a specific data type of + General; that is, Record 8 Field 1 = 1. For example, if the function + has the physical dimensionality of Energy (Force * Length), then the + required exponents would be as follows: + + Length = 1 + Force = 1 Energy = L * F + Temperature = 0 + + Units exponents for the remaining specific data types should not be + supplied. The following exponents will automatically be used. + + Table - Unit Exponents + ------------------------------------------------------- + Specific Direction + --------------------------------------------- + Data Translational Rotational + --------------------------------------------- + Type Length Force Temp Length Force Temp + ------------------------------------------------------- + 0 0 0 0 0 0 0 + 1 (requires input to fields 2,3,4) + 2 -2 1 0 -1 1 0 + 3 0 0 0 0 0 0 + 5 0 0 1 0 0 1 + 6 1 1 0 1 1 0 + 8 1 0 0 0 0 0 + 9 0 1 0 1 1 0 + 11 1 0 0 0 0 0 + 12 1 0 0 0 0 0 + 13 0 1 0 1 1 0 + 15 -2 1 0 -1 1 0 + 16 -1 1 0 1 1 0 + 17 0 0 0 0 0 0 + 18 0 0 0 0 0 0 + 19 0 0 0 0 0 0 + -------------------------------------------------------- + + NOTE + + Units exponents for scalar points are defined within + System Analysis prior to reading this dataset. + + Addendum B + + There are 8 distinct combinations of parameters which affect the + details of READ/WRITE operations. The parameters involved are + Ordinate Data Type, Ordinate Data Precision, and Abscissa Spacing. + Each combination is documented in the examples below. In all cases, + the number of data values (for even abscissa spacing) or data pairs + (for uneven abscissa spacing) is NVAL. The abcissa is always real + single precision. Complex double precision is handled by two real + double precision variables (real part followed by imaginary part) + because most systems do not directly support complex double precision. + + CASE 1 + + REAL + SINGLE PRECISION + EVEN SPACING + + Order of data in file Y1 Y2 Y3 Y4 Y5 Y6 + Y7 Y8 Y9 Y10 Y11 Y12 + . + . + . + Input + + REAL Y(6) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )(Y(I),I=1,6) + 1000 FORMAT(6E13.5) + NPRO=NPRO+6 + . + . code to process these six values + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + Output + + REAL Y(6) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up these six values + . + WRITE(LUN,1000,ERR= )(Y(I),I=1,6) + 1000 FORMAT(6E13.5) + NPRO=NPRO+6 + + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + CASE 2 + + REAL + SINGLE PRECISION + UNEVEN SPACING + + Order of data in file X1 Y1 X2 Y2 X3 Y3 + X4 Y4 X5 Y5 X6 Y6 + . + . + . + + Input + + REAL X(3),Y(3) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )(X(I),Y(I),I=1,3) + 1000 FORMAT(6E13.5) + NPRO=NPRO+3 + . + . code to process these three values + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + Output + + REAL X(3),Y(3) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up these three values + . + WRITE(LUN,1000,ERR= )(X(I),Y(I),I=1,3) + 1000 FORMAT(6E13.5) + NPRO=NPRO+3 + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + CASE 3 + + COMPLEX + SINGLE PRECISION + EVEN SPACING + + Order of data in file RY1 IY1 RY2 IY2 RY3 IY3 + RY4 IY4 RY5 IY5 RY6 IY6 + . + . + . + + Input + + COMPLEX Y(3) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )(Y(I),I=1,3) + 1000 FORMAT(6E13.5) + NPRO=NPRO+3 + . + . code to process these six values + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + + Output + + COMPLEX Y(3) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up these three values + . + WRITE(LUN,1000,ERR= )(Y(I),I=1,3) + 1000 FORMAT(6E13.5) + NPRO=NPRO+3 + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + CASE 4 + + COMPLEX + SINGLE PRECISION + UNEVEN SPACING + + Order of data in file X1 RY1 IY1 X2 RY2 IY2 + X3 RY3 IY3 X4 RY4 IY4 + + . + . + . + + Input + + REAL X(2) + COMPLEX Y(2) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )(X(I),Y(I),I=1,2) + 1000 FORMAT(6E13.5) + NPRO=NPRO+2 + . + . code to process these two values + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + Output + + REAL X(2) + COMPLEX Y(2) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up these two values + . + WRITE(LUN,1000,ERR= )(X(I),Y(I),I=1,2) + 1000 FORMAT(6E13.5) + NPRO=NPRO+2 + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + CASE 5 + + REAL + DOUBLE PRECISION + EVEN SPACING + + Order of data in file Y1 Y2 Y3 Y4 + Y5 Y6 Y7 Y8 + . + . + . + Input + + DOUBLE PRECISION Y(4) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )(Y(I),I=1,4) + 1000 FORMAT(4E20.12) + NPRO=NPRO+4 + . + . code to process these four values + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + Output + + DOUBLE PRECISION Y(4) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up these four values + . + WRITE(LUN,1000,ERR= )(Y(I),I=1,4) + 1000 FORMAT(4E20.12) + NPRO=NPRO+4 + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + CASE 6 + + REAL + DOUBLE PRECISION + UNEVEN SPACING + + Order of data in file X1 Y1 X2 Y2 + X3 Y3 X4 Y4 + . + . + . + Input + + REAL X(2) + DOUBLE PRECISION Y(2) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )(X(I),Y(I),I=1,2) + 1000 FORMAT(2(E13.5,E20.12)) + NPRO=NPRO+2 + . + . code to process these two values + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + Output + + REAL X(2) + DOUBLE PRECISION Y(2) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up these two values + . + WRITE(LUN,1000,ERR= )(X(I),Y(I),I=1,2) + 1000 FORMAT(2(E13.5,E20.12)) + NPRO=NPRO+2 + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + CASE 7 + + COMPLEX + DOUBLE PRECISION + EVEN SPACING + + Order of data in file RY1 IY1 RY2 IY2 + RY3 IY3 RY4 IY4 + . + . + . + + Input + + DOUBLE PRECISION Y(2,2) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )((Y(I,J),I=1,2),J=1,2) + 1000 FORMAT(4E20.12) + NPRO=NPRO+2 + . + . code to process these two values + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + Output + + DOUBLE PRECISION Y(2,2) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up these two values + . + WRITE(LUN,1000,ERR= )((Y(I,J),I=1,2),J=1,2) + 1000 FORMAT(4E20.12) + NPRO=NPRO+2 + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + CASE 8 + + COMPLEX + DOUBLE PRECISION + UNEVEN SPACING + + Order of data in file X1 RY1 IY1 + X2 RY2 IY2 + . + . + . + Input + + REAL X + DOUBLE PRECISION Y(2) + . + . + . + NPRO=0 + 10 READ(LUN,1000,ERR= ,END= )(X,Y(I),I=1,2) + 1000 FORMAT(E13.5,2E20.12) + NPRO=NPRO+1 + . + . code to process this value + . + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . + + Output + + REAL X + DOUBLE PRECISION Y(2) + . + . + . + NPRO=0 + 10 CONTINUE + . + . code to set up this value + . + WRITE(LUN,1000,ERR= )(X,Y(I),I=1,2) + 1000 FORMAT(E13.5,2E20.12) + NPRO=NPRO+1 + IF(NPRO.LT.NVAL)GO TO 10 + . + . continued processing + . +""" +function parse_dataset58(io) + + id1 = strip(readline(io)) + id2 = strip(readline(io)) + id3 = strip(readline(io)) + id4 = strip(readline(io)) + id5 = strip(readline(io)) + # @show(id1, id2, id3, id4, id5) + + # Record 6 + r6 = readline(io) + len_r6 = length(r6) + @show(r6) + #=r6 = split(readline(io)) + + func_type = parse(Int, strip(r6[1])) + func_id = parse(Int, strip(r6[2])) + version_num = parse(Int, strip(r6[3])) + load_case_id = parse(Int, strip(r6[4])) + response_entity = strip(r6[5]) + response_node = parse(Int, strip(r6[6])) + response_direction = parse(Int, strip(r6[7])) + reference_entity = strip(r6[8])=# + # This modified for the space in Sample_UFF58b_bin.uff record 6 field 5 + func_type = parse(Int, r6[1:5]) + func_id = parse(Int, r6[6:15]) + version_num = parse(Int, r6[16:20]) + load_case_id = parse(Int, r6[21:30]) + response_entity = r6[32:41] + response_node = parse(Int, r6[42:51]) + response_direction = parse(Int, r6[52:55]) + reference_entity = r6[57:66] + + if len_r6 > 8 + reference_node = parse(Int, r6[67:76]) + reference_direction = parse(Int, r6[77:80]) + else + reference_node = 0 + reference_direction = 0 + end + + # Record 7 + r7 = split(readline(io)) + ord_dtype, num_pts, abs_spacing_type = parse.(Int, strip.(r7[1:3])) + abs_min, abs_increment, zval = parse.(Float64, strip.(r7[4:6])) + + # Record 8 + r8 = split(readline(io)) + abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp = parse.(Int, strip.(r8[1:4])) + abs_axis_label, abs_axis_unit_label = strip.(r8[5:6]) + + # Record 9 + r9 = split(readline(io)) + ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp = parse.(Int, strip.(r9[1:4])) + ord_axis_label, ord_axis_unit_label = strip.(r9[5:6]) + + # Record 10 + r10 = split(readline(io)) + ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp = parse.(Int, strip.(r10[1:4])) + ord_denom_axis_label, ord_denom_axis_unit_label = strip.(r10[5:6]) + + # Record 11 + r11 = split(readline(io)) + z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp = parse.(Int, strip.(r11[1:4])) + z_axis_label, z_axis_unit_label = strip.(r11[5:6]) + + # Record 12 + + data, dtype = if ord_dtype == 2 + Float32[], Float32 + elseif ord_dtype == 4 + Float64[], Float64 + elseif ord_dtype == 5 + ComplexF32[], Float32 + elseif ord_dtype == 6 + ComplexF64[], Float64 + end + + # for dv in data_values + # entries = split(dv) + # _data = parse.(dtype, strip.(entries)) + # if ord_dtype < 5 + # append!(data, _data) + # elseif ord_dtype == 5 + # append!(data, complex.(_data[1:2:end], _data[2:2:end])) + # elseif ord_dtype == 6 + # append!(data, complex.(_data[1:2:end], _data[2:2:end])) + # end + # end + + while (dv = readline(io)) != " -1" + # Check if line contains spaces (standard format) or fixed-width fields (UFF58 specification) + if occursin(r"\s+", strip(dv)) && !occursin(r"^[\s\-\+\d\.E]+$", dv) + # Format with spaces - use standard split + entries = split(dv) + _data = parse.(dtype, strip.(entries)) + else + # Format without spaces - use fixed-width positions according to UFF58 specification + entries = String[] + line = dv + + if ord_dtype == 2 || ord_dtype == 5 + # Single precision: E13.5 format (13 characters per value) + field_width = 13 + elseif ord_dtype == 4 || ord_dtype == 6 + # Double precision: E20.12 format (20 characters per value) + field_width = 20 + end + + # Extract fixed-width fields + pos = 1 + while pos <= length(line) + if pos + field_width - 1 <= length(line) + field = strip(line[pos:pos+field_width-1]) + if !isempty(field) + push!(entries, field) + end + pos += field_width + else + # Last field potentially shorter + field = strip(line[pos:end]) + if !isempty(field) + push!(entries, field) + end + break + end + end + + _data = parse.(dtype, entries) + end + + if ord_dtype < 5 + append!(data, _data) + elseif ord_dtype == 5 + append!(data, complex.(_data[1:2:end], _data[2:2:end])) + elseif ord_dtype == 6 + append!(data, complex.(_data[1:2:end], _data[2:2:end])) + end + end + + nd = length(data) + if nd != num_pts + if nd > num_pts + data = data[1:num_pts] + end + end + + return Dataset58( + id1, + id2, + id3, + id4, + id5, + func_type, + func_id, + version_num, + load_case_id, + response_entity, + response_node, + response_direction, + reference_entity, + reference_node, + reference_direction, + ord_dtype, + num_pts, + abs_spacing_type, + abs_min, + abs_increment, + zval, + abs_spec_dtype, + abs_len_unit_exp, + abs_force_unit_exp, + abs_temp_unit_exp, + abs_axis_label, + abs_axis_unit_label, + ord_spec_dtype, + ord_len_unit_exp, + ord_force_unit_exp, + ord_temp_unit_exp, + ord_axis_label, + ord_axis_unit_label, + ord_denom_spec_dtype, + ord_denom_len_unit_exp, + ord_denom_force_unit_exp, + ord_denom_temp_unit_exp, + ord_denom_axis_label, + ord_denom_axis_unit_label, + z_spec_dtype, + z_len_unit_exp, + z_force_unit_exp, + z_temp_unit_exp, + z_axis_label, + z_axis_unit_label, + abscissa, + data + ) +end + +""" + write_dataset(dataset::Dataset58) -> Vector{String} + +Write a UFF Dataset 58 (Function Data) to a vector of strings. + +**Input** +- `dataset::Dataset58`: The Dataset58 instance to write. + +**Output** +- `Vector{String}`: A vector of strings representing the lines of the dataset. +""" +function write_dataset(dataset::Dataset58) + lines = String[] + + # Start marker + push!(lines, " -1") + + # Dataset number + push!(lines, " 58") + + # Records 1-5: ID Lines (80A1 format) + push!(lines, dataset.id1) + push!(lines, dataset.id2) + push!(lines, dataset.id3) + push!(lines, dataset.id4) + push!(lines, dataset.id5) + + # Record 6: DOF Identification + # Format: 2(I5,I10),2(1X,10A1,I10,I4) + r6_line = @sprintf("%5d%10d%5d%10d %-10s%10d%4d %-10s%10d%4d", + dataset.func_type, + dataset.func_id, + dataset.ver_num, + dataset.load_case, + dataset.resp_name, + dataset.resp_node, + dataset.resp_dir, + dataset.ref_name, + dataset.ref_node, + dataset.ref_dir) + push!(lines, r6_line) + + # Record 7: Data Form + # Format: 3I10,3E13.5 + r7_line = @sprintf("%10d%10d%10d%13.5E%13.5E%13.5E", + dataset.ord_dtype, + dataset.num_pts, + dataset.abs_spacing_type, + dataset.abs_min, + dataset.abs_increment, + dataset.zval) + push!(lines, r7_line) + + # Record 8: Abscissa Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r8_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.abs_spec_dtype, + dataset.abs_len_unit_exp, + dataset.abs_force_unit_exp, + dataset.abs_temp_unit_exp, + dataset.abs_axis_label, + dataset.abs_axis_unit_label) + push!(lines, r8_line) + + # Record 9: Ordinate Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r9_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.ord_spec_dtype, + dataset.ord_len_unit_exp, + dataset.ord_force_unit_exp, + dataset.ord_temp_unit_exp, + dataset.ord_axis_label, + dataset.ord_axis_unit_label) + push!(lines, r9_line) + + # Record 10: Ordinate Denominator Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r10_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.ord_denom_spec_dtype, + dataset.ord_denom_len_unit_exp, + dataset.ord_denom_force_unit_exp, + dataset.ord_denom_temp_unit_exp, + dataset.ord_denom_axis_label, + dataset.ord_denom_axis_unit_label) + push!(lines, r10_line) + + # Record 11: Z-axis Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r11_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.z_spec_dtype, + dataset.z_len_unit_exp, + dataset.z_force_unit_exp, + dataset.z_temp_unit_exp, + dataset.z_axis_label, + dataset.z_axis_unit_label) + push!(lines, r11_line) + + # Record 12: Data Values + # Format depends on ordinate data type and precision + if dataset.ord_dtype == 2 || dataset.ord_dtype == 4 + # Real data (single or double precision) + if dataset.ord_dtype == 2 + # Real single precision: 6E13.5 + values_per_line = 6 + fmt = "E13.5" + else + # Real double precision: 4E20.12 + values_per_line = 4 + fmt = "E20.12" + end + + # Write data in chunks + for i in 1:values_per_line:length(dataset.data) + end_idx = min(i + values_per_line - 1, length(dataset.data)) + chunk = dataset.data[i:end_idx] + + if dataset.ord_dtype == 2 + line = join([@sprintf(" %12.5E", v) for v in chunk], "") + else + line = join([@sprintf(" %19.12E", v) for v in chunk], "") + end + push!(lines, line) + end + + elseif dataset.ord_dtype == 5 || dataset.ord_dtype == 6 + # Complex data (single or double precision) + if dataset.ord_dtype == 5 + # Complex single precision: 6E13.5 (3 complex values per line) + values_per_line = 3 + else + # Complex double precision: 4E20.12 (2 complex values per line) + values_per_line = 2 + end + + # Write data in chunks (real and imaginary parts interleaved) + for i in 1:values_per_line:length(dataset.data) + end_idx = min(i + values_per_line - 1, length(dataset.data)) + chunk = dataset.data[i:end_idx] + + if dataset.ord_dtype == 5 + # 6E13.5 format + parts = Float64[] + for c in chunk + push!(parts, real(c)) + push!(parts, imag(c)) + end + line = join([@sprintf(" %12.5E", v) for v in parts], "") + else + # 4E20.12 format + parts = Float64[] + for c in chunk + push!(parts, real(c)) + push!(parts, imag(c)) + end + line = join([@sprintf(" %19.12E", v) for v in parts], "") + end + push!(lines, line) + end + end + + # End marker + push!(lines, " -1") + + return lines +end \ No newline at end of file diff --git a/src/datasets/dataset58b.jl b/src/datasets/dataset58b.jl new file mode 100644 index 0000000..7364ba4 --- /dev/null +++ b/src/datasets/dataset58b.jl @@ -0,0 +1,423 @@ +""" +The Binary 58 Universal File Format (UFF): + +The basic (ASCII) universal file format for data is universal file format +58. This format is completely documented by SDRC and a copy of that +documentation is on the UC-SDRL web site (58.asc). The +universal file format always begins with two records that are prior to the +information defined by each universal file format and ends with a record +that is placed after the information defined by the format. First of +all, all records are 80 character ASCII records for the basic universal +file format. The first and last record are start/stop records and are +always -1 in the first six columns, right justified (Fortran I6 field +with -1 in the field). The second record (Identifier Record) always +contains the universal file format number in the first 6 columns, right +justified. + +This gives a file structure as follows (where b represent a blank +character): + +bbbb-1 +bbbb58 +... +... +... +bbbb-1 + +The Binary 58 universal file format was originally developed by UC-SDRL +in order to eliminate the need to compress the UFF 58 records and to reduce +the time required to load the UFF 58 data records. The Binary 58 universal file +format yields files that are comparable to compressed files (approximately 3 to +4 times smaller than the equivalent UFF 58 file). The Binary 58 universal file +format loads approximately 30 to 40 times faster than the equivalent UFF 58 +file, depending upon the computing environment. This new format was +submitted to SDRC and subsequently adopted as a supported format. + +The Binary 58 universal file format uses the same ASCII records at the +start of each data file as the ASCII dataset 58 but, beginning with +record 12, the data is stored in binary form rather than the specified +ASCII format. The identifier record has the same 58 identifier in the +first six columns, right justified, but has additional information in +the rest of the 80 character record that identifies the binary format +(the size of the binary record, the format of the binary structure, etc.). + + -1 + 58b x y 11 zzzz 0 0 0 0 +... +... (11 ASCII header lines) +... +... +... (zzzz BINARY bytes of data, in format specifed by x and y, above) +... (interleaved as specified by the ASCII dataset 58) +... + -1 + + +When reading or writing a dataset 58b, care must be taken that the +binary data immediately follows the ASCII header lines and the closing +' -1' immediately follows the binary data. The binary data content +is written in the same sequence as the ASCII dataset 58 (ie. field +order sequence). The field size is NOT used, however the data type +(int/float/double) content is. Note: there are no CR/LF characters +embedded in or following the binary data. + + +===================================================================== +The Format of 58b ID-Line: +---------------------------- + +For the traditional dataset 58 (Function at Nodal DOF), the dataset +id-line is composed of four spaces followed by "58". This line has been +enhanced to contain additional information for the binary version of +dataset 58. + + -1 + 58b 2 2 11 4096 0 0 0 0 + + Format (I6,1A1,I6,I6,I12,I12,I6,I6,I12,I12) + + Field 1 - 58 [I6] + Field 2 - lowercase b [1A1] + Field 3 - Byte Ordering Method [I6] + 1 - Little Endian (DEC VMS & ULTRIX, WIN NT) + 2 - Big Endian (most UNIX) + Field 4 - Floating Point Format [I6] + 1 - DEC VMS + 2 - IEEE 754 (UNIX) + 3 - IBM 5/370 + Field 5 - number of ASCII lines following [I12] + 11 - for dataset 58 + Field 6 - number of bytes following ASCII lines [I12] + Fields 7-10 - Not used (fill with zeros) + + +The format of this line should remain constant for any other dataset +that takes on a binary format in the future. +""" +function parse_dataset58b(io) + + reset(io) + func = readline(io) + + # Need to implement proper error handling + endian = parse(Int, func[8:13]) # Julia only runs on little endian (as far as I am aware) [I6] + endian == 1 || println("Only implemented for Little Endian") + floating_point_format = parse(Int, func[14:19]) # Floating Point Format [I6] + floating_point_format == 1 || println("Only implemented for IEEE 754") + num_ascii_lines = parse(Int, func[20:31]) # number of ASCII lines following [I12] + num_ascii_lines == 1 || println("Header not correct") + binary_bytes = parse(Int, func[32:43]) # number of bytes following ASCII lines [I12] + + id1 = strip(readline(io)) + id2 = strip(readline(io)) + id3 = strip(readline(io)) + id4 = strip(readline(io)) + id5 = strip(readline(io)) + + # Record 6 + r6 = readline(io) + len_r6 = length(r6) + #=r6 = split(readline(io)) + + func_type = parse(Int, strip(r6[1])) + func_id = parse(Int, strip(r6[2])) + version_num = parse(Int, strip(r6[3])) + load_case_id = parse(Int, strip(r6[4])) + response_entity = strip(r6[5]) + response_node = parse(Int, strip(r6[6])) + response_direction = parse(Int, strip(r6[7])) + reference_entity = strip(r6[8])=# + # This modified for the space in Sample_UFF58b_bin.uff record 6 field 5 + func_type = parse(Int, r6[1:5]) + func_id = parse(Int, r6[6:15]) + version_num = parse(Int, r6[16:20]) + load_case_id = parse(Int, r6[21:30]) + response_entity = r6[32:41] + # @show(r6[32:41]) + response_node = parse(Int, r6[42:51]) + response_direction = parse(Int, r6[52:55]) + reference_entity = r6[57:66] + + if len_r6 > 8 + reference_node = parse(Int, r6[67:76]) + reference_direction = parse(Int, r6[77:80]) + else + reference_node = 0 + reference_direction = 0 + end + + # Record 7 + r7 = split(readline(io)) + ord_dtype, num_pts, abs_spacing_type = parse.(Int, strip.(r7[1:3])) + abs_min, abs_increment, zval = parse.(Float64, strip.(r7[4:6])) + + # Record 8 + r8 = split(readline(io)) + abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp = parse.(Int, strip.(r8[1:4])) + abs_axis_label, abs_axis_unit_label = strip.(r8[5:6]) + + # Record 9 + r9 = split(readline(io)) + ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp = parse.(Int, strip.(r9[1:4])) + ord_axis_label, ord_axis_unit_label = strip.(r9[5:6]) + + # Record 10 + r10 = split(readline(io)) + ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp = parse.(Int, strip.(r10[1:4])) + ord_denom_axis_label, ord_denom_axis_unit_label = strip.(r10[5:6]) + + # Record 11 + r11 = split(readline(io)) + z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp = parse.(Int, strip.(r11[1:4])) + z_axis_label, z_axis_unit_label = strip.(r11[5:6]) + + # Record 12 + _data = read(io, binary_bytes) + + # Convert UInt8 to Values + if (ord_dtype == 2 && abs_spacing_type == 1) # Case 1 - Real, Single Precision, Even Spacing + abscissa = Float32[] + data = reinterpret(Float32, _data) + elseif (ord_dtype == 2 && abs_spacing_type == 0) # Case 2 - Real, Single Precision, Uneven Spacing + tmp = reshape(reinterpret(Float32, _data), (2, :))' + abscissa = tmp[:, 1] + data = tmp[:, 2] + elseif (ord_dtype == 5 && abs_spacing_type == 1) # Case 3 - Complex, Single Precision, Even Spacing + abscissa = Float32[] + data = reinterpret(ComplexF32, _data) + elseif (ord_dtype == 5 && abs_spacing_type == 0) # Case 4 - Complex, Single Precision, Uneven Spacing + tmp = reshape(reinterpret(Float32, _data), (3, :))' + abscissa = tmp[:, 1] + data = reinterpret(ComplexF32, reshape(tmp[:, 2:3]', (:, 1))) + elseif (ord_dtype == 2 && abs_spacing_type == 1) # Case 5 - Real, Double Precision, Even Spacing + abscissa = Float64[] + data = reinterpret(Float64, _data) + elseif (ord_dtype == 2 && abs_spacing_type == 0) # Case 6 - Real, Double Precision, Uneven Spacing + 2*8*num_pts == binary_bytes || println("Data Integrity Problem") + tmp = reshape(reinterpret(Float64, _data), (2, :))' + abscissa = tmp[:, 1] + data = tmp[:, 2] + elseif (ord_dtype == 5 && abs_spacing_type == 1) # Case 7 - Complex, Double Precision, Even Spacing + abscissa = Float64[] + data = reinterpret(ComplexF64, _data) + elseif (ord_dtype == 5 && abs_spacing_type == 0) # Case 8 - Complex, Double Precision, Uneven Spacing + # There is some ambiguity as to whether the abscissa is Float32 or Float64. This handles both + if 3*8*num_pts == binary_bytes + tmp = reshape(reinterpret(Float64, _data), (3, :))' + abscissa = tmp[:, 1] + data = reinterpret(ComplexF64, reshape(tmp[:, 2:3]', (:, 1))) + elseif (4+16)*num_pts == binary_bytes + abscissa = reinterpret(Float32, Float_data[1:20:binary_bytes]) + data = reinterpret(Float64, _data[5:20:binary_bytes]) + else + println("Data Integrity Problem") + end + end + + readline(io) # remove trailing " -1" from dataset + + return Dataset58( + id1, + id2, + id3, + id4, + id5, + func_type, + func_id, + version_num, + load_case_id, + response_entity, + response_node, + response_direction, + reference_entity, + reference_node, + reference_direction, + ord_dtype, + num_pts, + abs_spacing_type, + abs_min, + abs_increment, + zval, + abs_spec_dtype, + abs_len_unit_exp, + abs_force_unit_exp, + abs_temp_unit_exp, + abs_axis_label, + abs_axis_unit_label, + ord_spec_dtype, + ord_len_unit_exp, + ord_force_unit_exp, + ord_temp_unit_exp, + ord_axis_label, + ord_axis_unit_label, + ord_denom_spec_dtype, + ord_denom_len_unit_exp, + ord_denom_force_unit_exp, + ord_denom_temp_unit_exp, + ord_denom_axis_label, + ord_denom_axis_unit_label, + z_spec_dtype, + z_len_unit_exp, + z_force_unit_exp, + z_temp_unit_exp, + z_axis_label, + z_axis_unit_label, + abscissa, + data + ) +end + +function write_dataset58(dataset::Dataset58) + lines = String[] + + # Start marker + push!(lines, " -1") + + # Dataset number + push!(lines, " 58") + + # Records 1-5: ID Lines (80A1 format) + push!(lines, dataset.id1) + push!(lines, dataset.id2) + push!(lines, dataset.id3) + push!(lines, dataset.id4) + push!(lines, dataset.id5) + + # Record 6: DOF Identification + # Format: 2(I5,I10),2(1X,10A1,I10,I4) + r6_line = @sprintf("%5d%10d%5d%10d %-10s%10d%4d %-10s%10d%4d", + dataset.func_type, + dataset.func_id, + dataset.ver_num, + dataset.load_case, + dataset.resp_name, + dataset.resp_node, + dataset.resp_dir, + dataset.ref_name, + dataset.ref_node, + dataset.ref_dir) + push!(lines, r6_line) + + # Record 7: Data Form + # Format: 3I10,3E13.5 + r7_line = @sprintf("%10d%10d%10d%13.5E%13.5E%13.5E", + dataset.ord_dtype, + dataset.num_pts, + dataset.abs_spacing_type, + dataset.abs_min, + dataset.abs_increment, + dataset.zval) + push!(lines, r7_line) + + # Record 8: Abscissa Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r8_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.abs_spec_dtype, + dataset.abs_len_unit_exp, + dataset.abs_force_unit_exp, + dataset.abs_temp_unit_exp, + dataset.abs_axis_label, + dataset.abs_axis_unit_label) + push!(lines, r8_line) + + # Record 9: Ordinate Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r9_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.ord_spec_dtype, + dataset.ord_len_unit_exp, + dataset.ord_force_unit_exp, + dataset.ord_temp_unit_exp, + dataset.ord_axis_label, + dataset.ord_axis_unit_label) + push!(lines, r9_line) + + # Record 10: Ordinate Denominator Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r10_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.ord_denom_spec_dtype, + dataset.ord_denom_len_unit_exp, + dataset.ord_denom_force_unit_exp, + dataset.ord_denom_temp_unit_exp, + dataset.ord_denom_axis_label, + dataset.ord_denom_axis_unit_label) + push!(lines, r10_line) + + # Record 11: Z-axis Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r11_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.z_spec_dtype, + dataset.z_len_unit_exp, + dataset.z_force_unit_exp, + dataset.z_temp_unit_exp, + dataset.z_axis_label, + dataset.z_axis_unit_label) + push!(lines, r11_line) + + # Record 12: Data Values + # Format depends on ordinate data type and precision + if dataset.ord_dtype == 2 || dataset.ord_dtype == 4 + # Real data (single or double precision) + if dataset.ord_dtype == 2 + # Real single precision: 6E13.5 + values_per_line = 6 + fmt = "E13.5" + else + # Real double precision: 4E20.12 + values_per_line = 4 + fmt = "E20.12" + end + + # Write data in chunks + for i in 1:values_per_line:length(dataset.data) + end_idx = min(i + values_per_line - 1, length(dataset.data)) + chunk = dataset.data[i:end_idx] + + if dataset.ord_dtype == 2 + line = join([@sprintf(" %12.5E", v) for v in chunk], "") + else + line = join([@sprintf(" %19.12E", v) for v in chunk], "") + end + push!(lines, line) + end + + elseif dataset.ord_dtype == 5 || dataset.ord_dtype == 6 + # Complex data (single or double precision) + if dataset.ord_dtype == 5 + # Complex single precision: 6E13.5 (3 complex values per line) + values_per_line = 3 + else + # Complex double precision: 4E20.12 (2 complex values per line) + values_per_line = 2 + end + + # Write data in chunks (real and imaginary parts interleaved) + for i in 1:values_per_line:length(dataset.data) + end_idx = min(i + values_per_line - 1, length(dataset.data)) + chunk = dataset.data[i:end_idx] + + if dataset.ord_dtype == 5 + # 6E13.5 format + parts = Float64[] + for c in chunk + push!(parts, real(c)) + push!(parts, imag(c)) + end + line = join([@sprintf(" %12.5E", v) for v in parts], "") + else + # 4E20.12 format + parts = Float64[] + for c in chunk + push!(parts, real(c)) + push!(parts, imag(c)) + end + line = join([@sprintf(" %19.12E", v) for v in parts], "") + end + push!(lines, line) + end + end + + # End marker + push!(lines, " -1") + + return lines +end \ No newline at end of file diff --git a/src/datasets/dataset58common.jl b/src/datasets/dataset58common.jl new file mode 100644 index 0000000..8e5f9ba --- /dev/null +++ b/src/datasets/dataset58common.jl @@ -0,0 +1,172 @@ +""" + Dataset58 + +A struct containing UFF Dataset 58 (Function at nodal dof) data. + +**Fields** +- `type::Symbol`: Data set type +- `name::String`: Data set name +- `id1::String`: ID line 1 +- `id2::String`: ID line 2 +- `id3::String`: ID line 3 +- `id4::String`: ID line 4 +- `id5::String`: ID line 5 +- `func_type::Int`: Function type +- `func_id::Int`: Function ID +- `ver_num::Int`: Version number +- `load_case::Int`: Load case +- `resp_name::String`: Response name +- `resp_node::Int`: Response node +- `resp_dir::Int`: Response direction +- `ref_name::String`: Reference name +- `ref_node::Int`: Reference node +- `ref_dir::Int`: Reference direction +- `ord_dtype::Int`: Ordinate data type +- `num_pts::Int`: Number of points +- `abs_spacing_type::Int`: Abscissa spacing type +- `abs_start::Float64`: Abscissa start +- `abs_increment::Float64`: Abscissa increment +- `zval::Float64`: Z-axis value +- `abs_spec_dtype::Int`: Abscissa specification data type +- `abs_len_unit_exp::Int`: Abscissa length unit exponent +- `abs_force_unit_exp::Int`: Abscissa force unit exponent +- `abs_temp_unit_exp::Int`: Abscissa temperature unit exponent +- `abs_axis_label::String`: Abscissa axis label +- `abs_axis_unit_label::String`: Abscissa axis unit label +- `ord_spec_dtype::Int`: Ordinate specification data type +- `ord_len_unit_exp::Int`: Ordinate length unit exponent +- `ord_force_unit_exp::Int`: Ordinate force unit exponent +- `ord_temp_unit_exp::Int`: Ordinate temperature unit exponent +- `ord_axis_label::String`: Ordinate axis label +- `ord_axis_unit_label::String`: Ordinate axis unit label +- `ord_denom_spec_dtype::Int`: Ordinate denominator specification data type +- `ord_denom_len_unit_exp::Int`: Ordinate denominator length unit exponent +- `ord_denom_force_unit_exp::Int`: Ordinate denominator force unit exponent +- `ord_denom_temp_unit_exp::Int`: Ordinate denominator temperature unit exponent +- `ord_denom_axis_label::String`: Ordinate denominator axis label +- `ord_denom_axis_unit_label::String`: Ordinate denominator axis unit label +- `z_spec_dtype::Int`: Z-axis specification data type +- `z_len_unit_exp::Int`: Z-axis length unit exponent +- `z_force_unit_exp::Int`: Z-axis force unit exponent +- `z_temp_unit_exp::Int`: Z-axis temperature unit exponent +- `z_axis_label::String`: Z-axis label +- `z_axis_unit_label::String`: Z-axis unit label +- `abscissa` - Data Values (empty if evenly spaced otherwise filled in) +- `data::AbstractVector`: Data values +""" +@show_data struct Dataset58 <: UFFDataset + # Fields specific to Dataset58 + type::Symbol # Data set type + name::String # Data set name + id1::String # Record 1 - field 1 + id2::String # Record 2 - field 1 + id3::String # Record 3 - field 1 + id4::String # Record 4 - field 1 + id5::String # Record 5 - field 1 + + #Record 6 fields + func_type::Int # Record 6 - field 1 + func_id::Int # Record 6 - field 2 + ver_num::Int # Record 6 - field 3 + load_case::Int # Record 6 - field 4 + resp_name::String # Record 6 - field 5 + resp_node::Int # Record 6 - field 6 + resp_dir::Int # Record 6 - field 7 + ref_name::String # Record 6 - field 8 + ref_node::Int # Record 6 - field 9 + ref_dir::Int # Record 6 - field 10 + + # Record 7 fields + ord_dtype::Int # Record 7 - field 1 + num_pts::Int # Record 7 - field 2 + abs_spacing_type::Int # Record 7 - field 3 + abs_min ::Float64 # Record 7 - field 4 + abs_increment ::Float64 # Record 7 - field 5 + zval::Float64 # Record 7 - field 6 + + # Record 8 fields + abs_spec_dtype::Int # Record 8 - field 1 + abs_len_unit_exp::Int # Record 8 - field 2 + abs_force_unit_exp::Int # Record 8 - field 3 + abs_temp_unit_exp::Int # Record 8 - field 4 + abs_axis_label::String # Record 8 - field 5 + abs_axis_unit_label::String # Record 8 - field 6 + + # Record 9 fields + ord_spec_dtype::Int # Record 9 - field 1 + ord_len_unit_exp::Int # Record 9 - field 2 + ord_force_unit_exp::Int # Record 9 - field 3 + ord_temp_unit_exp::Int # Record 9 - field 4 + ord_axis_label::String # Record 9 - field 5 + ord_axis_unit_label::String # Record 9 - field 6 + + # Record 10 fields + ord_denom_spec_dtype::Int # Record 10 - field 1 + ord_denom_len_unit_exp::Int # Record 10 - field 2 + ord_denom_force_unit_exp::Int # Record 10 - field 3 + ord_denom_temp_unit_exp::Int # Record 10 - field 4 + ord_denom_axis_label::String # Record 10 - field 5 + ord_denom_axis_unit_label::String # Record 10 - field 6 + + # Record 11 fields + z_spec_dtype::Int # Record 11 - field 1 + z_len_unit_exp::Int # Record 11 - field 2 + z_force_unit_exp::Int # Record 11 - field 3 + z_temp_unit_exp::Int # Record 11 - field 4 + z_axis_label::String # Record 11 - field 5 + z_axis_unit_label::String # Record 11 - field 6 + + # Record 12 fields + abscissa::AbstractVector # Record 12 if unevely spaced + data::AbstractVector # Record 12 + + Dataset58( + id1 = "", + id2 = "", + id3 = "", + id4 = "", + id5 = "", + func_type = 0, + func_id = 0, + ver_num = 0, + load_case = 0, + resp_name = "", + resp_node = 0, + resp_dir = 0, + ref_name = "", + ref_node = 0, + ref_dir = 0, + ord_dtype = 0, + num_pts = 0, + abs_spacing_type = 0, + abs_min = 0.0, + abs_increment = 0.0, + zval = 0.0, + abs_spec_dtype = 0, + abs_len_unit_exp = 0, + abs_force_unit_exp = 0, + abs_temp_unit_exp = 0, + abs_axis_label = "", + abs_axis_unit_label = "", + ord_spec_dtype = 0, + ord_len_unit_exp = 0, + ord_force_unit_exp = 0, + ord_temp_unit_exp = 0, + ord_axis_label = "", + ord_axis_unit_label = "", + ord_denom_spec_dtype = 0, + ord_denom_len_unit_exp = 0, + ord_denom_force_unit_exp = 0, + ord_denom_temp_unit_exp = 0, + ord_denom_axis_label = "", + ord_denom_axis_unit_label = "", + z_spec_dtype = 0, + z_len_unit_exp = 0, + z_force_unit_exp = 0, + z_temp_unit_exp = 0, + z_axis_label = "", + z_axis_unit_label = "", + abscissa = [], + data = [] + ) = new(:Dataset58, "Function at nodal dof", id1, id2, id3, id4, id5, func_type, func_id, ver_num, load_case, resp_name, resp_node, resp_dir, ref_name, ref_node, ref_dir, ord_dtype, num_pts, abs_spacing_type, abs_min, abs_increment, zval, abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp, abs_axis_label, abs_axis_unit_label, ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp, ord_axis_label, ord_axis_unit_label, ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp, ord_denom_axis_label, ord_denom_axis_unit_label, z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp, z_axis_label, z_axis_unit_label, abscissa, data) +end \ No newline at end of file diff --git a/src/datasets/dataset82.jl b/src/datasets/dataset82.jl index a9e70e9..27d808a 100644 --- a/src/datasets/dataset82.jl +++ b/src/datasets/dataset82.jl @@ -60,13 +60,13 @@ Universal Dataset Number: 82 identification line for a name. 6) Repeat Datasets for each Trace_Line """ -function parse_dataset82(block) - line_number, num_nodes, color = parse.(Int, split(block[2])) - id_line = strip(block[3]) +function parse_dataset82(io) + line_number, num_nodes, color = parse.(Int, split(readline(io))) + id_line = strip(readline(io)) lblock = block[4:end] line_nodes = Int[] - for line in lblock + while (line = readline(io)) != " -1" append!(line_nodes, parse.(Int, split(line))) end diff --git a/src/read_write_uff.jl b/src/read_write_uff.jl index 208f0c2..b5031aa 100644 --- a/src/read_write_uff.jl +++ b/src/read_write_uff.jl @@ -11,32 +11,34 @@ Reads a UFF (Universal File Format) file and parses its contents into a vector o """ function readuff(filename::String) - # Extract blocks from the UFF file - blocks = extract_blocks(filename) - nblocks = length(blocks) - - # Check each block for support - supported_blocks = issupported.(blocks) - nunsup= count(.!supported_blocks) - nsup= nblocks - nunsup - # Initialize an array to hold parsed datasets - data = Vector{UFFDataset}(undef, nsup) - - i = 1 - for (b, block) in enumerate(blocks) - # Determine dataset type from the first line of the block - dtype = strip(block[1]) - if !supported_blocks[b] - @warn "Unsupported dataset type: $dtype - skipping this block." - continue - end - + data = Vector{UFFDataset}(undef, 0) + # https://discourse.julialang.org/t/readline-and-end-of-file/64384/4 + open(filename) do io + while !eof(io) + line = readline(io) + # Look for dataset delimiter + if line == " -1" + # Determine dataset type from the following line & mark the position + mark(io) + line = readline(io) + @show(line) + dtype = length(line) > 6 ? strip(line[1:7]) : strip(line[1:6]) + @show(dtype) + if any(dtype .== supported_datasets()) # Parse the block based on its dataset type # https://stackoverflow.com/questions/34016768/julia-invoke-a-function-by-a-given-string/34023458#34023458 - parse_dataset = getfield(UFFFiles, Symbol("parse_dataset", dtype)) - data[i] = parse_dataset(block) - i += 1 + parse_function = getfield(UFFFiles, Symbol("parse_dataset", dtype)) + @show(parse_function) + datatmp = parse_function(io) + data = push!(data, datatmp) + else + @warn "Unsupported dataset type: $dtype - skipping this dataset" + while readline(io) != " -1" # Remove the -1 from the end of this dataset + end + end + end + end end return data @@ -58,6 +60,7 @@ written. function writeuff(filename::String, data) open(filename, "w") do io for dataset in data + @show(dataset, typeof(dataset)) lines = write_dataset(dataset) # Write the formatted lines to the file diff --git a/src/uff_helpers.jl b/src/uff_helpers.jl index 7da0a84..b38563f 100644 --- a/src/uff_helpers.jl +++ b/src/uff_helpers.jl @@ -21,7 +21,7 @@ Returns a vector of supported UFF dataset types. """ function supported_datasets() # Returns a vector of supported UFF dataset types - return [15, 18, 55, 58, 82, 151, 164, 2411, 2412, 2414] + return ["15", "18", "55", "58", "58b", "82", "151", "164", "1858", "2411", "2412", "2414"] end """ diff --git a/src/uff_utils.jl b/src/uff_utils.jl index dec010c..da10181 100644 --- a/src/uff_utils.jl +++ b/src/uff_utils.jl @@ -45,7 +45,7 @@ end """ extend_line(line::String) -> String -Extends a line to 80 characters by adding spaces if it is shorter than 80 characters. +Extends a line to 80 characters by adding spaces if it is shorter than 80 characters and trim to 80 if req'd. **Input** - `line::String`: The line to be extended. @@ -60,6 +60,8 @@ function extend_line(line) line *= " "^(80 - nl) end + line = length(line) > 80 ? line[1:80] : line + return line end diff --git a/test/datasets/dataset15.unv b/test/datasets/dataset15.unv index 2459b5b..678f3dc 100644 --- a/test/datasets/dataset15.unv +++ b/test/datasets/dataset15.unv @@ -7,4 +7,4 @@ 3 1 0 1 1.88940E+01 7.05130E+01 5.00000E+01 2 1 0 1 3.65000E+01 6.32200E+01 5.00000E+01 1 1 0 1 5.16190E+01 5.16190E+01 5.00000E+01 - -1 \ No newline at end of file + -1 diff --git a/test/datasets/dataset151&164.unv b/test/datasets/dataset151&164.unv new file mode 100644 index 0000000..cfb7b91 --- /dev/null +++ b/test/datasets/dataset151&164.unv @@ -0,0 +1,16 @@ + -1 + 151 +pumpModal +pumpModal +NX I-deas 5 : Test +26-Jan-21 14:01:43 28 0 0 +28-Jan-21 15:18:23 +NX I-deas 5 : Test +28-Jan-21 15:23:22 5 0 10 0 0 + -1 + -1 + 164 + 5mm (milli-newton) 2 + 1.00000000000000000D+03 1.00000000000000000D+03 1.00000000000000000D+00 + 2.73150000000000003D+02 + -1 diff --git a/test/datasets/dataset151_bad_format.unv b/test/datasets/dataset151_bad_format.unv new file mode 100644 index 0000000..2483a22 --- /dev/null +++ b/test/datasets/dataset151_bad_format.unv @@ -0,0 +1,10 @@ + -1 + 151 +17-10-2025_full-face1_Exc-milieu_averaging5-Magnitude_sans acc_b.svd + +PSV Version 10.3.1.0 +17-Oct-25 14:58:08 +None None +PolyUFFExport 4.4.0.0 - Compatible to SDRC +23-Oct-25 14:38:11 + -1 \ No newline at end of file diff --git a/test/datasets/dataset1858.unv b/test/datasets/dataset1858.unv new file mode 100644 index 0000000..edf8aba --- /dev/null +++ b/test/datasets/dataset1858.unv @@ -0,0 +1,10 @@ + -1 + 1858 + 0 0 1 0 0 0 + 0 4 0 0 0 0 0 0 0 0 0 0 + 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 + 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 5.2706007E-02 + 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00 +X+ X+ +NONE + -1 diff --git a/test/datasets/dataset58_FRF.unv b/test/datasets/dataset58_FRF.unv index b3646fd..7c7789b 100644 --- a/test/datasets/dataset58_FRF.unv +++ b/test/datasets/dataset58_FRF.unv @@ -8,7 +8,7 @@ NONE 4 0 0 0 .1.Z- 0 0 .56.Z 0 0 5 1600 1 0.00000E+00 5.00000E-01 0.00000E+00 18 0 0 0 NONE NONE - 0 0 0 0 Receptance (m/s≤)/N + 0 0 0 0 Receptance (m/s)/N 0 0 0 0 NONE NONE 2 0 0 0 NONE NONE -7.69795E-01 0.00000E+00 -1.29302E+00 -9.27769E-01 -8.84841E-01 4.68981E-01 diff --git a/test/datasets/dataset58_FRF_UTF.unv b/test/datasets/dataset58_FRF_UTF.unv new file mode 100644 index 0000000..b3646fd --- /dev/null +++ b/test/datasets/dataset58_FRF_UTF.unv @@ -0,0 +1,548 @@ + -1 + 58 +Frequency Response Function +NONE +05-Dec-18 14:22:22 +NONE +NONE + 4 0 0 0 .1.Z- 0 0 .56.Z 0 0 + 5 1600 1 0.00000E+00 5.00000E-01 0.00000E+00 + 18 0 0 0 NONE NONE + 0 0 0 0 Receptance (m/s≤)/N + 0 0 0 0 NONE NONE + 2 0 0 0 NONE NONE + -7.69795E-01 0.00000E+00 -1.29302E+00 -9.27769E-01 -8.84841E-01 4.68981E-01 + 4.49033E-01 -4.92083E-01 -1.41841E+00 -3.70723E+00 5.27809E-02 7.55944E-02 + 1.23214E-02 2.61379E-02 3.42432E-02 3.33811E-02 4.06272E-02 5.29518E-02 + 2.43586E-02 2.96662E-02 8.94292E-03 5.48408E-02 4.97663E-03 5.23353E-02 + -8.02575E-03 5.70889E-02 -2.80892E-02 5.06595E-02 -3.60888E-02 5.97548E-02 + -4.72775E-02 5.38830E-02 -5.36199E-02 5.12033E-02 -6.25912E-02 5.26219E-02 + -6.31927E-02 4.42813E-02 -6.81290E-02 3.40763E-02 -7.32928E-02 2.80226E-02 + -7.85727E-02 2.28939E-02 -8.68547E-02 1.01752E-02 -9.38070E-02 1.64300E-02 + -8.78238E-02 5.83527E-03 -8.64465E-02 4.02652E-03 -9.01528E-02 -9.70954E-04 + -7.83148E-02 -7.01451E-03 -8.85220E-02 -9.44155E-03 -7.81688E-02 -5.35135E-03 + -8.12845E-02 -7.62479E-03 -6.92312E-02 -1.10552E-02 -7.52836E-02 -9.21142E-03 + -7.04408E-02 -1.00611E-02 -6.84547E-02 -7.22230E-03 -6.74877E-02 -1.84545E-03 + -6.54551E-02 -1.98197E-03 -7.15917E-02 4.27568E-03 -6.76059E-02 9.17144E-03 + -7.13645E-02 1.34165E-02 -7.70859E-02 2.08397E-02 -8.43712E-02 2.40886E-02 + -8.20825E-02 2.36738E-02 -8.74959E-02 3.56456E-02 -9.57208E-02 3.98097E-02 + -1.03007E-01 4.65216E-02 -1.06027E-01 4.91052E-02 -1.08792E-01 5.10429E-02 + -1.24253E-01 6.05992E-02 -1.31353E-01 6.22727E-02 -1.35158E-01 6.92982E-02 + -1.51679E-01 6.95098E-02 -1.56432E-01 7.49052E-02 -1.67174E-01 7.90597E-02 + -1.76003E-01 8.77228E-02 -1.79400E-01 8.80093E-02 -1.89279E-01 9.47225E-02 + -2.07683E-01 9.74967E-02 -2.06251E-01 1.11086E-01 -2.20815E-01 1.18648E-01 + -2.29137E-01 1.32360E-01 -2.38340E-01 1.41168E-01 -2.39878E-01 1.59238E-01 + -2.50705E-01 1.71828E-01 -2.65740E-01 1.84520E-01 -2.68303E-01 2.08405E-01 + -2.80063E-01 2.33871E-01 -2.83953E-01 2.60786E-01 -2.98519E-01 2.95425E-01 + -2.94492E-01 3.28526E-01 -3.01633E-01 3.72440E-01 -3.02429E-01 4.21437E-01 + -2.87812E-01 4.73259E-01 -2.82062E-01 5.37932E-01 -2.54581E-01 6.05017E-01 + -2.28638E-01 6.78219E-01 -1.69644E-01 7.49079E-01 -1.01376E-01 8.32762E-01 + 7.00042E-03 8.99543E-01 1.53058E-01 9.55631E-01 3.43600E-01 9.68372E-01 + 5.81480E-01 9.04666E-01 8.36204E-01 6.96799E-01 1.01321E+00 2.23696E-01 + 6.27690E-01 -5.09511E-01 -4.57432E-01 -3.58843E-01 -5.88640E-01 5.08750E-01 + -2.32013E-01 8.72941E-01 7.25749E-02 9.45661E-01 2.91260E-01 9.14808E-01 + 4.28485E-01 8.33584E-01 5.21422E-01 7.43041E-01 5.78783E-01 6.64228E-01 + 6.12094E-01 5.92079E-01 6.30781E-01 5.23322E-01 6.38534E-01 4.63360E-01 + 6.39426E-01 4.21572E-01 6.42521E-01 3.70486E-01 6.34443E-01 3.37347E-01 + 6.25465E-01 3.06634E-01 6.19649E-01 2.79415E-01 6.15271E-01 2.61206E-01 + 6.02782E-01 2.46046E-01 5.97745E-01 2.24457E-01 5.91873E-01 2.11157E-01 + 5.85403E-01 1.95200E-01 5.77655E-01 1.83312E-01 5.72757E-01 1.78553E-01 + 5.57468E-01 1.68269E-01 5.53414E-01 1.63085E-01 5.43503E-01 1.53257E-01 + 5.29197E-01 1.43953E-01 5.14206E-01 1.45337E-01 4.94941E-01 1.37294E-01 + 4.68431E-01 1.38184E-01 4.41705E-01 1.40000E-01 4.02575E-01 1.47823E-01 + 3.49080E-01 1.62956E-01 2.76227E-01 1.93916E-01 1.80719E-01 2.42615E-01 + 4.24915E-02 3.36870E-01 -1.70370E-01 5.47194E-01 -4.51237E-01 1.09557E+00 + -8.16635E-02 2.44635E+00 2.06970E+00 2.37987E+00 2.40031E+00 9.08661E-01 + 2.01101E+00 4.09814E-01 1.81957E+00 2.07512E-01 1.67889E+00 8.15626E-02 + 1.57914E+00 2.49959E-02 1.51063E+00 -1.72509E-02 1.47360E+00 -4.23241E-02 + 1.44969E+00 -6.07675E-02 1.44169E+00 -7.67130E-02 1.44474E+00 -1.02720E-01 + 1.44903E+00 -1.17633E-01 1.46527E+00 -1.44342E-01 1.48496E+00 -1.65150E-01 + 1.51002E+00 -1.86697E-01 1.54790E+00 -2.11964E-01 1.58448E+00 -2.40096E-01 + 1.62641E+00 -2.75815E-01 1.67607E+00 -3.12525E-01 1.72946E+00 -3.60972E-01 + 1.78469E+00 -4.16443E-01 1.84842E+00 -4.85691E-01 1.89362E+00 -5.56699E-01 + 1.94373E+00 -6.34864E-01 1.99616E+00 -6.96061E-01 2.07686E+00 -7.66583E-01 + 2.15918E+00 -8.46900E-01 2.27548E+00 -9.52038E-01 2.39946E+00 -1.07820E+00 + 2.55066E+00 -1.24994E+00 2.70268E+00 -1.46805E+00 2.85988E+00 -1.74875E+00 + 3.00648E+00 -2.09818E+00 3.12194E+00 -2.56420E+00 3.16143E+00 -3.12954E+00 + 3.07826E+00 -3.84702E+00 2.76438E+00 -4.67844E+00 2.07598E+00 -5.53842E+00 + 9.43545E-01 -6.18351E+00 -4.95483E-01 -6.28228E+00 -1.80921E+00 -5.72092E+00 + -2.63933E+00 -4.74819E+00 -2.96090E+00 -3.76337E+00 -2.97899E+00 -2.95110E+00 + -2.83994E+00 -2.33472E+00 -2.63881E+00 -1.88048E+00 -2.43947E+00 -1.53986E+00 + -2.23746E+00 -1.27135E+00 -2.05352E+00 -1.08930E+00 -1.88721E+00 -9.27144E-01 + -1.73285E+00 -8.08755E-01 -1.58826E+00 -7.13001E-01 -1.45408E+00 -6.35895E-01 + -1.32753E+00 -5.72557E-01 -1.20557E+00 -5.29429E-01 -1.08582E+00 -4.95342E-01 + -9.80293E-01 -4.73863E-01 -8.61032E-01 -4.59100E-01 -7.48646E-01 -4.55477E-01 + -6.25159E-01 -4.74586E-01 -4.92788E-01 -5.15001E-01 -3.67996E-01 -5.70096E-01 + -2.22883E-01 -6.66156E-01 -8.31386E-02 -7.97111E-01 8.89232E-02 -9.42655E-01 + 2.30489E-01 -1.31341E+00 3.33000E-01 -1.67364E+00 8.00571E-02 -2.53277E+00 + -8.67444E-01 -3.12639E+00 -1.84807E+00 -2.80526E+00 -2.36028E+00 -2.14253E+00 + -2.49892E+00 -1.43896E+00 -2.33166E+00 -9.90943E-01 -2.16115E+00 -7.55866E-01 + -2.01852E+00 -5.79985E-01 -1.88409E+00 -4.64902E-01 -1.77651E+00 -3.90306E-01 + -1.68355E+00 -3.17756E-01 -1.59453E+00 -2.73289E-01 -1.54451E+00 -2.63344E-01 + -1.44688E+00 -2.13547E-01 -1.46255E+00 -2.04942E-01 -1.42076E+00 -1.20582E-01 + -1.22117E+00 -2.15693E-01 -1.29363E+00 -1.88156E-01 -1.28469E+00 -1.91072E-01 + -1.28130E+00 -1.19945E-01 -1.26664E+00 -1.18886E-01 -1.23394E+00 -8.62635E-02 + -1.21192E+00 -7.71947E-02 -1.18364E+00 -6.47157E-02 -1.16263E+00 -6.05281E-02 + -1.14939E+00 -6.04775E-02 -1.13983E+00 -5.68372E-02 -1.12655E+00 -5.34817E-02 + -1.11767E+00 -4.58341E-02 -1.11158E+00 -4.34906E-02 -1.10148E+00 -3.87246E-02 + -1.09724E+00 -3.42910E-02 -1.09366E+00 -3.00427E-02 -1.09248E+00 -2.86859E-02 + -1.08850E+00 -2.32084E-02 -1.08426E+00 -2.38299E-02 -1.08487E+00 -2.21787E-02 + -1.08633E+00 -1.47506E-02 -1.09172E+00 -5.25813E-03 -1.09225E+00 -7.75522E-03 + -1.09876E+00 2.94610E-03 -1.10418E+00 5.54801E-03 -1.10961E+00 1.44669E-02 + -1.12220E+00 2.23008E-02 -1.13354E+00 2.80694E-02 -1.15133E+00 3.86742E-02 + -1.16493E+00 4.83068E-02 -1.18786E+00 5.97765E-02 -1.21314E+00 7.36900E-02 + -1.24852E+00 9.17522E-02 -1.28137E+00 1.10178E-01 -1.33168E+00 1.32341E-01 + -1.37504E+00 1.63988E-01 -1.45139E+00 2.05844E-01 -1.53159E+00 2.70472E-01 + -1.63328E+00 3.67404E-01 -1.75801E+00 5.24302E-01 -1.88346E+00 8.01799E-01 + -1.91013E+00 1.28989E+00 -1.44976E+00 1.93727E+00 -4.47118E-01 1.92460E+00 + -2.25552E-02 1.25294E+00 -8.55540E-02 7.77850E-01 -2.37780E-01 5.33915E-01 + -3.84936E-01 4.05466E-01 -5.00044E-01 3.35886E-01 -5.94811E-01 3.00594E-01 + -6.81703E-01 2.75558E-01 -7.58497E-01 2.68003E-01 -8.31622E-01 2.69836E-01 + -9.01880E-01 2.69999E-01 -9.69806E-01 2.92423E-01 -1.03522E+00 3.09999E-01 + -1.10320E+00 3.35123E-01 -1.17288E+00 3.69772E-01 -1.25008E+00 4.16816E-01 + -1.32768E+00 4.64290E-01 -1.41282E+00 5.28881E-01 -1.50284E+00 5.98736E-01 + -1.59780E+00 6.95178E-01 -1.70612E+00 8.14380E-01 -1.81892E+00 9.57007E-01 + -1.93526E+00 1.14077E+00 -2.05371E+00 1.37649E+00 -2.16261E+00 1.67669E+00 + -2.23719E+00 2.05952E+00 -2.24754E+00 2.55976E+00 -2.12142E+00 3.16108E+00 + -1.76956E+00 3.83778E+00 -1.06884E+00 4.47371E+00 -3.38576E-02 4.81031E+00 + 1.08430E+00 4.63633E+00 1.95138E+00 4.01752E+00 2.40952E+00 3.25266E+00 + 2.55090E+00 2.55239E+00 2.51914E+00 1.99770E+00 2.41065E+00 1.57340E+00 + 2.27209E+00 1.26409E+00 2.14327E+00 1.02230E+00 2.01717E+00 8.36807E-01 + 1.91096E+00 6.91519E-01 1.80967E+00 5.71189E-01 1.72729E+00 4.63567E-01 + 1.65284E+00 3.67094E-01 1.58884E+00 2.72817E-01 1.51581E+00 1.72965E-01 + 1.43126E+00 7.27343E-02 1.32628E+00 -1.04309E-02 1.19419E+00 -5.52948E-02 + 1.07834E+00 -5.38202E-02 1.00426E+00 -2.41909E-02 9.52127E-01 4.59884E-04 + 9.22741E-01 2.22736E-02 9.04899E-01 3.06270E-02 8.91676E-01 4.04192E-02 + 8.80300E-01 4.30962E-02 8.70034E-01 4.36613E-02 8.62551E-01 4.20132E-02 + 8.58943E-01 3.89171E-02 8.57735E-01 4.30895E-02 8.60291E-01 3.36930E-02 + 8.62550E-01 3.04621E-02 8.61746E-01 2.54471E-02 8.65974E-01 2.04730E-02 + 8.73502E-01 6.39944E-03 8.82289E-01 4.33624E-04 8.91728E-01 -5.46997E-03 + 9.00570E-01 -1.32510E-02 9.11932E-01 -1.81548E-02 9.29011E-01 -2.41128E-02 + 9.43806E-01 -2.85280E-02 9.66980E-01 -4.12991E-02 9.88710E-01 -4.82869E-02 + 1.01179E+00 -5.66879E-02 1.04054E+00 -6.92853E-02 1.07195E+00 -8.12240E-02 + 1.10912E+00 -9.05089E-02 1.15168E+00 -1.02425E-01 1.19799E+00 -1.19505E-01 + 1.24979E+00 -1.37301E-01 1.31104E+00 -1.56605E-01 1.37061E+00 -1.83590E-01 + 1.44297E+00 -2.12048E-01 1.52149E+00 -2.44208E-01 1.61006E+00 -2.81160E-01 + 1.71556E+00 -3.28960E-01 1.83237E+00 -3.83680E-01 1.96120E+00 -4.52552E-01 + 2.11395E+00 -5.41224E-01 2.28979E+00 -6.50793E-01 2.49629E+00 -8.00468E-01 + 2.72907E+00 -9.90492E-01 2.99098E+00 -1.26130E+00 3.27242E+00 -1.61495E+00 + 3.58414E+00 -2.11765E+00 3.86723E+00 -2.81181E+00 4.04365E+00 -3.77513E+00 + 3.92359E+00 -5.07474E+00 3.13630E+00 -6.61514E+00 1.37148E+00 -7.79733E+00 + -8.60850E-01 -7.75965E+00 -2.38604E+00 -6.69095E+00 -3.01075E+00 -5.58839E+00 + -3.27295E+00 -4.86732E+00 -3.66466E+00 -4.36325E+00 -4.09814E+00 -3.61867E+00 + -4.19860E+00 -2.73658E+00 -4.00657E+00 -2.01125E+00 -3.71730E+00 -1.50671E+00 + -3.43174E+00 -1.15627E+00 -3.17059E+00 -9.06342E-01 -2.94248E+00 -7.24810E-01 + -2.73663E+00 -5.92880E-01 -2.56174E+00 -4.92884E-01 -2.40810E+00 -4.09273E-01 + -2.28029E+00 -3.55461E-01 -2.16828E+00 -3.07943E-01 -2.07065E+00 -2.66106E-01 + -1.98546E+00 -2.36299E-01 -1.90890E+00 -2.08171E-01 -1.83834E+00 -1.83813E-01 + -1.77269E+00 -1.60604E-01 -1.72247E+00 -1.42730E-01 -1.67790E+00 -1.30649E-01 + -1.63552E+00 -1.15311E-01 -1.59850E+00 -9.29454E-02 -1.55207E+00 -7.18257E-02 + -1.51258E+00 -7.17203E-02 -1.45627E+00 -5.85200E-02 -1.45810E+00 -8.57465E-02 + -1.42555E+00 -7.93042E-02 -1.42568E+00 -6.44799E-02 -1.41205E+00 -4.48774E-02 + -1.38099E+00 -5.02800E-02 -1.37437E+00 -4.41388E-02 -1.35897E+00 -2.01040E-02 + -1.33428E+00 -1.47386E-02 -1.33041E+00 -1.99768E-02 -1.32135E+00 -9.39334E-03 + -1.29939E+00 -5.49724E-03 -1.29200E+00 -4.21115E-03 -1.28380E+00 -4.81966E-05 + -1.27562E+00 3.35446E-03 -1.27220E+00 6.34817E-03 -1.26585E+00 7.88048E-03 + -1.26488E+00 1.66732E-02 -1.26286E+00 1.69425E-02 -1.25950E+00 2.18725E-02 + -1.25527E+00 2.97477E-02 -1.25700E+00 3.20759E-02 -1.25848E+00 4.10746E-02 + -1.25870E+00 4.43154E-02 -1.26400E+00 5.41356E-02 -1.27043E+00 6.05064E-02 + -1.28184E+00 6.91663E-02 -1.28922E+00 7.93551E-02 -1.29871E+00 9.60082E-02 + -1.30355E+00 1.19365E-01 -1.31932E+00 1.41954E-01 -1.32558E+00 1.83327E-01 + -1.32594E+00 2.21269E-01 -1.31164E+00 2.71627E-01 -1.25816E+00 3.02802E-01 + -1.22000E+00 3.22332E-01 -1.15791E+00 3.29938E-01 -1.11427E+00 2.88854E-01 + -1.10380E+00 2.51708E-01 -1.11032E+00 2.20683E-01 -1.11391E+00 2.01069E-01 + -1.13091E+00 1.81159E-01 -1.14162E+00 1.73800E-01 -1.15495E+00 1.62373E-01 + -1.16487E+00 1.60513E-01 -1.17774E+00 1.56309E-01 -1.18957E+00 1.49979E-01 + -1.20310E+00 1.46360E-01 -1.21779E+00 1.48093E-01 -1.23133E+00 1.44774E-01 + -1.25019E+00 1.47848E-01 -1.26166E+00 1.50413E-01 -1.27618E+00 1.50828E-01 + -1.29554E+00 1.54868E-01 -1.31156E+00 1.57765E-01 -1.32882E+00 1.67004E-01 + -1.35075E+00 1.67382E-01 -1.37038E+00 1.80038E-01 -1.38727E+00 1.86514E-01 + -1.41166E+00 1.87944E-01 -1.42961E+00 1.99313E-01 -1.45109E+00 2.09273E-01 + -1.48021E+00 2.19247E-01 -1.50621E+00 2.27247E-01 -1.52892E+00 2.34979E-01 + -1.55581E+00 2.47281E-01 -1.58444E+00 2.55969E-01 -1.61563E+00 2.70941E-01 + -1.64159E+00 2.84459E-01 -1.67809E+00 2.96768E-01 -1.71151E+00 3.10964E-01 + -1.74702E+00 3.28218E-01 -1.78880E+00 3.44218E-01 -1.82590E+00 3.63726E-01 + -1.86829E+00 3.77124E-01 -1.91336E+00 4.02448E-01 -1.96061E+00 4.23572E-01 + -2.00799E+00 4.53961E-01 -2.06165E+00 4.78008E-01 -2.12223E+00 5.04726E-01 + -2.18049E+00 5.43780E-01 -2.24209E+00 5.81901E-01 -2.31485E+00 6.19072E-01 + -2.38931E+00 6.78104E-01 -2.46784E+00 7.30245E-01 -2.55118E+00 7.89373E-01 + -2.64085E+00 8.68985E-01 -2.74625E+00 9.44718E-01 -2.85284E+00 1.04995E+00 + -2.97361E+00 1.16004E+00 -3.10058E+00 1.30824E+00 -3.23975E+00 1.47012E+00 + -3.38539E+00 1.68109E+00 -3.53763E+00 1.94506E+00 -3.68500E+00 2.27743E+00 + -3.79691E+00 2.70440E+00 -3.84854E+00 3.25085E+00 -3.72407E+00 3.92689E+00 + -3.32011E+00 4.65866E+00 -2.55120E+00 5.23924E+00 -1.53231E+00 5.39938E+00 + -6.55372E-01 5.05780E+00 -1.39621E-01 4.46157E+00 1.14338E-02 3.89604E+00 + -5.03656E-02 3.46670E+00 -2.06909E-01 3.19838E+00 -3.84167E-01 3.06425E+00 + -5.62654E-01 3.03597E+00 -7.10082E-01 3.08474E+00 -8.12790E-01 3.19534E+00 + -8.77431E-01 3.36159E+00 -8.92343E-01 3.55924E+00 -8.54410E-01 3.78554E+00 + -7.53344E-01 4.03177E+00 -5.80764E-01 4.27477E+00 -3.43688E-01 4.49750E+00 + -4.67943E-02 4.68904E+00 3.06120E-01 4.82639E+00 7.07213E-01 4.90838E+00 + 1.11589E+00 4.90685E+00 1.53973E+00 4.82687E+00 1.93079E+00 4.68008E+00 + 2.29882E+00 4.47175E+00 2.60931E+00 4.21093E+00 2.87814E+00 3.90804E+00 + 3.08616E+00 3.60481E+00 3.24544E+00 3.27673E+00 3.35657E+00 2.95630E+00 + 3.42935E+00 2.64004E+00 3.47242E+00 2.34428E+00 3.48640E+00 2.06843E+00 + 3.48479E+00 1.80650E+00 3.47172E+00 1.55336E+00 3.45234E+00 1.31927E+00 + 3.42898E+00 1.08803E+00 3.40254E+00 8.50188E-01 3.37917E+00 6.06387E-01 + 3.35371E+00 3.26062E-01 3.29552E+00 9.82213E-03 3.18210E+00 -3.54226E-01 + 2.96136E+00 -7.59600E-01 2.56910E+00 -1.13685E+00 2.01469E+00 -1.36969E+00 + 1.41578E+00 -1.35038E+00 9.43040E-01 -1.10942E+00 6.55793E-01 -7.83264E-01 + 5.30685E-01 -4.79545E-01 5.02427E-01 -2.38890E-01 5.18385E-01 -6.41174E-02 + 5.54334E-01 5.91639E-02 5.87753E-01 1.40425E-01 6.21780E-01 1.96755E-01 + 6.46316E-01 2.38110E-01 6.64636E-01 2.61671E-01 6.78616E-01 2.81020E-01 + 6.84959E-01 2.95637E-01 6.90919E-01 3.00626E-01 6.97919E-01 3.00389E-01 + 6.96757E-01 3.06732E-01 6.90464E-01 3.08219E-01 6.89777E-01 3.10034E-01 + 6.83634E-01 3.04027E-01 6.74809E-01 3.07866E-01 6.73457E-01 2.98831E-01 + 6.59555E-01 2.99189E-01 6.50761E-01 2.91477E-01 6.41175E-01 2.90750E-01 + 6.28731E-01 2.89447E-01 6.18313E-01 2.82997E-01 6.06617E-01 2.83002E-01 + 5.92305E-01 2.78754E-01 5.77756E-01 2.76007E-01 5.66239E-01 2.80049E-01 + 5.49342E-01 2.73468E-01 5.36786E-01 2.75307E-01 5.23140E-01 2.75100E-01 + 5.10541E-01 2.69889E-01 4.92345E-01 2.75843E-01 4.83053E-01 2.74187E-01 + 4.62721E-01 2.77530E-01 4.50229E-01 2.76299E-01 4.36879E-01 2.79380E-01 + 4.17351E-01 2.80278E-01 4.07655E-01 2.85697E-01 3.88296E-01 2.90808E-01 + 3.72073E-01 2.93156E-01 3.52203E-01 3.02093E-01 3.34614E-01 3.13196E-01 + 3.22726E-01 3.22585E-01 3.07055E-01 3.29848E-01 2.86815E-01 3.41585E-01 + 2.59885E-01 3.52895E-01 2.35515E-01 3.75797E-01 2.16829E-01 4.06575E-01 + 2.07024E-01 4.31034E-01 2.13700E-01 4.50524E-01 1.91734E-01 4.67497E-01 + 1.72416E-01 4.87317E-01 1.60743E-01 5.17761E-01 1.44148E-01 5.39605E-01 + 1.29851E-01 5.61990E-01 1.03412E-01 5.83361E-01 7.47675E-02 6.40581E-01 + 6.49053E-02 6.91175E-01 4.34194E-02 7.33413E-01 1.29260E-02 8.02164E-01 + 1.33974E-02 8.83533E-01 6.74511E-03 9.56428E-01 2.91620E-03 1.06107E+00 + 2.17392E-02 1.16965E+00 4.65225E-02 1.28341E+00 9.02490E-02 1.41439E+00 + 1.60697E-01 1.56405E+00 2.66634E-01 1.71563E+00 4.01209E-01 1.87421E+00 + 5.89396E-01 2.02248E+00 8.25637E-01 2.14799E+00 1.12317E+00 2.23968E+00 + 1.44574E+00 2.26278E+00 1.79712E+00 2.22108E+00 2.14545E+00 2.09576E+00 + 2.47346E+00 1.89432E+00 2.74270E+00 1.63160E+00 2.95319E+00 1.33551E+00 + 3.10440E+00 1.02875E+00 3.20988E+00 7.17665E-01 3.28912E+00 4.10324E-01 + 3.34148E+00 1.01907E-01 3.37116E+00 -2.04545E-01 3.38476E+00 -5.17165E-01 + 3.39240E+00 -8.40082E-01 3.38738E+00 -1.18972E+00 3.36010E+00 -1.58110E+00 + 3.28779E+00 -2.02188E+00 3.14998E+00 -2.52879E+00 2.90820E+00 -3.08406E+00 + 2.48071E+00 -3.68897E+00 1.82845E+00 -4.25007E+00 9.25123E-01 -4.62874E+00 + -1.34490E-01 -4.68446E+00 -1.13375E+00 -4.36770E+00 -1.92898E+00 -3.75318E+00 + -2.38358E+00 -2.99256E+00 -2.56983E+00 -2.31442E+00 -2.59500E+00 -1.70775E+00 + -2.51891E+00 -1.24911E+00 -2.41917E+00 -8.71776E-01 -2.28044E+00 -5.91402E-01 + -2.16326E+00 -3.90518E-01 -2.08196E+00 -2.20301E-01 -2.00827E+00 -7.67353E-02 + -1.95264E+00 4.70121E-02 -1.91633E+00 1.55412E-01 -1.89468E+00 2.56666E-01 + -1.88991E+00 3.53476E-01 -1.90880E+00 4.57645E-01 -1.93451E+00 5.72785E-01 + -1.98210E+00 6.99041E-01 -2.03370E+00 8.45914E-01 -2.09425E+00 1.01697E+00 + -2.16269E+00 1.21646E+00 -2.23324E+00 1.46269E+00 -2.28868E+00 1.75585E+00 + -2.32739E+00 2.11023E+00 -2.30694E+00 2.53421E+00 -2.20709E+00 3.03883E+00 + -1.97274E+00 3.58768E+00 -1.55347E+00 4.13916E+00 -9.33919E-01 4.61938E+00 + -1.37771E-01 4.90277E+00 7.31047E-01 4.93201E+00 1.52357E+00 4.69715E+00 + 2.15839E+00 4.26368E+00 2.61215E+00 3.74499E+00 2.87155E+00 3.23016E+00 + 3.01882E+00 2.74932E+00 3.07422E+00 2.33336E+00 3.06983E+00 1.97176E+00 + 3.03594E+00 1.66491E+00 2.98277E+00 1.41119E+00 2.91811E+00 1.19074E+00 + 2.84937E+00 1.00572E+00 2.78630E+00 8.47801E-01 2.72256E+00 7.10963E-01 + 2.66705E+00 5.88577E-01 2.60680E+00 4.90257E-01 2.56574E+00 3.98479E-01 + 2.52992E+00 3.12928E-01 2.49220E+00 2.26112E-01 2.46964E+00 1.55409E-01 + 2.44035E+00 8.62730E-02 2.41938E+00 2.18909E-02 2.40645E+00 -5.01989E-02 + 2.39389E+00 -1.15210E-01 2.38892E+00 -1.80726E-01 2.38739E+00 -2.47394E-01 + 2.39280E+00 -3.20902E-01 2.39590E+00 -3.87557E-01 2.40102E+00 -4.63103E-01 + 2.40923E+00 -5.45465E-01 2.42419E+00 -6.24451E-01 2.43689E+00 -7.24139E-01 + 2.45063E+00 -8.22469E-01 2.47194E+00 -9.28786E-01 2.48937E+00 -1.04462E+00 + 2.50538E+00 -1.17719E+00 2.51891E+00 -1.31714E+00 2.52376E+00 -1.47770E+00 + 2.52671E+00 -1.65116E+00 2.51126E+00 -1.84778E+00 2.48595E+00 -2.05511E+00 + 2.43587E+00 -2.29515E+00 2.35363E+00 -2.54813E+00 2.23739E+00 -2.81348E+00 + 2.07670E+00 -3.08742E+00 1.86420E+00 -3.36791E+00 1.58396E+00 -3.63676E+00 + 1.24495E+00 -3.87337E+00 8.53050E-01 -4.05840E+00 4.07729E-01 -4.18736E+00 + -5.73757E-02 -4.22065E+00 -5.41161E-01 -4.17450E+00 -9.91073E-01 -4.04158E+00 + -1.40085E+00 -3.82445E+00 -1.74757E+00 -3.55555E+00 -2.01758E+00 -3.24972E+00 + -2.22412E+00 -2.93506E+00 -2.37085E+00 -2.62630E+00 -2.45685E+00 -2.33389E+00 + -2.51386E+00 -2.06690E+00 -2.53837E+00 -1.82212E+00 -2.53788E+00 -1.60939E+00 + -2.53044E+00 -1.41836E+00 -2.51899E+00 -1.24922E+00 -2.49979E+00 -1.10171E+00 + -2.48529E+00 -9.71374E-01 -2.46855E+00 -8.46771E-01 -2.44964E+00 -7.36657E-01 + -2.43970E+00 -6.31731E-01 -2.42998E+00 -5.41335E-01 -2.42388E+00 -4.55741E-01 + -2.42257E+00 -3.71471E-01 -2.42952E+00 -2.90291E-01 -2.43534E+00 -2.17314E-01 + -2.44773E+00 -1.42974E-01 -2.46250E+00 -7.32629E-02 -2.48008E+00 -7.46983E-04 + -2.51265E+00 6.48214E-02 -2.54796E+00 1.35126E-01 -2.59576E+00 2.10832E-01 + -2.64549E+00 2.87965E-01 -2.70573E+00 3.74623E-01 -2.77504E+00 4.70916E-01 + -2.84378E+00 5.77140E-01 -2.92907E+00 6.89494E-01 -3.01673E+00 8.28368E-01 + -3.10992E+00 9.73616E-01 -3.20920E+00 1.14785E+00 -3.31657E+00 1.34882E+00 + -3.41652E+00 1.58343E+00 -3.51269E+00 1.85252E+00 -3.59286E+00 2.16297E+00 + -3.65265E+00 2.51115E+00 -3.67692E+00 2.90299E+00 -3.64884E+00 3.34055E+00 + -3.57778E+00 3.81084E+00 -3.42341E+00 4.31476E+00 -3.18316E+00 4.83169E+00 + -2.83904E+00 5.36077E+00 -2.39274E+00 5.86846E+00 -1.81705E+00 6.30192E+00 + -1.14553E+00 6.67050E+00 -3.87751E-01 6.89726E+00 4.19795E-01 6.97313E+00 + 1.23693E+00 6.89656E+00 1.99744E+00 6.66306E+00 2.68485E+00 6.28871E+00 + 3.26251E+00 5.83465E+00 3.71494E+00 5.32148E+00 4.05417E+00 4.78534E+00 + 4.28824E+00 4.26470E+00 4.45025E+00 3.75834E+00 4.54292E+00 3.27648E+00 + 4.57103E+00 2.83913E+00 4.56424E+00 2.44416E+00 4.52985E+00 2.10234E+00 + 4.48382E+00 1.79488E+00 4.44553E+00 1.51237E+00 4.41026E+00 1.23460E+00 + 4.34356E+00 9.68864E-01 4.26205E+00 7.16940E-01 4.16593E+00 4.97179E-01 + 4.09418E+00 3.09075E-01 4.02670E+00 1.28765E-01 3.97208E+00 -5.03240E-02 + 3.90118E+00 -2.40234E-01 3.83134E+00 -4.20766E-01 3.76956E+00 -5.91525E-01 + 3.71169E+00 -7.73800E-01 3.63755E+00 -9.75764E-01 3.54111E+00 -1.18335E+00 + 3.43031E+00 -1.38093E+00 3.30974E+00 -1.57885E+00 3.14676E+00 -1.79484E+00 + 2.95298E+00 -1.96577E+00 2.73984E+00 -2.11327E+00 2.52190E+00 -2.22942E+00 + 2.29115E+00 -2.31211E+00 2.07890E+00 -2.34091E+00 1.90123E+00 -2.36486E+00 + 1.74537E+00 -2.36890E+00 1.62107E+00 -2.37222E+00 1.51461E+00 -2.39841E+00 + 1.41940E+00 -2.42991E+00 1.32802E+00 -2.48571E+00 1.22746E+00 -2.55737E+00 + 1.11116E+00 -2.65082E+00 9.83270E-01 -2.76393E+00 8.24504E-01 -2.87359E+00 + 6.40590E-01 -2.98487E+00 4.20196E-01 -3.09295E+00 1.67349E-01 -3.18976E+00 + -1.11701E-01 -3.25377E+00 -4.24851E-01 -3.29139E+00 -7.45471E-01 -3.28582E+00 + -1.07615E+00 -3.23768E+00 -1.41640E+00 -3.14217E+00 -1.74911E+00 -3.00928E+00 + -2.05814E+00 -2.82368E+00 -2.34158E+00 -2.60968E+00 -2.59999E+00 -2.36956E+00 + -2.82871E+00 -2.09813E+00 -3.02525E+00 -1.81799E+00 -3.18525E+00 -1.51837E+00 + -3.33272E+00 -1.20641E+00 -3.43462E+00 -8.97693E-01 -3.51317E+00 -5.71596E-01 + -3.56857E+00 -2.45481E-01 -3.58871E+00 8.24711E-02 -3.58677E+00 4.17191E-01 + -3.54898E+00 7.45519E-01 -3.48473E+00 1.07303E+00 -3.38252E+00 1.38883E+00 + -3.25034E+00 1.70058E+00 -3.08097E+00 1.99169E+00 -2.88353E+00 2.27281E+00 + -2.65440E+00 2.50598E+00 -2.40336E+00 2.71002E+00 -2.14136E+00 2.87340E+00 + -1.87133E+00 3.00966E+00 -1.59142E+00 3.09967E+00 -1.32880E+00 3.15654E+00 + -1.06462E+00 3.18291E+00 -8.26732E-01 3.17625E+00 -6.17718E-01 3.15921E+00 + -4.16259E-01 3.11474E+00 -2.44774E-01 3.08661E+00 -4.28990E-02 3.01820E+00 + 7.72540E-02 2.92053E+00 1.80601E-01 2.87773E+00 2.76744E-01 2.83311E+00 + 4.22609E-01 2.83124E+00 5.86321E-01 2.71328E+00 6.03125E-01 2.58756E+00 + 6.12301E-01 2.60282E+00 7.30839E-01 2.64285E+00 8.79551E-01 2.59900E+00 + 9.87757E-01 2.51495E+00 1.06243E+00 2.44496E+00 1.11038E+00 2.38371E+00 + 1.15793E+00 2.37787E+00 1.25972E+00 2.38638E+00 1.42416E+00 2.36434E+00 + 1.59728E+00 2.26856E+00 1.73611E+00 2.11504E+00 1.81132E+00 1.93399E+00 + 1.83619E+00 1.75807E+00 1.82157E+00 1.61699E+00 1.79547E+00 1.51068E+00 + 1.77451E+00 1.42992E+00 1.75887E+00 1.35964E+00 1.75566E+00 1.29794E+00 + 1.75314E+00 1.22799E+00 1.74872E+00 1.14838E+00 1.73657E+00 1.07993E+00 + 1.72354E+00 1.01101E+00 1.70087E+00 9.44443E-01 1.67309E+00 8.82719E-01 + 1.64592E+00 8.18258E-01 1.61184E+00 7.66830E-01 1.58402E+00 7.19743E-01 + 1.54561E+00 6.73684E-01 1.50981E+00 6.34230E-01 1.47811E+00 5.95398E-01 + 1.43899E+00 5.65865E-01 1.39428E+00 5.38106E-01 1.36030E+00 5.10824E-01 + 1.31988E+00 4.85219E-01 1.28125E+00 4.63419E-01 1.23797E+00 4.47730E-01 + 1.19947E+00 4.35026E-01 1.15950E+00 4.22876E-01 1.11778E+00 4.13460E-01 + 1.07748E+00 4.03032E-01 1.03291E+00 3.98811E-01 9.94946E-01 3.96543E-01 + 9.47481E-01 3.91473E-01 9.05495E-01 3.94365E-01 8.59785E-01 4.01534E-01 + 8.17064E-01 4.04658E-01 7.70139E-01 4.12789E-01 7.23229E-01 4.20449E-01 + 6.69588E-01 4.40221E-01 6.21014E-01 4.62594E-01 5.70618E-01 4.83966E-01 + 5.16173E-01 5.04688E-01 4.59307E-01 5.40902E-01 4.10993E-01 5.74717E-01 + 3.51865E-01 6.17292E-01 2.94510E-01 6.60072E-01 2.34129E-01 7.14064E-01 + 1.74539E-01 7.79144E-01 1.11936E-01 8.44211E-01 4.87406E-02 9.18525E-01 + -1.64460E-02 1.00696E+00 -7.96798E-02 1.10591E+00 -1.46070E-01 1.22023E+00 + -2.01653E-01 1.34718E+00 -2.60187E-01 1.48792E+00 -3.07632E-01 1.65072E+00 + -3.49971E-01 1.82936E+00 -3.82840E-01 2.02876E+00 -3.95037E-01 2.25356E+00 + -3.90373E-01 2.50199E+00 -3.52044E-01 2.77574E+00 -2.98591E-01 3.06857E+00 + -1.78094E-01 3.38518E+00 -2.67563E-02 3.72066E+00 2.12653E-01 4.05853E+00 + 5.10221E-01 4.40030E+00 8.86167E-01 4.70939E+00 1.34661E+00 4.97108E+00 + 1.88350E+00 5.16703E+00 2.47681E+00 5.27273E+00 3.09963E+00 5.25981E+00 + 3.73401E+00 5.13003E+00 4.32590E+00 4.87906E+00 4.86461E+00 4.51561E+00 + 5.32030E+00 4.07347E+00 5.68743E+00 3.57893E+00 5.95593E+00 3.05409E+00 + 6.12640E+00 2.51450E+00 6.21518E+00 1.98589E+00 6.23558E+00 1.47142E+00 + 6.18701E+00 9.82187E-01 6.08148E+00 5.23162E-01 5.92179E+00 1.04723E-01 + 5.71646E+00 -2.71958E-01 5.48136E+00 -6.04784E-01 5.20622E+00 -8.94812E-01 + 4.91205E+00 -1.13661E+00 4.60337E+00 -1.30847E+00 4.29056E+00 -1.43168E+00 + 3.98416E+00 -1.50037E+00 3.69028E+00 -1.51919E+00 3.42680E+00 -1.49908E+00 + 3.19224E+00 -1.43670E+00 2.98607E+00 -1.35323E+00 2.82074E+00 -1.25012E+00 + 2.68381E+00 -1.13809E+00 2.57085E+00 -1.02835E+00 2.49795E+00 -9.10068E-01 + 2.44780E+00 -8.01132E-01 2.41164E+00 -7.03626E-01 2.39491E+00 -6.08069E-01 + 2.38722E+00 -5.21034E-01 2.38889E+00 -4.49570E-01 2.39725E+00 -3.83403E-01 + 2.41582E+00 -3.25959E-01 2.44031E+00 -2.76189E-01 2.46666E+00 -2.31484E-01 + 2.49363E+00 -1.92815E-01 2.52343E+00 -1.60870E-01 2.55738E+00 -1.29710E-01 + 2.59049E+00 -1.00864E-01 2.63284E+00 -8.19672E-02 2.67639E+00 -6.77752E-02 + 2.71630E+00 -5.61158E-02 2.75623E+00 -5.78605E-02 2.78113E+00 -4.54096E-02 + 2.81171E+00 -2.77697E-02 2.86506E+00 3.73493E-03 2.93475E+00 1.47546E-02 + 3.00302E+00 -5.80681E-03 3.06614E+00 -4.04488E-02 3.09304E+00 -6.20884E-02 + 3.11042E+00 -6.69009E-02 3.14815E+00 -5.30218E-02 3.20844E+00 -3.80762E-02 + 3.27488E+00 -3.18596E-02 3.35059E+00 -3.16815E-02 3.43265E+00 -2.62865E-02 + 3.53807E+00 -2.89605E-02 3.64646E+00 -5.36617E-02 3.75455E+00 -9.63433E-02 + 3.87595E+00 -1.41488E-01 4.00636E+00 -2.12502E-01 4.14062E+00 -2.95916E-01 + 4.25776E+00 -4.08995E-01 4.36739E+00 -5.24809E-01 4.47600E+00 -6.79560E-01 + 4.56802E+00 -8.42396E-01 4.63442E+00 -1.02761E+00 4.69618E+00 -1.21186E+00 + 4.73780E+00 -1.42278E+00 4.74353E+00 -1.63141E+00 4.74422E+00 -1.84542E+00 + 4.72072E+00 -2.07060E+00 4.66653E+00 -2.30314E+00 4.56924E+00 -2.52175E+00 + 4.45340E+00 -2.73649E+00 4.30331E+00 -2.93523E+00 4.12394E+00 -3.10967E+00 + 3.93433E+00 -3.24871E+00 3.71694E+00 -3.36426E+00 3.49711E+00 -3.44426E+00 + 3.29098E+00 -3.49816E+00 3.08491E+00 -3.52263E+00 2.86846E+00 -3.51696E+00 + 2.67996E+00 -3.48448E+00 2.50542E+00 -3.44053E+00 2.34947E+00 -3.36441E+00 + 2.19995E+00 -3.28025E+00 2.08192E+00 -3.19028E+00 1.97915E+00 -3.09155E+00 + 1.89169E+00 -2.98906E+00 1.82465E+00 -2.88780E+00 1.77164E+00 -2.77852E+00 + 1.73004E+00 -2.68236E+00 1.71077E+00 -2.58745E+00 1.69139E+00 -2.49041E+00 + 1.68527E+00 -2.39847E+00 1.68860E+00 -2.30646E+00 1.69906E+00 -2.23508E+00 + 1.71933E+00 -2.16287E+00 1.73923E+00 -2.09740E+00 1.77020E+00 -2.02575E+00 + 1.80643E+00 -1.97066E+00 1.84395E+00 -1.91504E+00 1.88276E+00 -1.86838E+00 + 1.93542E+00 -1.81834E+00 1.98187E+00 -1.77569E+00 2.03301E+00 -1.73643E+00 + 2.08963E+00 -1.71036E+00 2.14966E+00 -1.68374E+00 2.21454E+00 -1.65752E+00 + 2.27610E+00 -1.64164E+00 2.34179E+00 -1.62663E+00 2.41203E+00 -1.61311E+00 + 2.48192E+00 -1.61045E+00 2.55482E+00 -1.60572E+00 2.63511E+00 -1.60479E+00 + 2.71209E+00 -1.62041E+00 2.79440E+00 -1.62216E+00 2.87270E+00 -1.63533E+00 + 2.96214E+00 -1.65417E+00 3.05102E+00 -1.67844E+00 3.13881E+00 -1.71343E+00 + 3.23886E+00 -1.75313E+00 3.33145E+00 -1.78793E+00 3.42506E+00 -1.83502E+00 + 3.52706E+00 -1.88397E+00 3.63284E+00 -1.93463E+00 3.73538E+00 -2.01223E+00 + 3.84629E+00 -2.08264E+00 3.95956E+00 -2.17000E+00 4.06720E+00 -2.26563E+00 + 4.17901E+00 -2.37454E+00 4.28525E+00 -2.48595E+00 4.39425E+00 -2.61356E+00 + 4.48926E+00 -2.74885E+00 4.59696E+00 -2.89483E+00 4.68506E+00 -3.04560E+00 + 4.79027E+00 -3.20192E+00 4.88674E+00 -3.38259E+00 4.97377E+00 -3.57832E+00 + 5.05796E+00 -3.77716E+00 5.13246E+00 -3.99534E+00 5.21391E+00 -4.22002E+00 + 5.28591E+00 -4.47858E+00 5.34014E+00 -4.74741E+00 5.38425E+00 -5.03730E+00 + 5.39006E+00 -5.33973E+00 5.41181E+00 -5.65674E+00 5.38681E+00 -5.99847E+00 + 5.33752E+00 -6.34739E+00 5.27316E+00 -6.73286E+00 5.15695E+00 -7.11404E+00 + 5.00332E+00 -7.49689E+00 4.79426E+00 -7.88470E+00 4.54724E+00 -8.25538E+00 + 4.23761E+00 -8.60828E+00 3.91870E+00 -8.92690E+00 3.55270E+00 -9.22938E+00 + 3.15677E+00 -9.48430E+00 2.75299E+00 -9.70651E+00 2.31693E+00 -9.90280E+00 + 1.86266E+00 -1.00506E+01 1.39536E+00 -1.01503E+01 9.18566E-01 -1.02078E+01 + 4.57361E-01 -1.02212E+01 -4.32225E-03 -1.01776E+01 -4.52491E-01 -1.00992E+01 + -8.88389E-01 -9.98226E+00 -1.28108E+00 -9.82748E+00 -1.64077E+00 -9.65949E+00 + -1.99402E+00 -9.47334E+00 -2.32562E+00 -9.25516E+00 -2.62629E+00 -9.03074E+00 + -2.87703E+00 -8.78290E+00 -3.11725E+00 -8.54333E+00 -3.33192E+00 -8.28360E+00 + -3.51755E+00 -8.02771E+00 -3.68858E+00 -7.77467E+00 -3.82267E+00 -7.50821E+00 + -3.94172E+00 -7.26560E+00 -4.03683E+00 -7.01648E+00 -4.11597E+00 -6.76671E+00 + -4.16476E+00 -6.52739E+00 -4.20658E+00 -6.31413E+00 -4.22645E+00 -6.08139E+00 + -4.23589E+00 -5.88513E+00 -4.24137E+00 -5.69954E+00 -4.22702E+00 -5.51669E+00 + -4.20585E+00 -5.34795E+00 -4.18181E+00 -5.19177E+00 -4.14680E+00 -5.04739E+00 + -4.10350E+00 -4.91388E+00 -4.06778E+00 -4.79416E+00 -4.01534E+00 -4.68647E+00 + -3.97831E+00 -4.57617E+00 -3.92433E+00 -4.48686E+00 -3.87325E+00 -4.41059E+00 + -3.83097E+00 -4.33854E+00 -3.77648E+00 -4.27698E+00 -3.73686E+00 -4.22341E+00 + -3.69170E+00 -4.17428E+00 -3.64541E+00 -4.12630E+00 -3.60735E+00 -4.09556E+00 + -3.56821E+00 -4.07340E+00 -3.53170E+00 -4.05095E+00 -3.50390E+00 -4.03077E+00 + -3.47244E+00 -4.03248E+00 -3.44536E+00 -4.03075E+00 -3.41901E+00 -4.04153E+00 + -3.40981E+00 -4.05893E+00 -3.40155E+00 -4.08171E+00 -3.40974E+00 -4.11260E+00 + -3.39901E+00 -4.14277E+00 -3.42699E+00 -4.18404E+00 -3.44402E+00 -4.22990E+00 + -3.48878E+00 -4.27352E+00 -3.53223E+00 -4.32545E+00 -3.59418E+00 -4.38592E+00 + -3.65966E+00 -4.44222E+00 -3.73781E+00 -4.48349E+00 -3.83384E+00 -4.53232E+00 + -3.94943E+00 -4.57365E+00 -4.06340E+00 -4.60279E+00 -4.20004E+00 -4.62794E+00 + -4.34726E+00 -4.64607E+00 -4.50079E+00 -4.64348E+00 -4.66537E+00 -4.63040E+00 + -4.82939E+00 -4.59801E+00 -5.00371E+00 -4.55479E+00 -5.16714E+00 -4.48417E+00 + -5.33691E+00 -4.39996E+00 -5.50648E+00 -4.29858E+00 -5.65511E+00 -4.18993E+00 + -5.79948E+00 -4.05401E+00 -5.93504E+00 -3.91636E+00 -6.06156E+00 -3.75419E+00 + -6.17551E+00 -3.59662E+00 -6.26223E+00 -3.42723E+00 -6.34206E+00 -3.26515E+00 + -6.41260E+00 -3.08679E+00 -6.47687E+00 -2.90597E+00 -6.51857E+00 -2.73156E+00 + -6.55860E+00 -2.56171E+00 -6.57838E+00 -2.40381E+00 -6.59969E+00 -2.23930E+00 + -6.59800E+00 -2.07059E+00 -6.61200E+00 -1.92309E+00 -6.59755E+00 -1.77361E+00 + -6.58380E+00 -1.63277E+00 -6.58313E+00 -1.49190E+00 -6.58015E+00 -1.35258E+00 + -6.55690E+00 -1.22851E+00 -6.53578E+00 -1.10807E+00 -6.50889E+00 -9.80755E-01 + -6.48135E+00 -8.70439E-01 -6.46252E+00 -7.55766E-01 -6.45205E+00 -6.60001E-01 + -6.42450E+00 -5.34176E-01 -6.40239E+00 -4.10329E-01 -6.35411E+00 -3.09269E-01 + -6.30794E+00 -1.98001E-01 -6.26732E+00 -1.11148E-01 -6.22686E+00 -3.86756E-02 + -6.20435E+00 5.36066E-02 -6.17288E+00 1.34273E-01 -6.14924E+00 2.09951E-01 + -6.13130E+00 2.99924E-01 -6.11753E+00 3.90804E-01 -6.10886E+00 4.81672E-01 + -6.07583E+00 5.77304E-01 -6.05432E+00 6.65475E-01 -6.03145E+00 7.59447E-01 + -6.01114E+00 8.63904E-01 -5.98721E+00 9.61047E-01 -5.96104E+00 1.05716E+00 + -5.93666E+00 1.16316E+00 -5.90791E+00 1.26136E+00 -5.87811E+00 1.36058E+00 + -5.83308E+00 1.47307E+00 -5.79889E+00 1.57726E+00 -5.75760E+00 1.67871E+00 + -5.70990E+00 1.78751E+00 -5.66669E+00 1.89280E+00 -5.62311E+00 2.00404E+00 + -5.56433E+00 2.10246E+00 -5.50891E+00 2.21377E+00 -5.44302E+00 2.32826E+00 + -5.37171E+00 2.41383E+00 -5.30143E+00 2.51206E+00 -5.22730E+00 2.62095E+00 + -5.14269E+00 2.70100E+00 -5.05911E+00 2.79345E+00 -4.98267E+00 2.88438E+00 + -4.89630E+00 2.97164E+00 -4.81436E+00 3.04214E+00 -4.72749E+00 3.12470E+00 + -4.63592E+00 3.19584E+00 -4.56185E+00 3.27841E+00 -4.47002E+00 3.35387E+00 + -4.37963E+00 3.43038E+00 -4.29764E+00 3.49946E+00 -4.19665E+00 3.57911E+00 + -4.09351E+00 3.67599E+00 -3.98420E+00 3.75570E+00 -3.88098E+00 3.83016E+00 + -3.74509E+00 3.89560E+00 -3.61096E+00 3.97523E+00 -3.47758E+00 4.03443E+00 + -3.32916E+00 4.08056E+00 -3.18622E+00 4.11537E+00 -3.04353E+00 4.15726E+00 + -2.89100E+00 4.16825E+00 -2.74342E+00 4.19064E+00 -2.60087E+00 4.18338E+00 + -2.45660E+00 4.18984E+00 -2.31890E+00 4.17549E+00 -2.17453E+00 4.15244E+00 + -2.06076E+00 4.11910E+00 -1.92884E+00 4.07870E+00 -1.81259E+00 4.04665E+00 + -1.68737E+00 3.99006E+00 -1.57577E+00 3.94251E+00 -1.48278E+00 3.87552E+00 + -1.37996E+00 3.81932E+00 -1.30327E+00 3.75722E+00 -1.21706E+00 3.67842E+00 + -1.15491E+00 3.61714E+00 -1.08865E+00 3.54480E+00 -1.03021E+00 3.47392E+00 + -9.68721E-01 3.39999E+00 -9.27882E-01 3.32610E+00 -8.95123E-01 3.26769E+00 + -8.66818E-01 3.19600E+00 -8.44608E-01 3.12886E+00 -8.22534E-01 3.06647E+00 + -8.09392E-01 3.01730E+00 -8.02886E-01 2.96935E+00 -7.96270E-01 2.91978E+00 + -7.98254E-01 2.87568E+00 -7.99352E-01 2.83962E+00 -8.06091E-01 2.81346E+00 + -8.07160E-01 2.78222E+00 -8.24389E-01 2.75503E+00 -8.33184E-01 2.73976E+00 + -8.51477E-01 2.73580E+00 -8.65136E-01 2.73125E+00 -8.85255E-01 2.72863E+00 + -9.07618E-01 2.73232E+00 -9.22008E-01 2.75510E+00 -9.34111E-01 2.76357E+00 + -9.45228E-01 2.78913E+00 -9.61341E-01 2.82660E+00 -9.65108E-01 2.86305E+00 + -9.77377E-01 2.91004E+00 -9.76166E-01 2.95564E+00 -9.67109E-01 3.00980E+00 + -9.55232E-01 3.07949E+00 -9.36649E-01 3.14589E+00 -9.07935E-01 3.20988E+00 + -8.75499E-01 3.28146E+00 -8.32822E-01 3.34890E+00 -7.77262E-01 3.41873E+00 + -7.14584E-01 3.49316E+00 -6.58913E-01 3.56518E+00 -5.76929E-01 3.63554E+00 + -4.86966E-01 3.70074E+00 -3.88650E-01 3.76846E+00 -2.91531E-01 3.81561E+00 + -1.96336E-01 3.86585E+00 -8.55135E-02 3.92292E+00 4.36924E-02 3.97133E+00 + 1.70937E-01 3.99898E+00 2.92041E-01 4.02514E+00 4.26943E-01 4.04946E+00 + 5.60896E-01 4.07191E+00 6.99512E-01 4.08880E+00 8.46633E-01 4.09540E+00 + 1.01042E+00 4.10436E+00 1.16534E+00 4.08526E+00 1.32545E+00 4.05539E+00 + 1.48117E+00 4.01444E+00 1.64281E+00 3.98731E+00 1.81795E+00 3.92968E+00 + 2.00458E+00 3.86229E+00 2.18374E+00 3.75963E+00 2.35847E+00 3.61904E+00 + 2.50188E+00 3.45143E+00 2.61501E+00 3.27941E+00 2.68420E+00 3.10489E+00 + 2.71404E+00 2.94790E+00 2.75326E+00 2.81368E+00 2.76867E+00 2.69682E+00 + 2.80534E+00 2.59887E+00 2.83167E+00 2.50135E+00 2.87822E+00 2.40921E+00 + 2.91399E+00 2.30431E+00 2.94684E+00 2.20653E+00 3.00105E+00 2.09597E+00 + 3.02947E+00 1.98990E+00 3.04873E+00 1.87797E+00 3.06984E+00 1.76917E+00 + 3.08171E+00 1.65772E+00 3.08110E+00 1.55364E+00 3.08963E+00 1.45849E+00 + 3.08460E+00 1.36000E+00 3.07576E+00 1.26711E+00 3.07626E+00 1.17142E+00 + 3.06517E+00 1.09226E+00 3.05417E+00 1.00839E+00 3.04108E+00 9.30103E-01 + 3.03062E+00 8.63921E-01 3.01589E+00 7.83542E-01 3.00278E+00 7.15770E-01 + 2.98011E+00 6.48173E-01 2.97258E+00 5.88053E-01 2.95667E+00 5.29609E-01 + 2.93710E+00 4.69082E-01 2.91809E+00 4.18772E-01 2.90269E+00 3.68663E-01 + 2.89245E+00 3.17874E-01 2.87675E+00 2.67792E-01 2.85424E+00 2.33215E-01 + 2.84008E+00 1.88055E-01 2.83805E+00 1.50991E-01 2.82951E+00 1.18215E-01 + 2.82403E+00 8.41629E-02 2.82844E+00 4.81623E-02 2.83237E+00 1.24065E-02 + 2.82521E+00 -1.40139E-02 2.82949E+00 -4.53022E-02 2.83612E+00 -7.05202E-02 + 2.84014E+00 -9.01190E-02 2.86017E+00 -1.20663E-01 2.87880E+00 -1.51888E-01 + 2.90589E+00 -1.69389E-01 2.93076E+00 -2.05611E-01 2.96750E+00 -2.36382E-01 + 3.00923E+00 -2.71517E-01 3.05189E+00 -2.97792E-01 3.10101E+00 -3.48777E-01 + 3.14971E+00 -3.96320E-01 3.20505E+00 -4.49491E-01 3.26925E+00 -5.03391E-01 + 3.33782E+00 -5.83686E-01 3.39376E+00 -6.62328E-01 3.46142E+00 -7.45177E-01 + 3.51923E+00 -8.47520E-01 3.57269E+00 -9.59794E-01 3.62706E+00 -1.07572E+00 + 3.67400E+00 -1.19548E+00 3.71940E+00 -1.33118E+00 3.74325E+00 -1.47132E+00 + 3.76860E+00 -1.60969E+00 3.77713E+00 -1.76374E+00 3.78751E+00 -1.91063E+00 + 3.78400E+00 -2.06196E+00 3.76586E+00 -2.22231E+00 3.73312E+00 -2.36490E+00 + 3.69909E+00 -2.50662E+00 3.67422E+00 -2.66044E+00 3.62444E+00 -2.79756E+00 + 3.57428E+00 -2.94531E+00 3.51255E+00 -3.07716E+00 3.44999E+00 -3.21088E+00 + 3.39203E+00 -3.33822E+00 3.32300E+00 -3.45935E+00 3.26278E+00 -3.59468E+00 + 3.19635E+00 -3.71047E+00 3.12057E+00 -3.85054E+00 3.03467E+00 -3.98680E+00 + 2.94648E+00 -4.10820E+00 2.85169E+00 -4.23133E+00 2.76355E+00 -4.33686E+00 + 2.67745E+00 -4.46418E+00 2.58723E+00 -4.59889E+00 2.47890E+00 -4.73359E+00 + 2.35720E+00 -4.87195E+00 2.19924E+00 -4.98866E+00 2.03586E+00 -5.08565E+00 + 1.88578E+00 -5.14875E+00 1.75398E+00 -5.18770E+00 1.65216E+00 -5.22472E+00 + 1.56440E+00 -5.28345E+00 1.48731E+00 -5.36498E+00 1.40962E+00 -5.48754E+00 + 1.32410E+00 -5.60682E+00 1.19810E+00 -5.75449E+00 1.06971E+00 -5.90547E+00 + 8.96300E-01 -6.04699E+00 7.06613E-01 -6.19095E+00 4.90366E-01 -6.32227E+00 + 2.65175E-01 -6.42696E+00 2.01846E-02 -6.51218E+00 -2.29359E-01 -6.56842E+00 + -4.84049E-01 -6.62619E+00 -7.44709E-01 -6.64141E+00 -1.00512E+00 -6.66408E+00 + -1.27840E+00 -6.64250E+00 -1.54361E+00 -6.62308E+00 -1.79174E+00 -6.59106E+00 + -2.04613E+00 -6.51377E+00 -2.30965E+00 -6.43492E+00 -2.55638E+00 -6.33983E+00 + -2.79416E+00 -6.20975E+00 -3.01133E+00 -6.07851E+00 -3.21811E+00 -5.93051E+00 + -3.42061E+00 -5.78305E+00 -3.59656E+00 -5.63258E+00 -3.75207E+00 -5.45559E+00 + -3.91177E+00 -5.27944E+00 -4.05799E+00 -5.10156E+00 -4.17094E+00 -4.92820E+00 + -4.27608E+00 -4.74084E+00 -4.38809E+00 -4.57526E+00 -4.46702E+00 -4.38196E+00 + -4.53820E+00 -4.19637E+00 -4.59342E+00 -4.00961E+00 -4.64086E+00 -3.83474E+00 + -4.68422E+00 -3.66107E+00 -4.71353E+00 -3.48937E+00 -4.72996E+00 -3.32160E+00 + -4.73408E+00 -3.16189E+00 -4.71775E+00 -3.00172E+00 -4.72236E+00 -2.85974E+00 + -4.70077E+00 -2.72654E+00 -4.67561E+00 -2.58729E+00 -4.64940E+00 -2.47536E+00 + -4.61652E+00 -2.34769E+00 -4.58867E+00 -2.24450E+00 -4.55348E+00 -2.13646E+00 + -4.51761E+00 -2.04470E+00 -4.47426E+00 -1.95437E+00 -4.43333E+00 -1.87151E+00 + -4.37383E+00 -1.77505E+00 -4.34372E+00 -1.70766E+00 -4.30731E+00 -1.64856E+00 + -4.26380E+00 -1.57871E+00 -4.21566E+00 -1.52370E+00 -4.17906E+00 -1.46345E+00 + -4.13538E+00 -1.41602E+00 -4.09126E+00 -1.36450E+00 -4.06095E+00 -1.32654E+00 + -4.02153E+00 -1.28171E+00 -3.99403E+00 -1.25253E+00 -3.95115E+00 -1.22623E+00 + -3.91666E+00 -1.19914E+00 -3.88832E+00 -1.17306E+00 -3.86451E+00 -1.16154E+00 + -3.84725E+00 -1.14086E+00 -3.82484E+00 -1.13541E+00 -3.80477E+00 -1.12495E+00 + -3.79479E+00 -1.11603E+00 -3.78399E+00 -1.11866E+00 -3.78520E+00 -1.10681E+00 + -3.77580E+00 -1.10334E+00 -3.78130E+00 -1.08986E+00 -3.77693E+00 -1.09035E+00 + -3.78571E+00 -1.08683E+00 -3.79615E+00 -1.06622E+00 -3.81044E+00 -1.05973E+00 + -3.82861E+00 -1.04672E+00 -3.83422E+00 -1.02417E+00 -3.85363E+00 -1.02021E+00 + -3.86482E+00 -9.92038E-01 -3.86651E+00 -9.75658E-01 -3.88475E+00 -9.51098E-01 + -3.90490E+00 -9.33997E-01 -3.91544E+00 -9.05096E-01 -3.93934E+00 -8.91568E-01 + -3.94034E+00 -8.61041E-01 -3.95968E+00 -8.40527E-01 -3.97900E+00 -8.14851E-01 + -4.00029E+00 -7.78369E-01 -4.01877E+00 -7.49986E-01 -4.03721E+00 -7.27956E-01 + -4.05314E+00 -6.96085E-01 -4.07208E+00 -6.68363E-01 -4.08177E+00 -6.37458E-01 + -4.09625E+00 -5.98550E-01 -4.11921E+00 -5.77184E-01 -4.12858E+00 -5.42446E-01 + -4.14431E+00 -5.04730E-01 -4.15716E+00 -4.80687E-01 -4.17536E+00 -4.36222E-01 + -4.19078E+00 -4.11166E-01 -4.19755E+00 -3.73861E-01 -4.20933E+00 -3.43406E-01 + -4.22016E+00 -3.02052E-01 -4.23033E+00 -2.78869E-01 -4.24072E+00 -2.32225E-01 + -4.25096E+00 -2.01224E-01 -4.25878E+00 -1.72623E-01 -4.26699E+00 -1.37222E-01 + -4.27436E+00 -9.82300E-02 -4.27440E+00 -6.28084E-02 -4.27743E+00 -2.37050E-02 + -4.27762E+00 -5.35695E-03 -4.28119E+00 3.00863E-02 -4.28824E+00 6.72033E-02 + -4.29781E+00 9.90254E-02 -4.29451E+00 1.30190E-01 -4.30073E+00 1.55212E-01 + -4.30756E+00 2.04459E-01 -4.30564E+00 2.31725E-01 -4.30310E+00 2.64428E-01 + -4.31563E+00 2.96452E-01 -4.32230E+00 3.35282E-01 -4.30996E+00 3.61532E-01 + -4.31974E+00 3.88228E-01 -4.30663E+00 4.18974E-01 -4.31897E+00 4.56592E-01 + -4.32204E+00 4.76015E-01 -4.32087E+00 5.08377E-01 -4.32304E+00 5.43198E-01 + -4.32241E+00 5.61593E-01 -4.32979E+00 5.91005E-01 -4.32043E+00 6.10382E-01 + -4.33116E+00 6.29378E-01 -4.33852E+00 6.51228E-01 -4.34596E+00 6.75866E-01 + -4.35486E+00 7.11316E-01 -4.36502E+00 7.31296E-01 -4.37348E+00 7.51085E-01 + -4.39175E+00 7.79591E-01 -4.39939E+00 8.04902E-01 -4.41833E+00 8.36271E-01 + -4.42536E+00 8.79101E-01 -4.43284E+00 9.20073E-01 -4.42614E+00 9.58448E-01 + -4.42976E+00 1.00309E+00 -4.41348E+00 1.03909E+00 -4.40999E+00 1.06655E+00 + -4.39121E+00 1.08824E+00 -4.37389E+00 1.10798E+00 -4.36837E+00 1.12539E+00 + -4.36781E+00 1.14072E+00 -4.37029E+00 1.15919E+00 -4.36818E+00 1.16069E+00 + -4.37163E+00 1.17842E+00 -4.37631E+00 1.19625E+00 -4.39037E+00 1.20281E+00 + -4.39493E+00 1.22658E+00 -4.41734E+00 1.23993E+00 -4.43101E+00 1.25727E+00 + -4.43657E+00 1.27641E+00 -4.45513E+00 1.29446E+00 -4.46901E+00 1.31935E+00 + -4.49003E+00 1.32747E+00 -4.51591E+00 1.34459E+00 -4.53159E+00 1.35710E+00 + -4.54621E+00 1.38414E+00 -4.57473E+00 1.40639E+00 -4.59155E+00 1.42328E+00 + -4.62294E+00 1.44333E+00 -4.64991E+00 1.45652E+00 -4.66609E+00 1.47730E+00 + -4.69366E+00 1.50501E+00 -4.71777E+00 1.52613E+00 -4.74730E+00 1.55576E+00 + -4.77502E+00 1.57338E+00 -4.80563E+00 1.60017E+00 -4.83142E+00 1.62345E+00 + -4.87146E+00 1.64158E+00 -4.90701E+00 1.68124E+00 -4.93869E+00 1.69167E+00 + -4.98580E+00 1.74174E+00 -5.02072E+00 1.76788E+00 -5.05827E+00 1.80651E+00 + -5.09836E+00 1.84115E+00 -5.12935E+00 1.87407E+00 -5.17483E+00 1.92751E+00 + -5.22575E+00 1.98072E+00 -5.26550E+00 2.02214E+00 -5.31670E+00 2.06904E+00 + -5.35654E+00 2.12743E+00 0.00000E+00 0.00000E+00 0.00000E+00 0.00000E+00 + -1 \ No newline at end of file diff --git a/test/datasets/pump1.ufb b/test/datasets/pump1.ufb new file mode 100644 index 0000000000000000000000000000000000000000..cc4a1f40f916c23e2f7f829b3bfedd1f582f8214 GIT binary patch literal 13728 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 Date: Fri, 14 Nov 2025 16:14:18 -0500 Subject: [PATCH 2/4] Add Dataset1858 to exported datasets --- src/UFFFiles.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UFFFiles.jl b/src/UFFFiles.jl index 55d809a..11e9947 100644 --- a/src/UFFFiles.jl +++ b/src/UFFFiles.jl @@ -9,7 +9,7 @@ module UFFFiles # Exported Types # Types for UFF datasets -- see https://www.ceas3.uc.edu/sdrluff/all_files.php export Dataset15, Dataset18, Dataset55, Dataset58, Dataset82, - Dataset151, Dataset164, Dataset2411, Dataset2412, Dataset2414 + Dataset151, Dataset164, Dataset1858, Dataset2411, Dataset2412, Dataset2414 # Exported functions - Main functions export readuff, writeuff From 8644900f66d2602874e91d95589e6463ce61b2b0 Mon Sep 17 00:00:00 2001 From: jakezw Date: Wed, 19 Nov 2025 12:15:10 -0500 Subject: [PATCH 3/4] refactor write_dataset to accomadate binary files. except 2000 series files. Also implemented @scanf for some parsing --- Project.toml | 4 + src/UFFFiles.jl | 1 + src/datasets/dataset15.jl | 12 +- src/datasets/dataset151.jl | 26 +- src/datasets/dataset164.jl | 18 +- src/datasets/dataset18.jl | 23 +- src/datasets/dataset1858.jl | 71 +- src/datasets/dataset55.jl | 32 +- src/datasets/dataset58.jl | 165 +---- src/datasets/dataset58_original.jl | 1071 ---------------------------- src/datasets/dataset58b.jl | 251 ++----- src/datasets/dataset58common.jl | 145 ++++ src/datasets/dataset82.jl | 24 +- src/read_write_uff.jl | 16 +- test/runtests.jl | 1 + 15 files changed, 352 insertions(+), 1508 deletions(-) delete mode 100644 src/datasets/dataset58_original.jl diff --git a/Project.toml b/Project.toml index a0de348..4168eee 100644 --- a/Project.toml +++ b/Project.toml @@ -4,12 +4,16 @@ version = "0.3.0" authors = ["Mathieu Aucejo <79322171+maucejo@users.noreply.github.com> and contributors"] [deps] +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Scanf = "6ef1bc8b-493b-44e1-8d40-549aa65c4b41" [compat] +Dates = "1.11.0" FileIO = "1.17.1" Printf = "1.11.0" +Scanf = "0.5.4" Test = "1.11.0" julia = "1.10" diff --git a/src/UFFFiles.jl b/src/UFFFiles.jl index 11e9947..b2261d2 100644 --- a/src/UFFFiles.jl +++ b/src/UFFFiles.jl @@ -2,6 +2,7 @@ module UFFFiles using Dates using FileIO using Printf + using Scanf # Base UFFDataset abstract type abstract type UFFDataset end diff --git a/src/datasets/dataset15.jl b/src/datasets/dataset15.jl index 4a8f13d..02bdeb5 100644 --- a/src/datasets/dataset15.jl +++ b/src/datasets/dataset15.jl @@ -86,12 +86,12 @@ Write a UFF Dataset 15 (Nodes) to a vector of strings. **Output** - `Vector{String}`: Vector of formatted strings representing the UFF file content """ -function write_dataset(dataset::Dataset15) +function write_dataset(io, dataset::Dataset15) lines = String[] # Write header - push!(lines, " -1") - push!(lines, " 15") + println(io, " -1") + println(io, " 15") # Write node data for i in eachindex(dataset.node_ID) @@ -105,11 +105,11 @@ function write_dataset(dataset::Dataset15) dataset.coords[i][2], dataset.coords[i][3] ) - push!(lines, line) + println(io, line) end # Write footer - push!(lines, " -1") + println(io, " -1") - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset151.jl b/src/datasets/dataset151.jl index 1c720c7..b0be4d5 100644 --- a/src/datasets/dataset151.jl +++ b/src/datasets/dataset151.jl @@ -128,21 +128,19 @@ Write a UFF Dataset 151 (Header) to a vector of strings. **Output** - `Vector{String}`: Vector of formatted strings representing the UFF file content """ -function write_dataset(dataset::Dataset151) - lines = String[] - +function write_dataset(io, dataset::Dataset151) # Write header - push!(lines, " -1") - push!(lines, " 151") + println(io, " -1") + println(io, " 151") # Record 1: FORMAT(80A1) - model file name - push!(lines, extend_line(dataset.model_name)) + println(io, extend_line(dataset.model_name)) # Record 2: FORMAT(80A1) - model file description (empty line if no description) - push!(lines, extend_line(dataset.description)) + println(io, extend_line(dataset.description)) # Record 3: FORMAT(80A1) - program which created DB - push!(lines, extend_line(dataset.application)) + println(io, extend_line(dataset.application)) # Record 4: FORMAT(10A1,10A1,3I10) - date/time created, version, version, file_type # The datetime_created field should already contain both date and time @@ -169,7 +167,7 @@ function write_dataset(dataset::Dataset151) " " ) - push!(lines, record4) + println(io, record4) # Record 5: FORMAT(10A1,10A1) - date/time last saved record5 = @sprintf("%-10s%-10s%60s", @@ -178,10 +176,10 @@ function write_dataset(dataset::Dataset151) " " ) - push!(lines, record5) + println(io, record5) # Record 6: FORMAT(80A1) - program which created universal file - push!(lines, extend_line(dataset.program)) + println(io, extend_line(dataset.program)) # Record 7: FORMAT(10A1,10A1) - date/time written record7 = @sprintf("%-10s%-10s%60s", @@ -190,10 +188,10 @@ function write_dataset(dataset::Dataset151) " " ) - push!(lines, record7) + println(io, record7) # Write footer - push!(lines, " -1") + println(io, " -1") - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset164.jl b/src/datasets/dataset164.jl index 862b1b7..1592881 100644 --- a/src/datasets/dataset164.jl +++ b/src/datasets/dataset164.jl @@ -101,12 +101,10 @@ Write a UFF Dataset 164 (Units) to a vector of strings. **Output** - `Vector{String}`: Vector of formatted strings representing the UFF file content """ -function write_dataset(dataset::Dataset164) - lines = String[] - +function write_dataset(io, dataset::Dataset164) # Write header - push!(lines, " -1") - push!(lines, " 164") + println(io, " -1") + println(io, " 164") # Write Record 1: FORMAT(I10,20A1,I10) # Field 1: units code (I10) @@ -121,7 +119,7 @@ function write_dataset(dataset::Dataset164) desc, dataset.temperature_mode ) - push!(lines, line1) + println(io, line1) # Write Record 2: FORMAT(3D25.17) # First line: 3 conversion factors (length, force, temperature) @@ -130,16 +128,16 @@ function write_dataset(dataset::Dataset164) dataset.conversion_force, dataset.conversion_temperature ) - push!(lines, line2) + println(io, line2) # Second line: temperature offset line3 = @sprintf("%25.17E", dataset.conversion_temperature_offset ) - push!(lines, line3) + println(io, line3) # Write footer - push!(lines, " -1") + println(io, " -1") - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset18.jl b/src/datasets/dataset18.jl index 9ed80af..1af1b4d 100644 --- a/src/datasets/dataset18.jl +++ b/src/datasets/dataset18.jl @@ -130,20 +130,17 @@ Write a UFF Dataset 18 (Coordinate Systems) to a vector of strings. **Output** - `Vector{String}`: Vector of formatted strings representing the UFF file content """ -function write_dataset(dataset::Dataset18) - lines = String[] - +function write_dataset(io, dataset::Dataset18) # Header - push!(lines, " -1") - push!(lines, " 18") + println(io, " -1") + println(io, " 18") # Ensure we can iterate consistently over coordinate systems ncs = length(dataset.cs_num) for i in 1:ncs # Record 1: FORMAT(5I10) - 5 integers with width 10 - push!( - lines, + println(io, @sprintf("%10d%10d%10d%10d%10d", dataset.cs_num[i], dataset.cs_type[i], @@ -154,12 +151,11 @@ function write_dataset(dataset::Dataset18) ) # Record 2: FORMAT(20A2) - coordinate system name (40 characters) - push!(lines, dataset.cs_name[i]) + println(io, dataset.cs_name[i]) # Record 3: FORMAT(1P6E13.5) - 9 coordinate system definition parameters # Split into 2 lines: first line has 6 values, second line has 3 values - push!( - lines, + println(io, @sprintf("%13.5E%13.5E%13.5E%13.5E%13.5E%13.5E", dataset.cs_origin[i][1], dataset.cs_origin[i][2], @@ -169,8 +165,7 @@ function write_dataset(dataset::Dataset18) dataset.cs_x[i][3] ), ) - push!( - lines, + println(io, @sprintf("%13.5E%13.5E%13.5E", dataset.cs_xz[i][1], dataset.cs_xz[i][2], @@ -180,7 +175,7 @@ function write_dataset(dataset::Dataset18) end # Footer - push!(lines, " -1") + println(io, " -1") - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset1858.jl b/src/datasets/dataset1858.jl index 1b814fc..8ef38ed 100644 --- a/src/datasets/dataset1858.jl +++ b/src/datasets/dataset1858.jl @@ -187,12 +187,16 @@ Record 7: FORMAT (40A2) """ function parse_dataset1858(io) # Record 1 - record1 = extend_line(readline(io)) + record1 = (readline(io)) set_record_number = parse(Int, record1[1:12]) octave_format = parse(Int, record1[13:24]) meas_run = parse(Int, record1[25:36]) + + + n, set_record_number, octave_format, meas_run, unused... = @scanf(record1, "%12i%12i%12i%12i%12i%12i", Int, Int, Int, Int, Int, Int) + # Record 2 - record2 = extend_line(readline(io)) + record2 = (readline(io)) octave_weighting = parse(Int, record2[1:6]) window = parse(Int, record2[7:12]) amp_scaling = parse(Int, record2[13:18]) @@ -202,26 +206,45 @@ function parse_dataset1858(io) ord_denom_data_type_qual = parse(Int, record2[37:42]) z_axis_data_type_qual = parse(Int, record2[43:48]) sampling_type = parse(Int, record2[49:54]) - # Record 3 - record3 = extend_line(readline(io)) + + + n, octave_weighting, window, amp_scaling, normalization, abs_data_type_qual, + ord_num_data_type_qual, ord_denom_data_type_qual, z_axis_data_type_qual, + sampling_type = @scanf(record2, "%6i%6i%6i%6i%6i%6i%6i%6i%6i%6i%6i%6i", + Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) + + # Record 3 + record3 = (readline(io)) z_rpm_value = parse(Float64, record3[1:15]) z_time_value = parse(Float64, record3[16:30]) z_order_value = parse(Float64, record3[31:45]) num_samples = parse(Float64, record3[46:60]) |> Int # Single precision in data file but must be Int + + + n, z_rpm_value, z_time_value, z_order_value, num_samples, _ = @scanf(record3, "%15e%15e%15e%15e%15e", Float64, Float64, Float64, Int, Float64) + # Record 4 - record4 = extend_line(readline(io)) + record4 = (readline(io)) uv1 = parse(Float64, record4[1:15]) uv2 = parse(Float64, record4[16:30]) uv3 = parse(Float64, record4[31:45]) uv4 = parse(Float64, record4[46:60]) exp_window_damping = parse(Float64, record4[61:75]) + + + n, uv1, uv2, uv3, uv4, exp_window_damping = @scanf(record4, "%15e%15e%15e%15e%15e", Float64, Float64, Float64, Float64, Float64) + # Record 5 Unused _ = readline(io) + # Record 6 - record6 = extend_line(readline(io)) + record6 = (readline(io)) resp_dir = strip(record6[1:4]) ref_dir = strip(record6[7:10]) + + n, resp_dir, _, ref_dir = @scanf(record6, "%4c%2c%4c", String, String, String) + _ = readline(io) # Read unused Record 7 _ = readline(io) # Read trailing " -1" @@ -263,12 +286,10 @@ Write a UFF Dataset 1858 (Dataset58 qualifiers) to a vector of strings. **Output** - `Vector{String}`: Vector of formatted strings representing the UFF file content """ -function write_dataset(dataset::Dataset1858) #::Dataset1858) #the remainder is a copy from 164 and needs to be implemented - lines = String[] - +function write_dataset(io, dataset::Dataset1858) #::Dataset1858) #the remainder is a copy from 164 and needs to be implemented # Write header - push!(lines, " -1") - push!(lines, " 1858") + println(io, " -1") + println(io, " 1858") # Write Record 1: FORMAT(6I12) # Field 1 - Set record number @@ -282,7 +303,7 @@ function write_dataset(dataset::Dataset1858) #::Dataset1858) #the remainder is a dataset.meas_run, 0, 0, 0 ) - push!(lines, line1) + println(io, line1) # Write Record 2: FORMAT(12I6) # Field 1 - Weighting Type @@ -307,9 +328,9 @@ function write_dataset(dataset::Dataset1858) #::Dataset1858) #the remainder is a dataset.sampling_type, 0, 0, 0 ) - push!(lines, line2) + println(io, line2) -# Write Record 3: FORMAT (1P5E15.7) + # Write Record 3: FORMAT (1P5E15.7) # Field 1 - Z RPM value # Field 2 - Z Time value # Field 3 - Z Order value @@ -323,9 +344,9 @@ function write_dataset(dataset::Dataset1858) #::Dataset1858) #the remainder is a dataset.num_samples, 0.0 ) - push!(lines, line3) + println(io, line3) -# Write Record 4: FORMAT (1P5E15.7) + # Write Record 4: FORMAT (1P5E15.7) # Field 1 - User value 1 # Field 2 - User value 2 # Field 3 - User value 3 @@ -338,29 +359,29 @@ function write_dataset(dataset::Dataset1858) #::Dataset1858) #the remainder is a dataset.uv4, dataset.exp_window_damping ) -push!(lines, line4) + println(io, line4) -# Write Record 5: FORMAT (1P5E15.7) + # Write Record 5: FORMAT (1P5E15.7) # Fields 1-5 - not used (fill with zeros) line5 = @sprintf("%15.8e%15.8e%15.8e%15.8e%15.8e ", 0.0, 0.0, 0.0, 0.0, 0.0) -push!(lines, line5) + println(io, line5) -# Write Record 6: FORMAT (2A2,2X,2A2) + # Write Record 6: FORMAT (2A2,2X,2A2) # Field 1 - Response direction # Field 2 - Reference direction line6 = @sprintf("%-4s %-74s", dataset.resp_dir, dataset.ref_dir) -push!(lines, line6) + println(io, line6) -#Write Record 7: FORMAT (40A2) + # Write Record 7: FORMAT (40A2) # Field 1 - not used line7 = @sprintf("%-80s","NONE") - push!(lines, line7) + println(io, line7) # Write footer - push!(lines, " -1") + println(io, " -1") - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset55.jl b/src/datasets/dataset55.jl index 7c7a6d7..a7e17d8 100644 --- a/src/datasets/dataset55.jl +++ b/src/datasets/dataset55.jl @@ -508,21 +508,19 @@ Write a UFF Dataset 55 (Data at Nodes) to a vector of strings. **Output** - `Vector{String}`: Vector of formatted strings representing the UFF file content """ -function write_dataset(dataset::Dataset55) - lines = String[] - +function write_dataset(io, dataset::Dataset55) # Write header - push!(lines, " -1") - push!(lines, " 55") + println(io, " -1") + println(io, " 55") # Write Records 1-5: ID lines (format 40A2 or 80A1) - push!(lines, dataset.id1) - push!(lines, dataset.id2) - push!(lines, dataset.id3) - push!(lines, dataset.id4) + println(io, dataset.id1) + println(io, dataset.id2) + println(io, dataset.id3) + println(io, dataset.id4) # Properly indent the line - push!(lines, " "^9 * dataset.id5) + println(io, " "^9 * dataset.id5) # Write Record 6: format 6I10 line6 = @sprintf("%10d%10d%10d%10d%10d%10d", @@ -533,13 +531,13 @@ function write_dataset(dataset::Dataset55) dataset.dtype, dataset.ndv_per_node ) - push!(lines, line6) + println(io, line6) # Write Record 7: format 8I10 # Get r7_raw from the r7 NamedTuple r7_values = collect(values(dataset.r7)) line7_parts = [@sprintf("%10d", val) for val in r7_values] - push!(lines, join(line7_parts, "")) + println(io, join(line7_parts, "")) # Write Record 8: format 6E13.5 # Get r8_raw from the r8 NamedTuple @@ -548,7 +546,7 @@ function write_dataset(dataset::Dataset55) # Write up to 6 values per line for i in 1:6:length(line8_parts) end_idx = min(i + 5, length(line8_parts)) - push!(lines, join(line8_parts[i:end_idx], "")) + println(io, join(line8_parts[i:end_idx], "")) end # Write Records 9 and 10 for each node @@ -557,7 +555,7 @@ function write_dataset(dataset::Dataset55) for i in 1:nnodes # Record 9: format I10 - node number line9 = @sprintf("%10d", dataset.node_number[i]) - push!(lines, line9) + println(io, line9) # Record 10: format 6E13.5 - data values # Get data for this node @@ -585,12 +583,12 @@ function write_dataset(dataset::Dataset55) for j in 1:6:length(data_values) end_idx = min(j + 5, length(data_values)) line_parts = [@sprintf("%13.5e", val) for val in data_values[j:end_idx]] - push!(lines, join(line_parts, "")) + println(io, join(line_parts, "")) end end # Write footer - push!(lines, " -1") + println(io, " -1") - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset58.jl b/src/datasets/dataset58.jl index d29d280..a3699c8 100644 --- a/src/datasets/dataset58.jl +++ b/src/datasets/dataset58.jl @@ -969,144 +969,42 @@ function parse_dataset58(io) ) end -""" - write_dataset(dataset::Dataset58) -> Vector{String} - -Write a UFF Dataset 58 (Function Data) to a vector of strings. - -**Input** -- `dataset::Dataset58`: The Dataset58 instance to write. - -**Output** -- `Vector{String}`: A vector of strings representing the lines of the dataset. -""" -function write_dataset(dataset::Dataset58) - lines = String[] - - # Start marker - push!(lines, " -1") - - # Dataset number - push!(lines, " 58") - - # Records 1-5: ID Lines (80A1 format) - push!(lines, dataset.id1) - push!(lines, dataset.id2) - push!(lines, dataset.id3) - push!(lines, dataset.id4) - push!(lines, dataset.id5) - - # Record 6: DOF Identification - # Format: 2(I5,I10),2(1X,10A1,I10,I4) - r6_line = @sprintf("%5d%10d%5d%10d %-10s%10d%4d %-10s%10d%4d", - dataset.func_type, - dataset.func_id, - dataset.ver_num, - dataset.load_case, - dataset.resp_name, - dataset.resp_node, - dataset.resp_dir, - dataset.ref_name, - dataset.ref_node, - dataset.ref_dir) - push!(lines, r6_line) - - # Record 7: Data Form - # Format: 3I10,3E13.5 - r7_line = @sprintf("%10d%10d%10d%13.5E%13.5E%13.5E", - dataset.ord_dtype, - dataset.num_pts, - dataset.abs_spacing_type, - dataset.abs_min, - dataset.abs_increment, - dataset.zval) - push!(lines, r7_line) - - # Record 8: Abscissa Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r8_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.abs_spec_dtype, - dataset.abs_len_unit_exp, - dataset.abs_force_unit_exp, - dataset.abs_temp_unit_exp, - dataset.abs_axis_label, - dataset.abs_axis_unit_label) - push!(lines, r8_line) - - # Record 9: Ordinate Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r9_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.ord_spec_dtype, - dataset.ord_len_unit_exp, - dataset.ord_force_unit_exp, - dataset.ord_temp_unit_exp, - dataset.ord_axis_label, - dataset.ord_axis_unit_label) - push!(lines, r9_line) - - # Record 10: Ordinate Denominator Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r10_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.ord_denom_spec_dtype, - dataset.ord_denom_len_unit_exp, - dataset.ord_denom_force_unit_exp, - dataset.ord_denom_temp_unit_exp, - dataset.ord_denom_axis_label, - dataset.ord_denom_axis_unit_label) - push!(lines, r10_line) - - # Record 11: Z-axis Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r11_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.z_spec_dtype, - dataset.z_len_unit_exp, - dataset.z_force_unit_exp, - dataset.z_temp_unit_exp, - dataset.z_axis_label, - dataset.z_axis_unit_label) - push!(lines, r11_line) - +function write_dataset58_data(io, dataset::Dataset58) # Record 12: Data Values # Format depends on ordinate data type and precision - if dataset.ord_dtype == 2 || dataset.ord_dtype == 4 - # Real data (single or double precision) - if dataset.ord_dtype == 2 - # Real single precision: 6E13.5 - values_per_line = 6 - fmt = "E13.5" - else - # Real double precision: 4E20.12 - values_per_line = 4 - fmt = "E20.12" - end - # Write data in chunks - for i in 1:values_per_line:length(dataset.data) - end_idx = min(i + values_per_line - 1, length(dataset.data)) - chunk = dataset.data[i:end_idx] - - if dataset.ord_dtype == 2 - line = join([@sprintf(" %12.5E", v) for v in chunk], "") - else - line = join([@sprintf(" %19.12E", v) for v in chunk], "") - end - push!(lines, line) - end + if (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 1 - Real, Single Precision, Even Spacing + # FORMAT(6E13.5) 6 values per line + y_values_per_line = 6 + abscissa = Float32[] + for i in 1:y_values_per_line:length(dataset.data) + ie = min(i + y_values_per_line - 1, length(dataset.data)) + line = join([@sprintf(" %12.5E", v) for v in dataset.data[i:ie]]) + println(io, line) + end + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 2 - Real, Single Precision, Uneven Spacing + # Real single precision uneven: 6E13.5 (3 pair per line) + xy_pair_per_line = 3 + for i in 1:xy_pair_per_line:length(dataset.data) + ie = min(i + xy_pair_per_line - 1, length(dataset.data)) + line = join([@sprintf(" %12.5E %12.5E %12.5E", a, real(o), imag(o)) for (a, o) in zip(dataset.abscissa[i:ie], dataset.data[i:ie])]) + println(io, line) + end elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 3 - Complex, Single Precision, Even Spacing # Complex single precision even: 6E13.5 (3 complex values per line) y_pair_per_line = 3 for i in 1:y_pair_per_line:length(dataset.data) - ie = min(i + y_pair_per_line - 1, length(dataset.abscissa)) + ie = min(i + y_pair_per_line - 1, length(dataset.data)) line = join([@sprintf(" %12.5E %12.5E", real(v), imag(v)) for v in dataset.data[i:ie]]) - push!(lines, line) + println(io, line) end elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 4 - Complex, Single Precision, Uneven Spacing # Complex single precision uneven: 6E13.5 (3 complex values per line) xy_pair_per_line = 2 for i in 1:xy_pair_per_line:length(dataset.data) - ie = min(i + xy_pair_per_line - 1, length(dataset.abscissa)) + ie = min(i + xy_pair_per_line - 1, length(dataset.data)) line = join([@sprintf(" %12.5E %12.5E %12.5E", a, real(o), imag(o)) for (a, o) in zip(dataset.abscissa[i:ie], dataset.data[i:ie])]) - push!(lines, line) + println(io, line) end elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 5 - Real, Double Precision, Even Spacing # Real double precision even: 4E20.12 @@ -1115,36 +1013,33 @@ function write_dataset(dataset::Dataset58) ie = min(i + y_values_per_line - 1, length(dataset.data)) chunk = dataset.data[i:ie] line = join([@sprintf(" %19.12E", v) for v in chunk], "") - push!(lines, line) + println(io, line) end elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 6 - Real, Double Precision, Uneven Spacing # Real double precision uneven: 2(E13.5,E20.12) xy_pair_per_line = 2 for i in 1:xy_pair_per_line:length(dataset.data) - ie = min(i + xy_pair_per_line - 1, length(dataset.abscissa)) + ie = min(i + xy_pair_per_line - 1, length(dataset.data)) line = join([@sprintf(" %12.5E %19.12E", a, o) for (a, o) in zip(dataset.abscissa[i:ie], dataset.data[i:ie])]) - push!(lines, line) + println(io, line) end elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 7 - Complex, Double Precision, Even Spacing # Complex double precision even: 4E20.12 (2 complex values per line) y_pair_per_line = 3 for i in 1:y_pair_per_line:length(dataset.data) - ie = min(i + y_pair_per_line - 1, length(dataset.abscissa)) + ie = min(i + y_pair_per_line - 1, length(dataset.data)) line = join([@sprintf(" %19.12E %19.12E", real(v), imag(v)) for v in dataset.data[i:ie]]) - push!(lines, line) + println(io, line) end elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 8 - Complex, Double Precision, Uneven Spacing # Complex double precision uneven: E13.5,2E20.12 (1 complex values per line) xy_pair_per_line = 1 for i in 1:xy_pair_per_line:length(dataset.data) - ie = min(i + xy_pair_per_line - 1, length(dataset.abscissa)) + ie = min(i + xy_pair_per_line - 1, length(dataset.data)) line = join([@sprintf(" %12.5E %19.12E %19.12E", a, real(o), imag(o)) for (a, o) in zip(dataset.abscissa[i:ie], dataset.data[i:ie])]) - push!(lines, line) + println(io, line) end end - # End marker - push!(lines, " -1") - - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset58_original.jl b/src/datasets/dataset58_original.jl deleted file mode 100644 index 66d14ba..0000000 --- a/src/datasets/dataset58_original.jl +++ /dev/null @@ -1,1071 +0,0 @@ -""" -Universal Dataset Number: 58 - -**Name: Function at Nodal DOF** - - Record 1: Format(80A1) - Field 1 - ID Line 1 - - NOTE - - ID Line 1 is generally used for the function - description. - - - Record 2: Format(80A1) - Field 1 - ID Line 2 - - Record 3: Format(80A1) - Field 1 - ID Line 3 - - NOTE - - ID Line 3 is generally used to identify when the - function was created. The date is in the form - DD-MMM-YY, and the time is in the form HH:MM:SS, - with a general Format(9A1,1X,8A1). - - Record 4: Format(80A1) - Field 1 - ID Line 4 - - Record 5: Format(80A1) - Field 1 - ID Line 5 - - Record 6: Format(2(I5,I10),2(1X,10A1,I10,I4)) - DOF Identification - Field 1 - Function Type - 0 - General or Unknown - 1 - Time Response - 2 - Auto Spectrum - 3 - Cross Spectrum - 4 - Frequency Response Function - 5 - Transmissibility - 6 - Coherence - 7 - Auto Correlation - 8 - Cross Correlation - 9 - Power Spectral Density (PSD) - 10 - Energy Spectral Density (ESD) - 11 - Probability Density Function - 12 - Spectrum - 13 - Cumulative Frequency Distribution - 14 - Peaks Valley - 15 - Stress/Cycles - 16 - Strain/Cycles - 17 - Orbit - 18 - Mode Indicator Function - 19 - Force Pattern - 20 - Partial Power - 21 - Partial Coherence - 22 - Eigenvalue - 23 - Eigenvector - 24 - Shock Response Spectrum - 25 - Finite Impulse Response Filter - 26 - Multiple Coherence - 27 - Order Function - Field 2 - Function Identification Number - Field 3 - Version Number, or sequence number - Field 4 - Load Case Identification Number - 0 - Single Point Excitation - Field 5 - Response Entity Name ("NONE" if unused) - Field 6 - Response Node - Field 7 - Response Direction - 0 - Scalar - 1 - +X Translation 4 - +X Rotation - -1 - -X Translation -4 - -X Rotation - 2 - +Y Translation 5 - +Y Rotation - -2 - -Y Translation -5 - -Y Rotation - 3 - +Z Translation 6 - +Z Rotation - -3 - -Z Translation -6 - -Z Rotation - Field 8 - Reference Entity Name ("NONE" if unused) - Field 9 - Reference Node - Field 10 - Reference Direction (same as field 7) - - NOTE - - Fields 8, 9, and 10 are only relevant if field 4 - is zero. - - Record 7: Format(3I10,3E13.5) - Data Form - Field 1 - Ordinate Data Type - 2 - real, single precision - 4 - real, double precision - 5 - complex, single precision - 6 - complex, double precision - Field 2 - Number of data pairs for uneven abscissa - spacing, or number of data values for even - abscissa spacing - Field 3 - Abscissa Spacing - 0 - uneven - 1 - even (no abscissa values stored) - Field 4 - Abscissa minimum (0.0 if spacing uneven) - Field 5 - Abscissa increment (0.0 if spacing uneven) - Field 6 - Z-axis value (0.0 if unused) - - Record 8: Format(I10,3I5,2(1X,20A1)) - Abscissa Data Characteristics - Field 1 - Specific Data Type - 0 - unknown - 1 - general - 2 - stress - 3 - strain - 5 - temperature - 6 - heat flux - 8 - displacement - 9 - reaction force - 11 - velocity - 12 - acceleration - 13 - excitation force - 15 - pressure - 16 - mass - 17 - time - 18 - frequency - 19 - rpm - 20 - order - Field 2 - Length units exponent - Field 3 - Force units exponent - Field 4 - Temperature units exponent - - NOTE - - Fields 2, 3 and 4 are relevant only if the - Specific Data Type is General, or in the case of - ordinates, the response/reference direction is a - scalar, or the functions are being used for - nonlinear connectors in System Dynamics Analysis. - See Addendum 'A' for the units exponent table. - - Field 5 - Axis label ("NONE" if not used) - Field 6 - Axis units label ("NONE" if not used) - - NOTE - - If fields 5 and 6 are supplied, they take - precendence over program generated labels and - units. - - Record 9: Format(I10,3I5,2(1X,20A1)) - Ordinate (or ordinate numerator) Data Characteristics - - Record 10: Format(I10,3I5,2(1X,20A1)) - Ordinate Denominator Data Characteristics - - Record 11: Format(I10,3I5,2(1X,20A1)) - Z-axis Data Characteristics - - NOTE - - Records 9, 10, and 11 are always included and - have fields the same as record 8. If records 10 - and 11 are not used, set field 1 to zero. - - Record 12: - Data Values - - Ordinate Abscissa - Case Type Precision Spacing Format - ------------------------------------------------------------- - 1 real single even 6E13.5 - 2 real single uneven 6E13.5 - 3 complex single even 6E13.5 - 4 complex single uneven 6E13.5 - 5 real double even 4E20.12 - 6 real double uneven 2(E13.5,E20.12) - 7 complex double even 4E20.12 - 8 complex double uneven E13.5,2E20.12 - -------------------------------------------------------------- - - NOTE - - See Addendum 'B' for typical FORTRAN READ/WRITE - statements for each case. - - - General Notes: - - 1. ID lines may not be blank. If no information is required, - the word "NONE" must appear in columns 1 through 4. - - 2. ID line 1 appears on plots in Finite Element Modeling and is - used as the function description in System Dynamics Analysis. - - 3. Dataloaders use the following ID line conventions - ID Line 1 - Model Identification - ID Line 2 - Run Identification - ID Line 3 - Run Date and Time - ID Line 4 - Load Case Name - - 4. Coordinates codes from MODAL-PLUS and MODALX are decoded into - node and direction. - - 5. Entity names used in System Dynamics Analysis prior to I-DEAS - Level 5 have a 4 character maximum. Beginning with Level 5, - entity names will be ignored if this dataset is preceded by - dataset 259. If no dataset 259 precedes this dataset, then the - entity name will be assumed to exist in model bin number 1. - - 6. Record 10 is ignored by System Dynamics Analysis unless load - case = 0. Record 11 is always ignored by System Dynamics - Analysis. - - 7. In record 6, if the response or reference names are "NONE" - and are not overridden by a dataset 259, but the correspond- - ing node is non-zero, System Dynamics Analysis adds the node - and direction to the function description if space is sufficie - - 8. ID line 1 appears on XY plots in Test Data Analysis along - with ID line 5 if it is defined. If defined, the axis units - labels also appear on the XY plot instead of the normal - labeling based on the data type of the function. - - 9. For functions used with nonlinear connectors in System - Dynamics Analysis, the following requirements must be - adhered to: - - a) Record 6: For a displacement-dependent function, the - function type must be 0; for a frequency-dependent - function, it must be 4. In either case, the load case - identification number must be 0. - - b) Record 8: For a displacement-dependent function, the - specific data type must be 8 and the length units - exponent must be 0 or 1; for a frequency-dependent - function, the specific data type must be 18 and the - length units exponent must be 0. In either case, the - other units exponents must be 0. - - c) Record 9: The specific data type must be 13. The - temperature units exponent must be 0. For an ordinate - numerator of force, the length and force units - exponents must be 0 and 1, respectively. For an - ordinate numerator of moment, the length and force - units exponents must be 1 and 1, respectively. - - d) Record 10: The specific data type must be 8 for - stiffness and hysteretic damping; it must be 11 - for viscous damping. For an ordinate denominator of - translational displacement, the length units exponent - must be 1; for a rotational displacement, it must - be 0. The other units exponents must be 0. - - e) Dataset 217 must precede each function in order to - define the function's usage (i.e. stiffness, viscous - damping, hysteretic damping). - - Addendum A - - In order to correctly perform units conversion, length, force, and - temperature exponents must be supplied for a specific data type of - General; that is, Record 8 Field 1 = 1. For example, if the function - has the physical dimensionality of Energy (Force * Length), then the - required exponents would be as follows: - - Length = 1 - Force = 1 Energy = L * F - Temperature = 0 - - Units exponents for the remaining specific data types should not be - supplied. The following exponents will automatically be used. - - Table - Unit Exponents - ------------------------------------------------------- - Specific Direction - --------------------------------------------- - Data Translational Rotational - --------------------------------------------- - Type Length Force Temp Length Force Temp - ------------------------------------------------------- - 0 0 0 0 0 0 0 - 1 (requires input to fields 2,3,4) - 2 -2 1 0 -1 1 0 - 3 0 0 0 0 0 0 - 5 0 0 1 0 0 1 - 6 1 1 0 1 1 0 - 8 1 0 0 0 0 0 - 9 0 1 0 1 1 0 - 11 1 0 0 0 0 0 - 12 1 0 0 0 0 0 - 13 0 1 0 1 1 0 - 15 -2 1 0 -1 1 0 - 16 -1 1 0 1 1 0 - 17 0 0 0 0 0 0 - 18 0 0 0 0 0 0 - 19 0 0 0 0 0 0 - -------------------------------------------------------- - - NOTE - - Units exponents for scalar points are defined within - System Analysis prior to reading this dataset. - - Addendum B - - There are 8 distinct combinations of parameters which affect the - details of READ/WRITE operations. The parameters involved are - Ordinate Data Type, Ordinate Data Precision, and Abscissa Spacing. - Each combination is documented in the examples below. In all cases, - the number of data values (for even abscissa spacing) or data pairs - (for uneven abscissa spacing) is NVAL. The abcissa is always real - single precision. Complex double precision is handled by two real - double precision variables (real part followed by imaginary part) - because most systems do not directly support complex double precision. - - CASE 1 - - REAL - SINGLE PRECISION - EVEN SPACING - - Order of data in file Y1 Y2 Y3 Y4 Y5 Y6 - Y7 Y8 Y9 Y10 Y11 Y12 - . - . - . - Input - - REAL Y(6) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )(Y(I),I=1,6) - 1000 FORMAT(6E13.5) - NPRO=NPRO+6 - . - . code to process these six values - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - Output - - REAL Y(6) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up these six values - . - WRITE(LUN,1000,ERR= )(Y(I),I=1,6) - 1000 FORMAT(6E13.5) - NPRO=NPRO+6 - - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - CASE 2 - - REAL - SINGLE PRECISION - UNEVEN SPACING - - Order of data in file X1 Y1 X2 Y2 X3 Y3 - X4 Y4 X5 Y5 X6 Y6 - . - . - . - - Input - - REAL X(3),Y(3) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )(X(I),Y(I),I=1,3) - 1000 FORMAT(6E13.5) - NPRO=NPRO+3 - . - . code to process these three values - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - Output - - REAL X(3),Y(3) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up these three values - . - WRITE(LUN,1000,ERR= )(X(I),Y(I),I=1,3) - 1000 FORMAT(6E13.5) - NPRO=NPRO+3 - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - CASE 3 - - COMPLEX - SINGLE PRECISION - EVEN SPACING - - Order of data in file RY1 IY1 RY2 IY2 RY3 IY3 - RY4 IY4 RY5 IY5 RY6 IY6 - . - . - . - - Input - - COMPLEX Y(3) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )(Y(I),I=1,3) - 1000 FORMAT(6E13.5) - NPRO=NPRO+3 - . - . code to process these six values - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - - Output - - COMPLEX Y(3) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up these three values - . - WRITE(LUN,1000,ERR= )(Y(I),I=1,3) - 1000 FORMAT(6E13.5) - NPRO=NPRO+3 - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - CASE 4 - - COMPLEX - SINGLE PRECISION - UNEVEN SPACING - - Order of data in file X1 RY1 IY1 X2 RY2 IY2 - X3 RY3 IY3 X4 RY4 IY4 - - . - . - . - - Input - - REAL X(2) - COMPLEX Y(2) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )(X(I),Y(I),I=1,2) - 1000 FORMAT(6E13.5) - NPRO=NPRO+2 - . - . code to process these two values - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - Output - - REAL X(2) - COMPLEX Y(2) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up these two values - . - WRITE(LUN,1000,ERR= )(X(I),Y(I),I=1,2) - 1000 FORMAT(6E13.5) - NPRO=NPRO+2 - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - CASE 5 - - REAL - DOUBLE PRECISION - EVEN SPACING - - Order of data in file Y1 Y2 Y3 Y4 - Y5 Y6 Y7 Y8 - . - . - . - Input - - DOUBLE PRECISION Y(4) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )(Y(I),I=1,4) - 1000 FORMAT(4E20.12) - NPRO=NPRO+4 - . - . code to process these four values - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - Output - - DOUBLE PRECISION Y(4) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up these four values - . - WRITE(LUN,1000,ERR= )(Y(I),I=1,4) - 1000 FORMAT(4E20.12) - NPRO=NPRO+4 - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - CASE 6 - - REAL - DOUBLE PRECISION - UNEVEN SPACING - - Order of data in file X1 Y1 X2 Y2 - X3 Y3 X4 Y4 - . - . - . - Input - - REAL X(2) - DOUBLE PRECISION Y(2) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )(X(I),Y(I),I=1,2) - 1000 FORMAT(2(E13.5,E20.12)) - NPRO=NPRO+2 - . - . code to process these two values - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - Output - - REAL X(2) - DOUBLE PRECISION Y(2) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up these two values - . - WRITE(LUN,1000,ERR= )(X(I),Y(I),I=1,2) - 1000 FORMAT(2(E13.5,E20.12)) - NPRO=NPRO+2 - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - CASE 7 - - COMPLEX - DOUBLE PRECISION - EVEN SPACING - - Order of data in file RY1 IY1 RY2 IY2 - RY3 IY3 RY4 IY4 - . - . - . - - Input - - DOUBLE PRECISION Y(2,2) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )((Y(I,J),I=1,2),J=1,2) - 1000 FORMAT(4E20.12) - NPRO=NPRO+2 - . - . code to process these two values - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - Output - - DOUBLE PRECISION Y(2,2) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up these two values - . - WRITE(LUN,1000,ERR= )((Y(I,J),I=1,2),J=1,2) - 1000 FORMAT(4E20.12) - NPRO=NPRO+2 - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - CASE 8 - - COMPLEX - DOUBLE PRECISION - UNEVEN SPACING - - Order of data in file X1 RY1 IY1 - X2 RY2 IY2 - . - . - . - Input - - REAL X - DOUBLE PRECISION Y(2) - . - . - . - NPRO=0 - 10 READ(LUN,1000,ERR= ,END= )(X,Y(I),I=1,2) - 1000 FORMAT(E13.5,2E20.12) - NPRO=NPRO+1 - . - . code to process this value - . - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . - - Output - - REAL X - DOUBLE PRECISION Y(2) - . - . - . - NPRO=0 - 10 CONTINUE - . - . code to set up this value - . - WRITE(LUN,1000,ERR= )(X,Y(I),I=1,2) - 1000 FORMAT(E13.5,2E20.12) - NPRO=NPRO+1 - IF(NPRO.LT.NVAL)GO TO 10 - . - . continued processing - . -""" -function parse_dataset58(io) - - id1 = strip(readline(io)) - id2 = strip(readline(io)) - id3 = strip(readline(io)) - id4 = strip(readline(io)) - id5 = strip(readline(io)) - # @show(id1, id2, id3, id4, id5) - - # Record 6 - r6 = readline(io) - len_r6 = length(r6) - @show(r6) - #=r6 = split(readline(io)) - - func_type = parse(Int, strip(r6[1])) - func_id = parse(Int, strip(r6[2])) - version_num = parse(Int, strip(r6[3])) - load_case_id = parse(Int, strip(r6[4])) - response_entity = strip(r6[5]) - response_node = parse(Int, strip(r6[6])) - response_direction = parse(Int, strip(r6[7])) - reference_entity = strip(r6[8])=# - # This modified for the space in Sample_UFF58b_bin.uff record 6 field 5 - func_type = parse(Int, r6[1:5]) - func_id = parse(Int, r6[6:15]) - version_num = parse(Int, r6[16:20]) - load_case_id = parse(Int, r6[21:30]) - response_entity = r6[32:41] - response_node = parse(Int, r6[42:51]) - response_direction = parse(Int, r6[52:55]) - reference_entity = r6[57:66] - - if len_r6 > 8 - reference_node = parse(Int, r6[67:76]) - reference_direction = parse(Int, r6[77:80]) - else - reference_node = 0 - reference_direction = 0 - end - - # Record 7 - r7 = split(readline(io)) - ord_dtype, num_pts, abs_spacing_type = parse.(Int, strip.(r7[1:3])) - abs_min, abs_increment, zval = parse.(Float64, strip.(r7[4:6])) - - # Record 8 - r8 = split(readline(io)) - abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp = parse.(Int, strip.(r8[1:4])) - abs_axis_label, abs_axis_unit_label = strip.(r8[5:6]) - - # Record 9 - r9 = split(readline(io)) - ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp = parse.(Int, strip.(r9[1:4])) - ord_axis_label, ord_axis_unit_label = strip.(r9[5:6]) - - # Record 10 - r10 = split(readline(io)) - ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp = parse.(Int, strip.(r10[1:4])) - ord_denom_axis_label, ord_denom_axis_unit_label = strip.(r10[5:6]) - - # Record 11 - r11 = split(readline(io)) - z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp = parse.(Int, strip.(r11[1:4])) - z_axis_label, z_axis_unit_label = strip.(r11[5:6]) - - # Record 12 - - data, dtype = if ord_dtype == 2 - Float32[], Float32 - elseif ord_dtype == 4 - Float64[], Float64 - elseif ord_dtype == 5 - ComplexF32[], Float32 - elseif ord_dtype == 6 - ComplexF64[], Float64 - end - - # for dv in data_values - # entries = split(dv) - # _data = parse.(dtype, strip.(entries)) - # if ord_dtype < 5 - # append!(data, _data) - # elseif ord_dtype == 5 - # append!(data, complex.(_data[1:2:end], _data[2:2:end])) - # elseif ord_dtype == 6 - # append!(data, complex.(_data[1:2:end], _data[2:2:end])) - # end - # end - - while (dv = readline(io)) != " -1" - # Check if line contains spaces (standard format) or fixed-width fields (UFF58 specification) - if occursin(r"\s+", strip(dv)) && !occursin(r"^[\s\-\+\d\.E]+$", dv) - # Format with spaces - use standard split - entries = split(dv) - _data = parse.(dtype, strip.(entries)) - else - # Format without spaces - use fixed-width positions according to UFF58 specification - entries = String[] - line = dv - - if ord_dtype == 2 || ord_dtype == 5 - # Single precision: E13.5 format (13 characters per value) - field_width = 13 - elseif ord_dtype == 4 || ord_dtype == 6 - # Double precision: E20.12 format (20 characters per value) - field_width = 20 - end - - # Extract fixed-width fields - pos = 1 - while pos <= length(line) - if pos + field_width - 1 <= length(line) - field = strip(line[pos:pos+field_width-1]) - if !isempty(field) - push!(entries, field) - end - pos += field_width - else - # Last field potentially shorter - field = strip(line[pos:end]) - if !isempty(field) - push!(entries, field) - end - break - end - end - - _data = parse.(dtype, entries) - end - - if ord_dtype < 5 - append!(data, _data) - elseif ord_dtype == 5 - append!(data, complex.(_data[1:2:end], _data[2:2:end])) - elseif ord_dtype == 6 - append!(data, complex.(_data[1:2:end], _data[2:2:end])) - end - end - - nd = length(data) - if nd != num_pts - if nd > num_pts - data = data[1:num_pts] - end - end - - return Dataset58( - id1, - id2, - id3, - id4, - id5, - func_type, - func_id, - version_num, - load_case_id, - response_entity, - response_node, - response_direction, - reference_entity, - reference_node, - reference_direction, - ord_dtype, - num_pts, - abs_spacing_type, - abs_min, - abs_increment, - zval, - abs_spec_dtype, - abs_len_unit_exp, - abs_force_unit_exp, - abs_temp_unit_exp, - abs_axis_label, - abs_axis_unit_label, - ord_spec_dtype, - ord_len_unit_exp, - ord_force_unit_exp, - ord_temp_unit_exp, - ord_axis_label, - ord_axis_unit_label, - ord_denom_spec_dtype, - ord_denom_len_unit_exp, - ord_denom_force_unit_exp, - ord_denom_temp_unit_exp, - ord_denom_axis_label, - ord_denom_axis_unit_label, - z_spec_dtype, - z_len_unit_exp, - z_force_unit_exp, - z_temp_unit_exp, - z_axis_label, - z_axis_unit_label, - abscissa, - data - ) -end - -""" - write_dataset(dataset::Dataset58) -> Vector{String} - -Write a UFF Dataset 58 (Function Data) to a vector of strings. - -**Input** -- `dataset::Dataset58`: The Dataset58 instance to write. - -**Output** -- `Vector{String}`: A vector of strings representing the lines of the dataset. -""" -function write_dataset(dataset::Dataset58) - lines = String[] - - # Start marker - push!(lines, " -1") - - # Dataset number - push!(lines, " 58") - - # Records 1-5: ID Lines (80A1 format) - push!(lines, dataset.id1) - push!(lines, dataset.id2) - push!(lines, dataset.id3) - push!(lines, dataset.id4) - push!(lines, dataset.id5) - - # Record 6: DOF Identification - # Format: 2(I5,I10),2(1X,10A1,I10,I4) - r6_line = @sprintf("%5d%10d%5d%10d %-10s%10d%4d %-10s%10d%4d", - dataset.func_type, - dataset.func_id, - dataset.ver_num, - dataset.load_case, - dataset.resp_name, - dataset.resp_node, - dataset.resp_dir, - dataset.ref_name, - dataset.ref_node, - dataset.ref_dir) - push!(lines, r6_line) - - # Record 7: Data Form - # Format: 3I10,3E13.5 - r7_line = @sprintf("%10d%10d%10d%13.5E%13.5E%13.5E", - dataset.ord_dtype, - dataset.num_pts, - dataset.abs_spacing_type, - dataset.abs_min, - dataset.abs_increment, - dataset.zval) - push!(lines, r7_line) - - # Record 8: Abscissa Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r8_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.abs_spec_dtype, - dataset.abs_len_unit_exp, - dataset.abs_force_unit_exp, - dataset.abs_temp_unit_exp, - dataset.abs_axis_label, - dataset.abs_axis_unit_label) - push!(lines, r8_line) - - # Record 9: Ordinate Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r9_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.ord_spec_dtype, - dataset.ord_len_unit_exp, - dataset.ord_force_unit_exp, - dataset.ord_temp_unit_exp, - dataset.ord_axis_label, - dataset.ord_axis_unit_label) - push!(lines, r9_line) - - # Record 10: Ordinate Denominator Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r10_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.ord_denom_spec_dtype, - dataset.ord_denom_len_unit_exp, - dataset.ord_denom_force_unit_exp, - dataset.ord_denom_temp_unit_exp, - dataset.ord_denom_axis_label, - dataset.ord_denom_axis_unit_label) - push!(lines, r10_line) - - # Record 11: Z-axis Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r11_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.z_spec_dtype, - dataset.z_len_unit_exp, - dataset.z_force_unit_exp, - dataset.z_temp_unit_exp, - dataset.z_axis_label, - dataset.z_axis_unit_label) - push!(lines, r11_line) - - # Record 12: Data Values - # Format depends on ordinate data type and precision - if dataset.ord_dtype == 2 || dataset.ord_dtype == 4 - # Real data (single or double precision) - if dataset.ord_dtype == 2 - # Real single precision: 6E13.5 - values_per_line = 6 - fmt = "E13.5" - else - # Real double precision: 4E20.12 - values_per_line = 4 - fmt = "E20.12" - end - - # Write data in chunks - for i in 1:values_per_line:length(dataset.data) - end_idx = min(i + values_per_line - 1, length(dataset.data)) - chunk = dataset.data[i:end_idx] - - if dataset.ord_dtype == 2 - line = join([@sprintf(" %12.5E", v) for v in chunk], "") - else - line = join([@sprintf(" %19.12E", v) for v in chunk], "") - end - push!(lines, line) - end - - elseif dataset.ord_dtype == 5 || dataset.ord_dtype == 6 - # Complex data (single or double precision) - if dataset.ord_dtype == 5 - # Complex single precision: 6E13.5 (3 complex values per line) - values_per_line = 3 - else - # Complex double precision: 4E20.12 (2 complex values per line) - values_per_line = 2 - end - - # Write data in chunks (real and imaginary parts interleaved) - for i in 1:values_per_line:length(dataset.data) - end_idx = min(i + values_per_line - 1, length(dataset.data)) - chunk = dataset.data[i:end_idx] - - if dataset.ord_dtype == 5 - # 6E13.5 format - parts = Float64[] - for c in chunk - push!(parts, real(c)) - push!(parts, imag(c)) - end - line = join([@sprintf(" %12.5E", v) for v in parts], "") - else - # 4E20.12 format - parts = Float64[] - for c in chunk - push!(parts, real(c)) - push!(parts, imag(c)) - end - line = join([@sprintf(" %19.12E", v) for v in parts], "") - end - push!(lines, line) - end - end - - # End marker - push!(lines, " -1") - - return lines -end \ No newline at end of file diff --git a/src/datasets/dataset58b.jl b/src/datasets/dataset58b.jl index 7364ba4..1b0a01c 100644 --- a/src/datasets/dataset58b.jl +++ b/src/datasets/dataset58b.jl @@ -95,19 +95,18 @@ The format of this line should remain constant for any other dataset that takes on a binary format in the future. """ function parse_dataset58b(io) - + # this function should be able to read the abscissa for uneven datasets if they are Float32 or Float64. reset(io) func = readline(io) + n, _, type, endian, floating_point_format, num_ascii_lines, binary_bytes, _... = @scanf(func, "%6i%c%6i%6i%12i%12i%6i%6i%12i%12i", + Int, Char, Int, Int, Int, Int, Int, Int, Int, Int) # Need to implement proper error handling - endian = parse(Int, func[8:13]) # Julia only runs on little endian (as far as I am aware) [I6] + type == 'b' || error("Expected UFF58 binary file but type is $type") endian == 1 || println("Only implemented for Little Endian") - floating_point_format = parse(Int, func[14:19]) # Floating Point Format [I6] - floating_point_format == 1 || println("Only implemented for IEEE 754") - num_ascii_lines = parse(Int, func[20:31]) # number of ASCII lines following [I12] - num_ascii_lines == 1 || println("Header not correct") - binary_bytes = parse(Int, func[32:43]) # number of bytes following ASCII lines [I12] - + floating_point_format == 2 || println("Only implemented for IEEE 754") + num_ascii_lines == 11 || println("Header not correct") + id1 = strip(readline(io)) id2 = strip(readline(io)) id3 = strip(readline(io)) @@ -116,60 +115,34 @@ function parse_dataset58b(io) # Record 6 r6 = readline(io) - len_r6 = length(r6) - #=r6 = split(readline(io)) - - func_type = parse(Int, strip(r6[1])) - func_id = parse(Int, strip(r6[2])) - version_num = parse(Int, strip(r6[3])) - load_case_id = parse(Int, strip(r6[4])) - response_entity = strip(r6[5]) - response_node = parse(Int, strip(r6[6])) - response_direction = parse(Int, strip(r6[7])) - reference_entity = strip(r6[8])=# - # This modified for the space in Sample_UFF58b_bin.uff record 6 field 5 - func_type = parse(Int, r6[1:5]) - func_id = parse(Int, r6[6:15]) - version_num = parse(Int, r6[16:20]) - load_case_id = parse(Int, r6[21:30]) - response_entity = r6[32:41] - # @show(r6[32:41]) - response_node = parse(Int, r6[42:51]) - response_direction = parse(Int, r6[52:55]) - reference_entity = r6[57:66] - - if len_r6 > 8 - reference_node = parse(Int, r6[67:76]) - reference_direction = parse(Int, r6[77:80]) - else - reference_node = 0 - reference_direction = 0 - end + n, func_type, func_id, version_num, load_case_id, _, + response_entity, response_node, response_direction, _, + reference_entity, reference_node, reference_direction= + @scanf(r6, "%5i%10i%5i%10i%c%10c%10i%4i%c%10c%10i%4i", Int, Int, Int, Int, Char, String, Int, Int, Char, String, Int, Int) # Record 7 - r7 = split(readline(io)) - ord_dtype, num_pts, abs_spacing_type = parse.(Int, strip.(r7[1:3])) - abs_min, abs_increment, zval = parse.(Float64, strip.(r7[4:6])) + r7 = (readline(io)) + n, ord_dtype, num_pts, abs_spacing_type, abs_min, abs_increment, zval = @scanf(r7, "%10i%10i%10i%13e%13e%13e", Int, Int, Int, Float64, Float64, Float64) # Record 8 - r8 = split(readline(io)) - abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp = parse.(Int, strip.(r8[1:4])) - abs_axis_label, abs_axis_unit_label = strip.(r8[5:6]) + r8 = (readline(io)) + n, abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp, _, abs_axis_label, _, abs_axis_unit_label = + @scanf(r8, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 9 - r9 = split(readline(io)) - ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp = parse.(Int, strip.(r9[1:4])) - ord_axis_label, ord_axis_unit_label = strip.(r9[5:6]) + r9 = (readline(io)) + n, ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp, _, ord_axis_label, _, ord_axis_unit_label = + @scanf(r9, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 10 - r10 = split(readline(io)) - ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp = parse.(Int, strip.(r10[1:4])) - ord_denom_axis_label, ord_denom_axis_unit_label = strip.(r10[5:6]) + r10 = (readline(io)) + n, ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp, _, ord_denom_axis_label, _, ord_denom_axis_unit_label = + @scanf(r9, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 11 - r11 = split(readline(io)) - z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp = parse.(Int, strip.(r11[1:4])) - z_axis_label, z_axis_unit_label = strip.(r11[5:6]) + r11 = (readline(io)) + n, z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp, _, z_axis_label, _, z_axis_unit_label = + @scanf(r9, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 12 _data = read(io, binary_bytes) @@ -267,157 +240,35 @@ function parse_dataset58b(io) ) end -function write_dataset58(dataset::Dataset58) - lines = String[] - - # Start marker - push!(lines, " -1") - - # Dataset number - push!(lines, " 58") - - # Records 1-5: ID Lines (80A1 format) - push!(lines, dataset.id1) - push!(lines, dataset.id2) - push!(lines, dataset.id3) - push!(lines, dataset.id4) - push!(lines, dataset.id5) - - # Record 6: DOF Identification - # Format: 2(I5,I10),2(1X,10A1,I10,I4) - r6_line = @sprintf("%5d%10d%5d%10d %-10s%10d%4d %-10s%10d%4d", - dataset.func_type, - dataset.func_id, - dataset.ver_num, - dataset.load_case, - dataset.resp_name, - dataset.resp_node, - dataset.resp_dir, - dataset.ref_name, - dataset.ref_node, - dataset.ref_dir) - push!(lines, r6_line) - - # Record 7: Data Form - # Format: 3I10,3E13.5 - r7_line = @sprintf("%10d%10d%10d%13.5E%13.5E%13.5E", - dataset.ord_dtype, - dataset.num_pts, - dataset.abs_spacing_type, - dataset.abs_min, - dataset.abs_increment, - dataset.zval) - push!(lines, r7_line) - - # Record 8: Abscissa Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r8_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.abs_spec_dtype, - dataset.abs_len_unit_exp, - dataset.abs_force_unit_exp, - dataset.abs_temp_unit_exp, - dataset.abs_axis_label, - dataset.abs_axis_unit_label) - push!(lines, r8_line) - - # Record 9: Ordinate Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r9_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.ord_spec_dtype, - dataset.ord_len_unit_exp, - dataset.ord_force_unit_exp, - dataset.ord_temp_unit_exp, - dataset.ord_axis_label, - dataset.ord_axis_unit_label) - push!(lines, r9_line) - - # Record 10: Ordinate Denominator Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r10_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.ord_denom_spec_dtype, - dataset.ord_denom_len_unit_exp, - dataset.ord_denom_force_unit_exp, - dataset.ord_denom_temp_unit_exp, - dataset.ord_denom_axis_label, - dataset.ord_denom_axis_unit_label) - push!(lines, r10_line) - - # Record 11: Z-axis Data Characteristics - # Format: I10,3I5,2(1X,20A1) - r11_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", - dataset.z_spec_dtype, - dataset.z_len_unit_exp, - dataset.z_force_unit_exp, - dataset.z_temp_unit_exp, - dataset.z_axis_label, - dataset.z_axis_unit_label) - push!(lines, r11_line) - +function write_dataset58b_data(io, dataset) # Record 12: Data Values # Format depends on ordinate data type and precision - if dataset.ord_dtype == 2 || dataset.ord_dtype == 4 - # Real data (single or double precision) - if dataset.ord_dtype == 2 - # Real single precision: 6E13.5 - values_per_line = 6 - fmt = "E13.5" - else - # Real double precision: 4E20.12 - values_per_line = 4 - fmt = "E20.12" - end - # Write data in chunks - for i in 1:values_per_line:length(dataset.data) - end_idx = min(i + values_per_line - 1, length(dataset.data)) - chunk = dataset.data[i:end_idx] - - if dataset.ord_dtype == 2 - line = join([@sprintf(" %12.5E", v) for v in chunk], "") - else - line = join([@sprintf(" %19.12E", v) for v in chunk], "") - end - push!(lines, line) - end - - elseif dataset.ord_dtype == 5 || dataset.ord_dtype == 6 - # Complex data (single or double precision) - if dataset.ord_dtype == 5 - # Complex single precision: 6E13.5 (3 complex values per line) - values_per_line = 3 - else - # Complex double precision: 4E20.12 (2 complex values per line) - values_per_line = 2 - end - - # Write data in chunks (real and imaginary parts interleaved) - for i in 1:values_per_line:length(dataset.data) - end_idx = min(i + values_per_line - 1, length(dataset.data)) - chunk = dataset.data[i:end_idx] - - if dataset.ord_dtype == 5 - # 6E13.5 format - parts = Float64[] - for c in chunk - push!(parts, real(c)) - push!(parts, imag(c)) - end - line = join([@sprintf(" %12.5E", v) for v in parts], "") - else - # 4E20.12 format - parts = Float64[] - for c in chunk - push!(parts, real(c)) - push!(parts, imag(c)) - end - line = join([@sprintf(" %19.12E", v) for v in parts], "") - end - push!(lines, line) - end + if (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 1 - Real, Single Precision, Even Spacing + write(io, Float32.(dataset.data)) + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 2 - Real, Single Precision, Uneven Spacing + tmp = Float32.(reshape(reduce(vcat, [dataset.abscissa', dataset.data']), :, 1)) + write(io, tmp) + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 3 - Complex, Single Precision, Even Spacing + tmp = Float32.(reshape(reduce(vcat, [real(dataset.data)', imag(dataset.data)']), :, 1)) + write(io, tmp) + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 4 - Complex, Single Precision, Uneven Spacing + tmp = Float32.(reshape(reduce(vcat, [dataset.abscissa', real(dataset.data)', imag(dataset.data)']), :, 1)) + write(io, tmp) + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 5 - Real, Double Precision, Even Spacing + write(io, Float64.(dataset.data)) + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 6 - Real, Double Precision, Uneven Spacing + # Both abscissa and ordinate are Float64 + tmp = Float64.(reshape(reduce(vcat, [dataset.abscissa', dataset.data']), :, 1)) + write(io, tmp) + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 7 - Complex, Double Precision, Even Spacing + tmp = Float64.(reshape(reduce(vcat, [real(dataset.data)', imag(dataset.data)']), :, 1)) + write(io, tmp) + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 8 - Complex, Double Precision, Uneven Spacing + # Both abscissa and ordinate are Float64 + tmp = Float64.(reshape(reduce(vcat, [dataset.abscissa', real(dataset.data)', imag(dataset.data)']), :, 1)) + write(io, tmp) end - # End marker - push!(lines, " -1") - - return lines + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset58common.jl b/src/datasets/dataset58common.jl index 8e5f9ba..529a4b6 100644 --- a/src/datasets/dataset58common.jl +++ b/src/datasets/dataset58common.jl @@ -169,4 +169,149 @@ A struct containing UFF Dataset 58 (Function at nodal dof) data. abscissa = [], data = [] ) = new(:Dataset58, "Function at nodal dof", id1, id2, id3, id4, id5, func_type, func_id, ver_num, load_case, resp_name, resp_node, resp_dir, ref_name, ref_node, ref_dir, ord_dtype, num_pts, abs_spacing_type, abs_min, abs_increment, zval, abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp, abs_axis_label, abs_axis_unit_label, ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp, ord_axis_label, ord_axis_unit_label, ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp, ord_denom_axis_label, ord_denom_axis_unit_label, z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp, z_axis_label, z_axis_unit_label, abscissa, data) +end + + +""" + write_dataset(dataset::Dataset58) -> Vector{String} + +Write a UFF Dataset 58 (Function Data) to a vector of strings. + +**Input** +- `dataset::Dataset58`: The Dataset58 instance to write. + +**Output** +- `Vector{String}`: A vector of strings representing the lines of the dataset. +""" +function write_dataset(io, dataset::Dataset58) + # the abcissa for uneven double precision ASCII datasets are Float32. + # the abscissa for uneven double precision binary datasets are Float64 + # Start marker + println(io, " -1") + + n = length(dataset.data) + binary_bytes = + if (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 1 - Real, Single Precision, Even Spacing + n*32 + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 2 - Real, Single Precision, Uneven Spacing + 2n*32 + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 3 - Complex, Single Precision, Even Spacing + 2n*32 + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 4 - Complex, Single Precision, Uneven Spacing + 3n*32 + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 5 - Real, Double Precision, Even Spacing + n*64 + elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 6 - Real, Double Precision, Uneven Spacing + 2n*64 # both abscissa and ordinate written in Float64 + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 7 - Complex, Double Precision, Even Spacing + 2n*64 + elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 8 - Complex, Double Precision, Uneven Spacing + 3n*64 # both abscissa and ordinate written in Float64 + end + + # Dataset number + ds = if binary_write + @sprintf("%6i%c%6i%6i%12i%12i%6i%6i%12i%12i", + 58, # 58 + 'b', # lowercase b + 1, # little endian + 2, # IEEE 754 + 11, # number of ASCII lines following + binary_bytes, # number of bytes following ASCII lines + 0, 0, 0, 0 + ) + else + " 58" + end + println(io, ds) + + # Records 1-5: ID Lines (80A1 format) + println(io, dataset.id1) + println(io, dataset.id2) + println(io, dataset.id3) + println(io, dataset.id4) + println(io, dataset.id5) + + # Record 6: DOF Identification + # Format: 2(I5,I10),2(1X,10A1,I10,I4) + r6_line = @sprintf("%5d%10d%5d%10d %-10s%10d%4d %-10s%10d%4d", + dataset.func_type, + dataset.func_id, + dataset.ver_num, + dataset.load_case, + dataset.resp_name, + dataset.resp_node, + dataset.resp_dir, + dataset.ref_name, + dataset.ref_node, + dataset.ref_dir) + println(io, r6_line) + + # Record 7: Data Form + # Format: 3I10,3E13.5 + r7_line = @sprintf("%10d%10d%10d%13.5E%13.5E%13.5E", + dataset.ord_dtype, + dataset.num_pts, + dataset.abs_spacing_type, + dataset.abs_min, + dataset.abs_increment, + dataset.zval) + println(io, r7_line) + + # Record 8: Abscissa Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r8_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.abs_spec_dtype, + dataset.abs_len_unit_exp, + dataset.abs_force_unit_exp, + dataset.abs_temp_unit_exp, + dataset.abs_axis_label, + dataset.abs_axis_unit_label) + println(io, r8_line) + + # Record 9: Ordinate Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r9_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.ord_spec_dtype, + dataset.ord_len_unit_exp, + dataset.ord_force_unit_exp, + dataset.ord_temp_unit_exp, + dataset.ord_axis_label, + dataset.ord_axis_unit_label) + println(io, r9_line) + + # Record 10: Ordinate Denominator Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r10_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.ord_denom_spec_dtype, + dataset.ord_denom_len_unit_exp, + dataset.ord_denom_force_unit_exp, + dataset.ord_denom_temp_unit_exp, + dataset.ord_denom_axis_label, + dataset.ord_denom_axis_unit_label) + println(io, r10_line) + + # Record 11: Z-axis Data Characteristics + # Format: I10,3I5,2(1X,20A1) + r11_line = @sprintf("%10d%5d%5d%5d %-20s %-20s", + dataset.z_spec_dtype, + dataset.z_len_unit_exp, + dataset.z_force_unit_exp, + dataset.z_temp_unit_exp, + dataset.z_axis_label, + dataset.z_axis_unit_label) + println(io, r11_line) + + # Record 12: Data Values + # Call binary or ASCII routine + if binary_write + write_dataset58b_data(io, dataset) + else + write_dataset58_data(io, dataset) + end + + # End marker + println(io, " -1") + + return nothing end \ No newline at end of file diff --git a/src/datasets/dataset82.jl b/src/datasets/dataset82.jl index 27d808a..a85c23c 100644 --- a/src/datasets/dataset82.jl +++ b/src/datasets/dataset82.jl @@ -61,10 +61,14 @@ Universal Dataset Number: 82 6) Repeat Datasets for each Trace_Line """ function parse_dataset82(io) - line_number, num_nodes, color = parse.(Int, split(readline(io))) + # Record 1 + r1 = readline(io) + n, line_number, num_nodes, color = @scanf(r1, "%10i%10i%10i", Int, Int, Int) + + # Record 2 id_line = strip(readline(io)) - lblock = block[4:end] + # Record 3 line_nodes = Int[] while (line = readline(io)) != " -1" append!(line_nodes, parse.(Int, split(line))) @@ -90,12 +94,12 @@ Write a UFF Dataset 82 (Tracelines) to a vector of strings. **Output** - `Vector{String}`: Vector of formatted strings representing the UFF file content """ -function write_dataset(dataset::Dataset82) +function write_dataset(io, dataset::Dataset82) lines = String[] # Write header - push!(lines, " -1") - push!(lines, " 82") + println(io, " -1") + println(io, " 82") # Write Record 1: FORMAT(3I10) # Field 1: trace line number @@ -106,12 +110,12 @@ function write_dataset(dataset::Dataset82) dataset.num_nodes, dataset.color ) - push!(lines, line1) + println(io, line1) # Write Record 2: FORMAT(80A1) # Identification line (max 80 characters) id_line = rpad(dataset.id_line[1:min(length(dataset.id_line), 80)], 0) - push!(lines, id_line) + println(io, id_line) # Write Record 3: FORMAT(8I10) # Node numbers, 8 per line @@ -122,11 +126,11 @@ function write_dataset(dataset::Dataset82) # Format each node as I10 (10 characters, right-aligned) line_parts = [@sprintf("%10d", node) for node in nodes_chunk] - push!(lines, join(line_parts, "")) + println(io, join(line_parts, "")) end # Write footer - push!(lines, " -1") + println(io, " -1") - return lines + return nothing end \ No newline at end of file diff --git a/src/read_write_uff.jl b/src/read_write_uff.jl index b5031aa..9eb7411 100644 --- a/src/read_write_uff.jl +++ b/src/read_write_uff.jl @@ -1,3 +1,5 @@ +global binary_write::Bool + """ readuff(filename::String) -> Vector{UFFDataset} @@ -54,19 +56,21 @@ Writes a vector of UFFDataset objects to a UFF file. **Input** - `filename::String`: The path to the UFF file to be written. -- `data::Vector{UFFDataset}`: A vector containing the UFF datasets to be +- `datasets::Vector{UFFDataset}`: A vector containing the UFF datasets to be written. """ -function writeuff(filename::String, data) +function writeuff(filename::String, datasets; binary=true) + global binary_write = binary open(filename, "w") do io - for dataset in data + for dataset in datasets @show(dataset, typeof(dataset)) - lines = write_dataset(dataset) + #lines = + write_dataset(io, dataset) - # Write the formatted lines to the file + #= Write the formatted lines to the file for line in lines println(io, line) - end + end=# end end end diff --git a/test/runtests.jl b/test/runtests.jl index f6484e3..ff32de6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,6 +13,7 @@ writepath = "written_datasets" #@testset "dataset15" begin filenames = readdir("datasets") +filenames = [filenames[1:8]; filenames[14:end]] # exclude the 2000 series filesets for now # dataset = nothing for (i, filename) in enumerate(filenames) println(i, " ", filename) From 04d1e149c51b3735590fe114be072edb2369589a Mon Sep 17 00:00:00 2001 From: jakezw Date: Wed, 19 Nov 2025 21:21:22 -0500 Subject: [PATCH 4/4] Add tests for ASCII to binary and back, minor bug fixes, some more conversion to scanf --- .gitignore | 1 + src/datasets/dataset58.jl | 65 ++++++++++----------------------- src/datasets/dataset58common.jl | 16 ++++---- src/read_write_uff.jl | 8 ++-- test/runtests.jl | 17 ++++++++- 5 files changed, 49 insertions(+), 58 deletions(-) diff --git a/.gitignore b/.gitignore index 45e0c3c..4e26d60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /Manifest*.toml /test/datasets/face1.unv /test/datasets/short.unv +/test/datasets/written_datasets /docs/_site /docs/_freeze .DS_Store diff --git a/src/datasets/dataset58.jl b/src/datasets/dataset58.jl index a3699c8..307f235 100644 --- a/src/datasets/dataset58.jl +++ b/src/datasets/dataset58.jl @@ -713,62 +713,37 @@ function parse_dataset58(io) id3 = strip(readline(io)) id4 = strip(readline(io)) id5 = strip(readline(io)) - # @show(id1, id2, id3, id4, id5) # Record 6 r6 = readline(io) - len_r6 = length(r6) - - #=func_type = parse(Int, strip(r6[1])) - func_id = parse(Int, strip(r6[2])) - version_num = parse(Int, strip(r6[3])) - load_case_id = parse(Int, strip(r6[4])) - response_entity = strip(r6[5]) - response_node = parse(Int, strip(r6[6])) - response_direction = parse(Int, strip(r6[7])) - reference_entity = strip(r6[8])=# - # This modified for the space in Sample_UFF58b_bin.uff record 6 field 5 - func_type = parse(Int, r6[1:5]) - func_id = parse(Int, r6[6:15]) - version_num = parse(Int, r6[16:20]) - load_case_id = parse(Int, r6[21:30]) - response_entity = r6[32:41] - response_node = parse(Int, r6[42:51]) - response_direction = parse(Int, r6[52:55]) - reference_entity = r6[57:66] - - if len_r6 > 8 - reference_node = parse(Int, r6[67:76]) - reference_direction = parse(Int, r6[77:80]) - else - reference_node = 0 - reference_direction = 0 - end + n, func_type, func_id, version_num, load_case_id, _, + response_entity, response_node, response_direction, _, + reference_entity, reference_node, reference_direction= + @scanf(r6, "%5i%10i%5i%10i%c%10c%10i%4i%c%10c%10i%4i", Int, Int, Int, Int, Char, String, Int, Int, Char, String, Int, Int) # Record 7 - r7 = split(readline(io)) - ord_dtype, num_pts, abs_spacing_type = parse.(Int, strip.(r7[1:3])) - abs_min, abs_increment, zval = parse.(Float64, strip.(r7[4:6])) + r7 = (readline(io)) + n, ord_dtype, num_pts, abs_spacing_type, abs_min, abs_increment, zval = @scanf(r7, "%10i%10i%10i%13e%13e%13e", Int, Int, Int, Float64, Float64, Float64) # Record 8 - r8 = split(readline(io)) - abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp = parse.(Int, strip.(r8[1:4])) - abs_axis_label, abs_axis_unit_label = strip.(r8[5:6]) + r8 = (readline(io)) + n, abs_spec_dtype, abs_len_unit_exp, abs_force_unit_exp, abs_temp_unit_exp, _, abs_axis_label, _, abs_axis_unit_label = + @scanf(r8, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 9 - r9 = split(readline(io)) - ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp = parse.(Int, strip.(r9[1:4])) - ord_axis_label, ord_axis_unit_label = strip.(r9[5:6]) + r9 = (readline(io)) + n, ord_spec_dtype, ord_len_unit_exp, ord_force_unit_exp, ord_temp_unit_exp, _, ord_axis_label, _, ord_axis_unit_label = + @scanf(r9, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 10 - r10 = split(readline(io)) - ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp = parse.(Int, strip.(r10[1:4])) - ord_denom_axis_label, ord_denom_axis_unit_label = strip.(r10[5:6]) + r10 = (readline(io)) + n, ord_denom_spec_dtype, ord_denom_len_unit_exp, ord_denom_force_unit_exp, ord_denom_temp_unit_exp, _, ord_denom_axis_label, _, ord_denom_axis_unit_label = + @scanf(r9, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 11 - r11 = split(readline(io)) - z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp = parse.(Int, strip.(r11[1:4])) - z_axis_label, z_axis_unit_label = strip.(r11[5:6]) + r11 = (readline(io)) + n, z_spec_dtype, z_len_unit_exp, z_force_unit_exp, z_temp_unit_exp, _, z_axis_label, _, z_axis_unit_label = + @scanf(r9, "%10i%5i%5i%5i%c%20c%c%20c", Int, Int, Int, Int, Char, String, Char, String) # Record 12 if (ord_dtype == 2 && abs_spacing_type == 1) # Case 1 - Real, Single Precision, Even Spacing 6E13.5 @@ -777,12 +752,12 @@ function parse_dataset58(io) fw = 13 # field width for i in 1:n:num_pts r12 = readline(io) - @show(i, r12) + #@show(i, r12) for j in 1:n i + j - 1 > num_pts && break # break if num_pts exceeded _data[i+j-1] = parse(Float32, r12[(j-1)*fw+1:j*fw]) end - @show(typeof(_data), size(_data)) + #@show(typeof(_data), size(_data)) end abscissa = Float32[] data = _data diff --git a/src/datasets/dataset58common.jl b/src/datasets/dataset58common.jl index 529a4b6..8d3611c 100644 --- a/src/datasets/dataset58common.jl +++ b/src/datasets/dataset58common.jl @@ -192,21 +192,21 @@ function write_dataset(io, dataset::Dataset58) n = length(dataset.data) binary_bytes = if (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 1 - Real, Single Precision, Even Spacing - n*32 + n*4 elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 2 - Real, Single Precision, Uneven Spacing - 2n*32 + 2n*4 elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 3 - Complex, Single Precision, Even Spacing - 2n*32 + 2n*4 elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 4 - Complex, Single Precision, Uneven Spacing - 3n*32 + 3n*4 elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 1) # Case 5 - Real, Double Precision, Even Spacing - n*64 + n*8 elseif (dataset.ord_dtype == 2 && dataset.abs_spacing_type == 0) # Case 6 - Real, Double Precision, Uneven Spacing - 2n*64 # both abscissa and ordinate written in Float64 + 2n*8 # both abscissa and ordinate written in Float64 elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 1) # Case 7 - Complex, Double Precision, Even Spacing - 2n*64 + 2n*8 elseif (dataset.ord_dtype == 5 && dataset.abs_spacing_type == 0) # Case 8 - Complex, Double Precision, Uneven Spacing - 3n*64 # both abscissa and ordinate written in Float64 + 3n*8 # both abscissa and ordinate written in Float64 end # Dataset number diff --git a/src/read_write_uff.jl b/src/read_write_uff.jl index 9eb7411..3720e39 100644 --- a/src/read_write_uff.jl +++ b/src/read_write_uff.jl @@ -24,12 +24,12 @@ function readuff(filename::String) # Determine dataset type from the following line & mark the position mark(io) line = readline(io) - @show(line) + #@show(line) dtype = length(line) > 6 ? strip(line[1:7]) : strip(line[1:6]) - @show(dtype) + #@show(dtype) if any(dtype .== supported_datasets()) - # Parse the block based on its dataset type - # https://stackoverflow.com/questions/34016768/julia-invoke-a-function-by-a-given-string/34023458#34023458 + # Parse the block based on its dataset type + # https://stackoverflow.com/questions/34016768/julia-invoke-a-function-by-a-given-string/34023458#34023458 parse_function = getfield(UFFFiles, Symbol("parse_dataset", dtype)) @show(parse_function) datatmp = parse_function(io) diff --git a/test/runtests.jl b/test/runtests.jl index ff32de6..fbbda78 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -26,4 +26,19 @@ for (i, filename) in enumerate(filenames) # filecmp(joinpath(writepath, filename), "written_datasets/dataset15_w.unv") # dataset_w = readuff("datasets/dataset15.unv") # dataset == dataset_w -end \ No newline at end of file +end + +# read in an ASCII file write out as binary and read in and write out as ASCII +# test that the data is good +readname = "uff58_nospacing.uff" +writename = splitext(readname)[1] * ".ufb" +writename1 = splitext(readname)[1] * ".unv" +writename2 = splitext(readname)[1] * "_dp.ufb" +ds = readuff(joinpath(readpath, readname)) +writeuff(joinpath(writepath, writename), ds; binary=true) +ds1 = readuff(joinpath(writepath, writename)) +writeuff(joinpath(writepath, writename1), ds1; binary=false) +ds2 = readuff(joinpath(writepath, writename1)) +ds[1].ord_dtype = 4 +writeuff(joinpath(writepath, writename), ds; binary=true) +ds[1].data .≈ ds1[1].data .≈ ds2[1].data