def selectLinesForElement(lines, ion, modelAtms, pradks, starParms, varLimit = np.finfo(np.float64).max, enforceMin=False, refLines=None, refCorrs=None, lineWeights=None): # From the passed list, select all the lines of the passed ion # (in XX.x form), with abundances within +/-varLimit of the mean. # An additional selection criteria is that the line eqw falls on # the linear portion of the curve of growth. # If enforceMin = True, the selection will be limited to the lesser # of the total number of lines for this element, or the constant # MinNumStatLines. # To save time in looped, or multiple calls, solar (or giant) corrections # can be passed in refLines and refCorrs. This is basically the output # of RC.getGiantCorrections or RC.getSolarCorrections for the passed ion. corrLines, allLines = RC.SortAndFilterLines(lines[ion], ion, starParms, filterBlends=True, refCorrect=True, modelAtms=modelAtms , pradks=pradks, refLines=refLines, refCorrs=refCorrs, lineWeights=lineWeights) # If we did not receive enough (any) corrected lines, so return a subset of # all the lines. if (corrLines==None or len(corrLines) < k.MinNumStatLines): if len(allLines) <= k.MinNumStatLines: # Well, we can't make more lines, so just return what we have return sorted(allLines, key=lambda line: line[0]) else: meanAb = np.mean(np.array(allLines)[:,5]) allSorted = sorted(allLines, key=lambda line: abs(line[5]-meanAb))[:k.MinNumStatLines] return sorted(allSorted, key=lambda line: line[0]) elif enforceMin: # We have enough lines to consider filtering for the variance limit. meanAb = np.mean(np.array(corrLines)[:,5]) limitedLines = [line for line in corrLines if abs(line[5]-meanAb)<=varLimit] if len(limitedLines) < k.MinNumStatLines: # Variance filtering was a bit much, return the best we can return sorted(sorted(corrLines, key=lambda line: abs(line[5]-meanAb))[:k.MinNumStatLines], key=lambda l: l[0]) else: return sorted(limitedLines, key=lambda line: line[0]) else: # enforceMin not set, so filter away! meanAb = np.mean(np.array(corrLines)[:,5]) rtnLines = [x for x in corrLines if abs(x[5]-meanAb) < abs(varLimit)] return sorted(rtnLines, key=lambda line: line[0])
def PlotXPAbs(starData, clusterName='NGC-0752', ionList=kAllIonList, fileTag='', labelPlot=True, labelPoints=False, showTrendLine=False, modelAtms=None, pradks=None, referenceCorrect=False): # Make XP vs. Ab for the passed star # One element per plot. starName = starData[0] starParmTuple = tuple(starData[1:]) isGiant = RC.isGiantStar(starParmTuple) if isGiant: modelPath = k.GiantModelPath else: modelPath = k.DwarfModelPath if modelAtms == None or pradks == None: modelFiles = mk.findDataFiles(modelPath) modelAtms, pradks = mk.LoadModels(modelFiles) abdict, uncorrLines, unusedMin, unusedMax = \ AB.CalcAbsAndLines(clusterName+' '+starName, tuple(starData[1:6]), ionList=ionList, modelAtms=modelAtms, pradks=pradks) # uncorrLines: # # {elem.ion:[[Wavelength, Ex.Pot., logGf, eqw, logRW, abund],...]} if referenceCorrect: if isGiant: # Obligatory comment on bad Giant corrections, and using # Solar instead. correctDict, referenceLines, lineWeights = \ RC.GetSolarCorrections(ionList=ionList, modelAtms=modelAtms, pradks=pradks) else: correctDict, referenceLines, lineWeights = \ RC.GetDwarfCorrections(ionList=ionList, modelAtms=modelAtms, pradks=pradks) correctionsAvailable = False if len(correctDict) > 0 and len(referenceLines) > 0: correctionsAvailable = True for ion in ionList: if ion not in uncorrLines.keys(): continue # Does this element have NLTE corrections available? Note: we do # this BEFORE Solar corrections, which assumes that the same # NLTE corrections are already applied to any Solar corrections # we use. if ion in NLTEIons: LTELines = AB.CorrectNLTEAbs(ion, uncorrLines[ion], tuple(starData[1:6])) else: if ion in uncorrLines.keys(): LTELines = uncorrLines[ion] else: # Either synthesized lines, or none available LTELines = np.array([]) # Do we want the "reference corrected" abundances? if referenceCorrect and correctionsAvailable: tempAdj,tempAll = \ RC.SortAndFilterLines(LTELines, ion, tuple(starData[1:6]), solarCorrect=referenceCorrect, solarLines=referenceLines[ion], solarCorrs=correctDict[ion], lineWeights=lineWeights[ion]) # correctedLines: # [[ab, line STR score, wl, "quality"], ...] # allLines: # [[ab, line STR score, wl],...] # We want to use np.arrays, so... allLines = np.array(tempAll) correctedLines = np.array(tempAdj) if len(allLines) == 0 or len(correctedLines) == 0: correctionsAvailable = False elif len(allLines) == 1 or len(correctedLines) == 1: print('Single Line determination:{0}'.format(starData[0])) print(allLines, correctedLines) # One plot per ion. if labelPlot: plotLabel = 'XP vs Ab for [{2}/H] in {0} {1}.'.\ format(clusterName, starName, el.getIonName(ion)) else: plotLabel = '' if referenceCorrect and correctionsAvailable: tempPoints = [] for line in uncorrLines[ion]: correctedAbs = [l[0] for l in correctedLines if \ u.in_range(l[2],line[0]-0.05, line[0]+0.05)] if len(correctedAbs) > 0: tempPoints.append( [line[1], np.mean(correctedAbs), line[3], line[0]]) else: tempPoints.append([line[1], line[5], line[3], line[0]]) XPAbPoints = np.array(tempPoints) else: XPAbPoints = np.array([[line[1],line[5],line[3],line[0]]\ for line in uncorrLines[ion]]) if labelPoints: # Label the points with the wavelength pointLabels = ['{0:2.3f}'.format(point[3]) \ for point in XPAbPoints] else: pointLabels = None ps.XPAbPlot(XPAbPoints, starName, ion, fileTag=fileTag + 'XPAb', plotTitle=plotLabel, pointLabels=pointLabels, showTrendLine=showTrendLine)
def GetAbsForStar(starData, clusterName='NGC-0752', ions=kAllIonList, \ filterBlends=False, refCorrect=False,\ refLines=None, refDict=None, lineWeights=None, useDAOSpec=False, modelAtms=None, pradks=None): # Get all the elemental abundances for the single passed star (params): # starData: (starName, Teff, LogG, VTurb, Met, Mass) # # Returns a dictionary of {ion:(Ab, std, #lines, avg Quality)...} starName = starData[0] starParms = tuple(starData[1:6]) abdict, uncorrLines, unusedMins, unusedMaxes = \ AB.CalcAbsAndLines(clusterName+' '+starName, starParms, ionList=ions, modelAtms=modelAtms, pradks=pradks, useDAOlines=useDAOSpec) # uncorrLines: # # {elem.ion:[[Wavelength, Ex.Pot., logGf, eqw, logRW, abund],...]} starAbDict = {} ionLUT = sorted(list(abdict.keys())) ionLUT = sorted(set(ionLUT + [ion for ion in SynthAbsDict.keys()\ if starName in SynthAbsDict[ion].keys()])) if refCorrect and (refLines is None or refDict is None): refCorrect = False for ion in ionLUT: # We'll make one line per ion. Note, synth elements won't # necessarily have lines in the table/dict. if ion not in list(uncorrLines.keys()) + list(SynthAbsDict.keys()): continue if refCorrect and ion not in refLines.keys(): correctionsAvail = False else: correctionsAvail = True # Does this element have NLTE corrections available? Note: we do # this BEFORE Solar corrections, which assumes that the same # NLTE corrections are already applied to any Solar corrections # we use. if ion in NLTEIons: LTELines = AB.CorrectNLTEAbs(ion, uncorrLines[ion], starParms) else: if ion in uncorrLines.keys(): LTELines = uncorrLines[ion] else: # Either synthesized lines, or none available LTELines = np.array([]) # Now apply "Solar" or "Astrophysical Log gf" corrections, if requested if correctionsAvail and (refCorrect or filterBlends) and ion in uncorrLines.keys(): tempAdj,tempAll = \ RC.SortAndFilterLines(LTELines, ion, starParms, filterBlends=filterBlends, solarCorrect=refCorrect, solarLines=refLines[ion], solarCorrs=refDict[ion], lineWeights=lineWeights[ion]) # correctedLines: # [[ab, line STR score, wl, "quality"], ...] # allLines: # [[ab, line STR score, wl],...] # We want to use np.arrays, so... allLines = np.array(tempAll) correctedLines = np.array(tempAdj) else: if len(LTELines) > 0: allLines = np.array(\ [[l[5], el.STR(l[2], l[1], starParms[0]), l[0]] \ for l in LTELines]) correctedLines = np.array(\ [[l[0], l[1], l[2], k.AbWeights[-1]] \ for l in allLines]) else: allLines = correctedLines = np.array([]) if ion in SynthAbsDict.keys() and \ starName in SynthAbsDict[ion].keys(): # We have a C I or N I synthesis: if ion == 6.0: nonSynthLines = np.array([l for l in correctedLines\ if l[2]<7110 or l[2]>7120]) elif ion == 7.0: # N I synthesis uses both the 7115 region (giants) # and the 7442 region (all). Only the 7442 region # has a potentially measured line, tho. nonSynthLines = np.array([l for l in correctedLines \ if np.floor(l[2]) != 7442]) else: nonSynthLines = [] synthArray = GetSynthLines(starName, ion,\ clusterName=clusterName) # Returned tuple: (synthMean, synthStd, synthCount) # Include our synthesis as the number of lines measured if len(nonSynthLines) == 0: starAbDict[ion] = [synthArray[0], synthArray[1],\ synthArray[2],k.NoAbWeight] else: mean = np.mean(nonSynthLines[:, 0]) std = np.std(nonSynthLines[:, 0]) ct = len(nonSynthLines) totalCt = ct + synthArray[2] totalMean = ((mean*ct)+(synthArray[0]*synthArray[2]))/\ (totalCt) totalStd = np.sqrt(\ (ct*(totalMean-mean)**2+ synthArray[2]*(synthArray[0]-mean)**2)/\ (totalCt-1)) starAbDict[ion] = [totalMean, totalStd, totalCt, k.NoAbWeight] # We have already created the abundance dictionary for this ion, # so skip out on the next part. continue else: # No synthesized lines need to be added. pass if refCorrect and len(correctedLines) > 0: linesToCount = correctedLines avgQ = np.mean(correctedLines[:, 3]) else: linesToCount = allLines avgQ = k.NoAbWeight if len(linesToCount) > 0: starAbDict[ion] = [ np.mean(linesToCount[:, 0]), np.std(linesToCount[:, 0]), len(linesToCount), avgQ ] else: # No lines to count. Make sure we don't have an entry: if ion in starAbDict.keys(): del starAbDict[ion] return starAbDict
def PlotAbs(clusterName, starData, ions, fileTag='', plotTitle='', filterBlends=False, referenceCorrect=False, labelPoints=False, useDAOSpec=False, modelAtms=None, pradks=None): pointLabels = None # Lookup the abundance(s) for the passed star, and plot them # (into a .png file). One element per plot. starName = starData[0] starParmTuple = tuple(starData[1:6]) isGiant = RC.isGiantStar(starParmTuple) if isGiant: modelPath = k.GiantModelPath else: modelPath = k.DwarfModelPath if modelAtms == None or pradks == None: modelFiles = mk.findDataFiles(modelPath) modelAtms, pradks = mk.LoadModels(modelFiles) # uncorrLines format: # {elem.ion:[[Wavelength, Ex.Pot., logGf, eqw, logRW, abund],...]} # abDict format: # {elem.ion:[abundance mean, ab. std.dev., # lines]} abdict, uncorrLines, unusedMin, unusedMax = \ AB.CalcAbsAndLines(clusterName+' '+starName, starParmTuple, ionList=ions, modelAtms=modelAtms, pradks=pradks, useDAOlines=useDAOSpec) if isGiant: # Obtain the reference corrections for a giant star - Note: this is # badly broken! So, we're just going to use the Solar corrections for # now: correctDict, referenceLines, lineWeights = \ RC.GetDwarfCorrections(ionList=ions, modelAtms=modelAtms, pradks=pradks, useDAOSpec=useDAOSpec) # correctDict, referenceLines, lineWeights = \ # GetGiantCorrections(ionList=ions, # modelAtms=modelAtms, # pradks=pradks) else: # ...or for a dwarf star. correctDict, referenceLines, lineWeights = \ RC.GetDwarfCorrections(ionList=ions, modelAtms=modelAtms, pradks=pradks, useDAOSpec=useDAOSpec) for ion in ions: # We'll make one plot per ion. pointLabels = [] redData = greenData = blueData = [] if ion not in uncorrLines.keys(): print('No {0:2.1f} lines for {1}.'.format(ion, starName)) continue if (referenceCorrect or filterBlends) and \ ion in referenceLines.keys() and ion in correctDict.keys() and \ ion in lineWeights.keys(): adjustedLines, dataPoints = \ RC.SortAndFilterLines(uncorrLines[ion], ion, starParmTuple, filterBlends=filterBlends, solarCorrect=referenceCorrect, solarLines=referenceLines[ion], solarCorrs=correctDict[ion], lineWeights=lineWeights[ion]) tempData = [] for line in uncorrLines[ion]: corrLine = u.find(lambda l: l[0] == line[0], dataPoints) if corrLine is not None: tempData.append(corrLine) else: tempData.append([line[5], el.STR(line[2], line[1], \ starParmTuple[0]),line[0]]) redData = np.array(tempData) else: dataPoints = np.array([[line[5], el.STR(line[2], line[1], starParmTuple[0]), line[0]] \ for line in uncorrLines[ion]]) if labelPoints: pointLabels = ['{0:4.3f}'.format(line[2]) for line in dataPoints] pointLabels.extend(['{0:4.3f}'.\ format(line[2]) for line in redData]) pointLabels.extend(['{0:4.3f}'.\ format(line[2]) for line in greenData]) pointLabels.extend(['{0:4.3f}'.\ format(line[2]) for line in blueData]) loSlope, loIntercept, rv, pv, err = \ ps.GetDetectionLimit(starParmTuple, ion, modelAtms=modelAtms, pradks=pradks) hiSlope, hiIntercept, rv, pv, err = \ ps.GetCoGLimit(starParmTuple, ion, modelAtms=modelAtms, pradks=pradks) ps.AbSTRPlot(starName, ion, dataPoints, redSet=redData, greenSet=greenData, blueSet=blueData, lowLimit=(loSlope, loIntercept), hiLimit=(hiSlope, hiIntercept), fileTag=fileTag, plotTitle=plotTitle, labelPoints=pointLabels)
def MakeTeffPlots(clusterName='NGC-0752', starDataList=None, fileTag='', referenceCorrect=False): # Function plots Teff vs. slope of (XP vs. [Fe/H]) for a range of temperatures. # Intended to provide a spectroscopic confirmation/adjustment # for photometrically-determined parameters. We assume that at the "correct" # temperature, the slope of XP vs. [Fe/H] would be zero. if starDataList is None: starDataList = STP.GetAllStarParms(clusterName=clusterName) dModelFiles = mk.findDataFiles(k.DwarfModelPath) dModelAtms, dPradks = mk.LoadModels(dModelFiles) gModelFiles = mk.findDataFiles(k.GiantModelPath) gModelAtms, gPradks = mk.LoadModels(gModelFiles) # Map Fe I Ab vs. Ex pot. ions = [26.0] abDict = {} dTeffRange = np.linspace(5000, 7000, 81) gTeffRange = np.linspace(4000, 6000, 81) for star in starDataList: starName = star[0] isGiant = RC.isGiantStar(star[1:]) if isGiant: modelAtms = gModelAtms pradks = gPradks tRange = gTeffRange if referenceCorrect: correctDict, referenceLines, lineWeights = \ RC.GetGiantCorrections(ionList=ions, modelAtms=modelAtms, pradks=pradks) else: modelAtms = dModelAtms pradks = dPradks tRange = dTeffRange if referenceCorrect: correctDict, referenceLines, lineWeights = \ RC.GetDwarfCorrections(ionList=ions, modelAtms=modelAtms, pradks=pradks) logG = star[2] vTurb = star[3] met = star[4] slopes = [] for Teff in tRange: unusedDict, uncorrLines, unusedMin, unusedMax = \ AB.CalcAbsAndLines(clusterName+' '+starName, tuple([Teff, star[2], star[3], star[4], star[5]]),\ ionList=ions, modelAtms=modelAtms, pradks=pradks) XPs = [] Abs = [] if referenceCorrect: adjLines, allLines = RC.SortAndFilterLines( uncorrLines[26.0], 26.0, tuple([Teff, star[2], star[3], star[4], star[5]]), solarCorrect=True, solarLines=referenceLines[26.0], solarCorrs=correctDict[26.0], lineWeights=lineWeights[26.0]) if len(adjLines) > 10: # Assume 10 Fe I lines needed for nice plots for line in adjLines: # XP isn't returned, so have to do a lookup into the # original list. XPs.append( u.find(lambda l: l[0] == line[2], uncorrLines[26.0])[1]) Abs.append(line[0]) if len(XPs) == 0 or len(Abs) == 0: # Either no corrections, or corrections failed XPs = [line[1] for line in uncorrLines[26.0]] Abs = [line[5] for line in uncorrLines[26.0]] slope, intercept, rVal, pVal, err = sp.stats.linregress(XPs, Abs) slopes.append(slope) # We have to flip because interp expects the xvalues to be # monotomically increasing interpTs = np.interp([-0.02, 0., 0.02], slopes[::-1], tRange[::-1]) if interpTs[0] > interpTs[1]: minusR = interpTs[1] - interpTs[2] plusR = interpTs[0] - interpTs[1] else: minusR = interpTs[1] - interpTs[0] plusR = interpTs[2] - interpTs[1] fig = pyplot.figure() TeffLabel = r'$T_{{eff}} = {0:4.0f}^{{+{1:4.0f}}}_{{-{2:4.0f}}}$)'.\ format(interpTs[1],minusR,plusR) pyplot.scatter(tRange, slopes, label=TeffLabel) pyplot.axhline(0.0, linestyle=':') pyplot.legend() pyplot.savefig(k.ParmPlotDir + 'Teff/' + star[0] + fileTag + '_FeSlope.png') pyplot.close()