//--------------------------------------------------------------andiLinkDef.h // LinkDef.h for including netCDF and AIA MS in ROOT #pragma link off all globals; #pragma link off all classes; #pragma link off all functions; #pragma link C++ NcFile; #pragma link C++ NcVar; #pragma link C++ NcAtt; #pragma link C++ NcDim; #pragma link C++ NcTypedComponent; #pragma link C++ NcError; #pragma link C++ NcValues; /* -*-C-*- ******************************************************************************* * * File: ms10io.h * * Description: Public-domain implementation of the AIA MS Version 1.0.1 Data * Interchange Specification, Categories 1 and 2 data elements. * This file is a header file for the netCDF file I/O functions * of the MS specification. * Author: David Stranz * * Created: Thu Feb 20 15:00:16 1992 * Modified: Wed Jul 14 11:50:38 1993 (David Stranz) dstranz@lfrg1 * Language: C * Package: N/A * Status: Public Domain (Distribute with Copyright Notice) * * (C) Copyright 1992, 1993, Analytical Instrument Association * All rights reserved. * ******************************************************************************* */ #ifndef MS10_IO_INCLUDED #define MS10_IO_INCLUDED 1 /* THIS FILE SHOULD BE INCLUDED *ONLY* BY FILE ms10io.c !! */ /* ******************************************************************************** * * Global, static variables * ******************************************************************************** */ static char * ms_completeness_att = "C1+C2"; static char * ms_template_att = "1.0.1"; static char * ms_netcdf_att = "2.3.2"; static char * ms_languages_att = "English"; /* This definition is for those compilers which do not supply one (usually supplied in stddef.h, but it may be absent in non-ANSI compilers).*/ #ifndef offsetof #define offsetof(s_name,m_name) (long)(&(((s_name*)0))->m_name) #endif /* ******************************************************************************** * * MS_Dimensions data structure: This keeps track of all the dimension id * numbers used when reading or writing netCDF files. * ******************************************************************************** */ typedef struct { int id; /* dimension id */ long size; /* dimension size */ } ms_dim; typedef struct { ms_dim _2_byte_dim; ms_dim _4_byte_dim; ms_dim _8_byte_dim; ms_dim _16_byte_dim; ms_dim _32_byte_dim; ms_dim _64_byte_dim; ms_dim _128_byte_dim; ms_dim _255_byte_dim; ms_dim range_dim; ms_dim scan_number_dim; ms_dim point_number_dim; ms_dim instrument_number_dim; ms_dim group_number_dim; ms_dim group_max_masses_dim; ms_dim error_number_dim; } MS_Dimensions; /* ******************************************************************************** * * MS_Variables data structure: Keeps track of the netCDF variable ids. * The data structure member names might seem a bit long, but they are what * the "ncgen" utility would produce from the CDL file. * ******************************************************************************** */ typedef struct { int error_log_id; int instrument_name_id; int instrument_id_id; int instrument_mfr_id; int instrument_model_id; int instrument_serial_no_id; int instrument_sw_version_id; int instrument_fw_version_id; int instrument_os_version_id; int instrument_app_version_id; int instrument_comments_id; int scan_index_id; int point_count_id; int flag_count_id; int mass_values_id; int time_values_id; int intensity_values_id; int a_d_sampling_rate_id; int a_d_coaddition_factor_id; int scan_acquisition_time_id; int scan_duration_id; int inter_scan_time_id; int resolution_id; int actual_scan_id; int total_intensity_id; int mass_range_min_id; int mass_range_max_id; int time_range_min_id; int time_range_max_id; int group_mass_count_id; int group_start_id; int group_masses_id; int group_samplings_id; int group_delays_id; int entry_name_id; int entry_id_id; int entry_number_id; int source_data_file_id; int CAS_name_id; int CAS_number_id; int other_name_0_id; int other_name_1_id; int other_name_2_id; int other_name_3_id; int chemical_formula_id; int wiswesser_id; int smiles_id; int molfile_id; int other_structure_id; int retention_index_id; int retention_type_id; int absolute_retention_id; int relative_retention_id; int retention_reference_name_id; int retention_reference_CAS_id; int melting_point_id; int boiling_point_id; int chemical_mass_id; int nominal_mass_id; int accurate_mass_id; int entry_other_information_id; } MS_Variables; /* ******************************************************************************** * * Client data structure: each time an AIA MS file is opened, a new "client" * is registered for that file, associating the netCDF file ID with dimension, * variable, data format, and other information. * * The array, ms_clients, and counter (ms_client_count) keep track of * client information and are dynamically adjusted. The function * ms_associate_id() adds a new client, and ms_dissociate_id() removes it. * ******************************************************************************** */ typedef struct { int cdfid; ms_admin_expt_t expt_type; ms_data_format_t mass_type; ms_data_format_t time_type; ms_data_format_t inty_type; int has_masses; int has_times; MS_Dimensions dims; MS_Variables vars; long total_count; } MS_Client_Data; static MS_Client_Data * * ms_clients = NULL; static int ms_client_count = 0; /* ******************************************************************************** * * Datatype to format conversion table * ******************************************************************************** */ static struct { nc_type cdf_type; ms_data_format_t ms_fmt; } ms_types[] = { { NC_SHORT, data_short }, { NC_LONG, data_long }, { NC_FLOAT, data_float }, { NC_DOUBLE, data_double } }; static int nTypes = 4; /* ******************************************************************************** * * Data structures * * Most netCDF dimension, variable, and attribute definitions are presented * as arrays of data, defined by the three structures below. This affords more * easily maintainable code and avoids lengthy subroutines with explicit * calls to create or retrieve each element. * * There are a few exceptions to this table-driven algorithm; these are clearly * identified in the code. * ******************************************************************************** */ typedef struct { unsigned long offset; /* offset of dimension id */ char * name; /* dimension name */ long size; /* size of dimension */ } MS_Dimension_Data; typedef struct { unsigned long offset; /* offset of variable id */ char * name; /* name of variable */ nc_type datatype; /* type of variable */ long data_offset; /* offset of data element */ int ndim; /* number of dimensions (0 - 2) */ long dim[2]; /* dimensions ids */ } MS_Variable_Data; typedef struct { unsigned long offset; /* offset of data field */ char * name; /* field name */ long id; /* variable id (or NC_GLOBAL) */ nc_type datatype; /* variable data type */ int mandatory; /* non-zero if a required field */ int enumerated; /* non-zero if an enum type */ int default_value; /* for enum types only */ } MS_Attribute_Data; /* ******************************************************************************** * * MS_Dimension_Data arrays * ******************************************************************************** */ /* Dimensions with implementation-defined sizes are included in this table. Those which are data-dependent (e.g. number of scans) are explicitly created in code. */ static MS_Dimension_Data ms_dimensions[] = { { offsetof( MS_Dimensions, _2_byte_dim ), "_2_byte_string", 2L }, { offsetof( MS_Dimensions, _4_byte_dim ), "_4_byte_string", 4L }, { offsetof( MS_Dimensions, _8_byte_dim ), "_8_byte_string", 8L }, { offsetof( MS_Dimensions, _16_byte_dim ), "_16_byte_string", 16L }, { offsetof( MS_Dimensions, _32_byte_dim ), "_32_byte_string", 32L }, { offsetof( MS_Dimensions, _64_byte_dim ), "_64_byte_string", 64L }, { offsetof( MS_Dimensions, _128_byte_dim ), "_128_byte_string", 128L }, { offsetof( MS_Dimensions, _255_byte_dim ), "_255_byte_string", 255L }, { offsetof( MS_Dimensions, range_dim ), "range", 2L }, { offsetof( MS_Dimensions, point_number_dim ), "point_number", NC_UNLIMITED }, { offsetof( MS_Dimensions, error_number_dim ), "error_number", 1L } }; static int nDims = (sizeof( ms_dimensions ) / sizeof( MS_Dimension_Data )); /* ******************************************************************************** * * MS Variable data arrays * ******************************************************************************** */ /* Error log */ static MS_Variable_Data error_variables[] = { { offsetof( MS_Variables, error_log_id ), "error_log", NC_CHAR, (long)offsetof( MS_Admin_Data, error_log ), 2, { (long)offsetof( MS_Dimensions, error_number_dim ), (long)offsetof( MS_Dimensions, _64_byte_dim ) }} }; static int nError = sizeof( error_variables ) / sizeof( MS_Variable_Data ); /* Raw data per-scan variables */ static MS_Variable_Data raw_variables[] = { { offsetof( MS_Variables, a_d_sampling_rate_id ), "a_d_sampling_rate", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, a_d_rate ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, a_d_coaddition_factor_id ), "a_d_coaddition_factor", NC_SHORT, (long)offsetof( MS_Raw_Per_Scan, a_d_coadditions ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, scan_acquisition_time_id ), "scan_acquisition_time", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, scan_acq_time ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, scan_duration_id ), "scan_duration", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, scan_duration ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, inter_scan_time_id ), "inter_scan_time", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, inter_scan_time ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, resolution_id ), "resolution", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, resolution ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, actual_scan_id ), "actual_scan_number", NC_LONG, (long)offsetof( MS_Raw_Per_Scan, actual_scan_no ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, total_intensity_id ), "total_intensity", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, total_intensity ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, mass_range_min_id ), "mass_range_min", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, mass_range_min ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, mass_range_max_id ), "mass_range_max", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, mass_range_max ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, time_range_min_id ), "time_range_min", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, time_range_min ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, time_range_max_id ), "time_range_max", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Scan, time_range_max ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } } }; static int nRawP = sizeof( raw_variables ) / sizeof( MS_Variable_Data ); /* Raw data per scan group variables */ static MS_Variable_Data group_variables[] = { { offsetof( MS_Variables, group_mass_count_id ), "group_mass_count", NC_LONG, (long)offsetof( MS_Raw_Per_Group, mass_count ), 1, { (long)offsetof( MS_Dimensions, group_number_dim ), -1 } }, { offsetof( MS_Variables, group_start_id ), "group_starting_scan", NC_LONG, (long)offsetof( MS_Raw_Per_Group, starting_scan ), 1, { (long)offsetof( MS_Dimensions, group_number_dim ), -1 } }, { offsetof( MS_Variables, group_masses_id ), "group_masses", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Group, masses ), 2, { (long)offsetof( MS_Dimensions, group_number_dim ), (long)offsetof( MS_Dimensions, group_max_masses_dim ) } }, { offsetof( MS_Variables, group_samplings_id ), "group_sampling_times", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Group, sampling_times ), 2, { (long)offsetof( MS_Dimensions, group_number_dim ), (long)offsetof( MS_Dimensions, group_max_masses_dim ) } }, { offsetof( MS_Variables, group_delays_id ), "group_delay_times", NC_DOUBLE, (long)offsetof( MS_Raw_Per_Group, delay_times ), 2, { (long)offsetof( MS_Dimensions, group_number_dim ), (long)offsetof( MS_Dimensions, group_max_masses_dim ) } } }; static int nGroupP = sizeof( group_variables ) / sizeof( MS_Variable_Data ); /* INSTRUMENT-ID variables */ static MS_Variable_Data instrument_variables[] = { { offsetof( MS_Variables, instrument_name_id ), "instrument_name", NC_CHAR, (long)offsetof( MS_Instrument_Data, name ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_id_id ), "instrument_id", NC_CHAR, (long)offsetof( MS_Instrument_Data, id ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_mfr_id ), "instrument_mfr", NC_CHAR, (long)offsetof( MS_Instrument_Data, manufacturer ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_model_id ), "instrument_model", NC_CHAR, (long)offsetof( MS_Instrument_Data, model_number ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_serial_no_id ), "instrument_serial_no", NC_CHAR, (long)offsetof( MS_Instrument_Data, serial_number ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_sw_version_id ), "instrument_sw_version", NC_CHAR, (long)offsetof( MS_Instrument_Data, software_version ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_fw_version_id ), "instrument_fw_version", NC_CHAR, (long)offsetof( MS_Instrument_Data, firmware_version ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_os_version_id ), "instrument_os_version", NC_CHAR, (long)offsetof( MS_Instrument_Data, operating_system ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_app_version_id ), "instrument_app_version", NC_CHAR, (long)offsetof( MS_Instrument_Data, application_software ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, instrument_comments_id ), "instrument_comments", NC_CHAR, (long)offsetof( MS_Instrument_Data, comments ), 2, { (long)offsetof( MS_Dimensions, instrument_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } } }; static int nInst = sizeof( instrument_variables ) / sizeof( MS_Variable_Data ); /* LIBRARY DATA PER-SCAN variables */ static MS_Variable_Data library_variables[] = { { offsetof( MS_Variables, entry_name_id ), "entry_name", NC_CHAR, (long)offsetof( MS_Raw_Library, entry_name ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } }, { offsetof( MS_Variables, entry_id_id ), "entry_id", NC_CHAR, (long)offsetof( MS_Raw_Library, entry_id ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, entry_number_id ), "entry_number", NC_LONG, (long)offsetof( MS_Raw_Library, entry_number ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, source_data_file_id ), "source_data_file_reference", NC_CHAR, (long)offsetof( MS_Raw_Library, source_data_file_reference ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, CAS_name_id ), "CAS_name", NC_CHAR, (long)offsetof( MS_Raw_Library, cas_name ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } }, { offsetof( MS_Variables, CAS_number_id ), "CAS_number", NC_LONG, (long)offsetof( MS_Raw_Library, cas_number ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, other_name_0_id ), "other_name_0", NC_CHAR, (long)offsetof( MS_Raw_Library, other_name_0 ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } }, { offsetof( MS_Variables, other_name_1_id ), "other_name_1", NC_CHAR, (long)offsetof( MS_Raw_Library, other_name_1 ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } }, { offsetof( MS_Variables, other_name_2_id ), "other_name_2", NC_CHAR, (long)offsetof( MS_Raw_Library, other_name_2 ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } }, { offsetof( MS_Variables, other_name_3_id ), "other_name_3", NC_CHAR, (long)offsetof( MS_Raw_Library, other_name_3 ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } }, { offsetof( MS_Variables, chemical_formula_id ), "chemical_formula", NC_CHAR, (long)offsetof( MS_Raw_Library, formula ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _64_byte_dim ) } }, { offsetof( MS_Variables, smiles_id ), "smiles", NC_CHAR, (long)offsetof( MS_Raw_Library, smiles ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } }, { offsetof( MS_Variables, wiswesser_id ), "wiswesser", NC_CHAR, (long)offsetof( MS_Raw_Library, wiswesser ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _128_byte_dim ) } }, { offsetof( MS_Variables, molfile_id ), "molfile_reference", NC_CHAR, (long)offsetof( MS_Raw_Library, molfile_reference ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, other_structure_id ), "other_structure", NC_CHAR, (long)offsetof( MS_Raw_Library, other_structure ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _128_byte_dim ) } }, { offsetof( MS_Variables, retention_index_id ), "retention_index", NC_DOUBLE, (long)offsetof( MS_Raw_Library, retention_index ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, retention_type_id ), "retention_type", NC_CHAR, (long)offsetof( MS_Raw_Library, retention_type ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _32_byte_dim ) } }, { offsetof( MS_Variables, relative_retention_id ), "relative_retention", NC_DOUBLE, (long)offsetof( MS_Raw_Library, relative_retention ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, absolute_retention_id ), "absolute_retention", NC_DOUBLE, (long)offsetof( MS_Raw_Library, absolute_retention ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, retention_reference_name_id ), "retention_reference_name", NC_CHAR, (long)offsetof( MS_Raw_Library, retention_reference ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _128_byte_dim ) } }, { offsetof( MS_Variables, retention_reference_CAS_id ), "retention_reference_CAS", NC_LONG, (long)offsetof( MS_Raw_Library, retention_cas ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, melting_point_id ), "melting_point", NC_FLOAT, (long)offsetof( MS_Raw_Library, mp ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, boiling_point_id ), "boiling_point", NC_FLOAT, (long)offsetof( MS_Raw_Library, bp ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, chemical_mass_id ), "chemical_mass", NC_DOUBLE, (long)offsetof( MS_Raw_Library, chemical_mass ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, nominal_mass_id ), "nominal_mass", NC_LONG, (long)offsetof( MS_Raw_Library, nominal_mass ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, accurate_mass_id ), "accurate_mass", NC_DOUBLE, (long)offsetof( MS_Raw_Library, accurate_mass ), 1, { (long)offsetof( MS_Dimensions, scan_number_dim ), -1 } }, { offsetof( MS_Variables, entry_other_information_id ), "entry_other_information", NC_CHAR, (long)offsetof( MS_Raw_Library, other_info ), 2, { (long)offsetof( MS_Dimensions, scan_number_dim ), (long)offsetof( MS_Dimensions, _255_byte_dim ) } } }; static int nLib = sizeof( library_variables ) / sizeof( MS_Variable_Data ); /* ******************************************************************************** * * MS Attribute data arrays * ******************************************************************************** */ /* Attribute data array for ADMINISTRATIVE INFORMATION attributes */ static MS_Attribute_Data admin_attributes[] = { { offsetof( MS_Admin_Data, dataset_completeness ), "dataset_completeness", NC_GLOBAL, NC_CHAR, 1, 0, 0 }, { offsetof( MS_Admin_Data, ms_template_revision ), "ms_template_revision", NC_GLOBAL, NC_CHAR, 1, 0, 0 }, { offsetof( MS_Admin_Data, netcdf_revision), "netcdf_revision", NC_GLOBAL, NC_CHAR, 1, 0, 0 }, { offsetof( MS_Admin_Data, languages ), "languages", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, comments ), "administrative_comments", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, dataset_origin ), "dataset_origin", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, dataset_owner ), "dataset_owner", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, netcdf_date_time ), "netcdf_file_date_time_stamp", NC_GLOBAL, NC_CHAR, 1, 0, 0 }, { offsetof( MS_Admin_Data, experiment_title ), "experiment_title", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, experiment_date_time ), "experiment_date_time_stamp", NC_GLOBAL, NC_CHAR, 1, 0, 0 }, { offsetof( MS_Admin_Data, experiment_x_ref_0 ), "experiment_x_ref_0", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, experiment_x_ref_1 ), "experiment_x_ref_1", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, experiment_x_ref_2 ), "experiment_x_ref_2", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, experiment_x_ref_3 ), "experiment_x_ref_3", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, operator_name ), "operator_name", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, pre_expt_program_name ), "pre_experiment_program_name", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, post_expt_program_name ), "post_experiment_program_name", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, source_file_reference ), "source_file_reference", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, source_file_format ), "source_file_format", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, source_file_date_time ), "source_file_date_time_stamp", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, external_file_ref_0 ), "external_file_ref_0", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, external_file_ref_1 ), "external_file_ref_1", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, external_file_ref_2 ), "external_file_ref_2", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, external_file_ref_3 ), "external_file_ref_3", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, calibration_history_0 ), "calibration_history_0", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, calibration_history_1 ), "calibration_history_1", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, calibration_history_2 ), "calibration_history_2", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, calibration_history_3 ), "calibration_history_3", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Admin_Data, experiment_type ), "experiment_type", NC_GLOBAL, NC_CHAR, 0, 1, (int)expt_centroid }, { offsetof( MS_Admin_Data, number_times_processed ), "number_of_times_processed", NC_GLOBAL, NC_LONG, 0, 0, 0 }, { offsetof( MS_Admin_Data, number_times_calibrated ), "number_of_times_calibrated", NC_GLOBAL, NC_LONG, 0, 0, 0 } }; static int nAdminA = sizeof( admin_attributes ) / sizeof( MS_Attribute_Data ); /* Attribute data array for SAMPLE DESCRIPTION attributes */ static MS_Attribute_Data sample_attributes[] = { { offsetof( MS_Sample_Data, internal_id ), "sample_internal_id", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, external_id ), "sample_external_id", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, receipt_date_time ), "sample_receipt_date_time_stamp", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, owner ), "sample_owner", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, procedure_name ), "sample_procedure_name", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, matrix ), "sample_matrix", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, storage ), "sample_storage", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, disposal ), "sample_disposal", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, history ), "sample_history", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, prep_procedure ), "sample_prep_procedure", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, prep_comments ), "sample_prep_comments", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, manual_handling ), "sample_manual_handling", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, comments ), "sample_comments", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Sample_Data, state ), "sample_state", NC_GLOBAL, NC_CHAR, 0, 1, (int)state_other } }; static int nSamp = sizeof( sample_attributes ) / sizeof( MS_Attribute_Data ); /* Attribute data array for TEST METHOD attributes */ static MS_Attribute_Data test_attributes[] = { { offsetof( MS_Test_Data, separation_type ), "test_separation_type", NC_GLOBAL, NC_CHAR, 0, 1, (int)separation_none }, { offsetof( MS_Test_Data, ms_inlet ), "test_ms_inlet", NC_GLOBAL, NC_CHAR, 0, 1, (int)inlet_direct }, { offsetof( MS_Test_Data, ms_inlet_temperature ), "test_ms_inlet_temperature", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, ionization_mode ), "test_ionization_mode", NC_GLOBAL, NC_CHAR, 0, 1, (int)ionization_ei }, { offsetof( MS_Test_Data, ionization_polarity ), "test_ionization_polarity", NC_GLOBAL, NC_CHAR, 0, 1, (int)polarity_plus }, { offsetof( MS_Test_Data, electron_energy ), "test_electron_energy", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, laser_wavelength), "test_laser_wavelength", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, reagent_gas ), "test_reagent_gas", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Test_Data, reagent_gas_pressure ), "test_reagent_gas_pressure", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, fab_type ), "test_fab_type", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Test_Data, fab_matrix ), "test_fab_matrix", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Test_Data, source_temperature ), "test_source_temperature", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, filament_current ), "test_filament_current", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, emission_current ), "test_emission_current", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, accelerating_potential), "test_accelerating_potential", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, detector_type ), "test_detector_type", NC_GLOBAL, NC_CHAR, 0, 1, (int)detector_em }, { offsetof( MS_Test_Data, detector_potential ), "test_detector_potential", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, detector_entrance_potential ), "test_detector_entrance_potential", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, resolution_type ), "test_resolution_type", NC_GLOBAL, NC_CHAR, 0, 1, (int)resolution_constant }, { offsetof( MS_Test_Data, resolution_method ), "test_resolution_method", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Test_Data, scan_function ), "test_scan_function", NC_GLOBAL, NC_CHAR, 0, 1, (int)function_scan }, { offsetof( MS_Test_Data, scan_direction ), "test_scan_direction", NC_GLOBAL, NC_CHAR, 0, 1, (int)direction_up }, { offsetof( MS_Test_Data, scan_law ), "test_scan_law", NC_GLOBAL, NC_CHAR, 0, 1, (int)law_linear }, { offsetof( MS_Test_Data, scan_time ), "test_scan_time", NC_GLOBAL, NC_FLOAT, 0, 0, 0 }, { offsetof( MS_Test_Data, mass_calibration_file ), "mass_calibration_file", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Test_Data, external_reference_file ), "test_external_reference_file", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Test_Data, internal_reference_file ), "test_internal_reference_file", NC_GLOBAL, NC_CHAR, 0, 0, 0 }, { offsetof( MS_Test_Data, comments ), "test_comments", NC_GLOBAL, NC_CHAR, 0, 0, 0 } }; static int nTest = sizeof( test_attributes ) / sizeof( MS_Attribute_Data ); /* Attribute data array for RAW DATA GLOBAL attributes */ static MS_Attribute_Data raw_data_attributes[] = { { offsetof( MS_Raw_Data_Global, mass_format ), "raw_data_mass_format", NC_GLOBAL, NC_CHAR, 0, 1, (int)data_short }, { offsetof( MS_Raw_Data_Global, time_format ), "raw_data_time_format", NC_GLOBAL, NC_CHAR, 0, 1, (int)data_short }, { offsetof( MS_Raw_Data_Global, intensity_format ), "raw_data_intensity_format", NC_GLOBAL, NC_CHAR, 0, 1, (int)data_long }, { offsetof( MS_Raw_Data_Global, mass_units ), "units", (long)offsetof( MS_Variables, mass_values_id ), NC_CHAR, 0, 1, (int)mass_m_z }, { offsetof( MS_Raw_Data_Global, time_units ), "units", (long)offsetof( MS_Variables, time_values_id ), NC_CHAR, 0, 1, (int)time_seconds }, { offsetof( MS_Raw_Data_Global, intensity_units ), "units", (long)offsetof( MS_Variables, intensity_values_id ), NC_CHAR, 0, 1, (int)intensity_arbitrary }, { offsetof( MS_Raw_Data_Global, intensity_offset ), "add_offset", (long)offsetof( MS_Variables, intensity_values_id ), NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, mass_factor ), "scale_factor", (long)offsetof( MS_Variables, mass_values_id ), NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, time_factor ), "scale_factor", (long)offsetof( MS_Variables, time_values_id ), NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, intensity_factor ), "scale_factor", (long)offsetof( MS_Variables, intensity_values_id ), NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, total_intensity_units ), "units", (long)offsetof( MS_Variables, total_intensity_id ), NC_CHAR, 0, 1, (int)intensity_arbitrary }, { offsetof( MS_Raw_Data_Global, mass_label ), "long_name", (long)offsetof( MS_Variables, mass_values_id ), NC_CHAR, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, time_label ), "long_name", (long)offsetof( MS_Variables, time_values_id ), NC_CHAR, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, intensity_label ), "long_name", (long)offsetof( MS_Variables, intensity_values_id ), NC_CHAR, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, starting_scan_number ), "starting_scan_number", NC_GLOBAL, NC_LONG, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, mass_axis_global_min ), "global_mass_min", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, mass_axis_global_max ), "global_mass_max", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, time_axis_global_min ), "global_time_min", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, time_axis_global_max ), "global_time_max", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, intensity_axis_global_min ), "global_intensity_min", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, intensity_axis_global_max ), "global_intensity_max", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, calibrated_mass_min ), "calibrated_mass_min", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, calibrated_mass_max ), "calibrated_mass_max", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, run_time ), "actual_run_time_length", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, delay_time ), "actual_delay_time", NC_GLOBAL, NC_DOUBLE, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, uniform_flag ), "raw_data_uniform_sampling_flag", NC_GLOBAL, NC_SHORT, 0, 0, 0 }, { offsetof( MS_Raw_Data_Global, comments ), "raw_data_comments", NC_GLOBAL, NC_CHAR, 0, 0, 0 } }; static int nRaw = sizeof( raw_data_attributes ) / sizeof( MS_Attribute_Data ); #endif /* MS10_IO_INCLUDED */ /* DON'T ADD ANYTHING AFTER THIS #endif */ /* -*-C-*- ******************************************************************************* * * File: ms10.h * * Description: Header file for the public-domain implementation of the * MS netCDF Data Interchange Specification, Categories 1 & 2 * data elements * Author: David Stranz * * Created: Tue Feb 18 13:03:15 1992 * Modified: Tue Jul 20 10:58:05 1993 (David Stranz) dstranz@lfrg1 * Language: C * Package: N/A * Status: Public Domain (Distribute with Copyright Notice) * * (C) Copyright 1992, Analytical Instrument Association * All rights reserved. * ******************************************************************************* */ #ifndef MS10_INCLUDED #define MS10_INCLUDED 1 /* ******************************************************************************** * * Standard definitions for the MS Interchange * ******************************************************************************** */ /* Pointer, floating point, and integer elements in data structures are initialized to these values for output. On output, any field which contains one of these values will not be written to the netCDF file. For input, these values in a data field indicate that the netCDF file did not contain a value for the element. In other words, they are the default NULL values for (char *) pointers, (float) or (double) variables, or (int) or (long) variables, respectively. */ #ifndef NULL #define NULL ((void *) 0) #endif #define MS_NULL_FLT ((float) -9999.0) #define MS_NULL_INT (-9999) #define MS_NULL_BYTE (255) #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #define MS_ERROR (-1) /* Returned for all errors */ #define MS_NO_ERROR (0) /* Returned when successful */ #define MS_INST_LENGTH (32) /* Length of INSTRUMENT-ID data strings, including NULL */ #define MS_MAX_STRING_LENGTH (255) /* Maximum allowed length of string variables and attributes */ #define MS_STAMP_LENGTH (20) /* Length of a time stamp string, including NULL */ /* ******************************************************************************** * * MS enumerated types: Each MS data element which has an enumerated set * of possible values has a type defined to represent that set. Enumerated * constants select among the various members of the set. * * So that lookup and translation of enumerated constants to string literals * can be easily supported, the enumerated constants are sequential, beginning * with zero. This requires an ordering of the typedefs which appear below; * do not change the order without revising the initializations of constant * values. * ******************************************************************************** */ typedef enum { /* Experiment types */ expt_centroid = 0, /* Centroided Mass Spectrum */ expt_continuum, /* Continuum Mass Spectrum */ expt_library /* Library Mass Spectrum */ } ms_admin_expt_t; typedef enum { /* Sample states */ state_solid = (int) expt_library + 1, /* Solid */ state_liquid, /* Liquid */ state_gas, /* Gas */ state_supercrit, /* Supercritical Fluid */ state_plasma, /* Plasma */ state_other /* Other */ } ms_sample_state_t; typedef enum { /* Separation experiments */ separation_glc = (int) state_other + 1, /* Gas-Liquid Chromatography */ separation_gsc, /* Gas-Solid Chromatography */ separation_nplc, /* Normal Phase Liquid Chromatography */ separation_rplc, /* Reverse Phase Liquid Chromatography */ separation_ielc, /* Ion Exchange Liquid Chromatography */ separation_selc, /* Size Exclusion Liquid Chromatography */ separation_iplc, /* Ion Pair Liquid Chromatography */ separation_olc, /* Other Liquid Chromatography */ separation_sfc, /* Supercritical Fluid Chromatography */ separation_tlc, /* Thin Layer Chromatography */ separation_fff, /* Field Flow Fractionation */ separation_cze, /* Capillary Zone Electrophoresis */ separation_other, /* Other Chromatography */ separation_none /* No Chromatography */ } ms_test_separation_t; typedef enum { /* Mass spectrometer inlet types */ inlet_membrane = (int) separation_none + 1, /* Membrane Separator */ inlet_capillary, /* Capillary Direct */ inlet_opensplit, /* Open Split */ inlet_jet, /* Jet Separator */ inlet_direct, /* Direct Inlet Probe */ inlet_septum, /* Septum */ inlet_pb, /* Particle Beam */ inlet_reservoir, /* Reservoir */ inlet_belt, /* Moving Belt */ inlet_apci, /* Atmospheric Pressure Chemical Ionization */ inlet_fia, /* Flow Injection Analysis */ inlet_es, /* Electrospray */ inlet_infusion, /* Infusion */ inlet_ts, /* Thermospray */ inlet_probe, /* Other Probe */ inlet_other /* Other */ } ms_test_inlet_t; typedef enum { /* Ionization modes */ ionization_ei = (int) inlet_other + 1, /* Electron Impact */ ionization_ci, /* Chemical Ionization */ ionization_fab, /* Fast Atom Bombardment */ ionization_fd, /* Field Desorption */ ionization_fi, /* Field Ionization */ ionization_es, /* Electrospray */ ionization_ts, /* Thermospray */ ionization_apci, /* Atmospheric Pressure Chemical Ionization */ ionization_pd, /* Plasma Desorption */ ionization_ld, /* Laser Desorption */ ionization_spark, /* Spark Ionization */ ionization_thermal, /* Thermal Ionization */ ionization_other /* Other */ } ms_test_ioniz_t; typedef enum { /* Ionization polarities */ polarity_plus = (int) ionization_other + 1, /* Positive */ polarity_minus /* Negative */ } ms_test_polarity_t; typedef enum { /* Detector types */ detector_em = (int) polarity_minus + 1, /* Electron Multiplier */ detector_pm, /* Photomultplier */ detector_focal, /* Focal Plane Array */ detector_cup, /* Faraday Cup */ detector_dynode_em, /* Conversion Dynode Electron Multiplier */ detector_dynode_pm, /* Conversion dynode Photomultiplier */ detector_multicoll, /* Multicollector */ detector_other /* Other */ } ms_test_detector_t; /* Resolution types; only these two are permitted. Constant resolution implies constant absolute mass resolution across the mass axis, such as is found in quadrupoles; Proportional resolution implies constant proportional (mass / delta mass) resolution across the mass axis, as is found in magnetic sectors. */ typedef enum { resolution_constant = (int) detector_other + 1, /* Constant */ resolution_proportional /* Proportional */ } ms_test_res_t; typedef enum { /* Scan types */ function_scan = (int) resolution_proportional + 1, /* Mass Scan */ function_sid, /* Selected Ion Detection */ function_other /* Other */ } ms_test_function_t; /* Scan direction; "other" should be used for non-monotonic scans. Up means from low to high mass */ typedef enum { direction_up = (int) function_other + 1, /* Up */ direction_down, /* Down */ direction_other /* Other */ } ms_test_direction_t; typedef enum { /* Scan laws */ law_linear = (int) direction_other + 1, /* Linear */ law_exponential, /* Exponential */ law_quadratic, /* Quadratic */ law_other /* Other */ } ms_test_law_t; /* The mass, time, and intensity axes can each be stored in one of four formats to best match the original precision and conserve space in the netCDF file. */ typedef enum { /* Raw data format */ data_short = (int) law_other + 1, /* Short (16-bit integer) */ data_long, /* Long (32-bit integer) */ data_float, /* Float (IEEE 32-bit float) */ data_double /* Double (IEEE 64-bit float) */ } ms_data_format_t; /* Mass, time and intensity axes units have not been formally defined in the MS specification. These are some suggestions, and may change in future revisions. */ typedef enum { /* Units for the mass axis */ mass_m_z = (int) data_double + 1, /* M/Z */ mass_arbitrary, /* Arbitrary units */ mass_other /* Other */ } ms_data_mass_t; typedef enum { /* Units for the time axis */ time_seconds = (int) mass_other + 1, /* Seconds */ time_arbitrary, /* Arbitrary units */ time_other /* Other */ } ms_data_time_t; typedef enum { /* Units for the intensity axis; these same units also apply to total intensity */ intensity_counts = (int) time_other + 1, /* Total counts */ intensity_cps, /* Counts per second */ intensity_volts, /* Volts */ intensity_current, /* Current */ intensity_arbitrary, /* Arbitrary units */ intensity_other /* Other */ } ms_data_intensity_t; /* ******************************************************************************** * * Date/time stamp data structure; used for date/time conversions to * ISO 3307 format. * ******************************************************************************** */ typedef struct { char * string; /* input/output string */ int year; int month; int day; int hour; int minute; int second; int differential; } MS_Date_Time; /* ******************************************************************************** * * ADMINISTRATIVE-DATA Information Class - Category 1 & 2 Data Elements * ******************************************************************************** */ typedef struct { char * dataset_completeness; char * ms_template_revision; char * netcdf_revision; char * languages; char * comments; char * dataset_origin; char * dataset_owner; char * netcdf_date_time; char * experiment_title; char * experiment_date_time; char * experiment_x_ref_0; char * experiment_x_ref_1; char * experiment_x_ref_2; char * experiment_x_ref_3; char * operator_name; char * pre_expt_program_name; char * post_expt_program_name; char * source_file_reference; char * source_file_format; char * source_file_date_time; char * external_file_ref_0; char * external_file_ref_1; char * external_file_ref_2; char * external_file_ref_3; char * calibration_history_0; char * calibration_history_1; char * calibration_history_2; char * calibration_history_3; char * error_log; ms_admin_expt_t experiment_type; long number_times_processed; long number_times_calibrated; long number_instrument_components; } MS_Admin_Data; /* ******************************************************************************** * * INSTRUMENT-ID Information Class - Category 1 through 5 Data Elements * ******************************************************************************** */ /* Note that the contents or format of the string fields below have not been defined in the MS proposal. The structure definition has been provided for completeness only. */ typedef struct { long inst_no; char * name; char * id; char * manufacturer; char * model_number; char * serial_number; char * software_version; char * firmware_version; char * operating_system; char * application_software; char * comments; } MS_Instrument_Data; /* ******************************************************************************** * * SAMPLE-DESCRIPTION Information Class - Category 1 & 2 Data Elements * ******************************************************************************** */ typedef struct { char * internal_id; char * external_id; char * receipt_date_time; char * owner; char * procedure_name; char * matrix; char * storage; char * disposal; char * history; char * prep_procedure; char * prep_comments; char * manual_handling; char * comments; ms_sample_state_t state; } MS_Sample_Data; /* ******************************************************************************** * * TEST-METHOD Information Class - Category 1 & 2 Data Elements * ******************************************************************************** */ typedef struct { ms_test_separation_t separation_type; ms_test_inlet_t ms_inlet; float ms_inlet_temperature; ms_test_ioniz_t ionization_mode; ms_test_polarity_t ionization_polarity; float electron_energy; float laser_wavelength; char * reagent_gas; float reagent_gas_pressure; char * fab_type; char * fab_matrix; float source_temperature; float filament_current; float emission_current; float accelerating_potential; ms_test_detector_t detector_type; float detector_potential; float detector_entrance_potential; ms_test_res_t resolution_type; char * resolution_method; ms_test_function_t scan_function; ms_test_direction_t scan_direction; ms_test_law_t scan_law; float scan_time; char * mass_calibration_file; char * external_reference_file; char * internal_reference_file; char * comments; } MS_Test_Data; /* ******************************************************************************** * * RAW-DATA Information Class - Category 1 & 2 Data Elements * ******************************************************************************** */ /* The "has_masses" and "has_times" flags are used only when reading netCDF files, and are set to TRUE if the respective data is present in the file. */ typedef struct { long nscans; /* Number of scans in data set */ int has_masses; /* TRUE if masses present in file */ int has_times; /* TRUE if times present in file */ double mass_factor; double time_factor; double intensity_factor; double intensity_offset; ms_data_mass_t mass_units; ms_data_time_t time_units; ms_data_intensity_t intensity_units; ms_data_intensity_t total_intensity_units; ms_data_format_t mass_format; ms_data_format_t time_format; ms_data_format_t intensity_format; char * mass_label; char * time_label; char * intensity_label; long starting_scan_number; double mass_axis_global_min; double mass_axis_global_max; double time_axis_global_min; double time_axis_global_max; double intensity_axis_global_min; double intensity_axis_global_max; double calibrated_mass_min; double calibrated_mass_max; double run_time; double delay_time; short uniform_flag; char * comments; } MS_Raw_Data_Global; /* Note: this data is provided on a per-scan basis. The arrays of mass, time, and intensity values must be the same size, and have a one-to-one correspondence between them (i.e. one mass, time, and intensity triplet for each datum point). Mass or time data may be both present, or only mass or only time data. WHATEVER IS PRESENT, THE SAME DATA MUST BE PRESENT FOR EVERY SCAN IN THE FILE. If one abcissa type is missing, the pointer may be set to NULL. The arrays are declared as void * to allow for variable typing (they may actually be short, long, float, or double, depending on the data format indicated in the MS_Raw_Data_Global fields. Flag_masses and flag_values arrays are optional. If no peaks are flagged for a given scan, then NULL pointers may be passed. Otherwise, these arrays are filled pairwise with the mass/time and flag value for those peaks which are flagged. Peaks which have no flags need not be included. The following rules determine whether masses or times are passed in the flag_peaks array: (1) If both times and masses are recorded for scan data, then MASSES must be passed; (2) If times only are recorded, then TIMES must be passed; or, (3) If masses only are recorded, then MASSES must be passed. In every case, the flag_paeks array must be of the same data type as the masses or times array as appropriate. The flag_values array MUST be of the same data type as the intensities array (since it is physically written to the netCDF file by concatenating it to the end of the intensities data for each scan, and therefore must be of the same type). Flags values are listed below. If a peak has more than one flag, then a composite flag is constructed using the logical OR of the separate flags. All of the peaks in the flag_peakss array MUST be present in the masses or times array for the scan; unpredictable results will occur if there is a mismatch. For each scan, the scan_no, points, and flags fields MUST have valid values. If there are no peaks or flags for a given scan, pass zeros in those fields. An entry must be made in the netCDF file for every scan, whether it has peaks or not. */ typedef struct { long scan_no; /* Index number of this scan */ long points; /* Number of points in this scan*/ long flags; /* Number of flagged peaks */ long actual_scan_no; /* Data file scan number */ double total_intensity; double a_d_rate; short a_d_coadditions; double scan_acq_time; double scan_duration; double inter_scan_time; double mass_range_min; double mass_range_max; double time_range_min; double time_range_max; double resolution; void * masses; /* Array of masses */ void * times; /* Array of times */ void * intensities; /* Array of intensities */ long * flag_peaks; /* Array of flagged peaks */ short * flag_values; /* Array of flag values */ } MS_Raw_Per_Scan; /* The following struct is used for SIR/SIM/MID-type data to record the scan group information. The three arrays are parallel - that is, for each mass, there is a corresponding sampling time (how long that mass was monitored during the scan) and delay time (how long it took to get to the next monitored mass). All times are in milliseconds. On writing, the arrays are assumed to be dimensioned to "mass_count" length. On reading, the arrays are dynamically allocated to a length appropriate to the number of masses in the scan group being read. */ typedef struct { long group_no; /* Index number of this group */ long mass_count; /* Number of masses in group */ long starting_scan; /* Group starts with this scan */ double * masses; /* Array of masses */ double * sampling_times; /* Sampling time for each mass */ double * delay_times; /* Inter-mass delay time */ } MS_Raw_Per_Group; /* Note: For library data, in addition to the per-scan raw data, the following data is provided for each library spectrum. */ /* Note: The specification provides for any number of additional names; this is difficult to implement in netCDF, so in this present implementation, only four other additional names fields are provided. */ typedef struct { long scan_no; char * entry_name; char * entry_id; long entry_number; char * source_data_file_reference; char * cas_name; long cas_number; char * other_name_0; char * other_name_1; char * other_name_2; char * other_name_3; char * formula; char * smiles; char * wiswesser; char * molfile_reference; char * other_structure; double retention_index; char * retention_type; double absolute_retention; double relative_retention; char * retention_reference; long retention_cas; float mp; float bp; double chemical_mass; long nominal_mass; double accurate_mass; char * other_info; } MS_Raw_Library; /* ******************************************************************************** * * Peak flags - these may be "ORed" together to yield a composite flag * ******************************************************************************** */ #define MS_FLAG_NOT_HRP (1L << 0 ) #define MS_FLAG_MISSED_REF (1L << 1 ) #define MS_FLAG_UNRESOLVED (1L << 2 ) #define MS_FLAG_DBL_CHARGED (1L << 3 ) #define MS_FLAG_REFERENCE (1L << 4 ) #define MS_FLAG_EXCEPTION (1L << 5 ) #define MS_FLAG_SATURATED (1L << 6 ) #define MS_FLAG_SIGNIFICANT (1L << 7 ) #define MS_FLAG_MERGED (1L << 8 ) #define MS_FLAG_FRAGMENTED (1L << 9 ) #define MS_FLAG_AREA_HEIGHT (1L << 10) #define MS_FLAG_MATH_MODIFIED (1L << 11) #define MS_FLAG_NEGATIVE (1L << 12) #define MS_FLAG_EXTENDED (1L << 13) #define MS_FLAG_CALCULATED (1L << 14) #define MS_FLAG_LOCK_MASS (1L << 15) /* ******************************************************************************** * * Exported functions * ******************************************************************************** */ #ifdef __STDC__ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* From ms10aux.c: */ int ms_read_enum_attribute( int, int, char * ); char * ms_read_string_variable( int, int, long, long, int ); int ms_write_string_variable( int, int, long, long, int, char * ); int ms_open_write( char *, ms_admin_expt_t, long, long, ms_data_format_t, ms_data_format_t, ms_data_format_t, int, int ); int ms_open_read( char * ); void ms_close( int ); int ms_associate_id( int ); int ms_dissociate_id( int ); int ms_convert_date( int, MS_Date_Time * ); void ms_copy_array( void *, ms_data_format_t, long, void *, ms_data_format_t, int ); /* From ms10enum.c: */ char * ms_enum_to_string( int ); int ms_string_to_enum( char * ); /* From ms10io.c: */ int ms_write_dimensions( int, long, long ); int ms_read_dimensions( int ); int ms_write_variables( int, ms_admin_expt_t, ms_data_format_t, ms_data_format_t, ms_data_format_t, int, int ); int ms_read_variables( int ); int ms_write_global( int, MS_Admin_Data *, MS_Sample_Data *, MS_Test_Data *, MS_Raw_Data_Global * ); int ms_read_global( int, MS_Admin_Data *, MS_Sample_Data *, MS_Test_Data *, MS_Raw_Data_Global * ); void ms_init_global( int, MS_Admin_Data *, MS_Sample_Data *, MS_Test_Data *, MS_Raw_Data_Global * ); int ms_write_instrument( int, MS_Instrument_Data * ); int ms_read_instrument( int, MS_Instrument_Data * ); void ms_init_instrument( int, MS_Instrument_Data * ); int ms_write_per_scan( int, MS_Raw_Per_Scan *, MS_Raw_Library * ); int ms_read_per_scan( int, MS_Raw_Per_Scan *, MS_Raw_Library * ); void ms_init_per_scan( int, MS_Raw_Per_Scan *, MS_Raw_Library * ); int ms_write_group_global( int, long, long ); int ms_read_group_global( int, long *, long * ); int ms_write_per_group( int, MS_Raw_Per_Group * ); int ms_read_per_group( int, MS_Raw_Per_Group * ); void ms_init_per_group( int, MS_Raw_Per_Group * ); int ms_read_TIC( int, long *, double * *, double * * ); #ifdef __cplusplus } #endif /* __cplusplus */ #else /* __STDC__ */ /* From ms10aux.c: */ int ms_read_enum_attribute(); char * ms_read_string_variable(); int ms_write_string_variable(); int ms_open_write(); int ms_open_read(); void ms_close(); int ms_associate_id(); int ms_dissociate_id(); int ms_convert_date(); void ms_copy_array(); /* From ms10enum.c: */ char * ms_enum_to_string(); int ms_string_to_enum(); /* From ms10io.c: */ int ms_write_dimensions(); int ms_read_dimensions(); int ms_write_variables(); int ms_read_variables(); int ms_write_global(); int ms_read_global(); void ms_init_global(); int ms_write_instrument(); int ms_read_instrument(); void ms_init_instrument(); int ms_write_per_scan(); int ms_read_per_scan(); void ms_init_per_scan(); int ms_write_group_global(); int ms_read_group_global(); int ms_write_per_group(); int ms_read_per_group(); void ms_init_per_group(); int ms_read_TIC(); #endif /* __STDC__ */ #endif /* MS10_INCLUDED */ /* DON'T ADD ANYTHING AFTER THIS #endif */ /* -*-C-*- ******************************************************************************* * * File: ms10aux.c * * Description: Public-domain implementation of the MS netCDF Data * Interchange Specification, Categories 1 and 2 data elements. * This file contains auxilliary functions to support the MS * implementation. * Author: David Stranz * * Created: Thu Feb 20 15:00:16 1992 * Modified: Wed Jun 30 16:07:37 1993 (David Stranz) dstranz@lfrg1 * Language: C * Package: N/A * Status: Public Domain (Distribute with Copyright Notice) * * (C) Copyright 1992, Analytical Instrument Association * All rights reserved. * ******************************************************************************* */ #include #include #include "netcdf.h" #include "ms10.h" /* ******************************************************************************** * * Internal (static) functions * ******************************************************************************** */ /* ******************************************************************************** * * FUNCTION: put_number (static) * * DESCRIPTION: Formats an integer number into a character string, with * leading zeros. This function will fail if the count exceeds * the number of digits (i.e. the power of ten) which can be * represented in an integer. No assumption is made that the * string is NULL terminated on entry, and it is not NULL * terminated on exit. In other words, the arguments had * better be valid. * * ARGUMENTS: (char *) string, (int) starting string index, * (int) number of characters required, (int) integer value * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int put_number( char * string, int start, int count, int value ) #else /* __STDC__ */ static int put_number( string, start, count, value ) char * string; int start; int count; int value; #endif /* not __STDC__ */ { int index; if ( NULL == string ) return MS_ERROR; if ( value < 0 ) value = -value; index = start + count - 1; while ( value ) { string[index--] = '0' + (char)(value % 10); value /= 10; } while( index >= start ) /* add leading zeros */ string[index--] = '0'; return MS_NO_ERROR; } /* put_number */ /* ******************************************************************************** * * FUNCTION: get_number (static) * * DESCRIPTION: Retrieves an integer number from a character string. This * function will also fail if the character count exceeds the * the power of ten which can be represented by an integer. * The same assumptions as for put_number (above) apply. * * ARGUMENTS: (char *) string, (int) starting index of number in string, * (int) number of characters to decode * * RETURNS: (int) unsigned integer value (MS_ERROR on error) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int get_number( char * string, int start, int count ) #else /* __STDC__ */ static int get_number( string, start, count ) char * string; int start; int count; #endif /* not __STDC__ */ { int ret_val = 0; if ( NULL == string ) return MS_ERROR; while( count ) { ret_val *= 10; ret_val += (int)(string[start++] - '0'); count--; } return ret_val; } /* get_number */ /* ******************************************************************************** * * Exported functions * ******************************************************************************** */ /* ******************************************************************************** * * FUNCTION: ms_read_enum_attribute * * DESCRIPTION: Reads the literal version of an enumerated attribute from * the netCDF file and returns the enumerated constant value * * ARGUMENTS: (int) netCDF id, (int) variable id, (char *) name * * RETURNS: (int) enumerated value (MS_ERROR if error) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_enum_attribute( int cdfid, int varid, char * name ) #else /* __STDC__ */ int ms_read_enum_attribute( cdfid, varid, name ) int cdfid; int varid; char * name; #endif /* not __STDC__ */ { char * enum_literal; int enum_value; nc_type datatype; int len; if ( NULL == name ) return MS_ERROR; if ( MS_ERROR == ncattinq( cdfid, varid, name, &datatype, &len ) ) return MS_ERROR; if ( len <= 0 || datatype != NC_CHAR ) return MS_ERROR; /* Allocate a buffer to hold the literal value of the enumerated constant. */ if ( NULL == (enum_literal = (char *)malloc( (unsigned)(len + 1) * sizeof( char ) )) ) return MS_ERROR; /* Read the literal value */ if ( MS_ERROR == ncattget( cdfid, varid, name, enum_literal ) ) { free( enum_literal ); return MS_ERROR; } enum_literal[len] = '\0'; /* Convert to an enumerated value, then free the allocated string */ enum_value = ms_string_to_enum( enum_literal ); free( enum_literal ); if ( MS_ERROR == enum_value ) return MS_ERROR; return enum_value; } /* ms_read_enum_attribute */ /* ******************************************************************************** * * FUNCTION: ms_read_string_variable * * DESCRIPTION: Reads the value of a string variable from the netCDF file. * Space is allocated for the string value. The array index is * the first dimension for arrays of strings (the second dimension, * that of the string itself, is implicit); use -1 for non-array * string variables. * * ARGUMENTS: (int) netCDF id, (int) variable id, (long) array index 1, * (long) array index 2, (int) maximum size of string * * RETURNS: (char *) newly allocated string (NULL if error or empty) * * * * * ******************************************************************************** */ #ifdef __STDC__ char * ms_read_string_variable( int cdfid, int varid, long arr_index1, long arr_index2, int max_size ) #else /* __STDC__ */ char * ms_read_string_variable( cdfid, varid, arr_index1,arr_index2, max_size ) int cdfid; int varid; long arr_index1; long arr_index2; int max_size; #endif /* not __STDC__ */ { long tx_start[3]; /* Hyperslab corners */ long tx_count[3]; /* Hyperslab edges */ char * string; register int i; unsigned int len; /* Set up hyperslab indices and counts for multidimensional string variable access. */ tx_start[0] = ( arr_index1 < 0L ? 0L : arr_index1 ); tx_start[1] = ( arr_index2 < 0L ? 0L : arr_index2 ); tx_start[2] = 0L; /* in all cases */ tx_count[0] = (arr_index1 < 0L ? (long) max_size : 1L ); tx_count[1] = (arr_index2 < 0L ? (long) max_size : 1L ); tx_count[1] = (long) max_size; /* also in all cases */ /* Allocate a string to hold the variable value */ if ( NULL == (string = (char *)malloc( (unsigned) max_size * sizeof( char ) )) ) { return NULL; } for ( i = 0; i < max_size; string[i++] = ' ' ) { } string[max_size - 1] = '\0'; if ( MS_ERROR == ncvarget( cdfid, varid, tx_start, tx_count, (void *) string ) ) { free( string ); return NULL; } /* Put a terminating NULL, just in case... */ string[max_size - 1] = '\0'; /* If the string is entirely blank, then get rid of the allocated string and simply return a NULL pointer */ if ( 0 == (int)(len = strlen( string )) ) { free( string ); return NULL; } for ( i = len; i >= 0; i-- ) { if ( ' ' != string[i] && '\0' != string[i] ) break; string[i] = '\0'; } if ( 0 == (int) strlen( string ) ) { free( string ); return NULL; } return string; } /* ms_read_string_variable */ /* ******************************************************************************** * * FUNCTION: ms_write_string_variable * * DESCRIPTION: Writes the value of a string variable to the netCDF file. NULL- * values strings are supported, and are written out with zero * length. The array index is for the first dimension of string * array variables; use -1 for non-array strings * * ARGUMENTS: (int) netCDF id, (int) variable id, (long) first array index, * (long) second array index, (int) maximum length of string, * (char *) string * * RETURNS: (int) error code (MS_ERROR if error, 0 otherwise) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_string_variable( int cdfid, int varid, long arr_index1, long arr_index2, int max_size, char * string ) #else /* __STDC__ */ int ms_write_string_variable( cdfid, varid, arr_index1, arr_index2, max_size, string ) int cdfid; int varid; long arr_index1; long arr_index2; int max_size; char * string; #endif /* not __STDC__ */ { long tx_start[3]; /* Hyperslab corners */ long tx_count[3]; /* Hyperslab edges */ register int i; char * ms_buffer; tx_start[0] = ( arr_index1 < 0L ? 0L : arr_index1 ); tx_start[1] = ( arr_index2 < 0L ? 0L : arr_index2 ); tx_start[2] = 0L; /* in all cases */ tx_count[0] = (arr_index1 < 0L ? (long) max_size : 1L ); tx_count[1] = (arr_index2 < 0L ? (long) max_size : 1L ); tx_count[2] = (long) max_size; /* Allocate a buffer to hold the string to be written */ if ( NULL == (ms_buffer = (char *)malloc( (unsigned int)max_size * sizeof( char ) )) ) return MS_ERROR; for ( i = 0; i < max_size; ms_buffer[i++] = ' ' ) { } if ( string != NULL ) (void) strncpy( ms_buffer, string, (unsigned int)max_size ); ms_buffer[max_size - 1] = '\0'; if ( MS_ERROR == ncvarput( cdfid, varid, tx_start, tx_count, (void *) ms_buffer ) ) { free( ms_buffer ); return MS_ERROR; } free( ms_buffer ); return MS_NO_ERROR; } /* ms_write_string_variable */ /* ******************************************************************************** * * FUNCTION: ms_open_write * * DESCRIPTION: Opens a netCDF file for writing; any existing file is * overwritten. * * ARGUMENTS: (char *) filename, (ms_admin_expt_t) experiment type, * (long) number of scans, (long) number of instrument components, * (ms_data_format_t) mass data format, * (ms_data_format_t) time data format, * (ms_data_format_t) intensity data format, * (int) masses flag (TRUE if mass values will be written) * (int) times flag (TRUE if time values will be written) * * RETURNS: (int) fileID (MS_ERROR if error, id >= 0 if successful) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_open_write( char * filename, ms_admin_expt_t expt_type, long nscans, long ninst, ms_data_format_t mass_type, ms_data_format_t time_type, ms_data_format_t inty_type, int do_masses, int do_times ) #else /* __STDC__ */ int ms_open_write( filename, expt_type, nscans, ninst, mass_type, time_type, inty_type, do_masses, do_times ) char * filename; ms_admin_expt_t expt_type; long nscans; long ninst; ms_data_format_t mass_type; ms_data_format_t time_type; ms_data_format_t inty_type; int do_masses; int do_times; #endif /* not __STDC__ */ { int cdfid; if ( NULL == filename || 0 == strlen( filename ) ) return MS_ERROR; if ( MS_ERROR == (cdfid = nccreate( filename, NC_CLOBBER )) ) return MS_ERROR; if ( MS_ERROR == ms_associate_id( cdfid ) ) { (void)ncclose( cdfid ); return MS_ERROR; } if ( MS_ERROR == ms_write_dimensions( cdfid, nscans, ninst ) ) { (void)ncclose( cdfid ); return MS_ERROR; } if ( MS_ERROR == ms_write_variables( cdfid, expt_type, mass_type, time_type, inty_type, do_masses, do_times ) ) { (void)ncclose( cdfid ); return MS_ERROR; } /* Place the netCDF file into "data mode". This permits data to be written prior to writing the global information. Some applications may not know all global data prior to reading through the input file, so allowing global data to be written whenever it is convenient alleviates any need to make more than one pass thorugh the input file. We ignore the error return from this call. */ (void)ncendef( cdfid ); return cdfid; } /* ms_open_write */ /* ******************************************************************************** * * FUNCTION: ms_open_read * * DESCRIPTION: Opens a netCDF file for reading. * * ARGUMENTS: (char *) filename * * RETURNS: (int) file ID (MS_ERROR if error, id >= 0 if successful) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_open_read( char * filename ) #else /* __STDC__ */ int ms_open_read( filename ) char * filename; #endif /* not __STDC__ */ { int cdfid; if ( NULL == filename || 0 == strlen( filename ) ) return MS_ERROR; if ( MS_ERROR == (cdfid = ncopen( filename, NC_NOWRITE )) ) return MS_ERROR; if ( MS_ERROR == ms_associate_id( cdfid ) ) { (void)ncclose( cdfid ); return MS_ERROR; } if ( MS_ERROR == ms_read_dimensions( cdfid ) ) { (void)ncclose( cdfid ); return MS_ERROR; } if ( MS_ERROR == ms_read_variables( cdfid ) ) { (void)ncclose( cdfid ); return MS_ERROR; } return cdfid; } /* ms_open_read */ /* ******************************************************************************** * * FUNCTION: ms_close * * DESCRIPTION: Closes a netCDF file * * ARGUMENTS: (int) file id * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ void ms_close( int cdfid ) #else /* __STDC__ */ void ms_close( cdfid ) int cdfid; #endif /* not __STDC__ */ { (void)ncclose( cdfid ); (void)ms_dissociate_id( cdfid ); } /* ms_close */ /* ******************************************************************************** * * FUNCTION: ms_convert_date * * DESCRIPTION: Converts numeric data and time information to a ISO date/time * stamp string or vice-versa, depending on the flag. * * ARGUMENTS: (int) to_stamp flag - if TRUE, numeric data is converted to * a string, otherwise, the string is converted to numeric * data, (MS_Date_Time *) date/time data structure * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_convert_date( int flag, MS_Date_Time * dt ) #else /* __STDC__ */ int ms_convert_date( flag, dt ) int flag; MS_Date_Time * dt; #endif /* not __STDC__ */ { if ( NULL == dt ) return MS_ERROR; /* The ISO 3307 date format is: YYYYMMDDhhmmss+/-ffff, where YYYY is the full four-digit year MM is the month (January = 01) DD is the day of the month hh is the hour of day, on the 24-hour scale mm is the minute of the hour ss is the second within the minute +/- is the sign of the time differential factor (either a plus or a minus sign character) ffff is the difference (in hours and minutes) between Greenwich Mean Time (GMT) and local time. For example, the time 12:30:23 pm, December 1, 1992, Eastern Standard Time (5 hours behind GMT) is represented as: 19921201123023-0500 */ if ( flag ) { /* convert to string */ if ( NULL == (dt->string = (char *)malloc( MS_STAMP_LENGTH * sizeof( char ) )) ) return MS_ERROR; (void)put_number( dt->string, 0, 4, dt->year ); (void)put_number( dt->string, 4, 2, dt->month ); (void)put_number( dt->string, 6, 2, dt->day ); (void)put_number( dt->string, 8, 2, dt->hour ); (void)put_number( dt->string, 10, 2, dt->minute ); (void)put_number( dt->string, 12, 2, dt->second ); dt->string[14] = (dt->differential >= 0 ? '+' : '-'); (void)put_number( dt->string, 15, 4, dt->differential ); dt->string[19] = '\0'; return MS_NO_ERROR; } else { if ( NULL == dt->string || strlen( dt->string ) < MS_STAMP_LENGTH -1 ) return MS_ERROR; dt->year = get_number( dt->string, 0, 4 ); dt->month = get_number( dt->string, 4, 2 ); dt->day = get_number( dt->string, 6, 2 ); dt->hour = get_number( dt->string, 8, 2 ); dt->minute = get_number( dt->string, 10, 2 ); dt->second = get_number( dt->string, 12, 2 ); dt->differential = get_number( dt->string, 15, 4 ); if ( '-' == dt->string[14] ) dt->differential = -dt->differential; return MS_NO_ERROR; } } /* ms_convert_date */ /* ******************************************************************************** * * FUNCTION: ms_copy_array * * DESCRIPTION: Copies (and casts) the contents of one array into another. * Both input and output arrays must exist, be of the appropriate * types, and be of proper length. If the round flag is TRUE, * floating point values will be rounded (by adding 0.5, then * truncating) before being converted to integers. * * ARGUMENTS: (void *) input array, (ms_data_format_t) input data type, * (long) number of elements to copy, (void *) output array, * (ms_data_format_t) output array type, (int) round flag * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ void ms_copy_array( void * input, ms_data_format_t in_type, long in_count, void * output, ms_data_format_t out_type, int round_flag ) #else /* __STDC__ */ void ms_copy_array( input, in_type, in_count, output, out_type, round_flag ) void * input; ms_data_format_t in_type; long in_count; void * output; ms_data_format_t out_type; int round_flag; #endif /* not __STDC__ */ { long index; short * in_sp = NULL; short * out_sp = NULL; long * in_lp = NULL; long * out_lp = NULL; float * in_fp = NULL; float * out_fp = NULL; double * in_dp = NULL; double * out_dp = NULL; if ( NULL == input || NULL == output || in_count <= 0L ) return; switch( out_type ) { case data_short: out_sp = (short *) output; break; case data_long: out_lp = (long *) output; break; case data_float: out_fp = (float *) output; break; case data_double: out_dp = (double *) output; break; default: return; } switch( in_type ) { case data_short: in_sp = (short *) input; switch( out_type ) { case data_short: for ( index = 0; index < in_count; index++ ) *out_sp++ = *in_sp++; break; case data_long: for ( index = 0; index < in_count; index++ ) *out_lp++ = (long) *in_sp++; break; case data_float: for ( index = 0; index < in_count; index++ ) *out_fp++ = (float) *in_sp++; break; case data_double: for ( index = 0; index < in_count; index++ ) *out_dp++ = (double) *in_sp++; break; default: break; } break; case data_long: in_lp = (long *) input; switch( out_type ) { case data_short: for ( index = 0; index < in_count; index++ ) *out_sp++ = (short) *in_lp++; break; case data_long: for ( index = 0; index < in_count; index++ ) *out_lp++ = *in_lp++; break; case data_float: for ( index = 0; index < in_count; index++ ) *out_fp++ = (float) *in_lp++; break; case data_double: for ( index = 0; index < in_count; index++ ) *out_dp++ = (double) *in_lp++; break; default: break; } break; case data_float: in_fp = (float *) input; switch( out_type ) { case data_short: for ( index = 0; index < in_count; index++ ) *out_sp++ = (short) (*in_fp++ + (round_flag ? 0.5 : 0.0)); break; case data_long: for ( index = 0; index < in_count; index++ ) *out_lp++ = (long) (*in_fp++ + (round_flag ? 0.5 : 0.0)); break; case data_float: for ( index = 0; index < in_count; index++ ) *out_fp++ = *in_fp++; break; case data_double: for ( index = 0; index < in_count; index++ ) *out_dp++ = (double) *in_fp++; break; default: break; } break; case data_double: in_dp = (double *) input; switch( out_type ) { case data_short: for ( index = 0; index < in_count; index++ ) *out_sp++ = (short) (*in_dp++ + (round_flag ? 0.5 : 0.0)); break; case data_long: for ( index = 0; index < in_count; index++ ) *out_lp++ = (long) (*in_dp++ + (round_flag ? 0.5 : 0.0)); break; case data_float: for ( index = 0; index < in_count; index++ ) *out_fp++ = (float) *in_dp++; break; case data_double: for ( index = 0; index < in_count; index++ ) *out_dp++ = *in_dp++; break; default: break; } break; default: break; } return; } /* ms_copy_array */ /* -*-C-*- ******************************************************************************* * * File: ms10enum.c * * Description: Enumerated value <-> string literal translations for the MS * netCDF Data Interchange Specification, Categories 1 & 2 data * Author: David Stranz * * Created: Thu Feb 27 13:23:19 1992 * Modified: Mon Jun 28 09:47:13 1993 (David Stranz) dstranz@lfrg1 * Language: C * Package: N/A * Status: Public Domain (Distribute with Copyright Notice) * * (C) Copyright 1992, Analytical Instrument Association * All rights reserved. * ******************************************************************************* */ #include #include #include "ms10.h" /* ******************************************************************************** * * Enumerated set enum to string correspondences * * NOTE: The strings below are sorted in case-insensitive ascending alphabetical * order. If you add new strings, ensure that order is maintained! It is also * a requirement that all string literals be unique. * * A binary search is used to find string literals in this array; that is * the reason for the sorting and uniqueness requirements. * ******************************************************************************** */ typedef struct { char * literal_value; int enum_value; } EnumLiteral; static EnumLiteral ms_enums[] = { { "Arbitrary Mass Units", (int) mass_arbitrary }, { "Arbitrary Intensity Units", (int) intensity_arbitrary }, { "Arbitrary Time Units", (int) time_arbitrary }, { "Atmospheric Pressure Chemical Ionization", (int) ionization_apci }, { "Atmospheric Pressure Chemical Ionization Inlet", (int) inlet_apci }, { "Capillary Direct", (int) inlet_capillary }, { "Capillary Zone Electrophoresis", (int) separation_cze }, { "Centroided Mass Spectrum", (int) expt_centroid }, { "Chemical Ionization", (int) ionization_ci }, { "Constant Resolution", (int) resolution_constant }, { "Continuum Mass Spectrum", (int) expt_continuum }, { "Conversion Dynode Electron Multiplier", (int) detector_dynode_em }, { "Conversion Dynode Photomultiplier", (int) detector_dynode_pm }, { "Counts Per Second", (int) intensity_cps }, { "Current", (int) intensity_current }, { "Direct Inlet Probe", (int) inlet_direct }, { "Double", (int) data_double }, { "Down", (int) direction_down }, { "Electron Impact", (int) ionization_ei }, { "Electron Multiplier", (int) detector_em }, { "Electrospray Inlet", (int) inlet_es }, { "Electrospray Ionization", (int) ionization_es }, { "Exponential", (int) law_exponential }, { "Faraday Cup", (int) detector_cup }, { "Fast Atom Bombardment", (int) ionization_fab }, { "Field Desorption", (int) ionization_fd }, { "Field Flow Fractionation", (int) separation_fff }, { "Field Ionization", (int) ionization_fi }, { "Float", (int) data_float }, { "Flow Injection Analysis", (int) inlet_fia }, { "Focal Plane Array", (int) detector_focal }, { "Gas", (int) state_gas }, { "Gas-Liquid Chromatography", (int) separation_glc }, { "Gas-Solid Chromatography", (int) separation_gsc }, { "Infusion", (int) inlet_infusion }, { "Ion Exchange Liquid Chromatography", (int) separation_ielc }, { "Ion Pair Liquid Chromatography", (int) separation_iplc }, { "Jet Separator", (int) inlet_jet }, { "Laser Desorption", (int) ionization_ld }, { "Library Mass Spectrum", (int) expt_library }, { "Linear", (int) law_linear }, { "Liquid", (int) state_liquid }, { "Long", (int) data_long }, { "M/Z", (int) mass_m_z }, { "Mass Scan", (int) function_scan }, { "Membrane Separator", (int) inlet_membrane }, { "Moving Belt", (int) inlet_belt }, { "Multicollector", (int) detector_multicoll }, { "Negative Polarity", (int) polarity_minus }, { "No Chromatography", (int) separation_none }, { "Normal Phase Liquid Chromatography", (int) separation_nplc }, { "Open Split", (int) inlet_opensplit }, { "Other Chromatography", (int) separation_other }, { "Other Detector", (int) detector_other }, { "Other Direction", (int) direction_other }, { "Other Function", (int) function_other }, { "Other Inlet", (int) inlet_other }, { "Other Intensity", (int) intensity_other }, { "Other Ionization", (int) ionization_other }, { "Other Law", (int) law_other }, { "Other Liquid Chromatography", (int) separation_olc }, { "Other Mass", (int) mass_other }, { "Other Probe", (int) inlet_probe }, { "Other State", (int) state_other }, { "Other Time", (int) time_other }, { "Particle Beam", (int) inlet_pb }, { "Photomultiplier", (int) detector_pm }, { "Plasma", (int) state_plasma }, { "Plasma Desorption", (int) ionization_pd }, { "Positive Polarity", (int) polarity_plus }, { "Proportional Resolution", (int) resolution_proportional }, { "Quadratic", (int) law_quadratic }, { "Reservoir", (int) inlet_reservoir }, { "Reverse Phase Liquid Chromatography", (int) separation_rplc }, { "Seconds", (int) time_seconds }, { "Selected Ion Detection", (int) function_sid }, { "Septum", (int) inlet_septum }, { "Short", (int) data_short }, { "Size Exclusion Liquid Chromatography", (int) separation_selc }, { "Solid", (int) state_solid }, { "Spark Ionization", (int) ionization_spark }, { "Supercritical Fluid Chromatography", (int) separation_sfc }, { "Supercritical Fluid", (int) state_supercrit }, { "Thermal Ionization", (int) ionization_thermal }, { "Thermospray Inlet", (int) inlet_ts }, { "Thermospray Ionization", (int) ionization_ts }, { "Thin Layer Chromatography", (int) separation_tlc }, { "Total Counts", (int) intensity_counts }, { "Up", (int) direction_up }, { "Volts", (int) intensity_volts } }; #define ENUM_COUNT (sizeof( ms_enums ) / sizeof( EnumLiteral )) /* ******************************************************************************** * * Exported functions * ******************************************************************************** */ /* ******************************************************************************** * * FUNCTION: ms_enum_to_string * * DESCRIPTION: Converts the enumerated constant (passed as an int) to the * corresponding string literal. The caller MUST treat these * strings as read-only. * * ARGUMENTS: (int) enumerated constant * * RETURNS: (char *) pointer to string (NULL if not found) * * * * * ******************************************************************************** */ #ifdef __STDC__ char * ms_enum_to_string( int enum_value ) #else /* __STDC__ */ char * ms_enum_to_string( enum_value ) int enum_value; #endif /* not __STDC__ */ { int i; for ( i = 0; i < (int) ENUM_COUNT; i++ ) { if ( ms_enums[i].enum_value == enum_value ) { return ms_enums[i].literal_value; } } return NULL; } /* ms_enum_to_string */ /* ******************************************************************************** * * FUNCTION: ms_string_to_enum * * DESCRIPTION: Converts the string value to the corresponding enumerated * constant, returned as an int. Although the string literals are * upper/lower case, the comparisons are made case-insensitively. * * This routine performs a binary search of the enumerated string * list. In order for it to work successfully, the string list * MUST be sorted in ascending, case-insensitive alphabetical order. * If any additions/modifications are made to the list, ensure * that sort order is maintained. * * ARGUMENTS: (char *) string literal * * RETURNS: (int) enumerated constant (MS_ERROR if error) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_string_to_enum( char * literal_value ) #else /* __STDC__ */ int ms_string_to_enum( literal_value ) char * literal_value; #endif /* not __STDC__ */ { int left = 0; int right = ENUM_COUNT - 1; int pos; char *s; char *t; int diff; if ( (char *) NULL == literal_value ) return MS_ERROR; /* The binary search of the string array uses a trick to speed it up. Rather than compare full strings at each step, the first letters of the target and search strings are compared. Only if they match is a full string compare made. */ while ( right >= left ) { pos = (right + left) / 2; t = literal_value; s = ms_enums[pos].literal_value; while ((0 == (diff = (int) (tolower( *t ) - tolower( *s )))) && *s && *t ) { s++; t++; } if ( diff < 0 ) right = pos - 1; else if ( diff > 0 ) left = pos + 1; else return ms_enums[pos].enum_value; } return MS_ERROR; } /* ms_string_to_enum */ #ifdef TEST_ENUM #include /* ******************************************************************************** * * FUNCTION: main * * DESCRIPTION: Test routine for string to enum conversion * * ARGUMENTS: (none) * * RETURNS: (int) return code * * * * * ******************************************************************************** */ #ifdef __STDC__ int main() #else /* __STDC__ */ int main() #endif /* not __STDC__ */ { int enum_value; int i; char * literal_value; int hits[2 * ENUM_COUNT]; for ( i = 0; i < 2 * ENUM_COUNT; hits[i++] = 0 ); /* Look up every string value, then use the enumerated value to find the string. Make sure there are no duplicate enumerated constants. An error in the search for the enumerated constant given the string means that there is an error in the sort order. */ for ( i = 0; i < ENUM_COUNT; i++ ) { enum_value = ms_string_to_enum( ms_enums[i].literal_value ); literal_value = ms_enum_to_string( enum_value ); if ( hits[enum_value] != 0 ) fprintf( stdout, "Duplicate enum value!!\n" ); hits[enum_value] = 1; } return( 1 ); } /* main */ #endif /* TEST_ENUM */ /* -*-C-*- ******************************************************************************* * * File: ms10io.c * * Description: Public-domain implementation of the MS netCDF Data * Interchange Specification, Categories 1 and 2 data elements. * This file implements the netCDF file I/O functions of the * MS specification. * Author: David Stranz * * Created: Thu Feb 20 15:00:16 1992 * Modified: Wed Aug 25 12:51:32 1993 (David Stranz) dstranz@lfrg1 * Language: C * Package: N/A * Status: Public Domain (Distribute with Copyright Notice) * * (C) Copyright 1992, Analytical Instrument Association * All rights reserved. * ******************************************************************************* */ #include #include #include #include "netcdf.h" #include "ms10.h" #include "ms10io.h" #include /* ******************************************************************************** * * This is one monster file; however, in exchange for size, it isolates * all netCDF I/O and simplifies the interface to I/O routines (basically, * makes the majority of the process table driven). * ******************************************************************************** */ /* ******************************************************************************** * * Internal (static) functions * ******************************************************************************** */ /* ******************************************************************************** * * FUNCTION: format_to_datatype (static) * * DESCRIPTION: Converts a mass, time, or intensity format to a netCDF * data type. * * ARGUMENTS: (ms_data_format_t) format specifier, (nc_type) default type * * RETURNS: (nc_type) datatype specifier * * * * * ******************************************************************************** */ #ifdef __STDC__ static nc_type format_to_datatype( ms_data_format_t fmt, nc_type default_type ) #else /* __STDC__ */ static nc_type format_to_datatype( fmt, default_type ) ms_data_format_t fmt; nc_type default_type; #endif /* not __STDC__ */ { int i; for ( i = 0; i < nTypes; i++ ) if ( fmt == ms_types[i].ms_fmt ) return ms_types[i].cdf_type; return default_type; } /* format_to_datatype */ /* ******************************************************************************** * * FUNCTION: datatype_to_format (static) * * DESCRIPTION: Returns the datatype given the nc_type * * ARGUMENTS: (nc_type) input type, (ms_data_format_t) default format * * RETURNS: (ms_data_format_t) corresponding format * * * * * ******************************************************************************** */ #ifdef __STDC__ static ms_data_format_t datatype_to_format( nc_type typ, ms_data_format_t default_fmt ) #else /* __STDC__ */ static ms_data_format_t datatype_to_format( typ, default_fmt ) nc_type typ; ms_data_format_t default_fmt; #endif /* not __STDC__ */ { int i; for ( i = 0; i < nTypes; i++ ) if ( typ == ms_types[i].cdf_type ) return ms_types[i].ms_fmt; return default_fmt; } /* datatype_to_format */ /* ******************************************************************************** * * FUNCTION: put_default (static) * * DESCRIPTION: Utility routine to cast and load a default numeric data value * * ARGUMENTS: (nc_type) datatype, (void *) address of variable, (int) array * index * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ static void put_default( nc_type datatype, void * value, int offset ) #else /* __STDC__ */ static void put_default( datatype, value, offset ) nc_type datatype; void * value; int offset; #endif /* not __STDC__ */ { switch (datatype ) { case NC_BYTE: *((char *)value + offset) = (char)MS_NULL_BYTE; break; case NC_SHORT: *((short *)value + offset) = (short)MS_NULL_INT; break; case NC_LONG: *((long *)value + offset) = (long)MS_NULL_INT; break; case NC_FLOAT: *((float *)value + offset) = (float)MS_NULL_FLT; break; case NC_DOUBLE: *((double *)value + offset) = (double)MS_NULL_FLT; break; default: break; } return; } /* put_default */ /* ******************************************************************************** * * FUNCTION: make_array (static) * * DESCRIPTION: Allocates an array of the appropriate length and data type * * ARGUMENTS: (long) number of points, (nc_type) datatype * * RETURNS: (void *) pointer to array (NULL if error) * * * * * ******************************************************************************** */ #ifdef __STDC__ static void * make_array( long npts, nc_type datatype ) #else /* __STDC__ */ static void * make_array( npts, datatype ) long npts; nc_type datatype; #endif /* not __STDC__ */ { long size; switch ( datatype ) { case NC_SHORT: size = sizeof( short ); break; case NC_LONG: size = sizeof( long ); break; case NC_FLOAT: size = sizeof( float ); break; case NC_DOUBLE: size = sizeof( double ); break; default: return NULL; } return (void *) malloc( (unsigned long)(npts * size) ); } /* make_array */ /* ******************************************************************************** * * FUNCTION: init_indexed_variables (static) * * DESCRIPTION: Initializes (and optionally clears) variables which are * present on a per-scan or per-instrument basis. * * ARGUMENTS: (char *) values data structure pointer, * (int) number of variables, * (MS_Variable_Data *) variable definitions array pointer, * (int) clear flag * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ static void init_indexed_variables( char * values, int nDefs, MS_Variable_Data * defs, int clear ) #else /* __STDC__ */ static void init_indexed_variables( values, nDefs, defs, clear ) char * values; int nDefs; MS_Variable_Data * defs; int clear; #endif /* not __STDC__ */ { int i; if ( NULL == values || NULL == defs ) return; for ( i = 0; i < nDefs; i++ ) { if ( 0 == defs[i].ndim ) { /* not possible */ continue; } else if ( 1 == defs[i].ndim ) { /* single dimension */ if ( NC_CHAR == defs[i].datatype ) { continue; /* not possible */ } else { put_default( defs[i].datatype, (void *)(values + defs[i].data_offset), 0 ); } } else if ( 2 == defs[i].ndim ) { if ( NC_CHAR == defs[i].datatype ) { if ( clear && (*((char * *)(values + defs[i].data_offset))) ) free( *((char * *)(values + defs[i].data_offset)) ); *((char * *)(values + defs[i].data_offset)) = NULL; } else continue; } else continue; } /* for ( i = ... ) */ return; } /* init_indexed_variables */ /* ******************************************************************************** * * FUNCTION: write_variables (static) * * DESCRIPTION: Defines netCDF variables given an array of definitions * * ARGUMENTS: (int) netcdf file id, (int) number of variables, * (MS_Variables *) variable ids data structure, * (MS_Dimensions *) dimension ids data structure * (MS_Variable_Data *) variable data array * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int write_variables( int cdfid, int nDefs, MS_Variables * varbls, MS_Dimensions * dimens, MS_Variable_Data * defs ) #else /* __STDC__ */ static int write_variables( cdfid, nDefs, varbls, dimens, defs ) int cdfid; int nDefs; MS_Variables * varbls; MS_Dimensions * dimens; MS_Variable_Data * defs; #endif /* not __STDC__ */ { int i; /* index into variable data */ int j; /* index into dimension array */ int dim_ids[3]; /* dimension ids */ /* Error checking: nDefs > 0; varbls, dimens, defs must be non-NULL */ if ( nDefs <= 0 || NULL == varbls || NULL == dimens || NULL == defs ) return MS_ERROR; /* For each definition in the array, create a new netCDF variable */ for ( i = 0; i < nDefs; i++ ) { /* Load dimension ids into argument array for ncvardef call */ for ( j = 0; j < defs[i].ndim; j++ ) dim_ids[j] = ((ms_dim *)((char *)dimens + defs[i].dim[j]))->id; if ( MS_ERROR == (*((int *)(((char *)varbls) + defs[i].offset)) = ncvardef( cdfid, defs[i].name, defs[i].datatype, defs[i].ndim, dim_ids )) ) return MS_ERROR; } return MS_NO_ERROR; } /* write_variables */ /* ******************************************************************************** * * FUNCTION: read_variables (static) * * DESCRIPTION: Reads netCDF variable ids into the definitions array * * ARGUMENTS: (int) netCDF file id, (int) number of variables, * (MS_Variables *) variables data structure pointer, * (MS_Dimensions *) dimensions data structure pointer, * (MS_Variable_Data *) pointer to array of variable definitions * * RETURNS: (int) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int read_variables( int cdfid, int nDefs, MS_Variables * varbls, MS_Dimensions * dimens, MS_Variable_Data * defs ) #else /* __STDC__ */ static int read_variables( cdfid, nDefs, varbls, dimens, defs ) int cdfid; int nDefs; MS_Variables * varbls; MS_Dimensions * dimens; MS_Variable_Data * defs; #endif /* not __STDC__ */ { int i; /* Error checking: nDefs > 0; varbls, dimens, defs non-NULL */ if ( nDefs <= 0 || NULL == varbls || NULL == dimens || NULL == defs ) return MS_ERROR; for ( i = 0; i < nDefs; i++ ) { *((int *)(((char *)varbls) + defs[i].offset)) = ncvarid( cdfid, defs[i].name ); } return MS_NO_ERROR; } /* read_variables */ /* ******************************************************************************** * * FUNCTION: init_attributes (static) * * DESCRIPTION: Initializes an attribute data structure to default values. * Optionally (clear flag == TRUE), will also free non-NULL * strings. * * ARGUMENTS: (char *) cast pointer to attribute data structure, * (int) number of attributes, * (MS_Attribute_Data *) pointer to attribute values structure, * (int) clear flag * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ static void init_attributes( char * values, int nAtts, MS_Attribute_Data * atts, int clear ) #else /* __STDC__ */ static void init_attributes( values, nAtts, atts, clear ) char * values; int nAtts; MS_Attribute_Data * atts; int clear; #endif /* not __STDC__ */ { int i; /* Error check: pointers must be non-NULL */ if ( NULL == atts || NULL == values ) return; /* Enumerated attributes are stored in the file as NC_CHAR, but are represented in the data structures as integers, so they receive special treatment. In addition, if the clear flag is set, then any non-NULL character string pointers are freed before being set to NULL. */ for ( i = 0; i < nAtts; i++ ) { if ( NC_CHAR == atts[i].datatype ) { if ( atts[i].enumerated ) *((int *)(values + atts[i].offset)) = atts[i].default_value; else { if ( clear && (*((char * *)(values + atts[i].offset))) ) free( *((char * *)(values + atts[i].offset)) ); *((char * *)(values + atts[i].offset)) = NULL; } } else put_default( atts[i].datatype, (void *)(values + atts[i].offset), 0 ); } } /* init_attributes */ /* ******************************************************************************** * * FUNCTION: write_attributes (static) * * DESCRIPTION: Writes attribute values to the netCDF file * * ARGUMENTS: (int) netCDF file id, (int) number of attributes, * (MS_Variables *) variables data structure pointer, * (MS_Attribute_Data *) attribute definition data structure pointer, * (char *) cast pointer to attribute values data structure * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int write_attributes( int cdfid, int nAtt, MS_Variables * varbls, MS_Attribute_Data * atts, char * values ) #else /* __STDC__ */ static int write_attributes( cdfid, nAtt, varbls, atts, values ) int cdfid; int nAtt; MS_Variables * varbls; MS_Attribute_Data * atts; char * values; #endif /* not __STDC__ */ { int i; int len = 1; int id; long int_val; double dbl_val; int write_it; void * value; /* Error checking: nAtt > 0, all pointers valid */ if ( nAtt <= 0 || NULL == varbls || NULL == atts || NULL == values ) return MS_ERROR; /* Loop through attribute definitions. Depending on the type of each attribute, whether it is local or global, and whether it is an explicit or implicit value (i.e. needs to be retrieved via a lookup of the string representation of an enumerated value), extract the attribute value appropriately. If the attribute has a default value (NULL, MS_NULL_FLT, or MS_NULL_INT), ignore the attribute. Otherwise, write it to the file. */ for ( i = 0; i < nAtt; i++ ) { write_it = TRUE; /* Determine the datatype, and retrieve the attribute value */ switch( atts[i].datatype ) { /* All enumerated variables convert to NC_CHAR strings, so NC_CHAR attributes need special processing. */ case NC_CHAR: if ( atts[i].enumerated ) { value = (void *)ms_enum_to_string( *((int *)(values + atts[i].offset)) ); } else { value = (void *)(*((char * *)(values + atts[i].offset))); } if ( NULL == value ) { write_it = FALSE; break; } len = (long)strlen( (char *) value ) + 1; break; /* All other types are handled identically. */ case NC_BYTE: len = 1; value = (void *)(values + atts[i].offset); int_val = (long)(*((char *)value)); if ( MS_NULL_INT == int_val ) write_it = FALSE; break; case NC_SHORT: len = 1; value = (void *)(values + atts[i].offset); int_val = (long)(*((short *)value)); if ( MS_NULL_INT == int_val ) write_it = FALSE; break; case NC_LONG: len = 1; value = (void *)(values + atts[i].offset); int_val = *((long *)value); if ( MS_NULL_INT == int_val ) write_it = FALSE; break; case NC_FLOAT: len = 1; value = (void *)(values + atts[i].offset); dbl_val = (double)(*((float *)value)); if ( (int)MS_NULL_FLT == (int)dbl_val ) write_it = FALSE; break; case NC_DOUBLE: len = 1; value = (void *)(values + atts[i].offset); dbl_val = *((double *)value); if ( (int)MS_NULL_FLT == (int)dbl_val ) write_it = FALSE; break; default: return MS_ERROR; /* invalid datatype! */ } if ( !write_it ) { continue; } /* Check for local or global attribute. If local, retrieve variable id from MS_Variables data structure */ if ( NC_GLOBAL == atts[i].id ) id = NC_GLOBAL; else id = *((int *)((char *)varbls + atts[i].id)); /* Finally, write the attribute definition */ if ( MS_ERROR == ncattput( cdfid, id, atts[i].name, atts[i].datatype, len, value ) ) return MS_ERROR; } return MS_NO_ERROR; } /* write_attributes */ /* ******************************************************************************** * * FUNCTION: read_attributes (static) * * DESCRIPTION: Reads attribute values from the netCDF file. Numeric attribute * values are read directly into the fields for them; space is * first allocated for string attributes, then the values are * read in. This space must be freed before the next read (or the * pointer copied so it can later be freed), or a memory leak * will occur. * * Attributes which are defined but not present in the netCDF * file will be returned with default values (MS_NULL_INT, * MS_NULL_FLT, NULL, or the default enumerated type) as * appropriate. * * ARGUMENTS: (int) netCDF file id, (int) number of attributes, * (MS_Variables *) variables data structure pointer, * (MS_Attribute_Data *) attribute definition data structure pointer, * (char * *) cast pointer to attribute values data structure * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int read_attributes( int cdfid, int nAtts, MS_Variables * varbls, MS_Attribute_Data * atts, char * values ) #else /* __STDC__ */ static int read_attributes( cdfid, nAtts, varbls, atts, values ) int cdfid; int nAtts; MS_Variables * varbls; MS_Attribute_Data * atts; char * values; #endif /* not __STDC__ */ { int i; int isPresent; int varid; int length; nc_type datatype; char buffer[MS_MAX_STRING_LENGTH]; /* Error checking: all pointers must be non-NULL; nAtts > 0 */ if ( nAtts <= 0 || NULL == varbls || NULL == atts || NULL == values ) return MS_ERROR; for ( i = 0; i < nAtts; i++ ) { /* Determine the datatype, and retrieve appropriately */ if ( NC_GLOBAL == atts[i].id ) varid = NC_GLOBAL; else varid = *((int *)((char *)varbls + atts[i].id)); /* Inquire about the attribute. An error return indicates the attribute was not found. */ if ( MS_ERROR == ncattinq( cdfid, varid, atts[i].name, &datatype, &length ) ) isPresent = FALSE; else isPresent = TRUE; /* Check for datatype mismatch. */ if ( isPresent && ( datatype != atts[i].datatype ) ) return MS_ERROR; /* Check for missing mandatory attribute */ if ( atts[i].mandatory && FALSE == isPresent ) { return MS_ERROR; } switch ( atts[i].datatype ) { case NC_CHAR: /* A character string */ /* Character strings can be one of two types: either a free-form string value or the string form of an enumerated type. Free- form strings are retrieved into space allocated for them, whereas enumerated types are retrieved as strings into a buffer, then converted to the enumerated type. Free-form string attribute values which are not recorded in the file are assigned NULL pointers; missing enumerated values are assigned their defaults. */ if ( isPresent ) { memset( buffer, 0, sizeof( buffer ) ); if ( MS_ERROR == ncattget( cdfid, varid, atts[i].name, (void *)buffer ) ) { return MS_ERROR; } if ( atts[i].enumerated ) { *((int *)(values + atts[i].offset)) = ms_string_to_enum( buffer ); } else { char * p; p = (char *)malloc((unsigned long)(length + 1) * sizeof( char )); if ( NULL == p ) return MS_ERROR; (void)strcpy( p, buffer ); *((char * *)(values + atts[i].offset)) = p; } } else { if ( atts[i].enumerated ) *((int *)(values + atts[i].offset)) = atts[i].default_value; else *((char * *)(values + atts[i].offset)) = NULL; } break; /* Numeric types are all handled in essentially the same way; the MS implementation permits only single-valued numeric attributes (i.e. numeric attribute arrays are not supported, although this could be changed with a bit of effort). */ case NC_BYTE: { char byte_val = (char) MS_NULL_BYTE; if ( isPresent ) if ( MS_ERROR == ncattget( cdfid, varid, atts[i].name, (void *)&byte_val ) ) return MS_ERROR; *(values + atts[i].offset) = byte_val; break; } case NC_SHORT: { short short_val = (short) MS_NULL_INT; if ( isPresent ) if ( MS_ERROR == ncattget( cdfid, varid, atts[i].name, (void *)&short_val ) ) return MS_ERROR; *((short *)(values + atts[i].offset)) = short_val; break; } case NC_LONG: { long long_val = (long) MS_NULL_INT; if ( isPresent ) if ( MS_ERROR == ncattget( cdfid, varid, atts[i].name, (void *)&long_val ) ) return MS_ERROR; *((long *)(values + atts[i].offset)) = long_val; break; } case NC_FLOAT: { float float_val = (float) MS_NULL_FLT; if ( isPresent ) if ( MS_ERROR == ncattget( cdfid, varid, atts[i].name, (void *)&float_val ) ) return MS_ERROR; *((float *)(values + atts[i].offset)) = float_val; break; } case NC_DOUBLE: { double double_val = (double) MS_NULL_FLT; if ( isPresent ) if ( MS_ERROR == ncattget( cdfid, varid, atts[i].name, (void *)&double_val ) ) return MS_ERROR; *((double *)(values + atts[i].offset)) = double_val; break; } default: return MS_ERROR; /* undefined type */ } /* switch */ } /* for */ return MS_NO_ERROR; } /* read_attributes */ /* ******************************************************************************** * * FUNCTION: write_info (static) * * DESCRIPTION: Writes variable values to the netCDF file * * ARGUMENTS: (int) netCDF file id, * (MS_Variables *) variable ids data structure pointer, * (MS_Dimensions *) dimension ids data structure pointer, * (long) major dimension for array variables, * (int) number of data variables, * (char *) pointer to variable values data structure * (MS_Variable_Data *) pointer to MS_Variable_Data array * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int write_info( int cdfid, MS_Variables * varbls, MS_Dimensions * dimens, long index, int nvals, char * values, MS_Variable_Data * var_data ) #else /* __STDC__ */ static int write_info( cdfid, varbls, dimens, index, nvals, values, var_data ) int cdfid; MS_Variables * varbls; MS_Dimensions * dimens; long index; int nvals; char * values; MS_Variable_Data * var_data; #endif /* not __STDC__ */ { int i; int j; int varid; /* variable id */ long dt_count[2]; /* size of array or string */ long dt_start[2]; /* indices into hyperslab */ void * value; /* address of value to be written */ int nminor; /* Error checking: varbls, dimens, values, var_data non NULL */ if ( NULL == varbls || NULL == dimens || NULL == values || NULL == var_data ) return MS_ERROR; /* There are two cases to cover here: Case 1: If index < 0, then we are being asked to write a variable which occurs in one chunk (not on a per-scan basis, say). (1a): If it has zero dimensionality, then it is a single-valued variable. (1b): If the dimensionality is one and it is of type NC_CHAR, then it is a single character string. If it is of another type, then it represents an array of those types. (1c): If the dimensionality is two, then the only allowed type is NC_CHAR, and it represents an array of strings. (1d): Dimensionality > 2 is an error. Case 2: If index >= 0, then we are being asked to write one slab of a variable which occurs as a dimensioned array. (2a): Dimensionality zero is an error. (2b): Dimensionality one with type NC_CHAR is an error, but otherwise it represents one value of an arrayed set. (2c): Dimensionality two represents a hyperslab - either a single string or an array of numbers (such as a scan range) which varies with the major index. (2d): Dimensionality > 2 is not supported. So, all these choices make for a somewhat long and complicated bit of logic. It is further complicated by the fact that we are looping over all the fields in a data structure, and the logic must be applied separately to each member (although the indexing over major index must be the same for all elements - a data structure cannot have some elements which vary on a per-scan basis, and some which do not). */ for ( i = 0; i < nvals; i++ ) { /* loop over all data fields */ varid = *((int *)((char *)varbls + var_data[i].offset)); if ( index < 0 ) { /* case 1 */ if ( 0 == var_data[i].ndim ) { /* case 1a */ if ( NC_CHAR == var_data[i].datatype ) return MS_ERROR; /* error - strings are arrays */ /* Write a non-dimensioned variable value */ dt_start[0] = 0L; value = (void *)((char *)values + var_data[i].data_offset); if ( MS_ERROR == ncvarput1( cdfid, varid, dt_start, value ) ) return MS_ERROR; } else if ( 1 == var_data[i].ndim ) { /* case 1b */ if ( NC_CHAR == var_data[i].datatype ) { /* put a string */ dt_count[0] = ((ms_dim *)((char *)dimens + var_data[i].dim[0]))->size; if ( MS_ERROR == ms_write_string_variable( cdfid, varid, index, -1, dt_count[0], *((char * *) (values + var_data[i].data_offset)) ) ) return MS_ERROR; } else { /* put an array */ dt_start[0] = 0L; dt_count[0] = ((ms_dim *)((char *)dimens + var_data[i].dim[0]))->size; value = (void *)((char *)values + var_data[i].data_offset); if ( MS_ERROR == ncvarput( cdfid, varid, dt_start, dt_count, value ) ) return MS_ERROR; } } else if ( 2 == var_data[i].ndim ) { /* case 1c */ if ( NC_CHAR != var_data[i].datatype ) return MS_ERROR; /* error - no 2D arrays */ /* Put each string separately */ nminor = ((ms_dim *)((char *)dimens + var_data[i].dim[0]))->size; for ( j = 0; j < nminor; j++ ) { dt_count[0] = ((ms_dim *)((char *)dimens + var_data[i].dim[1]))->size; if ( MS_ERROR == ms_write_string_variable( cdfid, varid, (long)j, -1, dt_count[0], *((char * *) (values + var_data[i].data_offset) + j) ) ) return MS_ERROR; } } else /* case 1d - error */ return MS_ERROR; } /* if ( index < 0 ) */ else { /* case 2 */ if ( 0 == var_data[i].ndim ) /* case 2a - error */ return MS_ERROR; if ( 1 == var_data[i].ndim ) { /* case 2b */ if ( NC_CHAR == var_data[i].datatype ) return MS_ERROR; /* error */ dt_start[0] = (long)index; value = (void *)((char *)values + var_data[i].data_offset); if ( MS_ERROR == ncvarput1( cdfid, varid, dt_start, value ) ) return MS_ERROR; } else if ( 2 == var_data[i].ndim ) { /* case 2c */ dt_count[0] = 1L; dt_count[1] = ((ms_dim *)((char *)dimens + var_data[i].dim[1]))->size; if ( NC_CHAR == var_data[i].datatype ) { if ( MS_ERROR == ms_write_string_variable( cdfid, varid, index, -1, dt_count[1], *((char * *) (values + var_data[i].data_offset)) ) ) return MS_ERROR; } else { dt_start[0] = (long) index; dt_start[1] = 0L; value = (void *)(*((char * *)(values + var_data[i].data_offset))); if ( MS_ERROR == ncvarput( cdfid, varid, dt_start, dt_count, value ) ) return MS_ERROR; } } else /* case 2d */ return MS_ERROR; } } /* for ( i = 0; ... ) */ return MS_NO_ERROR; } /* write_info */ /* ******************************************************************************** * * FUNCTION: read_info (static) * * DESCRIPTION: Reads variable values from the netCDF file. * * ARGUMENTS: (int) netCDF file id, * (MS_Variables *) variables data structure pointer, * (MS_Dimensions *) dimensions data structure pointer, * (long) major dimension for array variables, * (int) number of data variables, * (char *) pointer to variable values data structure * (MS_Variable_Data *) pointer to MS_Variable_Data array * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int read_info( int cdfid, MS_Variables * varbls, MS_Dimensions * dimens, long index, int nvals, char * values, MS_Variable_Data * var_data ) #else /* __STDC__ */ static int read_info( cdfid, varbls, dimens, index, nvals, values, var_data ) int cdfid; MS_Variables * varbls; MS_Dimensions * dimens; long index; int nvals; char * values; MS_Variable_Data * var_data; #endif /* not __STDC__ */ { int i; long j; int varid; nc_type datatype; int nAtts; int ndim; int dim_id[3]; int isPresent; long dt_start[2]; long dt_count[2]; void * value; /* Error check: all pointers must be non-NULL; nvals > 0 */ if ( nvals <= 0 || NULL == varbls || NULL == dimens || NULL == values || NULL == var_data ) { return MS_ERROR; } /* As in writing variable values, there are two major cases: Case 1: If index < 0, we are being asked to read a variable which is non-indexed. (1a): If it has zero dimensionality, it is single-valued (and cannot be of type NC_CHAR). (1b): If it ha dimensionality one and is of type NC_CHAR, then it is a simple string, otherwise it is a numeric array. (1c): If the dimensionality is two, then it can only be of type NC_CHAR, since 2-D arrays of numerics are not supported as non-indexed variables in this implementation. (1d): Dimensionality > 2 is not supported and is an error. Case 2: If index >= 0, then we are being asked to retrieve an indexed variable. (2a): Dimensionality zero is an error. (2b): Dimensionality one with type NC_CHAR is also an error. Otherwise, it represent one numeric value of an indexed set. (2c): Dimensionality two is a hyperslab - either a single indexed string or an array of numeric values. (2d): Dimensionality > 2 is not supported and is an error. In both cases, space is allocated for strings and must be freed by the caller after use. Numeric values are copied directly into their storage locations. For values which occur as arrays, the arrays are presumed to be predefined, and the values are stored in the appropriate offsets (string pointers or numeric values). */ for ( i = 0; i < nvals; i++ ) { /* loop over all data fields */ varid = *((int *)((char *)varbls + var_data[i].offset)); /* Inquire about the variable; this is primarily to determine that the variable is present in the file. If it is not, we will assign a default value to it. */ if ( MS_ERROR == ncvarinq( cdfid, varid, (char *)0, &datatype, &ndim, dim_id, &nAtts ) ) isPresent = FALSE; else isPresent = TRUE; /* Check for datatype and dimensionality mismatch. */ if ( isPresent ) { if ( datatype != var_data[i].datatype ) { return MS_ERROR; } if ( ndim != var_data[i].ndim ) { return MS_ERROR; } } if ( index < 0 ) { /* case 1 */ if ( 0 == var_data[i].ndim ) { /* case 1a */ if ( NC_CHAR == var_data[i].datatype ) return MS_ERROR; /* error - strings are arrays */ /* Read a non-dimensioned numeric value */ if ( isPresent ) { dt_start[0] = 0L; value = (void *)((char *)values + var_data[i].data_offset); if ( MS_ERROR == ncvarget1( cdfid, varid, dt_start, value ) ) { return MS_ERROR; } } else { put_default( var_data[i].datatype, (void *) ((char *)values + var_data[i].data_offset), 0 ); } } else if ( 1 == var_data[i].ndim ) { /* case 1b */ dt_count[0] = ((ms_dim *)((char *)dimens + var_data[i].dim[0]))->size; if ( NC_CHAR == var_data[i].datatype ) { /* get a string */ *((char * *)(values + var_data[i].data_offset)) = ms_read_string_variable( cdfid, varid, index, -1, dt_count[0] ); } else { /* get an array */ if ( isPresent ) { dt_start[0] = 0L; if ( MS_ERROR == ncvarget( cdfid, varid, dt_start, dt_count, (void *)((char *)values + var_data[i].data_offset) ) ) { return MS_ERROR; } } else { /* assign default */ for ( j = 0; j < dt_count[0]; j++ ) { put_default( var_data[i].datatype, (void *)(((char *)values + var_data[i].data_offset)), j ); } } } } else if ( 2 == var_data[i].ndim ) { /* case 1c */ if ( NC_CHAR != var_data[i].datatype ) { return MS_ERROR; } /* Read an array of strings */ dt_count[0] = ((ms_dim *)((char *)dimens + var_data[i].dim[0]))->size; for ( j = 0; j < dt_count[0]; j++ ) { *((char * *)(values + var_data[i].data_offset) + j) = ms_read_string_variable( cdfid, varid, j, -1, dt_count[0] ); } } else { return MS_ERROR; /* case 1d */ } } /* if ( index < 0 ) */ else { /* case 2 */ if ( 0 == var_data[i].ndim ) /* case 2a - error */ return MS_ERROR; else if ( 1 == var_data[i].ndim ) { /* case 2b */ if ( NC_CHAR == var_data[i].datatype ) { return MS_ERROR; /* no indexed 1D strings*/ } dt_start[0] = (long) index; if ( isPresent ) { if ( MS_ERROR == ncvarget1( cdfid, varid, dt_start, (void *)((values + var_data[i].data_offset)) ) ) { return MS_ERROR; } } else { put_default ( var_data[i].datatype, (void *) ((char *)values + var_data[i].data_offset), 0 ); } } else if ( 2 == var_data[i].ndim ) { /* case 2c */ dt_count[0] = 1L; dt_count[1] = ((ms_dim *)((char *)dimens + var_data[i].dim[1]))->size; if ( NC_CHAR == var_data[i].datatype ) { *((char * *)(values + var_data[i].data_offset)) = ms_read_string_variable( cdfid, varid, index, -1, dt_count[1] ); } else { if ( isPresent ) { dt_start[0] = (long)index; dt_start[1] = 0L; value = (void *)(*((char * *)(values + var_data[i].data_offset))); if ( MS_ERROR == ncvarget( cdfid, varid, dt_start, dt_count, value ) ) { return MS_ERROR; } } else { for ( j = 0; j < dt_count[1]; j++ ) { put_default( var_data[i].datatype, (void *) ((char *)(values + var_data[i].data_offset)), j ); } } } } else { /* case 2d */ return MS_ERROR; } } /* else */ } /* for ( i = 0; ... ) */ return MS_NO_ERROR; } /* read_info */ /* ******************************************************************************** * * FUNCTION: client_index (static) * * DESCRIPTION: Looks up the index of the client in the ms_clients array given * the netCDF file id. * * ARGUMENTS: (int) netCDF id * * RETURNS: (int) client index (MS_ERROR on error) * * * * * ******************************************************************************** */ #ifdef __STDC__ static int client_index( int cdfid ) #else /* __STDC__ */ static int client_index( cdfid ) int cdfid; #endif /* not __STDC__ */ { int index; if ( NULL == ms_clients || 0 == ms_client_count ) return MS_ERROR; for ( index = 0; index < ms_client_count; index++ ) { if ( cdfid == ms_clients[index]->cdfid ) return index; } return MS_ERROR; } /* client_index */ /* ******************************************************************************** * * Exported (global) functions * ******************************************************************************** */ /* ******************************************************************************** * * FUNCTION: ms_write_dimensions * * DESCRIPTION: Creates dimension definitions in the output netCDF file * * ARGUMENTS: (int) netCDF file id, (long) number of scans, * (long) instrument component count, * * RETURNS: (int) error code (MS_ERROR if error, MS_NO_ERROR otherwise) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_dimensions( int cdfid, long nscans, long instrument_count ) #else /* __STDC__ */ int ms_write_dimensions( cdfid, nscans, instrument_count ) int cdfid; long nscans; long instrument_count; #endif /* not __STDC__ */ { int i; int index; MS_Dimensions * dims; /* Error check: nscans must be > 0 */ if ( nscans <= 0 ) return MS_ERROR; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); /* Define the dimensions in the data array first */ for ( i = 0; i < nDims; i++ ) { if ( MS_ERROR == (((ms_dim *)((char *)dims + ms_dimensions[i].offset))->id = ncdimdef( cdfid, ms_dimensions[i].name, ms_dimensions[i].size )) ) return MS_ERROR; ((ms_dim *)((char *)dims + ms_dimensions[i].offset))->size = ms_dimensions[i].size; } /* Next, define the scan_number and (if applicable) the instrument_number dimensions. */ if ( MS_ERROR == (dims->scan_number_dim.id = ncdimdef( cdfid, "scan_number", nscans )) ) return MS_ERROR; dims->scan_number_dim.size = nscans; if ( instrument_count > 0 ) { if ( MS_ERROR == (dims->instrument_number_dim.id = ncdimdef( cdfid, "instrument_number", instrument_count )) ) return MS_ERROR; dims->instrument_number_dim.size = instrument_count; } else { dims->instrument_number_dim.id = MS_ERROR; dims->instrument_number_dim.size = 0L; } return MS_NO_ERROR; } /* ms_write_dimensions */ /* ******************************************************************************** * * FUNCTION: ms_read_dimensions * * DESCRIPTION: Reads dimension definitions from the netCDF file * * ARGUMENTS: (int) netCDF file id * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_dimensions( int cdfid ) #else /* __STDC__ */ int ms_read_dimensions( cdfid ) int cdfid; #endif /* not __STDC__ */ { int i; int id; long size; int index; MS_Dimensions * dims; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); /* Read all dimensions from the dimensions array first. */ for ( i = 0; i < nDims; i++ ) { size = 0L; id = ncdimid( cdfid, ms_dimensions[i].name ); if ( -1 != id ) (void)ncdiminq( cdfid, id, (char *)0, &size ); ((ms_dim *)((char *)dims + ms_dimensions[i].offset))->id = id; ((ms_dim *)((char *)dims + ms_dimensions[i].offset))->size = size; } /* Then get the scan_number and instrument_number dimenensions */ dims->scan_number_dim.id = ncdimid( cdfid, "scan_number" ); if ( -1 != dims->scan_number_dim.id ) (void)ncdiminq( cdfid, dims->scan_number_dim.id, (char *)0, &(dims->scan_number_dim.size) ); dims->instrument_number_dim.id = ncdimid( cdfid, "instrument_number" ); if ( -1 != dims->instrument_number_dim.id ) (void)ncdiminq( cdfid, dims->instrument_number_dim.id, (char *)0, &(dims->instrument_number_dim.size) ); /* Get the scan group dimensions, if any */ dims->group_number_dim.id = ncdimid( cdfid, "group_number" ); if ( -1 != dims->group_number_dim.id ) (void) ncdiminq( cdfid, dims->group_number_dim.id, (char *)0, &(dims->group_number_dim.size) ); dims->group_max_masses_dim.id = ncdimid( cdfid, "group_max_masses" ); if ( -1 != dims->group_max_masses_dim.id ) (void) ncdiminq( cdfid, dims->group_max_masses_dim.id, (char *)0, &(dims->group_max_masses_dim.size) ); return MS_NO_ERROR; } /* ms_read_dimensions */ /* ******************************************************************************** * * FUNCTION: ms_write_variables * * DESCRIPTION: Defines all appropriate variables to the netCDF file. If * the experiment type is library, library definitions are * written. * * ARGUMENTS: (int) netCDF file id, (ms_admin_expt_t) experiment type, * (ms_data_format_t) mass format, * (ms_data_format_t) time format, * (ms_data_format_t) intensity format, * (int) TRUE if mass data is present, * (int) TRUE if time data is present (one or both of these flags * must be TRUE), * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_variables( int cdfid, ms_admin_expt_t expt_type, ms_data_format_t mass_fmt, ms_data_format_t time_fmt, ms_data_format_t intensity_fmt, int do_masses, int do_times ) #else /* __STDC__ */ int ms_write_variables( cdfid, expt_type, mass_fmt, time_fmt, intensity_fmt, do_masses, do_times ) int cdfid; ms_admin_expt_t expt_type; ms_data_format_t mass_fmt; ms_data_format_t time_fmt; ms_data_format_t intensity_fmt; int do_masses; int do_times; #endif /* not __STDC__ */ { int dim_ids[2]; nc_type datatype; int index; MS_Dimensions * dims; MS_Variables * vars; /* Error check: one or both of the flags must be TRUE */ if ( !(do_masses || do_times) ) { return MS_ERROR; } if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); ms_clients[index]->expt_type = expt_type; ms_clients[index]->mass_type = mass_fmt; ms_clients[index]->time_type = time_fmt; ms_clients[index]->inty_type = intensity_fmt; ms_clients[index]->has_masses = do_masses; ms_clients[index]->has_times = do_times; /* Write the general variable definitions */ if ( MS_ERROR == write_variables( cdfid, nError, vars, dims, error_variables ) ) return MS_ERROR; if ( MS_ERROR == write_variables( cdfid, nRawP, vars, dims, raw_variables ) ) return MS_ERROR; /* Three variables are used to keep track of the per-scan data: scan_index provides the offset into the mass, time, and intensity arrays for the start of each scan. point_count keeps a count of the number of peaks in each scan. flag_count keeps a count of the number of flags in each scan. */ dim_ids[0] = dims->scan_number_dim.id; if ( MS_ERROR == (vars->scan_index_id = ncvardef( cdfid, "scan_index", NC_LONG, 1, dim_ids )) ) return( MS_ERROR ); if ( MS_ERROR == (vars->point_count_id = ncvardef( cdfid, "point_count", NC_LONG, 1, dim_ids )) ) return( MS_ERROR ); if ( MS_ERROR == (vars->flag_count_id = ncvardef( cdfid, "flag_count", NC_LONG, 1, dim_ids )) ) return( MS_ERROR ); /* Write the mass, time, and intensity value variables. These have no predetermined data type, so must be defined at run time */ if ( do_masses ) { datatype = format_to_datatype( ms_clients[index]->mass_type, NC_SHORT ); dim_ids[0] = dims->point_number_dim.id; if ( MS_ERROR == (vars->mass_values_id = ncvardef( cdfid, "mass_values", datatype, 1, dim_ids )) ) return( MS_ERROR ); } else vars->mass_values_id = -1; if ( do_times ) { datatype = format_to_datatype( ms_clients[index]->time_type, NC_SHORT ); dim_ids[0] = dims->point_number_dim.id; if ( MS_ERROR == (vars->time_values_id = ncvardef( cdfid, "time_values", datatype, 1, dim_ids )) ) return( MS_ERROR ); } else vars->time_values_id = -1; datatype = format_to_datatype( ms_clients[index]->inty_type, NC_LONG ); dim_ids[0] = dims->point_number_dim.id; if ( MS_ERROR == (vars->intensity_values_id = ncvardef( cdfid, "intensity_values", datatype, 1, dim_ids )) ) return( MS_ERROR ); /* If appropriate, write the instrument and library variables definitions. Instrument variables are written if the instrument_number dimension id has been defined (i.e. != -1). Library variables are written if the experiment type is "expt_library". */ if ( MS_ERROR != dims->instrument_number_dim.id ) { if ( MS_ERROR == write_variables( cdfid, nInst, vars, dims, instrument_variables ) ) return MS_ERROR; } if ( expt_library == expt_type ) { if ( MS_ERROR == write_variables( cdfid, nLib, vars, dims, library_variables ) ) return MS_ERROR; } /* All done, all OK! */ return MS_NO_ERROR; } /* ms_write_variables */ /* ******************************************************************************** * * FUNCTION: ms_read_variables * * DESCRIPTION: Reads variable definitions from the netCDF file * * ARGUMENTS: (int) netCDF file id * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_variables( int cdfid ) #else /* __STDC__ */ int ms_read_variables( cdfid ) int cdfid; #endif /* not __STDC__ */ { int expt_type; int index; MS_Dimensions * dims; MS_Variables * vars; int ndims; int natts; nc_type inq_type; int dim_id[5]; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); /* Read array variables first */ if ( MS_ERROR == read_variables( cdfid, nError, vars, dims, error_variables ) ) return MS_ERROR; if ( MS_ERROR == read_variables( cdfid, nRawP, vars, dims, raw_variables ) ) return MS_ERROR; /* Read scan data variables */ vars->scan_index_id = ncvarid( cdfid, "scan_index" ); vars->point_count_id = ncvarid( cdfid, "point_count" ); vars->flag_count_id = ncvarid( cdfid, "flag_count" ); inq_type = NC_SHORT; if ( MS_ERROR != (vars->mass_values_id = ncvarid( cdfid, "mass_values" )) ) { ms_clients[index]->has_masses = TRUE; ncvarinq( cdfid, vars->mass_values_id, (char *)0, &inq_type, &ndims, dim_id, &natts ); } ms_clients[index]->mass_type = datatype_to_format( inq_type, data_short ); inq_type = NC_SHORT; if ( MS_ERROR != (vars->time_values_id = ncvarid( cdfid, "time_values" )) ) { ms_clients[index]->has_times = TRUE; ncvarinq( cdfid, vars->time_values_id, (char *)0, &inq_type, &ndims, dim_id, &natts ); } ms_clients[index]->time_type = datatype_to_format( inq_type, data_short ); inq_type = NC_LONG; if ( MS_ERROR != (vars->intensity_values_id = ncvarid( cdfid, "intensity_values" )) ) { ncvarinq( cdfid, vars->intensity_values_id, (char *)0, &inq_type, &ndims, dim_id, &natts ); } ms_clients[index]->inty_type = datatype_to_format( inq_type, data_long ); /* If the instrument_number_dim dimension has been defined, then instrument data is present in the file. Retrieve the ids for the variables. */ if ( -1 != dims->instrument_number_dim.id ) { if ( MS_ERROR == read_variables( cdfid, nInst, vars, dims, instrument_variables ) ) return MS_ERROR; } /* Check the experiment type; if it is a library type, then we need to retrieve the library variables also. */ if ( MS_ERROR == (expt_type = ms_read_enum_attribute( cdfid, NC_GLOBAL, "experiment_type" )) ) return MS_ERROR; ms_clients[index]->expt_type = (ms_admin_expt_t)expt_type; if ( expt_library == ms_clients[index]->expt_type ) { if ( MS_ERROR == read_variables( cdfid, nLib, vars, dims, library_variables ) ) return MS_ERROR; } return MS_NO_ERROR; } /* ms_read_variables */ /* ******************************************************************************** * * FUNCTION: ms_write_global * * DESCRIPTION: Writes global and local attribute values to the netCDF file * * ARGUMENTS: (int) netCDF file id, * (MS_Admin_Data *) administrative data structure pointer, * (MS_Sample_Data *) sample data structure pointer, * (MS_Test_Data *) test method data structure pointer, * (MS_Raw_Data_Global *) raw data global data structure pointer * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_global( int cdfid, MS_Admin_Data * admin_data, MS_Sample_Data * sample_data, MS_Test_Data * test_data, MS_Raw_Data_Global * raw_data ) #else /* __STDC__ */ int ms_write_global( cdfid, admin_data, sample_data, test_data, raw_data ) int cdfid; MS_Admin_Data * admin_data; MS_Sample_Data * sample_data; MS_Test_Data * test_data; MS_Raw_Data_Global * raw_data; #endif /* not __STDC__ */ { int err_code; int index; MS_Dimensions * dims; MS_Variables * vars; extern int ncopts; int saveOpts; if ( NULL == admin_data || NULL == sample_data || NULL == test_data || NULL == raw_data ) return MS_ERROR; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); /* Put the netCDF file into "define mode" (even though it may already be there). If it is already in define mode, this call returns an error, so we ignore it. */ saveOpts = ncopts; ncopts = 0; (void)ncredef( cdfid ); ncopts = saveOpts; /* The values of the first four Administrative-ID attributes are a property of the implementation revision level, and are defined as static character strings in the header file. Because of the mechanism used to initialize attribute data structures, they are loaded, written to the file, then the attribute pointers are set to NULL. This will avoid errors later when the MS_Admin_Structure is cleared. */ admin_data->dataset_completeness = ms_completeness_att; admin_data->ms_template_revision = ms_template_att; admin_data->netcdf_revision = ms_netcdf_att; admin_data->languages = ms_languages_att; err_code = write_attributes( cdfid, nAdminA, vars, admin_attributes, (char *)admin_data ); admin_data->dataset_completeness = NULL; admin_data->ms_template_revision = NULL; admin_data->netcdf_revision = NULL; admin_data->languages = NULL; if ( MS_ERROR == err_code ) return MS_ERROR; if ( MS_ERROR == write_attributes( cdfid, nSamp, vars, sample_attributes, (char *)sample_data ) ) return MS_ERROR; if ( MS_ERROR == write_attributes( cdfid, nTest, vars, test_attributes, (char *)test_data ) ) return MS_ERROR; if ( MS_ERROR == write_attributes( cdfid, nRaw, vars, raw_data_attributes, (char *)raw_data ) ) return MS_ERROR; /* Now, place the file in data mode */ saveOpts = ncopts; ncopts = 0; (void)ncendef( cdfid ); ncopts = saveOpts; /* Write out the error variable */ if ( MS_ERROR == write_info( cdfid, vars, dims, (long) -1, nError, (char *)admin_data, error_variables ) ) return MS_ERROR; return MS_NO_ERROR; } /* ms_write_global */ /* ******************************************************************************** * * FUNCTION: ms_read_global * * DESCRIPTION: Reads attribute values from the netCDF file * * ARGUMENTS: (int) netCDF file id, * (MS_Admin_data *) administrative data structure pointer, * (MS_Sample_Data *) sample data structure pointer, * (MS_Test_Data *) test method data structure pointer, * (MS_Raw_Data_Global *) raw data global data structure pointer * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_global( int cdfid, MS_Admin_Data * admin_data, MS_Sample_Data * sample_data, MS_Test_Data * test_data, MS_Raw_Data_Global * raw_data ) #else /* __STDC__ */ int ms_read_global( cdfid, admin_data, sample_data, test_data, raw_data ) int cdfid; MS_Admin_Data * admin_data; MS_Sample_Data * sample_data; MS_Test_Data * test_data; MS_Raw_Data_Global * raw_data; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; if ( NULL == admin_data || NULL == sample_data || NULL == test_data || NULL == raw_data ) return MS_ERROR; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); if ( MS_ERROR == read_attributes( cdfid, nAdminA, vars, admin_attributes, (char *)admin_data ) ) return MS_ERROR; if ( MS_ERROR == read_attributes( cdfid, nSamp, vars, sample_attributes, (char *)sample_data ) ) return MS_ERROR; if ( MS_ERROR == read_attributes( cdfid, nTest, vars, test_attributes, (char *)test_data ) ) return MS_ERROR; if ( MS_ERROR == read_attributes( cdfid, nRaw, vars, raw_data_attributes, (char *)raw_data ) ) return MS_ERROR; /* Now, read in the error variable value */ if ( MS_ERROR == read_info( cdfid, vars, dims, (long) -1, nError, (char *)admin_data, error_variables ) ) return MS_ERROR; /* Finally, put miscellaneous information into the admin_data and raw_data structures. */ raw_data->nscans = dims->scan_number_dim.size; admin_data->number_instrument_components = dims->instrument_number_dim.size; raw_data->has_masses = ms_clients[index]->has_masses; raw_data->has_times = ms_clients[index]->has_times; return MS_NO_ERROR; } /* ms_read_global */ /* ******************************************************************************** * * FUNCTION: ms_write_instrument * * DESCRIPTION: Writes the Instrument-ID information for the nth instrument * to the netCDF file. * * ARGUMENTS: (int) netCDF file id, * (MS_Instrument_Data *) instrument data structure pointer * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_instrument( int cdfid, MS_Instrument_Data * inst_data ) #else /* __STDC__ */ int ms_write_instrument( cdfid, inst_data ) int cdfid; MS_Instrument_Data * inst_data; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; if ( NULL == inst_data ) return MS_ERROR; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); if ( MS_ERROR == write_info( cdfid, vars, dims, inst_data->inst_no, nInst, (char *)inst_data, instrument_variables ) ) return MS_ERROR; return MS_NO_ERROR; } /* ms_write_instrument */ /* ******************************************************************************** * * FUNCTION: ms_read_instrument * * DESCRIPTION: Reads Instrument-ID information for the nth instrument from * the netCDF file. The MS_Instrument_Data structure field * "inst_no" must be pre-loaded with the instrument number * desired. * * ARGUMENTS: (int) netCDF file id * (MS_Instrument_Data *) instrument data structure pointer * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_instrument( int cdfid, MS_Instrument_Data * inst_data ) #else /* __STDC__ */ int ms_read_instrument( cdfid, inst_data ) int cdfid; MS_Instrument_Data * inst_data; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; if ( NULL == inst_data ) return MS_ERROR; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); if ( inst_data->inst_no >= dims->instrument_number_dim.size ) return MS_ERROR; if ( MS_ERROR == read_info( cdfid, vars, dims, inst_data->inst_no, nInst, (char *)inst_data, instrument_variables ) ) return MS_ERROR; return MS_NO_ERROR; } /* ms_read_instrument */ /* ******************************************************************************** * * FUNCTION: ms_write_per_scan * * DESCRIPTION: Writes raw and library per-scan information to the data file. * Either data stucture pointer can be NULL, in which case it * is ignored. * * ARGUMENTS: (int) netCDF file id, * (MS_Raw_Per_Scan *) raw data per scan data structure pointer * (MS_Raw_Library *) library per scan data structure pointer * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_per_scan( int cdfid, MS_Raw_Per_Scan * raw_data, MS_Raw_Library * lib_data ) #else /* __STDC__ */ int ms_write_per_scan( cdfid, raw_data, lib_data ) int cdfid; MS_Raw_Per_Scan * raw_data; MS_Raw_Library * lib_data; #endif /* not __STDC__ */ { int varid; long dt_start[2]; long dt_count[2]; void * flags; nc_type flag_type; int index; MS_Dimensions * dims; MS_Variables * vars; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); if ( raw_data ) { /* First, we write out the type-invariant data to the file. These are the fields defined in the MS_Variable_Data raw_variables array.*/ if ( MS_ERROR == write_info( cdfid, vars, dims, raw_data->scan_no, nRawP, (char *)raw_data, raw_variables ) ) return MS_ERROR; /* Next, write out the mass, time, and intensity data. For all scans in the file, either both masses and times, or only one of them may be present; in all cases, the same arrays MUST be present for all scans. NULL pointers must be passed for mass or time arrays which are not used. If there are no peaks for a given scan, then NULL pointers should be passed for all arrays, and points and flags variables set to zero.*/ /* Write out the number of points and number of flags to the point_count and flag_count arrays, respectively. */ dt_start[0] = raw_data->scan_no; if ( MS_ERROR == ncvarput1( cdfid, vars->point_count_id, dt_start, (void *)&(raw_data->points) ) ) return MS_ERROR; if ( MS_ERROR == ncvarput1( cdfid, vars->flag_count_id, dt_start, (void *)&(raw_data->flags) ) ) return MS_ERROR; /* Write out the start-of-scan index. */ if ( MS_ERROR == ncvarput1( cdfid, vars->scan_index_id, dt_start, (void *)&(ms_clients[index]->total_count) ) ) return MS_ERROR; /* Next, write out the point data; if there are no points, then we are done with this scan. */ if ( raw_data->points > 0L ) { dt_start[0] = ms_clients[index]->total_count; /* offset of this scan */ dt_count[0] = raw_data->points; /* number of points */ if ( MS_ERROR == ncvarput( cdfid, vars->intensity_values_id, dt_start, dt_count, (void *) raw_data->intensities ) ) return MS_ERROR; if ( raw_data->masses && ms_clients[index]->has_masses ) { if ( MS_ERROR == ncvarput( cdfid, vars->mass_values_id, dt_start, dt_count, (void *)raw_data->masses ) ) return MS_ERROR; } if ( raw_data->times && ms_clients[index]->has_times ) { if ( MS_ERROR == ncvarput( cdfid, vars->time_values_id, dt_start, dt_count, (void *)raw_data->times ) ) return MS_ERROR; } /* Update point count */ ms_clients[index]->total_count += raw_data->points; if ( raw_data->flags > 0L ) { dt_start[0] = ms_clients[index]->total_count; /* offset of flags */ dt_count[0] = raw_data->flags; /* number of flags */ /* If masses array is present, then tack flag_peaks onto the end of the masses array; otherwise, stick it onto the times */ if ( raw_data->masses ) { varid = vars->mass_values_id; flag_type = format_to_datatype( ms_clients[index]->mass_type, NC_SHORT ); } else { varid = vars->time_values_id; flag_type = format_to_datatype( ms_clients[index]->time_type, NC_SHORT ); } /* Make a temporary array (if required) to effect the cast from NC_LONG to whatever the flag type is in the file. If the flag type is already NC_LONG, then do not make a copy. */ if ( flag_type != NC_LONG ) { if ( NULL == (flags = make_array( raw_data->flags, flag_type )) ) return MS_ERROR; ms_copy_array( raw_data->flag_peaks, data_long, raw_data->flags, flags, datatype_to_format( flag_type, data_long ), FALSE ); } else flags = raw_data->flag_peaks; if ( MS_ERROR == ncvarput( cdfid, varid, dt_start, dt_count, (void *)flags ) ) { if ( flag_type != NC_LONG ) free( flags ); return MS_ERROR; } if ( flag_type != NC_LONG ) free( flags ); /* Stick the flags onto the end of the intensities array */ if ( ms_clients[index]->inty_type != data_short ) { if ( NULL == (flags = make_array( raw_data->flags, format_to_datatype( ms_clients[index]->inty_type, NC_SHORT ) )) ) return MS_ERROR; ms_copy_array( raw_data->flag_values, data_short, raw_data->flags, flags, ms_clients[index]->inty_type, FALSE ); } else flags = raw_data->flag_values; if ( MS_ERROR == ncvarput( cdfid, vars->intensity_values_id, dt_start, dt_count, (void *)flags ) ) { if ( ms_clients[index]->inty_type != data_short ) free( flags ); return MS_ERROR; } if ( ms_clients[index]->inty_type != data_short ) free( flags ); /* Update total point count to reflect addition of flags. */ ms_clients[index]->total_count += raw_data->flags; } /* if ( raw_data->flags > 0L ) */ } /* if (raw_data->points > 0L ) */ } /* if ( raw_data ) */ /* Write out library data, if present */ if ( lib_data && (expt_library == ms_clients[index]->expt_type) ) { if ( MS_ERROR == write_info( cdfid, vars, dims, lib_data->scan_no, nLib, (char *)lib_data, library_variables ) ) return MS_ERROR; } return MS_NO_ERROR; } /* ms_write_per_scan */ /* ******************************************************************************** * * FUNCTION: ms_read_per_scan * * DESCRIPTION: Reads raw and library per-scan data from the netCDF file. If * a NULL pointer is passed in for either data structure, that * data type will be ignored. * * ARGUMENTS: (int) netCDF file id, * (MS_Raw_Per_Scan *) raw data per-scan data structure pointer * (MS_Reaw_Library *) library per-scan data structure pointer * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_per_scan( int cdfid, MS_Raw_Per_Scan * raw_data, MS_Raw_Library * lib_data ) #else /* __STDC__ */ int ms_read_per_scan( cdfid, raw_data, lib_data ) int cdfid; MS_Raw_Per_Scan * raw_data; MS_Raw_Library * lib_data; #endif /* not __STDC__ */ { long scan_index; long dt_start[3]; long dt_count[3]; nc_type mass_type; nc_type time_type; nc_type inty_type; nc_type flag_type = NC_LONG; /* to keep lint happy */ int flag_id; int index; MS_Dimensions * dims; MS_Variables * vars; void * flags; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); flag_id = vars->time_values_id; /* also for lint */ mass_type = format_to_datatype( ms_clients[index]->mass_type, NC_SHORT ); time_type = format_to_datatype( ms_clients[index]->time_type, NC_SHORT ); inty_type = format_to_datatype( ms_clients[index]->inty_type, NC_LONG ); if ( raw_data ) { /* Retrieve the type-invariant data from the file */ if ( MS_ERROR == read_info( cdfid, vars, dims, raw_data->scan_no, nRawP, (char *)raw_data, raw_variables ) ) { return MS_ERROR; } /* Next, retrieve the mass, time, and intensity data. Because this is of variable type, we have to create arrays of the apropriate type to return to the caller. */ /* First, get the scan offset, point count, and flag count */ dt_start[0] = raw_data->scan_no; if ( MS_ERROR == ncvarget1( cdfid, vars->scan_index_id, dt_start, (void *)&scan_index ) ) { return MS_ERROR; } if ( MS_ERROR == ncvarget1( cdfid, vars->point_count_id, dt_start, (void *)&(raw_data->points) ) ) { return MS_ERROR; } if ( MS_ERROR == ncvarget1( cdfid, vars->flag_count_id, dt_start, (void *)&(raw_data->flags) ) ) { return MS_ERROR; } /* Do some initialization */ raw_data->masses = NULL; raw_data->times = NULL; raw_data->intensities = NULL; raw_data->flag_peaks = NULL; raw_data->flag_values = NULL; /* If no points, then we simply return the NULL arrays */ if ( raw_data->points > 0 ) { /* Allocate mass, time and intensity arrays, then read in the data */ dt_start[0] = scan_index; dt_count[0] = raw_data->points; if ( ms_clients[index]->has_times ) { flag_type = format_to_datatype( ms_clients[index]->time_type, NC_SHORT ); flag_id = vars->time_values_id; if ( NULL == (raw_data->times = make_array( raw_data->points, time_type )) ) return MS_ERROR; if ( MS_ERROR == ncvarget( cdfid, vars->time_values_id, dt_start, dt_count, raw_data->times ) ) return MS_ERROR; } if ( ms_clients[index]->has_masses ) { flag_type = mass_type; /* Note: may override previous type */ flag_id = vars->mass_values_id; if ( NULL == (raw_data->masses = make_array( raw_data->points, mass_type )) ) return MS_ERROR; if ( MS_ERROR == ncvarget( cdfid, vars->mass_values_id, dt_start, dt_count, raw_data->masses ) ) return MS_ERROR; } if ( NULL == (raw_data->intensities = make_array( raw_data->points, inty_type )) ) return MS_ERROR; if ( MS_ERROR == ncvarget( cdfid, vars->intensity_values_id, dt_start, dt_count, raw_data->intensities ) ) return MS_ERROR; /* Retrieve the flags, if any. If masses are present, the type of the flag_peaks is the same as that of the masses; otherwise it is the same as that of the times. The type of flag_values is always the same as that of the intensities. */ if ( raw_data->flags > 0 ) { dt_start[0] = scan_index + raw_data->points; dt_count[0] = raw_data->flags; if ( NULL == (raw_data->flag_peaks = (long *) make_array( raw_data->flags, NC_LONG )) ) return MS_ERROR; if ( NULL == (flags = make_array( raw_data->flags, flag_type )) ) return MS_ERROR; if ( MS_ERROR == ncvarget( cdfid, flag_id, dt_start, dt_count, flags ) ) { free( flags ); return MS_ERROR; } ms_copy_array( flags, datatype_to_format( flag_type, data_long ), raw_data->flags, raw_data->flag_peaks, data_long, FALSE ); free( flags ); if ( NULL == (raw_data->flag_values = (short *) make_array( raw_data->flags, NC_SHORT )) ) return MS_ERROR; if ( NULL == (flags = make_array( raw_data->flags, inty_type )) ) return MS_ERROR; if ( MS_ERROR == ncvarget( cdfid, vars->intensity_values_id, dt_start, dt_count, flags ) ) { free( flags ); return MS_ERROR; } ms_copy_array( flags, datatype_to_format( inty_type, data_short ), raw_data->flags, raw_data->flag_values, data_short, FALSE ); free( flags ); } /* if ( raw_data->flags > 0 ) */ } /* if( raw_data->points > 0 ) */ } /* if ( raw_data ) */ /* Retrieve library per-scan data if pointer is non-NULL */ if ( lib_data && (expt_library == ms_clients[index]->expt_type) ) { if ( MS_ERROR == read_info( cdfid, vars, dims, lib_data->scan_no, nLib, (char *)lib_data, library_variables ) ) return MS_ERROR; } return MS_NO_ERROR; } /* ms_read_per_scan */ /* ******************************************************************************** * * FUNCTION: ms_read_TIC * * DESCRIPTION: A convenience function to read the total ion chromatogram. The * netCDF file must have been opened using ms_open_read(), and * the global information must have been read in (using * ms_read_global()) prior to calling this function. The TIC * arrays returned by this function are new memory, and must be * freed by the caller (using free()) after use. * * ARGUMENTS: (int) netCDF file id, (long *) number of points in TIC, * (double * *) array of TIC values, (double * *) array of * TIC times * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_TIC( int cdfid, long * nTic, double * * tic, double * * rTime ) #else /* __STDC__ */ int ms_read_TIC( cdfid, nTic, tic, rTime ) int cdfid; long * nTic; double * * tic; double * * rTime; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; long dt_start[2]; long dt_count[2]; /* Some error checking */ if ( NULL == nTic || NULL == tic || NULL == rTime ) return MS_ERROR; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; /* Get the number of scans (same as number of TIC points) */ dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); *nTic = dims->scan_number_dim.size; /* Make the array to return the TIC values */ if ( NULL == (*tic = (double *)make_array( *nTic, NC_DOUBLE )) ) { *nTic = 0L; return MS_ERROR; } /* Make the array to hold the retention time values */ if ( NULL == (*rTime = (double *)make_array( *nTic, NC_DOUBLE )) ) { free( *tic ); *nTic = 0L; *tic = NULL; return MS_ERROR; } /* Now read in the TIC values. Set up for hyperslab access, then read them in. */ dt_start[0] = 0L; /* start with first point */ dt_count[0] = *nTic; if ( MS_ERROR == ncvarget( cdfid, vars->total_intensity_id, dt_start, dt_count, (void *)(*tic) ) ) { free( *tic ); free( *rTime ); *tic = NULL; *rTime = NULL; *nTic = 0L; return MS_ERROR; } if ( MS_ERROR == ncvarget( cdfid, vars->scan_acquisition_time_id, dt_start, dt_count, (void *)(*rTime) ) ) { free( *tic ); free( *rTime ); *tic = NULL; *rTime = NULL; *nTic = 0L; return MS_ERROR; } return MS_NO_ERROR; } /* ms_read_TIC */ /* ******************************************************************************** * * FUNCTION: ms_write_group_global * * DESCRIPTION: Writes scan group global information. * * ARGUMENTS: (int) netCDF file id, (long) number of scan groups, * (long) maximum number of masses in a group * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_group_global( int cdfid, long nGroups, long maxGroup ) #else /* __STDC__ */ int ms_write_group_global( cdfid, nGroups, maxGroup ) int cdfid; long nGroups; long maxGroup; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; extern int ncopts; int saveOpts; /* Error checking */ if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; if ( nGroups < 1 || maxGroup < 1 ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); /* Put the netCDF file into "define mode". Ignore any error, since the file might already be in define mode and we have no way to detect it */ saveOpts = ncopts; ncopts = 0; (void)ncredef( cdfid ); ncopts = saveOpts; /* Define the dimensions */ if ( MS_ERROR == (dims->group_number_dim.id = ncdimdef( cdfid, "group_number", nGroups )) ) return MS_ERROR; dims->group_number_dim.size = nGroups; if ( MS_ERROR == (dims->group_max_masses_dim.id = ncdimdef( cdfid, "group_max_masses", maxGroup )) ) return MS_ERROR; dims->group_max_masses_dim.size = maxGroup; /* Define the variables */ if ( MS_ERROR == write_variables( cdfid, nGroupP, vars, dims, group_variables ) ) return MS_ERROR; /* Return to "data mode" */ saveOpts = ncopts; ncopts = 0; (void)ncendef( cdfid ); ncopts = saveOpts; return MS_NO_ERROR; } /* ms_write_group_global */ /* ******************************************************************************** * * FUNCTION: ms_read_group_global * * DESCRIPTION: "Reads" scan group dimensions. These were, in fact, cached * during the call to ms_read_dimensions() (during ms_open_read()), * so this function simply checks to see if the dimension ids are * valid and fills the return variables if so. * * ARGUMENTS: (int) netCDF file id, (long *) number og groups, * (long *) maximum number of masses in any group * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_group_global( int cdfid, long * nGroups, long * maxGroup ) #else /* __STDC__ */ int ms_read_group_global( cdfid, nGroups, maxGroup ) int cdfid; long * nGroups; long * maxGroup; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; /* Do some error checking */ if ( NULL == nGroups || NULL == maxGroup ) return MS_ERROR; if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); /* Initialize the return variables. If dimensions are not defined for group information, then this is not an error, but simply indication that no group information is present in the file. If dimensions are defined, pass their sizes back in the calling arguments. */ *nGroups = 0L; *maxGroup = 0L; if ( -1 == dims->group_number_dim.id || -1 == dims->group_max_masses_dim.id ) return MS_NO_ERROR; *nGroups = dims->group_number_dim.size; *maxGroup = dims->group_max_masses_dim.size; /* Read variables ids */ if ( MS_ERROR == read_variables( cdfid, nGroupP, vars, dims, group_variables ) ) return MS_ERROR; return MS_NO_ERROR; } /* ms_read_group_global */ /* ******************************************************************************** * * FUNCTION: ms_write_per_group * * DESCRIPTION: Writes per-scan-group data to the netCDF file. * * ARGUMENTS: (int) netCDF file id, (MS_Raw_Per_Group *) per-group data * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_write_per_group( int cdfid, MS_Raw_Per_Group * group_data ) #else /* __STDC__ */ int ms_write_per_group( cdfid, group_data ) int cdfid; MS_Raw_Per_Group * group_data; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; /* Error checking: must be a valid client, data structure must be valid, and must have an appropriate group number. */ if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; if ( NULL == group_data ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); if ( group_data->group_no >= dims->group_number_dim.size ) return MS_ERROR; /* Write it out */ if ( MS_ERROR == write_info( cdfid, vars, dims, group_data->group_no, nGroupP, (char *)group_data, group_variables ) ) return MS_ERROR; return MS_NO_ERROR; } /* ms_write_per_group */ /* ******************************************************************************** * * FUNCTION: ms_read_per_group * * DESCRIPTION: Reads per-scan-group data from the file. The data arrays are * allocated during this call and must be freed by the caller after * use. The arrays are allocated to the maximum group size; * however, only the number of elements corresponding to the * actual number of masses in the group is used. The remainder * are set to the default value. The "group_no" member of the * MS_Raw_Per_Group structure must be set to the desired group * number prior to the call. * * ARGUMENTS: (int) netCDF file id, (MS_Raw_Per_Group *) group data * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_read_per_group( int cdfid, MS_Raw_Per_Group * group_data ) #else /* __STDC__ */ int ms_read_per_group( cdfid, group_data ) int cdfid; MS_Raw_Per_Group * group_data; #endif /* not __STDC__ */ { int index; MS_Dimensions * dims; MS_Variables * vars; long maxGroup; long j; /* Error checking: must be a valid client, data structure must be valid, and must have an appropriate group number. */ if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; if ( NULL == group_data ) return MS_ERROR; dims = &(ms_clients[index]->dims); vars = &(ms_clients[index]->vars); if ( group_data->group_no >= dims->group_number_dim.size ) return MS_ERROR; /* Create the data arrays */ maxGroup = dims->group_max_masses_dim.size; if ( NULL == (group_data->masses = (double *)malloc( maxGroup * sizeof( double ) )) ) return MS_ERROR; if ( NULL == (group_data->sampling_times = (double *)malloc( maxGroup * sizeof( double ) )) ) { free( group_data->masses ); group_data->masses = NULL; return MS_ERROR; } if ( NULL == (group_data->delay_times = (double *)malloc( maxGroup * sizeof( double ) )) ) { free( group_data->masses ); free( group_data->sampling_times ); group_data->masses = NULL; group_data->sampling_times = NULL; return MS_ERROR; } /* Read in the group */ if ( MS_ERROR == read_info( cdfid, vars, dims, group_data->group_no, nGroupP, (char *)group_data, group_variables ) ) { free( group_data->masses ); free( group_data->sampling_times ); free( group_data->delay_times ); group_data->masses = NULL; group_data->sampling_times = NULL; group_data->delay_times = NULL; group_data->mass_count = 0L; return MS_ERROR; } for ( j = group_data->mass_count; j < maxGroup; j++ ) { group_data->masses[j] = MS_NULL_FLT; group_data->sampling_times[j] = MS_NULL_FLT; group_data->delay_times[j] = MS_NULL_FLT; } return MS_NO_ERROR; } /* ms_read_per_group */ /* ******************************************************************************** * * FUNCTION: ms_init_global * * DESCRIPTION: Initializes (and optionally clears) attribute data structures * to default values. * NULL pointers to structures are ignored. * * If the clear flag is TRUE, then non-NULL character string * attribute values are freed (since these are assumed to be * allocated memory), then set to NULL. * * ARGUMENTS: (int) clear flag * (MS_Admin_Data *) administrative data structure pointer, * (MS_Sample_Data *) sample data structure pointer * (MS_Test_Data *) test method data structure pointer * (MS_Raw_Data_Global *) raw data global data structure pointer * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ void ms_init_global( int clear, MS_Admin_Data * admin_data, MS_Sample_Data * sample_data, MS_Test_Data * test_data, MS_Raw_Data_Global * raw_data ) #else /* __STDC__ */ void ms_init_global( clear, admin_data, sample_data, test_data, raw_data ) int clear; MS_Admin_Data * admin_data; MS_Sample_Data * sample_data; MS_Test_Data * test_data; MS_Raw_Data_Global * raw_data; #endif /* not __STDC__ */ { if ( admin_data ) init_attributes( (char *)admin_data, nAdminA, admin_attributes, clear ); if ( sample_data ) init_attributes( (char *)sample_data, nSamp, sample_attributes, clear ); if ( test_data ) init_attributes( (char *)test_data, nTest, test_attributes, clear ); if ( raw_data ) init_attributes( (char *)raw_data, nRaw, raw_data_attributes, clear ); } /* ms_init_global */ /* ******************************************************************************** * * FUNCTION: ms_init_instrument * * DESCRIPTION: Initializes (and optionally clears) instrument variables * * ARGUMENTS: (int) clear flag, * (MS_Instrument_Data *) instrument data structure pointer * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ void ms_init_instrument( int clear, MS_Instrument_Data * inst_data ) #else /* __STDC__ */ void ms_init_instrument( clear, inst_data ) int clear; MS_Instrument_Data * inst_data; #endif /* not __STDC__ */ { if ( inst_data ) init_indexed_variables( (char *)inst_data, nInst, instrument_variables, clear ); return; } /* ms_init_instrument */ /* ******************************************************************************** * * FUNCTION: ms_init_per_scan * * DESCRIPTION: Initializes (and optionally clears) raw and library per scan * data structures. If either data structure pointer is NULL, * that structure is ignored. * * ARGUMENTS: (int) clear flag, * (MS_Raw_Per_Scan *) raw per scan data structure * pointer, (MS_Raw_Library *) library per scan data structure * pointer * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ void ms_init_per_scan( int clear, MS_Raw_Per_Scan * raw_data, MS_Raw_Library * lib_data ) #else /* __STDC__ */ void ms_init_per_scan( clear, raw_data, lib_data ) int clear; MS_Raw_Per_Scan * raw_data; MS_Raw_Library * lib_data; #endif /* not __STDC__ */ { if ( raw_data ) { init_indexed_variables( (char *)raw_data, nRawP, raw_variables, clear ); raw_data->scan_no = -1L; raw_data->points = 0L; raw_data->flags = 0L; if ( clear && raw_data->masses ) free( raw_data->masses ); raw_data->masses = NULL; if ( clear && raw_data->times ) free( raw_data->times ); raw_data->times = NULL; if ( clear && raw_data->intensities ) free( raw_data->intensities ); raw_data->intensities = NULL; if ( clear && raw_data->flag_peaks ) free( raw_data->flag_peaks ); raw_data->flag_peaks = NULL; if ( clear && raw_data->flag_values ) free( raw_data->flag_values ); raw_data->flag_values = NULL; } if ( lib_data ) { init_indexed_variables( (char *)lib_data, nLib, library_variables, clear ); lib_data->scan_no = -1L; } return; } /* ms_init_per_scan */ /* ******************************************************************************** * * FUNCTION: ms_init_per_group * * DESCRIPTION: Initializes (and optionally clears) per-scan-group data * * ARGUMENTS: (int) clear flag, (MS_Raw_Per_Group *) group data * * RETURNS: (void) * * * * * ******************************************************************************** */ #ifdef __STDC__ void ms_init_per_group( int clear, MS_Raw_Per_Group * group_data ) #else /* __STDC__ */ void ms_init_per_group( clear, group_data ) int clear; MS_Raw_Per_Group * group_data; #endif /* not __STDC__ */ { if ( group_data ) { if ( clear ) { if ( group_data->masses ) free( group_data->masses ); if ( group_data->sampling_times ) free( group_data->sampling_times ); if ( group_data->delay_times ) free( group_data->delay_times ); } group_data->group_no = (long)MS_NULL_INT; group_data->mass_count = (long)MS_NULL_INT; group_data->starting_scan = (long)MS_NULL_INT; group_data->masses = NULL; group_data->sampling_times = NULL; group_data->delay_times = NULL; } return; } /* ms_init_per_group */ /* ******************************************************************************** * * FUNCTION: ms_associate_id * * DESCRIPTION: Associates a netCDF id with internal data structures * * ARGUMENTS: (int) netCDF id * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_associate_id( int cdfid ) #else /* __STDC__ */ int ms_associate_id( cdfid ) int cdfid; #endif /* not __STDC__ */ { int index; /* First, look up the netCDF id. If it is a duplicate, do nothing. */ if ( MS_ERROR != client_index( cdfid ) ) return MS_NO_ERROR; /* It must be unique, so extend the clients array, then make a new client data structure. */ if ( ms_client_count ) { if ( NULL == (ms_clients = (MS_Client_Data * *) realloc( (void *)ms_clients, (unsigned int)(ms_client_count + 1) * sizeof( MS_Client_Data *) )) ) return MS_ERROR; } else { if ( NULL == (ms_clients = (MS_Client_Data * *) malloc( sizeof( MS_Client_Data *) )) ) return MS_ERROR; } index = ms_client_count; if ( NULL == (ms_clients[index] = (MS_Client_Data *) malloc( sizeof( MS_Client_Data ) )) ) return MS_ERROR; ms_client_count++; ms_clients[index]->cdfid = cdfid; ms_clients[index]->mass_type = data_short; ms_clients[index]->time_type = data_short; ms_clients[index]->inty_type = data_long; ms_clients[index]->has_masses = FALSE; ms_clients[index]->has_times = FALSE; ms_clients[index]->total_count = 0L; return MS_NO_ERROR; } /* ms_associate_id */ /* ******************************************************************************** * * FUNCTION: ms_dissociate_id * * DESCRIPTION: Removes the association between a netCDF id and internal data * structures. Frees all allocated storage. * * ARGUMENTS: (int) netCDF id * * RETURNS: (int) error code (MS_ERROR / MS_NO_ERROR) * * * * * ******************************************************************************** */ #ifdef __STDC__ int ms_dissociate_id( int cdfid ) #else /* __STDC__ */ int ms_dissociate_id( cdfid ) int cdfid; #endif /* not __STDC__ */ { int index; int i; /* Do a lookup - if not found, that is an error */ if ( MS_ERROR == (index = client_index( cdfid )) ) return MS_ERROR; /* Free the data structure */ free( ms_clients[index] ); /* Compact the array */ for ( i = index; i < ms_client_count - 1; i++ ) ms_clients[i] = ms_clients[i+1]; ms_client_count--; if ( ms_client_count ) { if ( NULL == (ms_clients = (MS_Client_Data * *)realloc( (void *) ms_clients, (unsigned int)ms_client_count * sizeof( MS_Client_Data * ) )) ) return MS_ERROR; } else ms_clients = NULL; return MS_NO_ERROR; } /* ms_dissociate_id */