I thought it might be useful to post the read/write code for the CalcImage CIP project file format. This is the text file that CalcImage uses to store all information (not contained in the PFE MDB file), for defining a quantitative mapping project.
For example to help Ben Buse here:
Quote from: Ben Buse on April 27, 2026, 07:10:03 AMAlso need to figure out how to load files into calcimage best.
At moment I'm creating a new blank project in calcimage and then loading each of the files as grd files. Is there a better way of doing this.
I tried loading the wds elements through the create project wizzard. But when I added eds grd files at the end, it said must be added before off peak maps.
So here is the code for reading and then, writing a CalcImage CIP project file:
Sub CalcImageReadWriteProjectFile(mode As Integer)
' Read or write the project file
' mode = 1 read project
' mode = 2 write project
ierror = False
On Error GoTo CalcImageReadWriteProjectFileError
Dim i As Integer, tFlag As Integer, j As Integer
Dim itemp6 As Integer
Dim tfilename As String
Dim astring As String, bstring As String
' Read project
If mode% = 1 Then
' Init project
Call CalcImageInitProject(Int(0))
If ierror Then Exit Sub
' Check for version of CIP file for reading only!
CalcImageProjectVersion% = CalcImageGetProjectFileVersion()
If ierror Then Exit Sub
' If file version is zero, call special routine for backward compatibility (write project uses current version)
If CalcImageProjectVersion% = 0 Then
Call CalcImageReadVersionZeroCIPFile(mode%)
If ierror Then Exit Sub
Exit Sub
End If
' Project file contains full path, but condition and image files do not (must be in same folder as CIP and MDB file)
Open CalcImageProjectFile$ For Input As #CalcImageProjectFileNumber%
Input #CalcImageProjectFileNumber%, CalcImageProjectVersion%, CalcImageProjectTitle$
' Check that CIP file is not a newer version
If CalcImageProjectVersion% > CIP_FILE_VERSION% Then GoTo CalcImageReadWriteProjectFileNewerCIPFile
' If version 2, read CalcImageSampleNameTitle field
If CalcImageProjectVersion% >= 2 Then
Input #CalcImageProjectFileNumber%, CalcImageSampleNameTitle$
End If
' Read and load probe data file name
Input #CalcImageProjectFileNumber%, tfilename$
tfilename$ = MiscGetPathOnly$(CalcImageProjectFile$) & tfilename$
' Check for files existing
If Trim$(tfilename$) = vbNullString Then GoTo CalcImageReadWriteProjectFileBlankCondition
If Dir$(tfilename$) = vbNullString Then GoTo CalcImageReadWriteProjectFileMissingCondition
' Load Probe database file name (full path)
ProbeDataFile$ = tfilename$
Line Input #CalcImageProjectFileNumber%, astring$ ' read entire parameter line and parse each parameter (for backward compatibility)
' Read sample number
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageProbeDataSample% = Val(bstring$)
' Read number of images
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageNumberofImageFiles% = Val(bstring$)
If CalcImageNumberofImageFiles% > MAXIMAGE% Then GoTo CalcImageReadWriteProjectFileTooManyImages
' Read CalcImageCalculateTotalsImageFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateTotalsImageFlag% = Val(bstring$)
' Read CalcImageCalculateStoichiometricOxygenImageFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateStoichiometricOxygenImageFlag% = Val(bstring$)
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateExcessOxygenImageFlag% = Val(bstring$)
' Read CalcImageCalculateNetIntensitiesFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateNetIntensitiesFlag% = Val(bstring$)
' Read CalcImageCalculateBgdIntensitiesFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateBgdIntensitiesFlag% = Val(bstring$)
' Read CalcImageCalculateKratioIntensitiesFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateKratioIntensitiesFlag% = Val(bstring$)
' Read CalcImageCalculateQuantPercentsFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateQuantPercentsFlag% = Val(bstring$)
' Read CalcImageCalculateAtomicPercentsFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateAtomicPercentsFlag% = Val(bstring$)
' Read CalcImageCalculateOxidePercentsFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateOxidePercentsFlag% = Val(bstring$)
' Read CalcImageCalculateFormulaBasisFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateFormulaBasisFlag% = Val(bstring$)
' Read CalcImageCalculateElementByDiffImageFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateElementByDiffImageFlag% = Val(bstring$)
' Read CalcImageCalculateDetectionLimitsFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateDetectionLimitsFlag% = Val(bstring$)
' Read CalcImageCalculateAnalyticalSensitivityFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateAnalyticalSensitivityFlag% = Val(bstring$)
' Read CalcImageCalculateLogWeightPercentsFlag
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateLogWeightPercentsFlag% = Val(bstring$)
' Read CalcImageCalculateDetectionLimitsBlankingFlag (new)
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateDetectionLimitsBlankingFlag% = Val(bstring$)
' Read CalcImageCalculateAnalyticalSensitivityBlankingFlag (new)
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageCalculateAnalyticalSensitivityBlankingFlag% = Val(bstring$)
' Read CalcImageBlankValuesOutsideMinMaxAnalyticalTotalFlag (new)
Call MiscParseStringToStringA(astring$, VbSpace, bstring$)
If ierror Then Exit Sub
CalcImageBlankValuesOutsideMinMaxAnalyticalTotalFlag% = Val(bstring$)
' To ensure that the elemental quant flag is always set
CalcImageCalculateQuantPercentsFlag% = -1 ' always calculate elemental percents!
' Read image files (count time is no longer utilized since intensity data is in cps from PI)
For i% = 1 To CalcImageNumberofImageFiles%
If CalcImageProjectVersion% <= 9 Then
Input #CalcImageProjectFileNumber%, CalcImageImageTypes%(i%), CalcImageElementRows%(i%), CalcImageCountTimes!(i%), CalcImageBeamCurrents!(i%), CalcImageBeamCurrents2!(i%), CalcImageTimeOfAcqs#(i%), CalcImageTimeOfAcqs2#(i%), CalcImageImageFiles$(i%)
Else
Input #CalcImageProjectFileNumber%, CalcImageImageTypes%(i%), CalcImageElementRows%(i%), CalcImageCountTimes!(i%), CalcImageBeamCurrents!(i%), CalcImageBeamCurrents2!(i%), CalcImageTimeOfAcqs#(i%), CalcImageTimeOfAcqs2#(i%), CalcImageImageFiles$(i%), CalcImageImagePositions!(i%)
End If
CalcImageImageFiles$(i%) = MiscGetPathOnly$(CalcImageProjectFile$) & CalcImageImageFiles$(i%)
Next i%
' Now read CPQ files and parameters
Call CalcImageCPQReadWriteProjectFile(mode%, CalcImageProjectFileNumber%)
If ierror Then Exit Sub
' If version 3, read misc parameters array (6 integers)
If CalcImageProjectVersion% >= 3 Then
Input #CalcImageProjectFileNumber%, CalcImageTitleAppendDataFlag%, CalcImageSurferOutputTemplateFlag%, CalcImageSurferSliceTemplateFlag%, CalcImageSurferPolygonTemplateFlag%, CalcImageSurferStripTemplateFlag%, UseManualAssignmentModeFlag%, itemp6%
End If
' If version 4, read EDS spectrum image flag (not utilized yet) and filename
If CalcImageProjectVersion% >= 4 Then
Input #CalcImageProjectFileNumber%, tFlag%, IntegrateEDSSpectrumImagingFilename$
End If
' If version 5, read scan type (0 = beam scan, 1 = stage scan) and scan orientation type (0 = Cameca stage/beam or JEOL beam scan (UL/LR), 1 = JEOL stage scan (UR/LL))
If CalcImageProjectVersion% >= 5 Then
Input #CalcImageProjectFileNumber%, CalcImageScanTypeFlag%, CalcImageOrientationTypeFlag%
End If
' If version 6, read analog signal image output flags and names
If CalcImageProjectVersion% >= 6 Then
Input #CalcImageProjectFileNumber%, CalcImageAnalogSignalFlags(1), CalcImageAnalogSignalLabels(1), CalcImageAnalogSignalFlags(2), CalcImageAnalogSignalLabels(2), CalcImageAnalogSignalFlags(3), CalcImageAnalogSignalLabels(3)
End If
' If version 7, read analog signal image filenames
If CalcImageProjectVersion% >= 7 Then
Input #CalcImageProjectFileNumber%, AnalogFilenames$(1), AnalogFilenames$(2), AnalogFilenames$(3)
If Trim$(AnalogFilenames$(1)) <> vbNullString Then AnalogFilenames$(1) = MiscGetPathOnly$(CalcImageProjectFile$) & AnalogFilenames$(1)
If Trim$(AnalogFilenames$(2)) <> vbNullString Then AnalogFilenames$(2) = MiscGetPathOnly$(CalcImageProjectFile$) & AnalogFilenames$(2)
If Trim$(AnalogFilenames$(3)) <> vbNullString Then AnalogFilenames$(3) = MiscGetPathOnly$(CalcImageProjectFile$) & AnalogFilenames$(3)
End If
' If version 8, read number of TDI files and number of intervals
If CalcImageProjectVersion% >= 8 Then
Input #CalcImageProjectFileNumber%, CalcImageNumberOfTDIImageFiles%, CalcImageNumberOfTDIImageIntervals%
For i% = 1 To CalcImageNumberOfTDIImageFiles%
Input #CalcImageProjectFileNumber%, CalcImageTDIImageIntervals%(i%), CalcImageTDIElementRows%(i%), CalcImageTDICountTimes!(i%), CalcImageTDIBeamCurrents!(i%), CalcImageTDIBeamCurrents2!(i%), CalcImageTDITimeOfAcqs#(i%), CalcImageTDITimeOfAcqs2#(i%), CalcImageTDIImageFiles$(i%)
CalcImageTDIImageFiles$(i%) = MiscGetPathOnly$(CalcImageProjectFile$) & CalcImageTDIImageFiles$(i%)
Next i%
End If
' If version 9, read output matrix corrections flag and unused flags
If CalcImageProjectVersion% >= 9 Then
Input #CalcImageProjectFileNumber%, CalcImageCalculateMatrixCorrectionsFlag%, tFlag%, tFlag%, tFlag%, tFlag%, tFlag%
End If
' If version 11, read dynamic element parameters (version 10 is above for image files- spectrometer positions)
If CalcImageProjectVersion% >= 11 Then
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFlag%
For j% = 1 To MAXCRITERIA%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceElement%(j%), DynamicSpecifiedElementByDifferenceValue!(j%), DynamicSpecifiedElementByDifferenceGreaterLess%(j%)
Next j%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceOperator1%, DynamicSpecifiedElementByDifferenceOperator2%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFormulaFlag%
For j% = 1 To MAXCRITERIA%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFormulaElement%(j%), DynamicSpecifiedElementByDifferenceFormulaValue!(j%), DynamicSpecifiedElementByDifferenceFormulaGreaterLess%(j%)
Next j%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFormulaOperator1%, DynamicSpecifiedElementByDifferenceFormulaOperator2%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToOxygenFlag%
For j% = 1 To MAXCRITERIA%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToOxygenElement%(j%), DynamicSpecifiedElementByStoichiometryToOxygenValue!(j%), DynamicSpecifiedElementByStoichiometryToOxygenGreaterLess%(j%)
Next j%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToOxygenOperator1%, DynamicSpecifiedElementByStoichiometryToOxygenOperator2%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToAnotherFlag%
For j% = 1 To MAXCRITERIA%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToAnotherElement%(j%), DynamicSpecifiedElementByStoichiometryToAnotherValue!(j%), DynamicSpecifiedElementByStoichiometryToAnotherGreaterLess%(j%)
Next j%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToAnotherOperator1%, DynamicSpecifiedElementByStoichiometryToAnotherOperator2%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementExcessOxygenByDroopFlag%
For j% = 1 To MAXCRITERIA%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementExcessOxygenByDroopElement%(j%), DynamicSpecifiedElementExcessOxygenByDroopValue!(j%), DynamicSpecifiedElementExcessOxygenByDroopGreaterLess%(j%)
Next j%
Input #CalcImageProjectFileNumber%, DynamicSpecifiedElementExcessOxygenByDroopOperator1%, DynamicSpecifiedElementExcessOxygenByDroopOperator2%
End If
' If version 12, read dynamic oxygen by stoichiometry parameters
If CalcImageProjectVersion% >= 12 Then
Input #CalcImageProjectFileNumber%, DynamicOxygenByStoichiometryFlag%
For j% = 1 To MAXCRITERIA%
Input #CalcImageProjectFileNumber%, DynamicOxygenByStoichiometryElement%(j%), DynamicOxygenByStoichiometryValue!(j%), DynamicOxygenByStoichiometryGreaterLess%(j%)
Next j%
Input #CalcImageProjectFileNumber%, DynamicOxygenByStoichiometryOperator1%, DynamicOxygenByStoichiometryOperator2%
End If
Close #CalcImageProjectFileNumber%
' Check for blank title
If Trim$(CalcImageProjectTitle$) = vbNullString Then CalcImageProjectTitle$ = "CalcImage Quantitative Image Project " & Now
' Check for blank file names
For i% = 1 To CalcImageNumberofImageFiles%
If Trim$(CalcImageImageFiles$(i%)) = vbNullString Then GoTo CalcImageReadWriteProjectFileBlankImage
If Dir$(CalcImageImageFiles$(i%)) = vbNullString Then GoTo CalcImageReadWriteProjectFileMissingImage
Next i%
End If
' Write project
If mode% = 2 Then
' Update CIP project file to current version
CalcImageProjectVersion% = CIP_FILE_VERSION%
' Check for files existing
If Trim$(ProbeDataFile$) = vbNullString Then GoTo CalcImageReadWriteProjectFileBlankCondition
If Dir$(ProbeDataFile$) = vbNullString Then GoTo CalcImageReadWriteProjectFileMissingCondition
For i% = 1 To CalcImageNumberofImageFiles%
If Trim$(CalcImageImageFiles$(i%)) = vbNullString Then GoTo CalcImageReadWriteProjectFileBlankImage
If Dir$(CalcImageImageFiles$(i%)) = vbNullString Then GoTo CalcImageReadWriteProjectFileMissingImage
Next i%
' Check for blank title
If Trim$(CalcImageProjectTitle$) = vbNullString Then CalcImageProjectTitle$ = "CalcImage Quantitative Image Project " & Now
If CalcImageNumberofImageFiles% > MAXIMAGE% Then GoTo CalcImageReadWriteProjectFileTooManyImages
' Project file does not contain full path (uses current CIP folder)
Open CalcImageProjectFile$ For Output As #CalcImageProjectFileNumber%
Print #CalcImageProjectFileNumber%, CalcImageProjectVersion%, VbDquote$ & CalcImageProjectTitle$ & VbDquote$
Print #CalcImageProjectFileNumber%, VbDquote$ & CalcImageSampleNameTitle$ & VbDquote$
Print #CalcImageProjectFileNumber%, VbDquote$ & MiscGetFileNameOnly$(ProbeDataFile$) & VbDquote$
Print #CalcImageProjectFileNumber%, CalcImageProbeDataSample%, CalcImageNumberofImageFiles%, CalcImageCalculateTotalsImageFlag%, CalcImageCalculateStoichiometricOxygenImageFlag%, CalcImageCalculateExcessOxygenImageFlag%, CalcImageCalculateNetIntensitiesFlag%, CalcImageCalculateBgdIntensitiesFlag%, CalcImageCalculateKratioIntensitiesFlag%, CalcImageCalculateQuantPercentsFlag%, CalcImageCalculateAtomicPercentsFlag%, CalcImageCalculateOxidePercentsFlag%, CalcImageCalculateFormulaBasisFlag%, CalcImageCalculateElementByDiffImageFlag%, CalcImageCalculateDetectionLimitsFlag%, CalcImageCalculateAnalyticalSensitivityFlag%, CalcImageCalculateLogWeightPercentsFlag%, CalcImageCalculateDetectionLimitsBlankingFlag%, CalcImageCalculateAnalyticalSensitivityBlankingFlag%, CalcImageBlankValuesOutsideMinMaxAnalyticalTotalFlag%
' Write on and off peak image files
For i% = 1 To CalcImageNumberofImageFiles%
If CalcImageProjectVersion% <= 9 Then
Print #CalcImageProjectFileNumber%, CalcImageImageTypes%(i%), CalcImageElementRows%(i%), Format$(CalcImageCountTimes!(i%), f83$), CalcImageBeamCurrents!(i%), CalcImageBeamCurrents2!(i%), CalcImageTimeOfAcqs#(i%), CalcImageTimeOfAcqs2#(i%), VbDquote$ & MiscGetFileNameOnly$(CalcImageImageFiles$(i%)) & VbDquote$
Else
Print #CalcImageProjectFileNumber%, CalcImageImageTypes%(i%), CalcImageElementRows%(i%), Format$(CalcImageCountTimes!(i%), f83$), CalcImageBeamCurrents!(i%), CalcImageBeamCurrents2!(i%), CalcImageTimeOfAcqs#(i%), CalcImageTimeOfAcqs2#(i%), VbDquote$ & MiscGetFileNameOnly$(CalcImageImageFiles$(i%)) & VbDquote$, CalcImageImagePositions!(i%)
End If
Next i%
' Now write CPQ files and parameters
Call CalcImageCPQReadWriteProjectFile(mode%, CalcImageProjectFileNumber%)
If ierror Then Exit Sub
' Now write misc parameters
Print #CalcImageProjectFileNumber%, CalcImageTitleAppendDataFlag%, CalcImageSurferOutputTemplateFlag%, CalcImageSurferSliceTemplateFlag%, CalcImageSurferPolygonTemplateFlag%, CalcImageSurferStripTemplateFlag%, UseManualAssignmentModeFlag, itemp6%
' Now write EDS spectrum image flag (not utilized yet) and filename
Print #CalcImageProjectFileNumber%, tFlag%, VbDquote$ & IntegrateEDSSpectrumImagingFilename$ & VbDquote$
' Now write scan type (0 = beam scan, 1 = stage scan) and scan orientation type (0 = Cameca stage/beam or JEOL beam scan (UL/LR), 1 = JEOL stage scan (UR/LL))
Print #CalcImageProjectFileNumber%, CalcImageScanTypeFlag%, CalcImageOrientationTypeFlag%
' Now write analog signal image output flags and names
Print #CalcImageProjectFileNumber%, CalcImageAnalogSignalFlags(1), VbDquote$ & CalcImageAnalogSignalLabels(1) & VbDquote, CalcImageAnalogSignalFlags(2), VbDquote$ & CalcImageAnalogSignalLabels(2) & VbDquote, CalcImageAnalogSignalFlags(3), VbDquote$ & CalcImageAnalogSignalLabels(3) & VbDquote
' Now write analog signal file names
Print #CalcImageProjectFileNumber%, VbDquote$ & MiscGetFileNameOnly$(AnalogFilenames$(1)) & VbDquote$, VbDquote$ & MiscGetFileNameOnly$(AnalogFilenames$(2)) & VbDquote$, VbDquote$ & MiscGetFileNameOnly$(AnalogFilenames$(3)) & VbDquote$
' Now write number of TDI files and number of TDI intervals
Print #CalcImageProjectFileNumber%, CalcImageNumberOfTDIImageFiles%, CalcImageNumberOfTDIImageIntervals%
' Write TDI image files
For i% = 1 To CalcImageNumberOfTDIImageFiles%
Print #CalcImageProjectFileNumber%, CalcImageTDIImageIntervals%(i%), CalcImageTDIElementRows%(i%), Format$(CalcImageTDICountTimes!(i%), f83$), CalcImageTDIBeamCurrents!(i%), CalcImageTDIBeamCurrents2!(i%), CalcImageTDITimeOfAcqs#(i%), CalcImageTDITimeOfAcqs2#(i%), VbDquote & MiscGetFileNameOnly$(CalcImageTDIImageFiles$(i%)) & VbDquote
Next i%
' Write newest calculation flags
Print #CalcImageProjectFileNumber%, CalcImageCalculateMatrixCorrectionsFlag%, tFlag%, tFlag%, tFlag%, tFlag%, tFlag%
' Write dynamic element parameters
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFlag%
For j% = 1 To MAXCRITERIA%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceElement%(j%), DynamicSpecifiedElementByDifferenceValue!(j%), DynamicSpecifiedElementByDifferenceGreaterLess%(j%)
Next j%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceOperator1%, DynamicSpecifiedElementByDifferenceOperator2%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFormulaFlag%
For j% = 1 To MAXCRITERIA%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFormulaElement%(j%), DynamicSpecifiedElementByDifferenceFormulaValue!(j%), DynamicSpecifiedElementByDifferenceFormulaGreaterLess%(j%)
Next j%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByDifferenceFormulaOperator1%, DynamicSpecifiedElementByDifferenceFormulaOperator2%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToOxygenFlag%
For j% = 1 To MAXCRITERIA%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToOxygenElement%(j%), DynamicSpecifiedElementByStoichiometryToOxygenValue!(j%), DynamicSpecifiedElementByStoichiometryToOxygenGreaterLess%(j%)
Next j%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToOxygenOperator1%, DynamicSpecifiedElementByStoichiometryToOxygenOperator2%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToAnotherFlag%
For j% = 1 To MAXCRITERIA%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToAnotherElement%(j%), DynamicSpecifiedElementByStoichiometryToAnotherValue!(j%), DynamicSpecifiedElementByStoichiometryToAnotherGreaterLess%(j%)
Next j%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementByStoichiometryToAnotherOperator1%, DynamicSpecifiedElementByStoichiometryToAnotherOperator2%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementExcessOxygenByDroopFlag%
For j% = 1 To MAXCRITERIA%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementExcessOxygenByDroopElement%(j%), DynamicSpecifiedElementExcessOxygenByDroopValue!(j%), DynamicSpecifiedElementExcessOxygenByDroopGreaterLess%(j%)
Next j%
Print #CalcImageProjectFileNumber%, DynamicSpecifiedElementExcessOxygenByDroopOperator1%, DynamicSpecifiedElementExcessOxygenByDroopOperator2%
' Write dynamic oxygen by stoichiometry parameters
Print #CalcImageProjectFileNumber%, DynamicOxygenByStoichiometryFlag%
For j% = 1 To MAXCRITERIA%
Print #CalcImageProjectFileNumber%, DynamicOxygenByStoichiometryElement%(j%), DynamicOxygenByStoichiometryValue!(j%), DynamicOxygenByStoichiometryGreaterLess%(j%)
Next j%
Print #CalcImageProjectFileNumber%, DynamicOxygenByStoichiometryOperator1%, DynamicOxygenByStoichiometryOperator2%
Close #CalcImageProjectFileNumber%
End If
Exit Sub
' Errors
CalcImageReadWriteProjectFileError:
CalcImageProjectFile$ = vbNullString
CalcImageSampleNameTitle$ = vbNullString
MsgBox Error$, vbOKOnly + vbCritical, "CalcImageReadWriteProjectFile"
Close #CalcImageProjectFileNumber%
ierror = True
Exit Sub
CalcImageReadWriteProjectFileNewerCIPFile:
msg$ = "CalcImage CIP file (" & CalcImageProjectFile$ & ") version (" & Format$(CalcImageProjectVersion%) & ") was created by a newer version of the CalcImage application. Please update Probe for EPMA to get the most recent version of CalcImage"
MsgBox msg$, vbOKOnly + vbExclamation, "CalcImageReadWriteProjectFile"
Close #CalcImageProjectFileNumber%
ProbeDataFile$ = vbNullString
ierror = True
Exit Sub
CalcImageReadWriteProjectFileBlankCondition:
msg$ = "Probe data file name is blank in CalcImage Project File " & CalcImageProjectFile$
MsgBox msg$, vbOKOnly + vbExclamation, "CalcImageReadWriteProjectFile"
Close #CalcImageProjectFileNumber%
ProbeDataFile$ = vbNullString
ierror = True
Exit Sub
CalcImageReadWriteProjectFileMissingCondition:
msg$ = "Probe data file " & tfilename$ & " is missing"
MsgBox msg$, vbOKOnly + vbExclamation, "CalcImageReadWriteProjectFile"
Close #CalcImageProjectFileNumber%
CalcImageProjectFile$ = vbNullString
CalcImageSampleNameTitle$ = vbNullString
ierror = True
Exit Sub
CalcImageReadWriteProjectFileTooManyImages:
msg$ = "Too many image files specified in CalcImage Project File " & CalcImageProjectFile$
MsgBox msg$, vbOKOnly + vbExclamation, "CalcImageReadWriteProjectFile"
Close #CalcImageProjectFileNumber%
CalcImageProjectFile$ = vbNullString
CalcImageSampleNameTitle$ = vbNullString
ierror = True
Exit Sub
CalcImageReadWriteProjectFileBlankImage:
msg$ = "Image file number " & Str$(i%) & " name is blank in CalcImage Project File " & CalcImageProjectFile$
MsgBox msg$, vbOKOnly + vbExclamation, "CalcImageReadWriteProjectFile"
Close #CalcImageProjectFileNumber%
CalcImageProjectFile$ = vbNullString
CalcImageSampleNameTitle$ = vbNullString
ierror = True
Exit Sub
CalcImageReadWriteProjectFileMissingImage:
msg$ = "Image file " & CalcImageImageFiles$(i%) & " is missing"
MsgBox msg$, vbOKOnly + vbExclamation, "CalcImageReadWriteProjectFile"
Close #CalcImageProjectFileNumber%
CalcImageProjectFile$ = vbNullString
CalcImageSampleNameTitle$ = vbNullString
ierror = True
Exit Sub
End Sub
Note that additional explanation is provided in the CalcImage Help file:
(https://smf.probesoftware.com/gallery/1_28_04_26_11_14_40.png)
which can be accessed from the CalcImage Help menu.
Thanks for this post and the help file flag.
I'm just working through programming it in python.
I love this entry in the file definition, it made me smile
The next line contains flags for output of analog signal images:
0 "SE" 0 "BSE" 0 "CL"
"MSH4-1_00653_VS1.grd" "" ""
It's pretty self explanatory
What do the zeros mean in first line?
Second line is a list of the file names, does "" mean no file present
here's the code so far
#where only one set of maps in folder
#where uses last sample in mdb
#where mdb in same folder and only one mdb present
import tkinter
from tkinter import filedialog
from numpy import genfromtxt
import datetime
import pyodbc
cndfile = tkinter.filedialog.askopenfile(title="Select WDS element .cnd file")
reader = csv.reader(open(cndfile.name), delimiter=" ")
d = list(reader)
path = filedialog.askdirectory(title="Select location of csv kratio map files")
fc = open(path + '/' + 'test cip creation.cip','w')
fc.write('12'+' '+'"'+'CalcImage Quantitative Image Project'+' '+datetime.datetime.now().strftime("%x")+' '+datetime.datetime.now().strftime("%X")+'"')
for fileMDB in glob.glob(os.path.join(path,'*.MDB')):
print(fileMDB)
MDBname = re.sub("[]'[]",'',fileMDB.split('\\')[1]).split('.MDB')[0]
fc.write('"'+MDBname+'_'+ProjectName+'00001_'+'"')
fc.write('"'+MDBfile+'"')
MDB = fileMDB
DRV = 'Microsoft Access Driver (*.mdb, *.accdb)'
PWD = 'pw'
con = pyodbc.connect('DRIVER={};DBQ={};PWD={}'.format(DRV,MDB,PWD))
cur = con.cursor()
SQL = 'SELECT * FROM Sample;'
rows = cur.execute(SQL).fetchall()
LastSample = len(rows)
cur.close()
con.close()
MapCounter = len(glob.glob1(path,'*_.grd'))
MapCounterEDS = len(glob.glob1(path,'*EDS.grd'))
#MinusOxygen = 1
MapCounterPOFF = len(glob.glob1(path,'*POFF.grd'))
MapCounterNOFF = len(glob.glob1(path,'*NOFF.grd'))
#NumMaps = MapCounter+MapCounterEDS-MinusOxygen
NumMaps = MapCounter+MapCounterEDS+MapCounterPOFF+MapCounterNOFF
TotalsImageFlag = -1
StoicOxFlag = -1
ExcessOxFlag = 0
NetIntenFlag = 0
BgdIntenFlag = 0
KratioIntenFlag = 0
QuantPercFlag = -1
AtomPercFlag = 0
OxidePercFlag = -1
FormulaBasisFlag = 0
EleDiffFlag = 0
DetLimFlag = 0
ErrorFlag = 0
LogPctFlag = 0
DLBlankFlag = 0
ErrBlankFlag = 0
Final = 0
sub = '$XM_AP_SA_DWELL_TIME%0'
WDSDwell = [s for s in d if sub in s][0][1]
sub2 = '$XM_DATA_SAVE_DATE'
offset = 693594
#exceldate = datetime.datetime.date(datetime.datetime.strptime([s for s in d if sub2 in s][0][1],"%Y/%m/%d")).toordinal()-offset
exceltim = datetime.datetime(1899,12,30)
cnddatetime=[s for s in d if sub2 in s][0][1]+' '+[s for s in d if sub2 in s][0][2]
delta=datetime.datetime.strptime(cnddatetime,'%Y/%m/%d %H:%M:%S')-exceltim
excelstore = float(delta.days)+(float(delta.seconds)/86400)
sub3 = '$XM_CP_DATE'
cnddatetime3=[s for s in d if sub3 in s][0][1]+' '+[s for s in d if sub3 in s][0][2]
delta3=datetime.datetime.strptime(cnddatetime3,'%Y/%m/%d %H:%M:%S')-exceltim
excelstore3 = float(delta3.days)+(float(delta3.seconds)/86400)
fc.write(str(LastSample)+spacer+str(NumMaps)+spacer+str(TotalsImageFlag)+spacer+str(StoicOxFlag)+spacer+str(ExcessOxFlag)+spacer+str(NetIntenFlag)+spacer+str(BgdIntenFlag)+spacer+str(KratioIntenFlag)+spacer+str(QuantPercFlag)+spacer+str(AtomPercFlag)+spacer+str(OxidePercFlag)+spacer+str(FormulaBasisFlag)+spacer+str(EleDiffFlag)+spacer+str(DetLimFlag)+spacer+str(ErrorFlag)+spacer+str(LogPctFlag)+spacer+str(DLBlankFlag)+spacer+str(ErrBlankFlag)+spacer+str(Final))
PreBeam = "{:.3f}".format(float([s for s in d if '$XM_DATA_PROBE_CURRENT_PRE' in s][0][1])*1e9)
PostBeam = "{:.3f}".format(float([s for s in d if '$XM_DATA_PROBE_CURRENT_POST' in s][0][1])*1e9)
for fileGRD in glob.glob(os.path.join(path,'*_.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('0'+spacer+str(ChanNum)+spacer+str(WDSDwell)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"')
livefile = tkinter.filedialog.askopenfile(title="Select live time .csv file")
livedata = genfromtxt(livefile, delimiter=',')
EDSLive = np.median(livedata)
for fileGRD in glob.glob(os.path.join(path,'*EDS.grd')):
print(fileGRD)
ChanNum = 0
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('0'+spacer+str(ChanNum)+spacer+str(EDSLive)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"')
for fileGRD in glob.glob(os.path.join(path,'*POFF.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('1'+spacer+str(ChanNum)+spacer+str(WDSDwell)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"')
for fileGRD in glob.glob(os.path.join(path,'*NOFF.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('2'+spacer+str(ChanNum)+spacer+str(WDSDwell)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"')
fc.write('10')
fc.write(' 0 0 0 0 0 0 0 0 0 0 ')
fc.write('0')
TitleAppendFlag = -1
SurferTemplateFlag = 0
SurferSliceTemplateFlag = 0
SurferPolyTemplateFlag = 0
SurferStripTemplateFlag = 0
SpareFlag1 = 0
SpareFlag2 = 0
fc.write(TitleAppendFlag+spacer+SurferTemplateFlag+spacer+SurferSliceTemplateFlag+spacer+SurferPolyTemplateFlag+spacer+SurferStripTemplateFlag+spacer+SpareFlag1+spacer+SpareFlag2)
#EDS spectrum image not utilized
SpecImageFlag = 0
fc.write(SpecImageFlag+spacer+'"'+'"')
ScanType = 0 #0=beam 1=stage
StagePolarity = 0 #0=cameca 1=jeol
fc.write(ScanType+spacer+StagePolarity)
fc.write('0'+spacer+'"'+'SE'+'"'+spacer+'0'+spacer+'"'+'BSE'+'"'+spacer+'0'+spacer+'"'+'CL'+'"')
for fileGRD in glob.glob(os.path.join(path,'*SEI.grd')):
print(fileGRD)
SEIname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
for fileGRD in glob.glob(os.path.join(path,'*COMP.grd')):
print(fileGRD)
COMPname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write(SEIname+spacer+COMPname+spacer+'"'+'"')
#tdi corrections
tdi_num = 0 #number of tdi maps
tdi_intervals = 0 #number of tdi intervals
fc.write(tdi_num+spacer+tdi_intervals)
#placeholder flags
fc.write(' 0 0 0 0 0 0 ')
Quote from: Ben Buse on May 05, 2026, 07:25:57 AMThanks for this post and the help file flag.
I'm just working through programming it in python.
I love this entry in the file definition, it made me smile
The next line contains flags for output of analog signal images:
0 "SE" 0 "BSE" 0 "CL"
"MSH4-1_00653_VS1.grd" "" ""
It's pretty self explanatory
What do the zeros mean in first line?
Sorry about that! :)
The code from above is:
' If version 6, read analog signal image output flags and names
If CalcImageProjectVersion% >= 6 Then
Input #CalcImageProjectFileNumber%, CalcImageAnalogSignalFlags(1), CalcImageAnalogSignalLabels(1), CalcImageAnalogSignalFlags(2), CalcImageAnalogSignalLabels(2), CalcImageAnalogSignalFlags(3), CalcImageAnalogSignalLabels(3)
End If
The CalcImageAnalogSignalFlags parameters are booleans (0 or -1) and indicates if the image is to be displayed along with the x-ray maps as seen here in the GUI:
(https://smf.probesoftware.com/gallery/1_21_10_16_6_51_00.png)
Quote from: Ben Buse on May 05, 2026, 07:25:57 AMSecond line is a list of the file names, does "" mean no file present
The code is:
' If version 7, read analog signal image filenames
If CalcImageProjectVersion% >= 7 Then
Input #CalcImageProjectFileNumber%, AnalogFilenames$(1), AnalogFilenames$(2), AnalogFilenames$(3)
If Trim$(AnalogFilenames$(1)) <> vbNullString Then AnalogFilenames$(1) = MiscGetPathOnly$(CalcImageProjectFile$) & AnalogFilenames$(1)
If Trim$(AnalogFilenames$(2)) <> vbNullString Then AnalogFilenames$(2) = MiscGetPathOnly$(CalcImageProjectFile$) & AnalogFilenames$(2)
If Trim$(AnalogFilenames$(3)) <> vbNullString Then AnalogFilenames$(3) = MiscGetPathOnly$(CalcImageProjectFile$) & AnalogFilenames$(3)
End If
So yes, an empty double quotes means no image file was specified.
Great thanks
Ok here's latest version of the code and the file generated attached
When I load the generated cip file in CalcImage, it says 'input past end of file' so I'm obviously missing something
Should each line have a leading zero?
And I see I've missed the dynamic element feature lines at the end, - I guess I need to add them.
#where only one set of maps in folder
#where uses last sample in mdb
#where mdb in same folder and only one mdb present
import tkinter
from tkinter import filedialog
import numpy as np
from numpy import genfromtxt
import csv
import datetime
import pyodbc
import glob
import re
import os
cndfile = tkinter.filedialog.askopenfile(title="Select WDS element .cnd file")
reader = csv.reader(open(cndfile.name), delimiter=" ")
d = list(reader)
ProjectName = ' '.join(d[29][1:len(d[29])])
path = filedialog.askdirectory(title="Select location of grd files")
fc = open(path + '/' + 'test cip creation.cip','w')
fc.write('12'+' '+'"'+'CalcImage Quantitative Image Project'+' '+datetime.datetime.now().strftime("%x")+' '+datetime.datetime.now().strftime("%X")+'"'+'\n')
for fileMDB in glob.glob(os.path.join(path,'*.MDB')):
print(fileMDB)
MDBname = re.sub("[]'[]",'',fileMDB.split('\\')[1]).split('.MDB')[0]
MDBfile = re.sub("[]'[]",'',fileMDB.split('\\')[1])
spacer = ' '
fc.write('"'+MDBname+'_'+ProjectName+'00001_'+'"'+'\n')
fc.write('"'+MDBfile+'"'+'\n')
MDB = fileMDB
DRV = 'Microsoft Access Driver (*.mdb, *.accdb)'
PWD = 'pw'
con = pyodbc.connect('DRIVER={};DBQ={};PWD={}'.format(DRV,MDB,PWD))
cur = con.cursor()
SQL = 'SELECT * FROM Sample;'
rows = cur.execute(SQL).fetchall()
LastSample = len(rows)
cur.close()
con.close()
MapCounter = len(glob.glob1(path,'*_.grd'))
MapCounterEDS = len(glob.glob1(path,'*EDS.grd'))
#MinusOxygen = 1
MapCounterPOFF = len(glob.glob1(path,'*POFF.grd'))
MapCounterNOFF = len(glob.glob1(path,'*NOFF.grd'))
#NumMaps = MapCounter+MapCounterEDS-MinusOxygen
NumMaps = MapCounter+MapCounterEDS+MapCounterPOFF+MapCounterNOFF
TotalsImageFlag = -1
StoicOxFlag = -1
ExcessOxFlag = 0
NetIntenFlag = 0
BgdIntenFlag = 0
KratioIntenFlag = 0
QuantPercFlag = -1
AtomPercFlag = 0
OxidePercFlag = -1
FormulaBasisFlag = 0
EleDiffFlag = 0
DetLimFlag = 0
ErrorFlag = 0
LogPctFlag = 0
DLBlankFlag = 0
ErrBlankFlag = 0
Final = 0
sub = '$XM_AP_SA_DWELL_TIME%0'
WDSDwell = [s for s in d if sub in s][0][1]
sub2 = '$XM_DATA_SAVE_DATE'
offset = 693594
#exceldate = datetime.datetime.date(datetime.datetime.strptime([s for s in d if sub2 in s][0][1],"%Y/%m/%d")).toordinal()-offset
exceltim = datetime.datetime(1899,12,30)
cnddatetime=[s for s in d if sub2 in s][0][1]+' '+[s for s in d if sub2 in s][0][2]
delta=datetime.datetime.strptime(cnddatetime,'%Y/%m/%d %H:%M:%S')-exceltim
excelstore = float(delta.days)+(float(delta.seconds)/86400)
sub3 = '$XM_CP_DATE'
cnddatetime3=[s for s in d if sub3 in s][0][1]+' '+[s for s in d if sub3 in s][0][2]
delta3=datetime.datetime.strptime(cnddatetime3,'%Y/%m/%d %H:%M:%S')-exceltim
excelstore3 = float(delta3.days)+(float(delta3.seconds)/86400)
fc.write(str(LastSample)+spacer+str(NumMaps)+spacer+str(TotalsImageFlag)+spacer+str(StoicOxFlag)+spacer+str(ExcessOxFlag)+spacer+str(NetIntenFlag)+spacer+str(BgdIntenFlag)+spacer+str(KratioIntenFlag)+spacer+str(QuantPercFlag)+spacer+str(AtomPercFlag)+spacer+str(OxidePercFlag)+spacer+str(FormulaBasisFlag)+spacer+str(EleDiffFlag)+spacer+str(DetLimFlag)+spacer+str(ErrorFlag)+spacer+str(LogPctFlag)+spacer+str(DLBlankFlag)+spacer+str(ErrBlankFlag)+spacer+str(Final)+'\n')
PreBeam = "{:.3f}".format(float([s for s in d if '$XM_DATA_PROBE_CURRENT_PRE' in s][0][1])*1e9)
PostBeam = "{:.3f}".format(float([s for s in d if '$XM_DATA_PROBE_CURRENT_POST' in s][0][1])*1e9)
for fileGRD in glob.glob(os.path.join(path,'*_.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('0'+spacer+str(ChanNum)+spacer+str(WDSDwell)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+'\n')
livefile = tkinter.filedialog.askopenfile(title="Select live time .csv file")
livedata = genfromtxt(livefile, delimiter=',')
EDSLive = np.median(livedata)
for fileGRD in glob.glob(os.path.join(path,'*EDS.grd')):
print(fileGRD)
ChanNum = 0
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('0'+spacer+str(ChanNum)+spacer+str(EDSLive)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+'\n')
for fileGRD in glob.glob(os.path.join(path,'*POFF.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('1'+spacer+str(ChanNum)+spacer+str(WDSDwell)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+'\n')
for fileGRD in glob.glob(os.path.join(path,'*NOFF.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write('2'+spacer+str(ChanNum)+spacer+str(WDSDwell)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+'\n')
fc.write('10'+'\n')
fc.write(' 0 0 0 0 0 0 0 0 0 0 '+'\n')
fc.write('0'+'\n')
TitleAppendFlag = -1
SurferTemplateFlag = 0
SurferSliceTemplateFlag = 0
SurferPolyTemplateFlag = 0
SurferStripTemplateFlag = 0
SpareFlag1 = 0
SpareFlag2 = 0
fc.write(str(TitleAppendFlag)+spacer+str(SurferTemplateFlag)+spacer+str(SurferSliceTemplateFlag)+spacer+str(SurferPolyTemplateFlag)+spacer+str(SurferStripTemplateFlag)+spacer+str(SpareFlag1)+spacer+str(SpareFlag2)+'\n')
#EDS spectrum image not utilized
SpecImageFlag = 0
fc.write(str(SpecImageFlag)+spacer+'"'+'"'+'\n')
#Could read scan type from cnd file. Are these flags used?
ScanType = 0 #0=beam 1=stage
StagePolarity = 0 #0=cameca 1=jeol
fc.write(str(ScanType)+spacer+str(StagePolarity)+'\n')
SEIflag = 0
COMPflag = 0
for fileGRD in glob.glob(os.path.join(path,'*SEI.grd')):
print(fileGRD)
SEIname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
SEIflag = 1
for fileGRD in glob.glob(os.path.join(path,'*COMP.grd')):
print(fileGRD)
COMPname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
COMPflag = 1
fc.write(str(SEIflag)+spacer+'"'+'SE'+'"'+spacer+str(COMPflag)+spacer+'"'+'BSE'+'"'+spacer+'0'+spacer+'"'+'CL'+'"'+'\n')
fc.write(SEIname+spacer+COMPname+spacer+'"'+'"'+'\n')
#tdi corrections
tdi_num = 0 #number of tdi maps
tdi_intervals = 0 #number of tdi intervals
fc.write(str(tdi_num)+spacer+str(tdi_intervals)+'\n')
#placeholder flags
fc.write(' 0 0 0 0 0 0 '+'\n')
fc.close()
Quote from: Ben Buse on May 06, 2026, 03:37:20 AMWhen I load the generated cip file in CalcImage, it says 'input past end of file' so I'm obviously missing something
Yup, you'll need to add placeholders for dynamic elements. The other approach is to edit the version number at the beginning of the CIP file to an earlier version number, and then CalcImage will automatically add these missing placeholders...
Quote from: Ben Buse on May 06, 2026, 03:37:20 AMShould each line have a leading zero?
For the dynamic elements? See the code and/or look at one of your own CIP files. Here's an example from one of my projects:
11 "CalcImage Quantitative Image Project 5/9/2023 9:32:09 AM"
"Sulfide_Interferences_04-15-2016_FeCu_Sulfide_00053_"
"Sulfide_Interferences_04-15-2016.MDB"
12 15 -1 0 0 0 0 0 -1 -1 0 0 0 -1 -1 0 0 0 0
0 7 1.000 99.7344 100.009 42475.8307291667 42476.03375 "FeCu_Sulfide_00053_SP1_Ca_PET_.grd" 0
0 4 1.000 99.7344 100.009 42475.8307291667 42476.03375 "FeCu_Sulfide_00053_SP2_Mo_LPET_.grd" 0
0 5 1.000 99.7344 100.009 42475.8307291667 42476.03375 "FeCu_Sulfide_00053_SP3_Zn_LLIF_.grd" 0
0 2 1.000 99.7344 100.009 42475.8307291667 42476.03375 "FeCu_Sulfide_00053_SP4_S_PET_.grd" 0
0 1 1.000 99.7344 100.009 42475.8307291667 42476.03375 "FeCu_Sulfide_00053_SP5_Fe_LIF_.grd" 0
2 7 .500 100.101 100.177 42476.1366319444 42476.2391319444 "FeCu_Sulfide_00053_SP1_Ca_PET__MOFF.grd" 0
1 7 .500 99.9938 100.116 42476.0338888889 42476.1364814815 "FeCu_Sulfide_00053_SP1_Ca_PET__POFF.grd" 0
2 4 .500 100.101 100.177 42476.1366319444 42476.2391319444 "FeCu_Sulfide_00053_SP2_Mo_LPET__MOFF.grd" 0
1 4 .500 99.9938 100.116 42476.0338888889 42476.1364814815 "FeCu_Sulfide_00053_SP2_Mo_LPET__POFF.grd" 0
2 5 .500 100.101 100.177 42476.1366319444 42476.2391319444 "FeCu_Sulfide_00053_SP3_Zn_LLIF__MOFF.grd" 0
1 5 .500 99.9938 100.116 42476.0338888889 42476.1364814815 "FeCu_Sulfide_00053_SP3_Zn_LLIF__POFF.grd" 0
2 2 .500 100.101 100.177 42476.1366319444 42476.2391319444 "FeCu_Sulfide_00053_SP4_S_PET__MOFF.grd" 0
1 2 .500 99.9938 100.116 42476.0338888889 42476.1364814815 "FeCu_Sulfide_00053_SP4_S_PET__POFF.grd" 0
2 1 .500 100.101 100.177 42476.1366319444 42476.2391319444 "FeCu_Sulfide_00053_SP5_Fe_LIF__MOFF.grd" 0
1 1 .500 99.9938 100.116 42476.0338888889 42476.1364814815 "FeCu_Sulfide_00053_SP5_Fe_LIF__POFF.grd" 0
7
0 0 0 0 0 0 0
0
-1 0 0 0 0 0 0
0 ""
1 0
0 "SE" 0 "BSE" 0 "CL"
"" "" ""
0 0
0 0 0 0 0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
Thanks John,
Sorry another slip up, leading zeros should have read leading space.
I see from your example from line 4 onwards there is a leading space before first value in each line
Sorry for another question what are the zeros after the map name, which are shown in your example but not in the help file
..."FeCu_Sulfide_00053_SP1_Ca_PET_.grd" 0As in this line
0 7 1.000 99.7344 100.009 42475.8307291667 42476.03375 "FeCu_Sulfide_00053_SP1_Ca_PET_.grd" 0
Quote from: Ben Buse on May 07, 2026, 12:41:30 AMSorry for another question what are the zeros after the map name, which are shown in your example but not in the help file
I had to look this up myself! As shown in the code example here:
https://smf.probesoftware.com/index.php?topic=1844.msg14165#msg14165
it's for recording the spectrometer positions for performing multi-point background corrections in CalcImage:
https://smf.probesoftware.com/index.php?topic=249.msg12670#msg12670
https://smf.probesoftware.com/index.php?topic=510.msg12799#msg12799
These values are zero unless one is loading multiple background maps for use in the multi-point background correction as seen in Philip Poeml's CIP file:
12 "CalcImage Quantitative Image Project 6/8/2024 2:02:22 PM"
"SX60_analysis_SX60 #949 vertical large area_00853_"
"SX60_analysis.MDB"
33 40 -1 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0
0 1 .135 270.714 263.146 45399.9521296296 45401.2744328704 "SX60 #949 vertical large area_00853_WDS1_Ti_LIF_.grd" 68262
0 7 .135 270.714 263.146 45399.9521296296 45401.2744328704 "SX60 #949 vertical large area_00853_WDS2_U_QTZ_.grd" 58210
0 13 .135 270.714 263.146 45399.9521296296 45401.2744328704 "SX60 #949 vertical large area_00853_WDS3_Cs_LIF_.grd" 66705
0 19 .135 270.714 263.146 45399.9521296296 45401.2744328704 "SX60 #949 vertical large area_00853_WDS4_Y_PET_.grd" 73838
0 2 .135 259.773 255.15 45402.0083796296 45403.3304050926 "SX60 #949 vertical large area_00854_WDS1_La_LIF_.grd" 66203
0 8 .135 259.773 255.15 45402.0083796296 45403.3304050926 "SX60 #949 vertical large area_00854_WDS2_Np_QTZ_.grd" 56604
0 14 .135 259.773 255.15 45402.0083796296 45403.3304050926 "SX60 #949 vertical large area_00854_WDS3_Cr_LIF_.grd" 56917
0 20 .135 259.773 255.15 45402.0083796296 45403.3304050926 "SX60 #949 vertical large area_00854_WDS4_Zr_PET_.grd" 69478
0 3 .110 252.709 264.794 45403.6004050926 45404.6954398148 "SX60 #949 vertical large area_00855_WDS1_Ce_LIF_.grd" 63612
0 9 .110 252.709 264.794 45403.6004050926 45404.6954398148 "SX60 #949 vertical large area_00855_WDS2_Pu_QTZ_.grd" 55064
0 15 .110 252.709 264.794 45403.6004050926 45404.6954398148 "SX60 #949 vertical large area_00855_WDS3_Mn_LIF_.grd" 52252
0 21 .110 252.709 264.794 45403.6004050926 45404.6954398148 "SX60 #949 vertical large area_00855_WDS4_Mo_PET_.grd" 61844
0 4 .135 253.288 253.761 45404.9887037037 45406.3111111111 "SX60 #949 vertical large area_00856_WDS1_Pr_LIF_.grd" 61168
0 10 .135 253.288 253.761 45404.9887037037 45406.3111111111 "SX60 #949 vertical large area_00856_WDS2_Am_QTZ_.grd" 53594
0 16 .135 253.288 253.761 45404.9887037037 45406.3111111111 "SX60 #949 vertical large area_00856_WDS3_Gd_LIF_.grd" 50878
0 22 .135 253.288 253.761 45404.9887037037 45406.3111111111 "SX60 #949 vertical large area_00856_WDS4_Ru_PET_.grd" 55405
0 5 .160 247.291 252.297 45406.7075347222 45408.2500694444 "SX60 #949 vertical large area_00858_WDS1_Nd_LIF_.grd" 58866
0 11 .160 247.291 252.297 45406.7075347222 45408.2500694444 "SX60 #949 vertical large area_00858_WDS2_Cm_QTZ_.grd" 49355
0 17 .160 247.291 252.297 45406.7075347222 45408.2500694444 "SX60 #949 vertical large area_00858_WDS3_Fe_LIF_.grd" 48123
0 23 .160 247.291 252.297 45406.7075347222 45408.2500694444 "SX60 #949 vertical large area_00858_WDS4_Rh_PET_.grd" 52551
0 6 .150 251.259 252.388 45408.6489814815 45410.1065740741 "SX60 #949 vertical large area_00859_WDS1_Sm_LIF_.grd" 54627
0 12 .150 251.259 252.388 45408.6489814815 45410.1065740741 "SX60 #949 vertical large area_00859_WDS2_Xe_QTZ_.grd" 44844
0 18 .150 251.259 252.388 45408.6489814815 45410.1065740741 "SX60 #949 vertical large area_00859_WDS3_Ni_LIF_.grd" 41225
0 24 .150 251.259 252.388 45408.6489814815 45410.1065740741 "SX60 #949 vertical large area_00859_WDS4_Pd_PET_.grd" 47370
2 1 .030 259.911 259.636 45401.641400463 45402.0080902778 "SX60 #949 vertical large area_00853_WDS1_Ti_LIF__MOFF.grd" 60314
1 1 .030 262.932 260.14 45401.2746296296 45401.6411921296 "SX60 #949 vertical large area_00853_WDS1_Ti_LIF__POFF.grd" 69365
2 7 .030 259.911 259.636 45401.641400463 45402.0080902778 "SX60 #949 vertical large area_00853_WDS2_U_QTZ__MOFF.grd" 66128
1 7 .030 262.932 260.14 45401.2746296296 45401.6411921296 "SX60 #949 vertical large area_00853_WDS2_U_QTZ__POFF.grd" 66282
2 13 .030 259.911 259.636 45401.641400463 45402.0080902778 "SX60 #949 vertical large area_00853_WDS3_Cs_LIF__MOFF.grd" 57943
1 13 .030 262.932 260.14 45401.2746296296 45401.6411921296 "SX60 #949 vertical large area_00853_WDS3_Cs_LIF__POFF.grd" 67288
2 19 .030 259.911 259.636 45401.641400463 45402.0080902778 "SX60 #949 vertical large area_00853_WDS4_Y_PET__MOFF.grd" 63480
1 19 .030 262.932 260.14 45401.2746296296 45401.6411921296 "SX60 #949 vertical large area_00853_WDS4_Y_PET__POFF.grd" 75033
2 6 .030 254.112 255.302 45410.4760069444 45410.8446875 "SX60 #949 vertical large area_00859_WDS1_Sm_LIF__MOFF.grd" 55550
1 6 .030 252.205 252.983 45410.1067939815 45410.475787037 "SX60 #949 vertical large area_00859_WDS1_Sm_LIF__POFF.grd" 57861
2 12 .030 254.112 255.302 45410.4760069444 45410.8446875 "SX60 #949 vertical large area_00859_WDS2_Xe_QTZ__MOFF.grd" 44291
1 12 .030 252.205 252.983 45410.1067939815 45410.475787037 "SX60 #949 vertical large area_00859_WDS2_Xe_QTZ__POFF.grd" 45675
2 18 .030 254.112 255.302 45410.4760069444 45410.8446875 "SX60 #949 vertical large area_00859_WDS3_Ni_LIF__MOFF.grd" 38720
1 18 .030 252.205 252.983 45410.1067939815 45410.475787037 "SX60 #949 vertical large area_00859_WDS3_Ni_LIF__POFF.grd" 42405
2 24 .030 254.112 255.302 45410.4760069444 45410.8446875 "SX60 #949 vertical large area_00859_WDS4_Pd_PET__MOFF.grd" 45360
1 24 .030 252.205 252.983 45410.1067939815 45410.475787037 "SX60 #949 vertical large area_00859_WDS4_Pd_PET__POFF.grd" 50731
24
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
-1 0 0 0 0 0 0
0 ""
1 0
0 "VS1(BSE)" 0 "VS2(SE)" 0 "VS2(CL)"
"SX60 #949 vertical large area_00858_VS1.grd" "SX60 #949 vertical large area_00859_VS2.grd" ""
0 0
0 0 0 0 0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
0
1 0 0
1 0 0
1 0 0
0 0
Finally done it, thank you John for explaining this file, and it's great it's codable, now I just need to open the CIP file in CalcImage.
I ask the user for location of grd files, for live time map, for jeol wds cnd file, and assume only one set of maps in the folder, and only correct mdb is present in folder, then read from the mdb the last sample as the setup for the map quantification, and read the element order from the mdb.
Like the PTS to rpl and rpl via NeXL to grd, I will make this as plugin into hyperspy
Here's the python code, not yet arranged for hyperspy
#where only one set of maps in folder
#where uses last sample in mdb
#where mdb in same folder and only one mdb present
import tkinter
from tkinter import filedialog
import numpy as np
from numpy import genfromtxt
import csv
import datetime
import pyodbc
import glob
import re
import os
cndfile = tkinter.filedialog.askopenfile(title="Select WDS element .cnd file")
reader = csv.reader(open(cndfile.name), delimiter=" ")
d = list(reader)
ProjectName = ' '.join(d[29][1:len(d[29])])
path = filedialog.askdirectory(title="Select location of grd files")
fc = open(path + '/' + 'test cip creation.cip','w')
fc.write(' 12'+' '+'"'+'CalcImage Quantitative Image Project'+' '+datetime.datetime.now().strftime("%x")+' '+datetime.datetime.now().strftime("%X")+'"'+'\n')
for fileMDB in glob.glob(os.path.join(path,'*.MDB')):
print(fileMDB)
MDBname = re.sub("[]'[]",'',fileMDB.split('\\')[1]).split('.MDB')[0]
MDBfile = re.sub("[]'[]",'',fileMDB.split('\\')[1])
spacer = ' '
fc.write('"'+MDBname+'_'+ProjectName+'00001_'+'"'+'\n')
fc.write('"'+MDBfile+'"'+'\n')
MDB = fileMDB
DRV = 'Microsoft Access Driver (*.mdb, *.accdb)'
PWD = 'pw'
con = pyodbc.connect('DRIVER={};DBQ={};PWD={}'.format(DRV,MDB,PWD))
cur = con.cursor()
SQL = 'SELECT * FROM Sample;'
rows = cur.execute(SQL).fetchall()
LastSample = len(rows)
SQL = 'SELECT * FROM Element;'
rows = cur.execute(SQL).fetchall()
elementtable = np.array(rows)
eletable3=elementtable[np.isin(elementtable[:,0], str(LastSample))]
elementorder=[]
elementlist=[]
elementmotor=[]
for x in range(len(eletable3[:,1])):
elementorder.append(eletable3[x,1])
elementlist.append(eletable3[x,4])
elementmotor.append(eletable3[x,2])
cur.close()
con.close()
MapCounter = len(glob.glob1(path,'*_.grd'))
MapCounterEDS = len(glob.glob1(path,'*EDS.grd'))
#MinusOxygen = 1
MapCounterPOFF = len(glob.glob1(path,'*POFF.grd'))
MapCounterNOFF = len(glob.glob1(path,'*NOFF.grd'))
#NumMaps = MapCounter+MapCounterEDS-MinusOxygen
NumMaps = MapCounter+MapCounterEDS+MapCounterPOFF+MapCounterNOFF
TotalsImageFlag = -1
StoicOxFlag = -1
ExcessOxFlag = 0
NetIntenFlag = 0
BgdIntenFlag = 0
KratioIntenFlag = 0
QuantPercFlag = -1
AtomPercFlag = 0
OxidePercFlag = -1
FormulaBasisFlag = 0
EleDiffFlag = 0
DetLimFlag = 0
ErrorFlag = 0
LogPctFlag = 0
DLBlankFlag = 0
ErrBlankFlag = 0
Final = 0
sub = '$XM_AP_SA_DWELL_TIME%0'
WDSDwell = [s for s in d if sub in s][0][1]
sub2 = '$XM_DATA_SAVE_DATE'
offset = 693594
#exceldate = datetime.datetime.date(datetime.datetime.strptime([s for s in d if sub2 in s][0][1],"%Y/%m/%d")).toordinal()-offset
exceltim = datetime.datetime(1899,12,30)
cnddatetime=[s for s in d if sub2 in s][0][1]+' '+[s for s in d if sub2 in s][0][2]
delta=datetime.datetime.strptime(cnddatetime,'%Y/%m/%d %H:%M:%S')-exceltim
excelstore = float(delta.days)+(float(delta.seconds)/86400)
sub3 = '$XM_CP_DATE'
cnddatetime3=[s for s in d if sub3 in s][0][1]+' '+[s for s in d if sub3 in s][0][2]
delta3=datetime.datetime.strptime(cnddatetime3,'%Y/%m/%d %H:%M:%S')-exceltim
excelstore3 = float(delta3.days)+(float(delta3.seconds)/86400)
fc.write(' '+str(LastSample)+spacer+str(NumMaps)+spacer+str(TotalsImageFlag)+spacer+str(StoicOxFlag)+spacer+str(ExcessOxFlag)+spacer+str(NetIntenFlag)+spacer+str(BgdIntenFlag)+spacer+str(KratioIntenFlag)+spacer+str(QuantPercFlag)+spacer+str(AtomPercFlag)+spacer+str(OxidePercFlag)+spacer+str(FormulaBasisFlag)+spacer+str(EleDiffFlag)+spacer+str(DetLimFlag)+spacer+str(ErrorFlag)+spacer+str(LogPctFlag)+spacer+str(DLBlankFlag)+spacer+str(ErrBlankFlag)+spacer+str(Final)+'\n')
PreBeam = "{:.3f}".format(float([s for s in d if '$XM_DATA_PROBE_CURRENT_PRE' in s][0][1])*1e9)
PostBeam = "{:.3f}".format(float([s for s in d if '$XM_DATA_PROBE_CURRENT_POST' in s][0][1])*1e9)
for fileGRD in glob.glob(os.path.join(path,'*_.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
mapelement = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+5:wdsloc+7].split('_')[0]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
for x in [i for i,val in enumerate(elementlist) if val==mapelement]:
if elementmotor[x] == ChanNum:
ElePos = elementorder[x]
fc.write(' 0'+spacer+str(ElePos)+spacer+str(float(WDSDwell)/1000)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+spacer+'0'+'\n')
livefile = tkinter.filedialog.askopenfile(title="Select live time .csv file")
livedata = genfromtxt(livefile, delimiter=',')
EDSLive = np.median(livedata)
for fileGRD in glob.glob(os.path.join(path,'*EDS.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
mapelement = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+5:wdsloc+7].split('_')[0]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
for x in [i for i,val in enumerate(elementlist) if val==mapelement]:
if elementmotor[x] == ChanNum:
ElePos = elementorder[x]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
fc.write(' 0'+spacer+str(ElePos)+spacer+str(EDSLive)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+spacer+'0'+'\n')
for fileGRD in glob.glob(os.path.join(path,'*POFF.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
mapelement = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+5:wdsloc+7].split('_')[0]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
for x in [i for i,val in enumerate(elementlist) if val==mapelement]:
if elementmotor[x] == ChanNum:
ElePos = elementorder[x]
fc.write(' 1'+spacer+str(ElePos)+spacer+str(float(WDSDwell)/1000)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+spacer+'0'+'\n')
for fileGRD in glob.glob(os.path.join(path,'*NOFF.grd')):
print(fileGRD)
wdsloc = re.sub("[]'[]",'',fileGRD.split('\\')[1]).find('WDS')
ChanNum = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+3]
mapelement = re.sub("[]'[]",'',fileGRD.split('\\')[1])[wdsloc+5:wdsloc+7].split('_')[0]
fileGRDname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
for x in [i for i,val in enumerate(elementlist) if val==mapelement]:
if elementmotor[x] == ChanNum:
ElePos = elementorder[x]
fc.write(' 2'+spacer+str(ElePos)+spacer+str(float(WDSDwell)/1000)+spacer+str(PreBeam)+spacer+str(PostBeam)+spacer+str(excelstore)+spacer+str(excelstore3)+spacer+'"'+fileGRDname+'"'+spacer+'0'+'\n')
fc.write(' 10'+'\n')
fc.write(' 0 0 0 0 0 0 0 0 0 0 '+'\n')
fc.write(' 0'+'\n')
TitleAppendFlag = -1
SurferTemplateFlag = 0
SurferSliceTemplateFlag = 0
SurferPolyTemplateFlag = 0
SurferStripTemplateFlag = 0
SpareFlag1 = 0
SpareFlag2 = 0
fc.write(str(TitleAppendFlag)+spacer+str(SurferTemplateFlag)+spacer+str(SurferSliceTemplateFlag)+spacer+str(SurferPolyTemplateFlag)+spacer+str(SurferStripTemplateFlag)+spacer+str(SpareFlag1)+spacer+str(SpareFlag2)+'\n')
#EDS spectrum image not utilized
SpecImageFlag = 0
fc.write(str(SpecImageFlag)+spacer+'"'+'"'+'\n')
#Could read scan type from cnd file. Are these flags used?
ScanType = 0 #0=beam 1=stage
StagePolarity = 0 #0=cameca 1=jeol
fc.write(str(ScanType)+spacer+str(StagePolarity)+'\n')
SEIflag = 0
COMPflag = 0
for fileGRD in glob.glob(os.path.join(path,'*SEI.grd')):
print(fileGRD)
SEIname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
SEIflag = 1
for fileGRD in glob.glob(os.path.join(path,'*COMP.grd')):
print(fileGRD)
COMPname = re.sub("[]'[]",'',fileGRD.split('\\')[1])
COMPflag = 1
fc.write(str(SEIflag)+spacer+'"'+'SE'+'"'+spacer+str(COMPflag)+spacer+'"'+'BSE'+'"'+spacer+'0'+spacer+'"'+'CL'+'"'+'\n')
fc.write('"'+SEIname+'"'+spacer+'"'+COMPname+'"'+spacer+'"'+'"'+'\n')
#tdi corrections
tdi_num = 0 #number of tdi maps
tdi_intervals = 0 #number of tdi intervals
fc.write(' '+str(tdi_num)+spacer+str(tdi_intervals)+'\n')
#placeholder flags
fc.write(' 0 0 0 0 0 0 '+'\n')
fc.write(' 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 0 0 '+'\n'+' 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 0 0 '+'\n'+' 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 0 0 '+'\n'+' 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 0 0 '+'\n'+' 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 0 0 '+'\n'+' 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 1 0 0 '+'\n'+' 0 0 ')
fc.close()
And surfer results attached... for maps generated via NeXL
Quote from: Ben Buse on May 11, 2026, 10:43:27 AMFinally done it, thank you John for explaining this file, and it's great it's codable, now I just need to open the CIP file in CalcImage.
I ask the user for location of grd files, for live time map, for jeol wds cnd file, and assume only one set of maps in the folder, and only correct mdb is present in folder, then read from the mdb the last sample as the setup for the map quantification, and read the element order from the mdb.
And surfer results attached... for maps generated via NeXL
This is very impressive, congrats!
To confirm, you are acquiring the WDS and EDS maps together using the JEOL PC-EPMA software (WDS scan generator), so you can quant stage or beam scans?
And you are using the EDS standard intensities from the PFE MDB file? And you get good quant results on your maps?
It would be cool to do a map on a standard and then see if you get the same results using point analyses on the same standard in PFE.
In other words, do you get the same net cps live time intensities for both point standards in PFE and map pixel intensities?
Hi John
Yes WDS and EDS via PC-EPMA
No I'm not using PFE net intensities but PFE spectra from which NeXL calculates kratios which are converted into unknown net intensities for use with PFE standards
I think as I showed elsewhere I get very similar results, but not same as NeXL and JEOL different algorithms
So whilst loaded as unknown intensity maps I am essentially using NeXL calculated k-ratios rather than JEOL calculated k-ratios
It seems with EDS we should think about the k-ratio algorithm as a option as well as the matrix correction option. Just like if had Bruker or Thermo eds would give slightly different k-ratios using their algorithms.
Quote from: Ben Buse on May 11, 2026, 11:59:35 AMNo I'm not using PFE net intensities but PFE spectra from which NeXL calculates kratios which are converted into unknown net intensities for use with PFE standards
Ok, cool. So you have to export the standard spectra from PFE and extract the net intensities, but then how do you run the quant in CalcImage? Do you edit the PFE MDB EDS net intensity table with the new net intensities from NeXL?
Quote from: Ben Buse on May 11, 2026, 11:59:35 AMI think as I showed elsewhere I get very similar results, but not same as NeXL and JEOL different algorithms
So whilst loaded as unknown intensity maps I am essentially using NeXL calculated k-ratios rather than JEOL calculated k-ratios
It seems with EDS we should think about the k-ratio algorithm as a option as well as the matrix correction option. Just like if had Bruker or Thermo eds would give slightly different k-ratios using their algorithms.
I would be interested to see a table of how close the net intensities are for JEOL and NeXL.
Quote from: John DonovanOk, cool. So you have to export the standard spectra from PFE and extract the net intensities, but then how do you run the quant in CalcImage? Do you edit the PFE MDB EDS net intensity table with the new net intensities from NeXL?
No taking NeXL calculated k-ratio maps I multiply them by pfe std int to give unk int maps.
Quote from: John DonovanI would be interested to see a table of how close the net intensities are for JEOL and NeXL.
Yes this would be nice, and can quant pfe point spectra in NeXL as comparison of kratios and wt pct
It might be for conference and publication
Quote from: Ben Buse on May 11, 2026, 01:42:45 PMQuote from: John DonovanOk, cool. So you have to export the standard spectra from PFE and extract the net intensities, but then how do you run the quant in CalcImage? Do you edit the PFE MDB EDS net intensity table with the new net intensities from NeXL?
No taking NeXL calculated k-ratio maps I multiply them by pfe std int to give unk int maps.
Very clever.
There is one complication, I haven't quite got my head round.
The unknown grd map in calcimage is in cps.
With a single count time parameter for the whole map.
Does this matter or just effect pixel count statistics
Because pfe and calcimage kratio is persumably
unk intensity cps / std intensity cps
So
map pixel value / std intensity cps
So map stored count time not used, except for count stats
Is that correct?
Yes, GRD file EDS maps are in net cps (live time) and the map count times in the CIP file are used for calculating statistics and also documentation purposes.
Thanks John for confirming, now for some real maps/samples...