Spectroscopy¶
This chapter is a collection of instruments and analysis techniques used throughout the thesis. The sample preparation and synthesis were described previously and the diameter reduction with nitrogen poisoning during synthesis is described afterwards. The setup for taking spectra and images is described in more detail after the introduction of these basic methods here. All methods serve the investigations on Surface Adsorption on carbon nanotubes.
Wet Dispersion¶
If not stated otherwise, aqueous samples were debundled using Deoxycholate (DOC).[101] Typically 50mg of the raw CCVD material was dispersed in 10ml aqueous solution containing 1.5wt.% DOC. Water was purified with a millipore filter. Samples were sonicated for 1h with a Branson Horn Sonicator in a 50% duty cycle and subsequently centrifuged for 3-5min with a Haereus Spatech Biofuge 15 at 14000rpm.
Density Gradient Ultracentrifugation¶
Density Gradient Ultracentrifugation (DGU) was performed using a linear density gradient [102][103] with a Beckmann Optimatm L-90K ultra centrifuge. Fractioning of the centrifuged material was achieved with a KD Scientific KDS 210 syringe pump.
Absorption Spectroscopy¶
Absorption spectroscopy was performed on a Varian Cary 5000 UV-Vis-NIR spectrophotometer. The background of the pure solution was measured as a reference before every experiment. The spectra are processed and analyzed with a custom analysis program
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | #pragma rtGlobals=3
#include "utilities-peakfind"
Function AbsorptionLoadFolder()
String strFolder
String strFiles, strWave
String basename, concentration
Variable i, numFiles, numBegin, numEnd
String strBackground = "mkbg"
strFolder = PopUpChooseDirectory("X:Documents:RAW:Absorption")
// get files in directory
NewPath/O/Q path, strFolder
strFiles = IndexedFile(path,-1,".csv")
// search for mkbg[0-9]{2}
numBegin = strsearch(strFiles, strBackground, 0, 2)
numEnd = strsearch(strFiles, ";", numBegin, 2)
strBackground = strBackground + strFiles[(numBegin + 4), (numEnd -1)]
print "Background file is " + strBackground
// load background
wave background = $AbsorptionLoadFile(strFile = strFolder + strBackground)
strFiles = RemoveFromList(strBackground, strFiles)
// loop
numFiles = ItemsInList(strFiles)
for(i = 0; i < numFiles; i += 1)
strWave = AbsorptionLoadFile(strFile = strFolder + StringFromList(i, strFiles))
wave rootwave = root:$strWave
// remove background
rootwave[] -= background[p]
// // rescale to dilution factor
// SplitString/E="(.*)[_]{1}([0-9]*)" strWave, basename, concentration
// if(strlen(basename) * strlen(concentration) > 0)
// duplicate/o rootwave $basename
// wave corrected = root:$basename
// corrected[] = 10^(-corrected[p])
// corrected /= (str2num(concentration) / 100)
// corrected[] = -log(corrected[p])
// killwaves/Z rootwave
// endif
print "Loaded " + strWave
endfor
End
Function/S AbsorptionLoadFile([strFile])
String strFile
String strFileName, strFileType, strWave
String listWaves
Variable numWaves,i,j, numStart, numEnd
DFREF dfrSave, dfrTemp, dfr
if(ParamIsDefault(strFile))
strFile=PopUpChooseFile(strPrompt="Choose Absorption File")
endif
if (strlen(strFile) == 0)
return ""
endif
// load all waves to temp
dfrSave = GetDataFolderDFR()
dfrTemp = AbsorptionDFR(subDFR = "temp")
SetDataFolder dfrTemp
//Headings are in 2nd(0-1-2-->1) line, data starts in 2nd line, load all (0) from 1 to 2 columns, where d
LoadWave/A/D/J/K=1/L={1,2,0,0,2}/O/Q strFile
SetDataFolder dfrSave
dfr = AbsorptionDFR()
listWaves = S_waveNames
numWaves = ItemsInList(listWaves)
i = 0
if (numWaves == 2) // make to for loop
j = 2*i
// import columns from csv
wave wavWaveLength = dfrTemp:$StringFromList(j,S_waveNames)
wave wavIntensity = dfrTemp:$StringFromList(j+1,S_waveNames)
//Delete last point.
WaveStats/Q/Z/M=1 wavWaveLength
DeletePoints/M=0 (V_npnts),1, wavWaveLength, wavIntensity
strFileName = ParseFilePath(3, strFile, ":", 0, 0)
strFileType = ParseFilePath(4, strFile, ":", 0, 0)
strWave = CleanupName(strFileName, 0)
//strWave = UniqueName(strWave, 1, 0)
SetWaveScale(wavX = wavWaveLength, wavY = wavIntensity)
Redimension/N=(-1,3) wavIntensity
wavIntensity[][1] = wavWaveLength[p]
wavIntensity[][2] = 1240/wavWaveLength[p] //λ (nm) = 1240/E(eV)
SetDimLabel 1, 0, intensity, wavIntensity
SetDimLabel 1, 1, wavelength, wavIntensity
SetDimLabel 1, 2, electronVolt, wavIntensity
Duplicate/O/R=[0,*][0] wavIntensity root:$strWave
Redimension/N=(-1, 0) root:$strWave
Duplicate/O wavIntensity dfr:$strWave
KillWaves/Z wavWaveLength, wavIntensity
endif
return strWave
End
Function/Wave AbsorptionPrompt()
string redirectMe
string strWave = "absorption"
DFREF dfr = root:Packages:Absorption:
Prompt strWave, "Wave for Peak-Analysis",popup TraceNameList("", ";",1) //top graph "", seperate by ";", option 1: Include contour traces
DoPrompt "Enter wave", strWave
//$strIntensity is not possible for renamed traces: tracename#1 tracename#2 (see Instance Notation)
wave wavInput = TraceNameToWaveRef("",strWave)
redirectMe = NameOfWave(wavInput)
if(WaveExists(dfr:$redirectMe))
WAVE wavInput = dfr:$redirectMe
endif
redirectMe = NameOfWave(wavInput) + "j"
if(WaveExists(dfr:$redirectMe))
WAVE wavInput = dfr:$redirectMe
endif
print "input taken from", GetWavesDataFolder(wavInput, 2)
return wavInput
End
Function AbsorptionBgLinear()
AbsorptionBgLinearWave(AbsorptionPrompt())
End
// no error checking here.
// create linar background correction between pcsrA and pcsrB
Function AbsorptionBgLinearWave(wavInput)
wave wavInput
SetDataFolder root:
make/o/n=2 line
line={wavInput[pcsr(A)],wavInput[pcsr(B)]}
SetScale x, x2pnt(wavInput,pcsr(A)), x2pnt(wavInput, pcsr(B)), line
string strNewWave = nameofwave(wavInput) + "bgcorr"
duplicate/O wavInput $strNewWave
wave wavOutput = $strNewWave
interpolate2/T=1/I=3/Y=wavOutput line
wavOutput = wavInput-wavOutput
Killwaves/Z line
End
Function/Wave AbsorptionDifferentiateWave(wavInput, numSmooth, type)
Wave wavInput
Variable numSmooth, type
DFREF dfr = AbsorptionDFR(subDFR = NameOfWave(wavInput))
wave temp = Utilities#DifferentiateWave(wavInput, numSmooth, type)
Duplicate/O temp dfr:$(NameOfWave(wavInput) + "d")/WAVE=wavOutput
return wavOutput
End
Function/Wave AbsorptionDifferentiate2Wave(wavInput, numSmooth)
Wave wavInput
Variable numSmooth
// smooth and build second derivative
Wave wavFirst = AbsorptionDifferentiateWave(wavInput, numSmooth, 0)
Wave wavSecond = AbsorptionDifferentiateWave(wavFirst, numSmooth, 0)
return wavSecond
End
Function/Wave AbsorptionRemoveJump(wavInput)
wave wavInput
Variable gap, gapLeft, gapRight
Variable i, count
String newName
// create wave for jump correction
DFREF dfr = GetWavesDataFolderDFR(wavInput)
newName = NameOfWave(wavInput) + "j"
Duplicate/O wavInput, dfr:$newName
Wave wavJump = dfr:$newName
wavJump = 0
// get gap
Wave wavGaps = AbsorptionSearchGap(wavInput, 700, 900, 1.95)
count = Dimsize(wavGaps, 0)
print num2str(count) + " gaps found."
// if no gap was found return original wave
if (count == 0)
print "AbsorptionRemoveJump: No gap found"
wavJump = wavInput
return wavJump
endif
// currently only for one gap possible. 1 gap --> two values are found at start of Gap and end of Gap
if (count > 2)
print "AbsorptionRemoveJump: Too many gaps in defined range"
return wavJump
endif
// estimate values if no gap was present by differentiation
Wave wavDifferentiated = AbsorptionDifferentiateWave(wavInput, 0, 2) // type = Backward difference
// estimated = f(x0) + f'(x0) * delta x
// delta x = x_start - x_end
// gap = estimated - real
gap = wavInput[wavGaps[1]] - wavInput[wavGaps[0]] + wavDifferentiated[wavGaps[0]] * DimDelta(wavInput, 0) * (wavGaps[1] - wavGaps[0])
wavJump[0,wavGaps[0]] = gap
wavJump = wavInput + wavJump
return wavJump
End
Function/Wave AbsorptionSearchGap(wavInput, wlmin, wlmax, tolerance)
Wave wavInput
Variable wlmin, wlmax, tolerance
Variable i
Variable estimated, follower
Variable found = 0
Variable Pstart, Pend
Wave wavDifferentiated = AbsorptionDifferentiateWave(wavInput, 0, 2) // type = Backward difference
WaveStats/Q/R=(wlmin, wlmax) wavDifferentiated
Make/I/FREE/N=0 wavFound
tolerance = V_rms + tolerance * V_sdev
// assure ascending p points
Pstart = x2pnt(wavInput,wlmin)
Pend = x2pnt(wavInput,wlmax)
If (Pstart > Pend)
Pend = Pstart
Pstart = x2pnt(wavInput,wlmax)
endif
// search for gap in defined rannge. Maybe clean returned gaps.
for (i = Pstart; i < Pend; i += 1)
estimated = wavInput[i] + wavDifferentiated[i] * DimDelta(wavInput, 0)
follower = wavInput[i+1]
if (abs(estimated - follower) > tolerance)
FindValue/I=(i) wavFound
if (V_value == -1)
found += 1
Redimension/N=(found) wavFound
wavFound[(found-1)] = i
endif
endif
endfor
return wavFound
End
// see AutomaticallyFindPeaks from WM's <Peak AutoFind>
Function/Wave AbsorptionPeakFind(wavInput)
Wave wavInput
WAVE wavOutput = Utilities#PeakFind(wavInput)
DFREF dfr = AbsorptionDFR(subDFR = NameOfWave(wavInput))
KillWaves/Z dfr:$(NameOfWave(wavInput) + "peaks")
MoveWave wavOutput dfr:$(NameOfWave(wavInput) + "peaks")
return wavOutput
End
Function/Wave AbsorptionBackgroundConstruct(wavInput, [debugging, doubleExp])
Wave wavInput
Variable debugging, doubleExp
if (ParamIsDefault(debugging))
debugging = 0
endif
if (ParamIsDefault(doubleExp))
doubleExp = 1
endif
Variable i, j, startx, endx
Variable numMaxima, numMinima
String newName
DFREF dfr = GetWavesDataFolderDFR(wavInput)
Wave/Z wavOutput, wavDifferentiation, wavSmooth
newName = NameOfWave(wavInput) + "_bg"
Duplicate/O wavInput, dfr:$newName
Wave wavOutput = dfr:$newName
if (Dimsize(wavInput, 1) == 3)
Duplicate/FREE/R=[][0] wavInput wavIntensity
Redimension/N=(-1,0) wavInput
else
Duplicate/FREE wavInput wavIntensity
endif
wave/wave minima = AbsorptionDeleteDoubleMinima(wavIntensity, debugging = debugging)
wave/wave smoothed = AbsorptionDeleteSmooth(minima, smoothing = 3, logarithmic = 1, debugging = debugging)
wave fit_coeff = AbsorptionBackgroundFit(smoothed, expDouble=doubleExp)
if (!doubleExp)
if (Dimsize(wavOutput, 1) == 3)
wavOutput[][%intensity] = AbsorptionBackgroundExp(fit_coeff, wavOutput[p][%wavelength])
else
wavOutput = AbsorptionBackgroundExp(fit_coeff, x)
endif
print fit_coeff
print "y = K0+K1*exp(-(x-K5)/K2)"
else
if (Dimsize(wavOutput, 1) == 3)
wavOutput[][%intensity] = AbsorptionBackgroundExpDouble(fit_coeff, wavOutput[p][%wavelength])
else
wavOutput = AbsorptionBackgroundExpDouble(fit_coeff, x)
endif
print fit_coeff
print "y = K0+K1*exp(-(x-K5)/K2)+K3*exp(-(x-K5)/K4)"
endif
if (Dimsize(wavInput, 1) == 3)
Duplicate/FREE/R=[][0] wavInput wavIntensity
Redimension/N=(-1,0) wavInput
else
Duplicate/FREE wavInput wavIntensity
endif
return wavOutput
End
Function/Wave AbsorptionBackgroundRemove(wavInput, [doubleExp])
Wave wavInput
Variable doubleExp
if (ParamIsDefault(doubleExp))
doubleExp = 1
endif
Variable i, j, startx, endx
Variable numMaxima, numMinima
String newName
DFREF dfr = GetWavesDataFolderDFR(wavInput)
Wave/Z wavOutput, wavDifferentiation, wavSmooth
newName = NameOfWave(wavInput) + "_bgcorr"
Duplicate/O wavInput, dfr:$newName
Wave wavOutput = dfr:$newName
wave wavBackground = AbsorptionBackgroundConstruct(wavInput)
if (Dimsize(wavBackground, 1) == 3)
wavOutput[][%intensity] = wavInput[p][%intensity] - wavBackground[p][%intensity]
else
wavOutput = wavInput - wavBackground
endif
return wavOutput
End
// function is used to search for points in "minima" between two points from "maxima" wave
// returns p-index and positions in "minima" wave
// as input the x values are used
Function/Wave AbsorptionDoubleMinima(maxima, minima)
Wave maxima, minima
Variable startx, endx
variable i,j
Variable numMaxima, numMinima
numMaxima = Dimsize(maxima, 0)
numMinima = Dimsize(minima, 0)
// search for number of minima between two points.
// plot numMinima[][%delta] vs freeMaximaX for bugtracking
Make/FREE/I/N=(numMaxima, 3) output
// label columns of wave for readability
SetDimLabel 1, 0, startX, output
SetDimLabel 1, 1, endX, output
SetDimLabel 1, 2, delta, output
startx = 0
endx = 0
for(i = 0; i < (numMaxima - 1); i += 1)
// searching "minima" between following maxima:
// freeMaximaX[i], freeMaximaX[i+1]
startx = endx
for (j = startx; j < numMinima; j += 1)
if (minima[j] > maxima[i])
break
endif
endfor
startx = j
for (j = startx; j < numMinima; j += 1)
if (minima[j] > maxima[i+1])
break
endif
endfor
endx = j
output[i][%startX] = startx
output[i][%endX] = endx
output[i][%delta] = endx - startx
endfor
return output
End
Function/Wave AbsorptionGetMinima(wavInput, [addBorders])
wave wavInput
Variable addBorders
if (ParamIsDefault(addBorders))
addBorders = 0
endif
Variable numMinima
wave wavDifferentiation = Utilities#Differentiate2Wave(wavInput, 10)
wave wavMinima = AbsorptionPeakFind(wavDifferentiation)
numMinima = Dimsize(wavMinima, 0)
if (addBorders)
numMinima += 2
Wavestats/Q wavInput
Make/FREE/N=(numMinima) freeMinimaX = wavMinima[((p-2) < 0 ? 0 : (p-2))][%wavelength]
freeMinimaX[0,1] = {V_minloc, V_maxloc}
Make/FREE/N=(numMinima) freeMinimaY = wavInput[wavMinima[((p-2) < 0 ? 0 : (p-2))][%positionX]]
freeMinimaY[0,1] = {V_min, V_max}
else
Make/FREE/N=(numMinima) freeMinimaX = wavMinima[p][%wavelength]
Make/FREE/N=(numMinima) freeMinimaY = wavInput[wavMinima[p][%positionX]]
endif
Sort freeMinimaX, freeMinimaX, freeMinimaY
Make/Wave/FREE/N=2 output
output[0] = freeMinimaX
output[1] = freeMinimaY
return output
End
Function/Wave AbsorptionGetMaxima(wavInput)
wave wavInput
Variable numMaxima
wave wavMaxima = AbsorptionPeakFind(wavInput)
numMaxima = Dimsize(wavMaxima, 0)
Make/FREE/N=(numMaxima) freeMaximaX = wavMaxima[p][%wavelength]
Make/FREE/N=(numMaxima) freeMaximaY = wavInput[wavMaxima[p][%positionX]]
Sort freeMaximaX, freeMaximaX, freeMaximaY
Make/Wave/FREE/N=2 output
output[0] = freeMaximaX
output[1] = freeMaximaY
return output
End
// Delete minimum if two or more minima exist between one maximum in a wave
Function/Wave AbsorptionDeleteDoubleMinima(wavInput, [minima, maxima, debugging])
wave wavInput
wave/wave minima, maxima
Variable debugging
if (ParamIsDefault(debugging))
debugging = 0
endif
if (ParamIsDefault(minima))
wave/wave minima = AbsorptionGetMinima(wavInput, addBorders = 1)
endif
if (ParamIsDefault(maxima))
wave/wave maxima = AbsorptionGetMaxima(wavInput)
endif
Variable numMinima, numMaxima, i
Wave minimaX = minima[0]
wave minimaY = minima[1]
wave maximaX = maxima[0]
Wave maximaY = maxima[1]
Wave minimaPositions = AbsorptionDoubleMinima(maximaX, minimaX)
// create BoxWave with number of minima
if (debugging)
Make/O/I/N=(Dimsize(minimaPositions, 0), 2) root:absDoubleMinima
WAVE/I absDoubleMinima
absDoubleMinima[][0] = maximaX[p]
absDoubleMinima[][1] = minimaPositions[p][%delta]
endif
// Create Minima Wave
if (debugging)
Make/O/N=(Dimsize(minimaPositions, 0), 2) root:absMinimaInitial
WAVE absMinimaInitial
absMinimaInitial[][0] = minimaX[p]
absMinimaInitial[][1] = minimaY[p]
endif
numMinima = Dimsize(minimaX, 0)
numMaxima = Dimsize(maxima[0], 0)
// process points to yield only one point (the local minimum) between two maxima
Make/FREE/N=(numMinima) minimaXout = minimaX
Make/FREE/N=(numMinima) minimaYout = minimaY
for(i = numMaxima - 2; i > -1; i -= 1) // backwards due to DeletePoints
if (minimaPositions[i][%delta] > 1)
// get minimum
Wavestats/Q/R=(minimaX[minimaPositions[i][%startX]], minimaX[minimaPositions[i][%endX]]) wavInput
// set minimum
minimaXout[minimaPositions[i][%startX]] = V_minloc
minimaYout[minimaPositions[i][%startX]] = V_min
// delete remaining points
DeletePoints (minimaPositions[i][%startX] + 1), (minimaPositions[i][%endX] - minimaPositions[i][%startX] - 1), minimaYout, minimaXout
endif
endfor
// Create Minima Wave
if (debugging)
Make/O/N=(Dimsize(minimaPositions, 0), 2) root:absMinimaDouble
WAVE absMinimaDouble
absMinimaDouble[][0] = minimaXout[p]
absMinimaDouble[][1] = minimaYout[p]
endif
Make/Wave/FREE/N=2 output
output[0] = minimaXout
output[1] = minimaYout
return output
End
// delete points that are not smooth enough
Function/wave AbsorptionDeleteSmooth(minima, [smoothing, logarithmic, interpolate, debugging])
wave/wave minima
Variable smoothing, logarithmic, interpolate, debugging
if (ParamIsDefault(debugging))
debugging = 0
endif
if (ParamIsDefault(smoothing))
smoothing = 0
endif
if (ParamIsDefault(logarithmic))
logarithmic = 0
endif
if (ParamIsDefault(interpolate))
interpolate = 0
endif
Variable numMinima
wave minimaX = minima[0]
wave minimaY = minima[1]
numMinima = Dimsize(minimaY, 0)
Make/FREE/N=(numMinima) afterSmoothY = minimaY
Make/FREE/N=(numMinima) smoothed = minimaY
Make/FREE/N=(numMinima) valid = 1
if (logarithmic)
smoothed = ln(smoothed)
endif
switch(smoothing)
case 0:
// normal boxcar smoothing
Smooth/E=3 1, smoothed
break
case 1:
// Savitzky-Golay smoothing
Smooth/E=3/S=4 9, smoothed
break
case 2:
Smooth/E=3 1, smoothed
break
case 3:
Loess/Z/SMTH=0.75 srcWave=smoothed
if (!V_flag)
Smooth/E=3 1, smoothed
endif
break
endswitch
if (logarithmic)
smoothed = exp(smoothed)
endif
if (interpolate)
interpolate2/T=1/I=3/Y=smoothed minimaX, minimaY
endif
// check if value changed too much and drop particulary those values
afterSmoothY = minimaY - smoothed
Wavestats/Q afterSmoothY
valid = afterSmoothY[p] > V_rms ? NaN : 1 // delete only positive deviation (peaks)
afterSmoothY = minimaY * valid
Make/Wave/FREE/N=2 output
output[0] = minimaX
output[1] = afterSmoothY
if (debugging)
Make/O/N=(numMinima, 2) root:absSmooth
Wave absSmooth = root:absSmooth
absSmooth[][0] = minimaX[p]
absSmooth[][1] = smoothed[p]
Make/O/N=(numMinima, 2) root:absSmoothValid
Wave absSmoothValid = root:absSmoothValid
absSmoothValid[][0] = minimaX[p]
absSmoothValid[][1] = valid[p]
endif
return output
End
Function/wave AbsorptionBackgroundFit(wavInput, [expDouble])
wave/wave wavInput
Variable expDouble
if (ParamIsDefault(expDouble))
expDouble = 0
endif
wave smoothedX = wavInput[0]
wave smoothedY = wavInput[1]
// no need to guess parameters with curvefit
if (!expDouble)
// exponential fit with curve fit.
CurveFit/Q/X=1/NTHR=0 exp_XOffset smoothedY /X=smoothedX /F={0.95, 4}
Wave W_coef
Wave W_fitConstants
// store results for custom function
Make/FREE/N=4 coeff
coeff[0,2] = W_coef
coeff[3] = W_fitConstants[0]
// fit again to custom function
Wavestats/Q smoothedY
// initial guesses
// Make/FREE/N=4 coeff = {V_min, V_max-V_min, smoothedX[V_maxloc], 3/abs(smoothedX[V_minloc] - smoothedX[V_maxloc])}
Make/FREE/T/N=1 T_Constraints = {"K0 < " + num2str(V_min)}
FuncFit/Q/X=1/NTHR=0 AbsorptionBackgroundExp coeff smoothedY /X=smoothedX /F={0.95, 4} /C=T_Constraints
// y = K0+K1*exp(-(x-K5)/K2).
else
// double exponential fit with curve fit.
CurveFit/Q/X=1/NTHR=0 dblexp_XOffset smoothedY /X=smoothedX /F={0.95, 4}
Wave W_coef
Wave W_fitConstants
// store results for custom function
Make/FREE/N=6 coeff
coeff[0,4] = W_coef
coeff[5] = W_fitConstants[0]
// fit again to custom function
Wavestats/Q smoothedY
Make/FREE/T/N=3 T_Constraints = {"K0 < " + num2str(V_min)}
FuncFit/Q/X=1/NTHR=0 AbsorptionBackgroundExpDouble coeff smoothedY /X=smoothedX /F={0.95, 4} /C=T_Constraints
// y = K0+K1*exp(-(x-K5)/K2)+K3*exp(-(x-x0)/K4).
endif
return coeff
End
Function AbsorptionBackgroundExp(w,x) : FitFunc
Wave w
Variable x
//CurveFitDialog/ Equation:
//CurveFitDialog/ f(x) = a + b*exp(-1/c*(x-d))
//CurveFitDialog/ End of Equation
//CurveFitDialog/ Independent Variables 1
//CurveFitDialog/ x
//CurveFitDialog/ Coefficients 4
//CurveFitDialog/ w[0] = a
//CurveFitDialog/ w[1] = b
//CurveFitDialog/ w[2] = c
//CurveFitDialog/ w[3] = d
return w[0] + w[1]*exp(-(x-w[3])/w[2])
End
Function AbsorptionBackgroundExpDouble(w,x) : FitFunc
Wave w
Variable x
//CurveFitDialog/ Equation:
//CurveFitDialog/ f(x) = a + b*exp(-1/c*(x-f)) + d*exp(-1/e*(x-f))
//CurveFitDialog/ End of Equation
//CurveFitDialog/ Independent Variables 1
//CurveFitDialog/ x
//CurveFitDialog/ Coefficients 7
//CurveFitDialog/ w[0] = a
//CurveFitDialog/ w[1] = b
//CurveFitDialog/ w[2] = c
//CurveFitDialog/ w[3] = d
//CurveFitDialog/ w[4] = e
//CurveFitDialog/ w[5] = f
return w[0]+w[1]*exp(-(x-w[5])/w[2])+w[3]*exp(-(x-w[5])/w[4])
End
Function AbsorptionChiralityLoad([type])
String type
If (ParamIsDefault(type))
type = "sds"
endif
String strPath, strFile
String listFiles, listWaves, listFullPath
Variable numFiles, i
DFREF dfrSave, dfrChirality
dfrSave = GetDataFolderDFR()
dfrChirality = AbsorptionChiralityDFR(type=type)
// build path to files
strPath = SpecialDirPath("Igor Pro User Files", 0, 0, 0 ) + "User Procedures:chirality:"
strswitch(type)
case "free":
break
case "sds":
default:
strPath += "SDS:"
endswitch
// get all fileNames from path
GetFileFolderInfo/Q/Z=1 strPath
if (V_flag)
print "AbsorptionLoadChirality: Path not found " + strPath
endif
NewPath/O/Q path, strPath
listFiles = IndexedFile(path,-1,".ibw")
// load files in listFiles to waves in listWaves
numFiles = ItemsInList(listFiles)
listWaves = ""
for (i = 0; i < numFiles; i += 1)
strFile = StringFromList(i, listFiles)
SetDataFolder dfrChirality
LoadWave/Q/W/A/O/P=path strFile
SetDataFolder dfrSave
if (ItemsInList(S_waveNames) > 0)
listWaves = listWaves + S_waveNames
endif
endfor
return AbsorptionChiralityCheck(listWaves)
End
Function AbsorptionChiralityCheck(listLoaded, [listCheck])
String listLoaded
String listCheck
if (ParamIsDefault(listCheck))
listCheck = "diameter;lambda11;lambda22;nmindex;"
endif
String strCheck
Variable numWaves, i, found
numWaves = ItemsInList(listCheck)
found = 0
for (i = 0; i < numWaves; i += 1)
strCheck = StringFromList(i, listCheck)
if (WhichListItem(strCheck, listLoaded) != -1)
found += 1
endif
endfor
return (found == numWaves)
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #pragma TextEncoding = "UTF-8" // For details execute DisplayHelpTopic "The TextEncoding Pragma"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
Function/DF AbsorptionChiralityDFR([type])
String type
If (ParamIsDefault(type))
type = "sds"
endif
DFREF dfrSave, dfr
dfrSave = GetDataFolderDFR()
dfr = AbsorptionDFR(subDFR = "chirality")
SetDataFolder dfr
strswitch(type)
case "free":
NewDataFolder/O/S dfr:free
break
case "sds":
NewDataFolder/O/S dfr:sds
endswitch
dfr = GetDataFolderDFR()
SetDataFolder dfrSave
return dfr
End
Function/DF AbsorptionDFR([subDFR])
String subDFR
if (ParamIsDefault(subDFR))
subDFR = ""
Endif
DFREF dfrSave, dfr
dfrSave = GetDataFolderDFR()
SetDataFolder root:
NewDataFolder/O/S root:Packages
NewDataFolder/O/S root:Packages:Absorption
if (strlen(subDFR) > 0)
subDFR = CleanupName(subDFR, 0)
NewDataFolder/O/S $subDFR
endif
dfr = GetDataFolderDFR()
SetDataFolder dfrSave
return dfr
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | #pragma rtGlobals=3 // Use modern global access method and strict wave access.
#include <Peak AutoFind>
//Absorption-Load
// Version 5: removed "default unit" in SetWaveScale
// Version 6: Added interpolate2 function to SetWaveScale, Added test for not equally spaced waves.
// Version 7: added linear Background removal function
// Version 8: added Differentition
// Version 9: split to different Files
// Version 10: Peak Find
// Version 11: Background Fit to Minima
Menu "AKH"
Submenu "absorption"
"Load File", AbsorptionLoadFile()
"Load Directory", AbsorptionLoadFolder()
"Differentiate", AbsorptionDifferentiateDisplay()
"Differentiate2", AbsorptionDifferentiate2Display(0)
"Differentiate2 offset", AbsorptionDifferentiate2Display(1)
"Show Peaks", AbsorptionPeakDisplay()
"Show Background 2exp", AbsorptionBackgroundDisplay()
"Show Background exp", AbsorptionBackgroundDisplay(doubleExp = 0)
"Remove Background 2exp", AbsorptionBackgroundDisplay(bgcorr = 1)
"Remove Background exp", AbsorptionBackgroundDisplay(bgcorr = 1, doubleExp = 0)
"Remove Jump at 800nm", AbsorptionRemoveJumpDisplay()
"Linear Background on cursor", AbsorptionBgLinear()
"Kataura", AbsorptionKatauraDisplay()
"-"
"SetWaveScale", SetWaveScale()
"DisplayWave", DisplayWave()
"-"
end
End
Function AbsorptionDifferentiateDisplay()
wave input = AbsorptionPrompt()
wave output = AbsorptionDifferentiateWave(input, 10, 0)
RemoveFromGraph/Z derivative1
RemoveFromGraph/Z derivative2
if (Dimsize(output, 1) == 3)
AppendToGraph/R=axisderivative1 output[][%intensity]/TN=derivative1 vs output[][%wavelength]
else
AppendToGraph/R=axisderivative1 output/TN=derivative1
endif
SetAxis/A=2 axisderivative1
ModifyGraph freePos(axisderivative1)=0
ModifyGraph noLabel(axisderivative1)=1
ModifyGraph lblPosMode(axisderivative1)=1
ModifyGraph axisEnab(axisderivative1)={0.5,1}
ModifyGraph zero(axisderivative1)=1
Label axisderivative1 "1st derivative"
ModifyGraph mode(derivative1)=7
ModifyGraph rgb(derivative1)=(0,0,0)
End
Function AbsorptionDifferentiate2Display(setMinimum)
Variable setMinimum
wave output = AbsorptionDifferentiate2Wave(AbsorptionPrompt(), 10)
if (setMinimum)
Wavestats/Q output
output-=V_max
endif
RemoveFromGraph/Z derivative1
RemoveFromGraph/Z derivative2
if (Dimsize(output, 1) == 3)
AppendToGraph/R=axisderivative2 output[][%intensity]/TN=derivative2 vs output[][%wavelength]
else
AppendToGraph/R=axisderivative2 output/TN=derivative2
endif
SetAxis/A=2 axisderivative2
ModifyGraph freePos(axisderivative2)=0
ModifyGraph noLabel(axisderivative2)=1
ModifyGraph axisEnab(axisderivative2)={0.5,1}
Label axisderivative2 "2nd derivative"
ModifyGraph mode(derivative2)=7
ModifyGraph usePlusRGB(derivative2)=0,useNegRGB(derivative2)=1
#if IgorVersion() >= 7
ModifyGraph negRGB(derivative2)=(65535,54607,32768)
ModifyGraph plusRGB(derivative2)=(65535,0,0,32768)
#else
ModifyGraph negRGB(derivative2)=(65535,54607,32768)
ModifyGraph plusRGB(derivative2)=(65535,0,0)
#endif
ModifyGraph hbFill=0, hBarNegFill(derivative2)=2
ModifyGraph useNegPat(derivative2)=1
ModifyGraph rgb(derivative2)=(0,0,0)
ModifyGraph grid(axisderivative2)=1,lblPosMode(axisderivative2)=1
ModifyGraph nticks(axisderivative2)=10
End
Function AbsorptionRemoveJumpDisplay()
Wave wavInput = AbsorptionPrompt()
Wave wavOutput = AbsorptionRemoveJump(wavInput)
AppendToGraph wavOutput
end
// see AutoFindPeaksWorker from WM's <Peak AutoFind>
Function AbsorptionPeakDisplay()
Wave/Z wavInput, wavOutput
String tablename, tracename
Wave wavInput = AbsorptionPrompt()
Wave wavOutput = AbsorptionPeakFind(wavInput)
tracename = "peaks_" + NameOfWave(wavInput)
RemoveFromGraph/Z $tracename
AppendToGraph wavOutput[][%positionY]/TN=$tracename vs wavOutput[][%wavelength]
ModifyGraph rgb($tracename)=(0,0,65535)
ModifyGraph mode($tracename)=3
ModifyGraph marker($tracename)=19
// show table for peak wave if not yet present
tablename = "table_" + NameOfWave(wavOutput)
DoWindow $tablename
if (V_flag)
DoWindow/F $tablename
CheckDisplayed/W=$tablename wavOutput
if(!V_Flag)
AppendToTable wavOutput.ld // .ld: table with column names
endif
else
Edit/N=$tablename wavOutput.ld as "Peaks for " + NameOfWave(wavInput)
endif
End
Function AbsorptionBackgroundDisplay([bgcorr, debugging, doubleExp])
Variable bgcorr, debugging, doubleExp
String trace_bgcorr, trace_bg
if (ParamIsDefault(bgcorr))
bgcorr = 0
endif
if (ParamIsDefault(debugging))
debugging = 0
endif
if (ParamIsDefault(doubleExp))
doubleExp = 1
endif
Wave wavInput = AbsorptionPrompt()
if (bgcorr)
Wave wavOutput = AbsorptionBackgroundRemove(wavInput, doubleExp = doubleExp)
else
Wave wavOutput = AbsorptionBackgroundConstruct(wavInput, debugging = debugging, doubleExp = doubleExp)
endif
trace_bgcorr = "corrected_" + NameOfWave(wavInput)
trace_bg = "background_" + NameOfWave(wavInput)
RemoveFromGraph/Z $trace_bgcorr
RemoveFromGraph/Z $trace_bg
if (bgcorr)
AppendToGraph wavOutput/TN=$trace_bgcorr
ModifyGraph zero(left)=1
else
AppendToGraph wavOutput/TN=$trace_bg
ModifyGraph mode($trace_bg)=7,usePlusRGB($trace_bg)=1
#if (IgorVersion() >= 7.0)
ModifyGraph plusRGB($trace_bg)=(65535,0,0,16384)
#else
ModifyGraph plusRGB($trace_bg)=(65535,0,0)
#endif
ModifyGraph hbFill($trace_bg)=2
ModifyGraph zero(left)=0
endif
if (debugging)
endif
End
Function AbsorptionKatauraDisplay()
DFREF dfr
String tableName, katauraWindow, traceAbsorption, oldTraceAbsorption, tracePeaks
Variable numColumns
Wave/Z peaks, diameter, lambda11, lambda22, absorption
Wave/Z/T nmindex
// SHOW ABSORPTION Spectrum in new Window
// get wave
Wave absorption = AbsorptionPrompt()
numColumns = DimSize(absorption,1)
katauraWindow = "kataura_" + NameOfWave(absorption)
traceAbsorption = "absorption_" + NameOfWave(absorption)
oldTraceAbsorption = ""
DoWindow $katauraWindow
if (V_flag)
// modifiy old window
DoWindow/F $katauraWindow
// remember old trace
CheckDisplayed/W=$katauraWindow absorption
if(V_Flag)
oldTraceAbsorption = AbsorptionWaveRefToTraceName(katauraWindow, absorption)
endif
// append new
if(numColumns == 0)
AppendToGraph/W=$katauraWindow/B=bottom_right/L=wavelength absorption/TN=$traceAbsorption
elseif(numColumns == 3)
AppendToGraph/W=$katauraWindow/B=bottom_right/L=wavelength absorption[][%wavelength]/TN=$traceAbsorption vs absorption[][%intensity]
endif
// remove old
RemoveFromGraph/Z/W=$katauraWindow $oldTraceAbsorption
else
// create new window
if(numColumns == 0)
Display/B=bottom_right/L=wavelength/N=$katauraWindow absorption/TN=$traceAbsorption as "Kataura Plot for " + NameOfWave(absorption)
elseif(numColumns == 3)
Display/B=bottom_right/L=wavelength/N=$katauraWindow absorption[][%wavelength]/TN=$traceAbsorption vs absorption[][%intensity] as "Kataura Plot for " + NameOfWave(absorption)
endif
endif
Label/W=$katauraWindow bottom_right "optical density"
// SHOW KATAURA
// get waves
if (!AbsorptionChiralityLoad(type="sds"))
return 0
endif
dfr = AbsorptionChiralityDFR(type="sds")
Wave diameter = dfr:diameter
Wave lambda11 = dfr:lambda11
Wave lambda22 = dfr:lambda22
Wave/T nmindex = dfr:nmindex
// remove old traces
RemoveFromGraph/W=$katauraWindow/Z kataura1
RemoveFromGraph/W=$katauraWindow/Z kataura2
RemoveFromGraph/W=$katauraWindow/Z kataura3
RemoveFromGraph/W=$katauraWindow/Z kataura4
// add new traces
AppendToGraph/W=$katauraWindow/B=bottom_left/L=wavelength lambda11/TN=kataura1 vs diameter
AppendToGraph/W=$katauraWindow/B=bottom_left/L=wavelength lambda22/TN=kataura2 vs diameter
AppendToGraph/W=$katauraWindow/B=bottom_left/L=wavelength lambda11/TN=kataura3 vs diameter
AppendToGraph/W=$katauraWindow/B=bottom_left/L=wavelength lambda22/TN=kataura4 vs diameter
ModifyGraph rgb(kataura2)=(0,0,0), rgb(kataura4)=(0,0,0)
ModifyGraph mode(kataura1)=3, mode(kataura2)=3, mode(kataura3)=3, mode(kataura4)=3
ModifyGraph marker(kataura1)=1,marker(kataura2)=1
ModifyGraph textMarker(kataura3)={:Packages:Absorption:chirality:sds:nmindex,"default",0,0,5,0.00,10.00}
ModifyGraph textMarker(kataura4)={:Packages:Absorption:chirality:sds:nmindex,"default",0,0,5,0.00,10.00}
Label/W=$katauraWindow wavelength "wavelength / nm"
Label/W=$katauraWindow bottom_left "diameter / nm"
// show peaks
tracePeaks = "peaks_" + NameOfWave(absorption)
Wave peaks = AbsorptionPeakFind(absorption)
RemoveFromGraph/Z $tracePeaks
AppendToGraph/W=$katauraWindow/B=bottom_right/L=wavelength peaks[][%wavelength]/TN=$tracePeaks vs peaks[][%positionY]
ModifyGraph/W=$katauraWindow rgb($tracePeaks)=(0,0,65535)
ModifyGraph/W=$katauraWindow mode($tracePeaks)=3
ModifyGraph/W=$katauraWindow marker($tracePeaks)=19
// set axis
SetAxis/A=2
SetAxis bottom_left 0.65,1.15
ModifyGraph axisEnab(bottom_left)={0,0.79}, axisEnab(bottom_right)={0.8,1}
ModifyGraph freePos=0
ModifyGraph lblPosMode=1
// set axis grid
dfr = AbsorptionDFR(subDFR = NameOfWave(absorption))
Make/O/T/N=(Dimsize(peaks, 0)) dfr:peakAxis_label/WAVE=axis_label = num2str(round(peaks[p][%wavelength]))
Make/O/N=(Dimsize(peaks, 0)) dfr:peakAxis_tick/WAVE=axis_tick = peaks[p][%wavelength]
ModifyGraph userticks(wavelength)={axis_tick,axis_label}
ModifyGraph grid=1
// add legend
Legend/C/N=text0/J/F=0/A=MC "\\s(kataura1) E11\r\\s(kataura2) E22\r"
// show table for peak wave if not yet present
tablename = "table_" + NameOfWave(absorption)
DoWindow $tablename
if (V_flag)
DoWindow/F $tablename
CheckDisplayed/W=$tablename peaks
if(!V_Flag)
AppendToTable peaks.ld // .ld: table with column names
endif
else
Edit/N=$tablename peaks.ld as "Peaks for " + NameOfWave(absorption)
endif
End
Function DisplayWave()
wave wavWave = $GetWave(strPrompt="test")
if (WaveExists(wavWave))
display wavWave
endif
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | #pragma rtGlobals=3 // Use modern global access method and strict wave access.
//adapted function GetListOfFolderCont() from http://www.entorb.net/wickie/IGOR_Pro
Function /S GetListOfFolderCont(objectType)
Variable objectType //1==Waves, 2==Vars, 3==Strings, 4==Folders
//local variables
String strSourceFolder, strList
Variable i
//init
strSourceFolder = GetDataFolder(1) //":" is already added at the end of the string
strList = ""
//get List
for(i=0;i<CountObjects(strSourceFolder, objectType ); i+=1)
strList += strSourceFolder + GetIndexedObjName(strSourceFolder, objectType, i )+";"
endFor
return strList
End
//adapted function PopUpChooseFolder() from http://www.entorb.net/wickie/IGOR_Pro
Function/S PopUpChooseFolder()
//init local var
String strSaveDataFolder, strList, strFolders
//Save current DataFolder
strSaveDataFolder = GetDataFolder(1)
//Move to root
SetDataFolder root:
//Get List of Folders in root and add root foler
strList = GetListOfFolderCont(4)
strList = "root:;" + strList
strFolders = "root:"
Prompt strFolders,"Folder",popup,strList
DoPrompt "",strFolders
if (V_Flag == 1)
strFolders="" //return ""
endif
//Move back to Old Data Folder
SetDataFolder $strSaveDataFolder
Return strFolders
End
Function/S PopUpChooseWave(strDataFolder, [strText])
String strDataFolder, strText
strText = selectstring(paramIsDefault(strText), strText, "choose wave")
//init local var
String strSaveDataFolder, strList, strWave
//Save current DataFolder
strSaveDataFolder = GetDataFolder(1)
//Move to root
SetDataFolder $strDataFolder
//Get List of Waves in root and add root foler
strList = GetListOfFolderCont(1)
Prompt strWave,strText,popup,strList
DoPrompt "",strWave
if (V_Flag == 1)
strWave=""//return ""
endif
//Move back to Old Data Folder
SetDataFolder $strSaveDataFolder
Return strWave
End
//adapted from function OpenFileDialog on http://www.entorb.net/wickie/IGOR_Pro
Function/S PopUpChooseFile([strPrompt])
String strPrompt
strPrompt = selectstring(paramIsDefault(strPrompt), strPrompt, "choose file")
Variable refNum
String outputPath
String fileFilters = "Delimited Text Files (*.csv):.csv;"
//Browse to Absorption-Folder
String strPath = "Z:RAW:Absorption:"
//String strPath = "C:Users:mak24gg:Documents:RAW:Absorption:"
NewPath/O/Q path, strPath
PathInfo/S path
Open/D/F=fileFilters/R/M=strPrompt refNum
outputPath = S_fileName
return outputPath
End
Function/S PopUpChooseDirectory(strPath)
String strPath
// set start path
NewPath/Z/O/Q path, strPath
PathInfo/S path
if(!V_flag)
strPath = SpecialDirPath("Documents", 0, 0, 0)
NewPath/Z/O/Q path, strPath
PathInfo/S path
endif
NewPath/Z/M="choose Folder"/O/Q path
PathInfo path
if(!V_flag)
return PopUpChooseDirectory(strPath)
endif
strPath = S_path
GetFileFolderInfo/Q/Z=1 strPath
if (!V_isFolder)
return ""
endif
return strPath
End
Function/S PopUpChooseFileFolder([strPrompt])
String strPrompt
strPrompt = selectstring(paramIsDefault(strPrompt), strPrompt, "choose file")
String strPath, strFiles, strFile
strPath = PopUpChooseDirectory("X:Documents:RAW:Absorption")
NewPath/O/Q path, strPath
strFiles = IndexedFile(path,-1,".csv")
if (strlen(strFiles)==0)
print "No Files in selected Folder"
return ""
endif
Prompt strFile,strPrompt,popup,strFiles
DoPrompt "",strFile
if (V_Flag == 1)
return ""
endif
return (strPath + strFile)
End
Function/S GetWave([strPrompt])
String strPrompt
//This Function basically tests the String for convertability to a wave reference.
String strWave = PopUpChooseWave(PopUpChooseFolder(), strText=strPrompt)
wave wavWave = $strWave
if (WaveExists(wavWave))
//if (stringmatch(GetWavesDataFolder(wavWave, 2), strWave))
return strWave
else
return ""
endif
End
Function SetWaveScale([wavX, wavY, strUnit])
Wave wavX, WavY
String strUnit
strUnit = SelectString(ParamIsDefault(strUnit), strUnit, "")
if (ParamIsDefault(wavX))
// todo: strDirectory = PopUpChooseFolder()
wave wavX = $PopUpChooseWave("root:", strText="choose x wave")
endif
if (ParamIsDefault(wavY))
wave wavY = $PopUpChooseWave("root:", strText="choose y wave")
endif
Variable numOffset, numDelta
if (!WaveExists(wavX) || !WaveExists(wavY))
print "Error: Waves do not exist"
return 0
endif
numOffset = wavX[0]
numDelta = AbsorptionDelta(wavX, normal=1)
SetScale/P x, numOffset, numDelta, strUnit, wavY
return 1
End
Function AbsorptionDelta(wavInput, [normal])
Wave wavInput
Variable normal
if (ParamIsDefault(normal))
normal = 0
endif
Variable numSize, numDelta, i
String strDeltaWave
numSize = DimSize(wavInput,0)
if (numSize > 1)
if (normal)
numDelta = (wavInput[inf] - wavInput[0])/(numSize-1)
else
// calculate numDelta
Make/FREE/O/N=(numSize-1) wavDeltaWave
for (i=0; i<(numSize-1); i+=1)
wavDeltaWave[i] = (wavInput[(i+1)] - wavInput[i])
endfor
WaveStats/Q/W wavDeltaWave
wave M_WaveStats
numDelta = M_WaveStats[3] //average
//print "Wave " + nameofwave(wavInput) + " has a Delta of " + num2str(numDelta) + " with a standard deviation of " + num2str(M_WaveStats[4])
//if X-Wave is not equally spaced, set the half minimum delta at all points.
// controll by calculating statistical error 2*sigma/rms
if ((2*M_WaveStats[4]/M_WaveStats[5]*100)>5)
print "PLEMd2Delta: Wave is not equally spaced. Check Code and calculate new Delta."
// minimum
numDelta = M_WaveStats[10]
// avg - 2 * sdev : leave out the minimum 5% for statistical resaons
if (M_WaveStats[3] > 0) // sdev is always positive ;-)
numDelta = M_WaveStats[3] - 2 * M_WaveStats[4]
else
numDelta = M_WaveStats[3] + 2 * M_WaveStats[4]
endif
endif
// not used put possibly needed, when a new Delta Value is returned.
KillWaves/Z M_WaveStats
endif
else
numDelta = 0
endif
return numDelta
End
Function RemoveWaveScale(wavWave)
Wave wavWave
Variable numXOffset, numXDelta, numYOffset, numYDelta
String strXUnit, strYUnit
strXUnit = ""
strYUnit = ""
numYOffset = DimOffset(wavWave,1)
numXOffset = DimOffset(wavWave,0)
numYDelta = DimDelta(wavWave,1)
numXDelta = DimDelta(wavWave,0)
SetScale/P x, numXOffset, numXDelta, strXUnit, wavWave
SetScale/P y, numYOffset, numYDelta, strYUnit, wavWave
End
// See WM's CheckDisplayed
Function AbsorptionIsWaveInGraph(search)
Wave search
String currentTraces
Variable countTraces, i
Variable isPresent = 0
currentTraces = TraceNameList("",";",1)
countTraces = ItemsInList(currentTraces)
for (i=0;i<countTraces;i+=1)
Wave wv = TraceNameToWaveRef("", StringFromList(i,currentTraces) )
if (cmpstr(NameOfWave(wv),NameOfWave(search)) == 0)
isPresent = 1
endif
WaveClear wv
endfor
return isPresent
End
Function/S AbsorptionWaveRefToTraceName(graphNameStr, WaveRef)
String graphNameStr
Wave WaveRef
String traces, trace
Variable numTraces, i
Variable isPresent = 0
traces = TraceNameList(graphNameStr,";",1)
numTraces = ItemsInList(traces)
trace = ""
for(i = 0; i < numTraces; i += 1)
trace = StringFromList(i,traces)
Wave wv = TraceNameToWaveRef(graphNameStr, trace)
if (cmpstr(GetWavesDataFolder(wv, 1), GetWavesDataFolder(WaveRef, 1)) == 0)
break
endif
WaveClear wv
endfor
return trace
End
|
Raman Spectroscopy¶
Raman spectroscopy at 1064nm was done using a Nd:YAG laser together with a high resolution FT-spectrometer (Bruker IFS 120 HR coupled to a FRA-106).
Raman spectroscopy at 488nm was achieved using an Argon laser and a dichroitic mirror (520nm) coupled to an Andor Shamrock spectrometer with an Si-CCD array (Andor Newton). The grating has 300 lines/mm and a blaze wavelength at 500nm.
Raman spectroscopy at 570nm was done at a SP2500 spectrograph with a Princton Instruments Pixis 256 CCD array
PLE Spectroscopy¶
Photoluminescence excitation/emission spectroscopy and -microscopy was performed using a home-built setup. Spectra were acquired with a LabVIEW program. It is based on a similar setup [104] that was taken for taking PLE maps in solution. The generated spectra and images are loaded and processed with a Igor Pro program for loading measured data.
1 2 3 4 5 6 7 8 9 10 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
#include "plem-main"
#include "plem-menu"
#include "plem-prefs"
#include "plem-structure"
#include "plem-helper"
#include "plem-gui"
#include "plem-correction"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
#pragma IgorVersion=8
// Programmed by Matthias Kastner
// mail@matthias-kastner.de
// https://github.com/ukos-git/igor-swnt-plem
//
// LICENSE: MIT
//
// requires igor-common-utilites
// https://github.com/ukos-git/igor-common-utilities
#include "common-utilities"
// Variables for current Project only. See also the LoadPreferences towards the end of the procedure for additional settings that are saved system-wide.
Constant cPLEMd2Version = 4001
StrConstant cstrPLEMd2root = "root:PLEMd2"
StrConstant cstrPLEMd2correction = "root:PLEMd2:correction"
static Constant PLEM_SINGLE_BACKGROUND = 1
static Constant PLEM_MULTIPLE_BACKGROUND = 2
Function PLEMd2initVar()
print "PLEMd2initVar: intialization of global variables"
//Init Data Folder
String strSaveDataFolder = GetDataFolder(1)
SetDataFolder root:
NewDataFolder/O/S $cstrPLEMd2root
//Save Data Folder befor execution of this program so we can always switch after our program terminates
//definition here only for initialization.
//during run time it is set in PMRinit() but we will already switch folders here. so better also here safe the path.
String/G gstrSaveDataFolder = strSaveDataFolder
String/G gstrPLEMd1root = cstrPLEMd2root + ":" + "PLEMd1"
String/G gstrMapsFolder = cstrPLEMd2root + ":" + "maps"
SetDataFolder $cstrPLEMd2root
//Maps: Create Folder and Initialize Strings where we store the maps of the current project
NewDataFolder/O $gstrMapsFolder
String/G gstrMapsAvailable = ""
Variable/G gnumMapsAvailable = 0
PLEMd2MapStringReInit()
//save current init-version in project folder.
Variable/G gnumPLEMd2Version = cPLEMd2Version
//set a variable in root folder to recognize if the module was initialized.
SetDataFolder root:
Variable/G gnumPLEMd2IsInit = 1
SetDataFolder $cstrPLEMd2root
End
Function PLEMd2isInitialized()
NVAR/Z gnumPLEMd2IsInit = root:gnumPLEMd2IsInit
if(!NVAR_EXISTS(gnumPLEMd2IsInit))
return 0
endif
return gnumPLEMd2IsInit
End
// check if the Experiment was created with the same version as the program.
//
// Note: use PLEMd2init() for initialization
Function PLEMd2CheckExperimentVersion()
DFREF packageRoot = $cstrPLEMd2root
if(!DataFolderRefStatus(packageRoot))
return 0
endif
NVAR/Z ExperimentVersion = packageRoot:gnumPLEMd2Version
if(ExperimentVersion == cPLEMd2Version)
return 1
endif
End
// automatically initialize the current experiment to default values if necessary
Function PLEMd2initialize()
if(PLEMd2isInitialized() && PLEMd2CheckExperimentVersion())
return 0 // already initialized.
endif
PLEMd2Clean()
PLEMd2initVar()
End
// force reset package
Function PLEMd2reset()
Variable i, numMaps
if(PLEMd2isInitialized())
NVAR gnumPLEMd2IsInit = root:gnumPLEMd2IsInit
gnumPLEMd2IsInit = 0
endif
PLEMd2initialize()
// reset IBW files
numMaps = PLEMd2MapStringReInit()
for(i = 0; i < numMaps; i += 1)
PLEMd2ProcessIBW(PLEMd2strPLEM(i))
endfor
End
// cleanup package root
Function PLEMd2Clean()
String strVariables, strStrings, strAvailable
Variable i, numAvailable
DFREF dfrSave = GetDataFolderDFR()
DFREF packageRoot = $cstrPLEMd2root
// we assume that all paths belong to previous versions of the program.
if(PLEMd2CheckExperimentVersion())
KillPath/A/Z
endif
if(!DataFolderRefStatus(packageRoot))
return 0
endif
SetDataFolder packageRoot
strVariables = VariableList("V_*", ";", 4) // Scalar Igor Variables
strVariables += VariableList("*", ";", 2) //System Variables
strStrings = StringList("S_*", ";") // Scalar Igor Strings
// @todo add all variables except those that are needed in the current Experiment Version
numAvailable = ItemsInList(strVariables)
for(i = 0; i < numAvailable; i += 1)
strAvailable = StringFromList(i, strVariables)
Killvariables/Z $strAvailable
endfor
numAvailable = ItemsInList(strStrings)
for(i = 0; i < numAvailable; i += 1)
strAvailable = StringFromList(i, strStrings)
Killstrings/Z $strAvailable
endfor
SetDataFolder dfrSave
End
Function PLEMd2Open([strFile, display])
String strFile
Variable display
Variable retry, err, numLoaded
String strFileName, strFileType, strPartialPath, strBasePath
String strWave, strPLEM
Struct PLEMd2Prefs prefs
PLEMd2LoadPackagePrefs(prefs)
// this function serves as entrypoint for most activities
PLEMd2initialize()
if(ParamIsDefault(strFile))
strFile = PLEMd2PopUpChooseFile()
endif
if(ParamIsDefault(display))
display = 1
endif
// check for valid filename
GetFileFolderInfo/Q/Z=1 strFile
if(!!V_Flag || !V_isFile)
print "PLEMd2Open: Invalid filename for " + strFile
return 1
endif
// DisplayHelpTopic "Symbolic Paths"
strBasePath = prefs.strBasePath
GetFileFolderInfo/Q/Z=1 strBasePath
if(!V_flag && V_isFolder)
PathInfo PLEMbasePath
if(!V_flag)
NewPath/O/Q/Z PLEMbasePath, strBasePath
endif
endif
strFileName = ParseFilePath(3, strFile, ":", 0, 0)
strPLEM = CleanupName(strFileName, 0)
strFileType = ParseFilePath(4, strFile, ":", 0, 0)
strPartialPath = ReplaceString(RemoveEnding(strBasePath, ":"), strFile, "", 0, 1)
// Loading Procedure (LoadWave is not dfr aware)
strswitch(strFileType)
case "ibw":
// create dfr for loaded data
DFREF dfrLoad = NewFreeDataFolder()
// load wave to dfrLoad using original name from IBW (overwrite)
DFREF dfrSave = GetDataFolderDFR()
SetDataFolder dfrLoad
do
PathInfo PLEMbasePath
try
if(V_flag)
LoadWave/H/Q/N/O/P=PLEMbasePath strPartialPath; AbortOnRTE
else
LoadWave/H/Q/N/O strFile; AbortOnRTE
endif
numLoaded = V_flag
catch
err = GetRTError(1)
numLoaded = 0
printf "failed %d time(s) at %s with error: %s", retry + 1, strFile, GetErrMessage(err)
endtry
retry += 1
while(!numLoaded && retry < 3)
SetDataFolder dfrSave
if(numLoaded != 1)
KillDataFolder/Z dfrLoad
Abort "PLEMd2Open: Error Loaded more than one or no Wave from Igor Binary File"
endif
// reference loaded wave and lock it.
WAVE/Z wavIBW = PLEMd2getWaveFromDFR(dfrLoad)
SetWaveLock 0, wavIBW
Rename wavIBW IBW
SetWaveLock 1, wavIBW
String/G dfrLoad:sha256 = WaveHash(wavIBW, 1)
SVAR sha256 = dfrLoad:sha256
break
default:
Abort "PLEMd2Open: Could not open file"
break
endswitch
// check if PLEM exists with calculated name and hash
DFREF dfrPLEM = PLEMd2MapFolder(strPLEM)
if(DataFolderRefStatus(dfrPLEM) != 0)
SVAR/Z savedSha = dfrPLEM:sha256
if(SVAR_EXISTS(savedSha) && !!cmpstr(savedSha,sha256))
strPLEM = CleanupName(sha256, 0) // name conflict
endif
endif
DFREF dfrPLEM = PLEMd2MapFolder(strPLEM)
DFREF dfrMaps = PLEMd2MapsFolder()
if(DataFolderRefStatus(dfrPLEM) == 0)
MoveDataFolder/O=1 dfrLoad dfrMaps
RenameDataFolder dfrLoad, $strPLEM
else
DuplicateDataFolder/Z/O=3 dfrLoad, dfrMaps:$strPLEM
if(V_flag)
DFREF dfrMap = PLEMd2MapFolder(strPLEM)
WAVE/Z wavIBW = dfrMap:IBW
if(!WaveExists(wavIBW) || !!cmpstr(sha256, WaveHash(wavIBW, 1)))
Abort "PLEMd2Open: Could not Save loaded IBW"
endif
endif
KillDataFolder/Z dfrLoad
endif
// init stats
PLEMd2statsInitialize(strPLEM)
// create and display waves
PLEMd2ProcessIBW(strPLEM)
if(display)
PLEMd2Display(strPLEM)
endif
End
Function PLEMd2ProcessIBW(strPLEM)
String strPLEM
WAVE/Z wavIBW = PLEMd2wavIBW(strPLEM)
if(WaveExists(wavIBW))
PLEMd2ExtractInfo(strPLEM, wavIBW)
PLEMd2ExtractIBW(strPLEM, wavIBW)
else
print "Error: Reload IBW from disk using Plemd2Open() for full IBW processing"
endif
PLEMd2BuildMaps(strPLEM)
End
Function/DF PLEMd2ExtractWaves(wavIBW)
WAVE wavIBW
String strWaveNames, strWaveExtract
Variable numTotalX, numTotalY, i, j
// load waves from IBW file to dfr
DFREF dfr = NewFreeDataFolder()
// check consistency
strWaveNames = PLEMd2ExtractWaveList(wavIBW)
numTotalX = DimSize(wavIBW, 0)
numTotalY = DimSize(wavIBW, 1)
if(numTotalY == 0 || numTotalX == 0)
Abort "PLEMd2ExtractWaves: Binary File has no waves"
endif
if(numTotalY != ItemsInList(strWaveNames))
print "PLEMd2ExtractWaves: Error WaveNames not correct in WaveNotes."
PLEMd2FixWavenotes(wavIBW)
strWaveNames = PLEMd2ExtractWaveList(wavIBW)
endif
if(numTotalY != ItemsInList(strWaveNames))
printf "PLEMd2ExtractWaves: Missmatch in wavenames:\r%s\rWaveNames not correct in WaveNote. Counting %d data columns and %d labels.\r", strWaveNames, numTotalY, ItemsInList(strWaveNames)
if(numTotalY < ItemsInList(strWaveNames))
print "PLEMd2ExtractWaves: probably canceled measurement"
do
strWaveNames = RemoveListItem(ItemsInList(strWaveNames) - 1, strWaveNames)
while(numTotalY < ItemsInList(strWaveNames))
else
Abort "Manual interaction needed."
endif
endif
//Extract Columns from Binary Wave and give them proper names
for(i = 0; i < numTotalY; i += 1)
strWaveExtract = StringFromList(i, strWaveNames)
Make/D/O/N=(numTotalX) dfr:$strWaveExtract/WAVE=wv
wv[] = wavIBW[p][i]
WaveClear wv
endfor
return dfr
End
Function PLEMd2CopyWaveNote(wavIBW, wv)
WAVE wavIBW, wv
String strHeader
strHeader = Note(wavIBW)
strHeader = strHeader[0,(strsearch(strHeader, "IGOR0",0)-1)] // clean WaveNotes
Note/K/NOCR wv strHeader
End
Function PLEMd2ExtractIBW(strPLEM, wavIBW)
String strPLEM
WAVE wavIBW
Struct PLEMd2stats stats
String strWaveBG, strWavePL, corrections
Variable numExcitationFrom, numExcitationTo
Variable dim0, dim1
Variable i,j, numItems
DFREF packageRoot = $cstrPLEMd2root
SVAR gstrMapsFolder = packageRoot:gstrMapsFolder
if(!PLEMd2MapExists(strPLEM))
Abort "PLEMd2ExtractIBW: Map does not exist"
endif
//There are 3 different structures for DATA
//1) WAVES: WL, BG, PL ...
//2) WAVES: WL, BG_498_502, PL_498_502,BG_502_506,PL_502_506 ...
//3) WAVES: WL, BG, PL_498_502,PL_502_506,PL_506_510,PL_510_514 ...
//Possibilities handled:
//1)+3) stats.strbackground = single --> wavexists(background)
//2) stats. strBackground = multiple --> count(BG_*) = count (PL_*)
//4) image mode:
// special case of 1) size of WL wave is no equal to BG or PL.
// collect strWavePL und strWaveBG. WaveList is not DFR aware
DFREF saveDFR = GetDataFolderDFR()
PLEMd2statsLoad(stats, strPLEM)
DFREF dfr = PLEMd2ExtractWaves(wavIBW)
SetDataFolder dfr
strWavePL = WaveList("PL*", ";", "")
strWaveBG = WaveList("BG*", ";", "")
stats.numPLEMTotalY = ItemsInList(strWavePL, ";")
if(ItemsInList(strWavePL) == 0 || ItemsInList(strWaveBG) == 0)
Abort "No PL or BG Waves in :ORIGINAL"
endif
SetDataFolder saveDFR
// quick fix for wrong single backgrounds on PLE setup
if(stats.numbackground == PLEM_SINGLE_BACKGROUND && ItemsInList(strWaveBG) > 1)
stats.numBackground = PLEM_MULTIPLE_BACKGROUND
endif
// error checking for multiple background
if(stats.numbackground == PLEM_MULTIPLE_BACKGROUND && ItemsInList(strWaveBG, ";") != ItemsInList(strWavePL, ";"))
printf "number of bg: %d\t number of pl: %d\r", ItemsInList(strWaveBG, ";"), ItemsInList(strWavePL, ";")
if(WhichListItem("BG", strWaveBG) != -1)
print "mixed Single and multiple BG mode. Switching to single Background mode."
stats.numbackground = PLEM_SINGLE_BACKGROUND
else
Abort "PLEMd2ExtractIBW: Error Size Missmatch between Background Maps and PL Maps"
endif
endif
stats.numCalibrationMode = 0
if(stats.numPLEMTotalY == 1)
stats.numCalibrationMode = 1
endif
wave wavWavelength = dfr:WL
if(!WaveExists(wavWavelength))
Abort "PLEMd2ExtractIBW: Wavelength Wave not found within ORIGINAL Folder"
endif
stats.numPLEMTotalX = NumPnts(wavWavelength)
if(stats.numReadOutMode == 1)
// quick fix for image mode on cameras @todo: redefine readout mode and data storage in data format specifications
if(stats.numPLEMTotalX == 81919)
stats.numDetector = PLEMd2cameraXeva
stats.numPLEMTotalY = 256
stats.numPLEMTotalX = 320
else
stats.numDetector = PLEMd2cameraClara
stats.numPLEMTotalY = 1040
stats.numPLEMTotalX = 1392
endif
endif
// Redimension the Waves to proper size
dim0 = stats.numPLEMTotalX
dim1 = stats.numPLEMTotalY
Redimension/N=(dim0, dim1) stats.wavPLEM, stats.wavMeasure, stats.wavBackground
PLEMd2CopyWaveNote(wavIBW, stats.wavPLEM)
if(stats.numReadOutMode == 1)
// dim0 = 0 // no wavelength
// dim1 = 1 // save power and excitation wl
endif
Redimension/N=(dim0) stats.wavWavelength, stats.wavGrating, stats.wavQE
Redimension/N=(dim1) stats.wavExcitation, stats.wavYpower, stats.wavYphoton
// set x-Scaling
stats.wavWavelength = wavWavelength
// Grating Waves
corrections = PLEMd2getGratingString(stats.numGrating, PLEMd2getSystem(stats.strUser))
PLEMd2SetCorrection(corrections, stats.wavGrating, stats.wavWavelength)
// Quantum efficiency
corrections = PLEMd2getDetectorQEstring(stats.numDetector, stats.numCooling, PLEMd2getSystem(stats.strUser))
WAVE/Z qe = PLEMd2SetCorrection(corrections, stats.wavQE, stats.wavWavelength)
// emission filter
corrections = PLEMd2getFilterEmiString(PLEMd2getSystem(stats.strUser), stats.numDetector)
PLEMd2SetCorrection(corrections, stats.wavFilterEmi, stats.wavWavelength)
// different handling for spectra in calibration mode (1) and for maps (0)
if(stats.numCalibrationMode == 1)
wave wavMeasure = dfr:$(StringFromList(0, strWavePL))
wave wavBackground = dfr:$(StringFromList(0, strWaveBG))
if(stats.numReadOutMode == 1)
// image mode. currently no information for images is saved
Redimension/N=(stats.numPLEMTotalY * stats.numPLEMTotalX) wavMeasure, wavBackground // workaround for XEVA (2 pixel missing)
stats.wavMeasure = wavMeasure[p + stats.numPLEMTotalX * q]
stats.wavBackground = wavBackground[p + stats.numPLEMTotalX * q]
else
stats.wavMeasure = wavMeasure
stats.wavBackground = wavBackground
endif
if(stats.numReadOutMode == 1)
// image mode. currently no information for images is saved
stats.wavMeasure = wavMeasure[p + stats.numPLEMTotalX * q]
stats.wavBackground = wavBackground[p+stats.numPLEMTotalX*q]
endif
WaveClear wavBackground
WaveClear wavMeasure
// Excitation wave
stats.wavExcitation = (stats.numEmissionStart + stats.numEmissionEnd) / 2
else
for(i = 0; i < stats.numPLEMTotalY; i += 1)
// Original Waves: load
wave wavMeasure = dfr:$(StringFromList(i, strWavePL))
wave wavBackground = dfr:$(StringFromList(i, strWaveBG))
stats.wavMeasure[][i] = wavMeasure[p]
if(stats.numbackground == PLEM_MULTIPLE_BACKGROUND)
stats.wavBackground[][i] = wavBackground[p]
elseif(i == 0 && stats.numbackground == PLEM_SINGLE_BACKGROUND)
stats.wavBackground[][] = wavBackground[p]
//Redimension/N=(-1, 0) stats.wavBackground
endif
// Original Waves: unload
WaveClear wavBackground
WaveClear wavMeasure
// Excitation wave
numExcitationFrom = str2num(StringFromList(1,StringFromList(i,strWavePL), "_"))
numExcitationTo = str2num(StringFromList(2,StringFromList(i,strWavePL), "_"))
stats.wavExcitation[i] = (numExcitationFrom + numExcitationTo) / 2
// since PLEMv3.0 excitation is saved multiplied by 10.
if(stats.wavExcitation[i] > 1e3)
stats.wavExcitation[i] /= 10
endif
endfor
endif
// excitation filter
corrections = PLEMd2getFilterExcString(PLEMd2getSystem(stats.strUser), stats.numDetector)
PLEMd2SetCorrection(corrections, stats.wavFilterExc, stats.wavExcitation)
// Power correction waves
// requires Excitation wave for Photon Energy
if(stats.numDetector == PLEMd2detectorNewton || stats.numDetector == PLEMd2detectorIdus)
stats.wavYpower = str2num(StringFromList(p, PLEMd2ExtractPower(wavIBW), ";"))
stats.wavYphoton = (stats.wavYpower * 1e-6) / (6.62606957e-34 * 2.99792458e+8 / (stats.wavExcitation * 1e-9)) // power is in uW and Excitation is in nm
endif
// init camera specific corrections.
// Please note that sizeadjustment and rotationadjustment are not
// changeable on a "per file base" but on a "per experiment base"
stats.numPixelPitch = 1
NVAR/Z numSizeAdjustment = root:numSizeAdjustment
NVAR/Z numRotationAdjustment = root:numRotationAdjustment
// set camera specific corrections
if(stats.numDetector == PLEMd2detectorNewton)
// 26x26µm * (binning factors)
stats.numPixelPitch = 26
elseif(stats.numDetector == PLEMd2detectorIdus)
// 25x500µm
stats.numPixelPitch = 25
elseif(stats.numDetector == PLEMd2cameraClara)
// add camera specific settings
stats.numPixelPitch = 6.45 // 6.45um
// magnification adjustment
if(!NVAR_EXISTS(numSizeAdjustment))
Variable/G root:numSizeAdjustment = 0.960
NVAR numSizeAdjustment = root:numSizeAdjustment
endif
// rotation adjustments
if(!NVAR_EXISTS(numRotationAdjustment))
// mounted camera is rotated depending on setup
Variable/G root:numRotationAdjustment = -0.95
NVAR numRotationAdjustment = root:numRotationAdjustment
endif
numRotationAdjustment = -0.95 // overwrite! better rotation for mkl23clarascan
PLEMd2rotateLaser(stats)
elseif(stats.numDetector == plemd2cameraXeva)
// add camera specific settings
stats.numPixelPitch = 30 // 30um
// magnification adjustment
if(!NVAR_EXISTS(numSizeAdjustment))
Variable/G root:numSizeAdjustment = 0.977
NVAR numSizeAdjustment = root:numSizeAdjustment
endif
stats.booSwitchX = !stats.booSwitchX // xeva has reverse readout
endif
if(!NVAR_EXISTS(numRotationAdjustment))
Variable/G root:numRotationAdjustment = 0
NVAR numRotationAdjustment = root:numRotationAdjustment
endif
if(stats.numCalibrationMode != 1)
//todo counterpart in PLEMd2setScale
stats.numPLEMBottomY = (str2num(StringFromList(1, StringFromList(0, strWavePL), "_")) + str2num(StringFromList(2, StringFromList(0, strWavePL), "_"))) / 2
endif
PLEMd2statsSave(stats)
print GetWavesDataFolder(stats.wavPLEM, 2)
End
static Function PLEMd2setScale(stats)
Struct PLEMd2stats &stats
NVAR/Z numSizeAdjustment = root:numSizeAdjustment
if(!NVAR_EXISTS(numSizeAdjustment))
Variable/G root:numSizeAdjustment = 1
NVAR numSizeAdjustment = root:numSizeAdjustment
print "PLEMd2setScale: sizeAdjustment set to 1"
endif
// handle spectra
if(stats.numReadOutMode != 1)
stats.numPLEMLeftX = stats.wavWavelength[0]
stats.numPLEMDeltaX = PLEMd2Delta(stats.wavWavelength, normal = 1)
if(stats.numCalibrationMode == 1)
stats.numPLEMDeltaY = (stats.numEmissionEnd - stats.numEmissionStart)
stats.numPLEMBottomY = stats.numEmissionStart
else
stats.numPLEMBottomY = stats.wavExcitation[0]
stats.numPLEMDeltaY = PLEMd2Delta(stats.wavExcitation)
// since PLEMv3.0 excitation is saved multiplied by 10.
if(stats.numPLEMBottomY > 1e3)
stats.numPLEMBottomY /= 10
endif
endif
endif
// handle microscope images
if(stats.numReadOutMode == 1)
stats.numPLEMDeltaX = (stats.booSwitchY == 1 ? +1 : -1) * numSizeAdjustment * stats.numPixelPitch / stats.numMagnification
stats.numPLEMLeftX = stats.numPositionY - stats.numPLEMDeltaX * (stats.numLaserPositionX)
stats.numPLEMDeltaY = (stats.booSwitchX == 1 ? -1 : +1) * numSizeAdjustment * stats.numPixelPitch / stats.numMagnification
stats.numPLEMBottomY = stats.numPositionX - stats.numPLEMDeltaY * stats.numLaserPositionY
endif
PLEMd2statsSave(stats)
SetScale/P x stats.numPLEMLeftX, stats.numPLEMDeltaX, "", stats.wavPLEM, stats.wavMeasure, stats.wavBackground
SetScale/P y stats.numPLEMBottomY, stats.numPLEMDeltaY, "", stats.wavPLEM, stats.wavMeasure, stats.wavBackground
End
// recalculate laserposition for rotated image
static Function PLEMd2rotateLaser(stats)
Struct PLEMd2stats &stats
variable dim0, dim1
dim0 = stats.numLaserPositionX
dim1 = stats.numLaserPositionY
NVAR numRotationAdjustment = root:numRotationAdjustment
PLEMd2rotatePoint(dim0, dim1, stats.numPLEMTotalX, stats.numPLEMTotalY, numRotationAdjustment)
stats.numLaserPositionX = dim0
stats.numLaserPositionY = dim1
End
static Function PLEMd2rotatePoint(pointX, pointY, totalX, totalY, rotation)
Variable &pointX, &pointY
Variable totalX, totalY, rotation
// calculate LaserPosition (x,y) for rotated image when numRotationAdjustment != 0
Make/FREE/U/I/N=(totalX, totalY) wv = 0
wv[pointX][pointY] = 1000
ImageRotate/Q/E=(0)/O/A=(rotation) wv
WaveStats/M=1/Q wv
pointX = V_maxRowLoc
pointY = V_maxColLoc
return 0
End
Function PLEMd2BuildMaps(strPLEM)
String strPLEM
variable i, numExcitation
Struct PLEMd2stats stats
PLEMd2statsLoad(stats, strPLEM)
PLEMd2setScale(stats)
WAVE wavPLEM = stats.wavPLEM // work around bug in Multithread assignment which can not use stats.wavPLEM
// reset PLEM size to measurement (rotation changes it)
Redimension/N=(DimSize(stats.wavMeasure, 0), DimSize(stats.wavMeasure, 1)) stats.wavPLEM
if(stats.booBackground)
Multithread wavPLEM[][] = (stats.wavMeasure[p][q] - stats.wavBackground[p][q])
else
Multithread wavPLEM = stats.wavMeasure
endif
if(stats.booTime)
Multithread wavPLEM /= stats.numExposure
endif
if(stats.booWavelengthPitch)
Multithread wavPLEM[][] /= p > 0 ? abs(stats.wavWavelength[p] - stats.wavWavelength[p - 1]) : abs(stats.wavWavelength[1] - stats.wavWavelength[0])
endif
if(stats.numDetector == PLEMd2cameraClara || stats.numDetector == plemd2cameraXeva)
NVAR numRotationAdjustment = root:numRotationAdjustment
if(numRotationAdjustment != 0)
ImageRotate/Q/E=(NaN)/O/A=(numRotationAdjustment) stats.wavPLEM
endif
return NaN
endif
// spectrum corrections
if(stats.booPower)
if(DimSize(stats.wavPLEM, 1) == DimSize(stats.wavYpower, 0))
if(stats.booFilter)
Multithread wavPLEM /= (stats.wavYpower[q] / stats.wavFilterExc[q])
else
Multithread wavPLEM /= stats.wavYpower[q]
endif
else
Multithread wavPLEM /= stats.wavYpower[0]
endif
endif
if(stats.booPhoton)
if(stats.booFilter)
Multithread wavPLEM /= (stats.wavYphoton[q] / stats.wavFilterExc[q])
else
Multithread wavPLEM /= stats.wavYphoton[q]
endif
endif
if(stats.booFilter)
Multithread wavPLEM /= stats.wavFilterEmi[p]
endif
if(stats.booNormalization)
Multithread wavPLEM /= stats.numNormalization
endif
if(stats.booGrating)
Multithread wavPLEM /= stats.wavGrating[p]
endif
if(stats.booQuantumEfficiency)
stats.wavPLEM /= stats.wavQE[p]
endif
End
// function modified from absorption-load-v6
// calculates the mean distance between points in wave.
// mainly used in the process of transforming waves to igor wave format.
Function PLEMd2Delta(wavInput, [normal])
Wave wavInput
Variable normal
if(ParamIsDefault(normal))
normal = 0
endif
Variable numSize, numDelta, i
String strDeltaWave
numSize = DimSize(wavInput,0)
if(numSize > 1)
if(normal)
numDelta = abs((wavInput[numSize-1] - wavInput[0]))/(numSize-1)
else
// calculate numDelta
Make/FREE/O/N=(numSize-1) wavDeltaWave
for(i = 0; i < (numSize - 1); i += 1)
wavDeltaWave[i] = (wavInput[(i+1)] - wavInput[i])
endfor
WaveStats/Q/W wavDeltaWave
wave M_WaveStats
numDelta = M_WaveStats[3] //average
//print "Wave " + nameofwave(wavInput) + " has a Delta of " + num2str(numDelta) + " with a standard deviation of " + num2str(M_WaveStats[4])
//if X-Wave is not equally spaced, set the half minimum delta at all points.
// controll by calculating statistical error 2*sigma/rms
if((2 * M_WaveStats[4] / M_WaveStats[5] * 100) > 5)
print "PLEMd2Delta: Wave is not equally spaced. Check Code and calculate new Delta."
// minimum
numDelta = M_WaveStats[10]
// avg - 2 * sdev : leave out the minimum 5% for statistical resaons
if(M_WaveStats[3] > 0) // sdev is always positive ;-)
numDelta = M_WaveStats[3] - 2 * M_WaveStats[4]
else
numDelta = M_WaveStats[3] + 2 * M_WaveStats[4]
endif
endif
// not used put possibly needed, when a new Delta Value is returned.
KillWaves/Z M_WaveStats
endif
else
numDelta = 0
endif
return numDelta
End
Function PLEMd2ExtractInfo(strPLEM, wavIBW)
String strPLEM
WAVE wavIBW
String strFound
Struct PLEMd2Stats stats
PLEMd2statsLoad(stats, strPLEM)
stats.strPLEM = strPLEM
stats.strDate = PLEMd2ExtractSearch(wavIBW, "Date") /// @see PLEMd2Date2Minutes
stats.strUser = PLEMd2ExtractSearch(wavIBW, "User")
stats.strFileName = PLEMd2ExtractSearch(wavIBW, "File")
stats.numCalibrationMode = PLEMd2ExtractVariables(wavIBW, "numCalibrationMode")
stats.numSlit = PLEMd2ExtractVariables(wavIBW, "numSlit")
stats.numGrating = PLEMd2ExtractVariables(wavIBW, "numGrating")
stats.numFilter = PLEMd2ExtractVariables(wavIBW, "numFilter")
stats.numShutter = PLEMd2ExtractVariables(wavIBW, "numShutter")
stats.numWLcenter = PLEMd2ExtractVariables(wavIBW, "numWLcenter")
stats.numDetector = PLEMd2ExtractVariables(wavIBW, "numDetector")
stats.numCooling = PLEMd2ExtractVariables(wavIBW, "numCooling")
stats.numExposure = PLEMd2ExtractVariables(wavIBW, "numExposure")
stats.numBinning = PLEMd2ExtractVariables(wavIBW, "numBinning")
stats.numScans = PLEMd2ExtractVariables(wavIBW, "numScans")
stats.numBackground = PLEMd2ExtractVariables(wavIBW, "numBackground")
stats.numWLfirst = 0 // deprecated
stats.numWLlast = 0 // deprecated
stats.numWLdelta = PLEMd2ExtractVariables(wavIBW, "numWLdelta")
stats.numEmissionMode = PLEMd2ExtractVariables(wavIBW, "numEmissionMode")
stats.numEmissionPower = PLEMd2ExtractVariables(wavIBW, "numEmissionPower")
stats.numEmissionStart = PLEMd2ExtractVariables(wavIBW, "numEmissionStart")
stats.numEmissionEnd = PLEMd2ExtractVariables(wavIBW, "numEmissionEnd")
stats.numEmissionDelta = PLEMd2ExtractVariables(wavIBW, "numEmissionDelta")
stats.numEmissionStep = PLEMd2ExtractVariables(wavIBW, "numEmissionStep")
stats.numPositionX = PLEMd2ExtractVariables(wavIBW, "numPositionX")
stats.numPositionY = PLEMd2ExtractVariables(wavIBW, "numPositionY")
stats.numPositionZ = PLEMd2ExtractVariables(wavIBW, "numPositionZ")
stats.booSwitchX = PLEMd2ExtractVariables(wavIBW, "numSwitchX")
stats.booSwitchY = PLEMd2ExtractVariables(wavIBW, "numSwitchY")
stats.numReadOutMode = PLEMd2ExtractVariables(wavIBW, "numReadoutMode")
stats.numLaserPositionX = PLEMd2ExtractVariables(wavIBW, "numLaserX")
stats.numLaserPositionY = PLEMd2ExtractVariables(wavIBW, "numLaserY")
stats.numMagnification = PLEMd2ExtractVariables(wavIBW, "numMagnification")
PLEMd2statsSave(stats)
End
// @brief convert the stats.strDate string and return the time in minutes
//
// expected format for strDateTime: "DD.MM.YYYY/HH:MM"
Function PLEMd2Date2Minutes(strDateTime)
string strDateTime
string strDate, strTime
variable minutes
// format is DD.MM.YYYY
strDate = StringFromList(0, strDateTime, "/")
// format is HH:MM
strTime = StringFromList(1, strDateTime, "/")
minutes = date2secs(str2num(StringFromList(2, strDate, ".")), str2num(StringFromList(1, strDate, ".")), str2num(StringFromList(0, strDate, "."))) / 60
minutes += str2num(StringFromList(0, strTime, ":")) * 60
minutes += str2num(StringFromList(1, strTime, ":"))
return minutes
End
//This Function is called every time. we probably could make it more efficient. ;_(
Function PLEMd2ExtractVariables(wavIBW, strVariableName)
Wave wavIBW
String strVariableName
String strHeader, strReadLine, strItem
String strListVariableNames, strListVariables
Variable i, numCount
String strReturn = ""
strHeader = Note(wavIBW)
numCount = ItemsInList(strHeader, "\r\n")
i=0
do
i += 1
strReadLine = StringFromList(i, strHeader, "\r\n")
while ((StringMatch(strReadLine, "*IGOR0:*") != 1) && (i<numCount))
strListVariableNames = StringFromList(1, strReadLine, ":")
do
i += 1
strReadLine = StringFromList(i, strHeader, "\r\n")
while ((StringMatch(strReadLine, "*IGOR1:*") != 1) && (i<numCount))
strListVariables = StringFromList(1, strReadLine, ":")
strItem = StringFromList(WhichListItem(strVariableName, strListVariableNames), strListVariables)
//print "for " + strVariableName + " at item number: " + num2str(WhichListItem(strVariableName, strListVariableNames)) + " found item: " + strItem
return str2num(strItem)
End
Function/S PLEMd2ExtractSearch(wavIBW, strFind)
Wave wavIBW
String strFind
String strHeader, strReadLine, strItem
Variable i, numCount
String strReturn = ""
strHeader = Note(wavIBW)
numCount = ItemsInList(strHeader, "\r\n")
i=0
do
i += 1
strReadLine = StringFromList(i, strHeader, "\r\n")
while ((StringMatch(strReadLine, "*" + strFind + "*") != 1) && (i<numCount))
strItem = TrimString(strReadLine[strsearch(strReadLine, ":", 0) + 1, inf])
if((strlen(strReadLine)>0) && (strlen(strItem)>0))
strReturn = strItem
else
strReturn = ""
endif
return strReturn
End
Function/S PLEMd2ExtractWaveList(wavIBW)
Wave wavIBW
String strHeader, strList, strReadLine
Variable i, numLines, startLine, endLine
strHeader=note(wavIBW)
startLine = strsearch(strHeader, "IGOR3:", 0) + 6
if(startLine < 0)
Abort "Critical: String IGOR3: missing in WaveNote"
endif
endLine = strsearch(strHeader, "\r", startLine) - 1
if(endLine < 0)
endLine = strlen(strHeader)
endif
return strHeader[startLine, endLine]
End
Function/S PLEMd2ExtractPower(wavIBW)
//wavIBW can be any wave with correct wavenotes
Wave wavIBW
String strHeader, strReadLine
String strListPower, strListParse
Variable i, numCount, numItem
String strReturn = ""
strHeader = Note(wavIBW)
numCount = ItemsInList(strHeader, "\r\n")
i=0
do
i += 1
strReadLine = StringFromList(i, strHeader, "\r\n")
while ((StringMatch(strReadLine, "*Power at*") != 1) && (i<numCount)) //Power at Glass Plate (µW):
strListParse = StringFromList(1, strReadLine, ":")
numCount = ItemsInList(strListParse)
strListPower = ""
//assure to return numbers (not strings) in liststring
for(i = 0; i < numCount; i += 1)
numItem = str2num(StringFromList(i, strListParse))
strListPower = AddListItem(num2str(numItem), strListPower, ";",Inf)
endfor
//print "for " + strVariableName + " at item number: " + num2str(WhichListItem(strVariableName, strListVariableNames)) + " found item: " + strItem
return strListPower
End
Function/WAVE PLEMd2DuplicateByNum(numPLEM)
Variable numPLEM
if(numPLEM < 0)
print "PLEMd2DuplicateByNum: Wrong Function Call numPLEM out of range"
return $""
endif
String strPLEM
strPLEM = PLEMd2strPLEM(numPLEM)
return PLEMd2Duplicate(strPLEM)
End
Function/WAVE PLEMd2Duplicate(strPLEM, [overwrite])
String strPLEM
variable overwrite
String strTemp, strWavename
Variable i
Struct PLEMd2Stats stats
PLEMd2statsLoad(stats, strPLEM)
overwrite = ParamIsDefault(overwrite) ? 1 : !!overwrite
strWavename = "root:" + stats.strPLEM
strTemp = strWavename
if(!overwrite && WaveExists($strWavename))
print "PLEMd2Duplicate: Wave already exists. Using incremental WaveName"
i = -1
do
i += 1
strTemp = strWavename + "_" + num2str(i)
wave/Z wv = $strTemp
while(WaveExists(wv))
strWavename = strTemp
endif
Duplicate/O stats.wavPLEM $strWavename/WAVE=wv
print "PLEMd2Duplicate: WaveName is " + strWavename
return wv
End
Function PLEMd2FixWavenotes(wavIBW)
WAVE wavIBW
String strHeader, strWaveNames, strWaveNamesNew, falseBackground, i
print "PLEMd2FixWavenotes: Trying to correct WaveNote"
strHeader = Note(wavIBW)
if((StringMatch(strHeader, "*IGOR2:*")) == 0)
//IGOR2 not found so the error is probably related to that. (caused by early version of LabView program)
print "PLEMd2FixWavenotes: Error: Did not find IGOR2 in WaveNote. Fixing...."
//rename IGOR4 to IGOR3 and IGOR3 to IGOR2.
strHeader = ReplaceString("IGOR3:",strHeader, "IGOR2:")
strHeader = ReplaceString("IGOR4:",strHeader, "IGOR3:")
Endif
strWaveNames = PLEMd2ExtractWaveList(wavIBW)
if(StringMatch(strWaveNames, "*BG;*") && StringMatch(strWaveNames, "*BG_*"))
//mixed multiple and single background during measurement, revert to single bg
strWaveNamesNew = RemoveFromList(ListMatch(strWaveNames, "BG_*"), strWaveNames)
//strWaveNames = strHeader[strsearch(strHeader, "IGOR3:",0), strlen(strHeader)]
strHeader = ReplaceString("IGOR3:" + strWaveNames, strHeader, "IGOR3:" + strWaveNamesNew)
endif
End
Function PLEMd2AtlasReload(strPLEM)
String strPLEM
Struct PLEMd2stats stats
PLEMd2statsLoad(stats, strPLEM)
String strDataFolder = stats.strDataFolder + "CHIRALITY"
DFREF dfr = $strDataFolder
// create waves
Make/O/N=41/D dfr:atlasS1nm/WAVE=atlasS1nm
Make/O/N=41/D dfr:atlasS2nm/WAVE=atlasS2nm
Make/O/N=41/T dfr:atlasText/WAVE=atlasText
// fill waves with data
atlasS1nm[0]= {613.783,688.801,738.001,765.334,821.087,861.001,898.436,939.274,939.274,961.118,1008,1033.2,1078.12,1097.21,1107,1116.97,1148,1148,1169.66,1227.57,1227.57,1239.84,1239.84,1239.84,1278.19}
atlasS1nm[25]= {1291.5,1318.98,1347.65,1347.65,1347.65,1362.46,1377.6,1393.08,1441.68,1441.68,1441.68,1458.64,1458.64,1512,1549.8,1549.8}
atlasS2nm[0]= {568.735,510.223,613.783,596.078,480.559,576.671,688.801,497.928,659.49,563.564,639.094,729.319,712.553,582.085,642.405,548.603,789.708,708.481,784.71,629.361,779.775,720.838,666.582,607.766}
atlasS2nm[24]= {849.207,784.71,849.207,746.893,681.232,708.481,849.207,799.898,918.401,861.001,925.255,918.401,751.419,789.708,885.601,991.873,932.212}
atlasText[0] = {"(6,1)","(5,3)","(8,0)","(7,2)","(5,4)","(6,4)","(9,1)","(7,3)","(8,3)","(6,5)","(7,5)","(10,2)","(9,4)","(8,4)","(7,6)","(9,2)","(12,1)","(8,6)","(11,3)","(10,3)","(10,5)"}
atlasText[21]= {"(8,7)","(9,5)","(11,1)","(13,2)","(9,7)","(12,4)","(10,6)","(12,2)","(11,4)","(11,6)","(9,8)","(15,1)","(10,8)","(14,3)","(13,5)","(13,3)","(12,5)","(10,9)","(16,2)"}
End
Function PLEMd2AtlasRecalculate(strPLEM)
String strPLEM
Struct PLEMd2stats stats
PLEMd2statsLoad(stats, strPLEM)
Variable numPlank = 4.135667516E-12 //meV s
Variable numLight = 299792458E9 //nm/s
stats.wavEnergyS1 = numPlank * numLight / (numPlank * numLight / stats.wavAtlasS1nm[p] - stats.numS1offset)
stats.wavEnergyS2 = numPlank * numLight / (numPlank * numLight / stats.wavAtlasS2nm[p] - stats.numS2offset)
End
Function PLEMd2AtlasInit(strPLEM, [init, initT])
String strPLEM
WAVE init
WAVE/T initT
Struct PLEMd2stats stats
STRUCT cntRange range
Variable i, numChiralities, j
Variable xmin, xmax, ymin, ymax
Variable chirality_start, chirality_end
Variable tolerance = 5 // nm
PLEMd2AtlasReload(strPLEM)
PLEMd2statsLoad(stats, strPLEM)
if(!ParamIsDefault(init))
if(DimSize(init, 1) < 2)
Abort "PLEMd2AtlasInit: Invalid init wave"
endif
Redimension/N=(DimSize(init, 0)) stats.wavAtlasS1nm, stats.wavAtlasS2nm, stats.wavAtlasText
stats.wavAtlasS2nm[] = init[p][0]
stats.wavAtlasS1nm[] = init[p][1]
if(!ParamIsDefault(initT))
stats.wavAtlasText = initT[p]
else
stats.wavAtlasText = ""
endif
endif
// get boundaries from PLEM
PLEMd2GetAcceptableRange(stats, range)
ymin = range.yMin - tolerance
ymax = range.yMax + tolerance
xmin = range.xMin - tolerance
xmax = range.xMax + tolerance
// search for all chiralities within current window
Duplicate/O stats.wavAtlasS1nm stats.wavEnergyS1
Duplicate/O stats.wavAtlasS2nm stats.wavEnergyS2
Redimension/N=(DimSize(stats.wavAtlasText, 0)) stats.wavChiralityText
stats.wavChiralityText = stats.wavAtlasText[p]
stats.wavEnergyS2 = NaN
stats.wavEnergyS1 = NaN
numChiralities = Dimsize(stats.wavAtlasS1nm, 0)
j = 0
for(i = 0; i < numChiralities; i += 1)
if((stats.wavAtlasS2nm[i] > ymin) && (stats.wavAtlasS1nm[i] > xmin) && (stats.wavAtlasS2nm[i] < ymax) && (stats.wavAtlasS1nm[i] < xmax))
stats.wavEnergyS1[j] = stats.wavAtlasS1nm[i]
stats.wavEnergyS2[j] = stats.wavAtlasS2nm[i]
stats.wavChiralityText[j] = stats.wavAtlasText[i]
j += 1
endif
endfor
Redimension/N=(j) stats.wavEnergyS1, stats.wavEnergyS2, stats.wavChiralityText, stats.wavFWHMS1, stats.wavFWHMS2
// overwrite reset point.
Redimension/N=(j) stats.wavAtlasText, stats.wavAtlasS1nm, stats.wavAtlasS2nm, stats.wav2Dfit, stats.wav1Dfit
stats.wavAtlasText = stats.wavChiralityText[p]
stats.wavAtlasS1nm = stats.wavEnergyS1[p]
stats.wavAtlasS2nm = stats.wavEnergyS2[p]
stats.wav2Dfit = NaN
stats.wav1Dfit = NaN
stats.numS1offset = 0
stats.numS2offset = 0
PLEMd2statsSave(stats)
End
Function PLEMd2AtlasEdit(strPLEM)
String strPLEM
Struct PLEMd2stats stats
String winPLEMedit
if(PLEMd2MapExists(strPLEM) == 0)
print "PLEMd2AtlasFit: Map does not exist properly"
return 0
endif
PLEMd2statsLoad(stats, strPLEM)
winPLEMedit = PLEMd2getWindow(stats.strPLEM) + "_edit"
DoWindow/F $winPLEMedit
if(V_flag == 0)
Edit stats.wavchiralityText, stats.wav2Dfit, stats.wav1Dfit, stats.wavEnergyS1, stats.wavEnergyS2, stats.wavFWHMS1, stats.wavFWHMS2
DoWindow/C/N/R $winPLEMedit
endif
End
// uses 2d fit result to clean
Function PLEMd2AtlasClean(strPLEM, [ threshold ])
String strPLEM
Variable threshold
Variable i, numPoints
Variable xmin, xmax, ymin, ymax
Variable tolerance = 50
Variable accuracy
STRUCT cntRange range
Struct PLEMd2stats stats
PLEMd2statsLoad(stats, strPLEM)
threshold = ParamIsDefault(threshold) ? 0 : threshold
// get boundaries from PLEM
// get boundaries from PLEM
PLEMd2GetAcceptableRange(stats, range)
ymin = range.yMin - tolerance
ymax = range.yMax + tolerance
xmin = range.xMin - tolerance
xmax = range.xMax + tolerance
numPoints = DimSize(stats.wavchiralityText, 0)
for(i = numPoints - 1; i >= 0; i -= 1)
if(DimSize(stats.wavPLEM, 1) > 1)
if(stats.wav2Dfit[i] > threshold)
// value is greater than threshold
if((stats.wavEnergyS2[i] > ymin) && (stats.wavEnergyS2[i] < ymax))
// AND within y range
if((stats.wavEnergyS1[i] > xmin) && (stats.wavEnergyS1[i] < xmax))
// AND within x range
continue
endif
endif
endif
else
if(stats.wav1Dfit[i] > threshold)
// value is greater than threshold
if((stats.wavEnergyS1[i] > xmin) && (stats.wavEnergyS1[i] < xmax))
// AND within x range
continue
endif
endif
endif
DeletePoints i, 1, stats.wavchiralityText, stats.wav2Dfit, stats.wav1Dfit, stats.wavEnergyS1, stats.wavEnergyS2, stats.wavFWHMS1, stats.wavFWHMS2
endfor
// Remove Duplicates
if(DimSize(stats.wavchiralityText, 0) < 2)
return 0
endif
FindDuplicates/FREE/INDX=indexS1/TOL=25 stats.wavEnergyS1
FindDuplicates/FREE/INDX=indexS2/TOL=25 stats.wavEnergyS2
Concatenate/FREE {indexS1, indexS2}, indices
if(DimSize(indices, 0) > 1)
FindDuplicates/FREE/DN=duplicates indices
else
Duplicate/FREE indices duplicates
endif
if(DimSize(duplicates, 0) == 0 || numtype(duplicates[0]) != 0)
return 0
endif
numPoints = DimSize(duplicates, 0)
Sort duplicates, duplicates
for(i = numPoints - 1; i >= 0; i -= 1)
DeletePoints duplicates[i], 1, stats.wavchiralityText, stats.wav2Dfit, stats.wav1Dfit, stats.wavEnergyS1, stats.wavEnergyS2, stats.wavFWHMS1, stats.wavFWHMS2
endfor
// find text labels in atlas wave
numPoints = DimSize(stats.wavchiralityText, 0)
for(i = 0; i < numPoints; i += 1)
accuracy = 1
do
Extract/FREE/INDX/U/I stats.wavAtlasText, index, \
((round(stats.wavAtlasS1nm[p] / accuracy) * accuracy == round(stats.wavEnergyS1[i] / accuracy) * accuracy) && \
(round(stats.wavAtlasS2nm[p] / accuracy) * accuracy == round(stats.wavEnergyS2[i] / accuracy) * accuracy))
accuracy += 0.5
while(DimSize(index, 0) < 1)
if(DimSize(index, 0) > 1)
Make/FREE/N=(DimSize(index, 0)) temp = stats.wavAtlasS1nm[index[p]]
Sort index, temp
endif
stats.wavchiralityText[i] = stats.wavAtlasText[index[0]]
endfor
Sort/A=1 stats.wavchiralityText, stats.wavchiralityText, stats.wav2Dfit, stats.wav1Dfit, stats.wavEnergyS1, stats.wavEnergyS2, stats.wavFWHMS1, stats.wavFWHMS2
End
static Constant cminS1fwhm = 3
static Constant cmaxS1fwhm = 30
static Constant cminS2fwhm = 10
static Constant cmaxS2fwhm = 150
Function PLEMd2AtlasFit2D(strPLEM)
String strPLEM
Variable i, j, numAtlas, numFits
Variable pStart, pEnd, qStart, qEnd, pAccuracy, qAccuracy, minpqAccuracy = 5
String strWavPLEMfitSingle, strWavPLEMfit
Variable s1FWHM, s2FWHM, s2nm, s1nm, intensity
Variable numDeltaS1 = 25 //nm
Variable numDeltaS2 = 25 //nm
Variable V_fitOptions = 4 // used to suppress CurveFit dialog
Variable err
Struct PLEMd2stats stats
PLEMd2statsLoad(stats, strPLEM)
WAVE PLEM = removeSpikes(stats.wavPLEM)
pAccuracy = max(minpqAccuracy, ceil(numDeltaS1 / DimDelta(PLEM, 0)))
qAccuracy = max(minpqAccuracy, ceil(numDeltaS2 / DimDelta(PLEM, 1)))
Make/O/T/N=5 root:T_Constraints/WAVE=T_Constraints
T_Constraints[0] = "K1 > 0"
numFits = numpnts(stats.wavEnergyS1)
for(i = 0; i < numFits; i += 1)
intensity = stats.wav1Dfit[i]
s1nm = stats.wavEnergyS1[i]
s2nm = stats.wavEnergyS2[i]
s1FWHM = stats.wavFWHMS1[i]
s2FWHM = stats.wavFWHMS2[i]
// fit emission wavelength to get center wavelength for excitation fit
T_Constraints[1] = "K2 > " + num2str(s1nm - numDeltaS1 / 2)
T_Constraints[2] = "K2 < " + num2str(s1nm + numDeltaS1 / 2)
T_Constraints[3] = "K3 > " + num2str(cminS1fwhm / 1.66511) // 2*sqrt(ln(2)) = 1.66511
T_Constraints[4] = "K3 < " + num2str(cmaxS1fwhm / 1.66511) // 2*sqrt(ln(2)) = 1.66511
[ pStart, pEnd ] = FindLevelWrapper(stats.wavWavelength, s1nm, accuracy = pAccuracy)
[ qStart, qEnd ] = FindLevelWrapper(stats.wavExcitation, s2nm, accuracy = qAccuracy)
Duplicate/FREE/R=[pStart, pEnd][qStart, qEnd] PLEM dummy
MatrixOP/FREE fitme = sumRows(dummy)
Duplicate/FREE/R=[pStart, pEnd] stats.wavWavelength xfitme
try
CurveFit/Q gauss fitme/X=xfitme/C=T_Constraints; AbortOnRTE
WAVE W_coef
s1FWHM = W_coef[3] * 1.66511 // 2*sqrt(ln(2)) = 1.66511 @see GaussPeakParams
s1nm = W_coef[2]
WaveClear W_coef
catch
err = GetRTError(1)
endtry
WaveClear fitme, xfitme
// fit excitation wavelength
T_Constraints[1] = "K2 > " + num2str(s2nm - numDeltaS2 / 2)
T_Constraints[2] = "K2 < " + num2str(s2nm + numDeltaS2 / 2)
T_Constraints[3] = "K3 > " + num2str(cminS2fwhm / 1.66511)
T_Constraints[4] = "K3 < " + num2str(cmaxS2fwhm / 1.66511)
[ pStart, pEnd ] = FindLevelWrapper(stats.wavWavelength, s1nm, accuracy = pAccuracy)
[ qStart, qEnd ] = FindLevelWrapper(stats.wavExcitation, s2nm, accuracy = qAccuracy)
Duplicate/FREE/R=[pStart, pEnd][qStart, qEnd] PLEM dummy
MatrixOP/FREE fitme = sumCols(dummy)^t
Duplicate/FREE/R=[qStart, qEnd] stats.wavExcitation xfitme
try
CurveFit/Q gauss fitme/X=xfitme/C=T_Constraints; AbortOnRTE
WAVE W_coef
s2FWHM = W_coef[3] * 1.66511 // 2*sqrt(ln(2)) = 1.66511 @see GaussPeakParams
s2nm = W_coef[2]
WaveClear W_coef
catch
err = GetRTError(1)
endtry
WaveClear fitme, xfitme
stats.wavEnergyS2[i] = s2nm
stats.wavFWHMS2[i] = s2FWHM
// fit emission to get max intensity
T_Constraints[1] = "K2 > " + num2str(s1nm - numDeltaS1 / 2)
T_Constraints[2] = "K2 < " + num2str(s1nm + numDeltaS1 / 2)
T_Constraints[3] = "K3 > " + num2str(cminS1fwhm / 1.66511) // 2*sqrt(ln(2)) = 1.66511
T_Constraints[4] = "K3 < " + num2str(cmaxS1fwhm / 1.66511) // 2*sqrt(ln(2)) = 1.66511
[ pStart, pEnd ] = FindLevelWrapper(stats.wavWavelength, s1nm, accuracy = pAccuracy * 4)
FindLevel/Q/P/T=(qAccuracy) stats.wavExcitation, s2nm
qStart = V_Flag ? 0 : min(DimSize(stats.wavExcitation, 0) - 1, max(0, round(V_levelX)))
Duplicate/FREE/R=[pStart, pEnd][qStart] PLEM fitme
Redimension/N=(-1, 0) fitme
Duplicate/FREE/R=[pStart, pEnd] stats.wavWavelength xfitme
try
CurveFit/Q gauss fitme/X=xfitme/C=T_Constraints; AbortOnRTE
WAVE W_coef
intensity = W_coef[1]
s1FWHM = W_coef[3] * 1.66511 // 2*sqrt(ln(2)) = 1.66511 @see GaussPeakParams
s1nm = W_coef[2]
WaveClear W_coef
catch
err = GetRTError(1)
endtry
WaveClear fitme, xfitme
stats.wav1Dfit[i] = intensity
stats.wavEnergyS1[i] = s1nm
stats.wavFWHMS1[i] = s1FWHM
endfor
End
Function PLEMd2AtlasFit3D(strPLEM, [show])
String strPLEM
Variable show
Variable i, numS1, numS2
Variable numDeltaS1left, numDeltaS1right, numDeltaS2bottom, numDeltaS2top
Variable rightXvalue, topYvalue
Variable err
Variable s1FWHM, s2FWHM, s2emi, s1exc, distortion, intensity
String winPLEMfit, winPLEM
Struct PLEMd2stats stats
Variable V_fitOptions = 4 // used to suppress CurveFit dialog
Variable numDeltaS1 = 30
Variable numDeltaS2 = 30
show = ParamIsDefault(show) ? 0 : show
if(PLEMd2MapExists(strPLEM) == 0)
print "PLEMd2AtlasFit: Map does not exist properly"
return 1
endif
PLEMd2statsLoad(stats, strPLEM)
WAVE PLEM = removeSpikes(PLEMd2NanotubeRangePLEM(stats))
Redimension/N=(DimSize(PLEM, 0), DimSize(PLEM, 1), numpnts(stats.wavEnergyS1)) stats.wavPLEMfit
CopyScales PLEM, stats.wavPLEMfit, stats.wavPLEMfitSingle
rightXvalue = stats.numPLEMleftX + stats.numPLEMTotalX * stats.numPLEMdeltaX
topYvalue = stats.numPLEMbottomY + stats.numPLEMTotalY * stats.numPLEMdeltaY
// input
for(i = 0; i < numpnts(stats.wavEnergyS1); i += 1)
numS1 = stats.wavEnergyS1[i] // x
numS2 = stats.wavEnergyS2[i] // y
numDeltaS1left = numS1 - numDeltaS1
numDeltaS1right = numS1 + numDeltaS1
numDeltaS2bottom = numS2 - numDeltaS2
numDeltaS2top = numS2 + numDeltaS2
// 2*sqrt(ln(2)) = 1.66511 @see GaussPeakParams
Make/O/T/N=10 root:T_Constraints/WAVE=T_Constraints
T_Constraints[0] = "K2 > " + num2str(numDeltaS1left)
T_Constraints[1] = "K2 < " + num2str(numDeltaS1right)
T_Constraints[2] = "K4 > " + num2str(numDeltaS2bottom)
T_Constraints[3] = "K4 < " + num2str(numDeltaS2top)
T_Constraints[4] = "K3 > " + num2str(cminS1fwhm / 1.66511)
T_Constraints[5] = "K3 < " + num2str(cmaxS1fwhm / 1.66511)
T_Constraints[6] = "K5 > " + num2str(cminS2fwhm / 1.66511)
T_Constraints[7] = "K5 < " + num2str(cmaxS2fwhm / 1.66511)
T_Constraints[8] = "K6 > -0.1"
T_Constraints[9] = "K6 < 0.1"
stats.wavPLEMfit[][][i] = 0
stats.wav2Dfit[i] = 0
try
CurveFit/Q gauss2D PLEM(numDeltaS1left, numDeltaS1right)(numDeltaS2bottom, numDeltaS2top)/T=T_Constraints; AbortOnRTE
catch
err = GetRTError(1)
continue
endtry
Wave W_coef
intensity = W_coef[1]
s1FWHM = W_coef[3] * 1.66511
s2FWHM = W_coef[5] * 1.66511
distortion = abs(W_coef[6])
s2emi = W_coef[4]
s1exc = W_coef[2]
// check if distorted gaussian
if(distortion > 0.5)
continue
endif
// check if fwhm is within a valid range s2 is typically 15nm and s1 5nm
if((s1FWHM > cmaxS1fwhm * 2) || (s1FWHM < cminS1fwhm / 2) || (s2FWHM > cmaxS2fwhm * 2) || (s2FWHM < cminS2fwhm / 2))
continue
endif
// error checking
if((abs((numS1 - s1exc) / numS1) > 0.25 ) || (abs((numS2 - s2emi) / numS2) > 0.25 ))
continue
endif
stats.wavEnergyS1[i] = s1exc
stats.wavEnergyS2[i] = s2emi
stats.wavFWHMS1[i] = s1FWHM
stats.wavFWHMS2[i] = s2FWHM
stats.wav2Dfit[i] = W_coef[1]*2*pi* W_coef[3]* W_coef[5]*sqrt(1-W_coef[6]^2) // volume of 2d gauss without baseline
stats.wav1Dfit[i] = intensity
stats.wavPLEMfit[][][i] = Gauss2D(W_coef, x, y)
WaveClear W_coef
endfor
// add all maps to one map
PLEMd2AtlasMerge3d(stats.wavPLEMfit, stats.wavPLEMfitSingle)
if(!show)
return 0
endif
// check if window already exists
winPLEM = PLEMd2getWindow(stats.strPLEM)
DoWindow $winPLEM
// DoWindow sets the variable V_flag:
// 1 window existed
// 0 no such window
// 2 window is hidden.
if(!!V_flag)
String listContour = ContourNameList("", ";")
for(i = 0; i < ItemsInList(listContour); i += 1)
RemoveContour/W=$winPLEM $(StringFromList(i, listContour))
endfor
AppendMatrixContour/W=$winPLEM stats.wavPLEMfitSingle
ModifyContour/W=$winPLEM ''#0 labels=0,autoLevels={0,*,10}
endif
// check if window already exists
winPLEMfit = PLEMd2getWindow(stats.strPLEM) + "_fit"
DoWindow/F $winPLEMfit
if(V_flag == 2)
print "PLEMd2AtlasFit: Fit-Graph was hidden. Case not handled. check code"
elseif(V_flag == 0)
Display
DoWindow/C/N/R $winPLEMfit
Appendimage stats.wavPLEMfitSingle
PLEMd2Decorate()
endif
End
Function PLEMd2AtlasMerge3d(wave3d, wave2d)
Wave wave3d, wave2d
Variable i
Duplicate/O/R=[][][0] wave3d wave2d
Redimension/N=(Dimsize(wave3d, 0), Dimsize(wave3d, 1)) wave2d
for(i = 1; i < Dimsize(wave3d, 2); i += 1)
wave2d += wave3d[p][q][i]
endfor
End
Function PLEMd2AtlasShow(strPLEM)
String strPLEM
Struct PLEMd2stats stats
if(PLEMd2MapExists(strPLEM) == 0)
print "PLEMd2AtlasShow: Map does not exist properly"
return 0
endif
PLEMd2statsLoad(stats, strPLEM)
PLEMd2Display(strPLEM)
PLEMd2AtlasHide(strPLEM) //prevent multiple traces
AppendToGraph stats.wavEnergyS2/TN=plem01 vs stats.wavEnergyS1
AppendToGraph stats.wavEnergyS2/TN=plem02 vs stats.wavEnergyS1
AppendToGraph stats.wavEnergyS2/TN=plem03 vs stats.wavEnergyS1
ModifyGraph mode(plem02)=3 //cross
ModifyGraph marker(plem02)=1
ModifyGraph rgb(plem02)=(0,0,0)
ModifyGraph mode(plem03)=3 //dots
ModifyGraph useMrkStrokeRGB(plem03)=1
ModifyGraph textMarker(plem03)={stats.wavChiralityText, "default",0,0,5,0.00,10.00} //labels top
ModifyGraph rgb(plem03)=(65535,65535,65535)
ModifyGraph mrkStrokeRGB(plem03)=(65535,65535,65535)
ModifyGraph mode(plem01)=3 , msize(plem01)=2
ModifyGraph marker(plem01)=5 // squares
ModifyGraph marker(plem01)=8 // circles
ModifyGraph msize(plem01)=5
ModifyGraph height={Plan,1,left,bottom}
ModifyGraph height=0
End
Function PLEMd2AtlasHide(strPLEM)
String strPLEM
if(PLEMd2MapExists(strPLEM) == 0)
print "PLEMd2AtlasHide: Map does not exist properly"
return 0
endif
PLEMd2Display(strPLEM)
RemoveFromGraph/Z plem01
RemoveFromGraph/Z plem02
RemoveFromGraph/Z plem03
Variable i
String listContour = ContourNameList("", ";")
for(i = 0; i < ItemsInList(listContour); i += 1)
RemoveContour $(StringFromList(i, listContour))
endfor
End
//adapted from function OpenFileDialog on http://www.entorb.net/wickie/IGOR_Pro
Function/S PLEMd2PopUpChooseFile([strPrompt])
String strPrompt
Variable refNum
String strFileName, strLastPath, strFolderName
String fileFilters = "Igor Binary File (*.ibw):.ibw;General Text Files (*.txt, *.csv):.txt,.csv;All Files:.*;"
// get last path
Struct PLEMd2Prefs prefs
PLEMd2LoadPackagePrefs(prefs)
strLastPath = prefs.strLastPath
GetFileFolderInfo/Q/Z=1 strLastPath
if(V_Flag || !V_isFolder)
strLastPath = prefs.strBasePath
GetFileFolderInfo/Q/Z=1 strLastPath
if(V_Flag || !V_isFolder)
strLastPath = SpecialDirPath("Documents", 0, 0, 0 )
endif
endif
//Display file Dialog starting with last path
NewPath/O/Q PLEMd2LastPath, strLastPath
if(V_flag)
Abort "Invalid Path"
endif
PathInfo/S PLEMd2LastPath
if(!V_flag)
Abort "Symbolic path does not exist"
endif
strPrompt = SelectString(ParamIsDefault(strPrompt), strPrompt, "choose file")
Open/D/R/Z=2/F=fileFilters/M=strPrompt refNum
if(V_flag)
KillPath/Z PLEMd2LastPath
return ""
endif
strFileName = S_fileName
KillPath/Z PLEMd2LastPath // we don't need the path reference
// save as last path
strFolderName = ParseFilePath(1, strFileName, ":", 1, 0)
GetFileFolderInfo/Q/Z=1 strFolderName
if(V_isFolder)
prefs.strLastPath = strFolderName
PLEMd2SavePackagePrefs(prefs)
endif
return strFileName
End
// @todo only use wave @c mapsAvailable here
// @see PLEMd2getAllstrPLEM
Function PLEMd2getMapsAvailable()
DFREF dfr = $cstrPLEMd2root
NVAR/Z numMaps = dfr:gnumMapsAvailable
if(!NVAR_EXISTS(numMaps))
return ItemsInList(PLEMd2getStrMapsAvailable())
endif
return numMaps
End
// @todo only use wave @c mapsAvailable here
// @see PLEMd2getAllstrPLEM
Function/S PLEMd2getStrMapsAvailable()
DFREF dfr = $cstrPLEMd2root
SVAR/Z strMaps = dfr:gstrMapsAvailable
if(!SVAR_EXISTS(strMaps))
return ""
endif
return strMaps
End
Function PLEMd2AddMap(strMap)
String strMap
DFREF dfr = $cstrPLEMd2root
SVAR gstrMapsAvailable = dfr:gstrMapsAvailable
NVAR gnumMapsAvailable = dfr:gnumMapsAvailable
Variable numFind
numFind = FindListItem(strMap, gstrMapsAvailable)
if(numFind == -1)
gstrMapsAvailable += strMap + ";"
numFind = ItemsInList(gstrMapsAvailable)
gnumMapsAvailable = numFind
else
gnumMapsAvailable = ItemsInList(gstrMapsAvailable)
endif
return numFind
End
Function PLEMd2KillMap(strMap)
String strMap
DFREF dfr = $cstrPLEMd2root
SVAR gstrMapsAvailable = dfr:gstrMapsAvailable
NVAR gnumMapsAvailable = dfr:gnumMapsAvailable
if(FindListItem(strMap, gstrMapsAvailable) != -1)
gstrMapsAvailable = RemoveFromList(strMap, gstrMapsAvailable)
gnumMapsAvailable = ItemsInList(gstrMapsAvailable)
endif
DFREF dfrMap = PLEMd2MapFolder(strMap)
if(DataFolderRefStatus(dfrMap) != 0)
WAVE/Z wavIBW = dfrMap:IBW
SetWaveLock 0, wavIBW
WaveClear wavIBW
KillDataFolder/Z dfrMap
if(V_flag)
printf "PLEMd2KillMap: DataFolder %s could not be deleted.\r", strMap
endif
endif
End
Function PLEMd2KillMapByNum(numPLEM)
Variable numPLEM
if(numPLEM < 0)
print "PLEMd2KillMapByNum: Wrong Function Call numPLEM out of range"
return 0
endif
String strPLEM
strPLEM = PLEMd2strPLEM(numPLEM)
PLEMd2KillMap(strPLEM)
End
Function PLEMd2MapExists(strMap)
String strMap
String strMaps = PLEMd2getStrMapsAvailable()
if(FindListItem(strMap, strMaps) != -1)
return 1
endif
return 0
End
// check maps folder for content
//
// return number of maps
Function PLEMd2MapStringReInit()
DFREF dfr = $cstrPLEMd2root
SVAR gstrMapsFolder = dfr:gstrMapsFolder
SVAR gstrMapsAvailable = dfr:gstrMapsAvailable
NVAR gnumMapsAvailable = dfr:gnumMapsAvailable
Variable i, numMapsAvailable
String strMap
gstrMapsAvailable = ""
gnumMapsAvailable = 0
numMapsAvailable = CountObjects(gstrMapsFolder, 4) // number of data folders
for(i = 0; i < numMapsAvailable; i += 1)
strMap = GetIndexedObjName(gstrMapsFolder,4,i)
gstrMapsAvailable += strMap + ";"
endfor
gnumMapsAvailable = ItemsInList(gstrMapsAvailable)
return gnumMapsAvailable
End
//Helper Function
Function/S PLEMd2SetWaveScale(wavX, wavY, strOut)
Wave wavX, wavY
String strOut
Variable numSize, numOffset, numDelta
if(!waveExists(wavX) && !waveExists(wavY))
print "Error: Waves Do not exist or user cancelled at Prompt"
return ""
endif
if(!WaveExists($strOut))
Duplicate/O wavY $strOut
else
if(!StringMatch(GetWavesDataFolder(wavY, 2),GetWavesDataFolder($strOut, 2)))
Duplicate/O wavY $strOut
endif
endif
wave wavOut = $strOut
numSize = DimSize(wavX,0)
numOffset = wavX[0]
numDelta = (wavX[(numSize-1)] - wavX[0]) / (numSize-1)
SetScale/P x, numOffset, numDelta, "", wavOut
SetScale/P y, 1, 1, "", wavOut
return GetWavesDataFolder(wavOut, 2)
End
//Function sorts two Numbers
Function PLEMd2sort(left, right)
Variable &left,&right
Variable temp
if(left > right)
temp=left
left=right
right=temp
temp=0
endif
End
//Get number of map. in Menu-List.
Function PLEMd2numPLEM(strPLEM)
String strPLEM
DFREF dfr = $cstrPLEMd2root
string strMaps = PLEMd2getStrMapsAvailable()
return FindListItem(strPLEM, strMaps)
End
// @todo only use wave @c mapsAvailable
// @see PLEMd2getAllstrPLEM PLEMd2getStrMapsAvailable
Function/S PLEMd2strPLEM(numPLEM)
Variable numPLEM
DFREF dfr = $cstrPLEMd2root
string strMaps = PLEMd2getStrMapsAvailable()
return StringFromList(numPLEM, strMaps)
End
// @todo make this the main dependency for @c PLEMd2getStrMapsAvailable and related
// make it more robust with crc and datafolder / original IBW checkings
Function/WAVE PLEMd2getAllstrPLEM([forceRenew])
Variable forceRenew
String strPLEM
Variable i
Variable numMaps = PLEMd2getMapsAvailable() // @todo remove dependency
DFREF dfr = $cstrPLEMd2root
Struct PLEMd2stats stats
forceRenew = ParamIsDefault(forceRenew) ? 0 : !!forceRenew
WAVE/T/Z wv = dfr:mapsAvailable
if(WaveExists(wv) && !forceRenew)
if(DimSize(wv, 0) == numMaps)
return wv
else
Redimension/N=(numMaps) wv
endif
else
Make/O/T/N=(numMaps) dfr:mapsAvailable/WAVE=wv
endif
wv[] = PLEMd2strPLEM(p)
return wv
End
Function/WAVE PLEMd2getCoordinates([forceRenew])
Variable forceRenew
Variable i
Variable numMaps = PLEMd2getMapsAvailable()
DFREF dfr = $cstrPLEMd2root
Struct PLEMd2stats stats
forceRenew = ParamIsDefault(forceRenew) ? 0 : !!forceRenew
WAVE/Z wv = dfr:coordinates
if(WaveExists(wv) && !forceRenew)
if(DimSize(wv, 0) == numMaps)
return wv
else
Redimension/N=(numMaps, -1) wv
endif
else
Make/O/N=(numMaps, 3) dfr:coordinates/WAVE=wv = NaN
endif
WAVE/T wavStrPLEM = PLEMd2getAllstrPLEM()
for(i = 0; i < numMaps; i += 1)
PLEMd2statsLoad(stats, wavStrPLEM[i])
wv[i][0] = stats.numPositionX
wv[i][1] = stats.numPositionY
wv[i][2] = stats.numPositionZ
endfor
return wv
End
// Get the excitation Power from the maps in the given range
//
// @param overwrite if set to 1: recreate the wave if it already exists
// @param range specify the spectra ids with a numeric, uint wave
Function/WAVE PLEMd2getPower([overwrite, range])
Variable overwrite
WAVE/U/I range
Variable i, dim0, dim1
DFREF dfr = $cstrPLEMd2root
Struct PLEMd2stats stats
overwrite = ParamIsDefault(overwrite) ? 0 : !!overwrite
if(ParamIsDefault(range))
Make/FREE/U/I/N=(PLEMd2getMapsAvailable()) range = p
endif
dim0 = DimSize(range, 0)
WAVE/Z wv = dfr:power
if(WaveExists(wv) && !overwrite)
if(DimSize(wv, 0) == dim0)
return wv
endif
endif
PLEMd2statsLoad(stats, PLEMd2strPLEM(range[0]))
dim1 = DimSize(stats.wavPLEM, 1)
if(dim1 == 1)
dim1 = 0
endif
Make/O/N=(dim0, dim1) dfr:power/WAVE=wv = NaN
WAVE/T wavStrPLEM = PLEMd2getAllstrPLEM()
for(i = 0; i < dim0; i += 1)
PLEMd2statsLoad(stats, wavStrPLEM[range[i]])
wv[i][] = stats.wavYpower[q]
endfor
printf "PLEMd2getPower: created %s\r", GetWavesDataFolder(wv, 2)
return wv
End
Function/WAVE PLEMd2getPhoton([forceRenew])
Variable forceRenew
Variable i
Variable numMaps = PLEMd2getMapsAvailable()
DFREF dfr = $cstrPLEMd2root
Struct PLEMd2stats stats
forceRenew = ParamIsDefault(forceRenew) ? 0 : !!forceRenew
WAVE/Z wv = dfr:photon
if(WaveExists(wv) && !forceRenew)
if(DimSize(wv, 0) == numMaps)
return wv
else
Redimension/N=(numMaps, -1) wv
endif
else
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
Make/O/N=(numMaps, DimSize(stats.wavPLEM, 1)) dfr:photon/WAVE=wv = NaN
endif
WAVE/T wavStrPLEM = PLEMd2getAllstrPLEM()
for(i = 0; i < numMaps; i += 1)
PLEMd2statsLoad(stats, wavStrPLEM[i])
wv[i][] = stats.wavYphoton[q]
endfor
print GetWavesDataFolder(wv, 0)
return wv
End
Function/WAVE PLEMd2getDetectors()
Variable i
Variable numMaps
DFREF dfr = $cstrPLEMd2root
Struct PLEMd2stats stats
WAVE/T wavStrPLEM = PLEMd2getAllstrPLEM()
WAVE/U/B/Z wv = dfr:detectors
NVAR/Z crc = dfr:gnumDetectors
if(WaveExists(wv) && NVAR_Exists(crc) && WaveCRC(0, wavStrPLEM) == crc)
return wv
endif
if(!NVAR_Exists(crc))
Variable/G dfr:gnumDetectors
NVAR crc = dfr:gnumDetectors
endif
numMaps = PLEMd2getMapsAvailable()
Make/O/U/B/N=(numMaps) dfr:detectors/WAVE=wv = NaN
for(i = 0; i < numMaps; i += 1)
PLEMd2statsLoad(stats, wavStrPLEM[i])
wv[i] = stats.numDetector
endfor
crc = WaveCRC(0, wavStrPLEM)
return wv
End
// return PLEM with measurement range (setup specific to microscope with 830lp)
Function/WAVE PLEMd2NanotubeRangePLEM(stats)
Struct PLEMd2stats &stats
STRUCT cntRange range
PLEMd2GetAcceptableRange(stats, range)
Variable qMin, qMax
Variable pMin = ScaleToIndex(stats.wavPLEM, range.xMin, 0)
Variable pMax = ScaleToIndex(stats.wavPLEM, range.xMax, 0)
if(DimSize(stats.wavPLEM, 1) > 1)
qMin = ScaleToIndex(stats.wavPLEM, range.yMin, 1)
qMax = ScaleToIndex(stats.wavPLEM, range.yMax, 1)
Duplicate/FREE/R=[pMin, pMax][qMin, qMax] stats.wavPLEM, wv
else
Duplicate/FREE/R=[pMin, pMax] stats.wavPLEM, wv
endif
return wv
End
Structure cntRange
Variable xMin, xMax
Variable yMin, yMax
EndStructure
Function PLEMd2GetAcceptableRange(stats, range)
STRUCT PLEMd2stats &stats
STRUCT cntRange &range
if(stats.numDetector > 1)
Abort "PLEMd2GetAcceptableRange: Only for Newton and Idus"
endif
range.xMin = stats.numDetector == PLEMd2detectorNewton ? 830 : 1000
range.xMax = stats.numDetector == PLEMd2detectorNewton ? 1040 : 1280
range.yMin = 525
range.yMax = 760
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
Menu "PLEM", dynamic //create menu bar entry
PLEMd2MenuInit() + "Init", /q, PLEMd2initialize()
"Set Paths", PLEMd2SetPaths()
"Open", PLEMd2open()
"-"
SubMenu "Display"
//List all available Maps in current project (max 30)
PLEMd2Menu(0), PLEMd2DisplayByNum(0)
PLEMd2Menu(1), PLEMd2DisplayByNum(1)
PLEMd2Menu(2), PLEMd2DisplayByNum(2)
PLEMd2Menu(3), PLEMd2DisplayByNum(3)
PLEMd2Menu(4), PLEMd2DisplayByNum(4)
PLEMd2Menu(5), PLEMd2DisplayByNum(5)
PLEMd2Menu(6), PLEMd2DisplayByNum(6)
PLEMd2Menu(7), PLEMd2DisplayByNum(7)
PLEMd2Menu(8), PLEMd2DisplayByNum(8)
PLEMd2Menu(9), PLEMd2DisplayByNum(9)
PLEMd2Menu(10), PLEMd2DisplayByNum(10)
PLEMd2Menu(11), PLEMd2DisplayByNum(11)
PLEMd2Menu(12), PLEMd2DisplayByNum(12)
PLEMd2Menu(13), PLEMd2DisplayByNum(13)
PLEMd2Menu(14), PLEMd2DisplayByNum(14)
PLEMd2Menu(15), PLEMd2DisplayByNum(15)
PLEMd2Menu(16), PLEMd2DisplayByNum(16)
PLEMd2Menu(17), PLEMd2DisplayByNum(17)
PLEMd2Menu(18), PLEMd2DisplayByNum(18)
PLEMd2Menu(19), PLEMd2DisplayByNum(19)
PLEMd2Menu(20), PLEMd2DisplayByNum(20)
PLEMd2Menu(21), PLEMd2DisplayByNum(21)
PLEMd2Menu(22), PLEMd2DisplayByNum(22)
PLEMd2Menu(23), PLEMd2DisplayByNum(23)
PLEMd2Menu(24), PLEMd2DisplayByNum(24)
PLEMd2Menu(25), PLEMd2DisplayByNum(25)
PLEMd2Menu(26), PLEMd2DisplayByNum(26)
PLEMd2Menu(27), PLEMd2DisplayByNum(27)
PLEMd2Menu(28), PLEMd2DisplayByNum(28)
PLEMd2Menu(29), PLEMd2DisplayByNum(29)
End
"Info", PLEMd2Panel()
"Atlas", PLEMd2PanelAtlas()
"-"
SubMenu "Duplicate"
PLEMd2Menu(0), PLEMd2DuplicateByNum(0)
PLEMd2Menu(1), PLEMd2DuplicateByNum(1)
PLEMd2Menu(2), PLEMd2DuplicateByNum(2)
PLEMd2Menu(3), PLEMd2DuplicateByNum(3)
PLEMd2Menu(4), PLEMd2DuplicateByNum(4)
PLEMd2Menu(5), PLEMd2DuplicateByNum(5)
PLEMd2Menu(6), PLEMd2DuplicateByNum(6)
PLEMd2Menu(7), PLEMd2DuplicateByNum(7)
PLEMd2Menu(8), PLEMd2DuplicateByNum(8)
PLEMd2Menu(9), PLEMd2DuplicateByNum(9)
PLEMd2Menu(10), PLEMd2DuplicateByNum(10)
PLEMd2Menu(11), PLEMd2DuplicateByNum(11)
PLEMd2Menu(12), PLEMd2DuplicateByNum(12)
PLEMd2Menu(13), PLEMd2DuplicateByNum(13)
PLEMd2Menu(14), PLEMd2DuplicateByNum(14)
PLEMd2Menu(15), PLEMd2DuplicateByNum(15)
PLEMd2Menu(16), PLEMd2DuplicateByNum(16)
PLEMd2Menu(17), PLEMd2DuplicateByNum(17)
PLEMd2Menu(18), PLEMd2DuplicateByNum(18)
PLEMd2Menu(19), PLEMd2DuplicateByNum(19)
PLEMd2Menu(20), PLEMd2DuplicateByNum(20)
PLEMd2Menu(21), PLEMd2DuplicateByNum(21)
PLEMd2Menu(22), PLEMd2DuplicateByNum(22)
PLEMd2Menu(23), PLEMd2DuplicateByNum(23)
PLEMd2Menu(24), PLEMd2DuplicateByNum(24)
PLEMd2Menu(25), PLEMd2DuplicateByNum(25)
PLEMd2Menu(26), PLEMd2DuplicateByNum(26)
PLEMd2Menu(27), PLEMd2DuplicateByNum(27)
PLEMd2Menu(28), PLEMd2DuplicateByNum(28)
PLEMd2Menu(29), PLEMd2DuplicateByNum(29)
End
SubMenu "Kill"
PLEMd2Menu(0), PLEMd2KillMapByNum(0)
PLEMd2Menu(1), PLEMd2KillMapByNum(1)
PLEMd2Menu(2), PLEMd2KillMapByNum(2)
PLEMd2Menu(3), PLEMd2KillMapByNum(3)
PLEMd2Menu(4), PLEMd2KillMapByNum(4)
PLEMd2Menu(5), PLEMd2KillMapByNum(5)
PLEMd2Menu(6), PLEMd2KillMapByNum(6)
PLEMd2Menu(7), PLEMd2KillMapByNum(7)
PLEMd2Menu(8), PLEMd2KillMapByNum(8)
PLEMd2Menu(9), PLEMd2KillMapByNum(9)
PLEMd2Menu(10), PLEMd2KillMapByNum(10)
PLEMd2Menu(11), PLEMd2KillMapByNum(11)
PLEMd2Menu(12), PLEMd2KillMapByNum(12)
PLEMd2Menu(13), PLEMd2KillMapByNum(13)
PLEMd2Menu(14), PLEMd2KillMapByNum(14)
PLEMd2Menu(15), PLEMd2KillMapByNum(15)
PLEMd2Menu(16), PLEMd2KillMapByNum(16)
PLEMd2Menu(17), PLEMd2KillMapByNum(17)
PLEMd2Menu(18), PLEMd2KillMapByNum(18)
PLEMd2Menu(19), PLEMd2KillMapByNum(19)
PLEMd2Menu(20), PLEMd2KillMapByNum(20)
PLEMd2Menu(21), PLEMd2KillMapByNum(21)
PLEMd2Menu(22), PLEMd2KillMapByNum(22)
PLEMd2Menu(23), PLEMd2KillMapByNum(23)
PLEMd2Menu(24), PLEMd2KillMapByNum(24)
PLEMd2Menu(25), PLEMd2KillMapByNum(25)
PLEMd2Menu(26), PLEMd2KillMapByNum(26)
PLEMd2Menu(27), PLEMd2KillMapByNum(27)
PLEMd2Menu(28), PLEMd2KillMapByNum(28)
PLEMd2Menu(29), PLEMd2KillMapByNum(29)
End
End
Function/S PLEMd2Menu(numPLEM)
//directory persistent
Variable numPLEM
String strReturn = ""
//dynamic Menus are called every time the menu bar is pressed.
//global Variables should not automatically occur in other projects. so don't create them.
if(PLEMd2isInitialized())
SVAR gstrMapsAvailable = $(cstrPLEMd2root + ":gstrMapsAvailable")
NVAR gnumMapsAvailable = $(cstrPLEMd2root + ":gnumMapsAvailable")
if(numPLEM<gnumMapsAvailable)
strReturn = StringFromList(numPLEM, gstrMapsAvailable)
endif
endif
return strReturn
End
Function/t PLEMd2MenuInit()
if(PLEMd2isInitialized())
return "!" + num2char(18) //on
else
return "" // off
endif
End
Function PLEMd2SetPaths()
PLEMd2SetBasePath()
PLEMd2SetCorrectionPath()
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
StrConstant PLEMd2PackageName = "PLEM-displayer2"
static StrConstant PLEMd2PrefsFileName = "PLEMd2Preferences.bin"
static Constant PLEMd2PrefsRecordID = 0
static Constant reserved = 70 // Reserved uint32 capacity for future use
// Global Preferences stored in Igor Folder
Structure PLEMd2Prefs
uint32 version
double panelCoords[4]
uchar strLastPath[256]
char strBasePath[40]
char strCorrectionPath[80]
uint32 reserved[reserved]
EndStructure
// Sets prefs structure to default values.
static Function PLEMd2DefaultPackagePrefsStruct(prefs)
STRUCT PLEMd2Prefs &prefs
prefs.version = cPLEMd2Version
prefs.panelCoords[0] = 5 // Left
prefs.panelCoords[1] = 40 // Top
prefs.panelCoords[2] = 5+190 // Right
prefs.panelCoords[3] = 40+125 // Bottom
prefs.strLastPath = SpecialDirPath("Documents", 0, 0, 0)
prefs.strBasePath = ""
prefs.strCorrectionPath = ""
Variable i
for(i = 0; i < reserved; i += 1)
prefs.reserved[i] = 0
endfor
End
// SyncPackagePrefsStruct(prefs)
// Syncs package prefs structures to match state of panel. Call this only if the panel exists.
static Function PLEMd2SyncPackagePrefsStruct(prefs)
STRUCT PLEMd2Prefs &prefs
// Panel does exists. Set prefs to match panel settings.
prefs.version = cPLEMd2Version
GetWindow PLEMd2Panel wsize
// NewPanel uses device coordinates. We therefore need to scale from
// points (returned by GetWindow) to device units for windows created
// by NewPanel.
Variable scale = ScreenResolution / 72
prefs.panelCoords[0] = V_left * scale
prefs.panelCoords[1] = V_top * scale
prefs.panelCoords[2] = V_right * scale
prefs.panelCoords[3] = V_bottom * scale
// ControlInfo /W=PLEMd2Panel PhaseLock
// prefs.phaseLock = V_Value // 0=unchecked; 1=checked
End
// InitPackagePrefsStruct(prefs)
// Sets prefs structures to match state of panel or to default values if panel does not exist.
static Function PLEMd2InitPackagePrefsStruct(prefs)
STRUCT PLEMd2Prefs &prefs
DoWindow PLEMd2Panel
if(V_flag == 0)
// Panel does not exist. Set prefs struct to default.
PLEMd2DefaultPackagePrefsStruct(prefs)
else
// Panel does exists. Sync prefs struct to match panel state.
PLEMd2SyncPackagePrefsStruct(prefs)
endif
End
Function PLEMd2LoadPackagePrefs(prefs)
STRUCT PLEMd2Prefs &prefs
// This loads preferences from disk if they exist on disk.
LoadPackagePreferences PLEMd2PackageName, PLEMd2PrefsFileName, PLEMd2PrefsRecordID, prefs
// If error or prefs not found or not valid, initialize them.
if(V_flag!=0 || V_bytesRead==0 || prefs.version!= cPLEMd2Version)
//print "PLEMd2:LoadPackagePrefs: Loading from " + SpecialDirPath("Packages", 0, 0, 0)
PLEMd2InitPackagePrefsStruct(prefs) // Set based on panel if it exists or set to default values.
PLEMd2SavePackagePrefs(prefs) // Create initial prefs record.
endif
End
Function PLEMd2SavePackagePrefs(prefs)
STRUCT PLEMd2Prefs &prefs
//print "PLEMd2:SavePackagePrefs: Saving to " + SpecialDirPath("Packages", 0, 0, 0)
SavePackagePreferences PLEMd2PackageName, PLEMd2PrefsFileName, PLEMd2PrefsRecordID, prefs
End
// Save the location of the base path where all ibw files are saved.
//
// DisplayHelpTopic "Symbolic Paths"
Function PLEMd2SetBasePath()
String strBasePath
Struct PLEMd2Prefs prefs
PLEMd2LoadPackagePrefs(prefs)
strBasePath = prefs.strBasePath
NewPath/O/Q/Z PLEMbasePath, strBasePath
if(!V_flag)
PathInfo/S PLEMbasePath
endif
NewPath/O/Q/Z/M="Set PLEM base path" PLEMbasePath
if(V_flag)
return 0 // user canceled
endif
PathInfo PLEMbasePath
strBasePath = S_path
if(!V_flag)
return 0 // invalid path
endif
GetFileFolderInfo/Q/Z=1 strBasePath
if(!V_flag && V_isFolder)
prefs.strBasePath = strBasePath
PLEMd2SavePackagePrefs(prefs)
endif
End
// Save the location of the base path where all ibw files are saved.
//
// DisplayHelpTopic "Symbolic Paths"
Function PLEMd2SetCorrectionPath()
String strCorrectionPath
Struct PLEMd2Prefs prefs
PLEMd2LoadPackagePrefs(prefs)
strCorrectionPath = prefs.strCorrectionPath
NewPath/O/Q/Z PLEMCorrectionPath, strCorrectionPath
if(!V_flag)
PathInfo/S PLEMCorrectionPath
endif
NewPath/O/Q/Z/M="Set PLEMCorrectionPath path" PLEMCorrectionPath
if(V_flag)
return 0 // user canceled
endif
PathInfo PLEMCorrectionPath
strCorrectionPath = S_path
if(!V_flag)
return 0 // invalid path
endif
GetFileFolderInfo/Q/Z=1 strCorrectionPath
if(!V_flag && V_isFolder)
prefs.strCorrectionPath = strCorrectionPath
PLEMd2SavePackagePrefs(prefs)
endif
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
Constant PLEMd2detectorNewton = 0 // Andor Newton
Constant PLEMd2detectorIdus = 1 // Andor Idus
Constant PLEMd2cameraClara = 2 // Andor Clara
Constant PLEMd2cameraXeva = 3 // Xenics Xeva
//Structure for storing Information about a PLE-Map
Structure PLEMd2stats
//Versioning System to update/create new Global vars.
Variable numVersion
//strPLEM is Name of Map
//strDataFolder is Folder to Main directory
//strDataFolderOriginal is Folder to Processed IBW data Main:ORIGINAL
//numPLEM is number of Map in Menu Entry-List
//wavPLEM is the wave reference to :PLEM
String strPLEM, strDataFolder, strDataFolderOriginal
Variable numPLEM
//2D-Waves
Wave wavPLEM, wavMeasure, wavBackground
//1D-Waves
Wave wavExcitation, wavWavelength
Wave wavYpower, wavYphoton, wavGrating, wavQE, wavFilterExc, wavFilterEmi
// Normalization Value
Variable numNormalization
// Switches for calculation
Variable booBackground, booPower, booPhoton, booGrating, booQuantumEfficiency, booNormalization, booFilter, booTime, booWavelengthPitch
// chirality waves
Wave/D wavAtlasS1nm, wavAtlasS2nm
WAVE/T wavAtlasText
Wave/D wavEnergyS1, wavEnergyS2, wav2Dfit, wav1Dfit, wavFWHMS1, wavFWHMS2
WAVE/T wavChiralityText
Wave wavPLEMfit, wavPLEMfitSingle
// Variables for chirality offset
Variable numS1offset, numS2offset
// calculated variables
Variable numPLEMTotalX, numPLEMLeftX, numPLEMDeltaX
Variable numPLEMTotalY, numPLEMBottomY, numPLEMDeltaY
// nanostage position
variable numPositionX, numPositionY, numPositionZ, booSwitchX, booSwitchY
// image mode information (PLEMv3.3)
variable numReadOutMode, numLaserPositionX, numLaserPositionY, numMagnification, numPixelPitch
// variables from IBW file
// Note: numEmission* is the emission from the excitation source
String strDate, strUser, strFileName
Variable numCalibrationMode, numSlit, numGrating, numFilter, numShutter, numWLcenter, numDetector, numCooling, numExposure, numBinning, numWLfirst, numWLlast, numWLdelta, numEmissionMode, numEmissionPower, numEmissionStart, numEmissionEnd, numEmissionDelta, numEmissionStep, numScans, numBackground
Endstructure
Function PLEMd2statsLoad(stats, strMap)
Struct PLEMd2stats &stats
String strMap
DFREF dfrMap = PLEMd2MapFolder(strMap)
Wave stats.wavPLEM = createWave(dfrMap, "PLEM")
Wave stats.wavPLEMfitSingle = createWave(dfrMap, "PLEMfit")
Wave stats.wavMeasure = createWave(dfrMap, "MEASURE", setWaveType = PLEMd2WaveTypeUnsigned16)
Wave stats.wavBackground = createWave(dfrMap, "BACKGROUND", setWaveType = PLEMd2WaveTypeUnsigned16)
Wave stats.wavExcitation = createWave(dfrMap, "yExcitation")
Wave stats.wavWavelength = createWave(dfrMap, "xWavelength")
Wave stats.wavYpower = createWave(dfrMap, "yPower")
Wave stats.wavYphoton = createWave(dfrMap, "yPhoton")
Wave stats.wavGrating = createWave(dfrMap, "yGrating")
Wave stats.wavQE = createWave(dfrMap, "yQuantum") /// @todo re-calculate qe and grating when needed instead of storing them to save disk space
Wave stats.wavFilterExc = createWave(dfrMap, "yFilter")
Wave stats.wavFilterEmi = createWave(dfrMap, "xFilter")
DFREF dfrAtlas = returnMapChiralityFolder(strMap)
Wave/D stats.wavEnergyS1 = createWave(dfrAtlas, "PLEMs1nm")
Wave/D stats.wavEnergyS2 = createWave(dfrAtlas, "PLEMs2nm")
Wave/T stats.wavChiralityText = createWave(dfrAtlas, "PLEMchirality", setWaveType = PLEMd2WaveTypeText)
Wave/D stats.wavAtlasS1nm = createWave(dfrAtlas, "atlasS1nm")
Wave/D stats.wavAtlasS2nm = createWave(dfrAtlas, "atlasS2nm")
Wave/D stats.wavFWHMS1 = createWave(dfrAtlas, "atlasS1FWHMnm")
Wave/D stats.wavFWHMS2 = createWave(dfrAtlas, "atlasS2FWHMnm")
Wave/T stats.wavAtlasText = createWave(dfrAtlas, "atlasText", setWaveType = PLEMd2WaveTypeText)
Wave/D stats.wav1Dfit = createWave(dfrAtlas, "fit1D")
Wave/D stats.wav2Dfit = createWave(dfrAtlas, "fit2D")
Wave/D stats.wavPLEMfit = createWave(dfrAtlas, "fitPLEM")
// PLEMd2statsInitialize(strMap)
stats.numVersion = getMapVariable(strMap, "gnumVersion")
stats.numPLEM = getMapVariable(strMap, "gnumPLEM")
stats.strPLEM = getMapString(strMap, "gstrPLEM") // no magic here
stats.strDataFolder = getMapString(strMap, "gstrDataFolder")
stats.strDataFolderOriginal = getMapString(strMap, "gstrDataFolderOriginal")
stats.numNormalization = getMapVariable(strMap, "gnumNormalization")
stats.numNormalization = SelectNumber(stats.numNormalization != 0, 1, stats.numNormalization)
stats.booBackground = getMapVariable(strMap, "gbooBackground")
stats.booPower = getMapVariable(strMap, "gbooPower")
stats.booPhoton = getMapVariable(strMap, "gbooPhoton")
stats.booGrating = getMapVariable(strMap, "gbooGrating")
stats.booQuantumEfficiency = getMapVariable(strMap, "gbooQuantumEfficiency")
stats.booNormalization = getMapVariable(strMap, "gbooNormalization")
stats.booFilter = getMapVariable(strMap, "gbooFilter")
stats.booTime = getMapVariable(strMap, "gbooTime")
stats.booWavelengthPitch = getMapVariable(strMap, "gbooWavelengthPitch")
stats.numS1offset = getMapVariable(strMap, "gnumS1offset")
stats.numS2offset = getMapVariable(strMap, "gnumS2offset")
stats.numPLEMTotalX = getMapVariable(strMap, "gnumPLEMTotalX")
stats.numPLEMLeftX = getMapVariable(strMap, "gnumPLEMLeftX")
stats.numPLEMDeltaX = getMapVariable(strMap, "gnumPLEMDeltaX")
stats.numPLEMTotalY = getMapVariable(strMap, "gnumPLEMTotalY")
stats.numPLEMBottomY = getMapVariable(strMap, "gnumPLEMBottomY")
stats.numPLEMDeltaY = getMapVariable(strMap, "gnumPLEMDeltaY")
stats.strDate = getMapString(strMap, "gstrDate")
stats.strUser = getMapString(strMap, "gstrUser")
stats.strFileName = getMapString(strMap, "gstrFileName")
stats.numCalibrationMode = getMapVariable(strMap, "gnumCalibrationMode")
stats.numSlit = getMapVariable(strMap, "gnumSlit")
stats.numGrating = getMapVariable(strMap, "gnumGrating")
stats.numFilter = getMapVariable(strMap, "gnumFilter")
stats.numShutter = getMapVariable(strMap, "gnumShutter")
stats.numWLcenter = getMapVariable(strMap, "gnumWLcenter")
stats.numDetector = getMapVariable(strMap, "gnumDetector")
stats.numCooling = getMapVariable(strMap, "gnumCooling")
stats.numExposure = getMapVariable(strMap, "gnumExposure")
stats.numBinning = getMapVariable(strMap, "gnumBinning")
stats.numWLfirst = getMapVariable(strMap, "gnumWLfirst")
stats.numWLlast = getMapVariable(strMap, "gnumWLlast")
stats.numWLdelta = getMapVariable(strMap, "gnumWLdelta")
stats.numEmissionMode = getMapVariable(strMap, "gnumEmissionMode")
stats.numEmissionPower = getMapVariable(strMap, "gnumEmissionPower")
stats.numEmissionStart = getMapVariable(strMap, "gnumEmissionStart")
stats.numEmissionEnd = getMapVariable(strMap, "gnumEmissionEnd")
stats.numEmissionDelta = getMapVariable(strMap, "gnumEmissionDelta")
stats.numEmissionStep = getMapVariable(strMap, "gnumEmissionStep")
stats.numScans = getMapVariable(strMap, "gnumScans")
stats.numBackground = getMapVariable(strMap, "gnumBackground")
stats.numPositionX = getMapVariable(strMap, "gnumPositionX")
stats.numPositionY = getMapVariable(strMap, "gnumPositionY")
stats.numPositionZ = getMapVariable(strMap, "gnumPositionZ")
stats.booSwitchX = getMapVariable(strMap, "gbooSwitchX")
stats.booSwitchY = getMapVariable(strMap, "gbooSwitchY")
stats.numReadOutMode = getMapVariable(strMap, "gnumReadOutMode")
stats.numLaserPositionX = getMapVariable(strMap, "gnumLaserPositionX")
stats.numLaserPositionY = getMapVariable(strMap, "gnumLaserPositionY")
stats.numMagnification = getMapVariable(strMap, "gnumMagnification")
stats.numPixelPitch = getMapVariable(strMap, "gnumPixelPitch")
End
Function PLEMd2statsSave(stats)
Struct PLEMd2stats &stats
String strMap = stats.strPLEM
setMapVariable(strMap, "gnumVersion", stats.numVersion)
setMapVariable(strMap, "gnumPLEM", stats.numPLEM)
setMapString(strMap, "gstrPLEM", stats.strPLEM)
setMapString(strMap, "gstrDataFolder", stats.strDataFolder)
setMapString(strMap, "gstrDataFolderOriginal", stats.strDataFolderOriginal)
setMapVariable(strMap, "gnumNormalization", stats.numNormalization)
setMapVariable(strMap, "gbooBackground", stats.booBackground)
setMapVariable(strMap, "gbooPower", stats.booPower)
setMapVariable(strMap, "gbooPhoton", stats.booPhoton)
setMapVariable(strMap, "gbooGrating", stats.booGrating)
setMapVariable(strMap, "gbooQuantumEfficiency", stats.booQuantumEfficiency)
setMapVariable(strMap, "gbooNormalization", stats.booNormalization)
setMapVariable(strMap, "gbooFilter", stats.booFilter)
setMapVariable(strMap, "gbooTime", stats.booTime)
setMapVariable(strMap, "gbooWavelengthPitch", stats.booWavelengthPitch)
setMapVariable(strMap, "gnumS1offset", stats.numS1offset)
setMapVariable(strMap, "gnumS2offset", stats.numS2offset)
setMapVariable(strMap, "gnumPLEMTotalX", stats.numPLEMTotalX)
setMapVariable(strMap, "gnumPLEMLeftX", stats.numPLEMLeftX)
setMapVariable(strMap, "gnumPLEMDeltaX", stats.numPLEMDeltaX)
setMapVariable(strMap, "gnumPLEMTotalY", stats.numPLEMTotalY)
setMapVariable(strMap, "gnumPLEMBottomY ", stats.numPLEMBottomY)
setMapVariable(strMap, "gnumPLEMDeltaY", stats.numPLEMDeltaY)
setMapString(strMap, "gstrDate", stats.strDate)
setMapString(strMap, "gstrUser", stats.strUser)
setMapString(strMap, "gstrFileName", stats.strFileName)
setMapVariable(strMap, "gnumCalibrationMode", stats.numCalibrationMode)
setMapVariable(strMap, "gnumSlit", stats.numSlit)
setMapVariable(strMap, "gnumGrating", stats.numGrating)
setMapVariable(strMap, "gnumFilter", stats.numFilter)
setMapVariable(strMap, "gnumShutter", stats.numShutter)
setMapVariable(strMap, "gnumWLcenter", stats.numWLcenter)
setMapVariable(strMap, "gnumDetector", stats.numDetector)
setMapVariable(strMap, "gnumCooling", stats.numCooling)
setMapVariable(strMap, "gnumExposure", stats.numExposure)
setMapVariable(strMap, "gnumBinning", stats.numBinning)
setMapVariable(strMap, "gnumScans", stats.numScans)
setMapVariable(strMap, "gnumBackground", stats.numBackground)
setMapVariable(strMap, "gnumWLfirst", stats.numWLfirst)
setMapVariable(strMap, "gnumWLlast", stats.numWLlast)
setMapVariable(strMap, "gnumWLdelta", stats.numWLdelta)
setMapVariable(strMap, "gnumEmissionMode", stats.numEmissionMode)
setMapVariable(strMap, "gnumEmissionPower", stats.numEmissionPower)
setMapVariable(strMap, "gnumEmissionStart", stats.numEmissionStart)
setMapVariable(strMap, "gnumEmissionEnd", stats.numEmissionEnd)
setMapVariable(strMap, "gnumEmissionDelta", stats.numEmissionDelta)
setMapVariable(strMap, "gnumEmissionStep", stats.numEmissionStep)
setMapVariable(strMap, "gnumPositionX", stats.numPositionX)
setMapVariable(strMap, "gnumPositionY", stats.numPositionY)
setMapVariable(strMap, "gnumPositionZ", stats.numPositionZ)
setMapVariable(strMap, "gbooSwitchX", stats.booSwitchX)
setMapVariable(strMap, "gbooSwitchY", stats.booSwitchY)
setMapVariable(strMap, "gnumReadOutMode", stats.numReadOutMode)
setMapVariable(strMap, "gnumLaserPositionX", stats.numLaserPositionX)
setMapVariable(strMap, "gnumLaserPositionY", stats.numLaserPositionY)
setMapVariable(strMap, "gnumMagnification", stats.numMagnification)
setMapVariable(strMap, "gnumPixelPitch", stats.numPixelPitch)
End
Function PLEMd2statsInitialize(strMap)
//Initialize the stats struct without calling the load procedure
//**on Version-Missmatch
//**if Folder INFO is not there.
String strMap
Struct PLEMd2Stats stats
if(!PLEMd2isInitialized())
Abort "PLEMd2statsInitialize: PLEMd2 is not initialized."
endif
PLEMd2statsLoad(stats, strMap)
stats.numPLEM = PLEMd2AddMap(strMap)
stats.strPLEM = strMap
stats.strDataFolder = GetDataFolder(1, PLEMd2MapFolder(strMap))
stats.numVersion = cPLEMd2Version
stats.numNormalization = 1
stats.booBackground = 1
stats.booPower = 0
stats.booPhoton = 1
stats.booGrating = 1
stats.booQuantumEfficiency = 1
stats.booNormalization = 0
stats.booFilter = 1
stats.booTime = 1
stats.booWavelengthPitch = 1
PLEMd2statsSave(stats)
End
Function/S PLEMd2FullPathByString(strPLEM)
String strPLEM
String fullPath
DFREF packageRoot = $cstrPLEMd2root
SVAR/Z mapsFolder = packageRoot:gstrMapsFolder
if(!SVAR_EXISTS(mapsFolder))
Abort "Function can not return proper results if SVAR is missing"
endif
fullPath = ParseFilePath(2, mapsFolder, ":", 0, 0)
fullPath += strPLEM + ":PLEM"
return fullPath
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
#include "utilities-peakfind"
static StrConstant cstrPLEMd2maps = ":maps"
static StrConstant cstrPLEMd2info = ":INFO"
static StrConstant cstrPLEMd2chirality = ":CHIRALITY"
static StrConstant cstrPLEMd2originals = ":ORIGINAL"
static StrConstant cstrPLEMd2windowPrefix = ""
static StrConstant cstrPLEMd2windowSuffix = "_graph"
Function/S PLEMd2getWindow(strPLEM)
String strPLEM
return cstrPLEMd2windowPrefix + strPLEM + cstrPLEMd2windowSuffix
End
Function/S PLEMd2window2strPLEM(strWindow)
String strWindow
Variable numStart, numEnd
numStart = strlen(cstrPLEMd2windowPrefix) > 0 ? strsearch(strWindow, cstrPLEMd2windowPrefix, 0) : 0
numEnd = strlen(cstrPLEMd2windowSuffix) > 0 ? strsearch(strWindow, cstrPLEMd2windowSuffix, 0) : strsearch(strWindow, "#", 0)
if(numEnd == -1 && numStart == -1)
return strWindow
elseif(numEnd == -1 && numStart != -1)
return strWindow[numStart,inf]
else
return strWindow[numStart,numEnd-1]
endif
End
Function/DF DataFolderReference(dataFolderNameStr)
String dataFolderNameStr
if(!DataFolderExists(dataFolderNameStr))
NewDataFolder/O $dataFolderNameStr // can only create one level
endif
DFREF dfr = $dataFolderNameStr
return dfr
End
// Function returns DataFolder reference to package root.
static Function/DF returnPackageRoot()
DFREF dfrPackage = DataFolderReference(cstrPLEMd2root)
return dfrPackage
End
// Function returns DataFolder reference to base directory where maps are stored
Function/DF PLEMd2MapsFolder()
DFREF dfrPackage = returnPackageRoot()
DFREF dfrMaps = DataFolderReference(cstrPLEMd2root + cstrPLEMd2maps)
return dfrMaps
End
// Function returns DataFolder reference to base directory of map specified by strMap
Function/DF PLEMd2MapFolder(strMap)
String strMap
if(strlen(strMap) == 0)
Abort "Need a valid Map String"
endif
DFREF dfrMaps = PLEMd2MapsFolder()
DFREF dfrMap = dfrMaps:$strMap
return dfrMap
End
// Function returns DataFolder reference to current map's info folder where NVAR and SVAR are saved
static Function/DF returnMapInfoFolder(strMap)
String strMap
if(strlen(strMap) == 0)
Abort "Need a valid Map String"
endif
DFREF dfrMap = PLEMd2MapFolder(strMap)
DFREF dfrInfo = DataFolderReference(cstrPLEMd2root + cstrPLEMd2maps + ":" + strMap + cstrPLEMd2info)
return dfrInfo
End
// Function returns DataFolder reference to current map's info folder where NVAR and SVAR are saved
Function/DF returnMapChiralityFolder(strMap)
String strMap
DFREF dfrMap = PLEMd2MapFolder(strMap)
DFREF dfrChirality = DataFolderReference(cstrPLEMd2root + cstrPLEMd2maps + ":" + strMap + cstrPLEMd2chirality)
return dfrChirality
End
// Function returns value of Global String "name" in "dataFolder"
static Function/S getGstring(name, dataFolder)
String name
DFREF dataFolder
SVAR/Z/SDFR=dataFolder myVar = $name
if(!SVAR_EXISTS(myVar))
String/G dataFolder:$name = ""
return ""
else
return myVar
endif
End
// Function returns value of Global (numeric) Variable "name" in "dataFolder"
static Function getGvar(name, dataFolder)
String name
DFREF dataFolder
NVAR/Z/SDFR=dataFolder myVar = $name
if(!NVAR_EXISTS(myVar))
Variable/G dataFolder:$name = NaN
return NaN
else
return myVar
endif
End
// Wrapper Functions for creating Waves
Constant PLEMd2WaveTypeDouble = 0
Constant PLEMd2WaveTypeUnsigned32 = 1
Constant PLEMd2WaveTypeUnsigned16 = 2
Constant PLEMd2WaveTypeText = 3
Function/WAVE createWave(dfr, strWave, [setWaveType])
DFREF dfr
String strWave
Variable setWaveType
setWaveType = ParamIsDefault(setWaveType) ? PLEMd2WaveTypeDouble : setWaveType
WAVE/Z/SDFR=dfr wv = $strWave
if(WaveExists(wv))
return wv
endif
switch(setWaveType)
case PLEMd2WaveTypeDouble:
WAVE wv = createDoubleWave(dfr, strWave)
break
case PLEMd2WaveTypeUnsigned32:
WAVE wv = createUnsigned32Wave(dfr, strWave)
break
case PLEMd2WaveTypeUnsigned16:
WAVE wv = createUnsigned16Wave(dfr, strWave)
break
case PLEMd2WaveTypeText:
WAVE wv = createTextWave(dfr, strWave)
break
default:
WAVE wv = createDoubleWave(dfr, strWave)
endswitch
return wv
End
static Function/WAVE createDoubleWave(dfr, strWave)
DFREF dfr
String strWave
Make/D/N=0 dfr:$strWave/WAVE=wv
return wv
End
// 32bit unsigned wave
static Function/WAVE createUnsigned32Wave(dfr, strWave)
DFREF dfr
String strWave
Make/I/U/N=0 dfr:$strWave/WAVE=wv
return wv
End
// 16bit unsigned wave
static Function/WAVE createUnsigned16Wave(dfr, strWave)
DFREF dfr
String strWave
Make/W/U/N=0 dfr:$strWave/WAVE=wv
return wv
End
static Function/WAVE createTextWave(dfr, strWave)
DFREF dfr
String strWave
Make/T/N=0 dfr:$strWave/WAVE=wv
return wv
End
// Function sets Global String "name" in "dataFolder" to "value"
static Function setGstring(name, value, dataFolder)
String name, value
DFREF dataFolder
SVAR/Z/SDFR=dataFolder myVar = $name
if(!SVAR_EXISTS(myVar))
String/G dataFolder:$name
SVAR/Z/SDFR=dataFolder myVar = $name
if(!SVAR_EXISTS(myVar))
Abort "Could not create global String"
endif
endif
myVar = value
End
// Function sets Global Variable "name" in "dataFolder" to "value"
static Function setGvar(name, value, dataFolder)
String name
Variable value
DFREF dataFolder
NVAR/Z/SDFR=dataFolder myVar = $name
if(!NVAR_EXISTS(myVar))
Variable/G dataFolder:$name
NVAR/Z/SDFR=dataFolder myVar = $name
if(!NVAR_EXISTS(myVar))
Abort "Could not create global Variable"
endif
endif
myVar = value
End
// Abbreviated Functions for returning Variables from Package root.
Function/S getPackageString(name)
String name
DFREF dfrPackage = returnPackageRoot()
return getGstring(name, dfrPackage)
End
Function getPackageVariable(name)
String name
DFREF dfrPackage = returnPackageRoot()
return getGvar(name, dfrPackage)
End
Function setPackageString(name, value)
String name, value
DFREF dfrPackage = returnPackageRoot()
setGstring(name, value, dfrPackage)
End
Function setPackageVariable(name, value)
String name
Variable value
DFREF dfrPackage = returnPackageRoot()
setGvar(name, value, dfrPackage)
End
// Abbreviated Functions for returning Variables from current map.
Function/S getMapString(strMap, var)
String strMap, var
DFREF dfrInfo = returnMapInfoFolder(strMap)
return getGstring(var, dfrInfo)
End
Function getMapVariable(strMap, var)
String strMap, var
DFREF dfrInfo = returnMapInfoFolder(strMap)
return getGvar(var, dfrInfo)
End
Function setMapString(strMap, var, value)
String strMap, var, value
DFREF dfrInfo = returnMapInfoFolder(strMap)
setGstring(var, value, dfrInfo)
End
Function setMapVariable(strMap, var, value)
String strMap, var
Variable value
DFREF dfrInfo = returnMapInfoFolder(strMap)
setGvar(var, value, dfrInfo)
End
// Abbreviated Functions for returning Variables from CHIRALITY FOLDER
Function/S getAtlasString(strMap, var)
String strMap, var
DFREF dfrInfo = returnMapInfoFolder(strMap)
return getGstring(var, dfrInfo)
End
Function getAtlasVariable(strMap, var)
String strMap, var
DFREF dfrAtlas = returnMapChiralityFolder(strMap)
return getGvar(var, dfrAtlas)
End
Function setAtlasString(strMap, var, value)
String strMap, var, value
DFREF dfrAtlas = returnMapChiralityFolder(strMap)
setGstring(var, value, dfrAtlas)
End
Function setAtlasVariable(strMap, var, value)
String strMap, var
Variable value
DFREF dfrAtlas = returnMapChiralityFolder(strMap)
setGvar(var, value, dfrAtlas)
End
Function/WAVE PLEMd2wavIBW(strPLEM)
String strPLEM
DFREF dfr = PLEMd2MapFolder(strPLEM)
WAVE/Z wv = dfr:IBW
return wv
End
// @brief get the wave from the given datafolder
Function/WAVE PLEMd2getWaveFromDFR(dfr)
DFREF dfr
if(DataFolderRefStatus(dfr) == 0)
return $""
endif
if(CountObjectsDFR(dfr, 1) != 1)
Abort "no or more than one wave in map's DataFolder!"
endif
return dfr:$GetIndexedObjNameDFR(dfr, 1, 0)
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
#include <Graph Utility Procs>
Function PLEMd2Display(strPLEM)
String strPLEM
Struct PLEMd2Stats stats
String winPLEM
PLEMd2statsLoad(stats, strPLEM)
// check if spectrum is a valid input
if(strlen(stats.strPLEM) == 0)
print "PLEMd2Display: Error stats.strPLEM not set for Map: " + strPLEM + " check code"
return 0
endif
if(!WaveExists(stats.wavPLEM))
print "PLEMd2Display: Wave Not Found"
return 0
endif
// check if window already exists
winPLEM = PLEMd2getWindow(stats.strPLEM)
DoWindow/F $winPLEM
// DoWindow sets the variable V_flag:
// 1 window existed
// 0 no such window
// 2 window is hidden.
if(V_flag == 1)
CheckDisplayed/W=$winPLEM stats.wavPLEM
if(V_Flag)
print stats.strPLEM, "window found"
endif
return 0
elseif(V_flag == 2)
print "PLEMd2Display: Graph was hidden. Case not handled. check code"
elseif(V_flag == 0)
Display
DoWindow/C/N/R $winPLEM
if((stats.numCalibrationMode == 1) && (stats.numReadOutMode != 1))
AppendToGraph stats.wavPLEM vs stats.wavWavelength
ModifyGraph/W=$winPLEM standoff=0
SetAxis/W=$winPLEM/A left
Label/W=$winPLEM left "intensity / a.u."
Label/W=$winPLEM bottom "wavelength / nm (Excitation at "+num2str(stats.numEmissionStart)+"-"+num2str(stats.numEmissionEnd)+")"
else
//AppendImage stats.wavPLEM vs {stats.wavWavelength, stats.wavExcitation}
AppendImage stats.wavPLEM
PLEMd2Decorate(strWinPLEM = winPLEM, booImage = (stats.numReadOutMode == 1))
endif
endif
End
Function PLEMd2DisplayByNum(numPLEM)
Variable numPLEM
if(numPLEM < 0)
print "PLEMd2DisplayByNum: Wrong Function Call numPLEM out of range"
return 0
endif
String strPLEM
strPLEM = PLEMd2strPLEM(numPLEM)
PLEMd2Display(strPLEM)
End
Function PLEMd2Decorate([strWinPLEM, booImage])
String strWinPLEM
Variable booImage
Variable numZmin, numZmax
Variable numXmin, numXmax
Variable numYmin, numYmax
String strImages
// if no argument was selected, take top graph window
if(ParamIsDefault(strWinPLEM))
strWinPLEM = WinName(0, 1, 1)
endif
if(ParamIsDefault(booImage))
booImage = 0
endif
if(strlen(strWinPLEM) == 0)
Print "PLEMd2Decorate: No window to append to"
return 0
endif
// get the image name and wave reference.
strImages = ImageNameList(strWinPLEM, ";")
if(ItemsInList(strImages) != 1)
Print "PLEMd2Decorate: No Image found in top graph or More than one Image present"
endif
wave wavImage = ImageNameToWaveRef(strWinPLEM,StringFromList(0,strImages))
// get min and max of wave (statistically corrected)
WaveStats/Q/W wavImage
wave M_WaveStats
numZmin = M_WaveStats[10] //minimum
numZmin = M_WaveStats[3]-sign(M_WaveStats[3])*2*M_WaveStats[4] //statistical minimum
if(numZmin<0)
numZmin = 0
endif
numZmax = M_WaveStats[12] //maximum
//Images start a little earlier as the minimum due to the quadratic size of a pixel.
numYmin = DimOffset(wavImage,1) + sign(DimOffset(wavImage,1)) * (-1) * DimDelta(wavImage,1)/2
numYmax = DimOffset(wavImage,1) + DimDelta(wavImage,1)*(DimSize(wavImage,1)-1) + sign(DimOffset(wavImage,1)) * (+1) * DimDelta(wavImage,1)/2
numXmin = DimOffset(wavImage,0) + sign(DimOffset(wavImage,0)) * (-1) * DimDelta(wavImage,0)/2
numXmax = DimOffset(wavImage,0) + DimDelta(wavImage,0)*(DimSize(wavImage,0)-1) + sign(DimOffset(wavImage,0)) * (+1) * DimDelta(wavImage,0)/2
Killwaves/Z M_Wavestats
ModifyImage/W=$strWinPLEM ''#0 ctab= {numZmin,numZmax,Terrain256,0}
ModifyImage/W=$strWinPLEM ''#0 ctab= {*,*,Terrain256,0}
ModifyGraph/W=$strWinPLEM standoff=0
ModifyGraph/W=$strWinPLEM height={Aspect,((numYmax-numYmin)/(numXmax-numXmin))}
ModifyGraph/W=$strWinPLEM height = 0
SetAxis/W=$strWinPLEM left,numYmin, numYmax
SetAxis/W=$strWinPLEM/A left
SetAxis/W=$strWinPLEM bottom,numXmin,numXmax
SetAxis/W=$strWinPLEM/A bottom
if(booImage)
ModifyGraph zero=1
Label/W=$strWinPLEM left "position / µm"
Label/W=$strWinPLEM bottom "position / µm"
else
Label/W=$strWinPLEM left "excitation / nm"
Label/W=$strWinPLEM bottom "emission / nm"
endif
ModifyGraph width={Plan,1,bottom,left}
End
Function PLEMd2ShowNote([strWinPLEM])
String strWinPLEM
String strWinPLEMbase, strPLEM
String strImages, strTraces, strDataFolderMap, strDataFolderInfo
Struct PLEMd2Stats stats
// if no argument was selected, take top graph window
if(ParamIsDefault(strWinPLEM))
strWinPLEM = WinName(0, 1, 1)
endif
if(strlen(strWinPLEM) == 0)
Print "PLEMd2ShowNote: base window not found"
return 0
endif
// take parent window
strWinPLEMbase = strWinPLEM[0,(strsearch(strWinPLEM, "#",0)-1)]
// if the panel is already shown, do nothing
DoUpdate /W=$strWinPLEMbase#PLEMd2WaveNote
if(V_flag != 0)
Print "PLEMd2ShowNote: Panel already exists."
return 0
endif
// get the image name and wave reference.
strPLEM = PLEMd2window2strPLEM(strWinPLEMbase)
PLEMd2statsLoad(stats, strPLEM)
wave wavPLEM = stats.wavPLEM
CheckDisplayed wavPLEM
if( V_Flag != 1 )
print "PLEMd2ShowNote: wrong panel. wave not found"
endif
// display Note
String strWavenote = note(wavPLEM)
NewPanel /N=PLEMd2WaveNote/W=(0,0,300,400) /EXT=0 /HOST=$strWinPLEMbase
NewNotebook/F=0 /N=Note /W=(0,0,300,400) /HOST=$(strWinPLEMbase + "#PLEMd2WaveNote") as ("wavenote " + GetWavesDataFolder(wavPLEM,2))
Notebook # text=strWavenote
//TitleBox/Z gstrPLEMfull title=strWavenote, pos={10,10}, size={50,50}, frame=0, font="Helvetica"
End
Function PLEMd2Panel([strWinPLEM])
String strWinPLEM
String strImages, strTraces, strDataFolderMap, strDataFolderInfo
// if no argument was selected, take top graph window
if(ParamIsDefault(strWinPLEM))
strWinPLEM = WinName(0, 1, 1)
endif
DoWindow $strWinPLEM
if(V_flag != 1)
Abort "PLEMd2Panel: No window to append to"
endif
// if the panel is already shown, do nothing
DoUpdate/W=$strWinPLEM#PLEMd2Panel
if(V_flag != 0)
Print "PLEMd2Panel: Panel already exists."
return 0
endif
// get INFO folder (method only works if one trace is present)
WAVE wavPLEM = getTopWindowWave()
strDataFolderMap = GetWavesDataFolder(wavPLEM, 1)
strDataFolderInfo = strDataFolderMap + "INFO:"
if(DataFolderExists(strDataFolderInfo) == 0)
Print "PLEMd2Panel: INFO Data Folder for Image in top graph not found."
return 0
endif
// build panel
NewPanel /N=PLEMd2Panel/W=(0,0,300,250) /EXT=0 /HOST=$strWinPLEM
TitleBox/Z gstrPLEMfull variable=$(strDataFolderInfo + "gstrPLEMfull"), pos={0,0}, size={130,0}, disable=0, frame=0, font="Helvetica"
SetVariable normalization, value=$(strDataFolderInfo + "gnumNormalization"), pos={150,80}, title="normalization", size={130,0}, proc=SetVarProcCalculate
SetVariable delatX, value=$(strDataFolderInfo + "gnumPLEMDeltaX"), pos={150,100}, title="deltaX", size={130,0}, noedit=1
CheckBox boxBackground variable=$(strDataFolderInfo + "gbooBackground"), pos={10,20}, title="background", proc=CheckProcCalculate
CheckBox boxPower variable=$(strDataFolderInfo + "gbooPower"), pos={10,40}, title="power", proc=CheckProcCalculate
CheckBox boxPhoton variable=$(strDataFolderInfo + "gbooPhoton"), pos={10,60}, title="photon", proc=CheckProcCalculate
CheckBox boxGrating variable=$(strDataFolderInfo + "gbooGrating"), pos={10,120}, title="grating", proc=CheckProcCalculate
CheckBox boxQuantumEfficiency variable=$(strDataFolderInfo + "gbooQuantumEfficiency"), pos={10,160}, title="detector", proc=CheckProcCalculate
CheckBox boxNormalization variable=$(strDataFolderInfo + "gbooNormalization"), pos={10,80}, title="normalization", proc=CheckProcCalculate
CheckBox boxFilter variable=$(strDataFolderInfo + "gbooFilter"), pos={10,140}, title="filter", proc=CheckProcCalculate
CheckBox boxWLdelta variable=$(strDataFolderInfo + "gbooWavelengthPitch"), pos={10,100}, title="cts/nm", proc=CheckProcCalculate
CheckBox boxTime variable=$(strDataFolderInfo + "gbooTime"), pos={10,180}, title="cts/s", proc=CheckProcCalculate
Button ProcessIBW, pos={150, 30}, size={130,30}, proc=ButtonProcProcessIBW,title="reset"
Button ShowNote, pos={150, 140}, size={130,30}, proc=ButtonProcShowNote,title="WaveNote"
DoWindow PLEMd2Panel
End
Function PLEMd2PanelAtlas([strWinPLEM])
String strWinPLEM
String strImages, strTraces, strDataFolderMap, strDataFolderInfo
// if no argument was selected, take top graph window
if(ParamIsDefault(strWinPLEM))
strWinPLEM = WinName(0, 1, 1)
endif
if(strlen(strWinPLEM) == 0)
Print "PLEMd2Atlas: No window to append to"
return 0
endif
// if the panel is already shown, do nothing
DoUpdate /W=$strWinPLEM#PLEMd2PanelAtlas
if(V_flag != 0)
Print "PLEMd2Atlas: Panel already exists."
endif
// get the image name and wave reference.
strImages = ImageNameList(strWinPLEM, ";")
if(ItemsInList(strImages) == 0)
strTraces = TraceNameList(strWinPLEM, ";",1)
if(ItemsInList(strTraces) == 1)
wave wavPLEM = TraceNameToWaveRef(strWinPLEM,StringFromList(0,strTraces))
Print "PLEMd2Atlas: Traces are experimental"
else
Print "PLEMd2Atlas: No Image found. More than one or no trace found in top graph."
return 0
endif
elseif(ItemsInList(strImages) > 1)
Print "PLEMd2Atlas: More than one image found in top graph."
return 0
else
wave wavPLEM = ImageNameToWaveRef(strWinPLEM,StringFromList(0,strImages))
endif
// check for INFO folder
strDataFolderMap = GetWavesDataFolder(wavPLEM,1)
strDataFolderInfo = strDataFolderMap + "INFO:"
if(DataFolderExists(strDataFolderInfo) == 0)
Print "PLEMd2Panel: INFO Data Folder for Image in top graph not found."
return 0
endif
NewPanel /N=PLEMd2PanelAtlas/W=(0,0,300,100) /EXT=2 /HOST=$strWinPLEM
SetVariable gnumS1offset, proc=VariableProcAtlasRecalculate, value=$(strDataFolderInfo + "gnumS1offset"), pos={10,10}, size={130,0}
SetVariable gnumS2offset, proc=VariableProcAtlasRecalculate, value=$(strDataFolderInfo + "gnumS2offset"), pos={10,30}, size={130,0}
Button AtlasReset, proc=ButtonProcAtlasReset, title="reset", pos={10, 50}, size={50,25}
Button AtlasShow, proc=ButtonProcAtlasShow, title="show", pos={150, 10}, size={50,25}
Button AtlasHide, proc=ButtonProcAtlasHide, title="hide", pos={150, 40}, size={50,25}
Button AtlasFit3D, proc=ButtonProcAtlasFit3D, title="fit3D", pos={200, 10}, size={50,25}
Button AtlasFit2D, proc=ButtonProcAtlasFit2D, title="fit2D", pos={200, 40}, size={50,25}
Button AtlasFit1D, proc=ButtonProcAtlasFit1D, title="fit1D", pos={200, 40}, size={50,25}
Button AtlasEdit, proc=ButtonProcAtlasEdit, title="edit", pos={250, 10}, size={50,25}
Button AtlasClean, proc=ButtonProcAtlasClean, title="clean", pos={250, 40}, size={50,25}
//gnumPLEM;gnumVersion;gstrPLEM;gstrPLEMfull;gstrDataFolder;gstrDataFolderOriginal;gstrDate;gstrUser;gstrFileName;
//gnumPLEMTotalX;gnumPLEMLeftX;gnumPLEMDeltaX;gnumPLEMRightX;gnumPLEMTotalY;gnumPLEMBottomY;gnumPLEMDeltaY;gnumPLEMTopY;gnumCalibrationMode;
//gnumBackground; gnumSlit;gnumGrating;gnumFilter;
//gnumShutter;gnumWLcenter;gnumDetector;gnumCooling;gnumExposure;gnumBinning;gnumScans;gnumWLfirst;gnumWLlast;gnumWLdelta;
//gnumEmissionMode;gnumEmissionPower;gnumEmissionStart;gnumEmissionEnd;gnumEmissionDelta;gnumEmissionStep;
DoWindow PLEMd2PanelAtlas
End
Function ButtonProcAtlasShow(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2AtlasShow(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcAtlasHide(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2AtlasHide(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcAtlasReset(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2AtlasInit(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function VariableProcAtlasRecalculate(sva) : SetVariableControl
STRUCT WMSetVariableAction &sva
switch( sva.eventCode )
case 1: // mouse up
case 2: // Enter key
case 3: // Live update
Variable dval = sva.dval
String sval = sva.sval
String strPLEM
strPLEM = PLEMd2window2strPLEM(sva.win)
PLEMd2AtlasRecalculate(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcAtlasFit3D(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2AtlasFit3D(strPLEM, show = 1)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcAtlasFit1D(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2AtlasFit2D(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcAtlasEdit(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2AtlasEdit(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcAtlasClean(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2AtlasClean(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcProcessIBW(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2BuildMaps(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcShowNote(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
//String strPLEM
//strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2ShowNote(strWinPLEM=ba.win)
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcBuildMaps(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String strPLEM
strPLEM = PLEMd2window2strPLEM(ba.win)
PLEMd2BuildMaps(strPLEM)
break
case -1: // control being killed
break
endswitch
return 0
End
Function CheckProcCalculate(cba) : CheckBoxControl
STRUCT WMCheckboxAction &cba
String strPLEM
Variable mini, maxi
switch( cba.eventCode )
case 2: // mouse up
Variable checked = cba.checked
PLEMd2GetGraphMinMax(cba.win, mini, maxi)
strPLEM = PLEMd2window2strPLEM(cba.win)
PLEMd2BuildMaps(strPLEM)
PLEMd2SetGraphMinMax(cba.win, mini, maxi)
break
case -1: // control being killed
break
endswitch
return 0
End
// @brief get the minimum and maximum scaling of the wave in the displayed range in percent
static Function PLEMd2GetGraphMinMax(win, mini, maxi)
String win
Variable &mini, &maxi
Variable Ymin, Ymax
Variable Pmin, Pmax, Qmin, Qmax, Zmin, Zmax
string info
String strPLEM = PLEMd2window2strPLEM(win)
Struct PLEMd2stats stats
PLEMd2statsload(stats, strPLEM)
WAVE PLEM = stats.wavPLEM
GetAxis/Q bottom
if(!!V_flag)
print "SMAdisplayOriginal: Error getting bottom axis in top Graph"
return -1
endif
Pmin = ScaleToIndex(PLEM, V_min, 0)
Pmax = ScaleToIndex(PLEM, V_max, 0)
GetAxis/Q left
if(!!V_flag)
print "SMAdisplayOriginal: Error getting bottom axis in top Graph"
return -1
endif
Ymin = V_min
Ymax = V_max
if(DimSize(PLEM, 1) > 1) // map
Qmin = ScaleToIndex(PLEM, Ymin, 1)
Qmax = ScaleToIndex(PLEM, Ymax, 1)
info = WMGetRECREATIONFromInfo(ImageInfo(StringFromList(0, win, "#"), "PLEM", 0))
info = info[strsearch(info, "{", 0) + 1, strsearch(info, "}", 0) - 1]
Zmin = str2num(StringFromList(0, info, ","))
Zmax = str2num(StringFromList(1, info, ","))
Duplicate/FREE/R=[Pmin, Pmax][Qmin, Qmax] PLEM temp
else
Duplicate/FREE/R=[Pmin, Pmax] PLEM temp
endif
WaveStats/Q/M=1 temp
mini = (Zmin - V_min) / (V_max - V_min)
maxi = (Zmax - V_min) / (V_max - V_min)
End
// @brief get the minimum and maximum scaling of the wave in the window range
static Function PLEMd2SetGraphMinMax(win, mini, maxi)
String win
Variable mini, maxi
Variable Ymin, Ymax
Variable Pmin, Pmax, Qmin, Qmax, Zmin, Zmax
string info
String strPLEM = PLEMd2window2strPLEM(win)
Struct PLEMd2stats stats
if(!!numType(mini) && !!numType(maxi))
return 1
endif
PLEMd2statsload(stats, strPLEM)
WAVE PLEM = stats.wavPLEM
GetAxis/Q bottom
if(!!V_flag)
print "SMAdisplayOriginal: Error getting bottom axis in top Graph"
return -1
endif
Pmin = ScaleToIndex(PLEM, V_min, 0)
Pmax = ScaleToIndex(PLEM, V_max, 0)
GetAxis/Q left
if(!!V_flag)
print "SMAdisplayOriginal: Error getting bottom axis in top Graph"
return -1
endif
Ymin = V_min
Ymax = V_max
if(DimSize(PLEM, 1) > 1) // map
Qmin = ScaleToIndex(PLEM, Ymin, 1)
Qmax = ScaleToIndex(PLEM, Ymax, 1)
info = WMGetRECREATIONFromInfo(ImageInfo(StringFromList(0, win, "#"), "PLEM", 0))
info = info[strsearch(info, "{", 0) + 1, strsearch(info, "}", 0) - 1]
Zmin = str2num(StringFromList(0, info, ","))
Zmax = str2num(StringFromList(1, info, ","))
Duplicate/FREE/R=[Pmin, Pmax][Qmin, Qmax] PLEM temp
else
Zmin = Ymin
Zmax = Ymax
Duplicate/FREE/R=[Pmin, Pmax] PLEM temp
endif
WaveStats/Q/M=1 temp
mini = V_min + mini * (V_max - V_min)
maxi = V_min + maxi * (V_max - V_min)
if(DimSize(PLEM, 1) > 1) // map
if(!!numType(mini))
ModifyImage PLEM ctab= {*,maxi,$StringFromList(2, info, ","),str2num(StringFromList(3, info, ","))}
elseif(!!numType(maxi))
ModifyImage PLEM ctab= {mini,*,$StringFromList(2, info, ","),str2num(StringFromList(3, info, ","))}
else
ModifyImage PLEM ctab= {mini,maxi,$StringFromList(2, info, ","),str2num(StringFromList(3, info, ","))}
endif
else
if(!!numType(mini))
SetAxis left, *, maxi
elseif(!!numType(maxi))
SetAxis left, mini, *
else
SetAxis left, mini, maxi
endif
endif
End
Function SetVarProcCalculate(sva) : SetVariableControl
STRUCT WMSetVariableAction &sva
switch( sva.eventCode )
case 1: // mouse up
case 2: // Enter key
case 3: // Live update
Variable dval = sva.dval
if(dval != 0)
String strPLEM
strPLEM = PLEMd2window2strPLEM(sva.win)
PLEMd2BuildMaps(strPLEM)
endif
break
case -1: // control being killed
break
endswitch
return 0
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
Constant PLEM_SYSTEM_LIQUID = 0
Constant PLEM_SYSTEM_MICROSCOPE = 1
// @hacky system identification.
Function PLEMd2getSystem(strUser)
String strUser
strswitch(TrimString(strUser))
case "the master of microscopy":
case "unknown":
return PLEM_SYSTEM_MICROSCOPE
case "":
return -1
default:
return PLEM_SYSTEM_LIQUID
endswitch
End
Function/S PLEMd2getGratingString(numGrating, numSystem)
Variable numGrating, numSystem
switch(numSystem)
case PLEM_SYSTEM_LIQUID:
switch(numGrating)
case 1: // 150 l/mm 1055nm Blaze wl
return "grating150blz1055pplane"
case 2: // 150 l/mm 800nm Blaze wl
return "grating150blz800pplane"
case 3: // 150 l/mm 1250nm Blaze wl
return "grating150blz1250pplane"
default:
break
endswitch
break
case PLEM_SYSTEM_MICROSCOPE:
switch(numGrating)
case 1: // 300 l/mm 500nm Blaze wl
return "grating300blz500"
case 2: // 300 l/mm 1200nm Balze wl
return "grating300blz1200"
case 3: // 150 l/mm 1250nm Blaze wl
return "grating150blz1250pplane"
default:
break
endswitch
break
default:
endswitch
return ""
End
// get the file to load as quantum efficiency correction
// @todo: cooling is currently fixed.
Function/S PLEMd2getDetectorQEString(numDetector, numCooling, numSystem)
Variable numDetector, numCooling, numSystem
switch(numSystem)
case PLEM_SYSTEM_LIQUID:
switch(numDetector)
case PLEMd2detectorNewton:
return "qeNewtonDU920POEm75"
case PLEMd2detectorIdus:
return "qeIdusDU491A17m90"
default:
break
endswitch
break
case PLEM_SYSTEM_MICROSCOPE:
switch(numDetector)
case PLEMd2detectorNewton:
return "qeNewtonDU920POEm100"
case PLEMd2detectorIdus:
return "qeIdusDU491A17m90"
case PLEMd2cameraClara:
case PLEMd2cameraXeva:
default:
break
endswitch
break
default:
endswitch
return ""
End
// get the filter for correcting excitation
Function/S PLEMd2getFilterExcString(numSystem, numDetector)
Variable numSystem, numDetector
switch(numSystem)
case PLEM_SYSTEM_LIQUID:
break
case PLEM_SYSTEM_MICROSCOPE:
switch(numDetector)
case PLEMd2detectorNewton:
case PLEMd2detectorIdus:
// it is possible to add filterChroma760refl but it does not have good accuracy.
return "reflSilver;reflSilver"
default:
break
endswitch
break
default:
endswitch
return "_none_"
End
// get the filter for correcting excitation
Function/S PLEMd2getFilterEmiString(numSystem, numDetector)
Variable numSystem, numDetector
switch(numSystem)
case PLEM_SYSTEM_LIQUID:
break // currently no check for liquid system filter wheel
case PLEM_SYSTEM_MICROSCOPE:
switch(numDetector)
case PLEMd2detectorNewton:
case PLEMd2detectorIdus:
// manual possiblility: filterFEHL0750
return "filterCG830;filterChroma760trans;reflSilver;reflSilver;reflSilver"
default:
break
endswitch
break
default:
endswitch
return ""
End
// Get the (un-interpolated) quantum efficiency wave for the current PLEM
// Loads the wave from PLEMCorrectionPath if not present in the current experiment
Function/WAVE PLEMd2getQuantumEfficiency(stats)
Struct PLEMd2stats &stats
String strDetector
if(stats.numDetector == PLEMd2cameraClara || stats.numDetector == PLEMd2cameraXeva)
return $""
endif
DFREF dfr = DataFolderReference(cstrPLEMd2correction)
WAVE/Z wv = dfr:$strDetector
if(WaveExists(wv))
return wv
endif
PLEMd2LoadCorrectionWaves(strDetector)
WAVE wv = dfr:$strDetector
return wv
End
Function/S PLEMd2LoadFilters(strFilters)
String strFilters
Variable i, numFilters
String strFilter
String strFiltersOut = ""
DFREF dfr = DataFolderReference(cstrPLEMd2correction)
numFilters = ItemsInList(strFilters)
for(i = 0; i < numFilters; i += 1)
strFilter = StringFromList(i, strFilters)
WAVE/Z wv = dfr:$strFilter
if(!WaveExists(wv))
if(PLEMd2LoadCorrectionWaves(strFilter) == 0)
continue
endif
endif
strFiltersOut = AddListItem(strFilter, strFiltersOut)
endfor
return strFiltersOut
End
Function/WAVE PLEMd2SetCorrection(filters, target, targetX)
String filters
WAVE target, targetX
String strFilter
Variable i, numFilters, mini, maxi
DFREF dfr = DataFolderReference(cstrPLEMd2correction)
filters = PLEMd2LoadFilters(filters)
numFilters = ItemsInList(filters)
for(i = 0; i < numFilters; i += 1)
strFilter = StringFromList(i, filters)
WAVE/Z wv = dfr:$(strFilter)
if(!WaveExists(wv))
Abort "Filter not found."
endif
WAVE/Z wvX = dfr:$(strFilter + "_wl")
Duplicate/FREE target dummy
// linear interpolation to target wave
if(WaveExists(wvX))
Interpolate2/T=1/I=3/Y=dummy/X=targetX wvX, wv
else
Interpolate2/T=1/I=3/Y=dummy/X=targetX wv
endif
mini = WaveMin(wvX)
maxi = WaveMax(wvX)
dummy[] = targetX[p] > mini && targetX[p] < maxi ? dummy[p] : NaN
if(i == 0)
Duplicate/O dummy target
else
target *= dummy
endif
endfor
return target
End
Function PLEMd2LoadCorrectionWaves(strCorrectionWave)
String strCorrectionWave
Variable err, i, j, numFiles
Variable numLoaded = 0
String ibwList, ibwFile
PLEMd2LoadGratingPath()
PathInfo PLEMCorrectionPath
if(!V_flag)
Abort "could not find path"
endif
ibwList = IndexedFile(PLEMCorrectionPath, -1, ".ibw")
ibwList = ListMatch(ibwList, strCorrectionWave + "*")
numFiles = ItemsInList(ibwList)
DFREF saveDFR = GetDataFolderDFR()
DFREF dfr = DataFolderReference(cstrPLEMd2correction)
SetDataFolder dfr
for(i = 0; i < numFiles; i += 1)
ibwFile = StringFromList(i, ibwList)
try
GetFileFolderInfo/P=PLEMCorrectionPath/Q/Z=1 ibwFile
if(!V_flag && V_isFile)
LoadWave/Q/N/O/H/P=PLEMCorrectionPath ibwFile; AbortOnRTE
numLoaded += V_Flag
endif
catch
err = GetRTError(1)
endtry
endfor
SetWaveLock 1, allinCDF
SetDataFolder saveDFR
PathInfo PLEMCorrectionPath
if(numFiles > 0)
printf "%d/%d files matching %s loaded from %s.\r", numLoaded, numFiles, strCorrectionWave, S_path
endif
return numLoaded
End
// create PLEMCorrectionPath from package prefs
Function PLEMd2LoadGratingPath()
String strPath
Struct PLEMd2Prefs prefs
PathInfo PLEMCorrectionPath
if(V_flag)
return 0
endif
PLEMd2LoadPackagePrefs(prefs)
// DisplayHelpTopic "Symbolic Paths"
strPath = prefs.strCorrectionPath
GetFileFolderInfo/Q/Z=1 strPath
if(V_flag && !V_isFolder)
Abort "Could not load symbolic path for gratings"
endif
PathInfo strPath
if(!V_flag)
NewPath/O/Q/Z PLEMCorrectionPath, strPath
endif
return 0
End
|
Data Processing¶
Statistical Analysis¶
Statistical analysis, data preparation, and extraction was performed with a custom Igor Pro program for mass analysis.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
#include "sma-coordinates"
#include "sma-covariance"
#include "sma-duplicateRange"
#include "sma-images"
#include "sma-infostructure"
#include "sma-macro"
#include "sma-main"
#include "sma-menu"
#include "sma-peakfind"
#include "sma-prefs"
#include "sma-tools"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
Function SMA_FindMatchingSpectra(coordinates)
WAVE coordinates
variable dim0, numMatches, numMatchesOld, i, j
variable tolerance = 1 // tolerance in um around coordinate
Make/O/N=(0) root:matches/WAVE=matches
WAVE spectra = PLEMd2getCoordinates()
dim0 = DimSize(coordinates, 0)
for(i = 0; i < dim0; i += 1)
WAVE indices = CoordinateFinderXYrange(spectra, coordinates[i][0] - tolerance, coordinates[i][0] + tolerance, coordinates[i][1] - tolerance, coordinates[i][1] + tolerance, verbose = 1)
numMatches = DimSize(indices, 0)
numMatchesOld = DimSize(matches, 0)
Redimension/N=(numMatchesOld + numMatches) matches
for(j = 0; j < numMatches; j += 1)
matches[numMatchesOld + j] = indices[j]
PLEMd2Displaybynum(indices[j])
endfor
endfor
End
Function SMA_ExportCoordinates()
Variable i, numMaps
String name, file
String baseName, maps
SMAupdatePath()
STRUCT FILO#experiment filos
FILO#structureLoad(filos)
baseName = IgorInfo(1)
WAVE allCoordinates = PLEMd2getCoordinates(forceRenew = 1)
maps = PLEMd2getStrMapsAvailable()
WAVE/Z indices = root:peakIndex // one spectrum per exactscan
if(!WaveExists(indices))
numMaps = ItemsInList(maps)
Make/FREE/N=(numMaps) indices = p
endif
// quick validation if files were only loaded with SMAread()
if(ItemsInList(maps) != ItemsInList(filos.strFileList))
Abort "SMA_ExportCoordinates: Missmatch"
endif
numMaps = DimSize(indices, 0)
Make/O/N=(numMaps, 3) root:$(basename + "_coordinates")/WAVE=coordinates
Make/T/O/N=(numMaps) root:$(basename + "_originals")/WAVE=files
for(i = 0; i < numMaps; i += 1)
name = StringFromList(indices[i], maps)
file = StringFromList(indices[i], filos.strFileList)
if(!!cmpstr(name, CleanupName(ParseFilePath(3, file, ":", 0, 0), 0)))
Abort "smaload not valid for " + num2str(i)
endif
files[i] = file
coordinates[i][] = allCoordinates[indices[i]][q]
endfor
file = files[0]
if(!!cmpstr(file[0], ":"))
print files
print filos.strFolder
Abort "Lecacy Format detected"
endif
// save to home
Save/C/O/P=home files
Save/C/O/P=home coordinates
End
// merge two PLEM ranges and save them as a new ibw file
// only works for single background
Function SMA_MergeMaps(indices0, indices1)
WAVE indices0, indices1
String wavenote0, wavenote1, strPath, strPLEM
Variable i, numMaps
Variable start, ende
STRUCT PLEMd2Stats stats
Variable skip = 2 // skip the last 2 entries in the first wave
if(DimSize(indices0, 0) != DimSize(indices1, 0))
Abort "Size Missmatch"
endif
PathInfo home
strPath = S_Path + IgorInfo(1)
NewPath/C/O/Z newmaps, strPath
numMaps = DimSize(indices0, 0)
for(i = 0; i < numMaps; i += 1)
strPLEM = PLEMd2strPLEM(indices0[i])
PLEMd2statsLoad(stats, strPLEM)
DFREF dfr = $(GetWavesDataFolder(stats.wavPLEM, 1) + "ORIGINAL")
WAVE original0 = WaveRefIndexedDFR(dfr, 0)
PLEMd2statsLoad(stats, PLEMd2strPLEM(indices1[i]))
DFREF dfr = $(GetWavesDataFolder(stats.wavPLEM, 1) + "ORIGINAL")
WAVE original1 = WaveRefIndexedDFR(dfr, 0)
Duplicate/O original0 root:$strPLEM/WAVE=dest
Redimension/N=(-1, DimSize(original0, 1) + DimSize(original1, 1) - 2 - skip) dest // single bg
dest[][DimSize(original0, 1) - skip, *] = original1[p][q - DimSize(original0, 1) + skip + 2]
wavenote0 = note(original0)
start = strsearch(wavenote0, "Max Central Wavelength (nm): ", start)
ende = strsearch(wavenote0, "\r", start)
wavenote0 = wavenote0[0, start - 1] + "Max Central Wavelength (nm): " + num2str(stats.numEmissionEnd) + wavenote0[ende, inf]
wavenote1 = note(original1)
start = strsearch(wavenote1, "Power at Glass Plate (µW):", 0) + 28
ende = strsearch(wavenote1, "\r", start) - 1
wavenote1 = wavenote1[start, ende]
start = strsearch(wavenote0, "Power at Glass Plate", 0) + 28
ende = strsearch(wavenote0, "\r", start) - 9 * skip
wavenote0 = wavenote0[0, ende] + wavenote1 + wavenote0[ende + 9 * skip, inf]
wavenote1 = note(original1)
start = strsearch(wavenote1, "IGOR3:WL;BG;PL", 0) + 12 + skip * 12 + skip // skip "IGOR3:WL;BG;" and n x "PL_6875_7125"
wavenote0 += wavenote1[start, inf]
Note/K dest wavenote0
Save/C/O/P=newmaps dest
KillWaves dest
endfor
End
// see ACW_EraseMarqueeArea.
Function SMA_EraseMarqueeArea()
variable dim0, numMatches, i
GetMarquee left, bottom //V_bottom, V_top, V_left and V_right
if (V_flag == 0)
return 0
endif
WAVE coordinates = SMA_PromptTrace()
WAVE indices2 = CoordinateFinderXYrange(coordinates, V_bottom, V_top, V_left, V_right, verbose = 1)
numMatches = DimSize(indices2, 0)
if(!numMatches)
return 0
endif
// delete Points
WAVE/Z deleted = root:coordinates_deleted
if(!WaveExists(deleted))
Make/N=(numMatches, 3) root:coordinates_deleted/WAVE=deleted
else
dim0 = DimSize(deleted, 0)
dim0 = 0 // reset deleted wave
Redimension/N=(dim0 + numMatches, -1) deleted
endif
Sort/R indices2, indices2
if(!cmpstr(NameOfWave(coordinates), "coordinates"))
WAVE/Z l1 = root:legende
WAVE/Z l2 = root:legend_text
endif
for(i = 0; i < numMatches; i += 1)
deleted[dim0 + i][] = coordinates[indices2[i]][q]
DeletePoints/M=0 indices2[i], 1, coordinates
if(!cmpstr(NameOfWave(coordinates), "coordinates"))
if(WaveExists(l1) && WaveExists(l2))
DeletePoints/M=0 indices2[i], 1, l1, l2
endif
endif
endfor
// Append coordinates_deleted wave to top graph if not present
CheckDisplayed deleted
if(V_flag == 0)
AppendToGraph deleted[][0]/TN=deleted vs deleted[][1]
ModifyGraph mode(deleted)=4,marker(deleted)=8,opaque(deleted)=1,rgb(deleted)=(0,65535,0)
endif
End
// @brief Delete entities in @p coordinates that are duplicate values in @p reference
//
// give a @p companion wave that is connected with its rows to coordinates and delete from there as well.
// @returns number of points deleted
Function SMAdeleteDuplicateCoordinates(coordinates, reference, [companion])
WAVE coordinates, reference, companion
Variable i, j, numMatches, dim0
if(ParamIsDefault(companion))
if(DimSize(companion, 0) != DimSize(coordinates, 0))
Abort "SMAdeleteDuplicateCoordinates: companion and coordinates need to have the same number of rows."
endif
endif
Make/FREE/N=0 indices
dim0 = DimSize(reference, 0)
for(i = 0; i < dim0; i += 1)
WAVE duplicates = CoordinateFinderXYrange(coordinates, reference[i][0] - 1.5, reference[i][0] + 1.5, reference[i][1] - 1, reference[i][1] + 1, verbose = 0)
numMatches = DimSize(duplicates, 0)
if(!cmpstr(GetWavesDataFolder(coordinates, 2), GetWavesDataFolder(reference, 2))) // check if acting on the same wave
Extract/FREE duplicates, duplicates, (duplicates[p] > i)
endif
if(!WaveExists(duplicates))
continue
endif
Concatenate/FREE {indices, duplicates}, dummy
Duplicate/FREE dummy indices
WaveClear dummy
endfor
if(Dimsize(indices, 0) == 0)
return 0
endif
if(DimSize(indices, 0) > 1)
Sort indices, indices
FindDuplicates/FREE/RN=dummy/TOL=0 indices
if(!WaveExists(dummy))
return 0
endif
Duplicate/FREE dummy indices
endif
Extract/FREE indices, matches, numtype(indices[p]) == 0
numMatches = DimSize(matches, 0)
for(i = numMatches - 1; i > -1; i -= 1)
if(numtype(matches[i]) != 0)
numMatches -= 1
continue
endif
if(ParamIsDefault(companion))
DeletePoints matches[i], 1, coordinates
else
DeletePoints matches[i], 1, coordinates, companion
endif
endfor
// always be verbose due to the delete
printf "deleted %d matches in %s.\r", numMatches, GetWavesDataFolder(coordinates, 2)
return numMatches
End
Function/Wave SMA_PromptTrace()
String itemName
Variable selectedItem
string itemsList = ""
Variable numItems = 0
String topWindowImages = ImageNameList("", ";")
String topWindowTraces = TraceNameList("", ";", 1)
Variable numTraces = ItemsInList(topWindowTraces)
Variable numImages = ItemsInList(topWindowImages)
// remove trailing ";"
if(!cmpstr(topWindowImages[(strlen(topWindowImages) - 1), strlen(topWindowImages)], ";"))
topWindowImages = topWindowImages[0, strlen(topWindowImages) - 1]
endif
itemsList = AddListItem(topWindowImages, topWindowTraces, ";", numTraces)
numItems = numTraces + numImages
if(numItems == 0)
print "No traces found in top graph"
return $""
endif
if(numItems == 1)
if(numTraces)
return TraceNameToWaveRef("", StringFromList(0, itemsList))
else
return ImageNameToWaveRef("", StringFromList(0, itemsList))
endif
endif
Prompt selectedItem, "Choose Trace", popup, itemsList
DoPrompt "Enter wave", selectedItem
if(V_flag)
print "SMA_PromptTrace: catched Cancel"
return $""
endif
selectedItem -= 1 // zero based index
itemName = StringFromList(selectedItem, itemsList)
if(selectedItem < numTraces)
return TraceNameToWaveRef("", itemName)
else
return ImageNameToWaveRef("", itemName)
endif
End
Function GetCoordinates()
Variable temp, i, j
Variable numCoords, numPeaks
Variable numSize = 1024
String topWindowImages = ImageNameList("", ";")
String topWindowTraces = TraceNameList("", ";", 1)
if(ItemsInList(topWindowImages) == 0)
print "no Image found in top graph"
return 0
endif
WAVE/Z image = ImageNameToWaveRef("", StringFromList(0, topWindowImages))
if(!WaveExists(image))
print "image wave does not exist."
return 0
endif
STRUCT PLEMd2Stats stats
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
// start fresh
Make/O/N=(numSize, 3) root:coordinates/Wave=wavCoordinates = NaN
Make/O/N=(numSize, 3) root:legende/Wave=wavLegend = NaN
Make/O/T/N=(numSize) root:legend_text/Wave=wavLegendText = ""
// display coordinates
if(FindListItem("coordinates", topWindowTraces) == -1)
AppendToGraph wavCoordinates[][0]/TN=coordinates vs wavCoordinates[][1]
ModifyGraph mode(coordinates)=3,marker(coordinates)=1,msize(coordinates)=2
endif
if(FindListItem("legend", topWindowTraces) == -1)
AppendToGraph wavLegend[][0]/TN=legend vs wavLegend[][1]
ModifyGraph mode(legend)=3
ModifyGraph textMarker(legend)={wavLegendText,"default",0,0,5,0.00,0.00}
ModifyGraph msize(legend)=3
endif
Duplicate/FREE image, currentImage
// prepare: remove offset
ImageFilter/O/N=5 gauss currentImage
temp = WaveMin(currentImage)
currentImage -= temp
for(i = 0; i <= 300; i += 4)
Duplicate/FREE/R=(0, 300)(i) currentImage lineProfile
WAVE peaks = SMApeakFind(lineProfile, maxPeaks = 30, minPeakPercent = 0.1, smoothingfactor = NaN)
WaveClear lineProfile
numPeaks = DimSize(peaks, 0)
for(j = 0; j < numPeaks; j += 1)
if(peaks[j][%fwhm] > 5)
continue
endif
if(numSize < numCoords)
Redimension/N=(numCoords + 10, -1) wavCoordinates, wavLegend, wavLegendText
numSize = numCoords + 10
endif
wavCoordinates[numCoords][0] = i
wavCoordinates[numCoords][1] = peaks[j][%location]
wavCoordinates[numCoords][2] = stats.numPositionZ
wavLegend[numCoords][0] = wavCoordinates[numCoords][0]
wavLegend[numCoords][1] = wavCoordinates[numCoords][1]
wavLegendText[numCoords] = "i=" + num2str(peaks[j][%height]) + "\r f=" + num2str(peaks[j][%fwhm])
numCoords += 1
endfor
DoUpdate
WaveClear peaks
endfor
Redimension/N=(numCoords, -1) wavCoordinates, wavLegendText, wavLegend
SortColumns/KNDX={0,1} sortwaves=wavCoordinates
End
Function AddCoordinatesFromGraph()
Variable numItems
Variable aExists = 0
aExists= strlen(CsrInfo(A)) > 0
if(!aExists)
print "Cursor A not in Graph"
return 0
endif
WAVE/Z coordinates = root:coordinates
if(!WaveExists(coordinates))
SMAresetCoordinates()
WAVE coordinates = root:coordinates
endif
WAVE/T/Z legende = root:legend_text
numItems = DimSize(coordinates, 0)
Redimension/N=(numItems + 1, 3) coordinates
coordinates[numItems][0]=vcsr(A)
coordinates[numItems][1]=hcsr(A)
WAVE/Z normal = root:SMAcameraPlaneNormal
WAVE/Z distance = root:SMAcameraPlaneDistance
if(!WaveExists(normal) || !WaveExists(distance))
coordinates[numItems][2]=150
print "AddCoordinatesFromGraph: missing tilt plane parameters"
else
coordinates[numItems][2]= SMAcameraGetTiltPlane(coordinates[numItems][0],coordinates[numItems][1])
endif
if(WaveExists(legende))
Redimension/N=(numItems + 1, -1) legende
legende[numItems]="manual"
endif
// Append coordinates_deleted wave to top graph if not present
CheckDisplayed coordinates
if(V_flag == 0)
AppendToGraph coordinates[][0]/TN=coordinates vs coordinates[][1]
ModifyGraph mode(coordinates)=4,marker(coordinates)=8
endif
End
Function DeleteCoordinates(rangeMin, rangeMax)
Variable rangeMin, rangeMax
Variable numItems, i, deleteMe
Variable numDelete = 0
WAVE/Z coordinates = root:coordinates
WAVE/T/Z legende = root:legend_text
if(!WaveExists(coordinates))
print "required waves do not exist. Start SMAgetCoordinates first"
return 0
endif
Duplicate/FREE coordinates original
numItems = DimSize(original, 0)
for(i = 0; i < numItems; i += 1)
deleteMe = 0
if((coordinates[i - numDelete][0] < rangeMin) || (coordinates[i - numDelete][0] > rangeMax))
deleteMe = 1
endif
if((coordinates[i - numDelete][1] < rangeMin) || (coordinates[i - numDelete][1] > rangeMax))
deleteMe = 1
endif
if(deleteMe)
DeletePoints/M=0 i - numDelete, 1, coordinates
if(WaveExists(legende))
DeletePoints/M=0 i - numDelete, 1, legende
endif
numDelete += 1
endif
endfor
End
Function SortCoordinates()
WAVE/Z coordinates = root:coordinates
WAVE/T/Z legende = root:legend_text
if(!WaveExists(coordinates))
print "required waves do not exist. Start SMAgetCoordinates first"
return 0
endif
if(WaveExists(legende))
SortColumns/KNDX={0,1} keyWaves=coordinates, sortWaves={coordinates, legende}
else
SortColumns/KNDX={0,1} sortWaves=coordinates
endif
End
Function RoundCoordinates([accuracy])
Variable accuracy
WAVE/Z coordinates = root:coordinates
accuracy = ParamIsDefault(accuracy) ? 4 : accuracy
if(!WaveExists(coordinates))
print "required waves do not exist. Start SMAgetCoordinates first"
return 0
endif
coordinates[][0] = round(coordinates[p][0] / accuracy) * accuracy
End
Function SMAcalcZcoordinateFromTiltPlane([wv, zOffset])
WAVE wv
variable zOffset
zOffset = ParamIsDefault(zOffset) ? SMAcameraGetTiltPlane(0,0) : zOffset
if(ParamIsDefault(wv))
WAVE wv = root:coordinates
endif
if(!WaveExists(wv))
print "SMAcalcZcoordinateFromTiltPlane: input wave does not exist"
return 0
endif
WAVE/Z normal = root:SMAcameraPlaneNormal
WAVE/Z distance = root:SMAcameraPlaneDistance
if(!WaveExists(normal) || !WaveExists(distance))
print "SMAcalcZcoordinateFromTiltPlane: nothing done"
return 0
endif
wv[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zOffset)
End
// @brief search trenches for carbon nanotubes (considered experimental)
Function SMAgetCoordinates()
Variable i
STRUCT PLEMd2Stats stats
variable numMaps = PLEMd2getMapsAvailable()
SMAresetCoordinates()
SMAbuildGraphPLEM()
//WAVE fullimage = SMAmergeImages(0, createNew = 0)
//Duplicate/FREE fullimage, currentImage
//SMAparticleAnalysis(currentImage)
WAVE background = SMAestimateBackground()
for(i = 0; i < numMaps; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
Duplicate/FREE stats.wavPLEM, currentImage
ImageFilter/O /N=5 median currentImage // remove spikes
currentImage -= background
SMAsearchTrenches(currentImage, trenchpitch = 4)
endfor
return 1
End
Function SMAsearchTrenches(currentImage, [trenchpitch])
WAVE currentImage
Variable trenchpitch // distance from one trench to the next
Variable i, numPeaks, numCoords
Variable dim0, dim0offset, dim0delta, dim1
Variable Pmin, Pmax, Ymin, Ymax, Qdelta
Variable rangePdelta, rangeYdelta
Variable currentY, QcenterTrench
Variable rangeXmin = 5, rangeXmax = 300
Variable rangeYmin = 0, rangeYmax = 300
Variable Ydelta = 4/3 * 1 // size of trench area in y-direction
trenchpitch = ParamIsDefault(trenchpitch) ? 4 : trenchpitch
dim0 = DimSize(currentImage, 0)
dim0delta = DimDelta(currentImage, 0)
dim0offset = DimOffset(currentImage, 0)
Pmin = limit(ScaleToIndex(currentImage, rangeXmin, 0), 0, dim0 - 1)
Pmax = limit(ScaleToIndex(currentImage, rangeXmax, 0), 0, dim0 - 1)
Qdelta = floor(abs(ScaleToIndex(currentImage, Ydelta, 1) - ScaleToIndex(currentImage, 0, 1)))
dim1 = DimSize(currentImage, 1)
Ymin = IndexToScale(currentImage, 0, 1)
Ymax = IndexToScale(currentImage, dim1 - 1, 1)
SMAorderAsc(Ymin, Ymax)
Ymin = limit(ceil((Ymin + Ydelta) / trenchpitch) * trenchpitch, rangeYmin, rangeYmax)
Ymax = limit(floor((Ymax - Ydelta) / trenchpitch) * trenchpitch, rangeYmin, rangeYmax)
rangePdelta = abs(Pmax - Pmin) + 1
rangeYdelta = abs(Ymax - Ymin) / trenchpitch + 1
// differentiate 2 times along trench area
ImageFilter/O/N=5 gauss currentImage
Differentiate/DIM=0 currentImage
Differentiate/DIM=0 currentImage
ImageFilter/O/N=11 gauss currentImage
// extract all trenches. Trench width is Qdelta
Make/O/N=(rangePdelta, rangeYdelta) root:trenches/WAVE=wavTrenches = NaN
for(i = 0; i < rangeYdelta; i += 1)
currentY = Ymin + trenchpitch * i
QcenterTrench = ScaleToIndex(currentImage, currentY, 1)
Duplicate/FREE/R=[Pmin, Pmax][floor(QcenterTrench - Qdelta), ceil(QcenterTrench + Qdelta)] currentImage, currentTrench
MatrixOP/FREE currentTrenchAvg = sumRows(currentTrench)
wavTrenches[][i] = currentTrenchAvg[p]
endfor
// substract a median trench to see the peaks better
Make/O/N=(rangePdelta) root:averageTrench/WAVE=averageTrench
for(i = 0; i < rangePdelta; i += 1)
MatrixOP/FREE currentPixel = row(wavTrenches, i)
averageTrench[i] = median(currentPixel)
endfor
Smooth 50, averageTrench
wavTrenches[][] -= averageTrench[p]
// find the peaks and store them
Make/FREE/N=(rangePdelta) positionX = dim0offset + (Pmin + p) * dim0delta
Make/FREE/N=(0, 2) currentCoordinates
Make/FREE/N=(0, 0)/T description
for(i = 0; i < rangeYdelta; i += 1)
currentY = Ymin + trenchpitch * i
Duplicate/FREE/R=[][i] wavTrenches, currentTrenchAvg
WAVE peaks = PeakFind(currentTrenchAvg, wvXdata = positionX, maxPeaks = 10, minPeakPercent = 90)
numPeaks = DimSize(peaks, 0)
if(numPeaks == 0)
continue
endif
Redimension/N=(numPeaks, -1) currentCoordinates, description
currentCoordinates[][0] = currentY
currentCoordinates[][1] = peaks[p][%location]
description[] = num2str(round(peaks[p][%height]))
SMAaddCoordinates(currentCoordinates, text = description)
numCoords += numPeaks
endfor
return numCoords
End
Function SMAparticleAnalysis(currentImage)
WAVE currentImage
variable numPeaks
// differentiate 2 times to get the peaks without background
ImageFilter/O/N=5 gauss currentImage
Differentiate/DIM=0 currentImage
Differentiate/DIM=0 currentImage
ImageFilter/O/N=11 gauss currentImage
// remove 2nd derivative sattelites
currentImage *= -1 // inverted image
currentImage[][] = currentImage[p][q] < 0 ? 0 : currentImage[p][q]
// calculate Threshold
//StatsQuantiles/Q/ALL currentImage
//Wave W_StatsQuantiles
//myThreshold = W_StatsQuantiles[%upperOuterFence]
//print "Threshold set to ", myThreshold
//MatrixFilter/O NanZapMedian currentImage
//ImageThreshold/I/O/Q/M=0/T=(myThreshold) currentImage
ImageThreshold/I/O/Q/M=5 currentImage
// particle size: elipse with defined circularity, min and max area
ImageAnalyzeParticles/A=20/MAXA=500/CIRC={0.75 , 1.75}/W/M=2 stats currentImage
WAVE W_SpotX, W_spotY
WAVE W_BoundaryX, W_BoundaryY
WAVE W_ImageObjArea, M_rawMoments, W_circularity
numPeaks = DimSize(W_SpotX, 0)
if((numPeaks == 0) || (numPeaks > 3000))
print "Error: non reasonable peak count", numPeaks
return 0
endif
Make/FREE/N=(numPeaks, 2) currentCoordinates
currentCoordinates[][0] = IndexToScale(currentImage, M_rawMoments[p][1] / W_ImageObjArea[p], 1)
currentCoordinates[][1] = IndexToScale(currentImage, M_rawMoments[p][0] / W_ImageObjArea[p], 0)
return SMAaddCoordinates(currentCoordinates)
End
Function SMAresetCoordinates()
Make/O/N=(0, 3) root:coordinates/Wave=wavCoordinates = NaN
End
Function SMAaddCoordinates(currentCoordinates, [text])
WAVE currentCoordinates
WAVE/T text
Variable j, k, numPeaks, numCoords, numSize
Variable coordinateX, coordinateY, duplicateValue
numPeaks = DimSize(currentCoordinates, 0)
if(numPeaks == 0)
return 0
endif
WAVE/Z wavCoordinates = root:coordinates
if(!WaveExists(wavCoordinates))
Make/O/N=(0, 3) root:coordinates/Wave=wavCoordinates = NaN
endif
numCoords = DimSize(wavCoordinates, 0)
numSize = numCoords + numPeaks
WAVE/T/Z wavLegendText = root:legend_text
if(!WaveExists(wavLegendText))
Make/O/T/N=(numSize) root:legend_text/Wave=wavLegendText = ""
endif
Make/FREE/D/N=(numSize) coordinatesX = 0, coordinatesY = 0
Redimension/N=(numSize, -1) wavCoordinates, wavLegendText, coordinatesX, coordinatesY
for(j = 0; j < numPeaks; j += 1)
if(numSize < numCoords)
numSize = numCoords + 10
endif
// get coordinates (rounded to 0.1)
coordinateX = round(currentCoordinates[j][0]/0.1)*0.1
coordinateY = round(currentCoordinates[j][1]/0.1)*0.1
// compare to currently saved coordinates
k = -1
duplicateValue = 0
do
FindValue/S=(k+1)/T=1/V=(coordinateX) coordinatesX
k = V_Value
if(k == -1)
break
endif
// min. range for a new coordinate is 2 µm
if(round(coordinatesY[k]/2)*2 == round(coordinateY/2)*2)
duplicateValue = 1
break
endif
while(k < numCoords)
if(duplicateValue)
wavCoordinates[k][0] = (wavCoordinates[V_Value][0] + coordinateX) / 2
wavCoordinates[k][1] = (wavCoordinates[V_Value][1] + coordinateY) / 2
continue
endif
coordinatesX[numCoords] = coordinateX
coordinatesY[numCoords] = coordinateY
wavCoordinates[numCoords][0] = coordinateX
wavCoordinates[numCoords][1] = coordinateY
wavCoordinates[numCoords][2] = 150 // fixed
if(!ParamIsDefault(text))
wavLegendText[numCoords] = text[j]
else
wavLegendText[numCoords] = "(" + num2str(coordinateX) + ", " + num2str(coordinateY) + ")"
endif
numCoords += 1
endfor
Redimension/N=(numCoords, -1) wavCoordinates, wavLegendText
SortColumns/KNDX={0,1} sortwaves=wavCoordinates
return numCoords
End
Function/S SMAsearchCoordinate(coordinateX, coordinateY)
Variable coordinateX, coordinateY
Variable k
String listFound = ""
WAVE coordinates = PLEMd2getCoordinates()
// round coordinates
coordinateX = round(coordinateX/0.1)*0.1
coordinateY = round(coordinateY/0.1)*0.1
// separate Waves
Duplicate/FREE/R=[][0] coordinates coordinatesX
Duplicate/FREE/R=[][1] coordinates coordinatesY
Redimension/N=(-1, 0) coordinatesX, coordinatesY
k = -1
do
if(k==57)
print "hier"
endif
FindValue/S=(k+1)/T=1/V=(coordinateX) coordinatesX
k = V_Value
if(k == -1)
break
endif
if(round(coordinatesY[k]/2)*2 == round(coordinateY/2)*2)
listFound = AddListItem(num2str(k), listFound)
continue
endif
while(k < DimSize(coordinates, 0))
return listFound
End
// Zzero is the new zero position to which the z values will be corrected
// i.e. the new focus point at (x,y) = (0,0)
Function/WAVE SMAcameraCoordinates([Zzero, export])
Variable Zzero
Variable export
export = ParamIsDefault(export) ? 1 : !!export
Variable xstep = 48, ystep = 80, zstep = -1
Zzero = ParamIsDefault(Zzero) ? SMAcameraGetTiltPlane(0, 0) : Zzero
printf "SMAcameraCoordinates(Zzero = %.2f, export = %d)\r", Zzero, export
// 4 scans in x = 300/64
// 6 scans in y = 300/48
// 8 scans in z direction (4um from laserfocus to bottom of trench in 0.5um steps)
// --> 16 hours when integrating 300s.
Make/O/N=(4 * 6 * 8, 3) root:SMAfullscan/WAVE=wv
wv[][0] = 4 * 6 + mod(floor(p / 4), 6) * xstep
wv[][1] = 30 + mod(p, 4) * ystep
wv[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zZero) + floor(p / (4 * 6)) * zstep
Duplicate/O/R=[0 * 4 * 6, 1 * 4 * 6 - 1] wv root:SMAsinglescan00/WAVE=singlescan00
singlescan00[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zZero)
Duplicate/O/R=[0 * 4 * 6, 1 * 4 * 6 - 1] wv root:SMAsinglescan10/WAVE=singlescan10
singlescan10[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zZero) - 1
Duplicate/O/R=[0 * 4 * 6, 1 * 4 * 6 - 1] wv root:SMAsinglescan15/WAVE=singlescan15
singlescan15[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zZero) - 1.5
Duplicate/O/R=[0 * 4 * 6, 1 * 4 * 6 - 1] wv root:SMAsinglescan20/WAVE=singlescan20
singlescan20[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zZero) - 2
Duplicate/O/R=[0 * 4 * 6, 1 * 4 * 6 - 1] wv root:SMAsinglescan25/WAVE=singlescan25
singlescan25[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zZero) - 2.5
Duplicate/O/R=[0 * 4 * 6, 1 * 4 * 6 - 1] wv root:SMAsinglescan40/WAVE=singlescan40
singlescan40[][2] = SMAcameraGetTiltPlane(wv[p][0], wv[p][1], zOffset = zZero) - 4
if(export)
Save/J/O/DLIM=","/P=home singlescan00 as "singlescan00.csv"
Save/J/O/DLIM=","/P=home singlescan10 as "singlescan10.csv"
Save/J/O/DLIM=","/P=home singlescan15 as "singlescan15.csv"
Save/J/O/DLIM=","/P=home singlescan20 as "singlescan20.csv"
Save/J/O/DLIM=","/P=home singlescan25 as "singlescan25.csv"
Save/J/O/DLIM=","/P=home singlescan40 as "singlescan40.csv"
Save/J/O/DLIM=","/P=home wv as "fullscan.csv"
endif
return wv
End
Function SMAcameraGetIntensity()
variable i
STRUCT PLEMd2Stats stats
variable numMaps = PLEMd2getMapsAvailable()
variable V_FitError = 0
if(numMaps == 0)
SMAload()
numMaps = PLEMd2getMapsAvailable()
endif
Make/O/N=(numMaps) root:SMAcameraIntensity/WAVE=intensity
Make/O/N=(numMaps, 3) root:SMAcameraIntensityCoordinates/WAVE=coordinates
for(i = 0; i < numMaps; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
V_FitError = 0
if(DimSize(stats.wavPLEM, 1) > 1)
CurveFit/Q/M=0/W=2 Gauss2D stats.wavPLEM
else
CurveFit/Q/M=0/W=2 Gauss stats.wavPLEM
endif
if(V_FitError == 0)
WAVE W_Coef
intensity[i] = W_Coef[1]
else
intensity[i] = WaveMax(stats.wavPLEM)
endif
coordinates[i][0] = stats.numPositionX
coordinates[i][1] = stats.numPositionY
coordinates[i][2] = stats.numPositionZ
endfor
End
Function/WAVE SMAcameraGetTiltPlaneParameters([createNew])
variable createNew
variable numPeaks
createNew = ParamIsDefault(createNew) ? 0 : !!createNew
WAVE/Z focuspoints = root:SMAcameraFocusPoints
if(createNew || !WaveExists(focuspoints))
WAVE focuspoints = SMAgetFocuspoints(graph = 1, createNew = createNew)
endif
numPeaks = DimSize(focuspoints, 0)
if(!WaveExists(focuspoints) || (numPeaks != 3))
print "SMAcameraGetTiltPlaneParameters(): Please correct manually and call again."
edit focuspoints
print "call: to add from graph"
print "root:SMAcameraFocusPoints[2] = root:SMAcameraIntensityCoordinates[pcsr(a)][q]"
print "call after manual editing root:SMAcameraFocusPoints:"
print "SMAcameraGetTiltPlaneParameters(createNew=0)"
Abort "Error in peakfind"
endif
return SMAHessePlaneParameters(focuspoints)
End
/// @brief search for laserspot maxima in loaded images
Function/WAVE SMAgetFocuspoints([graph, createNew])
variable graph, createNew
variable numPeaks, i, step, pStart, pEnd, pPeak
variable numSpectra = PLEMd2getMapsAvailable()
variable numFocuspoints = 3
variable pOffset = 5
graph = ParamIsDefault(graph) ? 0 : !!graph
createNew = ParamIsDefault(createNew) ? 0 : !!createNew
WAVE/Z intensity = root:SMAcameraIntensity
WAVE/Z coordinates = root:SMAcameraIntensityCoordinates
if(!WaveExists(intensity) || !WaveExists(coordinates) || createNew)
SMAcameraGetIntensity()
WAVE intensity = root:SMAcameraIntensity
WAVE coordinates = root:SMAcameraIntensityCoordinates
endif
Duplicate/O intensity root:SMAcameraIntensitySmth/WAVE=intensity_smooth
Smooth 5, intensity_smooth
Make/O/N=(numFocuspoints, 3) root:SMAcameraFocusPoints/WAVE=focuspoints = 0
Make/O/N=(numFocuspoints) root:SMAcameraPlanePeakMaximum/WAVE=focuspointsPval = 0
for(i = 0; i < numFocuspoints; i += 1)
pStart = i * round(numSpectra / 3)
pEnd = (i + 1) * round(numSpectra / 3) - 1
// quick fix: experimentally the first points are often garbage
pStart += pOffset
Duplicate/FREE/R=[pStart,pEnd] intensity_smooth singlePeakY
Duplicate/FREE/R=[pStart,pEnd][2] coordinates singlePeakX
Redimension/N=(-1, 0) singlePeakX
WAVE guess = PeakFind(singlePeakY, wvXdata = singlePeakX, maxPeaks = 1)
WAVE/WAVE coef = BuildCoefWv(singlePeakY, wvXdata = singlePeakX, peaks = guess)
WAVE/WAVE/Z peakParam = fitGauss(singlePeakY, wvXdata = singlePeakX, wvCoef = coef)
if(!WaveExists(peakParam))
// revert to guess
WAVE/WAVE coef = BuildCoefWv(singlePeakY, wvXdata = singlePeakX, peaks = guess)
WAVE/WAVE peakParam = GaussCoefToPeakParam(coef)
endif
WAVE peakfind = peakParamToResult(peakParam)
if(!WaveExists(peakfind))
print "SMAgetFocuspoints(): Please correct manually and call again."
Abort "Error in peakfind"
endif
numPeaks = DimSize(peakfind, 0)
if(numPeaks == 1)
pPeak = pStart - pOffset
FindLevel singlePeakX, peakfind[0][%location]
if(!V_flag)
pPeak = V_LevelX
endif
focuspointsPval[i] = pPeak
focuspoints[i][] = coordinates[pPeak][q]
focuspoints[i][2] = peakfind[0][%location]
printf "peak%d: \t x-Axis: \t%06.2f \ty-Axis: \t%06.2f \tz-Axis: \t%06.2f\r", i, focuspoints[i][0], focuspoints[i][1], focuspoints[i][2]
endif
endfor
//output the results as graph
if(graph)
Make/O/T/N=(numFocuspoints) root:SMAcameraPlanePeakMaximumT = "(" + num2str(focuspoints[p][0]) + "," + num2str(focuspoints[p][1]) + ")"
step = floor(DimSize(coordinates, 0) / 10 / 2) * 2
Make/O/N=10 root:SMAcameraPlanePeakMaximumZ/WAVE=zWave = step / 2 + p * step
Make/O/T/N=10 root:SMAcameraPlanePeakMaximumZT = num2str(round(coordinates[zWave[p]][2] * 10) / 10)
Execute/Z "SMAcameraFocusPointsGraph()"
SavePICT/O/P=home/E=-5/B=72
endif
return focuspoints
End
Function/WAVE SMAHessePlaneParameters(focuspoints)
WAVE focuspoints
printf "SMAHessePlaneParameters(%s)\r", GetWavesDataFolder(focuspoints, 2)
Make/O/N=3 root:SMAcameraPlaneNormal/WAVE=normal
Make/O/N=1 root:SMAcameraPlaneDistance/WAVE=distance
MatrixOP/FREE row0 = row(focuspoints, 0)^t
MatrixOP/FREE row1 = row(focuspoints, 1)^t
MatrixOP/FREE row2 = row(focuspoints, 2)^t
MatrixOP/FREE temp1 = row1 - row0
MatrixOP/FREE temp2 = row2 - row0
Cross/T/DEST=normal temp1, temp2
MatrixOP/O distance = normal . averageCols(focuspoints)
print "calculated plane in Hesse Normal form. Saving to home folder."
Save/C/O/P=home distance, normal
return focuspoints
End
Function SMAcameraGetTiltPlane(coordinateX, coordinateY, [zOffset])
variable coordinateX, coordinateY, zOffset
variable coordinateZ
if(ParamIsDefault(zOffset))
zOffset = 0
else
zOffset -= SMAcameraGetTiltPlane(0, 0)
endif
WAVE/Z normal = root:SMAcameraPlaneNormal
WAVE/Z distance = root:SMAcameraPlaneDistance
if(!WaveExists(normal) || !WaveExists(distance))
SMAcameraGetTiltPlaneParameters()
WAVE normal = root:SMAcameraPlaneNormal
WAVE distance = root:SMAcameraPlaneDistance
endif
return zOffset + (distance[0] - normal[0] * coordinateX - normal[1] * coordinateY) / normal[2]
End
/// @brief Return a Wave of Waves with all matching PLEM indices for the supplied coordinates wave
Function/WAVE SMAfindCoordinatesInPLEM(coordinates, [verbose, accuracy])
WAVE coordinates
Variable verbose, accuracy
Variable i, dim0
verbose = ParamIsDefault(verbose) ? 0 : !!verbose
WAVE PLEMcoordinates = PLEMd2getCoordinates()
dim0 = DimSize(coordinates, 0)
Make/FREE/U/I/WAVE/N=(dim0) indices
if(ParamIsDefault(accuracy))
indices[] = CoordinateFinderXYZ(PLEMcoordinates, coordinates[p][0], coordinates[p][1], coordinates[p][2], verbose = verbose)
else
indices[] = CoordinateFinderXYZ(PLEMcoordinates, coordinates[p][0], coordinates[p][1], coordinates[p][2], verbose = verbose, accuracy = accuracy)
endif
return indices
End
// @brief reduce the found indices from @c SMAfindCoordinatesInPLEM to the first match
// @return unsigned integer wavv
Function/WAVE SMAreduceIndices(wv)
WAVE/WAVE wv
Variable i, numMaps = DimSize(wv, 0)
Make/N=(numMaps)/U/I/FREE indices
for(i = 0; i < numMaps; i += 1)
WAVE matches = wv[i]
indices[i] = matches[0]
endfor
return indices
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
// https://docs.byte-physics.de/json-xop/#download-and-installation
#include "json_functions"
static constant samplingAccuracy = 5e-2 // in nanometer
// Append the given spectra to a 2-dimensional wave.
//
// WARNING: Will alter the original data! (spikes, resample, interpolate)
// Automatically resamples data only if it was not equally acquired
// using different detectors, gratings, or excitation steps
//
// @param overwrite if set to 1: recreate the wave if it already exists
// @param range specify the spectra ids with a numeric, uint wave
// @param destName Name of destination WAVE in root: data folder
// @param downsample set to force to a specific wavelength spacing
// @param graph display a graph showing the source wave
Function/WAVE SMAgetSourceWave([overwrite, range, destName, downsample, graph])
Variable overwrite
WAVE/U/I range
String destName
Variable downsample, graph
Variable i, j, dim0, dim1, dim2, numMarkers, scale, index, accuracy, err
STRUCT PLEMd2Stats stats
DFREF dfr = root:
overwrite = ParamIsDefault(overwrite) ? 1 : !!overwrite
graph = ParamIsDefault(graph) ? 1 : !!graph
if(ParamIsDefault(range))
Make/FREE/U/I/N=(PLEMd2getMapsAvailable()) range = p
endif
dim0 = DimSize(range, 0)
if(ParamIsDefault(destName))
destName = "source"
endif
WAVE/Z wv = dfr:$destName
if(WaveExists(wv) && !overwrite)
if(DimSize(wv, 0) == dim0)
return wv
endif
endif
if(dim0 > (2^32))
Abort "SMAgetSourceWave: Too many spectra."
endif
STRUCT SMAsampling s
SMAgetResamplingInformation(range, s, range = 1, verbose = 0)
if(!ParamIsDefault(downsample))
s.xDelta = max(s.xDelta, downsample)
s.yDelta = max(s.yDelta, downsample)
endif
s.yDelta = numtype(s.yDelta) != 0 ? abs(s.yMax - s.yMin) : s.yDelta // undefined @c numExcitationStep in spectra
dim1 = round(abs(s.xMax - s.xMin) / s.xDelta)
dim2 = max(1, round(abs(s.yMax - s.yMin) / s.yDelta))
if(dim0 * dim1 * dim2 > (2^32))
if(dim0 * dim2 > (2^32))
Abort "SMAgetSourceWave: Can not handle this many points."
endif
do // downsample x (x is always smaller than y due to setup constraints)
s.xDelta *= 2
dim1 = round(abs(s.xMax - s.xMin) / s.xDelta)
if(s.xDelta > s.yDelta) // downsample y
s.yDelta *= 2
dim2 = max(1, round(abs(s.yMax - s.yMin) / s.yDelta))
endif
while(dim0 * dim1 * dim2 < (2^32))
endif
s.xSize = numtype(dim1) == 0 ? dim1 : 0
s.ySize = numtype(dim2) == 0 ? dim2 : 0
Make/FREE/N=(dim0, s.xSize * s.ySize) wv
if(dim2 == 1)
SetScale/I y, s.xMin, s.xMax, wv
endif
SMAsetSampling(wv, s)
Make/FREE/N=(s.xSize, s.ySize) target
Make/FREE/N=(s.xSize) targetX
SetScale/I x, s.xMin, s.xMax, target, targetX
SetScale/I y, s.yMin, s.yMax, target
// fill source wave
for(i = 0; i < dim0; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(range[i]))
WAVE PLEM = stats.wavPLEM
// resample along excitation Δλ > 1, size < 48
if(DimSize(PLEM, 1) > 2)
accuracy = min(samplingAccuracy, stats.numEmissionStep / s.yDelta)
try
RatioFromNumber/MERR=(accuracy) stats.numEmissionStep / s.yDelta; AbortOnRTE
Resample/DIM=1/UP=(V_numerator)/DOWN=(V_denominator)/N=3 PLEM; AbortOnRTE
catch
err = GetRTError(1)
printf "SMAgetSourceWave: Failed to Resample %s from %d to %d/%d Error: %s\r", stats.strPLEM, DimSize(PLEM, 1), V_numerator, V_denominator, GetRTErrMessage()
endtry
endif
// interpolate along emission Δλ < 1, size > 768
//
// last spectrum is garbage in PLE acquisition.
// Fixed with https://github.com/ukos-git/labview-plem/commit/87b38e6f03b345e5c9823fa79b9dc358dbe251be
target = median(PLEM) // we should have enough noise to fill missing values with median.
for(j = 0; j < max(1, DimSize(PLEM, 1) - 1); j += 1)
Duplicate/FREE/R=[][j] PLEM dummy
Redimension/N=(-1, 0) dummy
// T=1: linear interpolation
// T=3: smoothing spline interpolation
try
Interpolate2/T=1/I=3/Y=targetX stats.wavWavelength, dummy; AbortOnRTE
catch
err = GetRTError(1)
printf "SMAgetSourceWave: Error in interpolate2 for %d in %s\r", j, stats.strPLEM
targetX = NaN
endtry
scale = IndexToScale(PLEM, j, 1)
index = min(dim2 - 1, max(0, ScaleToIndex(target, scale, 1)))
target[][index] = targetX[p]
endfor
WAVE PLEM = removeSpikes(target)
// resample not necessary due to the previous interpolation but more failsafe
accuracy = min(samplingAccuracy, DimSize(targetX, 0) / s.xSize)
RatioFromNumber/MERR=(accuracy) DimSize(targetX, 0) / s.xSize
Resample/DIM=0/UP=(V_numerator)/DOWN=(V_denominator)/N=3 PLEM
Multithread wv[i][] = PLEM[mod(q, dim1)][floor(q / dim1)]
endfor
Duplicate/O wv dfr:$destName/WAVE=wv
if(!graph)
return wv
endif
DoWindow SMAsourceGraph
if(V_flag == 0)
SMAcopyWavelengthToRoot()
Display/N=SMAsourceGraph
AppendImage wv
ModifyImage ''#0 ctab= {*,*,YellowHot256,1}
endif
return wv
End
Function SMARedimensionToMap(wv)
WAVE wv
Variable dim0, dim1v1, dim1v2, dim1
STRUCT PLEMd2Stats stats
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
dim0 = DimSize(stats.wavPLEM, 0)
dim1 = round(DimSize(wv, 0) / dim0)
Redimension/E=1/N=(dim0, dim1) wv
SetScale/P x, DimOffset(stats.wavPLEM, 0), DimDelta(stats.wavPLEM, 0), wv
SetScale/P y, DimOffset(stats.wavPLEM, 1), DimDelta(stats.wavPLEM, 1), wv
End
// @brief Covariance for indices with different detectors
//
// @param indices Wave holding the ids of PLEM spectra
Function SMAgetCovarianceForDifferentSetups(indices)
WAVE/U/I indices
Variable i, numMaps
STRUCT PLEMd2Stats stats
WAVE allDetectors = PLEMd2getDetectors()
numMaps = DimSize(indices, 0)
if(numMaps == 0)
return 1
endif
Make/U/B/N=(numMaps)/FREE detectors = allDetectors[indices[p]]
Extract/FREE indices, indicesSilicon, (detectors[p] == PLEMd2detectorNewton)
WAVE autocorrelation = SMAcovariance(range = indicesSilicon, graph = 0)
Duplicate/O autocorrelation root:covariance_si_diag
WAVE/Z covariance = root:covariance_sym
if(WaveExists(covariance))
Duplicate/O covariance root:covariance_si
endif
Extract/FREE indices, indicesInGaAs, (detectors[p] == PLEMd2detectorIdus)
WAVE autocorrelation = SMAcovariance(range = indicesInGaAs, graph = 0)
Duplicate/O autocorrelation root:covariance_ingaas_diag
WAVE/Z covariance = root:covariance_sym
if(WaveExists(covariance))
Duplicate/O covariance root:covariance_ingaas
endif
KillWaves/Z covariance, autocorrelation
return 0
End
/// @brief calculate symmetric correlation spectra
///
/// NOTE: acts on downsampled data of 25nm spacing
///
/// @param normalized divide all spectra by its maximum
/// @param range specify the spectra ids with a numeric, uint wave
/// @returns a wave reference to the symmetric autocorrelation
Function/WAVE SMAcovariance([normalized, range, graph])
Variable normalized, graph
WAVE/U/I range
Variable replacement
STRUCT SMAsampling s
if(ParamIsDefault(normalized))
normalized = 1
endif
if(ParamIsDefault(graph))
graph = 1
endif
NVAR/Z downsample = root:downsample
if(ParamIsDefault(range))
if(NVAR_EXISTS(downsample))
WAVE source = SMAgetSourceWave(overwrite = 1, graph = 0, downsample = downsample)
else
WAVE source = SMAgetSourceWave(overwrite = 1, graph = 0)
endif
else
if(NVAR_EXISTS(downsample))
WAVE source = SMAgetSourceWave(overwrite = 1, range = range, graph = 0, downsample = downsample)
else
WAVE source = SMAgetSourceWave(overwrite = 1, range = range, graph = 0)
endif
endif
if(numpnts(source) == 0)
Duplicate/O source root:covariance_sym_diag/WAVE=symdiag
return symdiag
endif
// there should be a decent amount of equal noise to remove NaNs
StatsQuantiles/Q source
replacement = V_Q25
MatrixOP/O source = ReplaceNaNs(source, replacement)
// normalize
if(normalized)
MatrixoP/O source = normalizeRows(source)
endif
SMAgetSampling(source, s)
if(s.ySize > 1)
return SMAcovarianceMaps(source)
endif
MatrixOP/O root:covariance_sym/WAVE=sym = syncCorrelation(source)
MatrixOP/O root:covariance_sym_diag/WAVE=symdiag = getDiag(sym, 0)
SMAcopyWavelengthToRoot()
SetScale/P x, s.xMin, s.xDelta, sym, symdiag
SetScale/P y, s.xMin, s.xDelta, sym
if(!graph)
return symdiag
endif
DoWindow SMAcovarianceGraphDiagonal
if(V_flag == 0)
Display/N=SMAcovarianceGraphDiagonal symdiag/TN=diag_syncCorrelation
endif
DoWindow SMAcovarianceGraph
if(V_flag == 0)
Display/N=SMAcovarianceGraph
AppendImage/W=SMAcovarianceGraph sym
endif
return symdiag
End
// @brief get the autocorrelation of a 2d maps wave
//
// @param source give source wave
// @return the symmetric autocorrelation
Function/WAVE SMAcovarianceMaps(source)
WAVE source
STRUCT SMAsampling s
SMAgetSampling(source, s)
if(DimSize(source, 0) > 1)
//MatrixOP/O root:covariance_sym_diag/WAVE=symdiag = getDiag(syncCorrelation(source), 0)
MatrixOP/O root:covariance_sym_diag/WAVE=symdiag = varCols(source)^t
else
Duplicate/O source root:covariance_sym_diag/WAVE=symdiag
endif
Redimension/N=(s.xSize, s.ySize)/E=1 symdiag
SetScale/I x, s.xMin, s.xMax, symdiag
SetScale/I y, s.yMin, s.yMax, symdiag
DoWindow SMAcovarianceImage
if(V_flag == 0)
Display/N=SMAcovarianceImage
AppendImage/W=SMAcovarianceImage symdiag
ModifyImage covariance_sym_diag ctab= {*,*,Terrain256,0}
endif
return symdiag
End
// @brief structure with info for building source waves
//
// @see SMAgetResamplingInformation SMAgetSourceWave
static Structure SMAsampling
Variable xMin, xDelta, xMax, xSize
Variable yMin, yDelta, yMax, ySize
EndStructure
// @brief save the sampling information in the given wave.
//
// requires the JSON_XOP: http://docs.byte-physics.de/json-xop/
//
// @see SMAgetSamplin SMAsampling SMAcovarianceMaps SMAgetSourceWave
static Function SMAsetSampling(wv, s)
WAVE wv
STRUCT SMAsampling &s
Variable jsonID
String wavenote = Note(wv)
if(strlen(wavenote) == 0)
jsonID = JSON_New()
else
jsonID = JSON_Parse(wavenote, ignoreErr = 1)
endif
JSON_AddTreeObject(jsonID, "/scaling/x")
JSON_SetVariable(jsonID, "/scaling/x/min", s.xMin)
JSON_SetVariable(jsonID, "/scaling/x/delta", s.xDelta)
JSON_SetVariable(jsonID, "/scaling/x/max", s.xMax)
JSON_SetVariable(jsonID, "/scaling/x/size", s.xSize)
JSON_AddTreeObject(jsonID, "/scaling/y")
JSON_SetVariable(jsonID, "/scaling/y/min", s.yMin)
JSON_SetVariable(jsonID, "/scaling/y/delta", s.yDelta)
JSON_SetVariable(jsonID, "/scaling/y/max", s.yMax)
JSON_SetVariable(jsonID, "/scaling/y/size", s.ySize)
Note/K wv, JSON_Dump(jsonID)
JSON_Release(jsonID)
End
// @brief get the sampling information back from the given wave.
//
// requires the JSON_XOP: http://docs.byte-physics.de/json-xop/
//
// @see SMAsetSampling SMAsampling SMAcovarianceMaps SMAgetSourceWave
static Function SMAgetSampling(wv, s)
WAVE wv
STRUCT SMAsampling &s
Variable jsonID = JSON_Parse(Note(wv))
s.xMin = JSON_GetVariable(jsonID, "/scaling/x/min")
s.xDelta = JSON_GetVariable(jsonID, "/scaling/x/delta")
s.xMax = JSON_GetVariable(jsonID, "/scaling/x/max")
s.xSize = JSON_GetVariable(jsonID, "/scaling/x/size")
s.yMin = JSON_GetVariable(jsonID, "/scaling/y/min")
s.yDelta = JSON_GetVariable(jsonID, "/scaling/y/delta")
s.yMax = JSON_GetVariable(jsonID, "/scaling/y/max")
s.ySize = JSON_GetVariable(jsonID, "/scaling/y/size")
JSON_Release(jsonID)
End
// @brief analyze a range of maps to get resampling information
//
// NOTE: for equally scaled wave sets taken with equal (detector, grating)
// combination this function should yield the original wave scaling.
// @todo: add unit test
//
// For covariance calculation and any averaging on maps or spectra taken with
// different detectors or gratings, the maps have to get aligned to get
// overlapping pixels. Note that this procedure assumes equally spaced input
// waves and is not accurate when acting i.e. on unequally spaced waves like
// the wavelength waves from the grating waves that are of quadratic or higher
// order distored along the wavelength scale.
//
// Assumes positive delta values
//
// @param[in] indices unsigned integer wave containing the ids of spectra
// to analyze
// @param[out] s @see SMAsampling structure holding all acquired information
// @param[in] range respect fixed setup specific range (grating + detectors)
// @see PLEMd2NanotubeRangePLEM
// @param[in] verbose set output verbosity, default 1 (verbose)
Function SMAgetResamplingInformation(indices, s, [range, verbose])
WAVE/U/I indices
STRUCT SMAsampling &s
Variable range, verbose
Variable i, numMaps, dim0, newSamplingRate
STRUCT PLEMd2Stats stats
range = ParamIsDefault(range) ? 0 : !!range
verbose = ParamIsDefault(verbose) ? 1 : !!verbose
numMaps = DimSize(indices, 0)
Make/D/N=(numMaps)/FREE xCRC, yCRC
Make/N=(numMaps)/FREE excMin, excDelta, excMax, emiMin, emiDelta, emiMax
for(i = 0; i < numMaps; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(indices[i]))
// spectral emission intensity is called emi(ssion)
emiMin[i] = stats.wavWavelength[0]
emiMax[i] = stats.wavWavelength[DimSize(stats.wavWavelength, 0) - 1]
emiDelta[i] = stats.numWLdelta // inaccurate (<0.5nm)
if(range)
emiMin[i] = max(emiMin[i], stats.numDetector == PLEMd2detectorNewton ? 820 : 950)
emiMax[i] = min(emiMax[i], stats.numDetector == PLEMd2detectorNewton ? 1040 : 1250)
endif
xCRC[i] = StringCRC(0, num2str(stats.numGrating))
xCRC[i] = StringCRC(xCRC[i], num2str(stats.numDetector))
xCRC[i] = StringCRC(xCRC[i], num2str(stats.numWLcenter))
// emission from light source is called exc(itation)
excMin[i] = stats.numEmissionStart
excMax[i] = stats.numEmissionEnd
excDelta[i] = stats.numEmissionStep
if(range)
excMin[i] = max(excMin[i], 540)
excMax[i] = min(excMax[i], 750)
endif
yCRC[i] = StringCRC(0, num2str(stats.numEmissionStep))
yCRC[i] = StringCRC(yCRC[i], num2str(stats.numEmissionStart))
endfor
s.xMin = WaveMin(emiMin)
s.xMax = WaveMax(emiMax)
s.xDelta = median(emiDelta)
s.yMin = WaveMin(excMin)
s.yMax = WaveMax(excMax)
s.yDelta = median(excDelta)
if(numMaps < 2)
return 0
endif
// output status information about experiment
if(verbose)
FindDuplicates/FREE/RN=grating xCRC
dim0 = DimSize(grating, 0)
if(dim0 > 1)
printf "SMAgetResamplingInformation: %d different grating/detector setups\r", dim0
for(i = 0; i < dim0; i += 1)
Extract/FREE indices, sameXrange, xCRC[p] == grating[i]
printf "%02d: %d maps\r", i, DimSize(sameXrange, 0)
endfor
endif
FindDuplicates/FREE/RN=excitation yCRC
dim0 = DimSize(excitation, 0)
if(dim0 > 1)
printf "SMAgetResamplingInformation: %d different excitation setups\r", dim0
for(i = 0; i < dim0; i += 1)
Extract/FREE excMin, sameYrange, yCRC[p] == excitation[i]
printf "%02d: %d maps\r", i, DimSize(sameYrange, 0)
endfor
endif
endif
// find best sampling rate for different delta y
//
// do not do such things for xDelta as we can accept the error there but
// not in y where spacing is allowed up to 50nm.
excDelta[] = round(excDelta[p] / samplingAccuracy)
s.yDelta = median(excDelta)
FindDuplicates/FREE/TOL=0/RN=excDeltaUnique excDelta
dim0 = DimSize(excDeltaUnique, 0)
for(i = 0; i < dim0; i += 1)
newSamplingRate = excDeltaUnique[i]
if(mod(newSamplingRate, s.yDelta) != 0)
s.yDelta = gcd(s.yDelta, newSamplingRate )
endif
endfor
FindDuplicates/FREE/TOL=0/RN=excOffsetUnique excMin
dim0 = DimSize(excOffsetUnique, 0)
for(i = 1; i < dim0; i += 1)
newSamplingRate = abs(excOffsetUnique[i] - excOffsetUnique[i - 1])
if(mod(newSamplingRate, s.yDelta) != 0)
s.yDelta = gcd(s.yDelta, newSamplingRate )
endif
endfor
s.yDelta *= samplingAccuracy
End
// copy the wavelength from PLEM
// this should be a PLEMd2 function
//
// @param numPLEM [optional] specify the id of the spectrum where wavelength comes from.
Function/WAVE SMAcopyWavelengthToRoot([numPLEM])
variable numPLEM
variable numPoints
STRUCT PLEMd2Stats stats
numPLEM = ParamIsDefault(numPLEM) ? 0 : numPLEM
PLEMd2statsLoad(stats, PLEMd2strPLEM(numPLEM))
Duplicate/O stats.wavWavelength root:wavelength/WAVE=wavelength
// @todo: delete wavelengthImage here as it adds wrong assumtion. Instead use SetScale where 2D Waves need to be plotted.
Duplicate/O stats.wavWavelength root:wavelengthImage/WAVE=wavelength_graph
numPoints = DimSize(wavelength, 0)
Redimension/N=(numPoints + 1) wavelength_graph
wavelength_graph[numPoints] = wavelength_graph[numPoints - 1] + 1
return wavelength
End
// copy the excitation wavelength from PLEM
// this should be a PLEMd2 function
//
// @param numPLEM [optional] specify the id of the spectrum where wavelength comes from.
Function/WAVE SMAcopyExcitationToRoot([numPLEM])
variable numPLEM
variable numPoints
STRUCT PLEMd2Stats stats
numPLEM = ParamIsDefault(numPLEM) ? 0 : numPLEM
PLEMd2statsLoad(stats, PLEMd2strPLEM(numPLEM))
if(DimSize(stats.wavPLEM, 1) < 2)
Abort "Not a PLE map"
endif
Duplicate/O stats.wavWavelength root:excitation/WAVE=excitation
// @todo: delete wavelengthImage here as it adds wrong assumtion. Instead use SetScale where 2D Waves need to be plotted.
Duplicate/O stats.wavExcitation root:excitationImage/WAVE=excitation_image
numPoints = DimSize(excitation, 0)
Redimension/N=(numPoints + 1) excitation_image
excitation_image[numPoints] = excitation_image[numPoints - 1] + 1
return excitation
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
Function SMAdisplayOriginal([numPLEM])
Variable numPLEM
Variable xStart, xEnd, yStart, yEnd
if(ParamIsDefault(numPLEM))
numPLEM = SMAgetOriginalFromMarquee()
endif
// save graph axis settings
GetAxis/Q bottom
if(!!V_flag)
print "SMAdisplayOriginal: Error getting bottom axis in top Graph"
return -1
endif
yStart = V_min
yEnd = V_max
GetAxis/Q left
if(!!V_flag)
print "SMAdisplayOriginal: Error getting left axis in top Graph"
return -1
endif
xStart = V_min
xEnd = V_max
Variable offsetX, offsetY
SMAgetOffset(offsetX, offsetY)
Plemd2displaybynum(numPLEM)
// copy graph axis settings
GetAxis/Q bottom
if(!!V_flag)
print "SMAdisplayOriginal: Error getting bottom axis in top Graph"
return -1
endif
SetAxis bottom, yStart + offsetY, yEnd + offsetY
GetAxis/Q left
if(!!V_flag)
print "SMAdisplayOriginal: Error getting left axis in top Graph"
return -1
endif
SetAxis left, xStart + offsetX, xEnd + offsetX
End
// get center coordinate from marquee and display search the image that matches those coordinates closest
Function SMAgetOriginalFromMarquee()
Variable centerX, centerY
GetMarquee left, bottom //V_bottom, V_top, V_left and V_right
if (V_flag == 0)
return -1
endif
centerY = V_left + (V_left - V_right) / 2
centerX = V_bottom + (V_bottom - V_top) / 2
return SMAgetFirstImage(centerX, centerY, 150)
End
// returns the index of the image where the specified coordinates are located
Function SMAgetFirstImage(centerX, centerY, centerZ)
Variable centerX, centerY, centerZ
Variable accuracy = 0
Variable index
WAVE coordinates = PLEMd2getcoordinates(forceRenew=1)
do
accuracy += 10
WAVE/Z indices = CoordinateFinderXYZ(coordinates, centerX, centerY, centerZ, accuracy = accuracy, verbose = 0)
if(!WaveExists(indices))
continue
endif
index = indices[0]
while(!!numtype(index) && accuracy < 1e4)
if(index > PLEMd2getmapsavailable())
print "SMAgetFirstImage: Index out of range"
return -1
endif
if(!!numtype(index))
return -1
endif
return index
End
Function SMADuplicateRangeFromMarquee()
String win
WAVE wv = SMAduplicateRange(SMAgetOriginalFromMarquee())
if(!WaveExists(wv))
return 1
endif
win = "win_" + NameOfWave(wv)
Display/N=$win as win
AppendImage wv
ModifyGraph width={Plan,1,bottom,left}
ModifyImage ''#0 ctab= {*,*,RedWhiteBlue256,0}
End
Function SMADuplicateRangeFromCoordinates(coordinates)
WAVE coordinates
String name, win, strPath
Variable i
Variable numCoordinates = DimSize(coordinates, 0)
String coordinatesName = NameOfWave(coordinates)
String experimentName = IgorInfo(1)
if(DimSize(coordinates, 1) < 3)
Abort "Need at least 2 coordinates"
endif
PathInfo home
strPath = S_Path + experimentName
NewPath/C/O/Z images, strPath
for(i = 0; i < numCoordinates; i += 1)
sprintf name, "%s_image%03d", coordinatesName, i
SMADisplayCoordinates(coordinates[i][0], coordinates[i][1], range = 3) // set axis for SMAduplicateRange
DoUpdate/W=win_SMAimageStack
WAVE wv = SMAduplicateRange(SMAgetFirstImage(coordinates[i][0], coordinates[i][1], coordinates[i][2]), outputName = name)
Save/C/O/P=images wv
// create image for standard range
Redimension/U/I wv
Display/N=temp
win = S_name
AppendImage/W=$win wv
ModifyImage/W=$win $"#0" ctab= {0,*,YellowHot,0}
ModifyGraph/W=$win nticks=0, axthick=0, margin=1, width={Plan,1,bottom,left}
SetDrawLayer/W=$win UserFront
SetDrawEnv/W=$win linethick= 5,linefgc= (56797,56797,56797)
DrawLine/W=$win 0.822437513922712,0.1,0.944949852649121,0.1
SetDrawEnv/W=$win fsize= 24,fstyle= 1,textrgb= (65535,65535,65535)
DrawText/W=$win 0.82122905027933,0.25,"1µm"
DoUpdate/W=$win
saveWindow(win, customName = name, path = "images", saveJSON = 1, saveTiff = 1, saveImages = 0)
// cleanup
KillWindow/Z $win
KillWaves/Z wv
endfor
End
// read globally set offset variables and give instructions on how to update them.
// set the input variables to their global values.
Function SMAgetOffset(offsetX, offsetY)
Variable &offsetX, &offsetY
// manually set using: SMAtasksZeroToCursor()
NVAR/Z gOffsetX = root:offsetX
if(NVAR_Exists(gOffsetX))
offsetX = gOffsetX
endif
NVAR/Z gOffsetY = root:offsetY
if(NVAR_Exists(gOffsetY))
offsetY = gOffsetY
endif
End
Function SMAsetOffset(offsetX, offsetY)
Variable offsetX, offsetY
NVAR/Z gOffsetX = root:offsetX
if(!NVAR_Exists(gOffsetX))
Variable/G root:offsetX
NVAR gOffsetX = root:offsetX
endif
NVAR/Z gOffsetY = root:offsetY
if(!NVAR_Exists(gOffsetY))
Variable/G root:offsetY
NVAR gOffsetY = root:offsetY
endif
gOffsetX = offsetX
gOffsetY = offsetY
End
Function SMAaddOffset(addX, addY)
Variable addX, addY
Variable offsetX, offsetY
SMAgetOffset(offsetX, offsetY)
SMAsetOffset(offsetX + addX, offsetY + addY)
End
Function SMADisplayCoordinates(xCoordinate, yCoordinate, [range])
Variable xCoordinate, yCoordinate
Variable range
String win = "win_SMAimageStack" // use this image
if(ParamIsDefault(range))
range = 2 // extract 2µm in x- and 2*2µm in y-direction
endif
DoWindow/F $win
if(!V_flag)
Abort "Create SMAimageStack first"
endif
SetAxis/W=$win left, xCoordinate - range, xCoordinate + range
SetAxis/W=$win bottom, yCoordinate - 2 * range, yCoordinate + 2 * range
DoUpdate/W=$win
End
Function/WAVE SMAduplicateRange(FirstImage, [outputName])
String outputName
Variable FirstImage
Variable i, numPLEM
Variable offsetX, offsetY
Variable dim2 = 1
Variable StackSize = 24
Variable zStep = 1
if(ParamIsDefault(outputName))
outputName = "imageRange"
outputName = UniqueName(outputName, 1, 0)
endif
// get range from axis settings (not intuitive for marquee!)
GetAxis/Q left
if(!!V_flag)
return $""
endif
Variable xstart = V_min
Variable xend = V_max
GetAxis/Q bottom
if(!!V_flag)
return $""
endif
Variable ystart = V_min
Variable yend = V_max
SMAorderAsc(xStart, xEnd)
SMAorderAsc(yStart, yEnd)
SMAgetOffset(offsetX, offsetY)
Struct PLEMd2stats stats
PLEMd2statsLoad(stats, PLEMd2strPLEM(FirstImage))
WAVE imagestack = getTopWindowImage()
if(WaveExists(imagestack))
dim2 = DimSize(imagestack, 2)
endif
// prepare output wave container
Duplicate/O/R=(yStart + offsetY, yEnd + offsetY)(xStart + offsetX, xEnd + offsetX) stats.wavPLEM $outputName/WAVE=wv
Redimension/N=(-1, -1, dim2) wv
// set z Axis
WAVE zAxis = PLEMd2getCoordinates()
if(FirstImage + StackSize < PLEMd2getMapsAvailable())
zStep = zAxis[FirstImage][2] - zAxis[FirstImage + StackSize][2]
endif
SetScale/P z, zAxis[FirstImage][2], zStep, wv
// set x,y Axis offset
AddWaveScaleOffset(wv, offsetY, offsetX)
// write output wave
for(i = 0; i < dim2; i += 1)
numPLEM = FirstImage + i * StackSize
PLEMd2statsLoad(stats, PLEMd2strPLEM(numPLEM))
Duplicate/FREE/R=(yStart + offsetY, yEnd + offsetY)(xStart + offsetX, xEnd + offsetX) stats.wavPLEM image
wv[][][i] = image[p][q]
endfor
SMASetCoordinates(wv, (yEnd + yStart) / 2, (xEnd + xStart) / 2 )
return wv
End
Function SMASetCoordinates(wv, yCoordinate, xCoordinate)
WAVE wv
Variable yCoordinate, xCoordinate
Variable start, ende
String wavenote = note(wv)
start = strsearch(wavenote, "x-position", start)
ende = strsearch(wavenote, "\r", start)
wavenote = wavenote[0, start - 1] + "x-position: " + num2str(xCoordinate) + wavenote[ende, inf]
start = strsearch(wavenote, "y-position", start)
ende = strsearch(wavenote, "\r", start)
wavenote = wavenote[0, start - 1] + "y-position: " + num2str(yCoordinate) + wavenote[ende, inf]
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
// append all Images to one big Image (fullimage)
Function/WAVE SMAmergeImages([createNew, indices])
Variable createNew
WAVE/U/I indices
Variable pixelX, pixelY, resolution, imageborders
Variable positionX, positionY
Variable numMaps
Variable i, j, k, dim0, dim1
variable imagearea = 320
STRUCT PLEMd2Stats stats
Variable numMapsAvailable = PLEMd2getMapsAvailable()
if(numMapsAvailable == 0)
SMAread()
numMapsAvailable = PLEMd2getMapsAvailable()
endif
NVAR/Z gquick = root:numFullCalcultions
if(!NVAR_EXISTS(gquick))
Variable/G root:numFullCalcultions = 0
NVAR gquick = root:numFullCalcultions
endif
Variable quick = !gquick // quick fix for quick logic
if(ParamIsDefault(indices))
Make/FREE/N=(numMapsAvailable)/U/I indices = p
endif
createNew = ParamIsDefault(createNew) ? 1 : !!createNew
if(!createNew)
WAVE/Z fullimage = root:fullimage
if(WaveExists(fullimage))
return fullimage
endif
WaveClear fullimage
endif
Variable timerRefNum = StartMSTimer
wave/Z background = root:backgroundImage
if(!WaveExists(background))
wave background = SMAestimateBackground()
Duplicate/O background root:backgroundImage
endif
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
// create output image
resolution = (abs(DimDelta(stats.wavPLEM, 0)) + abs(DimDelta(stats.wavPLEM, 1))) / 2
WAVE imageRange = ImageDimensions(indices)
dim0 = abs(imageRange[%x][%max] - imageRange[%x][%min]) / resolution
dim1 = abs(imageRange[%y][%max] - imageRange[%y][%min]) / resolution
Make/O/N=(dim0, dim1) root:fullimage/WAVE=fullimage = 0
Make/FREE/B/U/N=(dim0, dim1) fullimagenorm = 0
SetScale/I x, imageRange[%x][%min], imageRange[%x][%max], fullimage
SetScale/I y, imageRange[%y][%min], imageRange[%y][%max], fullimage
// create intermediate image
dim0 = DimSize(stats.wavPLEM, 0)
dim1 = DimSize(stats.wavPLEM, 1)
Make/FREE/N=(dim0, dim1) currentImage
// add current image to output image
numMaps = DimSize(indices, 0)
for(i = 0; i < numMaps; i += 1)
if(numtype(indices[i]) != 0)
continue
endif
PLEMd2statsLoad(stats, PLEMd2strPLEM(indices[i]))
MultiThread currentImage[][] = stats.wavPLEM[p][q] - background[p][q]
if(!quick)
ImageFilter/O /N=5 median currentImage // remove spikes
endif
for(j = 0; j < dim0; j += 1)
positionX = IndexToScale(stats.wavPLEM, j, 0)
pixelX = ScaleToIndex(fullimage, positionX, 0)
if((pixelX < 0) || (pixelX > DimSize(fullimage, 0) - 1))
continue
endif
for(k = 0; k < dim1; k += 1)
if(numtype(currentImage[j][k]) != 0)
continue
endif
positionY = IndexToScale(stats.wavPLEM, k, 1)
pixelY = ScaleToIndex(fullimage, positionY, 1)
if((pixelY < 0) || (pixelY > DimSize(fullimage, 1) - 1))
continue
endif
fullimage[pixelX][pixelY] += currentImage[j][k]
fullimagenorm[pixelX][pixelY] += 1
endfor
endfor
endfor
MultiThread fullimage[][] = fullimagenorm[p][q] == 0 ? NaN : fullimage[p][q] / fullimagenorm[p][q]
// interpolate values, that were not found directly
if(!quick)
MultiThread fullimagenorm[][] = numtype(fullimage[p][q]) == 2
if(sum(fullimagenorm) / (dim0 * dim1) < 0.01)
ImageFilter/O NanZapMedian fullimage
endif
endif
SMAbuildGraphFullImage()
lap(timerRefNum, "SMAmergeImages")
return fullimage
End
// input a wave stackCoordinates and search for the coordinates included in it.
// the wave stackCoordinates is split to coordinate lists that have the size stackSize.
// the function can be called multiple times with varying stackNumber to merge differnt
// parts of the coordinate list.
Function/WAVE SMAmergeStack(stackCoordinates, stackNumber, stackSize, [createNew])
WAVE stackCoordinates
Variable stackNumber, stackSize
Variable createNew
Variable rangeStart, rangeEnd
createNew = ParamIsDefault(createNew) ? 1 : !!createNew
rangeStart = stackNumber * stackSize
rangeEnd = (stackNumber + 1) * stackSize - 1
Duplicate/FREE/R=[rangeStart, rangeEnd][] stackCoordinates scan
WAVE/U/I found = SMAreduceIndices(SMAfindCoordinatesInPLEM(scan))
make/free/n=(stackSize) normalnumber = numType(found[p]) == 0
if(sum(normalnumber) < stackSize / 4)
return $""
endif
WAVE fullimage = SMAmergeImages(indices = found, createNew = createNew)
SMAreduceRange(fullimage, bit = 8)
SMAconvertWaveToUint(fullimage, bit = 8)
return fullimage
End
Function/WAVE SMAprocessImageStack([coordinates, createNew])
WAVE coordinates
Variable createNew
Variable i, numFullImages, numImages
createNew = ParamIsDefault(createNew) ? 1 : !!createNew
if(ParamIsDefault(coordinates))
//WAVE coordinates = SMAcameraCoordinates(export = 0)
WAVE coordinates = PLEMd2getCoordinates()
endif
numImages = PLEMd2getMapsAvailable()
if(numImages == 0)
SMAread()
numImages = PLEMd2getMapsAvailable()
WAVE coordinates = PLEMd2getCoordinates(forceRenew = 1)
endif
if(!WaveExists(coordinates))
Abort
endif
numFullImages = floor(numImages / 24)
Wave fullimage = SMAmergeStack(coordinates, 0, 24)
WAVE/Z imagestack = root:SMAimagestack
if(DimSize(fullimage, 0) != DimSize(imagestack, 0) && DimSize(fullimage, 1) != DimSize(imagestack, 1))
Duplicate/O fullimage root:SMAimagestack/WAVE=imagestack
else
Multithread imagestack[][][0] = fullimage[p][q]
endif
Redimension/N=(-1, -1, numFullImages) imagestack
for(i = 1; i < numFullImages; i += 1)
Wave fullimage = SMAmergeStack(coordinates, i, 24, createNew = createNew)
if(WaveExists(fullimage))
MultiThread imagestack[][][i] = fullimage[p][q]
endif
endfor
SMAimageStackopenWindow()
return imagestack
End
// only valid for images
Function SMAmergeTimeSeries()
Variable i
Variable numImages = PLEMd2getMapsAvailable()
STRUCT PLEMd2Stats stats
if(numImages == 0)
SMAload()
endif
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
Duplicate/O stats.wavPLEM root:SMAimagestack/WAVE=imagestack
Redimension/N=(-1, -1, numImages) imagestack
for(i = 1; i < numImages; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
MultiThread imagestack[][][i] = stats.wavPLEM[p][q]
endfor
SMAimageStackopenWindow()
End
// see ACW_EraseMarqueeArea.
Function SMA_ExtractSumMarqueeArea()
variable pStart, pEnd, qStart, qEnd
variable i, dim2, cursorExists
string sourcewin, destwin
variable normalization = 0
string outputName = "timetrace"
sourcewin = WinName(0, 1)
destwin = outputName
GetMarquee left, bottom //V_bottom, V_top, V_left and V_right
if (V_flag == 0)
return 0
endif
WAVE/Z image = getTopWindowImage()
pStart = ScaleToIndex(image, V_left, 0)
pEnd = ScaleToIndex(image, V_right, 0)
qStart = ScaleToIndex(image, V_bottom, 1)
qEnd = ScaleToIndex(image, V_top, 1)
SMAorderAsc(pStart, pEnd)
SMAorderAsc(qStart, qEnd)
DoWindow $destwin
if(!V_Flag)
Display/N=$destwin
endif
outputName = UniqueName(outputName, 1, 0)
dim2 = DimSize(image, 2)
Make/N=(dim2) $outputName/WAVE=wv
cursorExists = strlen(CsrInfo(A)) > 0 && strlen(CsrInfo(B)) > 0
if(cursorExists)
print "substracting area between cursors as background for marquee area"
endif
for(i = 0; i < dim2; i += 1)
Duplicate/FREE/R=[pStart, pEnd][qStart, qEnd][i] image, marqueearea
if(cursorExists)
Duplicate/FREE/R=[pcsr(a, sourcewin), pcsr(b, sourcewin)][qcsr(a, sourcewin), qcsr(b, sourcewin)][i] image, reference
// background for marquearea
normalization = sum(reference) / (DimSize(reference, 0) * DimSize(reference, 1)) * (DimSize(marqueearea, 0) * DimSize(marqueearea, 1))
endif
wv[i] = sum(marqueearea) - normalization
endfor
AppendToGraph/W=$destwin wv
print outputname
End
// changes input wv to the maximum value, specified in root:numMaxValue.
// The value numMaxValue is relative to the bits of the output wave.
// Information is lost
Function SMAreduceRange(wv, [bit])
WAVE wv
Variable bit
Variable wMax, wMin, numSpace
bit = ParamIsDefault(bit) ? 32 : bit
numSpace = 2^bit - 1
NVAR/Z numMaxValue = root:numMaxValue
if(!NVAR_EXISTS(numMaxValue))
Variable/G root:numMaxValue = numSpace
NVAR numMaxValue = root:numMaxValue
endif
NVAR/Z numMinValue = root:numMinValue
if(!NVAR_EXISTS(numMinValue))
Variable/G root:numMinValue = 0
NVAR numMinValue = root:numMinValue
endif
if(numMaxValue < numSpace)
wMax = WaveMax(wv) / numSpace * numMaxValue
MultiThread wv = wv[p][q] > wMax ? wMax : wv[p][q]
endif
if(numMinValue > 0)
wMin = WaveMin(wv) / numSpace * numMinValue
MultiThread wv = wv[p][q] < wMin ? wMin : wv[p][q]
endif
End
// save storage by converting image to full uint
Function SMAconvertWaveToUint(wv, [bit])
WAVE wv
Variable bit
Variable wMin, wMax
Variable numSpace
bit = ParamIsDefault(bit) ? 32 : bit
numSpace = 2^bit - 1
wMin = WaveMin(wv)
wv -= wMin
wMax = WaveMax(wv)
wv[][] = round(wv[p][q] / wMax * numSpace)
switch(bit)
case 16:
Redimension/W/U wv // 16bit
break
case 8:
Redimension/B/U wv // 8bit
break
case 32:
default:
Redimension/I/U wv // 32bit
endswitch
End
Function/S SMAbuildGraphPLEM()
Variable i, range_min, range_max
String ImageNames
STRUCT PLEMd2Stats stats
String graphName = "SMAgetCoordinatesGraph"
NVAR gnumMapsAvailable = $(cstrPLEMd2root + ":gnumMapsAvailable")
DoWindow $graphName
if(V_flag != 0)
return graphName
endif
Display/W=(400,40,1200,650)/N=$graphName
graphName = S_name
WAVE wavCoordinates = root:coordinates
if(WaveExists(wavCoordinates))
AppendToGraph/W=$graphName wavCoordinates[][0]/TN=coordinates vs wavCoordinates[][1]
ModifyGraph/W=$graphName mode(coordinates)=3,marker(coordinates)=1,msize(coordinates)=2
endif
for(i = 0; i < gnumMapsAvailable; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
range_min = WaveMin(stats.wavPLEM)
range_max = WaveMax(stats.wavPLEM)
AppendImage/W=$graphName stats.wavPLEM
endfor
ImageNames = ImageNameList("", ";")
for(i = 0; i < gnumMapsAvailable; i += 1)
ModifyImage/W=$graphName $StringFromList(i, ImageNames) ctab= {range_min,range_max,Terrain,0}
endfor
return graphName
End
Function/S SMAbuildGraphFullImage()
String graphName = "SMAgetCoordinatesfullImage"
DoWindow $graphName
if(V_flag == 0)
Display/W=(400,40,1200,650)/N=$graphName
graphName = S_name
wave image = root:fullimage
if(!WaveExists(image))
Make/N=(2,2) root:fullimage/WAVE=image
endif
AppendImage/W=$graphName root:fullimage
ModifyImage/W=$graphName fullimage ctab= {*,*,Blue,1}
ModifyGraph/W=$graphName mirror=0
endif
return graphName
End
Function SMAtestSizeAdjustment()
Variable i
variable dim4size = 10
Variable dim4offset = 0.9760
Variable dim4delta = 0.0001
NVAR/Z numSizeAdjustment = root:numSizeAdjustment
if(!NVAR_EXISTS(numSizeAdjustment))
Variable/G root:numSizeAdjustment = 1
NVAR/Z numSizeAdjustment = root:numSizeAdjustment
endif
// load for magnification
STRUCT PLEMd2Stats stats
PLEMd2statsLoad(stats, PLEMd2strPLEM(1))
WAVE imagestack = SMAprocessImageStack(createNew = 0)
Duplicate/O imagestack root:SMAsizeAdjustment/WAVE=wv
Redimension/N=(-1, -1, -1, dim4size) wv
SetScale/P t, dim4offset, dim4delta, wv
Make/O/N=(dim4size) root:SMAnumSizeAdjustment/WAVE=dim4 = dim4offset + p * dim4delta
for(i = 0; i < dim4size; i += 1)
numSizeAdjustment = (dim4offset + i * dim4delta)
dim4[i] = stats.numMagnification / numSizeAdjustment
SMAreset(power = 0, photon = 0)
WAVE imagestack = SMAprocessImageStack(createNew = 1)
Multithread wv[][][][i] = imagestack[p][q][r]
endfor
DoWindow/F win_SMAimageStack
End
Function/WAVE SMAestimateBackground()
Variable pVal, qVal
Variable i
Variable originalQ25, originalQ75, resultingQ25, resultingQ75
Variable V_fitOptions=4 // used to suppress CurveFit dialog
Variable V_FitQuitReason // stores the CurveFit Quit Reason
Variable V_FitError // Curve Fit error
WAVE medianImage = SMAgetMedian(overwrite = 1)
Duplicate/FREE medianImage background
ImageFilter NaNZapMedian background // rotation rotation induced borders
ImageFilter/O/N=5 median background // remove spikes
Smooth 5, background // smooth along the trenches (spikes)
ImageFilter/O/N=101/P=3 avg background // reduce information
// align wave so that it has somewhat equal boundaries as original
StatsQuantiles/Q medianImage
originalQ75 = V_Q75
StatsQuantiles/Q background
resultingQ75 = V_Q75
background[][] = background[p][q] / resultingQ75 * originalQ75
StatsQuantiles/Q medianImage
originalQ25 = V_Q25
StatsQuantiles/Q background
resultingQ25 = V_Q25
background[][] = background[p][q] - resultingQ25 + originalQ25
// set to gaussian background from illumination if possible
Make/O/T/N=3 T_Constraints = {"K1 > 0","K3 > 0","K5 > 0"}
V_FitError = 0
CurveFit/Q Gauss2D background /C=T_Constraints
if(V_FitError == 0)
Wave W_coef, W_sigma
W_coef[] = abs(W_sigma[p] / W_coef[p]) > 0.3 ? NaN : W_coef[p]
if(numType(sum(W_coef) == 0))
background = Gauss2D(W_coef, x, y)
endif
WaveClear W_coef, W_sigma
endif
KillWaves/Z T_Constraints
return background
End
Function/WAVE SMAgetMedian([overwrite])
Variable overwrite
Variable i, dim0, dim1
Variable pVal, qVal
Struct PLEMd2Stats stats
NVAR gnumMapsAvailable = $(cstrPLEMd2root + ":gnumMapsAvailable")
overwrite = ParamIsDefault(overwrite) ? 0 : !!overwrite
WAVE/Z myMedian = root:SMAmedian
if(WaveExists(myMedian) && !overwrite)
return myMedian
endif
WaveClear myMedian
PLEMd2statsLoad(stats, PLEMd2strPLEM(1))
dim0 = DimSize(stats.wavPLEM, 0)
dim1 = DimSize(stats.wavPLEM, 1)
dim1 = dim1 != 0 ? dim1 : 1 // dim1 = 0 and dim1 = 1 is the same
Make/O/N=(dim0, dim1) root:SMAmedianBackground/WAVE=myMedian
SetScale/P x, 0, 1, myMedian
SetScale/P y, 0, 1, myMedian
// calculate median of all images
//Make/O/N=(dim0, dim1, gnumMapsAvailable) root:SMAmedianMatrix/WAVE=bgMatrix
Make/FREE/N=(dim0, dim1, gnumMapsAvailable) bgMatrix
for(i = 0; i < gnumMapsAvailable; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
if(dim1 != DimSize(stats.wavPLEM, 1))
continue
endif
if(dim1 == 1)
bgMatrix[][0][i] = stats.wavPLEM[p]
else
bgMatrix[][][i] = stats.wavPLEM[p][q]
endif
endfor
for(i = 0; i < dim0 * dim1; i += 1)
pVal = mod(i, dim0)
qVal = floor(i / dim0)
Duplicate/FREE/R=[pVal][qVal][0,*] bgMatrix, currentPixel
myMedian[pVal][qVal] = median(currentPixel)
WaveClear currentPixel
endfor
Duplicate/o bgmatrix root:temp
WaveClear bgMatrix
if(dim1 == 1)
Redimension/N=(dim0) myMedian
endif
return myMedian
End
Function/WAVE SMAWigner(numWigner, [transposed, forceReNew])
Variable numWigner, transposed, forceReNew
transposed = ParamIsDefault(transposed) ? 1 : !!transposed
forceReNew = ParamIsDefault(forceReNew) ? 0 : !!forceReNew
WAVE image = root:WignerSource
if(!WaveExists(image))
Abort "No Source defined for WignerTransform"
endif
if(transposed)
WAVE/Z complete = root:WignerFullHor
else
WAVE/Z complete = root:WignerFullVert
endif
if(forceReNew | !WaveExists(complete))
if(transposed)
WAVE complete = CreateWignerHor()
else
WAVE complete = CreateWignerVert()
endif
endif
if(transposed)
DelayUpdate
WAVE output = root:WignerImageHor
Multithread output = complete[p][q][numWigner]
MatrixOP/O root:WignerProfileSumHor/WAVE=WignerProfileSum = sqrt(sumcols((output*output)^t)^t))
else
//WIP
MatrixOP/O root:WignerProfileVert/WAVE=profile = sumcols(output)^t)
endif
SetScale/P x, DimOffset(image, !transposed), DimDelta(image, !transposed), WignerProfileSum
return output
End
Function/WAVE CreateWignerVert()
Variable i, j, dim0, dim1, dim3
WAVE image = root:WignerSource
dim0 = DimSize(image, 0) - 1
dim1 = floor(DimSize(image, 1) / 2) * 2
dim3 = dim1 / 2 + 1
MatrixOP/O root:LineProfileVert/WAVE=LineProfileVert = sumcols(image)^t)
SetScale/P x, DimOffset(image, 1), DimDelta(image, 1), LineProfileVert
Redimension/N=(dim1) LineProfileVert
Make/N=(dim1)/O root:LineProfileVertXdummy = DimOffset(image, 1) + p * DimDelta(image, 1)
Make/N=(dim0, dim1)/O root:WignerProfileVert/WAVE=WignerProfileVert
WignerTransform/DEST=WignerProfileVert LineProfileVert
MatrixOP/O root:WignerProfileSumVert/WAVE=WignerProfileSumVert = sqrt(sumcols((WignerProfileVert*WignerProfileVert)^t)^t))
SetScale/P x, DimOffset(image, 1), DimDelta(image, 1), WignerProfileSumVert
Make/N=(dim1)/O root:WignerProfileSumVertXdummy = DimOffset(image, 1) + p * DimDelta(image, 1)
// WIP
Make/N=(dim0, dim1)/O root:WignerImageVert/WAVE=output
Make/N=(dim0, dim1, dim3)/O root:WignerFullVert/WAVE=complete
Make/N=(dim1)/O root:LineProfile/WAVE=current_line
Make/N=(dim1)/O root:WignerProfile/WAVE=current_wigner
for(i = 0; i < dim1; i += 1)
current_line = image[i][p]
WignerTransform/DEST=current_wigner current_line
MultiThread complete[i][][] = current_wigner[q][r]
endfor
output = complete[p][q][0]
return complete
End
Function/WAVE CreateWignerHor()
Variable i, j, dim0, dim1, dim3
WAVE image = root:WignerSource
dim0 = floor(DimSize(image, 0) / 2) * 2
dim1 = DimSize(image, 1) - 1
dim3 = dim0 / 2 + 1
MatrixOP/O root:LineProfileHor/WAVE=LineProfileHor = sumcols(image^t)^t)
SetScale/P x, DimOffset(image, 0), DimDelta(image, 0), LineProfileHor
Redimension/N=(dim0) LineProfileHor
Make/N=(dim0, dim1)/O root:WignerProfileHor/WAVE=WignerProfileHor
WignerTransform/DEST=WignerProfileHor LineProfileHor
MatrixOP/O root:WignerProfileSumHor/WAVE=WignerProfileSumHor = sqrt(sumcols((WignerProfileHor*WignerProfileHor)^t)^t))
SetScale/P x, DimOffset(image, 0), DimDelta(image, 0), WignerProfileSumHor
Make/N=(dim0, dim1)/O root:WignerImageHor/WAVE=output
CopyScales image, output
Make/N=(dim0, dim1, dim3)/O root:WignerFullHor/WAVE=complete
Make/N=(dim0)/O root:LineProfile/WAVE=current_line
Make/N=(dim0)/O root:WignerProfile/WAVE=current_wigner
for(i = 0; i < dim1; i += 1)
current_line = image[p][i]
WignerTransform/DEST=current_wigner current_line
complete[][i][] = current_wigner[p][r]
endfor
output = complete[p][q][0]
return complete
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
// structure idea taken from info (igor-file-loader)
// https://github.com/ukos-git/igor-file-loader
// released under MIT license by same author @ukos-git
static strConstant cstructure = "structure" // path for global vars in Package dfr
static strConstant cpeakfit = "peakFit" // path for temp peakfit waves
static Constant cversion = 0004
Structure SMAinfo
Variable numVersion, numSpectra
DFREF dfrStructure
WAVE/WAVE wavSpectra, wavPeakFind
EndStructure
static Function SMAstructureInitGlobalVariables()
DFREF dfrPeakFit = SMApeakfitDF()
DFREF dfrStructure = SMAstructureDF()
createNVAR("numVersion", dfr = dfrStructure, set = cversion)
createNVAR("numSpectra", dfr = dfrStructure, init = 0)
End
static Function SMAstructureInitWaves()
DFREF dfrStructure = SMAstructureDF()
WAVE/Z/WAVE/SDFR=dfrStructure wavSpectra = spectra
if(!WaveExists(wavSpectra))
Make/WAVE dfrStructure:spectra/WAVE=wavSpectra
endif
WAVE/Z/WAVE/SDFR=dfrStructure wavPeakFind = peakfind
if(!WaveExists(wavPeakFind))
Make/WAVE dfrStructure:peakfind/WAVE=wavPeakFind
endif
End
Function SMAstructureLoad(info)
STRUCT SMAinfo &info
Variable SetDefault = 0
if(!SMAstructureIsInit())
SMApackageInitDF(info)
SMAstructureUpdate(info)
endif
DFREF info.dfrStructure = SMAstructureDF()
if(DataFolderRefStatus(info.dfrStructure) == 0)
print "SMAstructureLoad: \tUnexpected Behaviour."
endif
if(DataFolderRefStatus(info.dfrStructure) == 0)
print "SMAstructureLoad: \tUnexpected Behaviour."
endif
NVAR/Z/SDFR=info.dfrStructure numVersion
if(numVersion < cversion)
print "SMAstructureLoad: \tVersion Change detected."
printf "current Version: \t%04d\r", numVersion
SMAstructureUpdate(info)
printf "new Version: \t%04d\r", numVersion
endif
info.numVersion = numVersion
info.numSpectra = loadNVAR("numSpectra", dfr = info.dfrStructure)
WAVE/WAVE/SDFR=info.dfrStructure info.wavSpectra = spectra
WAVE/WAVE/SDFR=info.dfrStructure info.wavPeakFind = peakfind
End
Function SMAstructureSave(info)
STRUCT SMAinfo &info
DFREF dfrstructure = SMAstructureDF()
saveNVAR("numVersion", info.numVersion, dfr = dfrStructure)
saveNVAR("numSpectra", info.numSpectra, dfr = dfrStructure)
End
static Function/S SMApackageDF()
return "root:Packages:" + PossiblyQuoteName(cSMApackage)
End
static Function/DF SMAstructureDF()
string strDFR = SMApackageDF() + ":" + cstructure
DFREF dfr = $strDFR
return dfr
End
Function/DF SMApeakfitDF()
string strDFR = SMApackageDF() + ":" + cpeakfit
DFREF dfr = $strDFR
return dfr
End
static Function SMAstructureIsInit()
DFREF dfrStructure = SMAstructureDF()
if(!DataFolderRefStatus(dfrStructure))
return 0
endif
NVAR/Z/SDFR=dfrStructure numVersion
if(!NVAR_EXISTS(numVersion))
return 0
endif
return 1
End
static Function SMApackageInitDF(info)
STRUCT SMAinfo &info
DFREF dfrSave = GetDataFolderDFR()
SetDataFolder root:
NewDataFolder/O/S Packages
NewDataFolder/O $cSMApackage
SetDataFolder dfrSave
End
static Function SMAstructureInitDF(info)
STRUCT SMAinfo &info
DFREF dfr = $SMApackageDF()
DFREF new = dfr:$cstructure
if(DataFolderRefStatus(new) == 0)
NewDataFolder dfr:$cstructure
endif
End
static Function SMApeakfitInitDF(info)
STRUCT SMAinfo &info
DFREF dfr = $SMApackageDF()
DFREF new = dfr:$cpeakfit
if(DataFolderRefStatus(new) == 0)
NewDataFolder dfr:$cpeakfit
endif
End
static Function SMAstructureUpdate(info)
STRUCT SMAinfo &info
SMAstructureInitDF(info)
SMApeakfitInitDF(info)
SMAstructureInitGlobalVariables()
SMAstructureInitWaves()
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | #include <ImageSlider>
#include <AxisSlider>
#include <Color Table Control Panel>
Window SMAintensityAnalysis() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(240,50,784.5,445.25) as "intensity_analysis"
AppendImage nanotubes_transposed
ModifyImage nanotubes_transposed ctab= {0,315,Red,1}
ModifyGraph margin(right)=141,width={Aspect,1}
ModifyGraph grid=1
ModifyGraph mirror=0
SetAxis left -5,105
SetAxis bottom -5,105
ColorScale/C/N=text0/F=0/A=MC/X=67.56/Y=3.78 image=nanotubes_transposed
SetDrawLayer UserFront
EndMacro
Window SMAcameraFocusPointsGraph() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(825.75,299.75,1220.25,508.25) SMAcameraIntensity[160,*] as "zAxisIntensityv2"
AppendToGraph/T SMAcameraIntensity
AppendToGraph SMAcameraIntensity[0,79],SMAcameraIntensity[80,159]
AppendToGraph SMAcameraIntensitySmth
ModifyGraph userticks(bottom)={SMAcameraPlanePeakMaximum,SMAcameraPlanePeakMaximumT}
ModifyGraph userticks(top)={SMAcameraPlanePeakMaximumZ,SMAcameraPlanePeakMaximumZT}
ModifyGraph mode(SMAcameraIntensity#1)=3
ModifyGraph marker(SMAcameraIntensity#1)=8
ModifyGraph lSize(SMAcameraIntensity)=2,lSize(SMAcameraIntensity#2)=2,lSize(SMAcameraIntensity#3)=2
ModifyGraph rgb(SMAcameraIntensity#2)=(0,0,0),rgb(SMAcameraIntensity#3)=(1,16019,65535)
ModifyGraph msize(SMAcameraIntensity#1)=2,msize(SMAcameraIntensity#2)=2,msize(SMAcameraIntensity#3)=2
ModifyGraph grid(bottom)=1
SetAxis left 0,*
Label left "laser spot intensity"
Label bottom "(x,y) position"
Label top "z position"
EndMacro
Function SMAimageStackopenWindow()
NVAR/Z numSizeAdjustment = root:numSizeAdjustment
if(!NVAR_EXISTS(numSizeAdjustment))
Variable/G root:numSizeAdjustment = 1
endif
NVAR/Z numSizeAdjustmentSingleStack = root:numSizeAdjustmentSingleStack
if(!NVAR_EXISTS(numSizeAdjustmentSingleStack))
Variable/G root:numSizeAdjustmentSingleStack = 0
endif
DoWindow win_SMAimageStack
if(!V_flag)
Execute "win_SMAimageStack()"
WMAppendAxisSlider()
WAVE/Z imagestack = root:SMAimagestack
if(WaveExists(imagestack) && (DimSize(imagestack, 2) > 1))
WMAppend3DImageSlider()
endif
WMColorTableControlPanel#createColorTableControlPanel()
endif
DoWindow/F win_SMAimageStack
End
Window win_SMAimageStack() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(451.8,164.6,925.2,642.2)
AppendImage SMAimagestack
ModifyImage SMAimagestack ctab= {0,255,RedWhiteBlue256,0}
ModifyGraph width={Plan,1,bottom,left},height=396.85
ModifyGraph grid(left)=1
ModifyGraph mirror(left)=2,mirror(bottom)=0
ModifyGraph nticks=10
ModifyGraph minor=1
ModifyGraph fSize=8
ModifyGraph standoff=0
ModifyGraph axOffset(left)=0.428571
ModifyGraph gridRGB(left)=(26205,52428,1)
ModifyGraph tkLblRot(left)=90
ModifyGraph btLen=3
ModifyGraph tlOffset=-2
ModifyGraph manTick(left)={0,20,0,0},manMinor(left)={4,5}
ModifyGraph manTick(bottom)={0,20,0,0},manMinor(bottom)={4,0}
ControlBar 45
GroupBox CBSeparator0,pos={0.00,0.00},size={472.80,2.40}
Slider WMAxSlSl,pos={49.80,9.00},size={402.60,6.00},proc=WMAxisSliderProc
Slider WMAxSlSl,limits={0,1,0},value= 0.5,side= 0,vert= 0,ticks= 0
PopupMenu WMAxSlPop,pos={9.60,4.80},size={15.60,15.60},proc=WMAxSlPopProc
PopupMenu WMAxSlPop,mode=0,value= #"\"Instructions...;Set Axis...;Zoom Factor...;Resync position;Resize;Remove\""
NewPanel/HOST=#/EXT=0/W=(0,0,216,438.6) as "sizeAdjustment"
ModifyPanel cbRGB=(65534,65534,65534), fixedSize=0
SetDrawLayer UserBack
SetDrawEnv dash= 6,fillfgc= (61166,61166,61166)
DrawRect 15,87,186,145.8
DrawText 37.2,109.8,"scaling"
Button mergeImageStack,pos={54.00,297.00},size={99.00,18.00},proc=ButtonProcMergeImages,title="mergeImageStack"
SetVariable cnumSizeAdjustment,pos={6.00,12.00},size={186.00,13.80}
SetVariable cnumSizeAdjustment,limits={0.9,1.1,0.001},value= numSizeAdjustment
CheckBox checkSizeAdjustment,pos={33.00,51.00},size={80.40,12.00},title="only current stack"
CheckBox checkSizeAdjustment,variable= numSizeAdjustmentSingleStack
Button save,pos={456.00,54.00},size={75.00,24.00},proc=ButtonProcSMAImageStackSave,title="simple save"
Button save,labelBack=(65535,65535,65535)
Button save1,pos={54.00,343.80},size={99.00,18.00},proc=ButtonProcSMAImageStackSave,title="simple save"
Button save1,labelBack=(65535,65535,65535)
SetVariable cnumRotationAdjustment,pos={6.00,27.00},size={186.00,13.80}
SetVariable cnumRotationAdjustment,limits={-5,5,0.1},value= numRotationAdjustment
CheckBox SMAimagestack_check_fullcalc,pos={30.00,66.00},size={42.00,12.00},title="full calc"
CheckBox SMAimagestack_check_fullcalc,variable= numFullCalcultions
Button sizeAdjustment,pos={54.00,321.00},size={99.00,18.00},proc=ButtonProcSizeAdjustment,title="sizeAdjustment"
SetVariable cnumMin,pos={36.00,120.00},size={60.00,13.80},title="min"
SetVariable cnumMin,limits={0,255,1},value= numMinValue
SetVariable cnumMax,pos={102.00,120.00},size={60.00,13.80},title="max"
SetVariable cnumMax,limits={0,255,1},value= numMaxValue
RenameWindow #,P0
SetActiveSubwindow ##
NewPanel/HOST=#/EXT=1/W=(18.6,0,0,438.6) as "controls"
ModifyPanel cbRGB=(65534,65534,65534), fixedSize=0
Slider WMAxSlY,pos={6.00,6.00},size={6.00,408.00},proc=SliderProcSMAimageStackY
Slider WMAxSlY,limits={0,1,0},value= 0.644677661169415,side= 0,ticks= 0
RenameWindow #,P1
SetActiveSubwindow ##
EndMacro
Function SliderProcSMAimageStackY(sa) : SliderControl
STRUCT WMSliderAction &sa
switch( sa.eventCode )
case -1: // control being killed
break
default:
if( sa.eventCode & 1 ) // value set
String grfName= WinName(0, 1)
SVAR/Z axisName = root:Packages:WMAxisSlider:$(grfName):gAxisName
if(!SVAR_EXISTS(axisName))
break
endif
axisName = "left"
WMAxisSliderProc(sa.ctrlName, sa.curval, sa.eventCode)
endif
break
endswitch
return 0
End
Function SliderProcSMAimageStackX(sa) : SliderControl
STRUCT WMSliderAction &sa
switch( sa.eventCode )
case -1: // control being killed
break
default:
if( sa.eventCode & 1 ) // value set
String grfName= WinName(0, 1)
SVAR axisName = root:Packages:WMAxisSlider:$(grfName):gAxisName
axisName = "bottom"
WMAxisSliderProc(sa.ctrlName, sa.curval, sa.eventCode)
endif
break
endswitch
return 0
End
Function ButtonProcSMAImageStackSave(ba) : ButtonControl
STRUCT WMButtonAction &ba
NVAR/Z cnumLayer = root:Packages:WM3DImageSlider:win_SMAimageStack:gLayer
if(!NVAR_EXISTS(cnumLayer))
return 0
endif
variable i
variable numLayers = 8 // hard coded
variable zaxis
switch( ba.eventCode )
case 2: // mouse up
for(i = 0; i < numLayers; i += 1)
cnumLayer=i
WM3DImageSliderProc("",0,0)
zaxis = 150 - i * 0.5 // hard coded
TextBox/C/N=zAxis "\\JL\\Z24z=" + num2str(round(zaxis * 10)/10) + "µm"
SavePICT/O/P=home/E=-5/B=288 as "mkl12_focusscan_" + num2str(round(zaxis * 10)) + ".png"
endfor
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcMergeImages(ba) : ButtonControl
STRUCT WMButtonAction &ba
variable numLayer = 0
NVAR singleStack = root:numSizeAdjustmentSingleStack
NVAR/Z cnumLayer = root:Packages:WM3DImageSlider:win_SMAimageStack:gLayer
if(NVAR_EXISTS(cnumLayer))
numLayer = cnumLayer
endif
switch( ba.eventCode )
case 2: // mouse up
smareset(power = 0, photon = 0)
WAVE coordinates = PLEMd2getCoordinates(forceRenew = 0)
if(singleStack)
Wave fullimage = SMAmergeStack(coordinates, numLayer, 24)
WAVE imagestack = root:SMAimagestack
MultiThread imagestack[][][numLayer] = fullimage[p][q]
else
SMAprocessImageStack(coordinates = coordinates, createNew = 1)
endif
break
case -1: // control being killed
break
endswitch
return 0
End
Function ButtonProcSizeAdjustment(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
SMAtestsizeAdjustment()
break
case -1: // control being killed
break
endswitch
return 0
End
// derives from WMColorTableControlPanel#SliderProc
Function SMAfullstackSliderProc(sa) : SliderControl
STRUCT WMSliderAction &sa
string target
string colorPanel = "ColorTableControlPanel"
string SMAfullimageGraph = "win_SMAimageStack"
switch( sa.eventCode )
case -1: // control being killed
break
case 9: // mouse moved && mouse down
DoWindow $colorPanel
if(!V_flag)
WMColorTableControlPanel#createColorTableControlPanel()
endif
Slider highSliderSC, win=$colorPanel, limits={0,255,1}
Slider lowSliderSC, win=$colorPanel, limits={0,255,1}
target = StringFromList(0, ImageNameList(SMAfullimageGraph, ";")) + "*"
PopupMenu selectTracePU, win=$colorPanel, popmatch=target
WMColorTableControlPanel#SliderProc(sa)
break
endswitch
return 0
End
Function ListBoxProc_SMAselect(lba) : ListBoxControl
STRUCT WMListboxAction &lba
Variable row = lba.row
Variable col = lba.col
WAVE/T/Z listWave = lba.listWave
WAVE/Z selWave = lba.selWave
switch( lba.eventCode )
case -1: // control being killed
break
case 1: // mouse down
break
case 3: // double click
break
case 4: // cell selection
case 5: // cell selection plus shift key
WAVE selectedMaps = PLEMd2getWaveMapsSelection()
Extract listWave, selectedMaps, selWave[p] == 1
break
case 6: // begin edit
break
case 7: // finish edit
break
case 13: // checkbox clicked (Igor 6.2 or later)
break
endswitch
return 0
End
Function ButtonProc_SMAselectPower(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
// click code here
break
case -1: // control being killed
break
endswitch
return 0
End
Window SMAselectWaves() : Panel
PauseUpdate; Silent 1 // building window...
NewPanel /W=(306,137,806,237) as "select waves"
ListBox mapsAvailable,pos={0.00,0.00},size={200.00,100.00},proc=ListBoxProc_SMAselect
ListBox mapsAvailable,userdata(ResizeControlsInfo)= A"!!*'\"z!!#AW!!#@,z!!#](Aon\"Qzzzzzzzzzzzzzz!!#`-A7TLfzz"
ListBox mapsAvailable,userdata(ResizeControlsInfo) += A"zzzzzzzzzzzz!!#u:Du]k<zzzzzzzzzzz"
ListBox mapsAvailable,userdata(ResizeControlsInfo) += A"zzz!!#?(FEDG<zzzzzzzzzzzzzz!!!"
ListBox mapsAvailable,listWave=root:Packages:SMA:mapsavailable
ListBox mapsAvailable,selWave=root:Packages:SMA:mapsselected,mode= 4
ListBox mapsSelected,pos={206.00,0.00},size={200.00,100.00}
ListBox mapsSelected,userdata(ResizeControlsInfo)= A"!!,G^z!!#AW!!#@,z!!#`-A7TLfzzzzzzzzzzzzzz!!#o2B4uAezz"
ListBox mapsSelected,userdata(ResizeControlsInfo) += A"zzzzzzzzzzzz!!#u:Du]k<zzzzzzzzzzz"
ListBox mapsSelected,userdata(ResizeControlsInfo) += A"zzz!!#?(FEDG<zzzzzzzzzzzzzz!!!"
ListBox mapsSelected,listWave=root:Packages:SMA:mapsselection
Button extractpower,pos={414.00,2.00},size={81.00,25.00},proc=ButtonProc_SMAselectPower,title="extract power"
Button extractpower,userdata(ResizeControlsInfo)= A"!!,I5!!#7a!!#?[!!#=+z!!#o2B4uAezzzzzzzzzzzzzz!!#o2B4uAezz"
Button extractpower,userdata(ResizeControlsInfo) += A"zzzzzzzzzzzz!!#u:Du]k<zzzzzzzzzzz"
Button extractpower,userdata(ResizeControlsInfo) += A"zzz!!#u:Du]k<zzzzzzzzzzzzzz!!!"
SetWindow kwTopWin,hook(ResizeControls)=ResizeControls#ResizeControlsHook
SetWindow kwTopWin,userdata(ResizeControlsInfo)= A"!!*'\"z!!#C_!!#@,zzzzzzzzzzzzzzzzzzzzz"
SetWindow kwTopWin,userdata(ResizeControlsInfo) += A"zzzzzzzzzzzzzzzzzzzzzzzzz"
SetWindow kwTopWin,userdata(ResizeControlsInfo) += A"zzzzzzzzzzzzzzzzzzz!!!"
Execute/Q/Z "SetWindow kwTopWin sizeLimit={375,75,inf,inf}" // sizeLimit requires Igor 7 or later
EndMacro
Window SMAHistogram() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(256.5,314.75,653.25,522.5) fit_histResult,histResult,histResult as "SMAHistogram"
ModifyGraph mode(histResult#1)=5
ModifyGraph lSize(fit_histResult)=2,lSize(histResult)=2
ModifyGraph rgb(fit_histResult)=(65535,0,0,32768),rgb(histResult)=(0,0,0)
NewPanel/HOST=#/EXT=0/W=(0,0,78,278)
Slider slider0,pos={16.00,30.00},size={54.00,244.00},proc=SMAHistogramSliderProc
Slider slider0,limits={0,25,1},value= 1
CheckBox check_fit,pos={20.00,11.00},size={26.00,15.00},title="fit"
CheckBox check_fit,variable= checkbox_fit
RenameWindow #,P0
SetActiveSubwindow ##
EndMacro
Function SMAHistogramSliderProc(sa) : SliderControl
STRUCT WMSliderAction &sa
variable resolution = 2.5
variable width = 100
SVAR/Z diffwave = root:diffwave
if(!SVAR_EXists(diffwave))
return 0
endif
NVAR checkbox_fit = root:checkbox_fit
switch( sa.eventCode )
case -1: // control being killed
break
default:
if( sa.eventCode & 1 ) // value set
Variable curval = sa.curval
wave wv = $diffwave
Duplicate/O wv diff
wave histResult
diff = p < curval ? 0 : wv[p] - wv[p - curval]
Histogram/B={-(width - 1)/2,resolution,abs((width - 1)/resolution)} diff, histResult
if(checkbox_fit)
CurveFit/M=2/W=0 lor, histResult/D
endif
endif
break
endswitch
return 0
End
Window SMAwignerHor() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(1803,147.2,2486.4,1053.2)/L=left_LineProfileHor LineProfileHor as "SMAwignerHor"
AppendToGraph/L=left_WignerProfileSumHor WignerProfileSumHor
AppendImage/L=left_WignerImageHor WignerImageHor
ModifyImage WignerImageHor ctab= {-10000000000,10000000000,RedWhiteBlue,0}
AppendImage WignerSource
ModifyImage WignerSource ctab= {*,*,BlueHot,0}
ModifyImage WignerSource minRGB=0,maxRGB=NaN
AppendImage/L=left_WignerHor WignerProfileHor
ModifyImage WignerProfileHor ctab= {-39810717055349.7,39810717055349.7,RedWhiteBlue,0}
ModifyGraph margin(left)=42,margin(right)=127,width={Plan,1,bottom,left}
ModifyGraph grid(bottom)=1,grid(left_WignerImageHor)=1,grid(left)=1
ModifyGraph mirror(bottom)=0,mirror(left)=0
ModifyGraph nticks(left_LineProfileHor)=0,nticks(bottom)=2,nticks(left_WignerProfileSumHor)=0
ModifyGraph nticks(left_WignerImageHor)=2,nticks(left)=2,nticks(left_WignerHor)=0
ModifyGraph minor(bottom)=1
ModifyGraph noLabel(bottom)=2,noLabel(left_WignerImageHor)=2,noLabel(left)=2
ModifyGraph axOffset(left)=2.61538
ModifyGraph gridRGB(bottom)=(34952,34952,34952),gridRGB(left_WignerImageHor)=(34952,34952,34952)
ModifyGraph gridRGB(left)=(34952,34952,34952)
ModifyGraph axRGB(bottom)=(0,0,0,0),axRGB(left_WignerProfileSumHor)=(65535,65535,65535,0)
ModifyGraph axRGB(left_WignerImageHor)=(0,0,0,0),axRGB(left)=(0,0,0,0)
ModifyGraph lblPosMode(left_LineProfileHor)=1,lblPosMode(left_WignerHor)=1
ModifyGraph lblPos(bottom)=49,lblPos(left)=67,lblPos(left_WignerHor)=34
ModifyGraph lblLatPos(left_WignerHor)=13
ModifyGraph freePos(left_LineProfileHor)={0,kwFraction}
ModifyGraph freePos(left_WignerProfileSumHor)={0,kwFraction}
ModifyGraph freePos(left_WignerImageHor)={0,kwFraction}
ModifyGraph freePos(left_WignerHor)={0,kwFraction}
ModifyGraph axisEnab(left_LineProfileHor)={0.25,0.4}
ModifyGraph axisEnab(left_WignerProfileSumHor)={0.85,1}
ModifyGraph axisEnab(left_WignerImageHor)={0.6,0.85}
ModifyGraph axisEnab(left)={0,0.25}
ModifyGraph axisEnab(left_WignerHor)={0.4,0.6}
ModifyGraph manTick(left_LineProfileHor)={0,0,0,2},manMinor(left_LineProfileHor)={0,50}
ModifyGraph manTick(bottom)={0,2,0,0},manMinor(bottom)={0,50}
ModifyGraph manTick(left_WignerProfileSumHor)={0,0,0,2},manMinor(left_WignerProfileSumHor)={0,50}
ModifyGraph manTick(left_WignerImageHor)={0,2,0,0},manMinor(left_WignerImageHor)={0,50}
ModifyGraph manTick(left)={0,2,0,0},manMinor(left)={0,0}
ModifyGraph manTick(left_WignerHor)={0,0,0,2},manMinor(left_WignerHor)={0,50}
Label left_LineProfileHor "spacial emission\rintensity [a.u]"
Label left_WignerHor "momentum [1/µm]\r(k-space)"
Cursor/P/I/S=2/H=3/NUML=2 A WignerProfileHor -1194,8
ColorScale/C/N=WignerProfileColorScale/F=0/A=LB/X=74.01/Y=38.01/E=2
ColorScale/C/N=WignerProfileColorScale image=WignerProfileHor, heightPct=25
ColorScale/C/N=WignerProfileColorScale nticks=1, minor=1, prescaleExp=-12
ColorScale/C/N=WignerProfileColorScale tickUnit=1, ZisZ=1
AppendText "Wigner Intensity"
ColorScale/C/N=WignerImageScaleBar/F=0/A=LB/X=74.45/Y=61.16/E=2
ColorScale/C/N=WignerImageScaleBar image=WignerImageHor, heightPct=25, nticks=3
ColorScale/C/N=WignerImageScaleBar highTrip=10, notation=1, ZisZ=1
AppendText "Wigner Intensity |8⟩"
ColorScale/C/N=imageColorScale/F=0/A=LB/X=74.01/Y=3.88/E=2 image=WignerSource
ColorScale/C/N=imageColorScale heightPct=25
AppendText "intensity [a.u.]"
SetDrawLayer UserFront
SetDrawEnv linethick= 4,linefgc= (65535,65535,65535),fillfgc= (0,0,0),fsize= 16,textrgb= (65535,65535,65535)
SetDrawEnv gstart,gname= scalebarBottom
DrawLine 0.1,0.777306733167082,0.3,0.777306733167082
SetDrawEnv fsize= 16,textrgb= (65535,65535,65535)
DrawText 0.133442126514132,0.800504987531172,"0µm"
SetDrawEnv linethick= 4,linefgc= (65535,65535,65535),fillfgc= (0,0,0),fsize= 16,textrgb= (65535,65535,65535)
SetDrawEnv gstop
SetDrawEnv gstart,gname= scalebarTop
SetDrawEnv linefgc= (0,0,0)
DrawLine 0.1,0.177556109725685,0.3,0.177556109725685
SetDrawEnv fsize= 16
DrawText 0.133442126514132,0.200754364089775,"0µm"
SetDrawEnv linethick= 4,linefgc= (65535,65535,65535),fillfgc= (0,0,0),fsize= 16,textrgb= (65535,65535,65535)
SetDrawEnv gstop
SetDrawEnv gstart,gname= wigner_selection
SetDrawEnv xcoord= prel,ycoord= left_WignerHor,fillfgc= (65535,65535,65535,32768)
DrawRect 0,0.51098896382061,1,0.579120825663358
SetDrawEnv gstop
NewPanel/HOST=#/EXT=1/W=(30,0,0,567)
ModifyPanel fixedSize=0
SetDrawLayer UserBack
SetDrawEnv gstart,gname= wigner_selection
DrawRect 0.05,1.19586670935928,0.95,1.29552226847255
SetDrawEnv gstop
Slider slider0,pos={0.00,18.00},size={38.40,498.00},proc=SMASliderProcWignerHor
Slider slider0,limits={0,64,1},value= 8
RenameWindow #,P0
SetActiveSubwindow ##
EndMacro
Function SMASliderProcWignerHor(sa) : SliderControl
STRUCT WMSliderAction &sa
switch( sa.eventCode )
case -1: // control being killed
break
default:
if( sa.eventCode & 1 ) // value set
Variable curval = sa.curval
DelayUpdate
SMAWigner(sa.curval)
WAVE wv = root:WignerImageHor
Variable scaleEven = getEvenScale(wv)
ModifyImage/W=SMAwignerHor WignerImageHor ctab= {-1 * scaleEven, scaleEven,RedWhiteBlue,0}
DoWindow WignerGizmo
if(V_flag)
ModifyGizmo/N=WignerGizmo ModifyObject=WignerImage,objectType=surface,property={surfaceMaxRGBA, scaleEven, 0, 0, 1, 1}
ModifyGizmo/N=WignerGizmo ModifyObject=WignerImage,objectType=surface,property={surfaceMinRGBA, -1 * scaleEven, 1, 0, 0, 1}
endif
WAVE wv = root:WignerProfileHor
scaleEven = getEvenScale(wv)
ModifyImage/W=SMAwignerHor WignerProfileHor ctab= {-1 * scaleEven,scaleEven,RedWhiteBlue,0}
WAVE wv = root:WignerProfileHor
Cursor/W=SMAwignerHor/I A WignerProfileHor 115.42, IndexToScale(wv, sa.curval, 1)
ColorScale/W=SMAwignerHor/C/N=WignerImageScaleBar "Wigner Intensity |" + num2str(sa.curval) + "⟩"
SetDrawLayer/W=SMAwignerHor UserFront
DrawAction/W=SMAwignerHor getgroup=wigner_selection, delete
if(sa.curval > 26)
break
endif
SetDrawEnv/W=SMAwignerHor gstart, gname=wigner_selection
SetDrawEnv/W=SMAwignerHor xcoord= prel,ycoord= left_WignerHor
SetDrawEnv/W=SMAwignerHor fillfgc= (65535,65535,65535,32768)
Variable rectStart = DimOffset(wv, 1) + (sa.curval - 0.5) * DimDelta(wv, 1)
Variable rectEnd = DimOffset(wv, 1) + (sa.curval + 0.5) * DimDelta(wv, 1)
DrawRect/W=SMAwignerHor 0, rectStart, 1, rectEnd
SetDrawEnv/W=SMAwignerHor gstop
endif
break
endswitch
return 0
End
Window WignerGizmo() : GizmoPlot
PauseUpdate; Silent 1 // building window...
// Building Gizmo 7 window...
NewGizmo/T="WignerGizmo"/W=(1119.6,235.4,1609.8,474.8)
ModifyGizmo startRecMacro=700
ModifyGizmo scalingOption=63
AppendToGizmo Surface=root:WignerImageHor,name=WignerImage
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ lineColorType,1}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ fillMode,3}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ lineWidth,2}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ srcMode,0}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ lineColor,0.666667,0.666667,0.666667,1}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ surfaceCTab,RedWhiteBlue256}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ SurfaceCTABScaling,100}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ surfaceMinRGBA,-1e+10,1,0,0,1}
ModifyGizmo ModifyObject=WignerImage,objectType=surface,property={ surfaceMaxRGBA,1e+10,0,0,1,1}
ModifyGizmo modifyObject=WignerImage,objectType=Surface,property={calcNormals,1}
AppendToGizmo Axes=boxAxes,name=axes0
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={-1,axisScalingMode,1}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={-1,axisColor,0,0,0,1}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={0,ticks,3}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={1,ticks,3}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={2,ticks,3}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={0,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={1,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={2,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={3,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={4,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={5,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={6,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={7,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={8,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={9,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={10,visible,0}
ModifyGizmo ModifyObject=axes0,objectType=Axes,property={11,visible,0}
ModifyGizmo modifyObject=axes0,objectType=Axes,property={-1,Clipped,0}
ModifyGizmo setDisplayList=0, object=axes0
ModifyGizmo setDisplayList=1, object=WignerImage
ModifyGizmo autoscaling=1
ModifyGizmo currentGroupObject=""
ModifyGizmo showInfo
ModifyGizmo infoWindow={1863,0,2695,313}
ModifyGizmo endRecMacro
ModifyGizmo SETQUATERNION={0.551374,-0.180123,-0.254025,0.773960}
EndMacro
Window SMAmapsSum() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(412.5,56.75,799.5,303.5) peakExcitation vs peakEmission as "SMAmapsSum"
AppendImage mapsSum
ModifyImage mapsSum ctab= {0,*,Spectrum,0}
ModifyGraph mode=3
ModifyGraph marker=19
ModifyGraph rgb=(65535,65535,65535)
ModifyGraph useMrkStrokeRGB=1
ModifyGraph zmrkSize(peakExcitation)={peakHeight,0,*,1,10}
ModifyGraph mirror=0
Label left "excitation / nm"
Label bottom "emission / nm"
SetAxis left 525,*
EndMacro
Window SMApeakMaximum() : Graph
PauseUpdate; Silent 1 // building window...
Display /W=(39,178.25,425.25,425) peakExcitation vs peakEmission as "SMApeakMaximum"
ModifyGraph mode=3
ModifyGraph marker=19
ModifyGraph zmrkSize(peakExcitation)={peakHeight,0,*,1,10}
Label left "excitation / nm"
Label bottom "emission / nm"
SetAxis left 525,765
EndMacro
Window SMAexactscanImage() : Graph
PauseUpdate; Silent 1 // building window...
String fldrSav0= GetDataFolder(1)
SetDataFolder root:PLEMd2:
Display /W=(963,138.5,1316.25,413.75) coordinates[*][0]/TN=AcN vs coordinates[*][1] as "SMAexactscanImage"
AppendImage ::borders
ModifyImage borders explicit= 1
ModifyImage borders eval={0,65535,65535,65535}
ModifyImage borders eval={255,-1,-1,-1}
ModifyImage borders eval={1,13107,13107,13107}
AppendImage ::trenches
ModifyImage trenches explicit= 1
ModifyImage trenches eval={0,65535,65535,65535}
ModifyImage trenches eval={255,-1,-1,-1}
ModifyImage trenches eval={1,52428,52428,52428}
SetDataFolder fldrSav0
ModifyGraph margin(left)=7,margin(bottom)=7,margin(top)=7,margin(right)=85,expand=-1
ModifyGraph width={Plan,1,bottom,left}
ModifyGraph mode=3
ModifyGraph marker=29
ModifyGraph mrkThick=0.1
ModifyGraph gaps=0
ModifyGraph mrkStrokeRGB=(0,0,0,6554)
ModifyGraph zmrkSize(AcN)={peakHeight,0,*,0,5}
ModifyGraph zColor(AcN)={peakLocation,800,1300,dBZ14}
ModifyGraph mirror=0
ModifyGraph noLabel=2
ModifyGraph axRGB(left)=(0,0,0,0),axRGB(bottom)=(65535,65535,65535,0)
ModifyGraph manTick(left)={0,40,0,0},manMinor(left)={9,5}
ModifyGraph manTick(bottom)={0,40,0,0},manMinor(bottom)={9,5}
SetAxis left -5,300
SetAxis bottom -5,300
ColorScale/C/N=text0/F=0/A=LB/X=102.55/Y=4.55 trace=AcN
AppendText "central emission wavelength [nm]"
SetDrawLayer UserFront
SetDrawEnv xcoord= bottom,ycoord= left,linethick= 5
DrawLine 308.107553969184,287.5,358.107553969184,287.5
SetDrawEnv xcoord= bottom,ycoord= left
DrawText 317.7649537407,269.625,"50µm"
EndMacro
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
// requires IM FILO (igor-file-loader) version 0002
// https://github.com/ukos-git/igor-file-loader
#include "FILOmain"
#include "FILOprefs"
#include "FILOstructure"
#include "FILOtools"
// requires igor-common-utilites
// https://github.com/ukos-git/igor-common-utilities
#include "common-utilities"
// requires PLEM (igor-swnt-plem)
// https://github.com/ukos-git/igor-swnt-plem
#include "plem"
strConstant cSMApackage = "swnt-mass-analysis"
StrConstant cstrSMAroot = "root:Packages:SMA:"
Function SMAload()
FILO#load(fileType = ".ibw", packageID = 1)
SMAupdatePath()
End
Function SMAadd()
FILO#load(fileType = ".ibw", packageID = 1, appendToList = 1)
SMAupdatePath()
End
Function SMAfileInfo()
STRUCT FILO#experiment filos
FILO#structureLoad(filos)
Struct SMAprefs prefs
SMAloadPackagePrefs(prefs)
printf "SMAfileInfo: reading %d files from\r", ItemsInList(filos.strFileList)
printf "path: %s\r", prefs.strBasePath
printf "folder: %s\r", filos.strFolder
printf "file0: %s\r", StringFromList(0, filos.strFileList)
End
Function SMAread()
String file, files
Variable numFiles, i, error
String strPath = ""
Struct SMAprefs prefs
STRUCT FILO#experiment filos
SMAupdatePath() // update old paths
SMAloadPackagePrefs(prefs)
FILO#structureLoad(filos)
if(ItemsInList(filos.strFileList) == 0)
SMAload()
FILO#structureLoad(filos)
endif
files = filos.strFileList
file = StringFromList(0, filos.strFileList)
if(!cmpstr(file[0], ":"))
files = FILO#AddPrefixToListItems(prefs.strBasePath, files)
endif
// status
SMAfileInfo()
numFiles = ItemsInList(files)
for(i = 0; i < numFiles; i += 1)
file = StringFromList(i, files)
GetFileFolderInfo/Q/Z=1 file
if(!V_isFile)
printf "SMAread: Could not find %s\r", file
error += 1
endif
endfor
if(error > 0)
printf "SMAread: %d errors.", error
Abort "SMAread: Errors in file list"
endif
// load files
for(i = 0; i < numFiles; i += 1)
file = StringFromList(i, files)
printf "SMAread %03d: \t%s\r", i, file
PLEMd2Open(strFile = file, display = 0)
endfor
// hotfix for file load
file = StringFromList(0, files)
PLEMd2Open(strFile = file, display = 0)
End
Function SMAupdatePath()
String file, folder
Struct SMAprefs prefs
STRUCT FILO#experiment filos
FILO#structureLoad(filos)
SMAloadPackagePrefs(prefs)
filos.strFolder = FILO#RemovePrefixFromListItems(prefs.strBasePath, filos.strFolder)
filos.strFolder = RemoveEnding(filos.strFolder, ";")
filos.strFileList = FILO#RemovePrefixFromListItems(prefs.strBasePath, filos.strFileList)
// legacy format support
file = StringFromList(0, filos.strFileList)
if(!!cmpstr(file[0], ":"))
if(!cmpstr(file[0], "D")) // measurements were saved on drive d
filos.strFolder = FILO#RemovePrefixFromListItems("D", filos.strFolder)
filos.strFileList = FILO#RemovePrefixFromListItems("D", filos.strFileList)
filos.strFolder = ":data" + filos.strFolder
filos.strFileList = FILO#AddPrefixToListItems(":data", filos.strFileList)
elseif(!cmpstr(file[0], "Z"))
filos.strFolder = FILO#RemovePrefixFromListItems("Z", filos.strFolder)
filos.strFileList = FILO#RemovePrefixFromListItems("Z", filos.strFileList)
elseif(!cmpstr(file[0], "W"))
filos.strFolder = FILO#RemovePrefixFromListItems("W", filos.strFolder)
filos.strFileList = FILO#RemovePrefixFromListItems("W", filos.strFileList)
endif
endif
file = prefs.strBasePath + StringFromList(0, filos.strFileList)
GetFileFolderInfo/Q/Z=1 file
if(!V_isFile)
print filos.strFileList
Abort "File Not found"
endif
folder = prefs.strBasePath + filos.strFolder
GetFileFolderInfo/Q/Z=1 folder
if(!V_isFolder)
print filos.strFolder
Abort "Folder Not found"
endif
FILO#structureSave(filos)
End
Function SMAmapInfo()
String strPLEM
Variable i
variable numSpectra = PLEMd2getMapsAvailable()
STRUCT PLEMd2Stats stats
STRUCT SMAinfo info
SMAstructureLoad(info)
info.numSpectra = numSpectra
Redimension/N=(info.numSpectra) info.wavSpectra
for(i = 0; i < numSpectra; i += 1)
strPLEM = PLEMd2strPLEM(i)
PLEMd2statsLoad(stats, strPLEM)
info.wavSpectra[i] = stats.wavPLEM
endfor
SMAstructureSave(info)
End
Function SMAgetBestSpectra(bestEnergy)
variable bestEnergy
variable i, j, numPeaks
variable peakEnergy, peakHeight
variable bestIntensity
string secondBestPLEM, currentPLEM
string bestPLEM = ""
variable numSpec = PLEMd2getMapsAvailable()
STRUCT PLEMd2Stats stats
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
for(i = 0; i < numSpec; i += 1)
currentPLEM = PLEMd2strPLEM(i)
PLEMd2statsLoad(stats, currentPLEM)
WAVE peaks = SMApeakFind(stats.wavPLEM, createwaves = 0)
numPeaks = DimSize(peaks, 0)
for(j = 0; j < numPeaks; j += 1)
peakEnergy = peaks[j][%location]
peakHeight = peaks[j][%height]
if(abs(peakEnergy - bestEnergy) < 5)
print currentPLEM
if(peakHeight > bestIntensity)
bestIntensity = peakHeight
secondBestPLEM = bestPLEM
bestPLEM = currentPLEM
endif
endif
endfor
endfor
PLEMd2Display(bestPLEM)
PLEMd2Display(secondBestPLEM)
End
Function SMAgetMaximum(bestEnergy)
variable bestEnergy
variable i, j, numPeaks
variable peakEnergy, peakHeight
variable bestIntensity
string secondBestPLEM, currentPLEM
string bestPLEM = ""
variable numSpec = PLEMd2getMapsAvailable()
STRUCT PLEMd2Stats stats
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
for(i = 0; i < numSpec; i += 1)
currentPLEM = PLEMd2strPLEM(i)
PLEMd2statsLoad(stats, currentPLEM)
WAVE nospikes = removeSpikes(stats.wavPLEM)
WAVE guess = PeakFind(nospikes, maxPeaks = 10, minPeakPercent = 0.2, smoothingFactor = 1, verbose = 0)
//WAVE peaks = SMApeakFind(stats.wavPLEM, createwaves = 0)
numPeaks = DimSize(guess, 0)
for(j = 0; j < numPeaks; j += 1)
//peakEnergy = peaks[j][%location]
//peakHeight = peaks[j][%height]
peakEnergy = guess[j][%location]
peakHeight = guess[j][%height]
if(abs(peakEnergy - bestEnergy) < 5)
print currentPLEM
if(peakHeight > bestIntensity)
bestIntensity = peakHeight
secondBestPLEM = bestPLEM
bestPLEM = currentPLEM
endif
endif
endfor
endfor
PLEMd2Display(bestPLEM)
PLEMd2Display(secondBestPLEM)
End
Function SMAreset([power, photon, background])
variable power, photon, background
String strPLEM
Variable i
variable numSpectra = PLEMd2getMapsAvailable()
Struct PLEMd2Stats stats
power = ParamIsDefault(power) ? 0 : !!power
photon = ParamIsDefault(photon) ? 0 : !!photon
background = ParamIsDefault(background) ? 1 : !!background
for(i = 0; i < numSpectra; i += 1)
strPLEM = PLEMd2strPLEM(i)
PLEMd2statsLoad(stats, strPLEM)
stats.booBackground = background
stats.booPhoton = photon
stats.booPower = power
stats.booGrating = 1
stats.booQuantumEfficiency = 1
stats.booTime = 1
stats.booWavelengthPitch = 0
PLEMd2statsSave(stats)
PLEMd2BuildMaps(strPLEM)
endfor
End
Function SMAbackgroundMedian([power])
Variable power
String strPLEM
Variable i
variable numSpectra = PLEMd2getMapsAvailable()
Struct PLEMd2Stats stats
power = ParamIsDefault(power) ? 1 : 0
SMAreset(power = power)
WAVE globalMedian = SMAgetMedian(overwrite = 1)
for(i = 0; i < numSpectra; i += 1)
strPLEM = PLEMd2strPLEM(i)
PLEMd2statsLoad(stats, strPLEM)
stats.wavPLEM -= globalMedian
endfor
End
Function SMABackgroundAncestor()
String strPLEM, strPLEM2
Variable i, previousmax
Variable numSpectra = PLEMd2getMapsAvailable()
Struct PLEMd2Stats stats
Struct PLEMd2Stats stats2
for(i = 0; i < numSpectra; i += 1)
strPLEM = PLEMd2strPLEM(i)
PLEMd2statsLoad(stats, strPLEM)
stats.wavPLEM = stats.wavmeasure - stats.wavbackground
endfor
for(i = 2; i < numSpectra; i += 1)
strPLEM = PLEMd2strPLEM(i-1)
PLEMd2statsLoad(stats, strPLEM)
previousmax = WaveMax(stats.wavPLEM)
strPLEM2= PLEMd2strPLEM(i)
PLEMd2statsLoad(stats2, strPLEM2)
stats.wavPLEM = stats.wavPLEM - stats2.wavPLEM/WaveMax(stats.wavPLEM) * previousmax
endfor
End
Function SMAanalyse(min, max)
Variable min, max
Struct PLEMd2Stats stats
String strPLEM, caption
Variable i
Variable numSpectra = PLEMd2getMapsAvailable()
for(i = 1; i < numSpectra; i += 1)
strPLEM = PLEMd2strPLEM(i)
PLEMd2statsLoad(stats, strPLEM)
Wavestats/Q stats.wavPLEM
if((V_max > min) && (V_max < max))
PLEMd2DisplayByNum(i)
caption = stats.strPLEM +" at\r(x,y) = " + num2str(stats.numPositionX) + ", " + num2str(stats.numPositionY) + ""
TextBox/C/N=text0/F=0/B=1/A=RT/X=0.00/Y=0.00 caption
endif
endfor
End
Function SMAkillAllWindows()
String myWindow
Variable i
for(i=0; i<400; i += 1)
myWindow = "Graph" + num2str(i)
myWindow = "win_spectra50_00_" + num2str(i)
KillWindow/Z $myWindow
endfor
End
Function/DF SMAgetPackageRoot()
variable i, startFolder, numFolders
string currentFolder = ""
if(!DataFolderExists(cstrSMAroot))
if(!cmpstr(cstrSMAroot[0,4], "root:"))
startFolder = 1
currentFolder = "root"
endif
numFolders = ItemsInList(cstrSMAroot, ":")
for(i = startFolder; i < numFolders; i += 1)
currentFolder += ":" + StringFromList(i, cstrSMAroot, ":")
NewDataFolder/O $currentFolder
endfor
endif
DFREF dfr = $cstrSMAroot
return dfr
End
Function/WAVE SMAgetWaveMapsAvailable()
variable numSpectra = PLEMd2getMapsAvailable()
string strMaps = PLEMd2getStrMapsAvailable()
DFREF dfr = SMAgetPackageRoot()
if(numSpectra == 0)
return $""
endif
WAVE/T/Z wv = dfr:mapsavailable
if(WaveExists(wv))
if(DimSize(wv, 0) == numSpectra)
return wv
endif
endif
Make/O/T/N=(numSpectra) dfr:mapsavailable/WAVE=wv = StringFromList(p, strMaps)
return wv
End
Function/WAVE PLEMd2getWaveMapsSelected()
variable numSpectra = PLEMd2getMapsAvailable()
string strMaps = PLEMd2getStrMapsAvailable()
DFREF dfr = SMAgetPackageRoot()
if(numSpectra == 0)
return $""
endif
WAVE/T/Z wv = dfr:mapsselected
if(WaveExists(wv))
if(DimSize(wv, 0) != numSpectra)
Redimension/N=(numSpectra) dfr:mapsselected
endif
return wv
endif
Make/O/T/N=(numSpectra) dfr:mapsselection/WAVE=wv = StringFromList(p, strMaps)
return wv
End
Function/WAVE PLEMd2getWaveMapsSelection()
variable numSpectra = PLEMd2getMapsAvailable()
string strMaps = PLEMd2getStrMapsAvailable()
DFREF dfr = SMAgetPackageRoot()
if(numSpectra == 0)
return $""
endif
WAVE/Z wv = dfr:mapsselection
if(WaveExists(wv))
if(DimSize(wv, 0) != numSpectra)
Redimension/N=(numSpectra) dfr:mapsselection
endif
return wv
endif
Make/O/N=(numSpectra) dfr:mapsselection/WAVE=wv = 1
return wv
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
Menu "CameraImage"
// CTRL+1 is the keyboard shortcut
"AddCoordinates/1", /Q, AddCoordinatesFromGraph()
"Zero To Cursor", SMAtasksZeroToCursor()
"Process xyz coordinates", SMAtasksProcessCoordinates()
"Merge Coordinates", SMAtasksMergeCoordinates()
"PeakFind for coordinates", /Q, GetCoordinates()
"Correct Image overlap", /Q, SMAtestSizeAdjustment()
"GetHeight/2", SMAtasksPrintZposition()
End
Menu "GraphMarquee"
"Erase Points", SMA_EraseMarqueeArea()
"Extract z-dimension", SMA_ExtractSumMarqueeArea()
"Display Original", SMAdisplayOriginal()
"Duplicate", SMADuplicateRangeFromMarquee()
"Wigner", SMAtasksCreateWigner()
End
Menu "MassAnalysis"
"Load (init file links)", SMAload()
"Append (add file links)", SMAadd()
"Read (call PLEMd2)", SMAread()
"File Info", SMAfileInfo()
"Load Spectra", SMAtasksLoadExactscan()
"Load CameraScan", SMAtasksLoadCamerascan()
"Load Tiltscan", /Q, SMAtasksGetTiltPlane()
"Recalc TiltPlane", SMAcameraGetTiltPlaneParameters(createNew = 1)
"Load PointZero", SMAtasksPointZero()
"Load CameraScan (timeSeries to z)", SMAmergeTimeSeries()
"Background: Median", SMABackgroundMedian(power = 0)
"generate exactscan", SMAtasksGenerateExactscan()
"convert excactscan to exactcoordinates", SMAtasksGenerateCoordinates()
"Histogram", SMAtasksHistogram()
"Peak Analysis", SMApeakAnalysis()
"Simple Peak Analysis", SMAquickAnalysis()
"Single Peak Analysis", SMAsinglePeakAction(hcsr(A), hcsr(B))
"Analyse Exactscan", SMApeakAnalysisExactscan()
"Select Spectra Panel", SMAopenPanelSelectWaves()
"Set Base Path", SMASetBasePath()
End
Function SMAtasksZeroToCursor()
SMAaddOffset(vCsr(a), hCsr(a))
SetScaleToCursor()
End
Function SMAtasksLoadCamerascan()
SMAread()
SMAprocessImageStack()
SaveWindow("win_SMAimageStack")
End
Function SMAtasksCreateWigner()
WAVE wv = SMAduplicateRange(SMAgetOriginalFromMarquee())
if(!WaveExists(wv))
Abort "Could not Duplicate Image"
endif
DelayUpdate
Duplicate/O wv root:WignerSource
KillWaves/Z wv
SMAWigner(0, forceReNew = 1)
DoWindow WignerGizmo
if(!V_flag)
Execute " WignerGizmo()"
endif
DoWindow/F SMAwignerHor
if(!V_flag)
Execute " SMAwignerHor()"
endif
End
Function SMAtasksPrintZposition()
print "(x,y)=", hcsr(a), ",", vcsr(a)
print "z =", SMAcameraGetTiltPlane(hcsr(a), vcsr(a))
End
Function SMAtasksHistogram()
Make/O histResult = 0, fit_histResult = 0
SVAR/Z diffwave = root:diffwave
if(!SVAR_EXISTS(diffwave))
String/G root:diffwave
SVAR/Z diffwave = root:diffwave
endif
NVAR/Z checkbox_fit = root:checkbox_fit
if(!NVAR_EXISTS(checkbox_fit))
Variable/G root:checkbox_fit = 1
endif
WAVE wv = SMA_PromptTrace()
diffwave = GetWavesDataFolder(wv, 2)
DoWindow/F SMAHistogram
if(!V_flag)
Execute "SMAHistogram()"
endif
End
Function SMAtasksLoadExactscan()
variable numMaps = PLEMd2getMapsAvailable()
if(!numMaps)
SMAread()
endif
SMAgetSourceWave(overwrite = 1)
SMApeakAnalysisExactscan()
End
Function SMAtasksGenerateExactscan([wv])
WAVE wv
variable dim0, dim1
variable resolution = 11
variable stepsize = 0.5
if(ParamIsDefault(wv))
WAVE wv = root:coordinates
print "SMAtasksGenerateExactscan(wv = root:coordinates)"
endif
if(!WaveExists(wv))
print "SMAtasksGenerateExactscan: Can not find coordinates"
return 1
endif
dim0 = DimSize(wv, 0)
dim1 = DimSize(wv, 1)
Make/O/N=(dim0 * resolution, dim1) root:exactscan/WAVE=exactscan
exactscan[][] = wv[floor(p / resolution)][q]
exactscan[][1] = wv[floor(p / resolution)][1] - (resolution - 1) / 2 * stepsize + mod(p, 11) * stepsize
print "SMAcalcZcoordinateFromTiltPlane(wv = ", NameOfWave(exactscan), ", zOffset = ", SMAcameraGetTiltPlane(0,0), ")"
SMAcalcZcoordinateFromTiltPlane(wv = exactscan)
Save/J/O/DLIM=","/P=home exactscan as "exactscan.csv"
return 0
End
Function SMAtasksPointZero()
SMAgetFocuspoints(graph = 1)
Duplicate/O/R=[][2] root:SMAcameraIntensityCoordinates root:SMAcameraIntensityCoordinateZ/wave=coordinateZ
Redimension/N=(-1, 0) coordinateZ
Display/K=0 root:SMAcameraIntensitySmth vs coordinateZ
WaveStats/Q root:SMAcameraIntensitySmth
print "maximum", coordinateZ[V_maxloc], "um"
End
Function SMAtasksProcessCoordinates()
RoundCoordinates(accuracy = 4)
print "rounded coordinates"
SortCoordinates()
print "sorted coordinates"
DeleteCoordinates(-5, 305)
print "deleted range from -5um to 305um"
SMAcalcZcoordinateFromTiltPlane()
print "SMAcalcZcoordinateFromTiltPlane(zOffset = ", SMAcameraGetTiltPlane(0,0), ")"
End
Function SMAtasksGetTiltPlane()
Variable numMaps = PLEMd2getMapsAvailable()
// Tilt Plane Parameters could have been loaded from ibw files.
WAVE/Z normal = root:SMAcameraPlaneNormal
WAVE/Z distance = root:SMAcameraPlaneDistance
if(!WaveExists(normal) || !WaveExists(distance))
if(numMaps == 0)
Execute "SMAread()"
endif
endif
Execute "SMAreset(power=0, background=0)"
Execute " SMAcameraGetTiltPlaneParameters(createNew = 1)"
Execute "SMAcameraCoordinates()"
End
// panel for handling different wave-sets in one igor experiment
Function SMAopenPanelSelectWaves()
// create waves
SMAgetWaveMapsAvailable()
PLEMd2getWaveMapsSelected()
PLEMd2getWaveMapsSelection()
DoWindow SMAselectWaves
if(!V_flag)
Execute/Q "SMAselectWaves"
endif
DoWindow/F SMAselectWaves
End
// for coordinates from two camerascans.
Function SMAtasksMergeCoordinates()
WAVE coordinates0, coordinates1, coordinates
SMAMergeCoordinates(coordinates0, coordinates1)
End
// for coordinates from two camerascans.
// do not input root:coordinates!
Function/WAVE SMAMergeCoordinates(coordinates0, coordinates1)
WAVE coordinates0, coordinates1
WAVE/Z coordinates = root:coordinates
if(WAVEExists(coordinates))
duplicate/o coordinates root:coordinates_backup
endif
Variable dim00, dim01
dim00 = DimSize(coordinates0, 0)
dim01 = DimSize(coordinates1, 0)
make/O/N=(dim00 + dim01, 3) root:coordinates/WAVE=coordinates
coordinates[0, dim00 - 1] = coordinates0[p][q]
coordinates[dim00,*] = coordinates1[p - dim00][q]
End
// exactscan --> exactcoordinates
Function SMAtasksGenerateCoordinates()
WAVE exactscan = root:coordinates
Duplicate/O exactscan root:exactcoordinates/WAVE=wv
WAVE coordinates = PLEMd2getCoordinates()
wv[][] = coordinates[exactscan[p][1]][q]
print "SMAcalcZcoordinateFromTiltPlane(wv = ", GetWavesDataFolder(wv, 2), ", zOffset = ", SMAcameraGetTiltPlane(0,0), ")"
print "Save/J/O/DLIM=\",\"/P=home ", GetWavesDataFolder(wv, 2), " as \"exactcoordinates.csv\""
Save/J/O/DLIM=","/P=home wv as "exactcoordinates.csv"
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
// use root:source and root:wavelength wave to search for peaks
Function SMAsinglePeakAction(startX, endX, [source])
Variable startX, endX
WAVE source
variable i, dim0
// input waves
if(paramIsDefault(source))
WAVE source = SMAgetSourceWave(overwrite = 0)
endif
WAVE wl = root:wavelength
if(!WaveExists(wl))
WAVE wl = SMAcopyWavelengthToRoot()
endif
// search x coordinate in wavelength wave
FindValue/V=(startX)/T=1 wl
variable start = V_Value
FindValue/V=(endX)/T=1 wl
variable ende = V_value
if(start == -1 || ende == -1)
Abort "start or end not found in wavelength wave"
endif
// sync correlation for specified range
Duplicate/O/R=[0,*][start, ende] source root:source_extracted/wave=source2
MatrixOP/O root:source_extracted_timecorrelation/WAVE=extracted = getdiag(synccorrelation(source2^t), 0)
DoWindow source_extracted_timecorrelation_graph
if(!V_flag)
Display/N=source_extracted_timecorrelation_graph extracted
endif
dim0 = DimSize(source, 0)
// create output waves
Make/O/N=(DimSize(source, 0), 1024) root:source_extracted_fit/WAVE=myfitwave = NaN
SetScale/I y, startX, EndX, myfitwave
Make/O/N=(dim0) root:peakHeight/WAVE=wvHeight = NaN
Make/O/N=(dim0) root:peakHeightErr/WAVE=wvHeightErr = NaN
Make/O/N=(dim0) root:peakLocation/WAVE=wvPos = NaN
Make/O/N=(dim0) root:peakLocationErr/WAVE=wvPosnErr = NaN
Make/O/N=(dim0) root:peakFWHM/WAVE=wvFwhm = NaN
Make/O/N=(dim0) root:peakFWHMErr/WAVE=wvFwhmErr = NaN
// do fit in specified range
Duplicate/FREE/R=[start, ende] wl wl_extracted
for(i = 0; i < dim0; i += 1)
Duplicate/FREE/R=[i][start, ende] source source_extracted
Redimension/N=(abs(ende - start) + 1) source_extracted
WAVE guess = PeakFind(source_extracted, wvXdata = wl_extracted, maxPeaks = 1, smoothingFactor = 3) // align smoothingFactor to your needs
WAVE/WAVE coef = BuildCoefWv(source_extracted, peaks = guess)
WAVE/WAVE peakParam = fitGauss(source_extracted, wvXdata = wl_extracted, wvCoef = coef, cleanup = 1)
if(!WaveExists(peakParam))
printf "SMAsinglePeakAction: error fitting %d.\r", i
continue
endif
if(DimSize(peakParam, 0) != 1)
Abort "Code Inconsitency: More than one peak found."
endif
WAVE result = peakParamToResult(peakParam)
WAVE peakfit = CreateFitCurve(peakParam, startX, endX, 1024)
myfitwave[i][] = peakfit[q]
wvHeight[i] = result[0][%height]
wvHeightErr[i] = result[0][%height_err]
wvPos[i] = result[0][%location]
wvPosnErr[i] = result[0][%location_err]
wvFwhm[i] = result[0][%fwhm]
wvFwhmErr[i] = result[0][%fwhm_err]
endfor
DoWindow source_extracted_peak_height
if(!V_flag)
Display/N=source_extracted_peak_height wvHeight as "PLEM peak action"
endif
end
Function/WAVE SMApeakFind(input, [wvXdata, verbose, createWaves, maxPeaks, minPeakPercent, smoothingFactor])
WAVE input, wvXdata
variable verbose, createWaves, maxPeaks, minPeakPercent, smoothingFactor
variable numResults, i
if(ParamIsDefault(verbose))
verbose = 0
endif
if(ParamIsDefault(createWaves))
createWaves = 1
endif
if(ParamIsDefault(maxPeaks))
maxPeaks = 1
endif
if(ParamIsDefault(minPeakPercent))
minPeakPercent = 5
endif
if(ParamIsDefault(smoothingFactor))
smoothingFactor = 1
endif
Duplicate/FREE input, wv
if(DimSize(wv, 1) == 1)
Redimension/N=(-1,0) wv
endif
if(verbose)
printf "SMApeakFind(%s, verbose=%d)\r", GetWavesDatafolder(input, 2), verbose
endif
WAVE nospikes = removeSpikes(wv)
//WAVE nobackground = RemoveBackground(nospikes)
if(ParamIsDefault(wvXdata))
WAVE guess = PeakFind(nospikes, maxPeaks = maxPeaks, minPeakPercent = minPeakPercent, smoothingFactor = smoothingFactor, verbose = verbose)
else
WAVE guess = PeakFind(nospikes, wvXdata = wvXdata, maxPeaks = maxPeaks, minPeakPercent = minPeakPercent, smoothingFactor = smoothingFactor, verbose = verbose)
endif
DFREF dfr = SMApeakfitDF()
WAVE/WAVE coef = BuildCoefWv(nospikes, peaks = guess, dfr = dfr, verbose = verbose)
if(ParamIsDefault(wvXdata))
WAVE/WAVE/Z peakParam = fitGauss(nospikes, wvCoef = coef, verbose = verbose)
else
WAVE/WAVE/Z peakParam = fitGauss(nospikes, wvXdata = wvXdata, wvCoef = coef, verbose = verbose)
endif
if(verbose > 2)
print "==COEF WAVE=="
numResults = DimSize(coef, 0)
for(i = 0; i < numResults; i += 1)
WAVE output = coef[i]
print output
endfor
endif
KillWaveOfWaves(coef)
if(createWaves)
Duplicate/O nospikes root:nospikes
Duplicate/O wv root:original
//Duplicate/O nobackground root:nobackground
Duplicate/O nospikes root:nospikes
WAVE peakfit = CreateFitCurve(peakParam, DimOffset(input, 0), DimOffset(input, 0) + DimSize(input, 0) * DimDelta(input, 0), 1024)
Duplicate/O peakfit root:peakfit
WAVE peakfit = CreateFitCurve(peakParam, DimOffset(input, 0), DimOffset(input, 0) + DimSize(input, 0) * DimDelta(input, 0), DimSize(input, 0))
Duplicate/O peakfit root:residuum/WAVE=res
res = nospikes - peakfit
endif
if(!WaveExists(peakParam))
print "SMApeakFind Error: no peakParam"
return $""
endif
return peakParamToResult(peakParam)
End
Function SMApeakAnalysis()
variable i, j, numPeaks, offset
STRUCT PLEMd2Stats stats
Variable dim0 = PLEMd2getMapsAvailable()
SMAquickAnalysis()
WAVE/Z loc = root:peakLocation
if(!WaveExists(loc) || DimSize(loc, 0) != dim0)
Make/O/N=(dim0) root:peakLocation/WAVE=loc = NaN
endif
WAVE/Z int = root:peakHeight
if(!WaveExists(int) || DimSize(int, 0) != dim0)
Make/O/N=(dim0) root:peakHeight/WAVE=int = NaN
endif
WAVE/Z fwhm = root:peakFWHM
if(!WaveExists(fwhm) || DimSize(fwhm, 0) != dim0)
Make/O/N=(dim0) root:peakFWHM/WAVE=fwhm = NaN
endif
WAVE/Z area = root:peakArea
if(!WaveExists(area) || DimSize(area, 0) != dim0)
Make/O/N=(dim0) root:peakArea/WAVE=area = NaN
endif
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
if(DimSize(stats.wavPLEM, 1) > 1)
return SMApeakAnalysisMap()
endif
for(i = 0; i < dim0; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
// do peakfind on ranged wave
WAVE PLEMrange = PLEMd2NanotubeRangePLEM(stats)
WAVE corrected = removeSpikes(PLEMrange)
WAVE/WAVE peakfind = SMApeakFind(corrected, maxPeaks = 3, verbose = 0)
if(!WaveExists(peakfind))
continue // fall back to SMAquickAnalysis()
endif
numPeaks = DimSize(peakfind, 0)
for(j = 0; j < numPeaks; j += 1)
if(peakfind[j][%height] < int[i])
continue
endif
if((peakfind[j][%fwhm] < 5) || (peakfind[j][%fwhm] > 30))
continue
endif
int[i] = peakfind[j][%height]
loc[i] = peakfind[j][%location]
fwhm[i] = peakfind[j][%fwhm]
area[i] = peakfind[j][%area]
endfor
endfor
End
Function SMAatlasFit(indices, init, initT, [verbose])
WAVE/U/I indices
WAVE init
WAVE/T initT
Variable verbose
variable i, numPLEM, q25
verbose = ParamIsDefault(verbose) ? 0 : !!verbose
WAVE/T strPLEM = PLEMd2getAllstrPLEM()
numPLEM = DimSize(indices, 0)
for(i = 0; i < numPLEM; i += 1)
if(verbose)
printf "SMAatlasFit: %02d/%02d: index: %02d name: %s\r", i, numPLEM, indices[i], strPLEM[indices[i]]
endif
PLEMd2AtlasInit(strPLEM[indices[i]], init = init, initT = initT)
PLEMd2AtlasFit3D(strPLEM[indices[i]])
endfor
q25 = DimSize(indices, 0) < 100 ? 0 : SMAgetLowerQuartileIntensity(indices)
for(i = 0; i < numPLEM; i += 1)
PLEMd2AtlasClean(strPLEM[indices[i]], threshold = q25)
PLEMd2AtlasFit3D(strPLEM[indices[i]])
PLEMd2AtlasFit3D(strPLEM[indices[i]])
PLEMd2AtlasFit2D(strPLEM[indices[i]])
endfor
for(i = 0; i < numPLEM; i += 1)
PLEMd2AtlasClean(strPLEM[indices[i]], threshold = 0)
endfor
End
Function SMAgetLowerQuartileIntensity(indices)
WAVE/U/I indices
variable i, numPLEM
STRUCT PLEMd2stats stats
String strConcatenate = ""
WAVE/T strPLEMs = PLEMd2getAllstrPLEM()
numPLEM = DimSize(indices, 0)
for(i = 0; i < numPLEM; i += 1)
PLEMd2statsLoad(stats, strPLEMs[indices[i]])
if(DimSize(stats.wav1Dfit, 0) == 0)
continue
endif
strConcatenate = AddListItem(GetWavesDataFolder(stats.wav1Dfit, 2), strConcatenate)
endfor
if(ItemsInList(strConcatenate) == 0)
return NaN
endif
Concatenate/FREE strConcatenate, concat
MatrixOp/FREE intensity = replaceNaNs(concat, 0)
StatsQuantiles/Q intensity
return V_Q25
End
Function SMAdisplayAtlasFit(indices, color)
WAVE/U/I indices
WAVE/U/W color
variable i, numPLEM
String strPLEM, win
Struct PLEMd2stats stats
if(DimSize(color, 1) != 3)
Abort "SMAdisplayAtlasFit: Need 3 colors"
endif
win = "SMAatlasFit_graph"
DoWindow/F $win
if(!V_flag)
Display/N=$win as "SMAatlasFit"
win = S_Name
endif
WAVE/T strPLEMs = PLEMd2getAllstrPLEM()
WAVE/T traces = ListToTextWave(TraceNameList(win, ";", 0x1), ";")
numPLEM = DimSize(indices, 0)
for(i = 0; i < numPLEM; i += 1)
strPLEM = strPLEMs[indices[i]]
FindValue/TEXT=(strPLEM) traces
if(V_value != -1 && V_startPos == 0)
continue
endif
PLEMd2statsLoad(stats, strPLEM)
AppendToGraph/Q/W=$win/C=(color[0][0], color[0][1], color[0][2]) stats.wavEnergyS2/TN=$strPLEM vs stats.wavEnergyS1
ModifyGraph rgb($strPLEM)=(color[0][0],color[0][1],color[0][2],13107),useMrkStrokeRGB($strPLEM)=1
//ModifyGraph zmrkSize($strPLEM)={stats.wav1Dfit,mini,maxi,0.25,2}
ModifyGraph zmrkSize($strPLEM)={stats.wav1Dfit,0,*,0,2}
endfor
ModifyGraph/W=$win mode=4, marker=19, textMarker=0, useMrkStrokeRGB=1
End
Function SMApeakAnalysisMap()
variable i, j, numPeaks, numAccuracy
Variable fit_start, fit_end, numPoints
Struct PLEMd2stats stats
Variable numDelta = 100 / 2 // this is the fitting range around the initial guess
Variable V_fitOptions = 4 // used to suppress CurveFit dialog
Variable V_FitQuitReason // stores the CurveFit Quit Reason
Variable V_FitError // Curve Fit error
Variable dim0 = PLEMd2getMapsAvailable()
WAVE wavelength = SMAcopyWavelengthToRoot()
WAVE excitation = SMAcopyExcitationToRoot()
// todo: integrate with SMAatlasFit()
Make/O/N=(dim0) root:peakHeight/WAVE=peakHeight
Make/O/N=(dim0) root:peakEmission/WAVE=peakEmission
Make/O/N=(dim0) root:peakExcitation/WAVE=peakExcitation
for(i = 0; i < dim0; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
WAVE corrected = RemoveSpikes(stats.wavPLEM)
// fit Excitation
// find p,q
FindValue/T=2/V=(peakEmission[i] - numDelta) wavelength
if(V_Value == -1)
fit_start = 0
else
fit_start = V_Value
endif
FindValue/T=2/V=(peakEmission[i] + numDelta) wavelength
if(V_Value == -1)
fit_end = DimSize(corrected, 0) - 1
else
fit_end = V_Value
endif
numAccuracy = 0
do
numAccuracy += 1
FindValue/T=(numAccuracy)/V=(peakExcitation[i]) excitation
while(V_Value == -1)
numPoints = abs(fit_end - fit_start) + 1
Make/N=(numPoints)/FREE fitEmission = corrected[fit_start + p][V_Value]
Make/N=(numPoints)/FREE fitEmissionX = wavelength[fit_start + p]
WAVE/WAVE peakfind = SMApeakFind(fitEmission, wvXdata = fitEmissionX, maxPeaks = 3, verbose = 1)
if(!WaveExists(peakfind))
continue
endif
numPeaks = DimSize(peakfind, 0)
for(j = 0; j < numPeaks; j += 1)
if(peakfind[j][%height] < peakHeight[i])
continue
endif
if((peakfind[j][%fwhm] < 5) || (peakfind[j][%fwhm] > 50))
continue
endif
peakHeight[i] = peakfind[j][%height]
peakEmission[i] = peakfind[j][%location]
endfor
WaveClear peakfind
// fit Emission
// find p,q
FindValue/T=2/V=(peakExcitation[i] - numDelta) excitation
if(V_Value == -1)
fit_start = 0
else
fit_start = V_Value
endif
FindValue/T=2/V=(peakExcitation[i] + numDelta) excitation
if(V_Value == -1)
fit_end = DimSize(corrected, 1) - 1
else
fit_end = V_Value
endif
numAccuracy = 0
do
numAccuracy += 1
FindValue/T=(numAccuracy)/V=(peakEmission[i]) wavelength
while(V_Value == -1)
numPoints = abs(fit_end - fit_start) + 1
Make/N=(numPoints)/FREE fitExcitation = corrected[V_Value][fit_start + p]
Make/N=(numPoints)/FREE fitExcitationX = excitation[fit_start + p]
WAVE/WAVE peakfind = SMApeakFind(fitExcitation, wvXdata = fitExcitationX, maxPeaks = 3, verbose = 0)
if(!WaveExists(peakfind))
continue
endif
numPeaks = DimSize(peakfind, 0)
for(j = 0; j < numPeaks; j += 1)
if(peakfind[j][%height] < peakHeight[i])
continue
endif
if((peakfind[j][%fwhm] < 5) || (peakfind[j][%fwhm] > 50))
continue
endif
peakHeight[i] = peakfind[j][%height]
peakExcitation[i] = peakfind[j][%location]
endfor
WaveClear peakfind
endfor
// create simple sum
WAVE source = SMAgetSourceWave()
MatrixOp/O root:mapsSum/WAVE=dest = sumCols(source)^t
SMARedimensionToMap(dest)
// display
DoWindow/F SMAmapsSum
if(!V_flag)
Execute "SMAmapsSum()"
endif
DoWindow/F SMApeakMaximum
if(!V_flag)
Execute "SMApeakMaximum()"
endif
End
Function SMAquickAnalysis()
variable i, dim0
Struct PLEMd2stats stats
dim0 = Plemd2getMapsAvailable()
PLEMd2statsLoad(stats, PLEMd2strPLEM(0))
Make/O/N=(dim0) root:peakHeight/WAVE=int = NaN
if(DimSize(stats.wavPLEM, 1) > 1)
Make/O/N=(dim0) root:peakEmission/WAVE=emi = NaN
Make/O/N=(dim0) root:peakExcitation/WAVE=exc = NaN
else
Make/O/N=(dim0) root:peakLocation/WAVE=loc = NaN
endif
for(i = 0; i < dim0; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(i))
WAVE PLEMrange = PLEMd2NanotubeRangePLEM(stats)
WAVE corrected = removeSpikes(PLEMrange)
WaveStats/M=1/Q/P corrected // explicitly get min/max in points
int[i] = V_max
if(DimSize(stats.wavPLEM, 1) > 1)
emi[i] = stats.wavWavelength[ScaleToIndex(stats.wavPLEM, IndexToScale(corrected, V_maxRowLoc, 0), 0)]
exc[i] = stats.wavExcitation[ScaleToIndex(stats.wavPLEM, IndexToScale(corrected, V_maxColLoc, 1), 1)]
else
loc[i] = stats.wavWavelength[ScaleToIndex(stats.wavPLEM, IndexToScale(corrected, V_maxRowLoc, 0), 0)]
endif
endfor
End
// extract best Spectrum from exactscan to get only one spectrum per nanotube
Function SMApeakAnalysisExactscan()
variable i, numItems
WAVE index = SMApeakAnalysisGetBestIndex()
numItems = DimSize(index, 0)
WAVE loc = root:peakLocation
WAVE int = root:peakHeight
WAVE fwhm = root:peakFWHM
WAVE area = root:peakArea
Make/O/N=(numItems) root:peakLocationExact = numType(index[p]) == 0 ? loc[index[p]] : NaN
Make/O/N=(numItems) root:peakHeightExact = numType(index[p]) == 0 ? int[index[p]] : NaN
Make/O/N=(numItems) root:peakFWHMExact = numType(index[p]) == 0 ? fwhm[index[p]] : NaN
Make/O/N=(numItems) root:peakAreaExact = numType(index[p]) == 0 ? area[index[p]] : NaN
DoWindow/F SMAexactscanImage
if(!V_flag)
Plemd2getCoordinates()
SetDataFolder root:
SmaloadBasePath()
LoadWave/H/O/P=SMAbasePath ":collection:suspended:methods:exactscan:template:trenches.ibw"
LoadWave/H/O/P=SMAbasePath ":collection:suspended:methods:exactscan:template:borders.ibw"
Execute "SMAexactscanImage()"
Execute "saveWindow(\"SMAexactscanImage\", saveJSON = 0, saveImages = 1, saveSVG = 0)"
endif
End
// @brief find best spectrum from exactscan
//
// fixed to 11 scans around central position
// does not respect 2 different peak locations in one exactscan (too close nanotubes or bundles)
Function/WAVE SMApeakAnalysisGetBestIndex()
variable i, dim0, range, numPLEM, numIndex
variable rangeStart, rangeEnd
Struct PLEMd2stats stats
dim0 = Plemd2getMapsAvailable()
range = 11
WAVE/Z int = root:peakHeight
if(!WaveExists(int))
SMApeakAnalysis()
WAVE int = root:peakHeight
endif
numIndex = round(dim0 / range)
Make/O/N=(numIndex) root:peakIndex/WAVE=index = NaN
for(i = 0; i < numIndex; i += 1)
rangeStart = i * range
rangeEnd = rangeStart + range - 1
Duplicate/FREE/R=[rangeStart, rangeEnd] int int_range
SetScale/P x, 0, 1, int_range
WAVE/WAVE/Z peakParam = SMApeakFind(int_range, maxPeaks = 1)
numPLEM = NaN
if(WaveExists(peakParam))
numPLEM = peakParam[0][%location]
endif
if(numType(numPLEM) != 0) // fall back to maximum intensity spectrum
Wavestats/Q/M=1/P int_range
numPLEM = V_maxLoc
endif
numPLEM += rangeStart
numPLEM = max(min(round(numPLEM), rangeEnd), rangeStart)
index[i] = numPLEM
endfor
return index
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
#include <Peak AutoFind>
// prefs idea taken from WMs example and FILO (igor-file-loader)
// https://github.com/ukos-git/igor-file-loader
// released under MIT license by same author @ukos-git
static Constant cversion = 0002
static StrConstant cstrPackageName = "Spectra Mass Analysis"
static StrConstant cstrPreferencesFileName = "SMA.bin"
// The recordID is a unique number identifying a record within the preference file.
static Constant cPrefsRecordID = 0
static Constant reserved = 90
Structure SMAprefs
double version
char strBasePath[40]
// reserved forfuture use
uchar strReserved1[256]
uchar strReserved2[256]
double dblReserved[100]
uint32 intReserved[reserved]
EndStructure
static Function DefaultPackagePrefs(package)
STRUCT SMAprefs &package
Variable i
package.version = 0
package.strBasePath = ""
// reserved forfuture use
package.strReserved1 = ""
package.strReserved2 = ""
for(i = 0; i < reserved; i += 1)
package.dblReserved[i] = 0
package.intReserved[i] = 0
endfor
End
static Function ResetPackagePrefs(package)
STRUCT SMAprefs &package
package.strReserved1 = ""
package.strReserved2 = ""
End
static Function SyncPackagePrefs(package)
STRUCT SMAprefs &package
package.version = cversion
End
Function SMAloadPackagePrefs(package, [id])
STRUCT SMAprefs &package
Variable id
if(ParamIsDefault(id))
id = cPrefsRecordID
endif
LoadPackagePreferences cstrPackageName, cstrPreferencesFileName, id, package
if(V_flag != 0 || V_bytesRead == 0)
print "SMAloadPackagePrefs: \tPackage not initialized"
DefaultPackagePrefs(package)
endif
if(package.version < cversion)
print "SMALoadPackagePrefs: \tVersion change detected:"
printf "\tcurrent Version: \t%04d\r", package.version
ResetPackagePrefs(package)
SMAsavePackagePrefs(package)
printf "\tnew Version: \t%04d\r", cversion
endif
End
Function SMAsavePackagePrefs(package, [id])
STRUCT SMAprefs &package
Variable id
if(ParamIsDefault(id))
id = cPrefsRecordID
endif
SyncPackagePrefs(package)
SavePackagePreferences cstrPackageName, cstrPreferencesFileName, id, package
End
// Save the location of the base path.
// All files will be saved/updated relative to this path.
// This function originates at swnt-plem.
//
// DisplayHelpTopic "Symbolic Paths"
Function SMASetBasePath()
String strBasePath
Struct SMAprefs prefs
SMAloadPackagePrefs(prefs)
strBasePath = prefs.strBasePath
NewPath/O/Q/Z SMAbasePath, strBasePath
if(!V_flag)
PathInfo/S path
endif
NewPath/O/Q/Z/M="Set SMA base path" SMAbasePath
if(V_flag)
return 0 // user canceled
endif
PathInfo SMAbasePath
strBasePath = S_path
if(!V_flag)
return 0 // invalid path
endif
strBasePath = RemoveEnding(strBasePath, ":")
GetFileFolderInfo/Q/Z=1 strBasePath
if(!V_flag && V_isFolder)
prefs.strBasePath = strBasePath
SMAsavePackagePrefs(prefs)
endif
End
Function SMAloadBasePath()
String path
PathInfo SMAbasePath
if(V_flag)
return 0
endif
Struct SMAprefs prefs
SMAloadPackagePrefs(prefs)
path = prefs.strBasePath
NewPath/O/Q/Z SMAbasePath, path
if(V_flag)
printf "error setting base path to %s\r", path
return 1
endif
return 0
End
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | #pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3
#include "utilities-peakfind"
Function SMAorderAsc(minimum, maximum)
Variable &minimum, &maximum
Variable temp
if(minimum < maximum)
return 0
endif
temp = minimum
minimum = maximum
maximum = temp
return 0
End
Function/WAVE CoordinateFinderXYrange(coordinates, xmin, xmax, ymin, ymax, [verbose])
WAVE coordinates
Variable xmin, xmax, ymin, ymax, verbose
verbose = ParamIsDefault(verbose) ? 0 : !!verbose
Duplicate/FREE/R=[][0] coordinates, coordinateX
Duplicate/FREE/R=[][1] coordinates, coordinateY
Extract/INDX/FREE coordinateX, indicesX, coordinateX > xmin && coordinateX < xmax
Extract/INDX/FREE coordinateY, indicesY, coordinateY > ymin && coordinateY < ymax
Concatenate/FREE {indicesX, indicesY}, indicesXY
FindDuplicates/FREE/DN=indices indicesXY
if(DimSize(indices, 0) == 0 || numtype(indices[0]) != 0)
return $""
endif
if(verbose)
print indices
endif
return indices
End
/// @brief find x,y,z values in a 3-dimensional coordinates wave.
Function/WAVE CoordinateFinderXYZ(coordinates, xVal, yVal, zVal, [verbose, accuracy])
WAVE coordinates
Variable xVal, yVal, zVal, verbose
Variable accuracy
verbose = ParamIsDefault(verbose) ? 0 : !!verbose
accuracy = ParamIsDefault(accuracy) ? 0.5 : abs(accuracy)
Duplicate/FREE/R=[][0] coordinates, coordinateX
Duplicate/FREE/R=[][1] coordinates, coordinateY
Duplicate/FREE/R=[][2] coordinates, coordinateZ
coordinateX = round(coordinateX[p] / accuracy) * accuracy
coordinateY = round(coordinateY[p] / accuracy) * accuracy
coordinateZ = round(coordinateZ[p] / accuracy) * accuracy
xVal = round(xVal / accuracy) * accuracy
yVal = round(yVal / accuracy) * accuracy
zVal = round(zVal / accuracy) * accuracy
Extract/INDX/FREE coordinateX, indicesX, (coordinateX[p] == xVal)
Extract/INDX/FREE coordinateY, indicesY, (coordinateY[p] == yVal)
Extract/INDX/FREE coordinateZ, indicesZ, (coordinateZ[p] == zVal)
if(!DimSize(indicesX, 0) || !DimSize(indicesY, 0) || !DimSize(indicesZ, 0))
return $""
endif
Make/FREE/N=0 indicesXYZ
Concatenate {indicesX, indicesY, indicesZ}, indicesXYZ
Sort indicesXYZ, indicesXYZ
Redimension/N=(numpnts(indicesXYZ))/E=1 indicesXYZ
Extract/FREE indicesXYZ, indices, (p > 1 && (indicesXYZ[p] == indicesXYZ[p - 1]) && (indicesXYZ[p] == indicesXYZ[p - 2]))
if(!DimSize(indices, 0))
return $""
endif
if(verbose)
print "CoordinateFinderXYZ: found the following indices in the input wave:"
print indices
endif
return indices
End
/// @param indices Wave holding numeric ids of PLEM waves.
Function/WAVE ImageDimensions(indices)
WAVE indices
variable i, numMaps
variable xMin, xMax, yMin, yMax
STRUCT PLEMd2Stats stats
numMaps = DimSize(indices, 0)
for(i = 0; i < numMaps; i += 1)
PLEMd2statsLoad(stats, PLEMd2strPLEM(indices[i]))
xMin = min(ScaleMin(stats.wavPLEM, 0), xMin)
xMax = max(ScaleMax(stats.wavPLEM, 0), xMax)
yMin = min(ScaleMin(stats.wavPLEM, 1), yMin)
yMax = max(ScaleMax(stats.wavPLEM, 1) , yMax)
endfor
Make/FREE/N=(2,2) wv
SetDimLabel 0, 0, x, wv
SetDimLabel 0, 1, y, wv
SetDimLabel 1, 0, min, wv
SetDimLabel 1, 1, max, wv
wv[%x][%min] = xMin
wv[%x][%max] = xMax
wv[%y][%min] = yMin
wv[%y][%max] = yMax
return wv
End
Function ScaleMin(wv, dim)
WAVE wv
variable dim
if(DimDelta(wv, dim) > 0)
return DimOffset(wv, dim)
else
return DimOffset(wv, dim) + DimSize(wv, dim) * DimDelta(wv, dim)
endif
End
Function ScaleMax(wv, dim)
WAVE wv
variable dim
if(DimDelta(wv, dim) < 0)
return DimOffset(wv, dim)
else
return DimOffset(wv, dim) + DimSize(wv, dim) * DimDelta(wv, dim)
endif
End
// get a suitable value for ColorScales to have 0 always in the middle.
Function getEvenScale(wv)
WAVE wv
Variable scaleEven
Wavestats/Q/M=0 wv
scaleEven = max(abs(V_max), abs(V_min))
scaleEven = 10^(ceil(log(scaleEven)*5)/5)
return scaleEven
End
Function/S removePrefix(prefix, item)
String prefix, item
item = FILO#RemovePrefixFromListItems(prefix, item)
return RemoveEnding(item, ";")
End
|
Data Export¶
Data export was performed on continuous integration installations using docker containers with an automated Igor Pro pipeline. All graphs are available online as Igor Experiment (pxp) files in their complete form to perform further analyses and to extract data.
The drone.io pipeline can be triggered locally using make drone
or
drone exec.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | ---
kind: pipeline
name: build
platform:
os: linux
arch: amd64
clone:
depth: 50
steps:
- name: submodules
image: docker:git
commands:
- git submodule update --init --recursive
- test -e /drone/src/programs/igor-utilities/app/utilities-images.ipf
- test -e /drone/src/programs/igor-utilities/app/utilities-lists.ipf
- test -e /drone/src/programs/igor-plotly/src/PlotlyPrefs.ipf
- test -e /drone/src/programs/igor-plotly/src/PlotlyFunctions.ipf
- test -e /drone/src/programs/igor-plotly/src/Plotly.ipf
- name: get_tracked
image: drone/git
commands:
- mkdir -p log/
- git ls-tree -r HEAD --name-only > log/tracked
- stat log/tracked
- name: collect_changes
image: drone/git
commands:
- if ! git rev-parse --quiet --verify master; then git fetch origin master; fi
- git diff --name-only --diff-filter=MCRA master > log/changes
when:
branch:
exclude:
- master
- name: collect_all
image: ukos/igorpro-minimal
pull: if-not-exists
commands:
- git lfs version
- git lfs ls-files --name-only > log/changes
when:
branch:
- master
- bugfix/*
- name: prepare_igorpro
image: alpine
commands:
- grep '.pxp$' log/changes | tee log/pxp
- if ! test $(cat log/pxp | wc -l) -gt 0; then exit 0;fi
- name: pull_files
image: drone/git
commands:
- git lfs version
- for file in $(awk "NR % 1 == 0" log/pxp); do if ! sha256sum -c "$file.sha256"; then git lfs pull --include="$file"; fi; done
- git lfs pull --include="*.svg"
- name: pull_build_cache
image: ukos/rsync
commands:
- if test -z "$DRONE_COMMIT"; then exit 0; fi
- echo "be sure to mount that network share on the docker executor"
- rsync -rlt --perms --chmod=o=rwX --ignore-existing --exclude build /phd/stable/ ./
volumes:
- name: phd
path: /phd
when:
branch:
exclude:
- master
- name: igorpro
image: ukos/igorpro-minimal
pull: if-not-exists
working_dir: /drone/src
commands:
- if ! test $(wc -l log/pxp | cut -c1) -gt 0; then exit 0;fi
- ln -sv /drone/src/programs/igor-json-xop/output/win/x86/*.xop "/root/WaveMetrics/Igor Pro 8 User Files/Igor Extensions/"
- ln -sv /drone/src/programs/igor-filo/app "/root/WaveMetrics/Igor Pro 8 User Files/User Procedures/filo"
- ln -sv /drone/src/programs/igor-json-xop/procedures "/root/WaveMetrics/Igor Pro 8 User Files/User Procedures/json"
- ln -sv /drone/src/programs/igor-plem/app "/root/WaveMetrics/Igor Pro 8 User Files/User Procedures/plem"
- ln -sv /drone/src/programs/igor-plotly/src "/root/WaveMetrics/Igor Pro 8 User Files/User Procedures/plotly"
- ln -sv /drone/src/programs/igor-sma/app "/root/WaveMetrics/Igor Pro 8 User Files/User Procedures/sma"
- ln -sv /drone/src/programs/igor-utilities/app "/root/WaveMetrics/Igor Pro 8 User Files/User Procedures/utilities"
- readlink -e /root/WaveMetrics/Igor\ Pro\ 8\ User\ Files/User\ Procedures/*
- readlink -e /root/WaveMetrics/Igor\ Pro\ 8\ User\ Files/Igor\ Procedures/*
- for file in $(awk "NR % 1 == 0" log/pxp); do scripts/extract.sh "$file"; done
- name: verify
image: ukos/plotly
commands:
- /bin/sh scripts/html_verify_json.sh
- name: images
image: ukos/inkscape:latest
commands:
- /bin/sh scripts/latex_convert_svg.sh
- /bin/sh scripts/latex_convert_gif.sh
- /bin/sh scripts/html_convert_vector.sh
- if test -z "$DRONE_COMMIT"; then exit 0; fi # optional processing
- /bin/sh scripts/html_convert_heic.sh
- name: pdf
image: ukos/sphinx:latest
commands:
- /usr/bin/make latexpdf
- du -h build/latex/thesis.pdf
- mv -f build/latex/thesis.pdf _static/
- name: html
image: ukos/sphinx:latest
commands:
- /usr/bin/make clean
- /usr/bin/make html
- name: push_stable
image: ukos/rsync
commands:
- if test -z "$DRONE_COMMIT"; then exit 0; fi
- rsync -rlt --checksum --delete --delete-excluded --exclude .git --exclude-from=log/tracked ./ /phd/stable
volumes:
- name: phd
path: /phd
when:
branch:
- master
volumes:
- name: phd
host:
path: /mnt/phd
|
The GitLab runner pipeline allows parallelisation of the export step with different docker containers and deploys the website on the master branch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- programs/
variables:
GIT_LFS_SKIP_SMUDGE: "1"
stages:
- init
- igorpro
- postprocess
- build
- deploy
collect:
stage: init
image: ${CI_REGISTRY}/ukos-git/docker-igorpro # @todo use git lfs container with git lfs ls-files available
script:
- git lfs version
- mkdir -p log
- git ls-tree -r HEAD --name-only > log/tracked
- git lfs ls-files --name-only > log/changes
- grep '.pxp$' log/changes | tee log/pxp
- if ! test $(cat log/pxp | wc -l) -gt 0; then exit 0;fi
artifacts:
paths:
- log/
expire_in: 1 day
igorpro:
stage: igorpro
image: ${CI_REGISTRY}/ukos-git/docker-igorpro
variables:
GIT_SUBMODULE_STRATEGY: recursive
script:
- if ! test $(wc -l log/pxp | cut -c1) -gt 0; then exit 0;fi
- ln -sv $(pwd)/programs/igor-json-xop/output/win/x86/*.xop "${HOME}/WaveMetrics/Igor Pro 8 User Files/Igor Extensions/"
- ln -sv $(pwd)/programs/igor-filo/app "${HOME}/WaveMetrics/Igor Pro 8 User Files/User Procedures/filo"
- ln -sv $(pwd)/programs/igor-json-xop/procedures "${HOME}/WaveMetrics/Igor Pro 8 User Files/User Procedures/json"
- ln -sv $(pwd)/programs/igor-plem/app "${HOME}/WaveMetrics/Igor Pro 8 User Files/User Procedures/plem"
- ln -sv $(pwd)/programs/igor-plotly/src "${HOME}/WaveMetrics/Igor Pro 8 User Files/User Procedures/plotly"
- ln -sv $(pwd)/programs/igor-sma/app "${HOME}/WaveMetrics/Igor Pro 8 User Files/User Procedures/sma"
- ln -sv $(pwd)/programs/igor-utilities/app "${HOME}/WaveMetrics/Igor Pro 8 User Files/User Procedures/utilities"
- readlink -e ${HOME}/WaveMetrics/Igor\ Pro\ 8\ User\ Files/User\ Procedures/*
- readlink -e ${HOME}/WaveMetrics/Igor\ Pro\ 8\ User\ Files/Igor\ Procedures/*
- for file in $(awk "NR % ${CI_NODE_TOTAL} == ${CI_NODE_INDEX} - 1" log/pxp); do git lfs pull --include="$file" && scripts/extract.sh "$file"; done
parallel: 16
cache:
key: igorpro
untracked: true
artifacts:
untracked: true
expire_in: 1 day
timeout: 15 minutes
retry:
max: 1
verify:
stage: postprocess
image: ukos/plotly
script:
- /bin/sh scripts/html_verify_json.sh
images:
stage: postprocess
image: ukos/inkscape
script:
- /bin/sh scripts/latex_convert_svg.sh
- /bin/sh scripts/latex_convert_gif.sh
- /bin/sh scripts/html_convert_vector.sh
artifacts:
untracked: true
expire_in: 1 day
sphinx:
stage: build
image: ukos/sphinx
variables:
GIT_SUBMODULE_STRATEGY: recursive
script:
- git lfs pull --exclude "*.pxp"
- /usr/bin/make latexpdf
- du -h build/latex/thesis.pdf
- mv -f build/latex/thesis.pdf _static/
- /usr/bin/make html
artifacts:
paths:
- build/html/
expire_in: 1 week
retry:
max: 2
pages:
stage: deploy
image: alpine
script:
- mv -f build/html public
dependencies:
- sphinx
cache: {}
artifacts:
paths:
- public
only:
- master
|
CVD Control¶
The CVD setup has a python GUI. The recording of CVD parameters was performed with an Arduino Uno and has already been decribed elsewhere [85].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 | #!/usr/bin/env python
import MySQLdb as mysqlconnector
from MySQLdb.constants import CLIENT
import os
import socket
import decimal
import struct
from time import sleep
import multiprocessing
import ConfigParser
from MKFlowMessage import FBconvertLong # converter for long numbers to float and percent
#cvd-client->rbBmSDP7fSKp87b5
class MKDatabase(object):
sql = ""
connected = False
ready = False
messageID = -1
client = False
recording = False
recordingID = -1
fileName = ""
storage_description = 50
storage_values = 30
hostname = ""
# settings.cfg (see loadConfig)
dbUser = ""
dbPass = ""
dbHost = ""
dbName = ""
servername = ""
def __init__(self, isClient = False):
self.client = isClient
self.loadConfig()
self.test()
decimal.getcontext().prec = 2
def loadConfig(self):
config = ConfigParser.ConfigParser()
srcPath = os.path.dirname(os.path.realpath(__file__))
settingsFile = srcPath + '/../settings.cfg'
if not (os.path.exists(settingsFile)):
print "settings.cfg not found"
raise
config.read(settingsFile)
self.dbUser = config.get('Database', 'dbuser')
self.dbPass = config.get('Database', 'dbpass')
self.dbHost = config.get('Database', 'dbhost')
self.dbName = config.get('Database', 'dbname')
self.servername = config.get('Server', 'servername')
def open(self):
try:
if not self.checkIP():
print "server unavailable"
raise
self.db = mysqlconnector.connect(
host = self.dbHost,
user = self.dbUser,
passwd = self.dbPass,
db = self.dbName,
client_flag = CLIENT.FOUND_ROWS,
connect_timeout = 1
)
except:
print "database open failed."
self.close()
return False
else:
print "connected as user: %s" % self.dbUser
self.connected = True
return True
def close(self):
try:
self.db.close()
except:
if not self.checkIP():
print "connection lost. Database could not be closed normal"
self.connected = False
else:
self.connected = False
def isOpen(self):
#if not self.connected:
# return False
#try:
# stats = self.db.stat()
# if stats == 'MySQL server has gone away':
# self.close()
#except:
# self.connected = False
return self.connected
def write_without_timeout(self, db, sql, connection):
try:
cursor = db.cursor()
cursor.execute(sql)
affectedRows = cursor.rowcount
cursor.close()
db.commit()
except:
affectedRows = 0
try:
self.db.rollback()
except:
pass
connection.send(affectedRows)
connection.close()
def read_without_timeout(self, db, sql, connection):
affectedRows = 0
try:
cursor = db.cursor()
cursor.execute(sql)
data = cursor.fetchone()
cursor.close()
except:
connection.send([])
else:
connection.send(data)
connection.close()
# from alex martelli on http://stackoverflow.com/questions/1507091/python-mysqldb-query-timeout
def write(self, sql, update = False):
if not self.isOpen():
if not self.open():
raise
conn_parent, conn_child = multiprocessing.Pipe(False)
subproc = multiprocessing.Process(target = self.write_without_timeout,
args = (self.db, sql, conn_child))
subproc.start()
subproc.join(1)
if conn_parent.poll():
affectedRows = conn_parent.recv()
# on update statements rise if no lines were affected
if update and affectedRows == 0:
raise UpdateError('UPDATE statement failed')
else:
return affectedRows
subproc.terminate()
raise TimeoutError("Query %r ran for >%r" % (sql, timeout))
def read(self, sql):
if not self.isOpen():
if not self.open():
raise
conn_parent, conn_child = multiprocessing.Pipe(False)
subproc = multiprocessing.Process(target = self.read_without_timeout,
args = (self.db, sql, conn_child))
subproc.start()
subproc.join(1)
if conn_parent.poll():
data = conn_parent.recv()
try:
if len(data) == 0:
raise
except:
return []
else:
return data
else:
subproc.terminate()
return []
def writeArduino(self, sql):
try:
self.write(sql, True)
except:
try:
print "writeArduino failed: create database and try again."
self.createArduino()
self.resetArduino()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeRecording(self, sql):
try:
self.write(sql, True)
except:
try:
self.createRecording()
self.resetRecording()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeFlowbus(self, sql):
try:
self.write(sql)
except:
try:
self.createFlowbus()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeMessage(self, sql):
try:
self.write(sql, True)
except:
try:
self.createMessage()
self.resetMessage()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def test(self):
print "-- starting self-test --"
self.open()
sql="SELECT VERSION()"
data = self.read(sql)
self.close()
print "MySQL version : %s " % data
print "-- self test complete --"
def getHostname(self):
if self.hostname == "":
self.hostname = socket.gethostname()
return self.hostname
def isServer(self):
if (self.getHostname() == self.servername):
return True
else:
return False
def getIP(self):
if self.isServer():
ip = 'localhost'
else:
ip = self.dbHost
return ip
def checkIP(self, ip = ""):
if len(ip) == 0:
ip = self.getIP()
if ip == "localhost":
return True
command = "ping -c 1 -W 1 " + ip
print "executing '" + command + "'"
if os.system(command + " > /dev/null") == 0:
return True
else:
print "ip not found. sleeping penalty."
sleep(1)
return False
def createArduino(self):
sql = """CREATE TABLE IF NOT EXISTS `runtime_arduino` (
`temperature` decimal(6,2) NOT NULL DEFAULT '0',
`pressure` decimal(6,2) NOT NULL DEFAULT '0',
`argon` decimal(6,2) NOT NULL DEFAULT '0',
`ethanol` decimal(6,2) NOT NULL DEFAULT '0',
`spTemperature` int(11) NOT NULL DEFAULT '0',
`spPressure` int(11) NOT NULL DEFAULT '1000',
`spEthanol` int(11) NOT NULL DEFAULT '0',
`spArgon` int(11) NOT NULL DEFAULT '0'
) ENGINE=MEMORY DEFAULT Charset=utf8;"""
self.write(sql)
def resetArduino(self):
sql = """INSERT INTO `runtime_arduino`
(`temperature`, `pressure`, `argon`, `ethanol`, `spTemperature`, `spPressure`, `spEthanol`, `spArgon`)
VALUES
(0, 0, 0, 0, 0, 0, 0, 0);"""
self.write(sql)
def createFlowbus(self):
sql = """
CREATE TABLE IF NOT EXISTS `runtime_flowbus`
(
`instrument` smallint(2) NOT NULL DEFAULT '0',
`process` smallint(2) NOT NULL,
`flowBus` smallint(2) NOT NULL,
`dataType` tinyint(1) NOT NULL DEFAULT '0',
`parameter` binary(%i) NOT NULL DEFAULT '0',
`data` binary(%i) NOT NULL DEFAULT '0',
`time` decimal(7,2) NOT NULL DEFAULT '0',
UNIQUE KEY `instrument` (`instrument`,`process`,`flowBus`)
)
ENGINE=MEMORY
DEFAULT CHARSET=utf8;""" % (self.storage_description, self.storage_values)
self.write(sql)
def createRecording(self):
sql = """CREATE TABLE IF NOT EXISTS `runtime_recording` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`recording` tinyint(4) NOT NULL DEFAULT '0',
`id_recording` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
sql = """CREATE TABLE IF NOT EXISTS `recording` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`recording` tinyint(4) NOT NULL DEFAULT '0',
`filename` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
def resetRecording(self):
sql = """INSERT INTO `runtime_recording`
(`recording`)
VALUES
(0)"""
self.write(sql)
def createMessage(self):
sql = """CREATE TABLE IF NOT EXISTS `cvd`.`runtime_message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ready` tinyint(4) NOT NULL DEFAULT '0',
`id_message` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
sql = """CREATE TABLE IF NOT EXISTS `cvd`.`message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`processed` tinyint(4) NOT NULL DEFAULT '0',
`text` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
def resetMessage(self):
sql = """INSERT INTO `cvd`.`runtime_message`
(`ready`)
VALUES
(0)"""
self.write(sql)
sql = """DELETE FROM `cvd`.`message`
WHERE `processed` = 1"""
self.write(sql)
def setData(self, data, setpoint):
try:
self.temperature = decimal.Decimal(data[0])
self.pressure = decimal.Decimal(data[1])
self.argon = decimal.Decimal(data[2])
self.ethanol = decimal.Decimal(data[3])
except:
self.temperature = 0.00
self.pressure = 0.00
self.argon = 0.00
self.ethanol = 0.00
try:
self.spTemperature = int(setpoint[0])
self.spPressure = int(setpoint[1])
self.spArgon = int(setpoint[2])
self.spEthanol = int(setpoint[3])
except:
self.spTemperature = 0
self.spPressure = 1000
self.spEthanol = 0
self.spArgon = 0
sql = """UPDATE `cvd`.`runtime_arduino`
SET `temperature` = %s,
`pressure` = %s,
`ethanol` = %s,
`argon` = %s,
`spTemperature` = %s,
`spPressure` = %s,
`spEthanol` = %s,
`spArgon` = %s;""" % (self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon)
return self.writeArduino(sql)
def setLogFile(self, fileName):
id = self.getRecordingID()
if id < 0:
return False
sql = """UPDATE `cvd`.`recording`
SET `filename` = '%s',
`recording` = 1
WHERE `id` = %i
LIMIT 1;""" % (fileName, id)
if not self.writeRecording(sql):
return False
if self.getLogFile() == fileName:
return True
else:
return False
def isRecording(self):
sql = """SELECT `recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 1:
return False
else:
if data[0]:
return True
else:
return False
def stopRecording(self):
sql = """UPDATE `cvd`.`runtime_recording`
SET `recording` = 0;"""
if not self.writeRecording(sql):
return False
sql = """UPDATE `cvd`.`recording`
SET `recording` = 0
WHERE `recording` = 1;"""
if not self.writeRecording(sql):
return False
self.recordingID = -1
return True
def startRecording(self, filename = ''):
self.stopRecording
sql = """INSERT INTO `cvd`.`recording` (
`id` ,`time` , `recording` , `filename` )
VALUES (
NULL , CURRENT_TIMESTAMP , 1, '%s')""" % filename
if not self.writeRecording(sql):
return False
sql = """SELECT `id`
FROM `cvd`.`recording`
WHERE `recording` = 1
LIMIT 1;"""
data = self.read(sql)
if not len(data) == 1:
return False
sql = """UPDATE `cvd`.`runtime_recording`
SET `id_recording` = %i,
`recording` = 1
LIMIT 1;""" % data
if not self.writeRecording(sql):
return False
return True
def getRecordingID(self):
sql = """SELECT `id_recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
return int(data[0])
else:
return -1
def getLogFile(self):
# get id from memory table
recordingID = self.getRecordingID()
# update filename from disc table if not already saved in class
if not (recordingID == self.recordingID) or len(self.fileName) == 0:
print "querying filename from sql table"
self.close()
sql = """SELECT `filename`
FROM `cvd`.`recording`
WHERE `id` = %i;""" % recordingID
data = self.read(sql)
if len(data) == 1:
self.fileName = data[0]
else:
self.fileName = ''
self.recordingID = recordingID
return self.fileName
def setMessage(self, message):
sql = """INSERT INTO `cvd`.`message`
(`text`) VALUES ('%s');""" % (message)
if self.writeMessage(sql):
return self.updateMessage()
return False
def updateMessage(self):
sql = """SELECT `id` FROM `cvd`.`message`
WHERE `processed` = 0
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
id_message = data[0]
ready = 1
else:
ready = 0
id_message = -1
sql = """UPDATE `cvd`.`runtime_message`
SET `ready` = %i,
`id_message` = %i
LIMIT 1;""" % (ready, id_message)
return self.writeMessage(sql)
def isReady(self):
if self.ready:
return True
sql = """SELECT `ready`, `id_message`
FROM `cvd`.`runtime_message`;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 2:
data = (0,-1)
(self.ready, self.messageID) = data
if self.ready:
return True
else:
return False
def getMessage(self):
self.message = ""
# read from runtime (memory table)
if self.isReady():
# ready flag did also read out messageID.
# get message string from cvd.message
sql = """SELECT `text`
FROM `cvd`.`message`
WHERE `id` = %i
LIMIT 1;""" % self.messageID
data = self.read(sql)
if (len(data) == 1):
self.message = data[0]
# mark message in cvd.message as processed
sql = """UPDATE `cvd`.`message`
SET `processed` = 1
WHERE `id` = %i;""" % self.messageID
self.writeMessage(sql)
self.updateMessage()
# reset readout
self.ready = False
return self.message
def setFlowbus(self, instrument, process, flowBus, dataTypeString, dataInput, timeInput, parameterName):
time = decimal.Decimal(timeInput)
parameterName = parameterName.encode("hex")
if (dataTypeString == "character"):
dataType = 0
data = format(int(dataInput), 'x')
elif(dataTypeString == "integer"):
dataType = 1
data = format(int(dataInput), 'x')
elif(dataTypeString == "long"):
dataType = 2
data = format(int(dataInput), 'x')
elif(dataTypeString == "string"):
dataType = 3
data = dataInput.encode("hex")
else:
raise ValueError("can not identify dataType at setFlowBus()")
sql = """
INSERT INTO `cvd`.`runtime_flowbus`
(`instrument`,`process`,`flowBus`,`dataType`,`data`,`time`, `parameter`)
VALUES
(%i, %i, %i, %i, UNHEX(LPAD('%s',%i,'0')), %.2f, UNHEX(LPAD('%s',%i,'0')))""" % (instrument, process, flowBus, dataType, data, self.storage_values * 2, time, parameterName, self.storage_description * 2)
sql += """
ON DUPLICATE KEY UPDATE
`data` = UNHEX(LPAD('%s',%i,'0')),
`time` = %.2f;""" % (data, self.storage_values * 2, time)
self.writeFlowbus(sql)
def getFlowbus(self, instrument, process, flowBus):
sql = """
SELECT `dataType`,TRIM(LEADING '0' FROM HEX(`data`)),`time`,TRIM(LEADING '0' FROM HEX(`parameter`))
FROM `cvd`.`runtime_flowbus`
WHERE
( `instrument` = %i
AND `process` = %i
AND `flowBus` = %i);
""" % (instrument, process, flowBus)
data = self.read(sql)
if (len(data) == 4):
(dataType, dataOut, timeOut, parameter) = data
else:
return (-1,-1,-1)
parameter = parameter.decode("hex")
time = decimal.Decimal(timeOut)
if (dataType == 0):
data = int(dataOut, 16)
elif(dataType == 1):
data = int(dataOut, 16)
elif(dataType == 2):
data = FBconvertLong(process, flowBus, int(dataOut,16))
elif(dataType == 3):
data = dataOut.decode("hex")
else:
raise ValueError("can not identify dataType at getFlowBus()")
return (parameter, data, time)
def getAll(self):
sql = """SELECT temperature, pressure, ethanol, argon,
spTemperature, spPressure, spEthanol, spArgon
FROM `cvd`.`runtime_arduino`
LIMIT 1"""
data = self.read(sql)
if len(data) == 0:
print "database readout failed for arduino!"
data = (-1,-1,-1,-1, -1,-1,-1,-1)
(self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon) = data
class UpdateError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class TimeoutError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
sql = """UPDATE `cvd`.`runtime_arduino`
SET `temperature` = %s,
`pressure` = %s,
`ethanol` = %s,
`argon` = %s
`spTemperature` = %s,
`spPressure` = %s,
`spEthanol` = %s,
`spArgon` = %s
LIMIT 1;""" % (self.temperature, self.pressure, self.ethanol, self.argon, setpoint[0], setpoint[1], setpoint[2], setpoint[2])
return self.writeArduino(sql)
def setLogFile(self, fileName):
id = self.getRecordingID()
if id < 0:
return False
sql = """UPDATE `cvd`.`recording`
SET `filename` = '%s',
`recording` = 1
WHERE `id` = %i
LIMIT 1;""" % (fileName, id)
if not self.writeRecording(sql):
return False
if self.getLogFile() == fileName:
return True
else:
return False
def isRecording(self):
sql = """SELECT `recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 1:
return False
else:
if data[0]:
return True
else:
return False
def stopRecording(self):
sql = """UPDATE `cvd`.`runtime_recording`
SET `recording` = 0;"""
if not self.writeRecording(sql):
return False
sql = """UPDATE `cvd`.`recording`
SET `recording` = 0
WHERE `recording` = 1;"""
if not self.writeRecording(sql):
return False
self.recordingID = -1
return True
def startRecording(self, filename = ''):
self.stopRecording
sql = """INSERT INTO `cvd`.`recording` (
`id` ,`time` , `recording` , `filename` )
VALUES (
NULL , CURRENT_TIMESTAMP , 1, '%s')""" % filename
if not self.writeRecording(sql):
return False
sql = """SELECT `id`
FROM `cvd`.`recording`
WHERE `recording` = 1
LIMIT 1;"""
data = self.read(sql)
if not len(data) == 1:
return False
sql = """UPDATE `cvd`.`runtime_recording`
SET `id_recording` = %i,
`recording` = 1
LIMIT 1;""" % data
if not self.writeRecording(sql):
return False
return True
def getRecordingID(self):
sql = """SELECT `id_recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
return int(data[0])
else:
return -1
def getLogFile(self):
# get id from memory table
recordingID = self.getRecordingID()
# update filename from disc table if not already saved in class
if not (recordingID == self.recordingID) or len(self.fileName) == 0:
print "querying filename from sql table"
self.close()
sql = """SELECT `filename`
FROM `cvd`.`recording`
WHERE `id` = %i;""" % recordingID
data = self.read(sql)
if len(data) == 1:
self.fileName = data[0]
else:
self.fileName = ''
self.recordingID = recordingID
return self.fileName
def setMessage(self, message):
sql = """INSERT INTO `cvd`.`message`
(`text`) VALUES ('%s');""" % (message)
if self.writeMessage(sql):
return self.updateMessage()
return False
def updateMessage(self):
sql = """SELECT `id` FROM `cvd`.`message`
WHERE `processed` = 0
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
id_message = data[0]
ready = 1
else:
ready = 0
id_message = -1
sql = """UPDATE `cvd`.`runtime_message`
SET `ready` = %i,
`id_message` = %i
LIMIT 1;""" % (ready, id_message)
return self.writeMessage(sql)
def isReady(self):
if self.ready:
return True
sql = """SELECT `ready`, `id_message`
FROM `cvd`.`runtime_message`;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 2:
data = (0,-1)
(self.ready, self.messageID) = data
if self.ready:
return True
else:
return False
def getMessage(self):
self.message = ""
# read from runtime (memory table)
if self.isReady():
# ready flag did also read out messageID.
# get message string from cvd.message
sql = """SELECT `text`
FROM `cvd`.`message`
WHERE `id` = %i
LIMIT 1;""" % self.messageID
data = self.read(sql)
if (len(data) == 1):
self.message = data[0]
# mark message in cvd.message as processed
sql = """UPDATE `cvd`.`message`
SET `processed` = 1
WHERE `id` = %i;""" % self.messageID
self.writeMessage(sql)
self.updateMessage()
# reset readout
self.ready = False
return self.message
def setFlowbus(self, instrument, process, flowBus, dataTypeString, dataInput, timeInput, parameterName):
time = decimal.Decimal(timeInput)
parameterName = parameterName.encode("hex")
if (dataTypeString == "character"):
dataType = 0
data = format(int(dataInput), 'x')
elif(dataTypeString == "integer"):
dataType = 1
data = format(int(dataInput), 'x')
elif(dataTypeString == "long"):
dataType = 2
data = format(int(dataInput), 'x')
elif(dataTypeString == "string"):
dataType = 3
data = dataInput.encode("hex")
else:
raise ValueError("can not identify dataType at setFlowBus()")
sql = """
INSERT INTO `cvd`.`runtime_flowbus`
(`instrument`,`process`,`flowBus`,`dataType`,`data`,`time`, `parameter`)
VALUES
(%i, %i, %i, %i, UNHEX(LPAD('%s',%i,'0')), %.2f, UNHEX(LPAD('%s',%i,'0')))""" % (instrument, process, flowBus, dataType, data, self.storage_values * 2, time, parameterName, self.storage_description * 2)
sql += """
ON DUPLICATE KEY UPDATE
`data` = UNHEX(LPAD('%s',%i,'0')),
`time` = %.2f;""" % (data, self.storage_values * 2, time)
self.writeFlowbus(sql)
def getFlowbus(self, instrument, process, flowBus):
sql = """
SELECT `dataType`,TRIM(LEADING '0' FROM HEX(`data`)),`time`,TRIM(LEADING '0' FROM HEX(`parameter`))
FROM `cvd`.`runtime_flowbus`
WHERE
( `instrument` = %i
AND `process` = %i
AND `flowBus` = %i);
""" % (instrument, process, flowBus)
data = self.read(sql)
if (len(data) == 4):
(dataType, dataOut, timeOut, parameter) = data
else:
return (-1,-1,-1)
parameter = parameter.decode("hex")
time = decimal.Decimal(timeOut)
if (dataType == 0):
data = int(dataOut, 16)
elif(dataType == 1):
data = int(dataOut, 16)
elif(dataType == 2):
data = FBconvertLong(process, flowBus, int(dataOut,16))
elif(dataType == 3):
data = dataOut.decode("hex")
else:
raise ValueError("can not identify dataType at getFlowBus()")
return (parameter, data, time)
def getAll(self):
sql = """SELECT temperature, pressure, ethanol, argon,
spTemperature, spPressure, spEthanol, spArgon
FROM `cvd`.`runtime_arduino`
LIMIT 1"""
data = self.read(sql)
if len(data) == 0:
print "database readout failed for arduino!"
data = (-1,-1,-1,-1, -1,-1,-1,-1)
(self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon) = data
class UpdateError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class TimeoutError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | #!/usr/bin/env python
from __future__ import print_function
import threading
import time
import sys
from datetime import datetime
from MKDatabase import MKDatabase
from MKParser import MKParser
from MKLogFile import MKLogFileHandler
from MKSerial import MKSerial
class MKArduino():
def __init__(self, port = '/dev/ttyACM0'):
self.Serial = MKSerial('arduino', port, 9600)
self.Parser = MKParser()
self.Database = MKDatabase()
self.newFile = True
self.setFile = False
self.alive = False
self.sleeping = False
self.verbose = 0
def debug(self, verbose = 1):
self.verbose = verbose
def start(self):
try:
self.Serial.start()
self.thread = threading.Thread(target=self.loop)
self.thread.daemon = True
self.thread.start()
except:
self.stop()
raise
else:
self.alive = True
def stop(self):
self.alive = False
self.Serial.stop()
def join(self):
self.thread.join()
def isAlive(self):
return self.alive
def getPerformance(self):
if self.verbose < 0:
microsecond = datetime.now().microsecond
print(self.perfCounter, "\t", int((microsecond - self.performance)/100)/10.0)
self.performance = microsecond
self.perfCounter += 1
def resetPerformance(self):
if self.verbose < 0:
print('---')
self.perfCounter = 0
self.performance = datetime.now().microsecond
self.getPerformance()
def loop(self):
if self.verbose > 1:
print('entering loop ...')
while self.isAlive():
self.resetPerformance()
serialReady = self.Serial.isReady()
self.getPerformance()
databaseReady = self.Database.isReady()
self.getPerformance()
if not serialReady and not databaseReady:
if self.verbose > 0:
if not self.sleeping:
if self.verbose > 1:
print('sleeping .', end = '')
else:
print('.', end = '')
self.sleeping = True
else:
print('.', end = '')
sys.stdout.flush()
self.getPerformance()
time.sleep(0.1)
self.getPerformance()
else:
if self.verbose > 0:
if self.sleeping:
print('.', end = '\n')
sys.stdout.flush()
self.sleeping = False
if serialReady:
print('serial ready with %i messages' % len(self.Serial.receiveBuffer))
if databaseReady:
print('database ready')
self.getPerformance()
if databaseReady:
self.Serial.send(self.Database.getMessage())
if serialReady:
self.getPerformance()
message = self.Serial.getMessage()
self.getPerformance()
self.Parser.input(message)
self.getPerformance()
oneline = self.Parser.oneline()
self.getPerformance()
if self.verbose > 2:
print(oneline)
if self.Parser.getStatus():
self.getPerformance()
data = (self.Parser.get(2), self.Parser.get(5), self.Parser.get(8), self.Parser.get(11))
setpoint = (self.Parser.get(3), self.Parser.get(6), self.Parser.get(9), self.Parser.get(12))
setData = self.Database.setData(data, setpoint)
self.getPerformance()
if not setData:
if self.verbose > 2:
print("database write failed. add message to buffer again.")
self.Serial.receive(message)
self.getPerformance()
if self.Database.isRecording():
if self.newFile:
print('starting new LogFile.')
self.Logfile = MKLogFileHandler('mkmain','log',True)
self.Logfile.open()
self.newFile = False
self.setFile = True
if self.setFile:
print('set FileName in Database')
if self.Database.setLogFile(self.Logfile.getLogFile()):
self.setFile = False
self.Logfile.write(oneline)
else:
self.newFile = True
self.getPerformance()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 | #!/usr/bin/env python
import MySQLdb as mysqlconnector
from MySQLdb.constants import CLIENT
import os
import socket
import decimal
import struct
from time import sleep
import multiprocessing
import ConfigParser
from MKFlowMessage import FBconvertLong # converter for long numbers to float and percent
#cvd-client->rbBmSDP7fSKp87b5
class MKDatabase(object):
sql = ""
connected = False
ready = False
messageID = -1
client = False
recording = False
recordingID = -1
fileName = ""
storage_description = 50
storage_values = 30
hostname = ""
# settings.cfg (see loadConfig)
dbUser = ""
dbPass = ""
dbHost = ""
dbName = ""
servername = ""
def __init__(self, isClient = False):
self.client = isClient
self.loadConfig()
self.test()
decimal.getcontext().prec = 2
def loadConfig(self):
config = ConfigParser.ConfigParser()
srcPath = os.path.dirname(os.path.realpath(__file__))
settingsFile = srcPath + '/../settings.cfg'
if not (os.path.exists(settingsFile)):
print "settings.cfg not found"
raise
config.read(settingsFile)
self.dbUser = config.get('Database', 'dbuser')
self.dbPass = config.get('Database', 'dbpass')
self.dbHost = config.get('Database', 'dbhost')
self.dbName = config.get('Database', 'dbname')
self.servername = config.get('Server', 'servername')
def open(self):
try:
if not self.checkIP():
print "server unavailable"
raise
self.db = mysqlconnector.connect(
host = self.dbHost,
user = self.dbUser,
passwd = self.dbPass,
db = self.dbName,
client_flag = CLIENT.FOUND_ROWS,
connect_timeout = 1
)
except:
print "database open failed."
self.close()
return False
else:
print "connected as user: %s" % self.dbUser
self.connected = True
return True
def close(self):
try:
self.db.close()
except:
if not self.checkIP():
print "connection lost. Database could not be closed normal"
self.connected = False
else:
self.connected = False
def isOpen(self):
#if not self.connected:
# return False
#try:
# stats = self.db.stat()
# if stats == 'MySQL server has gone away':
# self.close()
#except:
# self.connected = False
return self.connected
def write_without_timeout(self, db, sql, connection):
try:
cursor = db.cursor()
cursor.execute(sql)
affectedRows = cursor.rowcount
cursor.close()
db.commit()
except:
affectedRows = 0
try:
self.db.rollback()
except:
pass
connection.send(affectedRows)
connection.close()
def read_without_timeout(self, db, sql, connection):
affectedRows = 0
try:
cursor = db.cursor()
cursor.execute(sql)
data = cursor.fetchone()
cursor.close()
except:
connection.send([])
else:
connection.send(data)
connection.close()
# from alex martelli on http://stackoverflow.com/questions/1507091/python-mysqldb-query-timeout
def write(self, sql, update = False):
if not self.isOpen():
if not self.open():
raise
conn_parent, conn_child = multiprocessing.Pipe(False)
subproc = multiprocessing.Process(target = self.write_without_timeout,
args = (self.db, sql, conn_child))
subproc.start()
subproc.join(1)
if conn_parent.poll():
affectedRows = conn_parent.recv()
# on update statements rise if no lines were affected
if update and affectedRows == 0:
raise UpdateError('UPDATE statement failed')
else:
return affectedRows
subproc.terminate()
raise TimeoutError("Query %r ran for >%r" % (sql, timeout))
def read(self, sql):
if not self.isOpen():
if not self.open():
raise
conn_parent, conn_child = multiprocessing.Pipe(False)
subproc = multiprocessing.Process(target = self.read_without_timeout,
args = (self.db, sql, conn_child))
subproc.start()
subproc.join(1)
if conn_parent.poll():
data = conn_parent.recv()
try:
if len(data) == 0:
raise
except:
return []
else:
return data
else:
subproc.terminate()
return []
def writeArduino(self, sql):
try:
self.write(sql, True)
except:
try:
print "writeArduino failed: create database and try again."
self.createArduino()
self.resetArduino()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeRecording(self, sql):
try:
self.write(sql, True)
except:
try:
self.createRecording()
self.resetRecording()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeFlowbus(self, sql):
try:
self.write(sql)
except:
try:
self.createFlowbus()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeMessage(self, sql):
try:
self.write(sql, True)
except:
try:
self.createMessage()
self.resetMessage()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def test(self):
print "-- starting self-test --"
self.open()
sql="SELECT VERSION()"
data = self.read(sql)
self.close()
print "MySQL version : %s " % data
print "-- self test complete --"
def getHostname(self):
if self.hostname == "":
self.hostname = socket.gethostname()
return self.hostname
def isServer(self):
if (self.getHostname() == self.servername):
return True
else:
return False
def getIP(self):
if self.isServer():
ip = 'localhost'
else:
ip = self.dbHost
return ip
def checkIP(self, ip = ""):
if len(ip) == 0:
ip = self.getIP()
if ip == "localhost":
return True
command = "ping -c 1 -W 1 " + ip
print "executing '" + command + "'"
if os.system(command + " > /dev/null") == 0:
return True
else:
print "ip not found. sleeping penalty."
sleep(1)
return False
def createArduino(self):
sql = """CREATE TABLE IF NOT EXISTS `runtime_arduino` (
`temperature` decimal(6,2) NOT NULL DEFAULT '0',
`pressure` decimal(6,2) NOT NULL DEFAULT '0',
`argon` decimal(6,2) NOT NULL DEFAULT '0',
`ethanol` decimal(6,2) NOT NULL DEFAULT '0',
`spTemperature` int(11) NOT NULL DEFAULT '0',
`spPressure` int(11) NOT NULL DEFAULT '1000',
`spEthanol` int(11) NOT NULL DEFAULT '0',
`spArgon` int(11) NOT NULL DEFAULT '0'
) ENGINE=MEMORY DEFAULT Charset=utf8;"""
self.write(sql)
def resetArduino(self):
sql = """INSERT INTO `runtime_arduino`
(`temperature`, `pressure`, `argon`, `ethanol`, `spTemperature`, `spPressure`, `spEthanol`, `spArgon`)
VALUES
(0, 0, 0, 0, 0, 0, 0, 0);"""
self.write(sql)
def createFlowbus(self):
sql = """
CREATE TABLE IF NOT EXISTS `runtime_flowbus`
(
`instrument` smallint(2) NOT NULL DEFAULT '0',
`process` smallint(2) NOT NULL,
`flowBus` smallint(2) NOT NULL,
`dataType` tinyint(1) NOT NULL DEFAULT '0',
`parameter` binary(%i) NOT NULL DEFAULT '0',
`data` binary(%i) NOT NULL DEFAULT '0',
`time` decimal(7,2) NOT NULL DEFAULT '0',
UNIQUE KEY `instrument` (`instrument`,`process`,`flowBus`)
)
ENGINE=MEMORY
DEFAULT CHARSET=utf8;""" % (self.storage_description, self.storage_values)
self.write(sql)
def createRecording(self):
sql = """CREATE TABLE IF NOT EXISTS `runtime_recording` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`recording` tinyint(4) NOT NULL DEFAULT '0',
`id_recording` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
sql = """CREATE TABLE IF NOT EXISTS `recording` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`recording` tinyint(4) NOT NULL DEFAULT '0',
`filename` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
def resetRecording(self):
sql = """INSERT INTO `runtime_recording`
(`recording`)
VALUES
(0)"""
self.write(sql)
def createMessage(self):
sql = """CREATE TABLE IF NOT EXISTS `cvd`.`runtime_message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ready` tinyint(4) NOT NULL DEFAULT '0',
`id_message` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
sql = """CREATE TABLE IF NOT EXISTS `cvd`.`message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`processed` tinyint(4) NOT NULL DEFAULT '0',
`text` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
def resetMessage(self):
sql = """INSERT INTO `cvd`.`runtime_message`
(`ready`)
VALUES
(0)"""
self.write(sql)
sql = """DELETE FROM `cvd`.`message`
WHERE `processed` = 1"""
self.write(sql)
def setData(self, data, setpoint):
try:
self.temperature = decimal.Decimal(data[0])
self.pressure = decimal.Decimal(data[1])
self.argon = decimal.Decimal(data[2])
self.ethanol = decimal.Decimal(data[3])
except:
self.temperature = 0.00
self.pressure = 0.00
self.argon = 0.00
self.ethanol = 0.00
try:
self.spTemperature = int(setpoint[0])
self.spPressure = int(setpoint[1])
self.spArgon = int(setpoint[2])
self.spEthanol = int(setpoint[3])
except:
self.spTemperature = 0
self.spPressure = 1000
self.spEthanol = 0
self.spArgon = 0
sql = """UPDATE `cvd`.`runtime_arduino`
SET `temperature` = %s,
`pressure` = %s,
`ethanol` = %s,
`argon` = %s,
`spTemperature` = %s,
`spPressure` = %s,
`spEthanol` = %s,
`spArgon` = %s;""" % (self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon)
return self.writeArduino(sql)
def setLogFile(self, fileName):
id = self.getRecordingID()
if id < 0:
return False
sql = """UPDATE `cvd`.`recording`
SET `filename` = '%s',
`recording` = 1
WHERE `id` = %i
LIMIT 1;""" % (fileName, id)
if not self.writeRecording(sql):
return False
if self.getLogFile() == fileName:
return True
else:
return False
def isRecording(self):
sql = """SELECT `recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 1:
return False
else:
if data[0]:
return True
else:
return False
def stopRecording(self):
sql = """UPDATE `cvd`.`runtime_recording`
SET `recording` = 0;"""
if not self.writeRecording(sql):
return False
sql = """UPDATE `cvd`.`recording`
SET `recording` = 0
WHERE `recording` = 1;"""
if not self.writeRecording(sql):
return False
self.recordingID = -1
return True
def startRecording(self, filename = ''):
self.stopRecording
sql = """INSERT INTO `cvd`.`recording` (
`id` ,`time` , `recording` , `filename` )
VALUES (
NULL , CURRENT_TIMESTAMP , 1, '%s')""" % filename
if not self.writeRecording(sql):
return False
sql = """SELECT `id`
FROM `cvd`.`recording`
WHERE `recording` = 1
LIMIT 1;"""
data = self.read(sql)
if not len(data) == 1:
return False
sql = """UPDATE `cvd`.`runtime_recording`
SET `id_recording` = %i,
`recording` = 1
LIMIT 1;""" % data
if not self.writeRecording(sql):
return False
return True
def getRecordingID(self):
sql = """SELECT `id_recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
return int(data[0])
else:
return -1
def getLogFile(self):
# get id from memory table
recordingID = self.getRecordingID()
# update filename from disc table if not already saved in class
if not (recordingID == self.recordingID) or len(self.fileName) == 0:
print "querying filename from sql table"
self.close()
sql = """SELECT `filename`
FROM `cvd`.`recording`
WHERE `id` = %i;""" % recordingID
data = self.read(sql)
if len(data) == 1:
self.fileName = data[0]
else:
self.fileName = ''
self.recordingID = recordingID
return self.fileName
def setMessage(self, message):
sql = """INSERT INTO `cvd`.`message`
(`text`) VALUES ('%s');""" % (message)
if self.writeMessage(sql):
return self.updateMessage()
return False
def updateMessage(self):
sql = """SELECT `id` FROM `cvd`.`message`
WHERE `processed` = 0
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
id_message = data[0]
ready = 1
else:
ready = 0
id_message = -1
sql = """UPDATE `cvd`.`runtime_message`
SET `ready` = %i,
`id_message` = %i
LIMIT 1;""" % (ready, id_message)
return self.writeMessage(sql)
def isReady(self):
if self.ready:
return True
sql = """SELECT `ready`, `id_message`
FROM `cvd`.`runtime_message`;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 2:
data = (0,-1)
(self.ready, self.messageID) = data
if self.ready:
return True
else:
return False
def getMessage(self):
self.message = ""
# read from runtime (memory table)
if self.isReady():
# ready flag did also read out messageID.
# get message string from cvd.message
sql = """SELECT `text`
FROM `cvd`.`message`
WHERE `id` = %i
LIMIT 1;""" % self.messageID
data = self.read(sql)
if (len(data) == 1):
self.message = data[0]
# mark message in cvd.message as processed
sql = """UPDATE `cvd`.`message`
SET `processed` = 1
WHERE `id` = %i;""" % self.messageID
self.writeMessage(sql)
self.updateMessage()
# reset readout
self.ready = False
return self.message
def setFlowbus(self, instrument, process, flowBus, dataTypeString, dataInput, timeInput, parameterName):
time = decimal.Decimal(timeInput)
parameterName = parameterName.encode("hex")
if (dataTypeString == "character"):
dataType = 0
data = format(int(dataInput), 'x')
elif(dataTypeString == "integer"):
dataType = 1
data = format(int(dataInput), 'x')
elif(dataTypeString == "long"):
dataType = 2
data = format(int(dataInput), 'x')
elif(dataTypeString == "string"):
dataType = 3
data = dataInput.encode("hex")
else:
raise ValueError("can not identify dataType at setFlowBus()")
sql = """
INSERT INTO `cvd`.`runtime_flowbus`
(`instrument`,`process`,`flowBus`,`dataType`,`data`,`time`, `parameter`)
VALUES
(%i, %i, %i, %i, UNHEX(LPAD('%s',%i,'0')), %.2f, UNHEX(LPAD('%s',%i,'0')))""" % (instrument, process, flowBus, dataType, data, self.storage_values * 2, time, parameterName, self.storage_description * 2)
sql += """
ON DUPLICATE KEY UPDATE
`data` = UNHEX(LPAD('%s',%i,'0')),
`time` = %.2f;""" % (data, self.storage_values * 2, time)
self.writeFlowbus(sql)
def getFlowbus(self, instrument, process, flowBus):
sql = """
SELECT `dataType`,TRIM(LEADING '0' FROM HEX(`data`)),`time`,TRIM(LEADING '0' FROM HEX(`parameter`))
FROM `cvd`.`runtime_flowbus`
WHERE
( `instrument` = %i
AND `process` = %i
AND `flowBus` = %i);
""" % (instrument, process, flowBus)
data = self.read(sql)
if (len(data) == 4):
(dataType, dataOut, timeOut, parameter) = data
else:
return (-1,-1,-1)
parameter = parameter.decode("hex")
time = decimal.Decimal(timeOut)
if (dataType == 0):
data = int(dataOut, 16)
elif(dataType == 1):
data = int(dataOut, 16)
elif(dataType == 2):
data = FBconvertLong(process, flowBus, int(dataOut,16))
elif(dataType == 3):
data = dataOut.decode("hex")
else:
raise ValueError("can not identify dataType at getFlowBus()")
return (parameter, data, time)
def getAll(self):
sql = """SELECT temperature, pressure, ethanol, argon,
spTemperature, spPressure, spEthanol, spArgon
FROM `cvd`.`runtime_arduino`
LIMIT 1"""
data = self.read(sql)
if len(data) == 0:
print "database readout failed for arduino!"
data = (-1,-1,-1,-1, -1,-1,-1,-1)
(self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon) = data
class UpdateError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class TimeoutError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
sql = """UPDATE `cvd`.`runtime_arduino`
SET `temperature` = %s,
`pressure` = %s,
`ethanol` = %s,
`argon` = %s
`spTemperature` = %s,
`spPressure` = %s,
`spEthanol` = %s,
`spArgon` = %s
LIMIT 1;""" % (self.temperature, self.pressure, self.ethanol, self.argon, setpoint[0], setpoint[1], setpoint[2], setpoint[2])
return self.writeArduino(sql)
def setLogFile(self, fileName):
id = self.getRecordingID()
if id < 0:
return False
sql = """UPDATE `cvd`.`recording`
SET `filename` = '%s',
`recording` = 1
WHERE `id` = %i
LIMIT 1;""" % (fileName, id)
if not self.writeRecording(sql):
return False
if self.getLogFile() == fileName:
return True
else:
return False
def isRecording(self):
sql = """SELECT `recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 1:
return False
else:
if data[0]:
return True
else:
return False
def stopRecording(self):
sql = """UPDATE `cvd`.`runtime_recording`
SET `recording` = 0;"""
if not self.writeRecording(sql):
return False
sql = """UPDATE `cvd`.`recording`
SET `recording` = 0
WHERE `recording` = 1;"""
if not self.writeRecording(sql):
return False
self.recordingID = -1
return True
def startRecording(self, filename = ''):
self.stopRecording
sql = """INSERT INTO `cvd`.`recording` (
`id` ,`time` , `recording` , `filename` )
VALUES (
NULL , CURRENT_TIMESTAMP , 1, '%s')""" % filename
if not self.writeRecording(sql):
return False
sql = """SELECT `id`
FROM `cvd`.`recording`
WHERE `recording` = 1
LIMIT 1;"""
data = self.read(sql)
if not len(data) == 1:
return False
sql = """UPDATE `cvd`.`runtime_recording`
SET `id_recording` = %i,
`recording` = 1
LIMIT 1;""" % data
if not self.writeRecording(sql):
return False
return True
def getRecordingID(self):
sql = """SELECT `id_recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
return int(data[0])
else:
return -1
def getLogFile(self):
# get id from memory table
recordingID = self.getRecordingID()
# update filename from disc table if not already saved in class
if not (recordingID == self.recordingID) or len(self.fileName) == 0:
print "querying filename from sql table"
self.close()
sql = """SELECT `filename`
FROM `cvd`.`recording`
WHERE `id` = %i;""" % recordingID
data = self.read(sql)
if len(data) == 1:
self.fileName = data[0]
else:
self.fileName = ''
self.recordingID = recordingID
return self.fileName
def setMessage(self, message):
sql = """INSERT INTO `cvd`.`message`
(`text`) VALUES ('%s');""" % (message)
if self.writeMessage(sql):
return self.updateMessage()
return False
def updateMessage(self):
sql = """SELECT `id` FROM `cvd`.`message`
WHERE `processed` = 0
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
id_message = data[0]
ready = 1
else:
ready = 0
id_message = -1
sql = """UPDATE `cvd`.`runtime_message`
SET `ready` = %i,
`id_message` = %i
LIMIT 1;""" % (ready, id_message)
return self.writeMessage(sql)
def isReady(self):
if self.ready:
return True
sql = """SELECT `ready`, `id_message`
FROM `cvd`.`runtime_message`;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 2:
data = (0,-1)
(self.ready, self.messageID) = data
if self.ready:
return True
else:
return False
def getMessage(self):
self.message = ""
# read from runtime (memory table)
if self.isReady():
# ready flag did also read out messageID.
# get message string from cvd.message
sql = """SELECT `text`
FROM `cvd`.`message`
WHERE `id` = %i
LIMIT 1;""" % self.messageID
data = self.read(sql)
if (len(data) == 1):
self.message = data[0]
# mark message in cvd.message as processed
sql = """UPDATE `cvd`.`message`
SET `processed` = 1
WHERE `id` = %i;""" % self.messageID
self.writeMessage(sql)
self.updateMessage()
# reset readout
self.ready = False
return self.message
def setFlowbus(self, instrument, process, flowBus, dataTypeString, dataInput, timeInput, parameterName):
time = decimal.Decimal(timeInput)
parameterName = parameterName.encode("hex")
if (dataTypeString == "character"):
dataType = 0
data = format(int(dataInput), 'x')
elif(dataTypeString == "integer"):
dataType = 1
data = format(int(dataInput), 'x')
elif(dataTypeString == "long"):
dataType = 2
data = format(int(dataInput), 'x')
elif(dataTypeString == "string"):
dataType = 3
data = dataInput.encode("hex")
else:
raise ValueError("can not identify dataType at setFlowBus()")
sql = """
INSERT INTO `cvd`.`runtime_flowbus`
(`instrument`,`process`,`flowBus`,`dataType`,`data`,`time`, `parameter`)
VALUES
(%i, %i, %i, %i, UNHEX(LPAD('%s',%i,'0')), %.2f, UNHEX(LPAD('%s',%i,'0')))""" % (instrument, process, flowBus, dataType, data, self.storage_values * 2, time, parameterName, self.storage_description * 2)
sql += """
ON DUPLICATE KEY UPDATE
`data` = UNHEX(LPAD('%s',%i,'0')),
`time` = %.2f;""" % (data, self.storage_values * 2, time)
self.writeFlowbus(sql)
def getFlowbus(self, instrument, process, flowBus):
sql = """
SELECT `dataType`,TRIM(LEADING '0' FROM HEX(`data`)),`time`,TRIM(LEADING '0' FROM HEX(`parameter`))
FROM `cvd`.`runtime_flowbus`
WHERE
( `instrument` = %i
AND `process` = %i
AND `flowBus` = %i);
""" % (instrument, process, flowBus)
data = self.read(sql)
if (len(data) == 4):
(dataType, dataOut, timeOut, parameter) = data
else:
return (-1,-1,-1)
parameter = parameter.decode("hex")
time = decimal.Decimal(timeOut)
if (dataType == 0):
data = int(dataOut, 16)
elif(dataType == 1):
data = int(dataOut, 16)
elif(dataType == 2):
data = FBconvertLong(process, flowBus, int(dataOut,16))
elif(dataType == 3):
data = dataOut.decode("hex")
else:
raise ValueError("can not identify dataType at getFlowBus()")
return (parameter, data, time)
def getAll(self):
sql = """SELECT temperature, pressure, ethanol, argon,
spTemperature, spPressure, spEthanol, spArgon
FROM `cvd`.`runtime_arduino`
LIMIT 1"""
data = self.read(sql)
if len(data) == 0:
print "database readout failed for arduino!"
data = (-1,-1,-1,-1, -1,-1,-1,-1)
(self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon) = data
class UpdateError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class TimeoutError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | #!/usr/bin/env python
import MKDatabase
from MKFlowMessage import FBconvertLong
# Main Class
class MKFlowCommunication():
def __init__(self):
self.nullNode = MKFlowNode(-1)
self.node_numbers = []
self.nodes = []
def addNode(self, number):
if not self.isNode(number):
self.node_numbers += [number]
node = MKFlowNode(number)
self.nodes += [node]
def isNode(self, number):
return (number in self.node_numbers)
def getNode(self, number):
if self.isNode(number):
id = self.node_numbers.index(number)
node = self.nodes[id]
return node
else:
return self.nullNode
def Node(self, number):
if not self.isNode(number):
self.addNode(number)
return self.getNode(number)
class MKFlowNode():
def __init__(self, node):
self.node = node
self.nullSequence = MKFlowSequence(-1)
self.sequence_numbers = []
self.sequences = []
def getNumber(self):
return self.node
def addSequence(self, number):
if not self.isSequence(number):
self.sequence_numbers += [number]
sequence = MKFlowSequence(number)
self.sequences += [sequence]
def isSequence(self, number):
return (number in self.sequence_numbers)
def getSequence(self, number):
if self.isSequence(number):
id = self.sequence_numbers.index(number)
sequence = self.sequences[id]
return sequence
else:
return self.nullSequence
def Sequence(self, number):
if not self.isSequence(number):
self.addSequence(number)
return self.getSequence(number)
class MKFlowSequence():
def __init__(self, sequence):
self.sequence = sequence
self.nullChild = MKFlowModbus(-1)
self.reset()
def reset(self):
self.parameter_ids = []
self.parameters = []
self.hasAnswer = False
self.hasRequest = False
self.RequestHasValue = False
self.isAnalysed = False
self.isStatus = False
self.isError = False
self.isValid = False
def setReadRequest(self, Message):
self.Request = Message.getSubType()
self.hasRequest = True
self.hasAnswer = False
self.RequestHasValue = False
self.timeRequest = Message.getSeconds()
def setWriteRequest(self, Message):
self.setReadRequest(Message)
self.RequestHasValue = True
def setStatus(self, Message):
self.setAnswer(Message)
self.isStatus = True
def setError(self, Message):
self.setAnswer(Message)
self.isError = True
def setAnswer(self, Message):
self.Answer = Message.getSubType()
self.timeAnswer = Message.getSeconds()
self.hasAnswer = True
self.isStatus = False
self.isError = False
def check(self):
if self.hasAnswer and self.hasRequest:
if abs(self.timeAnswer - self.timeRequest) > 10:
return False
else:
return True
else:
return False
def addParameter(self, index):
if not self.isParameter(index):
self.parameter_ids += [index]
Parameter = MKFlowModbus(index)
self.parameters += [Parameter]
def isParameter(self, index):
return index in self.parameter_ids
def getParameter(self, index):
if self.isParameter(index):
id = self.parameter_ids.index(index)
Parameter = self.parameters[id]
return Parameter
else:
return self.nullChild
def Parameter(self, index):
if not self.isParameter(index):
self.addParameter(index)
return self.getParameter(index)
def analyse(self):
if self.check():
# Process Request
for process in self.Request.process:
for parameter in process.Parameter:
self.Parameter(parameter.getIndex()).setNumber(parameter.getNumber())
self.Parameter(parameter.getIndex()).setProcess(parameter.getProcess())
self.Parameter(parameter.getIndex()).setName(parameter.getHuman())
self.Parameter(parameter.getIndex()).setLength(parameter.getLength())
if self.RequestHasValue:
self.Parameter(parameter.getIndex()).setValue(parameter.getValue())
self.Parameter(parameter.getIndex()).setDataType(parameter.getDataType())
# Process Answer
if not self.RequestHasValue and not self.isStatus and not self.isError:
for process in self.Answer.process:
for parameter in process.Parameter:
self.Parameter(parameter.getIndex()).setValue(parameter.getValue())
self.Parameter(parameter.getIndex()).setDataType(parameter.getDataType())
# Answer with Status or Error and set valid
self.valid = True
self.analyseStatus()
self.analyseError()
self.isAnalysed = True
def analyseStatus(self):
if self.isStatus:
if self.Answer.getStatus() == 0:
# no error
self.valid = True
elif self.Answer.getStatus() > 3 and self.Answer.getStatus() < 8:
# Parameter Error
where = self.Answer.getIndex()
count = 4
for index in self.parameter_ids:
Parameter = self.getParameter(index)
if not self.RequestHasValue:
Parameter.setInvalid()
if where == count:
self.error = "Status: %s\t Parameter: %s" % (self.Answer.getHuman(), Parameter.getName())
Parameter.setError(self.Answer.getHuman())
count += int(Parameter.getLength())
else:
self.error = self.Answer.getHuman()
self.valid = False
def analyseError(self):
if self.isError:
self.error = self.Answer.getText()
self.valid = False
if not self.valid:
for index in self.parameter_ids:
Parameter = self.getParameter(index)
Parameter.setError(self.error)
def output(self):
if self.check():
if not self.isAnalysed:
self.analyse()
for index in self.parameter_ids:
Parameter = self.getParameter(index)
try:
Parameter.stdout()
except:
self.stdout()
raise ValueError("error in MKFlowCommunication ModbusClass stdout")
def save(self, Database, instrument = 0):
if self.check():
reset = True
if not self.isAnalysed:
self.analyse()
for index in self.parameter_ids:
Parameter = self.getParameter(index)
try:
if not Parameter.isInvalid():
valid = True
proc = Parameter.getProcess()
fbnr = Parameter.getNumber()
name = Parameter.getName()
value = Parameter.getValue()
dataType = Parameter.getDataType()
time = self.timeAnswer
parameter = Parameter.getName()
reset = Database.setFlowbus(instrument, proc, fbnr, dataType, value, time, parameter)
except:
self.stdout()
print "error storing parameter."
reset = False
if reset:
self.reset()
else:
print "Sequence not cleared."
def stdout(self):
print "--- sequence: %i ---" % self.sequence
print "---- parameters: %s ----" % self.parameter_ids
if self.hasRequest:
print "---- request ----"
self.Request.stdout()
if self.hasAnswer:
print "---- answer ----"
self.Answer.stdout()
class MKFlowModbus():
def __init__(self, index):
self.index = index
self.invalid = False
self.error = ''
self.value = None
self.human = ''
self.dataType = 'invalid' # readybility. store as string
self.length = 0
def setProcess(self, process):
self.process = process
def getProcess(self):
return self.process
def setNumber(self, number):
self.number = number
def getNumber(self):
return self.number
def setValue(self, value):
self.value = value
def getValue(self):
return self.value
def setDataType(self, dataType):
self.dataType = dataType
def getDataType(self):
return self.dataType
def setName(self, string):
self.human = string
def getName(self):
return self.human
def setInvalid(self):
self.invalid = True
def setLength(self, length):
self.length = length
def getLength(self):
return self.length
def setError(self, error):
self.error = error
self.setInvalid()
def isInvalid(self):
if self.invalid:
return True
else:
return False
def stdout(self):
returnarray = [self.isInvalid(), self.getProcess(), self.getNumber(), self.getName()]
if not self.invalid:
returnarray += [FBconvertLong(self.getProcess(), self.getNumber(), self.getValue())]
else:
returnarray += [self.error]
print '\t'.join(str(i) for i in returnarray)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #!/usr/bin/env python
#import struct # imports struct API ???
import os # imports file system functions like open()
import time # sleep
import subprocess # socat
import MKFlowMessage # Message analyis class
from MKFlowSocat import MKFlowSocat
from MKFlowLogFile import MKFlowLogFile
# Main Class
class MKFlowInput():
def __init__(self):
self.reset()
def reset(self):
self.message1 = ''
self.message2 = ''
self.socat = False
self.log = False
self.port1 = ''
self.port2 = ''
def setLogFile(self,filename):
self.input = MKFlowLogFile(filename)
self.start()
def setBridge(self, port1, port2):
self.input = MKFlowSocat(port1, port2)
self.start()
def start(self):
self.input.open()
self.input.start()
def stop(self):
self.input.stop()
def readOut(self):
while not self.input.isReady():
time.sleep(0.1)
self.message1, self.message2 = self.input.read()
def getMessage(self):
try:
Message = self.Message()
self.readOut()
Message.process(self.message2, self.message1)
if Message.isInvalid:
# try next message. maybe they belong together
message_buffer = self.message2
self.readOut()
Message.process(self.message2, self.message1)
if Message.isInvalid:
message_buffer += self.message2
Message.process(message_buffer, self.message1)
except:
self.input.stop()
raise
else:
return Message
def isAlive(self):
return self.input.isAlive()
# shortcut
class Message(MKFlowMessage.MKFlowMessage):
class Invalid(MKFlowMessage.MKFlowInvalid):
pass
class Error(MKFlowMessage.MKFlowError):
pass
class Status(MKFlowMessage.MKFlowStatus):
pass
class Request(MKFlowMessage.MKFlowRequest):
pass
class Sent(MKFlowMessage.MKFlowSent):
pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | class MKFlowLogFile():
def __init__(self, logfile):
self.reset()
self.logfile = logfile
def reset(self):
self.logfile = ''
self.openmode = 'r'
self.fsoOpen = False
def open(self):
if not self.fsoOpen:
try:
self.fso = open(self.logfile, self.openmode)
except:
self.close()
raise ValueError('cannot open log file at ' + self.logfile)
else:
self.fsoOpen = True
def close(self):
if self.fsoOpen:
try:
self.fso.close()
except:
raise ValueError('cannot close log file at ' + self.logfile)
else:
self.fsoOpen = False
def read(self):
try:
self.open()
message1 = self.fso.readline()
message2 = self.fso.readline()
if (len(message2) == 0):
raise EOF("end of file reached")
except EOF:
self.close()
raise EOF
except:
message1 = ''
message2 = ''
return message1, message2
def start(self):
self.alive = True
def stop(self):
try:
self.close()
self.reset()
except:
print 'error closing logfile'
else:
self.alive = False
def isReady(self):
# ready while alive for log file
return self.isAlive()
def isAlive(self):
return self.alive
class EOF(Exception):
pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #!/usr/bin/env python
import threading
from MKFlowInput import MKFlowInput
from MKFlowCommunication import MKFlowCommunication
from MKDatabase import MKDatabase
class MKFlow():
def __init__(self, port1 = '/dev/ttyUSB2', port2 = '/dev/ttyUSB3', instrument = 0):
self.Input = MKFlowInput()
self.Storage = MKFlowCommunication()
self.Database = MKDatabase()
self.Input.setBridge(port1, port2)
#self.Input.setLogFile('/home/matthias/Documents/programs/python/swnt-reactor/data/log/bridge/testing/log1.log')
self.instrument = instrument
self.debugging = False
def debug(self):
self.debugging = True
def start(self):
try:
self.thread = threading.Thread(target=self.loop)
self.thread.daemon = True
self.thread.start()
except:
self.stop()
raise
def stop(self):
self.Input.stop()
def join(self):
self.thread.join()
def loop(self):
while self.Input.isAlive():
try:
Message = self.Input.getMessage()
SubMessage = Message.getSubType()
except:
break
else:
if not Message.isInvalid:
node = Message.getNode()
sequence = Message.getSequence()
Entity = self.Storage.Node(node).Sequence(sequence)
try:
if Message.isError:
Entity.setError(Message)
elif Message.isStatus:
Entity.setStatus(Message)
elif Message.isSent:
Entity.setAnswer(Message)
elif Message.isSentStatus:
Entity.setWriteRequest(Message)
elif Message.isRequest:
Entity.setReadRequest(Message)
else:
raise
except:
print "--- something happened ---"
try:
Message.stdout()
Submessage.stdout()
Entity.reset()
except:
raise
else:
# store if two messages are present in current Entity
# reset Entity afterwards.
try:
if self.debugging:
bufferSize = self.Input.input.bufferSize()
if bufferSize > 0:
print "Buffer: %i" % bufferSize
Entity.output()
Entity.save(self.Database, self.instrument)
pass
except ValueError:
raise
pass
except:
raise
else:
print "--- invalid ---"
SubMessage.stdoutShort(Message.stdoutShort())
pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 | #!/usr/bin/env python
from datetime import datetime # datetime supports milliseconds. time doesn't
import sys # used to get line number of error print sys.exc_traceback.tb_lineno
import struct # used to convert bin-->float
def FBconvertLong(process, fbnr, value):
if process == 33:
if fbnr == 0 or fbnr == 3:
return toFloat(value)
elif process == 114:
if fbnr == 1:
return float(value) / 16777215.0 * 100.0
return value
def toFloat(integer):
# convert integer to IEE float
return struct.unpack(">f", struct.pack(">I", integer))[0]
def fromFloat(floatingpoint):
# convert IEE float to integer
return struct.unpack('<I', struct.pack('<f', float(floatingpoint)))[0]
class MKFlowMessage():
def __init__(self):
self.clear()
# input binary message and socat headline
def process(self, message, socat = ''):
self.message1 = socat
self.message2 = message
self.resetSubType()
self.analyse()
def resetSubType(self):
# message type identifier
self.commandByte= -3
self.isInvalid = False # -2
self.isError = False # -1
self.isStatus = False # 0
self.isSent = False # 2
self.isSentStatus = False # 1
self.isRequest = False # 4
# clear message objects
self.Invalid = MKFlowInvalid()
self.Error = MKFlowError()
self.Status = MKFlowStatus()
self.Sent = MKFlowSent()
#self.SentStatus = MKFlowSentStatus()
self.Request = MKFlowRequest()
def getSubType(self):
if self.isInvalid:
return self.Invalid
if self.isError:
return self.Error
if self.isStatus:
return self.Status
if self.isSent or self.isSentStatus:
return self.Sent
if self.isRequest:
return self.Request
def clear(self):
self.data = []
self.node = -1
self.sequence = -1
self.length = -1
self.dataLength = -1
self.commandByte= -1
self.commandByteHuman = ''
self.commandByteHumanShort = ''
self.direction = ''
self.time = datetime
self.time_human = "%Y/%m/%d;%H:%M:%S.%f"
self.time_second = 0.00
def getNode(self):
return self.node
def getSequence(self):
return self.sequence
def getLength(self):
return self.length
def setLength(self, length):
self.length = length
def getDirection(self):
return self.direction
def getTime(self):
return self.time_human
def getSeconds(self):
return self.time_second
def getCommandByte(self):
return self.commandByte
def getCommandByteShort(self):
return self.commandByteHumanShort
def trim(self):
self.message1 = self.message1.replace('\n','')
self.message2 = self.message2.replace('\n','')
while self.message2[0:1] == " ":
self.message2 = self.message2[1:]
if len(self.message2) == 0:
break
def split(self):
self.message1 = self.message1.split(" ")
self.message2 = self.message2.split(" ")
def analyseDirection(self):
if self.message1[0] == '>':
self.direction = 'right'
elif self.message1[0] == '<':
self.direction = 'left'
else:
self.direction = 'none'
def analyseTime(self):
if len(self.message1) > 1:
self.time = datetime.strptime(self.message1[1] + ';' + self.message1[2], "%Y/%m/%d;%H:%M:%S.%f")
else:
self.time = datetime.now()
self.time_human = self.time.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
self.time_second = self.time.hour*60*60 + self.time.minute * 60 + self.time.second + self.time.microsecond/1e6
def parseMessage(self):
try:
self.trim()
self.split()
except:
self.Invalid.add('MKFlowMessage:parseMessage:\tError while parsing')
raise
def parseData(self):
#replace two DLE (escaped) sequences (10 10) by one databyte (10)
try:
start = 0
foundOne = False
while len(self.data) -1 > start:
found = self.data[start:].index(16)
if self.data[(found+start+1)] == 16:
self.data.pop(found+start)
start = start + found
foundOne = True
else:
start +=1
except ValueError:
# 10 not found. Ignore
pass
except:
# other errors --> report
self.Invalid.add('parseData Error at found: %i start: %i len: %i' % (found, start, len(self.data)))
raise
def checkMessage2(self):
# dataLength is length-Byte
if not (self.dataLength==len(self.data)-3) and not (self.dataLength == 0):
self.Invalid.add('MKFlowMessage:parseMessage2:\tError in socat output: length-Byte in message does not match socat length')
if (len(self.message2)<6):
self.Invalid.add('MKFlowMessage:parseMessage2:\tMessage shorter than 6 bytes: DLE STX SEQUENCE NODE ... DLE ETX')
# DLE STX SEQUENCE NODE LEN DATA DLE ETX
if not ((self.message2[0] == "10") and (self.message2[1] == "02")):
self.Invalid.add('MKFlowMessage:parseMessage2:\tno valid message beginning:\tDLE (0x10) STX (0x02) missing')
if not ((self.message2[-2] == "10") and (self.message2[-1] == "03")):
self.Invalid.add('MKFlowMessage:parseMessage2:\tno valid message ending:\tDLE (0x10) ETX (0x03) missing')
if self.Invalid.isActive():
raise ValueError('MKFlowMessage:parseMessage2:\tError while processing Message2')
def analyse(self):
try:
self.parseMessage()
self.analyseMessage()
self.analyseMessageType()
self.analyseCommandByte()
if self.Invalid.isActive():
raise ValueError('MKFlowMessage:analyse:\tMessage invalid')
except Exception as e:
self.Invalid.add('MKFlowMessage:analyse:\t'+str(e))
self.Invalid.add('MKFlowMessage:analyse:\tLine number:\t' + str(sys.exc_traceback.tb_lineno))
self.Invalid.add('MKFlowMessage:analyse:\tcommandByte:\t' + str(self.commandByte))
self.commandByte = -2
self.isInvalid = True
#raise
def analyseMessage(self):
# DLE STX SEQUENCE NODE LEN DATA DLE ETX
try:
self.analyseMessage1()
self.analyseMessage2()
except:
self.Invalid.add('MKFlowMessage:analyseMessage:\tError while extracting data.')
raise
def analyseMessage1(self):
try:
self.analyseDirection()
self.analyseTime()
self.setLength(len(self.message2))
except:
self.Invalid.add('MKFlowMessage:analyseMessage1:\tError while processing message1')
raise
def analyseMessage2(self):
# DLE STX SEQUENCE NODE LEN DATA DLE ETX
try:
self.data = [int(i,16) for i in self.message2[2:-2]]
self.parseData()
self.sequence = self.data[0]
self.node = self.data[1]
self.dataLength = self.data[2]
self.checkMessage2()
except:
self.Invalid.add('MKFlowMessage:analyseMessage2:\tError while extracting data.')
if len(self.data)<3:
self.Invalid.add('MKFlowMessage:analyseMessage2:\tlen(data)='+str(len(self.data)))
raise
def analyseMessageType(self):
# check if the message contains information
try:
# length 0 means.Error.Status in message. next byte after 00 contains.Error code.
if self.data[2] == 0:
self.commandByte = -1
else:
self.commandByte = self.data[3]
except:
self.Invalid.add('MKFlowMessage:analyseMessageType Error while retrieving Message')
raise
def analyseCommandByte(self):
try:
self.translateCommandByte()
if self.commandByte == -2:
self.isInvalid = True
elif self.commandByte == -1:
self.isError = True
self.Error.set(self.data[3:])
self.Error.setSequence(self.sequence)
self.Error.setNode(self.node)
self.Error.analyse()
elif self.commandByte == 0:
self.Status.set(self.data[4:])
self.Status.analyse()
self.isStatus = True
elif self.commandByte == 4:
self.Request.set(self.data[4:])
self.isRequest = True
elif (self.commandByte == 2):
self.Sent.set(self.data[4:])
self.isSent = True
elif (self.commandByte == 1):
self.Sent.set(self.data[4:])
self.isSentStatus = True
else:
myError = 'MKFlowMessage:analyseCommandByte commandByte ' + str(self.commandbyte) + ' not handled'
self.Invalid.add(myError)
self.Invalid.add(self.commandByteHuman)
raise ValueError(myError)
except:
raise
def translateCommandByte(self):
try:
if self.commandByte == -2:
self.commandByteHuman = "Invalid Message: Error in Program"
elif self.commandByte == -1:
self.commandByteHuman = "Valid Message: Error Message from Device"
elif self.commandByte == 0:
self.commandByteHuman = "Status message"
elif self.commandByte == 1:
self.commandByteHuman = "Send Parameter with destination address, will be answered with type 00 command"
elif self.commandByte == 2:
self.commandByteHuman = "Send Parameter with destination address, no.Status.Requested"
elif self.commandByte == 3:
self.commandByteHuman = "Send Parameter with source address, no.Status.Requested"
elif self.commandByte == 4:
self.commandByteHuman = "Request Parameter, will be answered with type 02 or 00 command"
elif self.commandByte == 6:
self.commandByteHuman = "Stop Process"
elif self.commandByte == 7:
self.commandByteHuman = "Start Process"
elif self.commandByte == 8:
self.commandByteHuman = "Claim Process"
elif self.commandByte == 9:
self.commandByteHuman = "Unclaim Process"
else:
self.commandByteHuman = "unhandled commandByte: " + str(self.commandByte)
raise ValueError(self.commandByteHuman)
if self.commandByte == 4:
self.commandByteHumanShort = 'REQ'
elif (self.commandByte >= 1) and (self.commandByte <= 3):
self.commandByteHumanShort = 'ST' + str(self.commandByte)
if self.commandByte == -2:
self.commandByteHumanShort = 'INV'
if self.commandByte == -1:
self.commandByteHumanShort = 'ERR'
if self.commandByte == 0:
self.commandByteHumanShort = 'INF'
except:
raise
def stdout(self):
print '-- message Class Output begin --'
print self.message1
print self.message2
print 'direction: \t' , self.getDirection()
print 'length: \t' , self.getLength()
print 'time: \t' , self.getTime()
print 'seconds: \t' , self.getSeconds()
print 'sequence: \t' , self.getSequence()
print 'node: \t' , self.getNode()
print 'command: \t' , self.getCommandByte()
print '-- message end --'
def stdoutShort(self, indent=''):
return '\t'.join(str(i) for i in [indent, self.getNode(), self.getSequence(), self.getCommandByteShort()])
# Message Type Classes
class MKFlowInvalid():
def __init__(self):
self.value = ''
self.active = False
def add(self, newValue):
self.active = True
self.value += str(newValue) + '\n'
def get(self):
if self.active:
return self.value
else:
return
def isActive(self):
return self.active
def stdout(self, leading = '\t'):
print leading, "-- MKFlowRequest Class Output Begin --"
print leading, "Value:\t", self.value
print leading, "-- MKFlowRequest Class Output End --"
def stdoutShort(self, indent=''):
return '\t'.join(str(i) for i in [indent, self.isActive()])
class MKFlowError():
def __init__(self):
self.value = 0
self.node = -1
self.sequence = -1
self.text = ''
self.active = False
def set(self, data):
self.active = True
self.data = data
self.value = data[0]
def setNode(self, node):
self.node = node
def setSequence(self,sequence):
self.sequence = sequence
def analyse(self):
if not len(self.data) == 1:
raise ValueError('Error Class has received too many input bytes')
self.translate()
def getText(self):
return self.text
def getHuman(self):
return self.getText()
def getValue(self):
return self.value
def getData(self):
return self.data
def translate(self):
if self.active:
self.text = 'device returned error code ' + str(self.value) + ': '
if (self.value==3):
self.text += 'propar protocol error'
elif (self.value==4):
self.text += 'propar protocol error (or CRC error)'
elif (self.value==5):
if self.node >= 0:
self.text += 'destination node address ' + str(self.node) + ' rejected'
else:
self.text += 'destination node address rejected'
if self.sequence >= 0:
self.text += ' for sequence ' + str(self.sequence)
elif (self.value==9):
self.text += 'response message timeout'
def stdout(self, indent = '\t'):
print indent, '-- Error Class Output Begin--'
print indent, 'Error Data:\t', self.getData()
print indent, 'Error Number:\t', self.getValue()
print indent, 'Error Message:\t', self.getText()
print indent, '-- Error Class Output Begin--'
def stdoutShort(self, indent=''):
return '\t'.join(str(i) for i in [indent, self.getValue(),None,None,self.getHuman()])
class MKFlowStatus():
def __init__(self):
self.data = []
self.status = -1
self.status_human = ''
self.index = -1
self.active = False
def set(self, data):
self.data = data
self.active = True
def analyse(self):
if len(self.data)>0:
self.status = self.data[0]
self.status_hex = hex(self.data[0])[2:]
if len(self.data)>1:
self.index = self.data[1]
self.humanize()
def isActive(self):
return self.active
def getStatus(self):
return self.status
def getStatusByte(self):
return self.status
def getIndex(self):
return self.index
def getHuman(self):
if self.status_human == '':
self.humanize()
return self.status_human
def humanize(self):
# dict([('no Status', -1), ('no Error', 0), ...])
if self.status == -1:
self.status_human = 'no Status'
elif self.status_hex == '0':
self.status_human = 'no Error'
elif self.status_hex == '1':
self.status_human = 'Process claimed'
elif self.status_hex == '2':
self.status_human = 'Command Error'
elif self.status_hex == '3':
self.status_human = 'Process Error'
elif self.status_hex == '4':
self.status_human = 'Parameter Error'
elif self.status_hex == '5':
self.status_human = 'Parameter type Error'
elif self.status_hex == '6':
self.status_human = 'Parameter value Error'
elif self.status_hex == '7':
self.status_human = 'Network not active'
elif self.status_hex == '8':
self.status_human = 'Time-out start character'
elif self.status_hex == '9':
self.status_human = 'Time-out serial line'
elif self.status_hex == 'a':
self.status_human = 'Hardware memory Error'
elif self.status_hex == 'b':
self.status_human = 'Node number Error'
elif self.status_hex == 'c':
self.status_human = 'General communication Error'
elif self.status_hex == 'd':
self.status_human = 'Read only Parameter.'
elif self.status_hex == 'e':
self.status_human = 'Error PC-communication'
elif self.status_hex == 'f':
self.status_human = 'No RS232 connection'
elif self.status_hex == '10':
self.status_human = 'PC out of memory'
elif self.status_hex == '11':
self.status_human = 'Write only Parameter'
elif self.status_hex == '12':
self.status_human = 'System configuration unknown'
elif self.status_hex == '13':
self.status_human = 'No free node address'
elif self.status_hex == '14':
self.status_human = 'Wrong interface type'
elif self.status_hex == '15':
self.status_human = 'Error serial port connection'
elif self.status_hex == '16':
self.status_human = 'Error opening communication'
elif self.status_hex == '17':
self.status_human = 'Communication Error'
elif self.status_hex == '18':
self.status_human = 'Error interface bus master'
elif self.status_hex == '19':
self.status_human = 'Timeout answer'
elif self.status_hex == '1a':
self.status_human = 'No start character'
elif self.status_hex == '1b':
self.status_human = 'Error first digit'
elif self.status_hex == '1c':
self.status_human = 'Buffer overflow in host'
elif self.status_hex == '1d':
self.status_human = 'Buffer overflow'
elif self.status_hex == '1e':
self.status_human = 'No answer found'
elif self.status_hex == '1f':
self.status_human = 'Error closing communication'
elif self.status_hex == '20':
self.status_human = 'Synchronisation Error'
elif self.status_hex == '21':
self.status_human = 'Send Error'
elif self.status_hex == '22':
self.status_human = 'Protocol Error'
elif self.status_hex == '23':
self.status_human = 'Buffer overflow in module'
def stdout(self, indent = '\t'):
print indent, "MKFlowStatus Class Output Begin"
print indent, "Data Array:\t", self.data
print indent, "Status : \t", self.getStatus()
print indent, "Status : \t", self.getHuman()
print indent, "Index Byte:\t", self.getIndex()
print indent, "MKFlowStatus Class Output End"
def stdoutShort(self,indent=''):
print indent, 'INFO\t', self.getStatus(), '\t\t', self.getHuman()
# subclass for MKFlowProcess
class MKFlowParameter():
def __init__(self):
self.dataType = 'undefined'
self.index = -1
self.process = -1
self.number = -1
self.dataLength = 0
self.dataStart = 0
self.data = []
self.human = ''
def set(self, data):
self.data = data
def setLength(self,length=0):
self.length = length
def setProcess(self, process):
self.process = process
def analyse(self):
pass
def analyseData(self):
self.index = self.data[0]
self.number= self.data[0]
def analyseDataType(self, number = -3):
if number == -3:
number = self.number
identifier = format(number, '08b')[1:3]
if identifier == '00':
self.dataType = 'character'
elif identifier == '01':
self.dataType = 'integer'
elif identifier == '10':
self.dataType = 'long'
elif identifier == '11':
self.dataType = 'string'
def substractDataType(self, number = -3):
if number == -3:
number = self.number
if self.dataType == 'string':
number -= int('60',16)
elif self.dataType == 'long':
number -= int('40',16)
elif self.dataType == 'integer':
number -= int('20',16)
elif self.dataType == 'character':
pass
return number
def isChained(self):
if self.index >= 128:
return True
else:
return False
def getData(self):
return self.data[0:self.length]
def getIndex(self):
index = self.index
if self.isChained():
index -= 128
if index >= 32:
index = self.substractDataType(index)
return index
def getProcess(self):
return self.process
def getNumber(self):
return self.number
def getDataType(self):
return self.dataType
def getLength(self):
return self.length
def getHuman(self):
if self.human == '':
self.humanize()
return self.human
def humanize(self):
getIdent = dict([('0:0', 0), ('0:1', 1), ('0:2', 2), ('0:3', 3), ('0:4', 4), ('0:5', 5), ('0:10', 6), ('1:0', 7), ('1:1', 8), ('1:2', 9), ('1:3', 10), ('1:4', 11), ('1:5', 12), ('1:6', 13), ('1:7', 14), ('1:8', 15), ('1:9', 16), ('1:10', 17), ('1:11', 18), ('1:12', 19), ('1:13', 20), ('1:14', 21), ('1:15', 22), ('1:16', 23), ('1:17', 24), ('1:18', 25), ('1:19', 26), ('1:20', 27), ('0:12', 28), ('0:13', 29), ('0:14', 30), ('9:1', 31), ('10:0', 32), ('10:1', 33), ('10:2', 34), ('114:12', 51), ('115:3', 52), ('116:6', 53), ('114:1', 54), ('117:1', 55), ('117:2', 56), ('115:1', 57), ('116:7', 58), ('115:2', 59), ('114:2', 60), ('114:3', 61), ('116:1', 62), ('116:2', 63), ('116:3', 64), ('116:4', 65), ('114:4', 66), ('116:5', 67), ('115:4', 68), ('115:5', 69), ('115:6', 70), ('114:5', 71), ('117:3', 72), ('117:4', 73), ('115:7', 78), ('114:6', 79), ('0:19', 80), ('114:7', 81), ('114:8', 82), ('114:9', 83), ('114:10', 84), ('114:11', 85), ('114:13', 86), ('114:14', 87), ('114:15', 88), ('113:1', 89), ('113:2', 90), ('113:3', 91), ('113:4', 92), ('118:1', 93), ('118:2', 94), ('118:3', 95), ('118:4', 96), ('118:5', 97), ('118:6', 98), ('118:7', 99), ('118:8', 100), ('118:9', 101), ('118:10', 102), ('114:16', 103), ('113:5', 104), ('115:9', 105), ('116:8', 106), ('115:8', 113), ('113:6', 114), ('97:1', 115), ('97:2', 116), ('97:3', 117), ('97:4', 118), ('97:5', 119), ('97:6', 120), ('104:1', 121), ('104:2', 122), ('104:3', 123), ('104:4', 124), ('104:5', 125), ('104:6', 126), ('104:7', 127), ('1:31', 128), ('104:8', 129), ('113:7', 130), ('33:1', 138), ('33:2', 139), ('114:17', 140), ('33:7', 141), ('33:8', 142), ('33:9', 143), ('33:10', 144), ('115:10', 146), ('33:9', 148), ('33:10', 149), ('33:5', 150), ('33:6', 151), ('33:11', 152), ('33:13', 153), ('97:9', 155), ('104:9', 156), ('33:14', 157), ('33:15', 158), ('33:16', 159), ('33:17', 160), ('33:18', 161), ('33:20', 162), ('115:11', 163), ('114:18', 164), ('114:20', 165), ('114:21', 166), ('114:22', 167), ('114:23', 168), ('33:21', 169), ('113:8', 170), ('113:9', 171), ('113:10', 172), ('113:11', 173), ('113:12', 174), ('118:11', 175), ('115:12', 176), ('113:13', 177), ('113:14', 178), ('113:15', 179), ('113:16', 180), ('97:7', 181), ('33:22', 182), ('0:18', 183), ('0:20', 184), ('123:1', 185), ('123:3', 186), ('123:4', 187), ('123:10', 188), ('114:24', 189), ('115:13', 190), ('115:14', 191), ('116:9', 192), ('115:15', 193), ('115:16', 194), ('115:17', 195), ('115:18', 196), ('33:4', 197), ('125:10', 198), ('125:3', 199), ('125:9', 200), ('125:20', 201), ('115:22', 202), ('125:21', 203), ('33:0', 204), ('33:3', 205), ('33:23', 206), ('119:1', 207), ('119:2', 208), ('119:3', 209), ('119:4', 210), ('119:5', 211), ('119:6', 212), ('116:21', 213), ('116:22', 214), ('116:23', 215), ('116:24', 216), ('116:25', 217), ('116:26', 218), ('116:27', 219), ('116:28', 220), ('117:5', 221), ('33:24', 222), ('117:6', 223), ('33:25', 224), ('33:26', 225), ('33:27', 226), ('33:28', 227), ('33:29', 228), ('33:30', 229), ('114:25', 230), ('114:26', 231), ('114:27', 232), ('114:28', 233), ('114:29', 234), ('0:21', 235), ('115:20', 236), ('33:31', 237), ('33:12', 238), ('33:13', 239), ('33:16', 240), ('33:17', 241), ('33:10', 244), ('33:11', 245), ('113:17', 248), ('113:18', 249), ('113:20', 250), ('113:21', 251), ('113:22', 252), ('114:30', 253), ('113:23', 254), ('113:24', 255), ('113:25', 256), ('113:26', 257), ('113:27', 258), ('113:28', 259), ('113:29', 260), ('113:30', 261), ('113:31', 262), ('116:10', 263), ('116:11', 264), ('116:12', 265), ('116:13', 266), ('116:14', 267), ('65:15', 268), ('116:15', 269), ('116:18', 270), ('116:8', 271), ('116:9', 272), ('104:10', 273), ('104:11', 274), ('65:1', 275), ('116:17', 276), ('116:29', 277), ('116:30', 278), ('116:30', 279), ('116:31', 280), ('121:0', 281), ('121:1', 282), ('121:2', 283), ('121:3', 284), ('121:4', 285), ('121:5', 286), ('114:31', 287), ('65:21', 288), ('65:22', 289), ('65:23', 290), ('65:24', 291), ('65:25', 292), ('116:20', 293), ('115:31', 294), ('104:12', 295), ('104:13', 296), ('104:14', 297), ('125:8', 298), ('125:11', 299), ('124:7', 300), ('124:8', 301), ('124:10', 302), ('124:9', 303), ('124:11', 304), ('124:20', 305), ('124:21', 306), ('120:0', 307), ('120:2', 308), ('120:6', 309), ('120:7', 310), ('120:3', 311), ('120:1', 312), ('120:4', 313), ('120:5', 314), ('120:8', 315), ('120:9', 316), ('120:10', 317), ('120:11', 318), ('0:6', 319), ('0:7', 320), ('124:31', 321), ('115:23', 322), ('118:12', 323), ('65:26', 324), ('116:16', 325), ('119:31', 326), ('115:24', 327), ('125:12', 328), ('124:12', 329), ('0:8', 330)])
getWord = dict([(0, 'Identification string'), (1, 'Primary node address'), (2, 'Secondary node address'), (3, 'Next node address'), (4, 'Last node address'), (5, 'Arbitrage'), (6, 'Initreset'), (7, 'Measure'), (8, 'Setpoint'), (9, 'Setpoint slope'), (10, 'Analog input'), (11, 'Control mode'), (12, 'Polynomial constant A'), (13, 'Polynomial constant B'), (14, 'Polynomial constant C'), (15, 'Polynomial constant D'), (16, 'Polynomial constant E'), (17, 'Polynomial constant F'), (18, 'Polynomial constant G'), (19, 'Polynomial constant H'), (20, 'Capacity'), (21, 'Sensor type'), (22, 'Capacity unit index'), (23, 'Fluid number'), (24, 'Fluid name'), (25, 'Claim node'), (26, 'Modify'), (27, 'Alarm info'), (28, 'Channel amount'), (29, 'First channel'), (30, 'Last channel'), (31, '<hostcontrl>'), (32, 'Alarm message unit type'), (33, 'Alarm message number'), (34, 'Relay status'), (51, 'Cycle time'), (52, 'Analog mode'), (53, 'Reference voltage'), (54, 'Valve output'), (55, 'Dynamic display factor'), (56, 'Static display factor'), (57, 'Calibration mode'), (58, 'Valve offset'), (59, 'Monitor mode'), (60, 'Alarm register1'), (61, 'Alarm register2'), (62, '<CalRegZS1>'), (63, '<CalRegFS1>'), (64, '<CalRegZS2>'), (65, '<CalRegFS2>'), (66, 'ADC control register'), (67, 'Bridge potmeter'), (68, '<AlarmEnble>'), (69, 'Test mode'), (70, '<ADC channel select>'), (71, 'Normal step controller response'), (72, 'Setpoint exponential smoothing filter'), (73, 'Sensor exponential smoothing filter'), (78, 'Tuning mode'), (79, 'Valve default'), (80, 'Global modify'), (81, 'Valve span correction factor'), (82, 'Valve curve correction'), (83, '<MemShipNor>'), (84, '<MemShipOpn>'), (85, 'IO status'), (86, '<FuzzStNeNo>'), (87, '<FuzzStPoNo>'), (88, '<FuzzStOpen>'), (89, 'Device type'), (90, 'BHTModel number'), (91, 'Serial number'), (92, 'Customer model'), (93, 'BHT1'), (94, 'BHT2'), (95, 'BHT3'), (96, 'BHT4'), (97, 'BHT5'), (98, 'BHT6'), (99, 'BHT7'), (100, 'BHT8'), (101, 'BHT9'), (102, 'BHT10'), (103, 'Broadcast repeating time'), (104, 'Firmware version'), (105, 'Pressure sensor type'), (106, 'Barometer pressure'), (113, 'Reset'), (114, 'User tag'), (115, 'Alarm limit maximum'), (116, 'Alarm limit minimum'), (117, 'Alarm mode'), (118, 'Alarm output mode'), (119, 'Alarm setpoint mode'), (120, 'Alarm new setpoint'), (121, 'Counter value'), (122, 'Counter unit index'), (123, 'Counter limit'), (124, 'Counter output mode'), (125, 'Counter setpoint mode'), (126, 'Counter new setpoint'), (127, 'Counter unit'), (128, 'Capacity unit'), (129, 'Counter mode'), (130, 'Minimum hardware revision'), (138, 'Slave factor'), (139, 'Reference voltage input'), (140, 'Stable situation controller response'), (141, 'Temperature'), (142, 'Pressure'), (143, 'Time'), (144, 'Calibrated volume'), (146, 'Range select'), (148, 'Frequency'), (149, 'Impulses/m3'), (150, 'Normal volume flow'), (151, 'Volume flow'), (152, 'Delta-p'), (153, '<scalefact>'), (155, 'Reset alarm enable'), (156, 'Reset counter enable'), (157, 'Master node'), (158, 'Master process'), (159, 'Remote instrument node'), (160, 'Remote instrument process'), (161, 'Minimum custom range'), (162, 'Maximum custom range'), (163, 'Relay/TTL output'), (164, 'Open from zero controller response'), (165, 'Controller features'), (166, 'PID-Kp'), (167, 'PID-Ti'), (168, 'PID-Td'), (169, 'Density'), (170, 'Calibration certificate'), (171, 'Calibration date'), (172, 'Service number'), (173, 'Service date'), (174, 'Identification number'), (175, 'BHT11'), (176, 'Power mode'), (177, 'Pressure inlet'), (178, 'Pressure outlet'), (179, 'Orifice'), (180, 'Fluid temperature'), (181, 'Alarm delay'), (182, 'Capacity 0%'), (183, 'Number of channels'), (184, 'Device function'), (185, 'Scan channel'), (186, 'Scan parameter'), (187, 'Scan time'), (188, 'Scan data'), (189, 'Valve open'), (190, 'Number of runs'), (191, 'Minimum process time'), (192, 'Leak rate'), (193, 'Mode info request'), (194, 'Mode info option list'), (195, 'Mode info option description'), (196, 'Calibrations options'), (197, 'Mass flow'), (198, 'Bus address'), (199, 'Interface configuration'), (200, 'Baudrate'), (201, 'Bus diagnostic string'), (202, 'Number of vanes'), (203, 'Fieldbus'), (204, 'fMeasure'), (205, 'fSetpoint'), (206, 'Mass'), (207, 'Manufacturer status register'), (208, 'Manufacturer warning register'), (209, 'Manufacturer error register'), (210, 'Diagnostic history string'), (211, 'Diagnostic mode'), (212, 'Manufacturer status enable'), (213, 'Analog output zero adjust'), (214, 'Analog output span adjust'), (215, 'Analog input zero adjust'), (216, 'Analog input span adjust'), (217, 'Sensor input zero adjust'), (218, 'Sensor input span adjust'), (219, 'Temperature input zero adjust'), (220, 'Temperature input span adjust'), (221, 'Adaptive smoothing factor'), (222, 'Slope setpoint step'), (223, 'Filter length'), (224, 'Absolute accuracy'), (225, 'Lookup table index'), (226, 'Lookup table X'), (227, 'Lookup table Y'), (228, 'Lookup table temperature index'), (229, 'Lookup table temperature'), (230, 'Valve maximum'), (231, 'Valve mode'), (232, 'Valve open correction'), (233, 'Valve zero hold'), (234, 'Valve slope'), (235, 'IFI data'), (236, 'Range used'), (237, 'Fluidset properties'), (238, 'Lookup table unit type index'), (239, 'Lookup table unit type'), (240, 'Lookup table unit index'), (241, 'Lookup table unit'), (244, 'Capacity unit type temperature'), (245, 'Capacity unit pressure'), (248, 'Formula type'), (249, 'Heat capacity'), (250, 'Thermal conductivity'), (251, 'Viscosity'), (252, 'Standard flow'), (253, 'Controller speed'), (254, 'Sensor code'), (255, 'Sensor configuration code'), (256, 'Restriction code'), (257, 'Restriction configurator code'), (258, 'Restriction NxP'), (259, 'Seals information'), (260, 'Valve code'), (261, 'Valve configuration code'), (262, 'Instrument properties'), (263, 'Lookup table frequency index'), (264, 'Lookup table frequency frequency'), (265, 'Lookup table frequency temperature'), (266, 'Lookup table frequency density'), (267, 'Lookup table frequency span adjust'), (268, 'Capacity unit index (ext)'), (269, 'Density actual'), (270, 'Measured restriction'), (271, 'Temperature potmeter'), (272, 'Temperature potmeter gain'), (273, 'Counter controller overrun correction'), (274, 'Counter controller gain'), (275, 'Sub fluid number'), (276, 'Temperature compensation factor'), (277, 'DSP register address'), (278, 'DSP register long'), (279, 'DSP register floating point'), (280, 'DSP register integer'), (281, 'Standard deviation'), (282, 'Measurement status'), (283, 'Measurement stop criteria'), (284, 'Measurement time out'), (285, 'Maximum number of runs'), (286, 'Minimum standard deviation'), (287, 'IO switch status'), (288, 'Sensor bridge settings'), (289, 'Sensor bridge current'), (290, 'Sensor resistance'), (291, 'Sensor bridge voltage'), (292, 'Sensor group name'), (293, 'Sensor calibration temperature'), (294, 'Valve safe state'), (295, 'Counter unit type index'), (296, 'Counter unit type'), (297, 'Counter unit index (ext)'), (298, 'Bus1 selection'), (299, 'Bus1 medium'), (300, 'Bus2 mode'), (301, 'Bus2 selection'), (302, 'Bus2 address'), (303, 'Bus2 baudrate'), (304, 'Bus2 medium'), (305, 'Bus2 diagnostics'), (306, 'Bus2 name'), (307, 'PIO channel selection'), (308, 'PIO parameter'), (309, 'PIO input/output filter'), (310, 'PIO parameter capacity 0%'), (311, 'PIO parameter capacity 100%'), (312, 'PIO configuration selection'), (313, 'PIO analog zero adjust'), (314, 'PIO analog span adjust'), (315, 'PIO hardware capacity max'), (316, 'PIO capacity set selection'), (317, 'PIO hardware capacity 0%'), (318, 'PIO hardware capacity 100%'), (319, 'Hardware platform id'), (320, 'Hardware platform sub id'), (321, 'Temporary baudrate'), (322, 'Setpoint monitor mode'), (323, 'BHT12'), (324, 'Nominal sensor voltage'), (325, 'Sensor voltage compensation factor'), (326, 'PCB serial number'), (327, 'Minimum measure time'), (328, 'Bus1 parity'), (329, 'Bus2 parity'), (330, 'Firmware id')])
myIdent = str(self.getProcess()) + ":" + str(self.getNumber())
if myIdent in getIdent.keys():
if getIdent[myIdent] in getWord.keys():
self.human = getWord[getIdent[myIdent]]
# subclass for MKFlowData
class MKFlowProcess():
class MKFlowParameter(MKFlowParameter):
pass
def __init__(self):
self.number = -1
self.length = 0
self.data = []
self.Parameter = []
def set(self, data):
self.data = data
self.number = data[0]
def analyse(self):
index = 0
position = 1
chained = True
while chained:
index = len(self.Parameter)
self.Parameter.append(self.MKFlowParameter())
self.Parameter[index].set(self.data[position:])
self.Parameter[index].setProcess(self.getProcess())
self.Parameter[index].analyse()
position += self.Parameter[index].getLength()
chained = self.Parameter[index].isChained()
self.length = position
def isChained(self):
if self.number >= 128:
return True
else:
return False
def getNumber(self):
return self.number
def getProcess(self):
if self.isChained():
return (self.number - 128)
else:
return self.number
def getLength(self):
return self.length
def stdout(self, leading = '\t\t'):
print leading, "-- MKFlowProcess Class Output Begin --"
print leading, 'Data:\t', self.data
print leading, 'Data:\t', self.data[0:self.getLength()]
print leading, '1st byte:\t', format(self.data[0], '08b')[0:4] + ' ' + format(self.data[0], '08b')[4:8]
print leading, 'chained:\t', self.isChained()
print leading, 'Process:\t', self.getProcess()
print leading, 'Total Parameters: ', len(self.Parameter)
for parameter in self.Parameter:
parameter.stdout(leading + '\t')
print leading, "-- MKFlowProcess Class Output End --"
class MKFlowData():
class MKFlowProcess(MKFlowProcess):
pass
def __init__(self):
self.data = []
self.active = False
self.process = []
self.length = 0
def set(self,data):
self.active = True
self.data = data
self.analyse()
def analyse(self):
self.analyseProcess()
if not self.check():
raise ValueError('Data was not fully processed. Some information might be missing. Declare whole as invalid')
pass
def check(self):
return (len(self.data) == self.length)
def analyseProcess(self):
index = 0
position = 0
chained = True
while chained:
index = len(self.process)
self.process.append(self.MKFlowProcess())
self.process[index].set(self.data[position:])
self.process[index].analyse()
position += self.process[index].getLength()
chained = self.process[index].isChained()
self.length = position
def stdout(self, leading = '\t'):
print leading, "-- MKFlowData Class Output Begin --"
print leading, "Data Array: \t", self.data
print leading, "Data Array: \t", self.data[0:self.length]
print leading, 'Total Processes:\t', len(self.process)
print leading, 'Data' + (" not " if not self.check() else " ") +'fully processed'
for process in self.process:
process.stdout('\t\t')
print leading, "-- MKFlowData Class Output End --"
class MKFlowRequest(MKFlowData):
def stdoutShort(self, indent=''):
for process in self.process:
for parameter in process.Parameter:
return '\t'.join(str(i) for i in [indent , parameter.getProcess(), parameter.getIndex(), parameter.getNumber(), parameter.getHuman()])
class MKFlowProcess(MKFlowProcess):
class MKFlowParameter(MKFlowParameter):
def analyse(self):
self.analyseData()
self.analyseDataType(self.number)
self.setLength(3)
def analyseData(self):
try:
if len(self.data)<3:
raise ValueError('MKFlowRequest:analyseData data array too short')
self.index = self.data[0]
self.process = self.data[1] # process should be filled by parent
self.number = self.data[2]
except:
raise
def setLength(self,length=0):
self.length = length
if self.dataType == 'string':
self.length += 1
self.DataLength = self.data[3]
def getNumber(self):
# FB Number ( no chaining parameter present)
return self.substractDataType(self.number)
def stdout(self, leading = '\t\t\t'):
print leading, "-- MKFlowRequest Class Output Begin --"
print leading, 'Data: \t', self.getData()
print leading, '1st byte:\t', format(self.data[0], '08b')[0:4] + ' ' + format(self.data[0], '08b')[4:8]
print leading, 'Chained: \t', self.isChained()
print leading, 'Index: \t', self.getIndex()
print leading, '2nd byte:\t', format(self.data[1], '08b')[0:4] + ' ' + format(self.data[1], '08b')[4:8]
print leading, 'Process: \t', self.getProcess()
print leading, '3rd byte:\t', format(self.data[2], '08b')[0:4] + ' ' + format(self.data[2], '08b')[4:8]
print leading, 'DataType:\t', self.getDataType()
print leading, 'FbNr: \t', self.getNumber()
print leading, 'Length: \t', self.getLength()
print leading, 'Human Ind:\t', self.getHuman()
print leading, "-- MKFlowRequest Class Output End --"
class MKFlowSent(MKFlowData):
def stdoutShort(self, indent=''):
for process in self.process:
for parameter in process.Parameter:
return '\t'.join(str(i) for i in [indent, process.getProcess(), parameter.getIndex(), None, parameter.getValue()])
class MKFlowProcess(MKFlowProcess):
class MKFlowParameter(MKFlowParameter):
def analyse(self):
self.analyseData()
self.analyseDataType()
self.analyseValue()
def analyseValue(self):
self.dataStart = 1
self.dataValueFloat = float(0)
if self.dataType == 'string':
self.dataLength = self.data[self.dataStart]
self.dataStart += 1
self.setLength()
self.dataValue = ''.join(chr(i) for i in self.data[self.dataStart:self.length])
elif self.dataType == 'long':
# can also be IEE floating point notation
self.dataLength = 4
self.setLength()
self.dataValue = int(''.join(hex(i)[2:] for i in self.data[self.dataStart:self.length]),16)
elif self.dataType == 'integer':
self.dataLength = 2
self.setLength()
self.dataValue = int(''.join(hex(i)[2:] for i in self.data[self.dataStart:self.length]),16)
elif self.dataType == 'character':
self.dataLength = 1
self.setLength()
self.dataValue = self.data[self.dataStart]
else:
self.dataLength = 0
self.setLength()
self.dataValue = None
raise ValueError('MKFlowSent:analyseValue datatype not found: ' + str(self.dataType))
if (len(self.data)) < self.length:
pass
#raise ValueError('length of data does not match message size.')
elif (len(self.data)) > self.length:
pass
#raise ValueError('length of data too long. Check for chaining!')
def setLength(self):
if self.dataLength == 0:
# undefined length. use whole
self.length = len(self.data)
else:
self.length = self.dataLength + self.dataStart
def getValue(self):
return self.dataValue
def stdout(self, leading = '\t\t\t'):
print leading, "-- MKFlowSent:MKFlowProcess:MKFlowParameter Class Output Begin --"
print leading, 'Data: \t', self.getData()
print leading, '1st byte:\t', format(self.data[0], '08b')[0:4] + ' ' + format(self.data[0], '08b')[4:8]
print leading, 'Chained: \t', self.isChained()
print leading, 'DataType:\t', self.getDataType()
print leading, 'Index: \t', self.getIndex()
print leading, '2nd byte:\t', format(self.data[1], '08b')[0:4] + ' ' + format(self.data[1], '08b')[4:8]
print leading, 'Length: \t', self.getLength()
print leading, 'Value: \t', self.getValue()
print leading, "-- MKFlowSent:MKFlowProcess:MKFlowParameter Class Output End --"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #!/usr/bin/env python
import subprocess
import threading
class MKFlowSocat:
def __init__(self, port1, port2):
self.buffer = []
self.port1 = port1
self.port2 = port2
def start(self):
try:
self.alive = True
self.thread = threading.Thread(target=self.loop)
self.thread.daemon = True # never care about it anymore
self.thread.start()
except:
print 'error stopping thread'
def stop(self):
try:
self.close()
except:
print 'error stopping thread'
else:
self.alive = False
def join(self):
self.thread.join()
def open(self):
exe = 'socat -x %s,raw,echo=0,b38400,crnl %s,raw,echo=0,b38400,crnl' % (self.port1, self.port2)
self.popen = subprocess.Popen(exe.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def close(self):
try:
self.popen.terminate()
self.popen.wait()
except:
print "error closing socat"
raise
def loop(self):
for line in iter(self.popen.stdout.readline, b''):
self.buffer.append(line)
def read(self):
if self.buffer[0][0] == "<" or self.buffer[0][0] == ">":
return self.buffer.pop(0), self.buffer.pop(0)
elif len(self.buffer[0]) == 0:
# message 1 is empty. pop two messages
return self.buffer.pop(0), self.buffer.pop(0)
else:
# message 1 is missing in rpi's socat
return '', self.buffer.pop(0)
def isReady(self):
size = self.bufferSize()
if size > 30:
self.buffer = [self.buffer[-1]]
print "buffer overflow"
return True
return size > 0
def bufferSize(self):
return len(self.buffer)
def isAlive(self):
return self.alive
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | #!/usr/bin/env python
import struct # imports struct API ???
import os # imports file system functions like open()
import threading # multithreading
from time import time
from datetime import datetime
class MKLogFileHandler:
#path_general = os.getcwd() + '/' #use current working dir path
path_general = '/var/local'
path_log = '/log'
path_run = '/run'
path = '/'
file_run = '_runtime.log'
file_log = '_dummyTIME.log'
file_error = '_error.log'
ready = False
separator = '\t'
newline = ''
timestamp_short = False
error_message = ''
def __init__(self,path = '',log_type = 'error', fulldate = False):
self.path = '/' + path
# update date
if fulldate:
self.file_log = '_' + datetime.now().strftime("%Y%m%d-%H%M%S") + '.log'
else:
self.file_log = '_' + datetime.now().strftime("%Y%m%d") + '.log'
if log_type == 'run':
self.logfile = self.path_general + self.path_run + self.path + self.file_run
self.openmode='w' #open run-time-log file, delete content first.
self.timestamp_short = True
elif log_type == 'log':
self.logfile = self.path_general + self.path_log + self.path + self.file_log
self.openmode='w'
self.timestamp_short = True
elif log_type == 'error':
self.logfile = self.path_general + self.path_run + self.path + self.file_error
self.openmode = 'w' #make new log file
self.separator = ':\t'
self.newline = '\n'
def open(self):
try:
self.fso = open(self.logfile, self.openmode)
except:
self.error_message = 'cannot open log file at ' + self.logfile
raise
try:
self.fso.close()
except:
self.error_message = 'cannot close log file at ' + self.logfile
raise
else:
self.ready=True
def timestamp(self):
if self.timestamp_short:
return str(time())
else:
return datetime.now().strftime("%Y-%m-%d %H:%M:%S") #use %f for microseconds
def write(self, strWrite):
with open(self.logfile, 'a') as fso:
fso.write(self.timestamp())
fso.write(self.separator)
fso.write(strWrite)
fso.write(self.newline)
fso.close
def setNewline(self, newline='\n'):
self.newline = newline
def getError(self):
return self.error_message
def getLogFile(self):
return self.logfile
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #!/usr/bin/env python
import MKTerminal,MKSerial,MKParser,MKDatabase,MKFlowMain
from MKLogFile import MKLogFileHandler
import threading # multithreading
import time # sleep
#def transmitter(mySerial arduino, myTerminal terminal):
def main():
def myTransmitter(arduino, terminal):
#while arduino.isAlive() and terminal.isAlive():
parser = MKParser.MKParser()
database = MKDatabase.MKDatabase()
newFile = True
while True:
if terminal.isReady():
arduino.send(terminal.getMessage())
if arduino.isReady():
parser.input(arduino.getMessage())
oneline = parser.oneline()
if parser.getStatus():
terminal.display(oneline)
#terminal.display("")
if not parser.isHeadline() and parser.getStatus():
database.setData(parser.get(2), parser.get(5), parser.get(8), parser.get(11))
database.setSetpoint(parser.get(3), parser.get(6), parser.get(9), parser.get(12))
if database.isRecording():
if newFile:
logfile = MKLogFileHandler('mkmain','log',True)
logfile.open()
database.setLogFile(logfile.getLogFile())
newFile = False
logfile.write(oneline)
else:
newFile = True
if database.isReady():
arduino.send(database.getMessage())
time.sleep(0.1)
threads = []
# Create new threads
arduino = MKSerial.MKSerial('arduino','/dev/ttyACM0',9600)
terminal = MKTerminal.MKTerminal()
ethanol = MKFlowMain.MKFlow('/dev/ttyUSB2', '/dev/ttyUSB3', 0)
argon = MKFlowMain.MKFlow('/dev/ttyUSB0', '/dev/ttyUSB1', 1)
transmitter = threading.Thread(target=myTransmitter, args=(arduino,terminal))
transmitter.setDaemon(True) # never care about it anymore
# Add threads to thread list
threads.append(arduino)
threads.append(terminal)
threads.append(transmitter)#append after arduino and terminal!
threads.append(ethanol)
threads.append(argon)
# Start new Threads
for t in threads:
t.start()
terminal.join()
main()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | #!/usr/bin/env python
from MKLogFile import MKLogFileHandler
import sys
class MKParser:
name = 'parser'
message = ['time','Temperature','temp','spTemp','Pressure','press','spPress','Argon','argon','spArgon','EtOH','etoh','spEtoh']
length = 0
status = False
def __init__(self):
try:
self.error = MKLogFileHandler(self.name,'error')
self.error.open()
except:
print 'Error creating log-file: error.log'
print self.error.getError()
sys.exit(1)
try:
self.log = MKLogFileHandler(self.name,'run')
self.log.open()
self.log.setNewLine('\n')
except:
self.error.write('error opening log file')
def input(self,strInput):
#self.log.write('input received')
if self.parse(strInput):
# process content and save as array
self.status = True
else:
self.error.write('length missmatch in string. Counting ' + str(self.length) + ' items')
self.status = False
return self.status
def parse(self,strInput,intArduinoVersion=None):
if intArduinoVersion is None:
intArduinoVersion = 2
# Default Version (from master thesis) is 2
# strInput is the string that gets extracted
# intArduinoVersion is the version
success = False
strInput = strInput.replace('\n','')
extractMe = strInput.split("\t")
self.length = len(extractMe)
if intArduinoVersion == 2:
if self.length == 23:
self.message[0]=extractMe[0]
self.message[2]=extractMe[2] # temp
self.message[3]=extractMe[5] # sptemp
self.message[5]=extractMe[9] # press
self.message[6]=extractMe[12]# sppress
self.message[8]=extractMe[14]# argon
self.message[9]=extractMe[17]# spargon
self.message[11]=extractMe[19]# etoh
self.message[12]=extractMe[22]# spetoh
success = True
elif intArduinoVersion == 3:
if self.length == 18:
self.message[0]=extractMe[0]
# self.message[1] = Temperature
self.message[2]=extractMe[1] # temp
self.message[3]=extractMe[4] # sptemp
# self.message[4] = Pressure
self.message[5]=extractMe[7] # press
self.message[6]=extractMe[10]# sppress
# self.message[7] = Argon
self.message[8]=extractMe[11]# argon
self.message[9]=extractMe[14]# spargon
# self.message[10] = Argon
self.message[11]=extractMe[15]# etoh
self.message[12]=extractMe[18]# spetoh
success = True
return success
def oneline(self):
strReturn = ''
for i in self.message:
strReturn += i + '\t'
strReturn += '\n'
return strReturn
def isHeadline(self):
if self.get(2) == "temp":
return True
else:
return False
def getStatus(self):
return self.status
def get(self,position):
return self.message[position]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | #!/usr/bin/env python
import serial # imports pyserial API
import struct # imports struct API
import sys # sys.exit()
import threading # multithreading
import time # sleep
from MKLogFile import MKLogFileHandler
LF = serial.to_bytes([10])
CR = serial.to_bytes([13])
CRLF = serial.to_bytes([13, 10])
class MKSerial:
sendBuffer = ''
receiveBuffer = []
receiveBufferReady = False
alive=False
serialName='unnamed'
serialPort=''
serialBaudrate = 9600
newline=CRLF
def __init__(self,serialName='arduino',serialPort='/dev/ttyACM0',serialBaudrate=9600):
self.serialName = serialName
self.serialPort = serialPort
self.serialBaudrate = serialBaudrate
self.openLogfiles()
self.openSerial()
#self.start() # automatically start threading
def openLogfiles(self):
try:
self.error = MKLogFileHandler(self.serialName,'error')
self.error.open()
except:
print 'Error creating file: error.log'
sys.exit(1)
try:
self.run = MKLogFileHandler(self.serialName,'run')
self.run.open()
except:
self.error.write('error opening log files')
def openSerial(self):
self.error.write('opening RS232 for ' + self.serialName + ' on Port ' + self.serialPort + ' with ' + str(self.serialBaudrate) + ' baud')
try:
self.serial = serial.Serial()
self.serial.port = self.serialPort
self.serial.baudrate = self.serialBaudrate
self.serial.timeout = 3 # required so that the readline can exit.
except self.serial.SerialException, e:
self.error.write('error initializing serial class')
sys.exit(1)
try:
self.serial.open()
self.serial.setDTR(True)
self.serial.setRTS(True)
except self.serial.SerialException, e:
self.error.write('Could not open serial port')
sys.exit(1)
while not self.serial.isOpen():
self.error.write('opening port ...')
time.sleep(0.1)
self.error.write('port open.')
def start(self):
self.error.write('starting thread')
try:
self.alive = True
self.thread = threading.Thread(target=self.infiniteloop)
self.thread.daemon = True # never care about it anymore
self.thread.start()
except:
self.error.write('error stopping thread')
def join(self):
self.thread.join()
def stop(self):
self.error.write('stopping thread ...')
try:
self.alive = False
#self.join()
except:
self.error.write('error stopping thread')
else:
self.error.write('thread stopped.')
self.close()
def close(self):
self.error.write('closing serial connection ...')
try:
self.serial.setDTR(False)
self.serial.setRTS(False)
self.serial.close()
except:
self.error.write('error closing serial connection')
else:
self.error.write('serial connection closed.')
def send(self,message):
self.sendBuffer+=message
def receive(self, message):
self.receiveBuffer.append(message)
self.receiveBufferReady = True
def read(self):
val = self.serial.readline(); #read line by line data from the serial file
self.receive(val) #clear from time to time!
self.run.write(val)
def write(self):
if len(self.sendBuffer) > 0 and self.isAlive():
self.error.write('sending message ' + self.sendBuffer)
try:
self.serial.write(self.sendBuffer)
self.serial.write(self.newline)
except:
self.error.write('error sending message')
else:
self.sendBuffer=''
def infiniteloop(self):
self.error.write('starting infinite Loop on ' + self.serial.port)
while (self.serial.isOpen() and self.alive):
try:
self.read()
self.write()
except:
self.error.write('Exception in infinite Loop')
self.stop()
time.sleep(0.1)
self.error.write('stoped infinite loop.')
def isAlive(self):
return self.alive
def isReady(self):
return self.receiveBufferReady
def getMessage(self):
text = self.receiveBuffer.pop(0)
self.receiveBufferReady = len(self.receiveBuffer) > 0
return text
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #!/usr/bin/env python
import sys, os, threading, time
if sys.version_info >= (3, 0):
def character(b):
return b.decode('latin1')
else:
def character(b):
return b
class MKConsole(object):
def __init__(self):
self.fd = sys.stdin.fileno()
def getkey(self):
c = os.read(self.fd, 1)
return c
class MKTerminal(object):
EXITCHARCTER = 'q'
message = ''
alive=False
readyToSend=False
readyToDisplay=False
def __init__(self,echo=False):
self.echo = echo
self.Console = MKConsole()
def start(self):
self.alive = True
self.readerthread = threading.Thread(target=self.read)
self.readerthread.setDaemon(True) # never care about it anymore
self.readerthread.start()
self.writerthread = threading.Thread(target=self.write)
self.writerthread.setDaemon(True) # never care about it anymore
self.writerthread.start()
def join(self):
self.readerthread.join()
def stop(self):
self.alive = False
def send(self,myChar):
if myChar == '\n':
self.readyToSend=True
else:
self.message+=myChar
def read(self):
while self.alive:
try:
b = self.Console.getkey()
c = character(b)
if c == self.EXITCHARCTER:
raise KeyboardInterrupt
self.send(c)
if self.echo == True:
sys.stdout.write(c)
sys.stdout.flush()
time.sleep(0.1)
except KeyboardInterrupt:
self.stop()
def write(self):
while self.alive:
if self.readyToDisplay:
sys.stdout.write(self.printme)
sys.stdout.flush()
self.readyToDisplay=False
time.sleep(0.1)
def isAlive(self):
return self.alive
def isReady(self):
return self.readyToSend
def getMessage(self):
message=self.message
self.message=''
self.readyToSend=False
return message
def display(self,text):
self.readyToDisplay=True
self.printme=text
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | #!/usr/bin/env python
import Tkinter as tk
import os
import MKDatabase
class swntReactorGUI(object):
def __init__(self, master, **kwargs):
# database connection as client
self.db = MKDatabase.MKDatabase(True)
# fullscreen
self.master=master
pad=30
self.geometry_toggle='200x200+0+0'
self.master.geometry("{0}x{1}+0+0".format(master.winfo_screenwidth(), master.winfo_screenheight()-pad))
# keyboard capture events.
self.master.bind('<F4>',self.geometryToggle)
self.master.bind('<Escape>',self.buttonShutdownFocus)
self.master.bind("<Key>", self.key)
self.master.bind("<Return>", self.newline)
self.master.bind("<KP_Enter>", self.newline)
# GUI basics
self.GUI(**kwargs)
# init GUI Variables
self.Buffer = ''
self.bufferDisplay.set("press key")
self.timerDisplay.set("")
self.pressureDisplay.set("")
self.temperatureDisplay.set("")
self.argonDisplay.set("")
self.ethanolDisplay.set("")
self.timer = 0
def key(self, event):
self.LabelBufferDisplay.configure(fg='blue')
self.BufferAdd(event.char)
def newline(self, event):
self.LabelBufferDisplay.configure(fg='red')
self.BufferSend()
def BufferAdd(self,char):
if char == '/':
char = 't'
elif char == '+':
char = 'e'
elif char == '-':
char = 'a'
elif char == '*':
char = 'p'
self.Buffer = self.Buffer + char
self.bufferDisplay.set(self.Buffer)
def BufferSend(self):
if self.db.setMessage(self.Buffer):
self.LabelBufferDisplay.configure(fg='green')
self.BufferClear()
def BufferClear(self):
self.Buffer = ''
def update(self):
# update database
self.db.getAll()
self.timer += 0.1
# update labels
self.timerDisplay.set("{0:.1f}".format(self.timer))
self.pressureDisplay.set("{0:.2f} ({1:.0f})".format(self.db.pressure, self.db.spPressure))
self.temperatureDisplay.set("{0:.0f} ({1:.0f})".format(self.db.temperature, self.db.spTemperature))
self.argonDisplay.set("{0:.1f} ({1:.0f})".format(self.db.argon, self.db.spArgon))
self.ethanolDisplay.set("{0:.1f} ({1:.0f})".format(self.db.ethanol, self.db.spEthanol))
self.ip.set(self.db.getIP())
if self.db.isRecording(): # needs to call database every time
self.filename.set(self.db.getLogFile())
else:
self.filename.set('')
# schedule next call
self.master.after(100, self.update)
def GUI(self, **kwargs):
# buttons
self.frameQuit = tk.Frame(self.master, **kwargs)
self.frameQuit.pack(side=tk.BOTTOM)
self.filename = tk.StringVar()
tk.Label(self.frameQuit, textvariable=self.filename, font=("Helvetica", 14)).pack(side=tk.LEFT)
tk.Button(self.frameQuit, text="record", command=self.buttonRecord).pack(side=tk.LEFT)
tk.Button(self.frameQuit, text="quit", command=self.master.quit).pack(side=tk.LEFT)
self.buttonShutdown = tk.Button(
self.frameQuit,
text="shutdown", fg="red",
command=self.buttonShutdownExec)
self.buttonShutdown.pack(side=tk.LEFT)
self.buttonShutdown.bind('<Return>', self.buttonShutdownExec)
# label timer
self.timerDisplay = tk.StringVar()
tk.Label(self.frameQuit, textvariable=self.timerDisplay, font=("Helvetica", 14)).pack(side=tk.LEFT)
# label ip
self.ip = tk.StringVar()
tk.Label(self.frameQuit, textvariable=self.ip, font=("Helvetica", 14)).pack(side=tk.LEFT)
# input
self.frameInput = tk.Frame(self.master, **kwargs)
self.frameInput.pack(side=tk.TOP)
self.bufferDisplay = tk.StringVar()
tk.Label(self.frameInput, text="Input: ", font=("Helvetica", 64)).pack(side=tk.LEFT)
self.LabelBufferDisplay = tk.Label(self.frameInput, textvariable=self.bufferDisplay, font=("Helvetica", 64))
self.LabelBufferDisplay.pack(side=tk.RIGHT)
# temperature
self.frameTemperature = tk.Frame(self.master, **kwargs)
self.frameTemperature.pack(side=tk.TOP)
self.temperatureDisplay = tk.StringVar()
tk.Label(self.frameTemperature, text="Temperature: ", font=("Helvetica", 64)).pack(padx=5,side=tk.LEFT)
tk.Label(self.frameTemperature, textvariable=self.temperatureDisplay, font=("Helvetica", 64)).pack(side=tk.RIGHT)
# pressure
self.framePressure = tk.Frame(self.master, **kwargs)
self.framePressure.pack(side=tk.TOP)
self.pressureDisplay = tk.StringVar()
tk.Label(self.framePressure, text="Pressure: ", font=("Helvetica", 64)).pack(padx=5,side=tk.LEFT)
tk.Label(self.framePressure, textvariable=self.pressureDisplay, font=("Helvetica", 64)).pack(side=tk.RIGHT)
# Argon
self.frameArgon = tk.Frame(self.master, **kwargs)
self.frameArgon.pack(side=tk.TOP)
self.argonDisplay = tk.StringVar()
tk.Label(self.frameArgon, text="Argon: ", font=("Helvetica", 64)).pack(padx=5,side=tk.LEFT)
tk.Label(self.frameArgon, textvariable=self.argonDisplay, font=("Helvetica", 64)).pack(side=tk.RIGHT)
# Ethanol
self.frameEthanol = tk.Frame(self.master, **kwargs)
self.frameEthanol.pack(side=tk.TOP)
self.ethanolDisplay = tk.StringVar()
tk.Label(self.frameEthanol, text="Ethanol: ", font=("Helvetica", 64)).pack(padx=5,side=tk.LEFT)
tk.Label(self.frameEthanol, textvariable=self.ethanolDisplay, font=("Helvetica", 64)).pack(side=tk.RIGHT)
def buttonShutdownExec(self,event=None):
command1 = "/home/matthias/Documents/programs/python/swnt-reactor/script/shutdown"
command2 = "/home/pi/programs/swnt-reactor/script/shutdown"
if os.path.isfile(command1):
print "shutdown was pressed in test environment"
if os.path.isfile(command2):
self.filename.set("shutdown in progress ...")
os.system(command2)
self.master.quit
def buttonShutdownFocus(self,event=None):
self.buttonShutdown.focus()
def buttonRecord(self, event=None):
if self.db.isRecording():
success = self.db.stopRecording()
else:
success = self.db.startRecording()
if success:
self.timer = 0
def geometryToggle(self,event=None):
# event will be filled with Tkinter.Event when Key is Pressed.
# save old geom.
geometry_old=self.master.winfo_geometry()
# toggle to new
self.master.geometry(self.geometry_toggle)
self.geometry_toggle=geometry_old
root=tk.Tk()
app=swntReactorGUI(root)
root.after(100, app.update)
root.mainloop()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/env python
import time
from MKArduino import MKArduino
arduino = MKArduino()
threads = []
threads.append(arduino)
for t in threads:
print "starting ..."
t.debug(1)
t.start()
try:
while True:
time.sleep(10)
except KeyboardInterrupt:
for t in threads:
print "stoping ..."
t.stop()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/env python
import time
from MKFlowMain import MKFlow
ethanol = MKFlow('/dev/ttyUSB2', '/dev/ttyUSB3', 0)
argon = MKFlow('/dev/ttyUSB0', '/dev/ttyUSB1', 1)
threads = []
threads.append(ethanol)
threads.append(argon)
for t in threads:
print "starting ..."
t.start()
t.debug()
try:
while True:
time.sleep(10)
except KeyboardInterrupt:
for t in threads:
print "stoping ..."
t.stop()
|
The flow for various carbon sources is digitally read with the Bronkhorst flow meters using a custom python program
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #!/usr/bin/env python
import threading
from MKFlowInput import MKFlowInput
from MKFlowCommunication import MKFlowCommunication
from MKDatabase import MKDatabase
class MKFlow():
def __init__(self, port1 = '/dev/ttyUSB2', port2 = '/dev/ttyUSB3', instrument = 0):
self.Input = MKFlowInput()
self.Storage = MKFlowCommunication()
self.Database = MKDatabase()
self.Input.setBridge(port1, port2)
#self.Input.setLogFile('/home/matthias/Documents/programs/python/swnt-reactor/data/log/bridge/testing/log1.log')
self.instrument = instrument
self.debugging = False
def debug(self):
self.debugging = True
def start(self):
try:
self.thread = threading.Thread(target=self.loop)
self.thread.daemon = True
self.thread.start()
except:
self.stop()
raise
def stop(self):
self.Input.stop()
def join(self):
self.thread.join()
def loop(self):
while self.Input.isAlive():
try:
Message = self.Input.getMessage()
SubMessage = Message.getSubType()
except:
break
else:
if not Message.isInvalid:
node = Message.getNode()
sequence = Message.getSequence()
Entity = self.Storage.Node(node).Sequence(sequence)
try:
if Message.isError:
Entity.setError(Message)
elif Message.isStatus:
Entity.setStatus(Message)
elif Message.isSent:
Entity.setAnswer(Message)
elif Message.isSentStatus:
Entity.setWriteRequest(Message)
elif Message.isRequest:
Entity.setReadRequest(Message)
else:
raise
except:
print "--- something happened ---"
try:
Message.stdout()
Submessage.stdout()
Entity.reset()
except:
raise
else:
# store if two messages are present in current Entity
# reset Entity afterwards.
try:
if self.debugging:
bufferSize = self.Input.input.bufferSize()
if bufferSize > 0:
print "Buffer: %i" % bufferSize
Entity.output()
Entity.save(self.Database, self.instrument)
pass
except ValueError:
raise
pass
except:
raise
else:
print "--- invalid ---"
SubMessage.stdoutShort(Message.stdoutShort())
pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | #!/usr/bin/env python
import MySQLdb as mysqlconnector
from MySQLdb.constants import CLIENT
import os
import socket
import decimal
import struct
from time import sleep
import multiprocessing
from MKFlowMessage import FBconvertLong # converter for long numbers to float and percent
#cvd-client->rbBmSDP7fSKp87b5
class MKDatabase(object):
sql = ""
connected = False
ready = False
messageID = -1
hostname = ""
client = False
recording = False
recordingID = -1
fileName = ""
storage_description = 50
storage_values = 30
def __init__(self, isClient = False):
self.client = isClient
self.test()
decimal.getcontext().prec = 2
def open(self):
try:
if not self.checkIP():
print "server unavailable"
raise
dbHost = self.getIP()
dbName = "cvd"
if self.client:
dbUser = "cvd-client"
dbPass = "rbBmSDP7fSKp87b5"
else:
if self.getHostname() == "lab117":
dbUser = "cvd-server"
dbPass = "uhNYLSHRn2f3LhmS"
elif self.getHostname() == "uk-work":
dbUser = "cvd-uk-work"
dbPass = "ARHFpNwB5ZbZQdqh"
else:
dbUser = "cvd-other"
dbPass = "bmF94vVXAB5yf7Mx"
self.db = mysqlconnector.connect(
host = dbHost,
user = dbUser,
passwd = dbPass,
db = dbName,
client_flag = CLIENT.FOUND_ROWS,
connect_timeout = 1
)
except:
print "database open failed."
self.close()
return False
else:
print "connected as user: %s" % dbUser
self.connected = True
return True
def close(self):
try:
self.db.close()
except:
if not self.checkIP():
print "connection lost. Database could not be closed normal"
self.connected = False
else:
self.connected = False
def isOpen(self):
#if not self.connected:
# return False
#try:
# stats = self.db.stat()
# if stats == 'MySQL server has gone away':
# self.close()
#except:
# self.connected = False
return self.connected
def write_without_timeout(self, db, sql, connection):
try:
cursor = db.cursor()
cursor.execute(sql)
affectedRows = cursor.rowcount
cursor.close()
db.commit()
except:
affectedRows = 0
try:
self.db.rollback()
except:
pass
connection.send(affectedRows)
connection.close()
def read_without_timeout(self, db, sql, connection):
affectedRows = 0
try:
cursor = db.cursor()
cursor.execute(sql)
data = cursor.fetchone()
cursor.close()
except:
connection.send([])
else:
connection.send(data)
connection.close()
# from alex martelli on http://stackoverflow.com/questions/1507091/python-mysqldb-query-timeout
def write(self, sql, update = False):
if not self.isOpen():
if not self.open():
raise
conn_parent, conn_child = multiprocessing.Pipe(False)
subproc = multiprocessing.Process(target = self.write_without_timeout,
args = (self.db, sql, conn_child))
subproc.start()
subproc.join(1)
if conn_parent.poll():
affectedRows = conn_parent.recv()
# on update statements rise if no lines were affected
if update and affectedRows == 0:
raise UpdateError('UPDATE statement failed')
else:
return affectedRows
subproc.terminate()
raise TimeoutError("Query %r ran for >%r" % (sql, timeout))
def read(self, sql):
if not self.isOpen():
if not self.open():
raise
conn_parent, conn_child = multiprocessing.Pipe(False)
subproc = multiprocessing.Process(target = self.read_without_timeout,
args = (self.db, sql, conn_child))
subproc.start()
subproc.join(1)
if conn_parent.poll():
data = conn_parent.recv()
try:
if len(data) == 0:
raise
except:
return []
else:
return data
else:
subproc.terminate()
return []
def writeArduino(self, sql):
try:
self.write(sql, True)
except:
try:
print "writeArduino failed: create database and try again."
self.createArduino()
self.resetArduino()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeRecording(self, sql):
try:
self.write(sql, True)
except:
try:
self.createRecording()
self.resetRecording()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeFlowbus(self, sql):
try:
self.write(sql)
except:
try:
self.createFlowbus()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def writeMessage(self, sql):
try:
self.write(sql, True)
except:
try:
self.createMessage()
self.resetMessage()
self.write(sql)
except:
self.close()
return False
else:
return True
else:
return True
def test(self):
print "-- starting self-test --"
self.open()
sql="SELECT VERSION()"
data = self.read(sql)
self.close()
print "MySQL version : %s " % data
print "-- self test complete --"
def getHostname(self):
if self.hostname == "":
self.hostname = socket.gethostname()
return self.hostname
def isServer(self):
if (self.getHostname() == "lab117"):
return True
else:
return False
def getIP(self):
if self.isServer():
ip = 'localhost'
else:
ip = "132.187.77.71"
return ip
def checkIP(self, ip = ""):
if len(ip) == 0:
ip = self.getIP()
if ip == "localhost":
return True
command = "ping -c 1 -W 1 " + ip
print "executing '" + command + "'"
if os.system(command + " > /dev/null") == 0:
return True
else:
print "ip not found. sleeping penalty."
sleep(1)
return False
def createArduino(self):
sql = """CREATE TABLE IF NOT EXISTS `runtime_arduino` (
`temperature` decimal(6,2) NOT NULL DEFAULT '0',
`pressure` decimal(6,2) NOT NULL DEFAULT '0',
`argon` decimal(6,2) NOT NULL DEFAULT '0',
`ethanol` decimal(6,2) NOT NULL DEFAULT '0',
`spTemperature` int(11) NOT NULL DEFAULT '0',
`spPressure` int(11) NOT NULL DEFAULT '1000',
`spEthanol` int(11) NOT NULL DEFAULT '0',
`spArgon` int(11) NOT NULL DEFAULT '0'
) ENGINE=MEMORY DEFAULT Charset=utf8;"""
self.write(sql)
def resetArduino(self):
sql = """INSERT INTO `runtime_arduino`
(`temperature`, `pressure`, `argon`, `ethanol`, `spTemperature`, `spPressure`, `spEthanol`, `spArgon`)
VALUES
(0, 0, 0, 0, 0, 0, 0, 0);"""
self.write(sql)
def createFlowbus(self):
sql = """
CREATE TABLE IF NOT EXISTS `runtime_flowbus`
(
`instrument` smallint(2) NOT NULL DEFAULT '0',
`process` smallint(2) NOT NULL,
`flowBus` smallint(2) NOT NULL,
`dataType` tinyint(1) NOT NULL DEFAULT '0',
`parameter` binary(%i) NOT NULL DEFAULT '0',
`data` binary(%i) NOT NULL DEFAULT '0',
`time` decimal(7,2) NOT NULL DEFAULT '0',
UNIQUE KEY `instrument` (`instrument`,`process`,`flowBus`)
)
ENGINE=MEMORY
DEFAULT CHARSET=utf8;""" % (self.storage_description, self.storage_values)
self.write(sql)
def createRecording(self):
sql = """CREATE TABLE IF NOT EXISTS `runtime_recording` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`recording` tinyint(4) NOT NULL DEFAULT '0',
`id_recording` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
sql = """CREATE TABLE IF NOT EXISTS `recording` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`recording` tinyint(4) NOT NULL DEFAULT '0',
`filename` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
def resetRecording(self):
sql = """INSERT INTO `runtime_recording`
(`recording`)
VALUES
(0)"""
self.write(sql)
def createMessage(self):
sql = """CREATE TABLE IF NOT EXISTS `cvd`.`runtime_message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ready` tinyint(4) NOT NULL DEFAULT '0',
`id_message` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
sql = """CREATE TABLE IF NOT EXISTS `cvd`.`message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`processed` tinyint(4) NOT NULL DEFAULT '0',
`text` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT Charset=utf8 AUTO_INCREMENT=40;"""
self.write(sql)
def resetMessage(self):
sql = """INSERT INTO `cvd`.`runtime_message`
(`ready`)
VALUES
(0)"""
self.write(sql)
sql = """DELETE FROM `cvd`.`message`
WHERE `processed` = 1"""
self.write(sql)
def setData(self, data, setpoint):
try:
self.temperature = decimal.Decimal(data[0])
self.pressure = decimal.Decimal(data[1])
self.argon = decimal.Decimal(data[2])
self.ethanol = decimal.Decimal(data[3])
except:
self.temperature = 0.00
self.pressure = 0.00
self.argon = 0.00
self.ethanol = 0.00
try:
self.spTemperature = int(setpoint[0])
self.spPressure = int(setpoint[1])
self.spArgon = int(setpoint[2])
self.spEthanol = int(setpoint[3])
except:
self.spTemperature = 0
self.spPressure = 1000
self.spEthanol = 0
self.spArgon = 0
sql = """UPDATE `cvd`.`runtime_arduino`
SET `temperature` = %s,
`pressure` = %s,
`ethanol` = %s,
`argon` = %s,
`spTemperature` = %s,
`spPressure` = %s,
`spEthanol` = %s,
`spArgon` = %s;""" % (self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon)
return self.writeArduino(sql)
def setLogFile(self, fileName):
id = self.getRecordingID()
if id < 0:
return False
sql = """UPDATE `cvd`.`recording`
SET `filename` = '%s',
`recording` = 1
WHERE `id` = %i
LIMIT 1;""" % (fileName, id)
if not self.writeRecording(sql):
return False
if self.getLogFile() == fileName:
return True
else:
return False
def isRecording(self):
sql = """SELECT `recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 1:
return False
else:
if data[0]:
return True
else:
return False
def stopRecording(self):
sql = """UPDATE `cvd`.`runtime_recording`
SET `recording` = 0;"""
if not self.writeRecording(sql):
return False
sql = """UPDATE `cvd`.`recording`
SET `recording` = 0
WHERE `recording` = 1;"""
if not self.writeRecording(sql):
return False
self.recordingID = -1
return True
def startRecording(self, filename = ''):
self.stopRecording
sql = """INSERT INTO `cvd`.`recording` (
`id` ,`time` , `recording` , `filename` )
VALUES (
NULL , CURRENT_TIMESTAMP , 1, '%s')""" % filename
if not self.writeRecording(sql):
return False
sql = """SELECT `id`
FROM `cvd`.`recording`
WHERE `recording` = 1
LIMIT 1;"""
data = self.read(sql)
if not len(data) == 1:
return False
sql = """UPDATE `cvd`.`runtime_recording`
SET `id_recording` = %i,
`recording` = 1
LIMIT 1;""" % data
if not self.writeRecording(sql):
return False
return True
def getRecordingID(self):
sql = """SELECT `id_recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
return int(data[0])
else:
return -1
def getLogFile(self):
# get id from memory table
recordingID = self.getRecordingID()
# update filename from disc table if not already saved in class
if not (recordingID == self.recordingID) or len(self.fileName) == 0:
print "querying filename from sql table"
self.close()
sql = """SELECT `filename`
FROM `cvd`.`recording`
WHERE `id` = %i;""" % recordingID
data = self.read(sql)
if len(data) == 1:
self.fileName = data[0]
else:
self.fileName = ''
self.recordingID = recordingID
return self.fileName
def setMessage(self, message):
sql = """INSERT INTO `cvd`.`message`
(`text`) VALUES ('%s');""" % (message)
if self.writeMessage(sql):
return self.updateMessage()
return False
def updateMessage(self):
sql = """SELECT `id` FROM `cvd`.`message`
WHERE `processed` = 0
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
id_message = data[0]
ready = 1
else:
ready = 0
id_message = -1
sql = """UPDATE `cvd`.`runtime_message`
SET `ready` = %i,
`id_message` = %i
LIMIT 1;""" % (ready, id_message)
return self.writeMessage(sql)
def isReady(self):
if self.ready:
return True
sql = """SELECT `ready`, `id_message`
FROM `cvd`.`runtime_message`;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 2:
data = (0,-1)
(self.ready, self.messageID) = data
if self.ready:
return True
else:
return False
def getMessage(self):
self.message = ""
# read from runtime (memory table)
if self.isReady():
# ready flag did also read out messageID.
# get message string from cvd.message
sql = """SELECT `text`
FROM `cvd`.`message`
WHERE `id` = %i
LIMIT 1;""" % self.messageID
data = self.read(sql)
if (len(data) == 1):
self.message = data[0]
# mark message in cvd.message as processed
sql = """UPDATE `cvd`.`message`
SET `processed` = 1
WHERE `id` = %i;""" % self.messageID
self.writeMessage(sql)
self.updateMessage()
# reset readout
self.ready = False
return self.message
def setFlowbus(self, instrument, process, flowBus, dataTypeString, dataInput, timeInput, parameterName):
time = decimal.Decimal(timeInput)
parameterName = parameterName.encode("hex")
if (dataTypeString == "character"):
dataType = 0
data = format(int(dataInput), 'x')
elif(dataTypeString == "integer"):
dataType = 1
data = format(int(dataInput), 'x')
elif(dataTypeString == "long"):
dataType = 2
data = format(int(dataInput), 'x')
elif(dataTypeString == "string"):
dataType = 3
data = dataInput.encode("hex")
else:
raise ValueError("can not identify dataType at setFlowBus()")
sql = """
INSERT INTO `cvd`.`runtime_flowbus`
(`instrument`,`process`,`flowBus`,`dataType`,`data`,`time`, `parameter`)
VALUES
(%i, %i, %i, %i, UNHEX(LPAD('%s',%i,'0')), %.2f, UNHEX(LPAD('%s',%i,'0')))""" % (instrument, process, flowBus, dataType, data, self.storage_values * 2, time, parameterName, self.storage_description * 2)
sql += """
ON DUPLICATE KEY UPDATE
`data` = UNHEX(LPAD('%s',%i,'0')),
`time` = %.2f;""" % (data, self.storage_values * 2, time)
self.writeFlowbus(sql)
def getFlowbus(self, instrument, process, flowBus):
sql = """
SELECT `dataType`,TRIM(LEADING '0' FROM HEX(`data`)),`time`,TRIM(LEADING '0' FROM HEX(`parameter`))
FROM `cvd`.`runtime_flowbus`
WHERE
( `instrument` = %i
AND `process` = %i
AND `flowBus` = %i);
""" % (instrument, process, flowBus)
data = self.read(sql)
if (len(data) == 4):
(dataType, dataOut, timeOut, parameter) = data
else:
return (-1,-1,-1)
parameter = parameter.decode("hex")
time = decimal.Decimal(timeOut)
if (dataType == 0):
data = int(dataOut, 16)
elif(dataType == 1):
data = int(dataOut, 16)
elif(dataType == 2):
data = FBconvertLong(process, flowBus, int(dataOut,16))
elif(dataType == 3):
data = dataOut.decode("hex")
else:
raise ValueError("can not identify dataType at getFlowBus()")
return (parameter, data, time)
def getAll(self):
sql = """SELECT temperature, pressure, ethanol, argon,
spTemperature, spPressure, spEthanol, spArgon
FROM `cvd`.`runtime_arduino`
LIMIT 1"""
data = self.read(sql)
if len(data) == 0:
print "database readout failed for arduino!"
data = (-1,-1,-1,-1, -1,-1,-1,-1)
(self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon) = data
class UpdateError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class TimeoutError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
sql = """UPDATE `cvd`.`runtime_arduino`
SET `temperature` = %s,
`pressure` = %s,
`ethanol` = %s,
`argon` = %s
`spTemperature` = %s,
`spPressure` = %s,
`spEthanol` = %s,
`spArgon` = %s
LIMIT 1;""" % (self.temperature, self.pressure, self.ethanol, self.argon, setpoint[0], setpoint[1], setpoint[2], setpoint[2])
return self.writeArduino(sql)
def setLogFile(self, fileName):
id = self.getRecordingID()
if id < 0:
return False
sql = """UPDATE `cvd`.`recording`
SET `filename` = '%s',
`recording` = 1
WHERE `id` = %i
LIMIT 1;""" % (fileName, id)
if not self.writeRecording(sql):
return False
if self.getLogFile() == fileName:
return True
else:
return False
def isRecording(self):
sql = """SELECT `recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 1:
return False
else:
if data[0]:
return True
else:
return False
def stopRecording(self):
sql = """UPDATE `cvd`.`runtime_recording`
SET `recording` = 0;"""
if not self.writeRecording(sql):
return False
sql = """UPDATE `cvd`.`recording`
SET `recording` = 0
WHERE `recording` = 1;"""
if not self.writeRecording(sql):
return False
self.recordingID = -1
return True
def startRecording(self, filename = ''):
self.stopRecording
sql = """INSERT INTO `cvd`.`recording` (
`id` ,`time` , `recording` , `filename` )
VALUES (
NULL , CURRENT_TIMESTAMP , 1, '%s')""" % filename
if not self.writeRecording(sql):
return False
sql = """SELECT `id`
FROM `cvd`.`recording`
WHERE `recording` = 1
LIMIT 1;"""
data = self.read(sql)
if not len(data) == 1:
return False
sql = """UPDATE `cvd`.`runtime_recording`
SET `id_recording` = %i,
`recording` = 1
LIMIT 1;""" % data
if not self.writeRecording(sql):
return False
return True
def getRecordingID(self):
sql = """SELECT `id_recording`
FROM `cvd`.`runtime_recording`
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
return int(data[0])
else:
return -1
def getLogFile(self):
# get id from memory table
recordingID = self.getRecordingID()
# update filename from disc table if not already saved in class
if not (recordingID == self.recordingID) or len(self.fileName) == 0:
print "querying filename from sql table"
self.close()
sql = """SELECT `filename`
FROM `cvd`.`recording`
WHERE `id` = %i;""" % recordingID
data = self.read(sql)
if len(data) == 1:
self.fileName = data[0]
else:
self.fileName = ''
self.recordingID = recordingID
return self.fileName
def setMessage(self, message):
sql = """INSERT INTO `cvd`.`message`
(`text`) VALUES ('%s');""" % (message)
if self.writeMessage(sql):
return self.updateMessage()
return False
def updateMessage(self):
sql = """SELECT `id` FROM `cvd`.`message`
WHERE `processed` = 0
LIMIT 1;"""
data = self.read(sql)
if (len(data) == 1):
id_message = data[0]
ready = 1
else:
ready = 0
id_message = -1
sql = """UPDATE `cvd`.`runtime_message`
SET `ready` = %i,
`id_message` = %i
LIMIT 1;""" % (ready, id_message)
return self.writeMessage(sql)
def isReady(self):
if self.ready:
return True
sql = """SELECT `ready`, `id_message`
FROM `cvd`.`runtime_message`;"""
try:
data = self.read(sql)
except:
return False
if not len(data) == 2:
data = (0,-1)
(self.ready, self.messageID) = data
if self.ready:
return True
else:
return False
def getMessage(self):
self.message = ""
# read from runtime (memory table)
if self.isReady():
# ready flag did also read out messageID.
# get message string from cvd.message
sql = """SELECT `text`
FROM `cvd`.`message`
WHERE `id` = %i
LIMIT 1;""" % self.messageID
data = self.read(sql)
if (len(data) == 1):
self.message = data[0]
# mark message in cvd.message as processed
sql = """UPDATE `cvd`.`message`
SET `processed` = 1
WHERE `id` = %i;""" % self.messageID
self.writeMessage(sql)
self.updateMessage()
# reset readout
self.ready = False
return self.message
def setFlowbus(self, instrument, process, flowBus, dataTypeString, dataInput, timeInput, parameterName):
time = decimal.Decimal(timeInput)
parameterName = parameterName.encode("hex")
if (dataTypeString == "character"):
dataType = 0
data = format(int(dataInput), 'x')
elif(dataTypeString == "integer"):
dataType = 1
data = format(int(dataInput), 'x')
elif(dataTypeString == "long"):
dataType = 2
data = format(int(dataInput), 'x')
elif(dataTypeString == "string"):
dataType = 3
data = dataInput.encode("hex")
else:
raise ValueError("can not identify dataType at setFlowBus()")
sql = """
INSERT INTO `cvd`.`runtime_flowbus`
(`instrument`,`process`,`flowBus`,`dataType`,`data`,`time`, `parameter`)
VALUES
(%i, %i, %i, %i, UNHEX(LPAD('%s',%i,'0')), %.2f, UNHEX(LPAD('%s',%i,'0')))""" % (instrument, process, flowBus, dataType, data, self.storage_values * 2, time, parameterName, self.storage_description * 2)
sql += """
ON DUPLICATE KEY UPDATE
`data` = UNHEX(LPAD('%s',%i,'0')),
`time` = %.2f;""" % (data, self.storage_values * 2, time)
self.writeFlowbus(sql)
def getFlowbus(self, instrument, process, flowBus):
sql = """
SELECT `dataType`,TRIM(LEADING '0' FROM HEX(`data`)),`time`,TRIM(LEADING '0' FROM HEX(`parameter`))
FROM `cvd`.`runtime_flowbus`
WHERE
( `instrument` = %i
AND `process` = %i
AND `flowBus` = %i);
""" % (instrument, process, flowBus)
data = self.read(sql)
if (len(data) == 4):
(dataType, dataOut, timeOut, parameter) = data
else:
return (-1,-1,-1)
parameter = parameter.decode("hex")
time = decimal.Decimal(timeOut)
if (dataType == 0):
data = int(dataOut, 16)
elif(dataType == 1):
data = int(dataOut, 16)
elif(dataType == 2):
data = FBconvertLong(process, flowBus, int(dataOut,16))
elif(dataType == 3):
data = dataOut.decode("hex")
else:
raise ValueError("can not identify dataType at getFlowBus()")
return (parameter, data, time)
def getAll(self):
sql = """SELECT temperature, pressure, ethanol, argon,
spTemperature, spPressure, spEthanol, spArgon
FROM `cvd`.`runtime_arduino`
LIMIT 1"""
data = self.read(sql)
if len(data) == 0:
print "database readout failed for arduino!"
data = (-1,-1,-1,-1, -1,-1,-1,-1)
(self.temperature, self.pressure, self.ethanol, self.argon, self.spTemperature, self.spPressure, self.spEthanol, self.spArgon) = data
class UpdateError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class TimeoutError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #!/usr/bin/env python
#import struct # imports struct API ???
import os # imports file system functions like open()
import time # sleep
import subprocess # socat
import MKFlowMessage # Message analyis class
from MKFlowSocat import MKFlowSocat
from MKFlowLogFile import MKFlowLogFile
# Main Class
class MKFlowInput():
def __init__(self):
self.reset()
def reset(self):
self.message1 = ''
self.message2 = ''
self.socat = False
self.log = False
self.port1 = ''
self.port2 = ''
def setLogFile(self,filename):
self.input = MKFlowLogFile(filename)
self.start()
def setBridge(self, port1, port2):
self.input = MKFlowSocat(port1, port2)
self.start()
def start(self):
self.input.open()
self.input.start()
def stop(self):
self.input.stop()
def readOut(self):
while not self.input.isReady():
time.sleep(0.1)
self.message1, self.message2 = self.input.read()
def getMessage(self):
try:
Message = self.Message()
self.readOut()
Message.process(self.message2, self.message1)
if Message.isInvalid:
# try next message. maybe they belong together
message_buffer = self.message2
self.readOut()
Message.process(self.message2, self.message1)
if Message.isInvalid:
message_buffer += self.message2
Message.process(message_buffer, self.message1)
except:
self.input.stop()
raise
else:
return Message
def isAlive(self):
return self.input.isAlive()
# shortcut
class Message(MKFlowMessage.MKFlowMessage):
class Invalid(MKFlowMessage.MKFlowInvalid):
pass
class Error(MKFlowMessage.MKFlowError):
pass
class Status(MKFlowMessage.MKFlowStatus):
pass
class Request(MKFlowMessage.MKFlowRequest):
pass
class Sent(MKFlowMessage.MKFlowSent):
pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #!/usr/bin/env python
import subprocess
import threading
class MKFlowSocat:
def __init__(self, port1, port2):
self.buffer = []
self.port1 = port1
self.port2 = port2
def start(self):
try:
self.alive = True
self.thread = threading.Thread(target=self.loop)
self.thread.daemon = True # never care about it anymore
self.thread.start()
except:
print 'error stopping thread'
def stop(self):
try:
self.close()
except:
print 'error stopping thread'
else:
self.alive = False
def join(self):
self.thread.join()
def open(self):
exe = 'socat -x %s,raw,echo=0,b38400,crnl %s,raw,echo=0,b38400,crnl' % (self.port1, self.port2)
self.popen = subprocess.Popen(exe.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def close(self):
try:
self.popen.terminate()
self.popen.wait()
except:
print "error closing socat"
raise
def loop(self):
for line in iter(self.popen.stdout.readline, b''):
self.buffer.append(line)
def read(self):
if self.buffer[0][0] == "<" or self.buffer[0][0] == ">":
return self.buffer.pop(0), self.buffer.pop(0)
elif len(self.buffer[0]) == 0:
# message 1 is empty. pop two messages
return self.buffer.pop(0), self.buffer.pop(0)
else:
# message 1 is missing in rpi's socat
return '', self.buffer.pop(0)
def isReady(self):
size = self.bufferSize()
if size > 30:
self.buffer = [self.buffer[-1]]
print "buffer overflow"
return True
return size > 0
def bufferSize(self):
return len(self.buffer)
def isAlive(self):
return self.alive
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | #!/usr/bin/env python
import MKDatabase
from MKFlowMessage import FBconvertLong
# Main Class
class MKFlowCommunication():
def __init__(self):
self.nullNode = MKFlowNode(-1)
self.node_numbers = []
self.nodes = []
def addNode(self, number):
if not self.isNode(number):
self.node_numbers += [number]
node = MKFlowNode(number)
self.nodes += [node]
def isNode(self, number):
return (number in self.node_numbers)
def getNode(self, number):
if self.isNode(number):
id = self.node_numbers.index(number)
node = self.nodes[id]
return node
else:
return self.nullNode
def Node(self, number):
if not self.isNode(number):
self.addNode(number)
return self.getNode(number)
class MKFlowNode():
def __init__(self, node):
self.node = node
self.nullSequence = MKFlowSequence(-1)
self.sequence_numbers = []
self.sequences = []
def getNumber(self):
return self.node
def addSequence(self, number):
if not self.isSequence(number):
self.sequence_numbers += [number]
sequence = MKFlowSequence(number)
self.sequences += [sequence]
def isSequence(self, number):
return (number in self.sequence_numbers)
def getSequence(self, number):
if self.isSequence(number):
id = self.sequence_numbers.index(number)
sequence = self.sequences[id]
return sequence
else:
return self.nullSequence
def Sequence(self, number):
if not self.isSequence(number):
self.addSequence(number)
return self.getSequence(number)
class MKFlowSequence():
def __init__(self, sequence):
self.sequence = sequence
self.nullChild = MKFlowModbus(-1)
self.reset()
def reset(self):
self.parameter_ids = []
self.parameters = []
self.hasAnswer = False
self.hasRequest = False
self.RequestHasValue = False
self.isAnalysed = False
self.isStatus = False
self.isError = False
self.isValid = False
def setReadRequest(self, Message):
self.Request = Message.getSubType()
self.hasRequest = True
self.hasAnswer = False
self.RequestHasValue = False
self.timeRequest = Message.getSeconds()
def setWriteRequest(self, Message):
self.setReadRequest(Message)
self.RequestHasValue = True
def setStatus(self, Message):
self.setAnswer(Message)
self.isStatus = True
def setError(self, Message):
self.setAnswer(Message)
self.isError = True
def setAnswer(self, Message):
self.Answer = Message.getSubType()
self.timeAnswer = Message.getSeconds()
self.hasAnswer = True
self.isStatus = False
self.isError = False
def check(self):
if self.hasAnswer and self.hasRequest:
if abs(self.timeAnswer - self.timeRequest) > 10:
return False
else:
return True
else:
return False
def addParameter(self, index):
if not self.isParameter(index):
self.parameter_ids += [index]
Parameter = MKFlowModbus(index)
self.parameters += [Parameter]
def isParameter(self, index):
return index in self.parameter_ids
def getParameter(self, index):
if self.isParameter(index):
id = self.parameter_ids.index(index)
Parameter = self.parameters[id]
return Parameter
else:
return self.nullChild
def Parameter(self, index):
if not self.isParameter(index):
self.addParameter(index)
return self.getParameter(index)
def analyse(self):
if self.check():
# Process Request
for process in self.Request.process:
for parameter in process.Parameter:
self.Parameter(parameter.getIndex()).setNumber(parameter.getNumber())
self.Parameter(parameter.getIndex()).setProcess(parameter.getProcess())
self.Parameter(parameter.getIndex()).setName(parameter.getHuman())
self.Parameter(parameter.getIndex()).setLength(parameter.getLength())
if self.RequestHasValue:
self.Parameter(parameter.getIndex()).setValue(parameter.getValue())
self.Parameter(parameter.getIndex()).setDataType(parameter.getDataType())
# Process Answer
if not self.RequestHasValue and not self.isStatus and not self.isError:
for process in self.Answer.process:
for parameter in process.Parameter:
self.Parameter(parameter.getIndex()).setValue(parameter.getValue())
self.Parameter(parameter.getIndex()).setDataType(parameter.getDataType())
# Answer with Status or Error and set valid
self.valid = True
self.analyseStatus()
self.analyseError()
self.isAnalysed = True
def analyseStatus(self):
if self.isStatus:
if self.Answer.getStatus() == 0:
# no error
self.valid = True
elif self.Answer.getStatus() > 3 and self.Answer.getStatus() < 8:
# Parameter Error
where = self.Answer.getIndex()
count = 4
for index in self.parameter_ids:
Parameter = self.getParameter(index)
if not self.RequestHasValue:
Parameter.setInvalid()
if where == count:
self.error = "Status: %s\t Parameter: %s" % (self.Answer.getHuman(), Parameter.getName())
Parameter.setError(self.Answer.getHuman())
count += int(Parameter.getLength())
else:
self.error = self.Answer.getHuman()
self.valid = False
def analyseError(self):
if self.isError:
self.error = self.Answer.getText()
self.valid = False
if not self.valid:
for index in self.parameter_ids:
Parameter = self.getParameter(index)
Parameter.setError(self.error)
def output(self):
if self.check():
if not self.isAnalysed:
self.analyse()
for index in self.parameter_ids:
Parameter = self.getParameter(index)
try:
Parameter.stdout()
except:
self.stdout()
raise ValueError("error in MKFlowCommunication ModbusClass stdout")
def save(self, Database, instrument = 0):
if self.check():
reset = True
if not self.isAnalysed:
self.analyse()
for index in self.parameter_ids:
Parameter = self.getParameter(index)
try:
if not Parameter.isInvalid():
valid = True
proc = Parameter.getProcess()
fbnr = Parameter.getNumber()
name = Parameter.getName()
value = Parameter.getValue()
dataType = Parameter.getDataType()
time = self.timeAnswer
parameter = Parameter.getName()
reset = Database.setFlowbus(instrument, proc, fbnr, dataType, value, time, parameter)
except:
self.stdout()
print "error storing parameter."
reset = False
if reset:
self.reset()
else:
print "Sequence not cleared."
def stdout(self):
print "--- sequence: %i ---" % self.sequence
print "---- parameters: %s ----" % self.parameter_ids
if self.hasRequest:
print "---- request ----"
self.Request.stdout()
if self.hasAnswer:
print "---- answer ----"
self.Answer.stdout()
class MKFlowModbus():
def __init__(self, index):
self.index = index
self.invalid = False
self.error = ''
self.value = None
self.human = ''
self.dataType = 'invalid' # readybility. store as string
self.length = 0
def setProcess(self, process):
self.process = process
def getProcess(self):
return self.process
def setNumber(self, number):
self.number = number
def getNumber(self):
return self.number
def setValue(self, value):
self.value = value
def getValue(self):
return self.value
def setDataType(self, dataType):
self.dataType = dataType
def getDataType(self):
return self.dataType
def setName(self, string):
self.human = string
def getName(self):
return self.human
def setInvalid(self):
self.invalid = True
def setLength(self, length):
self.length = length
def getLength(self):
return self.length
def setError(self, error):
self.error = error
self.setInvalid()
def isInvalid(self):
if self.invalid:
return True
else:
return False
def stdout(self):
returnarray = [self.isInvalid(), self.getProcess(), self.getNumber(), self.getName()]
if not self.invalid:
returnarray += [FBconvertLong(self.getProcess(), self.getNumber(), self.getValue())]
else:
returnarray += [self.error]
print '\t'.join(str(i) for i in returnarray)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | class MKFlowLogFile():
def __init__(self, logfile):
self.reset()
self.logfile = logfile
def reset(self):
self.logfile = ''
self.openmode = 'r'
self.fsoOpen = False
def open(self):
if not self.fsoOpen:
try:
self.fso = open(self.logfile, self.openmode)
except:
self.close()
raise ValueError('cannot open log file at ' + self.logfile)
else:
self.fsoOpen = True
def close(self):
if self.fsoOpen:
try:
self.fso.close()
except:
raise ValueError('cannot close log file at ' + self.logfile)
else:
self.fsoOpen = False
def read(self):
try:
self.open()
message1 = self.fso.readline()
message2 = self.fso.readline()
if (len(message2) == 0):
raise EOF("end of file reached")
except EOF:
self.close()
raise EOF
except:
message1 = ''
message2 = ''
return message1, message2
def start(self):
self.alive = True
def stop(self):
try:
self.close()
self.reset()
except:
print 'error closing logfile'
else:
self.alive = False
def isReady(self):
# ready while alive for log file
return self.isAlive()
def isAlive(self):
return self.alive
class EOF(Exception):
pass
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 | #!/usr/bin/env python
from datetime import datetime # datetime supports milliseconds. time doesn't
import sys # used to get line number of error print sys.exc_traceback.tb_lineno
import struct # used to convert bin-->float
def FBconvertLong(process, fbnr, value):
if process == 33:
if fbnr == 0 or fbnr == 3:
return toFloat(value)
elif process == 114:
if fbnr == 1:
return float(value) / 16777215.0 * 100.0
return value
def toFloat(integer):
# convert integer to IEE float
return struct.unpack(">f", struct.pack(">I", integer))[0]
def fromFloat(floatingpoint):
# convert IEE float to integer
return struct.unpack('<I', struct.pack('<f', float(floatingpoint)))[0]
class MKFlowMessage():
def __init__(self):
self.clear()
# input binary message and socat headline
def process(self, message, socat = ''):
self.message1 = socat
self.message2 = message
self.resetSubType()
self.analyse()
def resetSubType(self):
# message type identifier
self.commandByte= -3
self.isInvalid = False # -2
self.isError = False # -1
self.isStatus = False # 0
self.isSent = False # 2
self.isSentStatus = False # 1
self.isRequest = False # 4
# clear message objects
self.Invalid = MKFlowInvalid()
self.Error = MKFlowError()
self.Status = MKFlowStatus()
self.Sent = MKFlowSent()
#self.SentStatus = MKFlowSentStatus()
self.Request = MKFlowRequest()
def getSubType(self):
if self.isInvalid:
return self.Invalid
if self.isError:
return self.Error
if self.isStatus:
return self.Status
if self.isSent or self.isSentStatus:
return self.Sent
if self.isRequest:
return self.Request
def clear(self):
self.data = []
self.node = -1
self.sequence = -1
self.length = -1
self.dataLength = -1
self.commandByte= -1
self.commandByteHuman = ''
self.commandByteHumanShort = ''
self.direction = ''
self.time = datetime
self.time_human = "%Y/%m/%d;%H:%M:%S.%f"
self.time_second = 0.00
def getNode(self):
return self.node
def getSequence(self):
return self.sequence
def getLength(self):
return self.length
def setLength(self, length):
self.length = length
def getDirection(self):
return self.direction
def getTime(self):
return self.time_human
def getSeconds(self):
return self.time_second
def getCommandByte(self):
return self.commandByte
def getCommandByteShort(self):
return self.commandByteHumanShort
def trim(self):
self.message1 = self.message1.replace('\n','')
self.message2 = self.message2.replace('\n','')
while self.message2[0:1] == " ":
self.message2 = self.message2[1:]
if len(self.message2) == 0:
break
def split(self):
self.message1 = self.message1.split(" ")
self.message2 = self.message2.split(" ")
def analyseDirection(self):
if self.message1[0] == '>':
self.direction = 'right'
elif self.message1[0] == '<':
self.direction = 'left'
else:
self.direction = 'none'
def analyseTime(self):
if len(self.message1) > 1:
self.time = datetime.strptime(self.message1[1] + ';' + self.message1[2], "%Y/%m/%d;%H:%M:%S.%f")
else:
self.time = datetime.now()
self.time_human = self.time.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
self.time_second = self.time.hour*60*60 + self.time.minute * 60 + self.time.second + self.time.microsecond/1e6
def parseMessage(self):
try:
self.trim()
self.split()
except:
self.Invalid.add('MKFlowMessage:parseMessage:\tError while parsing')
raise
def parseData(self):
#replace two DLE (escaped) sequences (10 10) by one databyte (10)
try:
start = 0
foundOne = False
while len(self.data) -1 > start:
found = self.data[start:].index(16)
if self.data[(found+start+1)] == 16:
self.data.pop(found+start)
start = start + found
foundOne = True
else:
start +=1
except ValueError:
# 10 not found. Ignore
pass
except:
# other errors --> report
self.Invalid.add('parseData Error at found: %i start: %i len: %i' % (found, start, len(self.data)))
raise
def checkMessage2(self):
# dataLength is length-Byte
if not (self.dataLength==len(self.data)-3) and not (self.dataLength == 0):
self.Invalid.add('MKFlowMessage:parseMessage2:\tError in socat output: length-Byte in message does not match socat length')
if (len(self.message2)<6):
self.Invalid.add('MKFlowMessage:parseMessage2:\tMessage shorter than 6 bytes: DLE STX SEQUENCE NODE ... DLE ETX')
# DLE STX SEQUENCE NODE LEN DATA DLE ETX
if not ((self.message2[0] == "10") and (self.message2[1] == "02")):
self.Invalid.add('MKFlowMessage:parseMessage2:\tno valid message beginning:\tDLE (0x10) STX (0x02) missing')
if not ((self.message2[-2] == "10") and (self.message2[-1] == "03")):
self.Invalid.add('MKFlowMessage:parseMessage2:\tno valid message ending:\tDLE (0x10) ETX (0x03) missing')
if self.Invalid.isActive():
raise ValueError('MKFlowMessage:parseMessage2:\tError while processing Message2')
def analyse(self):
try:
self.parseMessage()
self.analyseMessage()
self.analyseMessageType()
self.analyseCommandByte()
if self.Invalid.isActive():
raise ValueError('MKFlowMessage:analyse:\tMessage invalid')
except Exception as e:
self.Invalid.add('MKFlowMessage:analyse:\t'+str(e))
self.Invalid.add('MKFlowMessage:analyse:\tLine number:\t' + str(sys.exc_traceback.tb_lineno))
self.Invalid.add('MKFlowMessage:analyse:\tcommandByte:\t' + str(self.commandByte))
self.commandByte = -2
self.isInvalid = True
#raise
def analyseMessage(self):
# DLE STX SEQUENCE NODE LEN DATA DLE ETX
try:
self.analyseMessage1()
self.analyseMessage2()
except:
self.Invalid.add('MKFlowMessage:analyseMessage:\tError while extracting data.')
raise
def analyseMessage1(self):
try:
self.analyseDirection()
self.analyseTime()
self.setLength(len(self.message2))
except:
self.Invalid.add('MKFlowMessage:analyseMessage1:\tError while processing message1')
raise
def analyseMessage2(self):
# DLE STX SEQUENCE NODE LEN DATA DLE ETX
try:
self.data = [int(i,16) for i in self.message2[2:-2]]
self.parseData()
self.sequence = self.data[0]
self.node = self.data[1]
self.dataLength = self.data[2]
self.checkMessage2()
except:
self.Invalid.add('MKFlowMessage:analyseMessage2:\tError while extracting data.')
if len(self.data)<3:
self.Invalid.add('MKFlowMessage:analyseMessage2:\tlen(data)='+str(len(self.data)))
raise
def analyseMessageType(self):
# check if the message contains information
try:
# length 0 means.Error.Status in message. next byte after 00 contains.Error code.
if self.data[2] == 0:
self.commandByte = -1
else:
self.commandByte = self.data[3]
except:
self.Invalid.add('MKFlowMessage:analyseMessageType Error while retrieving Message')
raise
def analyseCommandByte(self):
try:
self.translateCommandByte()
if self.commandByte == -2:
self.isInvalid = True
elif self.commandByte == -1:
self.isError = True
self.Error.set(self.data[3:])
self.Error.setSequence(self.sequence)
self.Error.setNode(self.node)
self.Error.analyse()
elif self.commandByte == 0:
self.Status.set(self.data[4:])
self.Status.analyse()
self.isStatus = True
elif self.commandByte == 4:
self.Request.set(self.data[4:])
self.isRequest = True
elif (self.commandByte == 2):
self.Sent.set(self.data[4:])
self.isSent = True
elif (self.commandByte == 1):
self.Sent.set(self.data[4:])
self.isSentStatus = True
else:
myError = 'MKFlowMessage:analyseCommandByte commandByte ' + str(self.commandbyte) + ' not handled'
self.Invalid.add(myError)
self.Invalid.add(self.commandByteHuman)
raise ValueError(myError)
except:
raise
def translateCommandByte(self):
try:
if self.commandByte == -2:
self.commandByteHuman = "Invalid Message: Error in Program"
elif self.commandByte == -1:
self.commandByteHuman = "Valid Message: Error Message from Device"
elif self.commandByte == 0:
self.commandByteHuman = "Status message"
elif self.commandByte == 1:
self.commandByteHuman = "Send Parameter with destination address, will be answered with type 00 command"
elif self.commandByte == 2:
self.commandByteHuman = "Send Parameter with destination address, no.Status.Requested"
elif self.commandByte == 3:
self.commandByteHuman = "Send Parameter with source address, no.Status.Requested"
elif self.commandByte == 4:
self.commandByteHuman = "Request Parameter, will be answered with type 02 or 00 command"
elif self.commandByte == 6:
self.commandByteHuman = "Stop Process"
elif self.commandByte == 7:
self.commandByteHuman = "Start Process"
elif self.commandByte == 8:
self.commandByteHuman = "Claim Process"
elif self.commandByte == 9:
self.commandByteHuman = "Unclaim Process"
else:
self.commandByteHuman = "unhandled commandByte: " + str(self.commandByte)
raise ValueError(self.commandByteHuman)
if self.commandByte == 4:
self.commandByteHumanShort = 'REQ'
elif (self.commandByte >= 1) and (self.commandByte <= 3):
self.commandByteHumanShort = 'ST' + str(self.commandByte)
if self.commandByte == -2:
self.commandByteHumanShort = 'INV'
if self.commandByte == -1:
self.commandByteHumanShort = 'ERR'
if self.commandByte == 0:
self.commandByteHumanShort = 'INF'
except:
raise
def stdout(self):
print '-- message Class Output begin --'
print self.message1
print self.message2
print 'direction: \t' , self.getDirection()
print 'length: \t' , self.getLength()
print 'time: \t' , self.getTime()
print 'seconds: \t' , self.getSeconds()
print 'sequence: \t' , self.getSequence()
print 'node: \t' , self.getNode()
print 'command: \t' , self.getCommandByte()
print '-- message end --'
def stdoutShort(self, indent=''):
return '\t'.join(str(i) for i in [indent, self.getNode(), self.getSequence(), self.getCommandByteShort()])
# Message Type Classes
class MKFlowInvalid():
def __init__(self):
self.value = ''
self.active = False
def add(self, newValue):
self.active = True
self.value += str(newValue) + '\n'
def get(self):
if self.active:
return self.value
else:
return
def isActive(self):
return self.active
def stdout(self, leading = '\t'):
print leading, "-- MKFlowRequest Class Output Begin --"
print leading, "Value:\t", self.value
print leading, "-- MKFlowRequest Class Output End --"
def stdoutShort(self, indent=''):
return '\t'.join(str(i) for i in [indent, self.isActive()])
class MKFlowError():
def __init__(self):
self.value = 0
self.node = -1
self.sequence = -1
self.text = ''
self.active = False
def set(self, data):
self.active = True
self.data = data
self.value = data[0]
def setNode(self, node):
self.node = node
def setSequence(self,sequence):
self.sequence = sequence
def analyse(self):
if not len(self.data) == 1:
raise ValueError('Error Class has received too many input bytes')
self.translate()
def getText(self):
return self.text
def getHuman(self):
return self.getText()
def getValue(self):
return self.value
def getData(self):
return self.data
def translate(self):
if self.active:
self.text = 'device returned error code ' + str(self.value) + ': '
if (self.value==3):
self.text += 'propar protocol error'
elif (self.value==4):
self.text += 'propar protocol error (or CRC error)'
elif (self.value==5):
if self.node >= 0:
self.text += 'destination node address ' + str(self.node) + ' rejected'
else:
self.text += 'destination node address rejected'
if self.sequence >= 0:
self.text += ' for sequence ' + str(self.sequence)
elif (self.value==9):
self.text += 'response message timeout'
def stdout(self, indent = '\t'):
print indent, '-- Error Class Output Begin--'
print indent, 'Error Data:\t', self.getData()
print indent, 'Error Number:\t', self.getValue()
print indent, 'Error Message:\t', self.getText()
print indent, '-- Error Class Output Begin--'
def stdoutShort(self, indent=''):
return '\t'.join(str(i) for i in [indent, self.getValue(),None,None,self.getHuman()])
class MKFlowStatus():
def __init__(self):
self.data = []
self.status = -1
self.status_human = ''
self.index = -1
self.active = False
def set(self, data):
self.data = data
self.active = True
def analyse(self):
if len(self.data)>0:
self.status = self.data[0]
self.status_hex = hex(self.data[0])[2:]
if len(self.data)>1:
self.index = self.data[1]
self.humanize()
def isActive(self):
return self.active
def getStatus(self):
return self.status
def getStatusByte(self):
return self.status
def getIndex(self):
return self.index
def getHuman(self):
if self.status_human == '':
self.humanize()
return self.status_human
def humanize(self):
# dict([('no Status', -1), ('no Error', 0), ...])
if self.status == -1:
self.status_human = 'no Status'
elif self.status_hex == '0':
self.status_human = 'no Error'
elif self.status_hex == '1':
self.status_human = 'Process claimed'
elif self.status_hex == '2':
self.status_human = 'Command Error'
elif self.status_hex == '3':
self.status_human = 'Process Error'
elif self.status_hex == '4':
self.status_human = 'Parameter Error'
elif self.status_hex == '5':
self.status_human = 'Parameter type Error'
elif self.status_hex == '6':
self.status_human = 'Parameter value Error'
elif self.status_hex == '7':
self.status_human = 'Network not active'
elif self.status_hex == '8':
self.status_human = 'Time-out start character'
elif self.status_hex == '9':
self.status_human = 'Time-out serial line'
elif self.status_hex == 'a':
self.status_human = 'Hardware memory Error'
elif self.status_hex == 'b':
self.status_human = 'Node number Error'
elif self.status_hex == 'c':
self.status_human = 'General communication Error'
elif self.status_hex == 'd':
self.status_human = 'Read only Parameter.'
elif self.status_hex == 'e':
self.status_human = 'Error PC-communication'
elif self.status_hex == 'f':
self.status_human = 'No RS232 connection'
elif self.status_hex == '10':
self.status_human = 'PC out of memory'
elif self.status_hex == '11':
self.status_human = 'Write only Parameter'
elif self.status_hex == '12':
self.status_human = 'System configuration unknown'
elif self.status_hex == '13':
self.status_human = 'No free node address'
elif self.status_hex == '14':
self.status_human = 'Wrong interface type'
elif self.status_hex == '15':
self.status_human = 'Error serial port connection'
elif self.status_hex == '16':
self.status_human = 'Error opening communication'
elif self.status_hex == '17':
self.status_human = 'Communication Error'
elif self.status_hex == '18':
self.status_human = 'Error interface bus master'
elif self.status_hex == '19':
self.status_human = 'Timeout answer'
elif self.status_hex == '1a':
self.status_human = 'No start character'
elif self.status_hex == '1b':
self.status_human = 'Error first digit'
elif self.status_hex == '1c':
self.status_human = 'Buffer overflow in host'
elif self.status_hex == '1d':
self.status_human = 'Buffer overflow'
elif self.status_hex == '1e':
self.status_human = 'No answer found'
elif self.status_hex == '1f':
self.status_human = 'Error closing communication'
elif self.status_hex == '20':
self.status_human = 'Synchronisation Error'
elif self.status_hex == '21':
self.status_human = 'Send Error'
elif self.status_hex == '22':
self.status_human = 'Protocol Error'
elif self.status_hex == '23':
self.status_human = 'Buffer overflow in module'
def stdout(self, indent = '\t'):
print indent, "MKFlowStatus Class Output Begin"
print indent, "Data Array:\t", self.data
print indent, "Status : \t", self.getStatus()
print indent, "Status : \t", self.getHuman()
print indent, "Index Byte:\t", self.getIndex()
print indent, "MKFlowStatus Class Output End"
def stdoutShort(self,indent=''):
print indent, 'INFO\t', self.getStatus(), '\t\t', self.getHuman()
# subclass for MKFlowProcess
class MKFlowParameter():
def __init__(self):
self.dataType = 'undefined'
self.index = -1
self.process = -1
self.number = -1
self.dataLength = 0
self.dataStart = 0
self.data = []
self.human = ''
def set(self, data):
self.data = data
def setLength(self,length=0):
self.length = length
def setProcess(self, process):
self.process = process
def analyse(self):
pass
def analyseData(self):
self.index = self.data[0]
self.number= self.data[0]
def analyseDataType(self, number = -3):
if number == -3:
number = self.number
identifier = format(number, '08b')[1:3]
if identifier == '00':
self.dataType = 'character'
elif identifier == '01':
self.dataType = 'integer'
elif identifier == '10':
self.dataType = 'long'
elif identifier == '11':
self.dataType = 'string'
def substractDataType(self, number = -3):
if number == -3:
number = self.number
if self.dataType == 'string':
number -= int('60',16)
elif self.dataType == 'long':
number -= int('40',16)
elif self.dataType == 'integer':
number -= int('20',16)
elif self.dataType == 'character':
pass
return number
def isChained(self):
if self.index >= 128:
return True
else:
return False
def getData(self):
return self.data[0:self.length]
def getIndex(self):
index = self.index
if self.isChained():
index -= 128
if index >= 32:
index = self.substractDataType(index)
return index
def getProcess(self):
return self.process
def getNumber(self):
return self.number
def getDataType(self):
return self.dataType
def getLength(self):
return self.length
def getHuman(self):
if self.human == '':
self.humanize()
return self.human
def humanize(self):
getIdent = dict([('0:0', 0), ('0:1', 1), ('0:2', 2), ('0:3', 3), ('0:4', 4), ('0:5', 5), ('0:10', 6), ('1:0', 7), ('1:1', 8), ('1:2', 9), ('1:3', 10), ('1:4', 11), ('1:5', 12), ('1:6', 13), ('1:7', 14), ('1:8', 15), ('1:9', 16), ('1:10', 17), ('1:11', 18), ('1:12', 19), ('1:13', 20), ('1:14', 21), ('1:15', 22), ('1:16', 23), ('1:17', 24), ('1:18', 25), ('1:19', 26), ('1:20', 27), ('0:12', 28), ('0:13', 29), ('0:14', 30), ('9:1', 31), ('10:0', 32), ('10:1', 33), ('10:2', 34), ('114:12', 51), ('115:3', 52), ('116:6', 53), ('114:1', 54), ('117:1', 55), ('117:2', 56), ('115:1', 57), ('116:7', 58), ('115:2', 59), ('114:2', 60), ('114:3', 61), ('116:1', 62), ('116:2', 63), ('116:3', 64), ('116:4', 65), ('114:4', 66), ('116:5', 67), ('115:4', 68), ('115:5', 69), ('115:6', 70), ('114:5', 71), ('117:3', 72), ('117:4', 73), ('115:7', 78), ('114:6', 79), ('0:19', 80), ('114:7', 81), ('114:8', 82), ('114:9', 83), ('114:10', 84), ('114:11', 85), ('114:13', 86), ('114:14', 87), ('114:15', 88), ('113:1', 89), ('113:2', 90), ('113:3', 91), ('113:4', 92), ('118:1', 93), ('118:2', 94), ('118:3', 95), ('118:4', 96), ('118:5', 97), ('118:6', 98), ('118:7', 99), ('118:8', 100), ('118:9', 101), ('118:10', 102), ('114:16', 103), ('113:5', 104), ('115:9', 105), ('116:8', 106), ('115:8', 113), ('113:6', 114), ('97:1', 115), ('97:2', 116), ('97:3', 117), ('97:4', 118), ('97:5', 119), ('97:6', 120), ('104:1', 121), ('104:2', 122), ('104:3', 123), ('104:4', 124), ('104:5', 125), ('104:6', 126), ('104:7', 127), ('1:31', 128), ('104:8', 129), ('113:7', 130), ('33:1', 138), ('33:2', 139), ('114:17', 140), ('33:7', 141), ('33:8', 142), ('33:9', 143), ('33:10', 144), ('115:10', 146), ('33:9', 148), ('33:10', 149), ('33:5', 150), ('33:6', 151), ('33:11', 152), ('33:13', 153), ('97:9', 155), ('104:9', 156), ('33:14', 157), ('33:15', 158), ('33:16', 159), ('33:17', 160), ('33:18', 161), ('33:20', 162), ('115:11', 163), ('114:18', 164), ('114:20', 165), ('114:21', 166), ('114:22', 167), ('114:23', 168), ('33:21', 169), ('113:8', 170), ('113:9', 171), ('113:10', 172), ('113:11', 173), ('113:12', 174), ('118:11', 175), ('115:12', 176), ('113:13', 177), ('113:14', 178), ('113:15', 179), ('113:16', 180), ('97:7', 181), ('33:22', 182), ('0:18', 183), ('0:20', 184), ('123:1', 185), ('123:3', 186), ('123:4', 187), ('123:10', 188), ('114:24', 189), ('115:13', 190), ('115:14', 191), ('116:9', 192), ('115:15', 193), ('115:16', 194), ('115:17', 195), ('115:18', 196), ('33:4', 197), ('125:10', 198), ('125:3', 199), ('125:9', 200), ('125:20', 201), ('115:22', 202), ('125:21', 203), ('33:0', 204), ('33:3', 205), ('33:23', 206), ('119:1', 207), ('119:2', 208), ('119:3', 209), ('119:4', 210), ('119:5', 211), ('119:6', 212), ('116:21', 213), ('116:22', 214), ('116:23', 215), ('116:24', 216), ('116:25', 217), ('116:26', 218), ('116:27', 219), ('116:28', 220), ('117:5', 221), ('33:24', 222), ('117:6', 223), ('33:25', 224), ('33:26', 225), ('33:27', 226), ('33:28', 227), ('33:29', 228), ('33:30', 229), ('114:25', 230), ('114:26', 231), ('114:27', 232), ('114:28', 233), ('114:29', 234), ('0:21', 235), ('115:20', 236), ('33:31', 237), ('33:12', 238), ('33:13', 239), ('33:16', 240), ('33:17', 241), ('33:10', 244), ('33:11', 245), ('113:17', 248), ('113:18', 249), ('113:20', 250), ('113:21', 251), ('113:22', 252), ('114:30', 253), ('113:23', 254), ('113:24', 255), ('113:25', 256), ('113:26', 257), ('113:27', 258), ('113:28', 259), ('113:29', 260), ('113:30', 261), ('113:31', 262), ('116:10', 263), ('116:11', 264), ('116:12', 265), ('116:13', 266), ('116:14', 267), ('65:15', 268), ('116:15', 269), ('116:18', 270), ('116:8', 271), ('116:9', 272), ('104:10', 273), ('104:11', 274), ('65:1', 275), ('116:17', 276), ('116:29', 277), ('116:30', 278), ('116:30', 279), ('116:31', 280), ('121:0', 281), ('121:1', 282), ('121:2', 283), ('121:3', 284), ('121:4', 285), ('121:5', 286), ('114:31', 287), ('65:21', 288), ('65:22', 289), ('65:23', 290), ('65:24', 291), ('65:25', 292), ('116:20', 293), ('115:31', 294), ('104:12', 295), ('104:13', 296), ('104:14', 297), ('125:8', 298), ('125:11', 299), ('124:7', 300), ('124:8', 301), ('124:10', 302), ('124:9', 303), ('124:11', 304), ('124:20', 305), ('124:21', 306), ('120:0', 307), ('120:2', 308), ('120:6', 309), ('120:7', 310), ('120:3', 311), ('120:1', 312), ('120:4', 313), ('120:5', 314), ('120:8', 315), ('120:9', 316), ('120:10', 317), ('120:11', 318), ('0:6', 319), ('0:7', 320), ('124:31', 321), ('115:23', 322), ('118:12', 323), ('65:26', 324), ('116:16', 325), ('119:31', 326), ('115:24', 327), ('125:12', 328), ('124:12', 329), ('0:8', 330)])
getWord = dict([(0, 'Identification string'), (1, 'Primary node address'), (2, 'Secondary node address'), (3, 'Next node address'), (4, 'Last node address'), (5, 'Arbitrage'), (6, 'Initreset'), (7, 'Measure'), (8, 'Setpoint'), (9, 'Setpoint slope'), (10, 'Analog input'), (11, 'Control mode'), (12, 'Polynomial constant A'), (13, 'Polynomial constant B'), (14, 'Polynomial constant C'), (15, 'Polynomial constant D'), (16, 'Polynomial constant E'), (17, 'Polynomial constant F'), (18, 'Polynomial constant G'), (19, 'Polynomial constant H'), (20, 'Capacity'), (21, 'Sensor type'), (22, 'Capacity unit index'), (23, 'Fluid number'), (24, 'Fluid name'), (25, 'Claim node'), (26, 'Modify'), (27, 'Alarm info'), (28, 'Channel amount'), (29, 'First channel'), (30, 'Last channel'), (31, '<hostcontrl>'), (32, 'Alarm message unit type'), (33, 'Alarm message number'), (34, 'Relay status'), (51, 'Cycle time'), (52, 'Analog mode'), (53, 'Reference voltage'), (54, 'Valve output'), (55, 'Dynamic display factor'), (56, 'Static display factor'), (57, 'Calibration mode'), (58, 'Valve offset'), (59, 'Monitor mode'), (60, 'Alarm register1'), (61, 'Alarm register2'), (62, '<CalRegZS1>'), (63, '<CalRegFS1>'), (64, '<CalRegZS2>'), (65, '<CalRegFS2>'), (66, 'ADC control register'), (67, 'Bridge potmeter'), (68, '<AlarmEnble>'), (69, 'Test mode'), (70, '<ADC channel select>'), (71, 'Normal step controller response'), (72, 'Setpoint exponential smoothing filter'), (73, 'Sensor exponential smoothing filter'), (78, 'Tuning mode'), (79, 'Valve default'), (80, 'Global modify'), (81, 'Valve span correction factor'), (82, 'Valve curve correction'), (83, '<MemShipNor>'), (84, '<MemShipOpn>'), (85, 'IO status'), (86, '<FuzzStNeNo>'), (87, '<FuzzStPoNo>'), (88, '<FuzzStOpen>'), (89, 'Device type'), (90, 'BHTModel number'), (91, 'Serial number'), (92, 'Customer model'), (93, 'BHT1'), (94, 'BHT2'), (95, 'BHT3'), (96, 'BHT4'), (97, 'BHT5'), (98, 'BHT6'), (99, 'BHT7'), (100, 'BHT8'), (101, 'BHT9'), (102, 'BHT10'), (103, 'Broadcast repeating time'), (104, 'Firmware version'), (105, 'Pressure sensor type'), (106, 'Barometer pressure'), (113, 'Reset'), (114, 'User tag'), (115, 'Alarm limit maximum'), (116, 'Alarm limit minimum'), (117, 'Alarm mode'), (118, 'Alarm output mode'), (119, 'Alarm setpoint mode'), (120, 'Alarm new setpoint'), (121, 'Counter value'), (122, 'Counter unit index'), (123, 'Counter limit'), (124, 'Counter output mode'), (125, 'Counter setpoint mode'), (126, 'Counter new setpoint'), (127, 'Counter unit'), (128, 'Capacity unit'), (129, 'Counter mode'), (130, 'Minimum hardware revision'), (138, 'Slave factor'), (139, 'Reference voltage input'), (140, 'Stable situation controller response'), (141, 'Temperature'), (142, 'Pressure'), (143, 'Time'), (144, 'Calibrated volume'), (146, 'Range select'), (148, 'Frequency'), (149, 'Impulses/m3'), (150, 'Normal volume flow'), (151, 'Volume flow'), (152, 'Delta-p'), (153, '<scalefact>'), (155, 'Reset alarm enable'), (156, 'Reset counter enable'), (157, 'Master node'), (158, 'Master process'), (159, 'Remote instrument node'), (160, 'Remote instrument process'), (161, 'Minimum custom range'), (162, 'Maximum custom range'), (163, 'Relay/TTL output'), (164, 'Open from zero controller response'), (165, 'Controller features'), (166, 'PID-Kp'), (167, 'PID-Ti'), (168, 'PID-Td'), (169, 'Density'), (170, 'Calibration certificate'), (171, 'Calibration date'), (172, 'Service number'), (173, 'Service date'), (174, 'Identification number'), (175, 'BHT11'), (176, 'Power mode'), (177, 'Pressure inlet'), (178, 'Pressure outlet'), (179, 'Orifice'), (180, 'Fluid temperature'), (181, 'Alarm delay'), (182, 'Capacity 0%'), (183, 'Number of channels'), (184, 'Device function'), (185, 'Scan channel'), (186, 'Scan parameter'), (187, 'Scan time'), (188, 'Scan data'), (189, 'Valve open'), (190, 'Number of runs'), (191, 'Minimum process time'), (192, 'Leak rate'), (193, 'Mode info request'), (194, 'Mode info option list'), (195, 'Mode info option description'), (196, 'Calibrations options'), (197, 'Mass flow'), (198, 'Bus address'), (199, 'Interface configuration'), (200, 'Baudrate'), (201, 'Bus diagnostic string'), (202, 'Number of vanes'), (203, 'Fieldbus'), (204, 'fMeasure'), (205, 'fSetpoint'), (206, 'Mass'), (207, 'Manufacturer status register'), (208, 'Manufacturer warning register'), (209, 'Manufacturer error register'), (210, 'Diagnostic history string'), (211, 'Diagnostic mode'), (212, 'Manufacturer status enable'), (213, 'Analog output zero adjust'), (214, 'Analog output span adjust'), (215, 'Analog input zero adjust'), (216, 'Analog input span adjust'), (217, 'Sensor input zero adjust'), (218, 'Sensor input span adjust'), (219, 'Temperature input zero adjust'), (220, 'Temperature input span adjust'), (221, 'Adaptive smoothing factor'), (222, 'Slope setpoint step'), (223, 'Filter length'), (224, 'Absolute accuracy'), (225, 'Lookup table index'), (226, 'Lookup table X'), (227, 'Lookup table Y'), (228, 'Lookup table temperature index'), (229, 'Lookup table temperature'), (230, 'Valve maximum'), (231, 'Valve mode'), (232, 'Valve open correction'), (233, 'Valve zero hold'), (234, 'Valve slope'), (235, 'IFI data'), (236, 'Range used'), (237, 'Fluidset properties'), (238, 'Lookup table unit type index'), (239, 'Lookup table unit type'), (240, 'Lookup table unit index'), (241, 'Lookup table unit'), (244, 'Capacity unit type temperature'), (245, 'Capacity unit pressure'), (248, 'Formula type'), (249, 'Heat capacity'), (250, 'Thermal conductivity'), (251, 'Viscosity'), (252, 'Standard flow'), (253, 'Controller speed'), (254, 'Sensor code'), (255, 'Sensor configuration code'), (256, 'Restriction code'), (257, 'Restriction configurator code'), (258, 'Restriction NxP'), (259, 'Seals information'), (260, 'Valve code'), (261, 'Valve configuration code'), (262, 'Instrument properties'), (263, 'Lookup table frequency index'), (264, 'Lookup table frequency frequency'), (265, 'Lookup table frequency temperature'), (266, 'Lookup table frequency density'), (267, 'Lookup table frequency span adjust'), (268, 'Capacity unit index (ext)'), (269, 'Density actual'), (270, 'Measured restriction'), (271, 'Temperature potmeter'), (272, 'Temperature potmeter gain'), (273, 'Counter controller overrun correction'), (274, 'Counter controller gain'), (275, 'Sub fluid number'), (276, 'Temperature compensation factor'), (277, 'DSP register address'), (278, 'DSP register long'), (279, 'DSP register floating point'), (280, 'DSP register integer'), (281, 'Standard deviation'), (282, 'Measurement status'), (283, 'Measurement stop criteria'), (284, 'Measurement time out'), (285, 'Maximum number of runs'), (286, 'Minimum standard deviation'), (287, 'IO switch status'), (288, 'Sensor bridge settings'), (289, 'Sensor bridge current'), (290, 'Sensor resistance'), (291, 'Sensor bridge voltage'), (292, 'Sensor group name'), (293, 'Sensor calibration temperature'), (294, 'Valve safe state'), (295, 'Counter unit type index'), (296, 'Counter unit type'), (297, 'Counter unit index (ext)'), (298, 'Bus1 selection'), (299, 'Bus1 medium'), (300, 'Bus2 mode'), (301, 'Bus2 selection'), (302, 'Bus2 address'), (303, 'Bus2 baudrate'), (304, 'Bus2 medium'), (305, 'Bus2 diagnostics'), (306, 'Bus2 name'), (307, 'PIO channel selection'), (308, 'PIO parameter'), (309, 'PIO input/output filter'), (310, 'PIO parameter capacity 0%'), (311, 'PIO parameter capacity 100%'), (312, 'PIO configuration selection'), (313, 'PIO analog zero adjust'), (314, 'PIO analog span adjust'), (315, 'PIO hardware capacity max'), (316, 'PIO capacity set selection'), (317, 'PIO hardware capacity 0%'), (318, 'PIO hardware capacity 100%'), (319, 'Hardware platform id'), (320, 'Hardware platform sub id'), (321, 'Temporary baudrate'), (322, 'Setpoint monitor mode'), (323, 'BHT12'), (324, 'Nominal sensor voltage'), (325, 'Sensor voltage compensation factor'), (326, 'PCB serial number'), (327, 'Minimum measure time'), (328, 'Bus1 parity'), (329, 'Bus2 parity'), (330, 'Firmware id')])
myIdent = str(self.getProcess()) + ":" + str(self.getNumber())
if myIdent in getIdent.keys():
if getIdent[myIdent] in getWord.keys():
self.human = getWord[getIdent[myIdent]]
# subclass for MKFlowData
class MKFlowProcess():
class MKFlowParameter(MKFlowParameter):
pass
def __init__(self):
self.number = -1
self.length = 0
self.data = []
self.Parameter = []
def set(self, data):
self.data = data
self.number = data[0]
def analyse(self):
index = 0
position = 1
chained = True
while chained:
index = len(self.Parameter)
self.Parameter.append(self.MKFlowParameter())
self.Parameter[index].set(self.data[position:])
self.Parameter[index].setProcess(self.getProcess())
self.Parameter[index].analyse()
position += self.Parameter[index].getLength()
chained = self.Parameter[index].isChained()
self.length = position
def isChained(self):
if self.number >= 128:
return True
else:
return False
def getNumber(self):
return self.number
def getProcess(self):
if self.isChained():
return (self.number - 128)
else:
return self.number
def getLength(self):
return self.length
def stdout(self, leading = '\t\t'):
print leading, "-- MKFlowProcess Class Output Begin --"
print leading, 'Data:\t', self.data
print leading, 'Data:\t', self.data[0:self.getLength()]
print leading, '1st byte:\t', format(self.data[0], '08b')[0:4] + ' ' + format(self.data[0], '08b')[4:8]
print leading, 'chained:\t', self.isChained()
print leading, 'Process:\t', self.getProcess()
print leading, 'Total Parameters: ', len(self.Parameter)
for parameter in self.Parameter:
parameter.stdout(leading + '\t')
print leading, "-- MKFlowProcess Class Output End --"
class MKFlowData():
class MKFlowProcess(MKFlowProcess):
pass
def __init__(self):
self.data = []
self.active = False
self.process = []
self.length = 0
def set(self,data):
self.active = True
self.data = data
self.analyse()
def analyse(self):
self.analyseProcess()
if not self.check():
raise ValueError('Data was not fully processed. Some information might be missing. Declare whole as invalid')
pass
def check(self):
return (len(self.data) == self.length)
def analyseProcess(self):
index = 0
position = 0
chained = True
while chained:
index = len(self.process)
self.process.append(self.MKFlowProcess())
self.process[index].set(self.data[position:])
self.process[index].analyse()
position += self.process[index].getLength()
chained = self.process[index].isChained()
self.length = position
def stdout(self, leading = '\t'):
print leading, "-- MKFlowData Class Output Begin --"
print leading, "Data Array: \t", self.data
print leading, "Data Array: \t", self.data[0:self.length]
print leading, 'Total Processes:\t', len(self.process)
print leading, 'Data' + (" not " if not self.check() else " ") +'fully processed'
for process in self.process:
process.stdout('\t\t')
print leading, "-- MKFlowData Class Output End --"
class MKFlowRequest(MKFlowData):
def stdoutShort(self, indent=''):
for process in self.process:
for parameter in process.Parameter:
return '\t'.join(str(i) for i in [indent , parameter.getProcess(), parameter.getIndex(), parameter.getNumber(), parameter.getHuman()])
class MKFlowProcess(MKFlowProcess):
class MKFlowParameter(MKFlowParameter):
def analyse(self):
self.analyseData()
self.analyseDataType(self.number)
self.setLength(3)
def analyseData(self):
try:
if len(self.data)<3:
raise ValueError('MKFlowRequest:analyseData data array too short')
self.index = self.data[0]
self.process = self.data[1] # process should be filled by parent
self.number = self.data[2]
except:
raise
def setLength(self,length=0):
self.length = length
if self.dataType == 'string':
self.length += 1
self.DataLength = self.data[3]
def getNumber(self):
# FB Number ( no chaining parameter present)
return self.substractDataType(self.number)
def stdout(self, leading = '\t\t\t'):
print leading, "-- MKFlowRequest Class Output Begin --"
print leading, 'Data: \t', self.getData()
print leading, '1st byte:\t', format(self.data[0], '08b')[0:4] + ' ' + format(self.data[0], '08b')[4:8]
print leading, 'Chained: \t', self.isChained()
print leading, 'Index: \t', self.getIndex()
print leading, '2nd byte:\t', format(self.data[1], '08b')[0:4] + ' ' + format(self.data[1], '08b')[4:8]
print leading, 'Process: \t', self.getProcess()
print leading, '3rd byte:\t', format(self.data[2], '08b')[0:4] + ' ' + format(self.data[2], '08b')[4:8]
print leading, 'DataType:\t', self.getDataType()
print leading, 'FbNr: \t', self.getNumber()
print leading, 'Length: \t', self.getLength()
print leading, 'Human Ind:\t', self.getHuman()
print leading, "-- MKFlowRequest Class Output End --"
class MKFlowSent(MKFlowData):
def stdoutShort(self, indent=''):
for process in self.process:
for parameter in process.Parameter:
return '\t'.join(str(i) for i in [indent, process.getProcess(), parameter.getIndex(), None, parameter.getValue()])
class MKFlowProcess(MKFlowProcess):
class MKFlowParameter(MKFlowParameter):
def analyse(self):
self.analyseData()
self.analyseDataType()
self.analyseValue()
def analyseValue(self):
self.dataStart = 1
self.dataValueFloat = float(0)
if self.dataType == 'string':
self.dataLength = self.data[self.dataStart]
self.dataStart += 1
self.setLength()
self.dataValue = ''.join(chr(i) for i in self.data[self.dataStart:self.length])
elif self.dataType == 'long':
# can also be IEE floating point notation
self.dataLength = 4
self.setLength()
self.dataValue = int(''.join(hex(i)[2:] for i in self.data[self.dataStart:self.length]),16)
elif self.dataType == 'integer':
self.dataLength = 2
self.setLength()
self.dataValue = int(''.join(hex(i)[2:] for i in self.data[self.dataStart:self.length]),16)
elif self.dataType == 'character':
self.dataLength = 1
self.setLength()
self.dataValue = self.data[self.dataStart]
else:
self.dataLength = 0
self.setLength()
self.dataValue = None
raise ValueError('MKFlowSent:analyseValue datatype not found: ' + str(self.dataType))
if (len(self.data)) < self.length:
pass
#raise ValueError('length of data does not match message size.')
elif (len(self.data)) > self.length:
pass
#raise ValueError('length of data too long. Check for chaining!')
def setLength(self):
if self.dataLength == 0:
# undefined length. use whole
self.length = len(self.data)
else:
self.length = self.dataLength + self.dataStart
def getValue(self):
return self.dataValue
def stdout(self, leading = '\t\t\t'):
print leading, "-- MKFlowSent:MKFlowProcess:MKFlowParameter Class Output Begin --"
print leading, 'Data: \t', self.getData()
print leading, '1st byte:\t', format(self.data[0], '08b')[0:4] + ' ' + format(self.data[0], '08b')[4:8]
print leading, 'Chained: \t', self.isChained()
print leading, 'DataType:\t', self.getDataType()
print leading, 'Index: \t', self.getIndex()
print leading, '2nd byte:\t', format(self.data[1], '08b')[0:4] + ' ' + format(self.data[1], '08b')[4:8]
print leading, 'Length: \t', self.getLength()
print leading, 'Value: \t', self.getValue()
print leading, "-- MKFlowSent:MKFlowProcess:MKFlowParameter Class Output End --"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/env python
import time
from MKFlowMain import MKFlow
ethanol = MKFlow('/dev/ttyUSB2', '/dev/ttyUSB3', 0)
argon = MKFlow('/dev/ttyUSB0', '/dev/ttyUSB1', 1)
threads = []
threads.append(ethanol)
threads.append(argon)
for t in threads:
print "starting ..."
t.start()
t.debug()
try:
while True:
time.sleep(10)
except KeyboardInterrupt:
for t in threads:
print "stoping ..."
t.stop()
|