def camera2asdf(camera_refname, author, description, useafter): try: model = pcf2model(camera_refname, name='camera') except: print("Camera file was not converted.") raise camera_model = CameraModel(model=model) camera_model.meta.author = author camera_model.meta.description = description camera_model.meta.pedigree = "GROUND" camera_model.meta.title = "NIRSPEC CAMERA file" camera_model.meta.useafter = useafter entry = HistoryEntry({ 'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software camera_model.history.append(entry) return camera_model
def create_reffile_header(model): model.meta.instrument.name = "MIRI" model.meta.instrument.detector = "MIRIMAGE" model.meta.instrument.band = "N/A" model.meta.instrument.channel = "N/A" model.meta.exposure.type = "MIR_IMAGE" model.meta.author = "Alistair Glasse, David R. Law" model.meta.pedigree = "GROUND" model.meta.useafter = "2000-01-01T00:00:00" model.meta.reftype = "filteroffset" if (model.meta.model_type is 'DistortionModel'): model.meta.exposure.p_exptype = "MIR_IMAGE|MIR_TACQ|MIR_LYOT|MIR_4QPM|MIR_CORONCAL|MIR_LRS-FIXEDSLIT|MIR_LRS-SLITLESS|MIR_TACONFIRM|" if (model.meta.model_type is 'FilteroffsetModel'): model.meta.exposure.p_exptype = "MIR_IMAGE|MIR_TACQ|MIR_LYOT|MIR_4QPM|MIR_CORONCAL|MIR_TACONFIRM|" entry = HistoryEntry({ 'description': "New version created from CDP-7 with updated filter offset format", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'miricoord', 'author': 'D.Law', 'homepage': 'https://github.com/STScI-MIRI/miricoord', 'version': "master" }) entry['software'] = software model.history = [entry] return model
def create_msa_reference(msa_file, output_name, author=None, description=None, useafter=None): f = fits.open(msa_file) auth = f[0].header['AUTHOR'] descrip = f[0].header['DESCR'] date = f[0].header['DATE'] f.close() if author is None: author = auth if description is None: description = descrip if useafter is None: useafter = date try: msa_model = msa2asdf(msa_file, author, description, useafter) except: raise Exception("MSA file was not converted") entry = HistoryEntry({ 'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software msa_model.history.append(entry) msa_model.to_asdf(output_name) msa_model.validate()
def create_reffile_header(model, detector, band, channel, author, useafter, description=""): model.meta.description = description model.meta.author = author model.meta.useafter = useafter model.meta.pedigree = 'GROUND' model.meta.instrument.name = "MIRI" model.meta.instrument.detector = detector model.meta.instrument.channel = channel model.meta.instrument.band = band model.meta.exposure.type = "MIR_MRS" entry = HistoryEntry({ 'description': "DOCUMENT: MIRI-TN-00001-ETH_Iss2-1_Calibrationproduct_MRS_d2c. Updated regions file from CDP-8B.05.01", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'miricoord', 'author': 'D.Law', 'homepage': 'https://github.com/STScI-MIRI/miricoord', 'version': "master" }) entry['software'] = software model.history = [entry] return model
def create_reffile_header(model): model.meta.instrument.name = "MIRI" model.meta.instrument.detector = "MIRIMAGE" model.meta.instrument.band = "N/A" model.meta.instrument.channel = "N/A" model.meta.exposure.type = "MIR_IMAGE" model.meta.exposure.p_exptype = "MIR_IMAGE|MIR_LRS-FIXEDSLIT|MIR_LRS-SLITLESS|" model.meta.author = "Alistair Glasse, David R. Law" model.meta.pedigree = "GROUND" model.meta.useafter = "2000-01-01T00:00:00" entry = HistoryEntry({ 'description': "New version created from CDP-7b with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'coordinates', 'author': 'D.Law', 'homepage': 'https://github.com/STScI-MIRI/miricoord', 'version': "master" }) entry['software'] = software model.history = [entry] return model
def create_ote_reference(ote_file, output_name, author=None, description=None, useafter="2016-03-01T09:08:05"): f = open(ote_file) lines = [l.strip() for l in f.readlines()] f.close() for i, line in enumerate(lines): if 'AUTHOR' in line: auth = lines[i + 1] continue elif 'DESCRIPTION' in line: descrip = lines[i + 1] continue elif 'DATE' in line: date = lines[i + 1] continue if author is None: author = auth if description is None: description = descrip if useafter is None: useafter = date try: model = ote2asdf(ote_file, author, description, useafter) except: raise Exception("OTE file was not converted.") entry = HistoryEntry({'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow()}) software = Software({'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1"}) entry['software'] = software model.history.append(entry) model.to_asdf(output_name) model.validate()
def create_fore_reference(refdir, author=None, description=None, useafter=None): # fore reference file for i, filter in enumerate( ["CLEAR", "F070LP", "F100LP", "F110W", "F140X", "F170LP", "F290LP"]): filename = "Fore_{0}.pcf".format(filter) out_name = "fore_cv3_{0}.asdf".format(filter) fore_refname = os.path.join(refdir, "CoordTransform", filename) with open(fore_refname) as f: lines = f.readlines() lines = [l.strip() for l in lines] for i, line in enumerate(lines): if 'AUTHOR' in line: auth = lines[i + 1] continue elif 'DESCRIPTION' in line: descrip = lines[i + 1] continue elif 'DATE' in line: date = lines[i + 1] continue if author is None: author = auth if description is None: description = descrip if useafter is None: useafter = date try: model = fore2asdf(fore_refname, name='fore') except: raise Exception( ("FORE file was not created - filter {0}".format(filter))) fore_model = FOREModel() fore_model.model = model fore_model.meta.pedigree = 'GROUND' fore_model.meta.author = author fore_model.meta.description = description fore_model.meta.useafter = useafter fore_model.meta.instrument.filter = filter entry = HistoryEntry({ 'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software fore_model.history.append(entry) fore_model.to_asdf(out_name) fore_model.validate()
def create_history_entry(description, software=None): """ Create a HistoryEntry object. Parameters ---------- description : str Description of the change. software : dict or list of dict A description of the software used. It should not include asdf itself, as that is automatically notated in the `asdf_library` entry. Each dict must have the following keys: ``name``: The name of the software ``author``: The author or institution that produced the software ``homepage``: A URI to the homepage of the software ``version``: The version of the software Examples -------- >>> soft = {'name': 'jwreftools', 'author': 'STSCI', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7"} >>> entry = create_history_entry(description="HISTORY of this file", software=soft) """ from asdf.tags.core import Software, HistoryEntry import datetime if isinstance(software, list): software = [Software(x) for x in software] elif software is not None: software = Software(software) entry = HistoryEntry({ 'description': description, 'time': datetime.datetime.utcnow() }) if software is not None: entry['software'] = software return entry
def create_ifufore_reference(ifufore_refname, out_name, author=None, description=None, useafter=None): #filename = "IFU_FORE.pcf" with open(ifufore_refname) as f: lines = f.readlines() lines = [l.strip() for l in lines] for i, line in enumerate(lines): if 'AUTHOR' in line: auth = lines[i + 1] continue elif 'DESCRIPTION' in line: descrip = lines[i + 1] continue elif 'DATE' in line: date = lines[i + 1] continue if author is None: author = auth if description is None: description = descrip if useafter is None: useafter = date try: model = fore2asdf(ifufore_refname, name='ifufore') except: print("IFUFORE file was not created.") raise ifufore_model = IFUFOREModel() ifufore_model.model = model ifufore_model.meta.pedigree = 'GROUND' ifufore_model.meta.author = author ifufore_model.meta.description = description ifufore_model.meta.useafter = useafter entry = HistoryEntry({ 'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software ifufore_model.history.append(entry) ifufore_model.to_asdf(out_name) ifufore_model.validate()
def create_fpa_reference(fpa_refname, out_name, author=None, description=None, useafter=None): with open(fpa_refname) as f: lines = f.readlines() lines = [l.strip() for l in lines] for i, line in enumerate(lines): if 'AUTHOR' in line: auth = lines[i + 1] continue elif 'DESCRIPTION' in line: descrip = lines[i + 1] continue elif 'DATE' in line: date = lines[i + 1] continue if author is None: author = auth if description is None: description = descrip if useafter is None: useafter = date try: model = fpa2asdf(fpa_refname, author, description, useafter) except: raise entry = HistoryEntry({ 'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software model.history.append(entry) model.to_asdf(out_name) model.validate()
def create_wavelengthrange_reference(wave_range_file, output_name, author=None, description=None, useafter=None): f = open(wave_range_file) lines = [l.strip() for l in f.readlines()] f.close() for i, line in enumerate(lines): if 'AUTHOR' in line: auth = lines[i + 1] continue elif 'DESCRIPTION' in line: descrip = lines[i + 1] continue elif 'DATE' in line: date = lines[i + 1] continue if author is None: author = auth if description is None: description = descrip if useafter is None: useafter = date wr_model = wavelength_range(wave_range_file, author, description, useafter) entry = HistoryEntry({ 'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software wr_model.history.append(entry) wr_model.to_asdf(output_name) wr_model.validate()
def software_history_entry(self, value: dict): """Set the software used for making history entries.""" if value is None: from weldx import __version__ as version self._DEFAULT_SOFTWARE_ENTRY = { "name": "weldx", "author": "BAM", "homepage": "https://www.bam.de/Content/EN/Projects/WelDX/weldx.html", "version": version, } else: if not isinstance(value, Dict): raise ValueError("expected a dictionary type") try: test = AsdfFile(tree=dict(software=Software(value))) test.validate() except ValidationError as ve: raise ValueError(f"Given value has invalid format: {ve}") self._DEFAULT_SOFTWARE_ENTRY = value
current_data = msm.Data(name="Welding current", data=I) # voltage data U_ts = ut.sine(f=Q_(10, "1/s"), amp=Q_(3, "V"), bias=Q_(40, "V"), phase=Q_(0.1, "rad")) U = U_ts.interp_time(time) U["time"] = U["time"] voltage_data = msm.Data(name="Welding voltage", data=U) HKS_sensor = msm.GenericEquipment(name="HKS P1000-S3") BH_ELM = msm.GenericEquipment(name="Beckhoff ELM3002-0000") twincat_scope = Software(name="Beckhoff TwinCAT ScopeView", version="3.4.3143") src_current = msm.Source( name="Current Sensor", output_signal=msm.Signal(signal_type="analog", unit="V", data=None), error=msm.Error(Q_(0.1, "percent")), ) HKS_sensor.sources = [] HKS_sensor.sources.append(src_current) from weldx.core import MathematicalExpression [a, x, b] = sympy.symbols("a x b") current_AD_func = MathematicalExpression(a * x + b) current_AD_func.set_parameter("a", Q_(32768.0 / 10.0, "1/V"))
def create_grism_waverange(outname="", history="Ground NIRCAM Grismwavelengthrange", author="STScI", filter_range=None): """Create a wavelengthrange reference file. Supply a filter range dictionary keyed on order or use the default """ ref_kw = common_reference_file_keywords(reftype="wavelengthrange", title="NIRCAM Grism wavelenghtrange", description="NIRCAM Grism+Filter Wavelength Ranges", exp_type="NRC_GRISM", author=author, model_type="WavelengthrangeModel", filename=outname, ) if filter_range is None: # These numbers from Nor Pirzkal, in microns filter_range = {1: {'F250M': [2.500411072, 4.800260833], 'F277W': [2.500411072, 3.807062006], 'F300M': [2.684896869, 4.025318456], 'F322W2': [2.5011293930000003, 4.215842089], 'F335M': [3.01459734, 4.260432726], 'F356W': [3.001085025, 4.302320901], 'F360M': [3.178096344, 4.00099629], 'F410M': [3.6267051809999997, 4.5644598], 'F430M': [4.04828939, 4.511761774], 'F444W': [3.696969216, 4.899565197], 'F460M': [3.103778615, 4.881999188], 'F480M': [4.5158154679999996, 4.899565197]}, 2: {'F250M': [2.500411072, 2.667345336], 'F277W': [2.500411072, 3.2642254050000004], 'F300M': [2.6659796289999997, 3.2997071729999994], 'F322W2': [2.5011293930000003, 4.136119434], 'F335M': [2.54572003, 3.6780519760000003], 'F356W': [2.529505253, 4.133416971], 'F360M': [2.557881113, 4.83740855], 'F410M': [2.5186954019999996, 4.759037127], 'F430M': [2.5362614100000003, 4.541488865], 'F444W': [2.5011293930000003, 4.899565197], 'F460M': [2.575447122, 4.883350419], 'F480M': [2.549773725, 4.899565197]}} # array of integers orders = list(filter_range.keys()) orders.sort() # same filters for every order, array of strings wrange_selector = list(filter_range[orders[0]].keys()) wrange_selector.sort() # The lists below need # to remain ordered to be correctly referenced wavelengthrange = [] for order in orders: o = [] for fname in wrange_selector: o.append(filter_range[order][fname]) wavelengthrange.append(o) ref = wcs_ref_models.WavelengthrangeModel() ref.meta.update(ref_kw) ref.meta.exposure.p_exptype = "NRC_GRISM|NRC_TSGRISM" ref.meta.input_units = u.micron ref.meta.output_units = u.micron ref.wrange_selector = wrange_selector ref.wrange = wavelengthrange ref.order = orders entry = HistoryEntry({'description': history, 'time': datetime.datetime.utcnow()}) sdict = Software({'name': 'nircam_reftools.py', 'author': author, 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': '0.7.1'}) entry['sofware'] = sdict ref.history['entries'] = [entry] ref.to_asdf(outname) ref.validate()
def create_ifupost_reference(model_dir, out_name, author=None, description=None, useafter=None): """ Create the IFUPOST reference. Parameters ---------- model_dir : str Directory with the model. it should contain a subdirectory ``CoordTransform``. out_name : str Name for the reference file. author : str Author field. description : str Consice description of the file. useafter : str A useafter date in ISO format. """ model_dir = os.path.join(model_dir, "CoordTransform", "IFU") ifupost_list = glob.glob(model_dir + '/IFU-POST*') f = open(ifupost_list[0]) lines = f.readlines() f.close() lines = [l.strip() for l in lines] for i, line in enumerate(lines): if 'AUTHOR' in line: auth = lines[i + 1] continue elif 'DESCRIPTION' in line: descrip = lines[i + 1] continue elif 'DATE' in line: date = lines[i + 1] continue if author is None: author = auth if description is None: description = descrip if useafter is None: useafter = date try: model = ifupost2asdf(ifupost_list, author, description, useafter) except: raise Exception("IFUPOST file was not created.") entry = HistoryEntry({ 'description': "New version created from CV3 with updated file structure", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software model.history.append(entry) model.to_asdf(out_name) model.validate()
def create_wavecorr_refs(wzpc_files, outname=None, author=None, description=None, useafter="2015-11-01"): """ Create WAVECORR reference files (Nirspec wavelength zero-point correction). Parameters ---------- wzpc_files : list or str A list of *slit-*wzprf.fits file names to create the Fixed Slits reference file. A file name to create the MSA reference file. author : str Author. If None it will be read from the first file. description : str Description of the file. If None will be read from the header. useafter : str Useafter date. """ model = WaveCorrModel() aps = [] if isinstance(wzpc_files, list): # Create a reference file for the Fixed Slits mode. model.meta.exposure.type = "NRS_FIXEDSLIT" model.meta.exposure.p_exptype = "NRS_FIXEDSLIT|NRS_BRIGHTOBJ|" for f in wzpc_files: aps.append( _wzpc2asdf(f, author=author, description=description, useafter=useafter)) if description is None: description = "Wavelength zero-point reference file for Nirspec fixed slits, computed using a simple toy model." elif isinstance(wzpc_files, str): model.meta.exposure.type = "NRS_MSASPEC" wzpc_files = [wzpc_files] aps.append( _wzpc2asdf(wzpc_files[0], author=author, description=description, useafter=useafter)) else: raise ValueError( "Invalid input - expected a string or a list of strings.") f0 = wzpc_files[0] model.apertures = aps if author is None: author = fits.getval(f0, 'AUTHOR') if description is None: description = fits.getval(f0, 'DESCRIP') pedigree = fits.getval(f0, 'PEDIGREE') model.meta.author = author model.meta.pedigree = pedigree model.meta.description = description model.meta.useafter = useafter model.meta.date = fits.getval(f0, 'date') model.meta.origin = fits.getval(f0, 'author') model.meta.instrument.p_detector = "NRS1|NRS2|" entry = HistoryEntry({ 'description': "NIRSPEC wavelength zero-point correction.", 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'jwstreftools', 'author': 'N.Dencheva', 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': "0.7.1" }) entry['software'] = software model.history.append(entry) if outname is None: outname = "nirspec_wavecorr.asdf" model.to_asdf(outname)
def create_grism_config(conffile="", fname="", pupil="", author="STScI", history="NIRISS Grism Parameters", outname=""): """ pupil is the blocking filter filter is the grism Create an asdf reference file to hold Grism C (column) or Grism R (rows) configuration, no sensativity information is included Note: The orders are named alphabetically, i.e. Order A, Order B There are also sensativity fits files which are tables of wavelength, sensativity, and error. These are specified in the conffile but will not be read in and saved in the output reference file. direct_filter is not specified because it assumes that the wedge information (wx,wy) is included in the conf file in one of the key-value pairs, where the key includes the beam designation For each spectral order, the configuration file contains a pair of magnitude-cutoff values. Sources with magnitudes fainter than the extraction cutoff (MMAG_EXTRACT_X) are not extracted, but are accounted for when computing the spectral contamination and background estimates. Sources with magnitudes fainter than the second cutoff (MMAG_MARK_X) are completely ignored. Here, X equals A, B, C, etc., with each letter referring to a spectral order, as specified in the configuration file. -- the initial conf file that nor gave me didn't have this keyword so this code adds a placeholder. this reference file also contains the polynomial model which is appropriate for the coefficients which are listed. Parameters ---------- conffile : str The text file with configuration information pupil : str Name of the grism the conffile corresponds to filter : str Name of the filter the conffile corresponds to author : str The name of the author history : str A comment about the refrence file to be saved with the meta information outname : str Output name for the reference file Returns ------- fasdf : asdf.AsdfFile(jwst.datamodels.NIRISSGrismModel) """ if not history: history = "Created from {0:s}".format(conffile) # if pupil is none get from filename like NIRCAM_modB_R.conf if not fname: fname = conffile.split(".")[0] if not pupil: pupil = conffile.split(".")[1] ref_kw = common_reference_file_keywords(reftype="specwcs", description="{0:s} dispersion model parameters".format(pupil), exp_type="NIS_WFSS", model_type='NIRISSGrismModel', pupil=pupil, filtername=fname, history=history, author=author, filename=outname, ) # get all the key-value pairs from the input file conf = dict_from_file(conffile) beamdict = split_order_info(conf) letter = re.compile("^[a-zA-Z0-9]{0,1}$") # match one only etoken = re.compile("^BEAM_[A-Z,a-z]{1,1}") # find beam key # add min and max mag info if not provided # also make beam coeff lists # wx are the wedge offsets for the filters # in niriss there's a different grism file for each filter # for k, bdict in beamdict.items(): # if isinstance(bdict, dict): # keys = bdict.keys() # minmag = "MMAG_EXTRACT" # maxmag = "MMAG_MARK" # if minmag not in keys: # beamdict[k][minmag] = 99. # if maxmag not in keys: # beamdict[k][maxmag] = 0.0 # if "wx" not in keys: # beamdict[k]['wx'] = 0.0 # if "wy" not in keys: # beamdict[k]['wy'] = 0.0 # add to the big tree # tree['spectral_orders'] = beamdict # add the polynomial model for this file. # this structure allows there to be a different polynomial relationship # for each order if necessary. Either way, the coefficients should be # stored with the polynomials since they are directly dependent on # each other # for order in tree['spectral_orders']: # print("order: {}".format(order)) # xc = tree['spectral_orders'][order]["DISPX"] # yc = tree['spectral_orders'][order]["DISPY"] # lc = tree['spectral_orders'][order]["DISPL"] # print("{} {} {}".format(xc, yc, lc)) # model = models.PolyTraceDispersion(xc, yc, lc, w) # tree['spectral_orders'][order]['model'] = model # The lists below need # to remain ordered and referenced by filter or order orders = sorted(beamdict.keys()) # disp[] per sorted order displ = [] dispx = [] dispy = [] invdispl = [] for order in orders: # convert the displ wavelengths to microns l0 = beamdict[order]['DISPL'][0] / 10000. l1 = beamdict[order]['DISPL'][1] / 10000. # create polynomials for the coefficients of each order invdispl.append(Polynomial1D(1, c0=-l0/l1, c1=1./l1)) displ.append(Polynomial1D(1, c0=l0, c1=l1)) # the dispxy functions here are pulled into a 1D # such that the final poly is ans = x_model + t*y_model e0, e1 = beamdict[order]['DISPX'] model_x = Polynomial2D(2, c0_0=e0[0], c1_0=e0[1], c2_0=e0[4], c0_1=e0[2], c1_1=e0[5], c0_2=e0[3]) model_y = Polynomial2D(2, c0_0=e1[0], c1_0=e1[1], c2_0=e1[4], c0_1=e1[2], c1_1=e1[5], c0_2=e1[3]) dispx.append((model_x, model_y)) e0, e1 = beamdict[order]['DISPY'] model_x = Polynomial2D(2, c0_0=e0[0], c1_0=e0[1], c2_0=e0[4], c0_1=e0[2], c1_1=e0[5], c0_2=e0[3]) model_y = Polynomial2D(2, c0_0=e1[0], c1_0=e1[1], c2_0=e1[4], c0_1=e1[2], c1_1=e1[5], c0_2=e1[3]) dispy.append((model_x, model_y)) # disp is x_model + t*y_model # invdisp is (t - model_x) / model_y # change the orders into translatable integer strings # the conf file niriss is giving me are using letter designations beam_lookup = {"A": "+1", "B": "0", "C": "+2", "D": "+3", "E": "-1"} ordermap = [int(beam_lookup[order]) for order in orders] # save the reference file ref = NIRISSGrismModel() ref.meta.update(ref_kw) ref.meta.input_units = u.micron ref.meta.output_units = u.micron ref.dispx = dispx ref.dispy = dispy ref.displ = displ ref.invdispl = invdispl ref.fwcpos_ref = conf['FWCPOS_REF'] ref.orders = ordermap entry = HistoryEntry({'description': history, 'time': datetime.datetime.utcnow()}) sdict = Software({'name': 'niriss_reftools.py', 'author': author, 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': '0.7.1'}) entry['sofware'] = sdict ref.history['entries'] = [entry] ref.to_asdf(outname) ref.validate()
def create_grism_waverange(outname="", history="NIRCAM Grism wavelengthrange", author="STScI", module="N/A", pupil="N/A", filter_range=None): """Create a wavelengthrange reference file. There is a different file for each filter Supply a filter range dictionary or use the default """ ref_kw = common_reference_file_keywords(reftype="wavelengthrange", title="NIRISS WFSS waverange", exp_type="NIS_WFSS", description="NIRISS WFSS Filter Wavelength Ranges", useafter="2014-01-01T00:00:00", author=author, model_type="WavelengthrangeModel", module=module, pupil=None, filename=outname, filtername=None) if filter_range is None: # These numbers from Grabriel Brammer, in microns # There is only one set of ranges because they are # valid for all orders listed, the wavelengthrange # file requires a double array by order, so they # will be replicated for each order, this allows # allows adaptation for future updates per order filter_range = {'F090W': [0.79, 1.03], 'F115W': [0.97, 1.32], 'F140M': [1.29, 1.52], 'F150W': [1.29, 1.71], 'F158M': [1.41, 1.74], 'F200W': [1.70, 2.28] } orders = [-1, 0, 1, 2, 3] else: # array of integers orders = list(filter_range.keys()) orders.sort() # same filters for every order, array of strings wrange_selector = list(filter_range.keys()) wrange_selector.sort() # The lists below need # to remain ordered to be correctly referenced wavelengthrange = [] for order in orders: o = [] for fname in wrange_selector: o.append(filter_range[fname]) wavelengthrange.append(o) ref = wcs_ref_models.WavelengthrangeModel() ref.meta.update(ref_kw) ref.meta.input_units = u.micron ref.meta.output_units = u.micron ref.wrange_selector = wrange_selector ref.wrange = wavelengthrange ref.order = orders entry = HistoryEntry({'description': history, 'time': datetime.datetime.utcnow()}) sdict = Software({'name': 'niriss_reftools.py', 'author': author, 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': '0.7.1'}) entry['sofware'] = sdict ref.history['entries'] = [entry] ref.to_asdf(outname) ref.validate()
def single_pass_weld_example( out_file: Optional[Union[str, BytesIO]] = "single_pass_weld_example.asdf", ) -> Optional[tuple[BytesIO, dict]]: """Create ASDF file containing all required fields of the single_pass_weld schema. Parameters ---------- out_file : destination file, if None returns a BytesIO buffer. Returns ------- buff, tree When writing to memory, return the buffer and the tree (as dictionary). """ # Imports import asdf import numpy as np import pandas as pd from asdf.tags.core import Software import weldx.geometry as geo import weldx.measurement as msm # importing the weldx package with prevalent default abbreviations import weldx.transformations as tf from weldx.asdf.util import get_schema_path, write_buffer, write_read_buffer from weldx.constants import META_ATTR, Q_ from weldx.core import MathematicalExpression, TimeSeries from weldx.tags.aws.process.gas_component import GasComponent from weldx.tags.aws.process.shielding_gas_for_procedure import ( ShieldingGasForProcedure, ) from weldx.tags.aws.process.shielding_gas_type import ShieldingGasType from weldx.tags.processes.process import GmawProcess from weldx.transformations.local_cs import LocalCoordinateSystem as lcs from weldx.transformations.rotation import WXRotation from weldx.welding.groove.iso_9692_1 import get_groove from weldx.welding.util import sine # Timestamp reference_timestamp = pd.Timestamp("2020-11-09 12:00:00") # Geometry # groove + trace = geometry groove = get_groove( groove_type="VGroove", workpiece_thickness=Q_(5, "mm"), groove_angle=Q_(50, "deg"), root_face=Q_(1, "mm"), root_gap=Q_(1, "mm"), ) # define the weld seam length in mm seam_length = Q_(300, "mm") # create a linear trace segment a the complete weld seam trace trace_segment = geo.LinearHorizontalTraceSegment(seam_length) trace = geo.Trace(trace_segment) geometry = dict(groove_shape=groove, seam_length=seam_length) base_metal = dict(common_name="S355J2+N", standard="DIN EN 10225-2:2011") workpiece = dict(base_metal=base_metal, geometry=geometry) # Setup the Coordinate System Manager (CSM) # crete a new coordinate system manager with default base coordinate system csm = tf.CoordinateSystemManager("base") # add the workpiece coordinate system csm.add_cs( coordinate_system_name="workpiece", reference_system_name="base", lcs=trace.coordinate_system, ) tcp_start_point = Q_([5.0, 0.0, 2.0], "mm") tcp_end_point = Q_([-5.0, 0.0, 2.0], "mm") + np.append( seam_length, Q_([0, 0], "mm")) v_weld = Q_(10, "mm/s") s_weld = (tcp_end_point - tcp_start_point)[0] # length of the weld t_weld = s_weld / v_weld t_start = pd.Timedelta("0s") t_end = pd.Timedelta(str(t_weld.to_base_units())) rot = WXRotation.from_euler(seq="x", angles=180, degrees=True) coords = [tcp_start_point.magnitude, tcp_end_point.magnitude] tcp_wire = lcs(coordinates=coords, orientation=rot, time=[t_start, t_end]) # add the workpiece coordinate system csm.add_cs( coordinate_system_name="tcp_wire", reference_system_name="workpiece", lcs=tcp_wire, ) tcp_contact = lcs(coordinates=[0, 0, -10]) # add the workpiece coordinate system csm.add_cs( coordinate_system_name="tcp_contact", reference_system_name="tcp_wire", lcs=tcp_contact, ) TCP_reference = csm.get_cs("tcp_contact", "workpiece") # Measurements # time time = pd.timedelta_range(start="0s", end="10s", freq="2s") # current data I_ts = sine(f=Q_(10, "1/s"), amp=Q_(20, "A"), bias=Q_(300, "A")) current_data = TimeSeries(I_ts.interp_time(time).data, time) # voltage data U_ts = sine(f=Q_(10, "1/s"), amp=Q_(3, "V"), bias=Q_(40, "V"), phase=Q_(0.1, "rad")) voltage_data = TimeSeries(U_ts.interp_time(time).data, time) # define current source and transformations src_current = msm.SignalSource( name="Current Sensor", output_signal=msm.Signal(signal_type="analog", units="V", data=None), error=msm.Error(Q_(0.1, "percent")), ) current_AD_transform = msm.SignalTransformation( name="AD conversion current measurement", error=msm.Error(Q_(0.01, "percent")), func=MathematicalExpression( "a * x + b", dict(a=Q_(32768.0 / 10.0, "1/V"), b=Q_(0.0, ""))), type_transformation="AD", ) current_calib_transform = msm.SignalTransformation( name="Calibration current measurement", error=msm.Error(0.0), func=MathematicalExpression( "a * x + b", dict(a=Q_(1000.0 / 32768.0, "A"), b=Q_(0.0, "A"))), ) # define voltage source and transformations src_voltage = msm.SignalSource( name="Voltage Sensor", output_signal=msm.Signal("analog", "V", data=None), error=msm.Error(Q_(0.1, "percent")), ) voltage_AD_transform = msm.SignalTransformation( name="AD conversion voltage measurement", error=msm.Error(Q_(0.01, "percent")), func=MathematicalExpression( "a * x + b", dict(a=Q_(32768.0 / 10.0, "1/V"), b=Q_(0.0, ""))), type_transformation="AD", ) voltage_calib_transform = msm.SignalTransformation( name="Calibration voltage measurement", error=msm.Error(0.0), func=MathematicalExpression( "a * x + b", dict(a=Q_(100.0 / 32768.0, "V"), b=Q_(0.0, "V"))), ) # Define lab equipment HKS_sensor = msm.MeasurementEquipment( name="HKS P1000-S3", sources=[src_current, src_voltage], ) BH_ELM = msm.MeasurementEquipment( name="Beckhoff ELM3002-0000", transformations=[current_AD_transform, voltage_AD_transform], ) twincat_scope = Software(name="Beckhoff TwinCAT ScopeView", version="3.4.3143") setattr(current_calib_transform, META_ATTR, dict(software=twincat_scope)) setattr(voltage_calib_transform, META_ATTR, dict(software=twincat_scope)) # Define current measurement chain welding_current_chain = msm.MeasurementChain.from_equipment( name="welding current measurement chain", equipment=HKS_sensor, source_name="Current Sensor", ) welding_current_chain.add_transformation_from_equipment( equipment=BH_ELM, transformation_name="AD conversion current measurement", ) welding_current_chain.add_transformation( transformation=current_calib_transform, data=current_data, ) # Define voltage measurement chain welding_voltage_chain = msm.MeasurementChain.from_equipment( name="welding voltage measurement chain", equipment=HKS_sensor, source_name="Voltage Sensor", ) welding_voltage_chain.add_transformation_from_equipment( equipment=BH_ELM, transformation_name="AD conversion voltage measurement", ) welding_voltage_chain.add_transformation( transformation=voltage_calib_transform, data=voltage_data, ) # Define measurements welding_current = msm.Measurement( name="welding current measurement", data=[current_data], measurement_chain=welding_current_chain, ) welding_voltage = msm.Measurement( name="welding voltage measurement", data=[voltage_data], measurement_chain=welding_voltage_chain, ) # GMAW Process params_pulse = dict( wire_feedrate=Q_(10.0, "m/min"), pulse_voltage=Q_(40.0, "V"), pulse_duration=Q_(5.0, "ms"), pulse_frequency=Q_(100.0, "Hz"), base_current=Q_(60.0, "A"), ) process_pulse = GmawProcess( "pulse", "CLOOS", "Quinto", params_pulse, tag="CLOOS/pulse", meta={"modulation": "UI"}, ) gas_comp = [ GasComponent("argon", Q_(82, "percent")), GasComponent("carbon dioxide", Q_(18, "percent")), ] gas_type = ShieldingGasType(gas_component=gas_comp, common_name="SG") gas_for_procedure = ShieldingGasForProcedure( use_torch_shielding_gas=True, torch_shielding_gas=gas_type, torch_shielding_gas_flowrate=Q_(20, "l / min"), ) process = dict( welding_process=process_pulse, shielding_gas=gas_for_procedure, weld_speed=TimeSeries(v_weld), welding_wire={"diameter": Q_(1.2, "mm")}, ) # ASDF file tree = dict( reference_timestamp=reference_timestamp, equipment=[HKS_sensor, BH_ELM], measurements=[welding_current, welding_voltage], welding_current=welding_current_chain.get_signal( "Calibration current measurement").data, welding_voltage=welding_voltage_chain.get_signal( "Calibration voltage measurement").data, coordinate_systems=csm, TCP=TCP_reference, workpiece=workpiece, process=process, ) tree[META_ATTR] = {"welder": "A.W. Elder"} model_path = get_schema_path("single_pass_weld-0.1.0.yaml") # pre-validate? write_read_buffer( tree, asdffile_kwargs=dict(custom_schema=str(model_path)), ) if out_file: with asdf.AsdfFile( tree, custom_schema=str(model_path), ) as ff: ff.write_to(out_file, all_array_storage="inline") else: return ( write_buffer( tree, asdffile_kwargs=dict(custom_schema=str(model_path)), write_kwargs=dict(all_array_storage="inline"), ), tree, )
def create_grism_specwcs(conffile="", pupil=None, direct_filter=None, author="STScI", history="", outname=None): """ Note: This code is shamelessly stolen from the jwreftools package (see https://github.com/spacetelescope/jwreftools/) and adapted for use on HST GRISMCONF files. The docstrings and comments have not yet been updated accordingly. Create an asdf reference file to hold grism configuration information. No sensitivity information is included Note: The orders are named alphabetically, i.e. Order A, Order B There are also sensativity fits files which are tables of wavelength, sensativity, and error. These are specified in the conffile but will not be read in and saved in the output reference file for now. It's possible they may be included in the future, either here or as a separate reference files. Their use here would be to help define the min and max wavelengths which set the extent of the dispersed trace on the grism image. Convolving the sensitiviy file with the filter throughput allows one to calculate the wavelength of minimum throughput which defines the edges of the trace. direct_filter is not specified because it assumes that the wedge information (wx,wy) is included in the conf file in one of the key-value pairs, where the key includes the beam designation this reference file also contains the polynomial model which is appropriate for the coefficients which are listed. wavelength = DISPL(order,x0,y0,t) dx = DISPX(order,x0,y0,t) dy = DISPY(order,x0,y0,t) t = INVDISPX(order,x0,y0,dx) t = INVDISPY(order,x0,y0,dy) t = INVDISL(order,x0,y0, wavelength) Parameters ---------- conffile : str The text file with configuration information, formatted as aXe expects pupil : str Name of the grism the conffile corresponds to Taken from the conffile name if not specified module : str Name of the Nircam module Taken from the conffile name if not specified author : str The name of the author history : str A comment about the refrence file to be saved with the meta information outname : str Output name for the reference file Returns ------- fasdf : asdf.AsdfFile(WFC3IRGrismModel) """ if outname is None: outname = "wfc3_ir_specwcs.asdf" if not history: history = "Created from {0:s}".format(conffile) # if pupil is none get from filename like NIRCAM_modB_R.conf if pupil is None: pupil = "GRISM" + conffile.split(".")[0][-1] print("Pupil is {}".format(pupil)) ref_kw = common_reference_file_keywords( reftype="specwcs", title="HST IR Grism Parameters", description="{0:s} dispersion models".format(pupil), exp_type="WFC3_IR", author=author, model_type="WFC3IRGrismModel", fname=direct_filter, pupil=pupil, filename=outname, ) # get all the key-value pairs from the input file conf = dict_from_file(conffile) beamdict = split_order_info(conf) # Get x and y offsets from the filter, if necessary if direct_filter is not None: wx = beamdict["WEDGE"][direct_filter][0] wy = beamdict["WEDGE"][direct_filter][0] else: wx, wy = 0, 0 beamdict.pop("WEDGE") # beam = re.compile('^(?:[+\-]){0,1}[a-zA-Z0-9]{0,1}$') # match beam only # read in the sensitivity tables to save their content # they currently have names like this: NIRCam.A.1st.sensitivity.fits # translated as inst.beam/order.param temp = dict() etoken = re.compile("^[a-zA-Z]*_(?:[+\-]){1,1}[1,2]{1,1}") # find beam key for b, bdict in beamdict.items(): temp[b] = dict() # add the new beam information to beamdict and remove spurious beam info for k in temp: for kk in temp[k]: if etoken.match(kk): kk = kk.replace("_{}".format(k), "") beamdict[k][kk] = temp[k][kk] # for NIRCAM, the R and C grism coefficients contain zeros where # the dispersion is in the opposite direction. Meaning, the GRISMR, # which disperses along ROWS has coefficients of zero in the y models # and vice versa. # # There are separate reference files for each grism. Depending on the grism # dispersion direction you either want to use the dx from source center or # the dy from source center in the inverse dispersion relationship which is # used to calculate the t value needed to calculate the wavelength at that # pixel. # The model creation here takes all of this into account by looking at the # GRISM[R/C] the file is used for and creating a reference model with the # appropriate dispersion direction in use. This eliminates having to decide # which direction to calculatethe dispersion from given the input x,y # pixel in the dispersed image. orders = beamdict.keys() # dispersion models valid per order and direction saved to reference file # Forward invdispl = [] invdispx = [] invdispy = [] # Backward displ = [] dispx = [] dispy = [] for order in orders: # convert the displ wavelengths to microns if the input # file is still in angstroms l0 = beamdict[order]['DISPL'][0] / 10000. l1 = beamdict[order]['DISPL'][1] / 10000. # create polynomials using the coefficients of each order # This holds the wavelength lookup coeffs # This model is INVDISPL for backward and returns t # This model should be DISPL for forward and returns wavelength if l1 == 0: lmodel = Polynomial1D(1, c0=0, c1=0) else: lmodel = Polynomial1D(1, c0=-l0 / l1, c1=1. / l1) invdispl.append(lmodel) lmodel = Polynomial1D(1, c0=l0, c1=l1) displ.append(lmodel) # This holds the x coefficients, for the R grism this model is the # the INVDISPX returning t, for the C grism this model is the DISPX e = beamdict[order]['DISPX'] xmodel = DISPXY_Model(e, wx) dispx.append(xmodel) inv_xmodel = DISPXY_Model(e, wx, inv=True) invdispx.append(inv_xmodel) # This holds the y coefficients, for the C grism, this model is # the INVDISPY, returning t, for the R grism, this model is the DISPY e = beamdict[order]['DISPY'] ymodel = DISPXY_Model(e, wy) dispy.append(ymodel) inv_ymodel = DISPXY_Model(e, wy, inv=True) invdispy.append(ymodel) # change the orders into translatable integers # so that we can look up the order with the proper index oo = [int(o) for o in beamdict] # We need to register the converter for the DISPXY_Model class with asdf asdf.get_config().add_extension(DISPXY_Extension()) ref = WFC3IRGrismModel() ref.meta.update(ref_kw) # This reference file is good for NRC_WFSS and TSGRISM modes ref.meta.exposure.p_exptype = "NRC_WFSS|NRC_TSGRISM" ref.meta.input_units = u.micron ref.meta.output_units = u.micron ref.displ = displ ref.dispx = dispx print(ref.dispx) ref.dispy = dispy print(ref.dispy) ref.invdispx = invdispx ref.invdispy = invdispy ref.invdispl = invdispl ref.order = oo history = HistoryEntry({ 'description': history, 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'nircam_reftools.py', 'author': author, 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': '0.7.1' }) history['software'] = software ref.history = [history] ref.to_asdf(outname) ref.validate()
def create_wfss_wavelengthrange(outname="nircam_wfss_wavelengthrange.asdf", history="Ground NIRCAM Grism wavelengthrange", author="STScI", wavelengthrange=None, extract_orders=None): """Create a wavelengthrange reference file for NIRCAM. Parameters ---------- outname: str The output name of the file history: str History information about it's creation author: str Person or entity making the file wavelengthrange: list(tuples) A list of tuples that set the order, filter, and wavelength range min and max extract_orders: list[list] A list of lists that specify """ ref_kw = common_reference_file_keywords( reftype="wavelengthrange", title="NIRCAM WFSS reference file", description="NIRCAM Grism-Filter Wavelength Ranges", exp_type="NRC_WFSS", author=author, pupil="ANY", model_type="WavelengthrangeModel", filename=outname, ) if wavelengthrange is None: # This is a list of tuples that specify the # order, filter, wave min, wave max wavelengthrange = [ (1, 'F250M', 2.500411072, 4.800260833), (1, 'F277W', 2.500411072, 3.807062006), (1, 'F300M', 2.684896869, 4.025318456), (1, 'F322W2', 2.5011293930000003, 4.215842089), (1, 'F335M', 3.01459734, 4.260432726), (1, 'F356W', 3.001085025, 4.302320901), (1, 'F360M', 3.178096344, 4.00099629), (1, 'F410M', 3.6267051809999997, 4.5644598), (1, 'F430M', 4.04828939, 4.511761774), (1, 'F444W', 3.696969216, 4.899565197), (1, 'F460M', 3.103778615, 4.881999188), (1, 'F480M', 4.5158154679999996, 4.899565197), (2, 'F250M', 2.500411072, 2.667345336), (2, 'F277W', 2.500411072, 3.2642254050000004), (2, 'F300M', 2.6659796289999997, 3.2997071729999994), (2, 'F322W2', 2.5011293930000003, 4.136119434), (2, 'F335M', 2.54572003, 3.6780519760000003), (2, 'F356W', 2.529505253, 4.133416971), (2, 'F360M', 2.557881113, 4.83740855), (2, 'F410M', 2.5186954019999996, 4.759037127), (2, 'F430M', 2.5362614100000003, 4.541488865), (2, 'F444W', 2.5011293930000003, 4.899565197), (2, 'F460M', 2.575447122, 4.883350419), (2, 'F480M', 2.549773725, 4.899565197), ] # array of integers of unique orders orders = sorted(set((x[0] for x in wavelengthrange))) filters = sorted(set((x[1] for x in wavelengthrange))) # Nircam has not specified any limitation on the orders # that should be extracted by default yet so all are # included. if extract_orders is None: extract_orders = [] for f in filters: extract_orders.append([f, orders]) ref = wcs_ref_models.WavelengthrangeModel() ref.meta.update(ref_kw) ref.meta.exposure.p_exptype = "NRC_WFSS" ref.meta.input_units = u.micron ref.meta.output_units = u.micron ref.wavelengthrange = wavelengthrange ref.extract_orders = extract_orders ref.order = orders ref.waverange_selector = filters history = HistoryEntry({ 'description': history, 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'nircam_reftools.py', 'author': author, 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': '0.7.1' }) history['software'] = software ref.history = [history] ref.validate() ref.to_asdf(outname)
def create_tsgrism_wavelengthrange(outname="wfc3_tsgrism_wavelengthrange.asdf", history="WFC3 TSGrism wavelengthrange", author="STScI", wavelengthrange=None, extract_orders=None): """Create a wavelengthrange reference file for WFC3 TSGRISM mode. Parameters ---------- outname: str The output name of the file history: str History information about it's creation author: str Person or entity making the file wavelengthrange: list(tuples) A list of tuples that set the order, filter, and wavelength range min and max extract_orders: list[list] A list of lists that specify """ ref_kw = common_reference_file_keywords( reftype="wavelengthrange", title="WFC3 TSGRISM reference file", description="WFC3 Grism-Filter Wavelength Ranges", exp_type="WFC3_TSGRISM", author=author, pupil="ANY", model_type="WavelengthrangeModel", filename=outname, ) if wavelengthrange is None: # This is a list of tuples that specify the # order, filter, wave min, wave max wavelengthrange = [ (-1, 'G102', 0.7488958984375, 1.1496958984375), (0, 'G102', 0.7401, 1.2297), (1, 'G102', 0.7496, 1.1979), (2, 'G102', 0.7401, 1.1897), (3, 'G102', 0.7571, 0.9878), (-1, 'G141', 1.031, 1.7845), (0, 'G141', 1.0402, 1.6998), (1, 'G141', 0.9953, 1.7697), (2, 'G141', 0.9702, 1.5903), (3, 'G141', 1.0068, 1.3875), (4, 'G141', 1.031, 1.7845), ] # array of integers of unique orders orders = sorted(set((x[0] for x in wavelengthrange))) filters = sorted(set((x[1] for x in wavelengthrange))) # Nircam has not specified any limitation on the orders # that should be extracted by default yet so all are # included. if extract_orders is None: extract_orders = [ ('G102', [1]), ('G141', [1]), ] ref = wcs_ref_models.WavelengthrangeModel() ref.meta.update(ref_kw) ref.meta.exposure.p_exptype = "WFC3_TSGRISM" ref.meta.input_units = u.micron ref.meta.output_units = u.micron ref.wavelengthrange = wavelengthrange ref.extract_orders = extract_orders ref.order = orders ref.waverange_selector = filters history = HistoryEntry({ 'description': history, 'time': datetime.datetime.utcnow() }) software = Software({ 'name': 'wfc3_reftools.py', 'author': author, 'homepage': 'https://github.com/spacetelescope/astrogrism_sandbox', 'version': '0.0.0' }) history['software'] = software ref.history = [history] ref.validate() ref.to_asdf(outname)
def create_grism_config(conffile="", pupil=None, module=None, author="STScI", history="", outname=""): """ Create an asdf reference file to hold Grism C (column) or Grism R (rows) configuration, no sensativity information is included Note: The orders are named alphabetically, i.e. Order A, Order B There are also sensativity fits files which are tables of wavelength, sensativity, and error. These are specified in the conffile but will not be read in and saved in the output reference file for now. It's possible they may be included in the future, either here or as a separate reference files. Their use here would be to help define the min and max wavelengths which set the extent of the dispersed trace on the grism image. Convolving the sensitiviy file with the filter throughput allows one to calculate the wavelength of minimum throughput which defines the edges of the trace. direct_filter is not specified because it assumes that the wedge information (wx,wy) is included in the conf file in one of the key-value pairs, where the key includes the beam designation this reference file also contains the polynomial model which is appropriate for the coefficients which are listed. wavelength = DISPL(order,x0,y0,t) dx = DISPX(order,x0,y0,t) dy = DISPY(order,x0,y0,t) t = INVDISPX(order,x0,y0,dx) t = INVDISPY(order,x0,y0,dy) t = INVDISL(order,x0,y0, wavelength) Parameters ---------- conffile : str The text file with configuration information, formatted as aXe expects pupil : str Name of the grism the conffile corresponds to Taken from the conffile name if not specified module : str Name of the Nircam module Taken from the conffile name if not specified author : str The name of the author history : str A comment about the refrence file to be saved with the meta information outname : str Output name for the reference file Returns ------- fasdf : asdf.AsdfFile(jwst.datamodels.NIRCAMGrismModel) """ if not history: history = "Created from {0:s}".format(conffile) # if pupil is none get from filename like NIRCAM_modB_R.conf if pupil is None: pupil = "GRISM" + conffile.split(".")[0][-1] # if module is none get from filename if module is None: module = conffile.split(".")[0][-3] print("Pupil is {}".format(pupil)) ref_kw = common_reference_file_keywords(reftype="specwcs", title="NIRCAM Grism Parameters", description="{0:s} dispersion models".format(pupil), exp_type="NRC_GRISM", author=author, model_type="NIRCAMGrismModel", module=module, pupil=pupil, filename=outname, ) # get all the key-value pairs from the input file conf = dict_from_file(conffile) beamdict = split_order_info(conf) # beam = re.compile('^(?:[+\-]){0,1}[a-zA-Z0-9]{0,1}$') # match beam only # read in the sensitivity tables to save their content # they currently have names like this: NIRCam.A.1st.sensitivity.fits # translated as inst.beam/order.param temp = dict() etoken = re.compile("^[a-zA-Z]*_(?:[+\-]){1,1}[1,2]{1,1}") # find beam key for b, bdict in beamdict.items(): temp[b] = dict() # for key in bdict: # if 'SENSITIVITY' in key: # print("Reading sensitivity from: {0:s}".format(bdict[key])) # sdata = read_sensitivity_file(bdict[key]) # skeys = sdata.keys() # for k in skeys: # temp[b][key+"_"+k] = sdata[k] # add the new beam information to beamdict and remove spurious beam info for k in temp: for kk in temp[k]: if etoken.match(kk): kk = kk.replace("_{}".format(k), "") beamdict[k][kk] = temp[k][kk] # add min and max mag info if not provided # also make beam coeff lists # wx are the wedge offsets for the filters # for k, bdict in beamdict.items(): # if isinstance(bdict, dict): # keys = bdict.keys() # if "MMAG_EXTRACT" not in keys: # beamdict[k]["MMAG_EXTRACT"] = 99.0 # if maxmag not in keys: # beamdict[k][maxmag] = 0.0 # if "wx" not in keys: # beamdict[k]['wx'] = 0.0 # if "wy" not in keys: # beamdict[k]['wy'] = 0.0 # add the model for transforms # for NIRCAM, the R and C grism coefficients contain zeros where # the dispersion is in the opposite direction. Meaning, the GRISMR, # which disperses along ROWS has coefficients of zero in the y models # and vice versa. # # There are separate reference files for each grism. Depending on the grism # dispersion direction you either want to use the dx from source center or # the dy from source center in the inverse dispersion relationship which is # used to calculate the t value needed to calculate the wavelength at that pixel. # # The model creation here takes all of this into account by looking at the GRISM[R/C] # the file is used for and creating a reference model with the appropriate dispersion # direction in use. This eliminates having to decide which direction to calculate # the dispersion from given the input x,y pixel in the dispersed image. orders = beamdict.keys() # dispersion models valid per order and direction saved to reference file # Forward invdispl = [] invdispx = [] invdispy = [] # Backward displ = [] dispx = [] dispy = [] for order in orders: # convert the displ wavelengths to microns if the input file is still in angstroms l0 = beamdict[order]['DISPL'][0] / 10000. l1 = beamdict[order]['DISPL'][1] / 10000. # create polynomials using the coefficients of each order # This holds the wavelength lookup coeffs # This model is INVDISPL for backward and returns t # This model should be DISPL for forward and returns wavelength if l1 == 0: lmodel = Polynomial1D(1, c0=0, c1=0) else: lmodel = Polynomial1D(1, c0=-l0/l1, c1=1./l1) invdispl.append(lmodel) lmodel = Polynomial1D(1, c0=l0, c1=l1) displ.append(lmodel) # This holds the x coefficients, for the R grism this model is the # the INVDISPX returning t, for the C grism this model is the DISPX x0, x1 = beamdict[order]['DISPX'] xmodel = Polynomial1D(1, c0=x0, c1=x1) dispx.append(xmodel) if x1 == 0: xmodel = Polynomial1D(1, c0=0, c1=0) else: xmodel = Polynomial1D(1, c0=-x0/x1, c1=1./x1) invdispx.append(xmodel) # This holds the y coefficients, for the C grism, this model is # the INVDISPY, returning t, for the R grism, this model is the DISPY y0, y1 = beamdict[order]['DISPY'] ymodel = Polynomial1D(1, c0=y0, c1=y1) dispy.append(ymodel) if y1 == 0: ymodel = Polynomial1D(1, c0=0, c1=0) else: ymodel = Polynomial1D(1, c0=-y0/y1, c1=1./y1) invdispy.append(ymodel) # change the orders into translatable integers # so that we can look up the order with the proper index oo = [int(o) for o in beamdict] ref = NIRCAMGrismModel() ref.meta.update(ref_kw) # This reference file is good for NRC_GRISM and TSGRISM modes ref.meta.exposure.p_exptype = "NRC_GRISM|NRC_TSGRISM" ref.meta.input_units = u.micron ref.meta.output_units = u.micron ref.displ = displ ref.dispx = dispx ref.dispy = dispy ref.invdispx = invdispx ref.invdispy = invdispy ref.invdispl = invdispl ref.orders = oo entry = HistoryEntry({'description': history, 'time': datetime.datetime.utcnow()}) sdict = Software({'name': 'nircam_reftools.py', 'author': author, 'homepage': 'https://github.com/spacetelescope/jwreftools', 'version': '0.7.1'}) entry['sofware'] = sdict ref.history['entries'] = [entry] ref.to_asdf(outname) ref.validate()