; Generic routine to produce PDS4-compliant CDF files. ; ARGUMENTS: ; ; STRUCT: an array of structures. Rules concerning 'Struct': ; 1) The number of elements in 'struct' must be equal to the number of timestamps. ; 2) Each element in the array correspond to a single timestamp. In other words, there can be no "ancillary" ; data that is relevant to all the data in the file unless it is repeated for every timestamp. ; For example, an energy table must be repeated N times if there are N elements in 'struct' ; 3) Each of the tags in 'struct' will become a CDF variable name in the output file. ; 4) 'struct' must have the following tags: Time_MET (mission elapsed time) and Time_UNIX ; 5) The rest of the tags can have any name. ; ; UNITS: an array of strings with the same number of elements as tags in 'struct', expressing the physical units in which each variable is represented ; DESCRIPTION: an array of strings with the same number of elements as tags in 'struct'describing explicitly in words what each variable is ; KEYWORDS: none are mandatory for the program to run aand make a PDS-compliant file. ; However, this is where all the descriptive information goes. ; DISPLAY_RANGE: This is a 2 x N_tags-element array (where N_tags is the number of tags in 'struct') of minimum and maximum values that should be displayed. ; Certain web interfaces such as CDA-web use this information for auto plotting. ; If this keyword is not set (or if the minimum or maximum for a given tag is a NaN), ; then the minimum and maximum are set to the nearest factor of 10 either positive or negative, whichever is appropriate. ; FILE: this is the output CDF file name you want, including the path. ; ; The remainder of the keywords are best described by the default values shown below (pertaining to the MAVEN SEP instrument) ; ; pro mvn_pf_make_cdf, struct, units, description, display_range = display_range, $ file = file,$ title = title, $ project = project, $ mission = mission, $ discipline = discipline, $ descriptor = descriptor, $ data_type = data_type,$ data_version = data_version, $ experiment_description = experiment_description, $ software_revision = software_revision, $ logical_source = logical_source, $ logical_source_description = logical_source_description, $ Instrument_lead_name = instrument_lead_name, $ Instrument_lead_affiliation = instrument_lead_affiliation, $ Instrument_type = instrument_type, $ mission_group = mission_group, $ Parent_CDF_files = parent_CDF_files,$ HTTP_LINK = HTTP_LINK, $ LINK_TEXT = LINK_TEXT, $ LINK_TITLE = LINK_TITLE if not keyword_set(file) then file = 'test.cdf' If not keyword_set (title) then title = 'MAVEN SEP ion spectra' If not keyword_set (project) then project = 'MAVEN' ;; Just in case the mission name is different from the project name. If not keyword_set (mission) then mission = project If not keyword_set (discipline) then discipline = 'Planetary Science>Planetary Plasma Interactions' If not keyword_set (descriptor) then descriptor = 'SEP> Solar Energetic Particle Instrument' If not keyword_set (data_type) then data_type = 'Level 2' If not keyword_set (data_version) then data_version= '1' If not keyword_set (experiment_description) then experiment_description = 'MAVEN SEP energetic electron and ion fluxes' if not keyword_set (software_revision) then software_revision = 'Revision 0' ; This is the logical source identifier in the SIS If not keyword_set (logical_source) then logical_source = 'sep.calibrated.ion_spec_svy' ;; This is a full-word description of logical source identifier in the SIS If not keyword_set (logical_source_description) then logical_source_description = $ 'DERIVED FROM: MAVEN SEP (Solar Energetic Particle) ion spectra in 4 look directions' If not keyword_set (instrument_lead_name) then instrument_lead_name = 'Davin Larson (davin@ssl.berkeley.edu)' If not keyword_set (instrument_lead_affiliation) then $ instrument_lead_affiliation = 'UC Berkeley Space Sciences Laboratory' If not keyword_set (instrument_type) then instrument_type = 'Energetic Particle Detector' If not keyword_set (mission_group) then mission_group = 'MAVEN' If not keyword_set (parent_CDF_files) then parent_CDF_files = 'None' If not keyword_set (HTTP_LINK) then HTTP_LINK = 'http://lasp.colorado.edu/home/maven/' If not keyword_set (LINK_TEXT) then LINK_TEXT = 'General Information about the MAVEN mission' If not keyword_set (LINK_TITLE) then LINK_TITLE = 'MAVEN homepage' cdf_leap_second_init date_range = time_double(['2013-11-18/00:00','2040-12-31/23:59']) met_range = time_double('2040-12-31/23:59') - time_double('2013-11-18/00:00') epoch_range = time_epoch(date_range) tt2000_range = long64((add_tt2000_offset(date_range)-time_double('2000-01-01/12:00'))*1e9) epoch = time_epoch(struct.time_UNIX) timett2000 = long64((add_tt2000_offset(struct.time_unix)-time_double('2000-01-01/12:00'))*1e9) fileid = cdf_create(file,/single_file,/network_encoding,/clobber) id0 = cdf_attcreate(fileid,'Title',/global_scope) id1 = cdf_attcreate(fileid,'Project',/global_scope) id2 = cdf_attcreate(fileid,'Discipline',/global_scope) id3 = cdf_attcreate(fileid,'Source_name',/global_scope) id4 = cdf_attcreate(fileid,'Descriptor',/global_scope) id5 = cdf_attcreate(fileid,'Data_type',/global_scope) id6 = cdf_attcreate(fileid,'Data_version',/global_scope) id7 = cdf_attcreate(fileid,'TEXT',/global_scope) id8 = cdf_attcreate(fileid,'Mods',/global_scope) id9 = cdf_attcreate(fileid,'Logical_file_id',/global_scope) id10 = cdf_attcreate(fileid,'Logical_source',/global_scope) id11 = cdf_attcreate(fileid,'Logical_source_description',/global_scope) id12 = cdf_attcreate(fileid,'PI_name',/global_scope) id13 = cdf_attcreate(fileid,'PI_affiliation',/global_scope) id14 = cdf_attcreate(fileid,'Instrument_type',/global_scope) id15 = cdf_attcreate(fileid,'Mission_group',/global_scope) id16 = cdf_attcreate(fileid,'Parents',/global_scope) id17 = cdf_attcreate(fileid,'HTTP_LINK',/global_scope) id18 = cdf_attcreate(fileid,'LINK_TEXT',/global_scope) id19 = cdf_attcreate(fileid,'LINK_TITLE',/global_scope) cdf_attput,fileid,'Title',0, title cdf_attput,fileid,'Project',0,project cdf_attput,fileid,'Discipline',0,discipline cdf_attput,fileid,'Source_name',0,mission cdf_attput,fileid,'Descriptor',0,descriptor cdf_attput,fileid,'Data_type',0,data_type cdf_attput,fileid,'Data_version',0,data_version cdf_attput,fileid,'TEXT',0,experiment_description cdf_attput,fileid,'Mods',0,software_revision cdf_attput,fileid,'Logical_file_id',0,file cdf_attput,fileid,'Logical_source',0,logical_source cdf_attput,fileid,'Logical_source_description',0,logical_source_description cdf_attput,fileid,'PI_name',0,instrument_lead_name cdf_attput,fileid,'PI_affiliation',0,instrument_lead_affiliation cdf_attput,fileid,'Instrument_type',0,instrument_type cdf_attput,fileid,'Mission_group',0,mission_group cdf_attput,fileid,'Parents',0,parent_CDF_files cdf_attput,fileid,'HTTP_LINK',0,HTTP_LINK cdf_attput,fileid,'LINK_TEXT',0,LINK_TEXT cdf_attput,fileid,'LINK_TITLE',0,LINK_TITLE dummy = cdf_attcreate(fileid,'FIELDNAM',/variable_scope) ; description of the variable dummy = cdf_attcreate(fileid,'MONOTON',/variable_scope) ; monotonicity of the variable dummy = cdf_attcreate(fileid,'FORMAT',/variable_scope) dummy = cdf_attcreate(fileid,'FORM_PTR',/variable_scope) dummy = cdf_attcreate(fileid,'LABLAXIS',/variable_scope) dummy = cdf_attcreate(fileid,'VAR_TYPE',/variable_scope) dummy = cdf_attcreate(fileid,'FILLVAL',/variable_scope) dummy = cdf_attcreate(fileid,'DEPEND_0',/variable_scope) dummy = cdf_attcreate(fileid,'DISPLAY_TYPE',/variable_scope) dummy = cdf_attcreate(fileid,'VALIDMIN',/variable_scope) dummy = cdf_attcreate(fileid,'VALIDMAX',/variable_scope) dummy = cdf_attcreate(fileid,'SCALEMIN',/variable_scope) dummy = cdf_attcreate(fileid,'SCALEMAX',/variable_scope) dummy = cdf_attcreate(fileid,'UNITS',/variable_scope) dummy = cdf_attcreate(fileid,'CATDESC',/variable_scope) ;variable_list = ['Epoch','Time_TT2000','Time_MET','Time_Unix','Atten_State','Grouping','Num_Accum','Counts','Diff_En_Fluxes'] Variable_list = strlowcase(tag_names (struct)) nvars = n_elements(variable_list) nrec = n_elements(struct) if n_elements (units) ne n_tags (struct) then message, $ 'The number of elements in Units mmust be equal to the number of variables in struct' ; Due to specific keywords, we have to do all of the making for these two before going on to the other the variables. n_dimension = size (Epoch,/n_dimensions) Dim = reform (size (epoch,/dimension)) dim_vary = replicate (1, n_dimension) variable_ID = $ cdf_varcreate(fileid, 'Epoch',dim_vary, $ /CDF_EPOCH, /REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT','Epoch','F17.7',/ZVARIABLE cdf_attput,fileid,'FIELDNAM','Epoch','Epoch',/ZVARIABLE cdf_attput,fileid,'LABLAXIS','Epoch','Epoch',/ZVARIABLE cdf_attput,fileid,'VAR_TYPE','Epoch','data',/ZVARIABLE cdf_attput,fileid,'FILLVAL','Epoch',-1.0e31,/ZVARIABLE cdf_attput,fileid,'DISPLAY_TYPE','Epoch','time_series',/ZVARIABLE cdf_attput,fileid,'VALIDMIN','Epoch',epoch_range[0],/ZVARIABLE cdf_attput,fileid,'VALIDMAX','Epoch',epoch_range[1],/ZVARIABLE cdf_attput,fileid,'SCALEMIN','Epoch',epoch[0],/ZVARIABLE cdf_attput,fileid,'SCALEMAX','Epoch',epoch[nrec-1],/ZVARIABLE cdf_attput,fileid,'UNITS','Epoch','ms',/ZVARIABLE cdf_attput,fileid,'MONOTON','Epoch','INCREASE',/ZVARIABLE cdf_attput,fileid,'CATDESC','Epoch','Time, start of sample, in NSSDC Epoch',/ZVARIABLE cdf_varput,fileid,'Epoch',epoch variable_id = $ cdf_varcreate(fileid,'Time_TT2000',dim_vary, $ /CDF_TIME_TT2000,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT','Time_TT2000','F17.7',/ZVARIABLE cdf_attput,fileid,'FIELDNAM','Time_TT2000','Time_TT2000',/ZVARIABLE cdf_attput,fileid,'LABLAXIS','Time_TT2000','Time_TT2000',/ZVARIABLE cdf_attput,fileid,'VAR_TYPE','Time_TT2000','data',/ZVARIABLE cdf_attput,fileid,'FILLVAL','Time_TT2000',-1.0e31,/ZVARIABLE cdf_attput,fileid,'DISPLAY_TYPE','Time_TT2000','time_series',/ZVARIABLE cdf_attput,fileid,'VALIDMIN','Time_TT2000',tt2000_range[0],/ZVARIABLE cdf_attput,fileid,'VALIDMAX','Time_TT2000',tt2000_range[1],/ZVARIABLE cdf_attput,fileid,'SCALEMIN','Time_TT2000',timett2000[0],/ZVARIABLE cdf_attput,fileid,'SCALEMAX','Time_TT2000',timett2000[nrec-1],/ZVARIABLE cdf_attput,fileid,'UNITS','Time_TT2000','ns',/ZVARIABLE cdf_attput,fileid,'MONOTON','Time_TT2000','INCREASE',/ZVARIABLE cdf_attput,fileid,'CATDESC','Time_TT2000','Time, start of sample, in TT2000 time base',/ZVARIABLE cdf_varput,fileid,'Time_TT2000',timett2000 for i = 0,nvars-1 do begin ; Now determine the dimensionality and type of the variable n_dimension = size (struct.(i),/n_dimensions) ; The dimension used to create the CDF variable must be 1 lower than the IDL variable. ; In other words, the CDF dimensionality refers to the dimensionality of each record. ; For example, electron temperature is not a CDF variable of dimension (n_times), but instead has dimension zero, but varies with each record. Dim = reform (size (struct.(i),/dimension))-1 ; type = size (struct.(i),/type) dim_vary = replicate (1, n_dimension) case type of 1: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_BYTE,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'I4',/ZVARIABLE end 2: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_INT1,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'I6',/ZVARIABLE end 3: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_INT2,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'I11',/ZVARIABLE end 4: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_FLOAT,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'F15.7',/ZVARIABLE end 5: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_DOUBLE,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'F15.7',/ZVARIABLE end 6: message, 'No complex data types allowed in CDF variables. Real variables only!' 7: message, 'No string data types allowed in CDF variables.' 8: message, 'No structure data types allowed in CDF variables.' 9: message, 'No complex data types allowed in CDF variables. Real variables only!' 10: message, 'No pointer data types allowed in CDF variables.' 11: message, 'No object reference data types allowed in CDF variables. 12: Begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_UINT1,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'I6',/ZVARIABLE end 13: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_UINT2,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'I10',/ZVARIABLE end 14: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_INT4,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'I20',/ZVARIABLE end 15: begin variable_ID = $ cdf_varcreate(fileid, variable_list[i],dim_vary, $ /CDF_UINT4,/REC_VARY,/ZVARIABLE) cdf_attput,fileid,'FORMAT',variable_ID,'I20',/ZVARIABLE end Endcase cdf_attput,fileid,'FIELDNAM',variable_ID,variable_list[i],/ZVARIABLE cdf_attput,fileid,'LABLAXIS',variable_ID,variable_list[i],/ZVARIABLE cdf_attput,fileid,'VAR_TYPE',variable_ID,'data',/ZVARIABLE cdf_attput,fileid,'FILLVAL',variable_ID,-1.0e31,/ZVARIABLE cdf_attput,fileid,'DISPLAY_TYPE',variable_ID,'time_series',/ZVARIABLE if variable_list[i] eq 'time_met' then begin Valid_range = [0, 60*365L*86400] ; 60 years Scale_range = [struct[0].time_met, struct[nrec-1].time_met] Monotonic = 'INCREASE' endif else if variable_list[i] eq 'time_unix' then begin Valid_range = time_double (['1970-01-01','2050-01-01']) Scale_range = [struct[0].time_unix, struct[nrec-1].time_unix] Monotonic = 'INCREASE' endif else begin Monotonic = 'FALSE' Valid_range = [-1e25,1e25] temp_range = minmax(struct.(i), /nan) if sign(temp_range [0]) eq 1 then $ ;Some guesswork as to what a reasonable range might be if the user doesn't specify autoscale_range = [10^(Floor(alog10(temp_range[0]))),$ 10^(Ceil(alog10(temp_range[1])))] else if sign(temp_range [0]) eq -1 then $ autoscale_range = [-1*10^(Ceil(alog10(abs(temp_range[0])))),$ 10^(Ceil(alog10(temp_range[1])))] else autoscale_range = [0,10^(Ceil(alog10(temp_range[1])))] If keyword_set (display_range) then begin if finite (total (display_range[*,i])) then scale_range = display_range [*,i] else scale_range = autoscale_range endif else begin scale_range = autoscale_range endelse endelse ; Fill in some of the attributes for the variables cdf_attput,fileid,'VALIDMIN',variable_list[i],valid_range[0],/ZVARIABLE cdf_attput,fileid,'VALIDMAX',variable_list[i],valid_range[1],/ZVARIABLE cdf_attput,fileid,'SCALEMIN',variable_list[i],scale_range[0],/ZVARIABLE cdf_attput,fileid,'SCALEMAX',variable_list[i],scale_range[1],/ZVARIABLE cdf_attput,fileid,'UNITS',variable_list[i],units[i],/ZVARIABLE cdf_attput,fileid,'MONOTON',variable_list[i],monotonic,/ZVARIABLE cdf_attput,fileid,'CATDESC',variable_list[i],description[i],/ZVARIABLE cdf_varput,fileid,variable_list[i],struct.(i) endfor cdf_close,fileid end