@@ -933,81 +933,36 @@ int fit2DPeaks(unsigned nPeaks, int nrPixelsThisRegion, double *z,
933933
934934 // Set up FunctionData with pre-allocated peak buffers (Fix 5)
935935 // fitPeakBuf is a single block of nPeaks*8 doubles, carved into 8 arrays:
936- FunctionData f_data = {
937- .NrPixels = nrPixelsThisRegion ,
938- .nPeaks = (int )nPeaks ,
939- .Rs = Rs ,
940- .Etas = Etas ,
941- .z = z ,
942- .pkIMAX = fitPeakBuf + 0 * nPeaks ,
943- .pkR = fitPeakBuf + 1 * nPeaks ,
944- .pkEta = fitPeakBuf + 2 * nPeaks ,
945- .pkMu = fitPeakBuf + 3 * nPeaks ,
946- .pkInvSigmaGR2 = fitPeakBuf + 4 * nPeaks ,
947- .pkInvSigmaLR2 = fitPeakBuf + 5 * nPeaks ,
948- .pkInvSigmaGEta2 = fitPeakBuf + 6 * nPeaks ,
949- .pkInvSigmaLEta2 = fitPeakBuf + 7 * nPeaks };
936+ FunctionData f_data = {.NrPixels = nrPixelsThisRegion ,
937+ .nPeaks = (int )nPeaks ,
938+ .Rs = Rs ,
939+ .Etas = Etas ,
940+ .z = z ,
941+ .pkIMAX = fitPeakBuf + 0 * nPeaks ,
942+ .pkR = fitPeakBuf + 1 * nPeaks ,
943+ .pkEta = fitPeakBuf + 2 * nPeaks ,
944+ .pkMu = fitPeakBuf + 3 * nPeaks ,
945+ .pkInvSigmaGR2 = fitPeakBuf + 4 * nPeaks ,
946+ .pkInvSigmaLR2 = fitPeakBuf + 5 * nPeaks ,
947+ .pkInvSigmaGEta2 = fitPeakBuf + 6 * nPeaks ,
948+ .pkInvSigmaLEta2 = fitPeakBuf + 7 * nPeaks };
950949
951950 int rc = 0 ;
952951 double minf = 0 ;
953952
954953 if (nPeaks > 1 ) {
955954 // -----------------------------------------------------------
956- // Fix 1, Stage 1: Fit each peak INDIVIDUALLY with Nelder-Mead
957- // This keeps dimensionality at 9 (1 bg + 8 peak) regardless of total peaks.
955+ // Joint fit with SBPLX: internally decomposes the high-dimensional
956+ // space into lower-dimensional subspaces, making it efficient for
957+ // multi-peak fitting while properly handling overlapping peaks.
958958 // -----------------------------------------------------------
959- double x1 [9 ], xl1 [9 ], xu1 [9 ];
960- FunctionData f_data_single = f_data ;
961- f_data_single .nPeaks = 1 ; // Single-peak objective
962-
963- for (unsigned p = 0 ; p < nPeaks ; p ++ ) {
964- // bg
965- x1 [0 ] = x [0 ];
966- xl1 [0 ] = xl [0 ];
967- xu1 [0 ] = xu [0 ];
968- // Copy this peak's 8 params & bounds
969- for (int j = 1 ; j <= 8 ; j ++ ) {
970- x1 [j ] = x [8 * p + j ];
971- xl1 [j ] = xl [8 * p + j ];
972- xu1 [j ] = xu [8 * p + j ];
973- }
974-
975- nlopt_opt opt1 = nlopt_create (NLOPT_LN_NELDERMEAD , 9 );
976- if (!opt1 )
977- continue ;
978-
979- nlopt_set_lower_bounds (opt1 , xl1 );
980- nlopt_set_upper_bounds (opt1 , xu1 );
981- nlopt_set_maxtime (opt1 , 2.0 ); // Short per-peak timeout
982- nlopt_set_min_objective (opt1 , peakFittingObjectiveFunction ,
983- & f_data_single );
984-
985- double minf1 ;
986- nlopt_optimize (opt1 , x1 , & minf1 );
987- nlopt_destroy (opt1 );
988-
989- // Write back fitted values
990- x [0 ] = x1 [0 ]; // bg converges toward shared value
991- for (int j = 1 ; j <= 8 ; j ++ ) {
992- x [8 * p + j ] = x1 [j ];
993- }
994- }
995-
996- // -----------------------------------------------------------
997- // Fix 1, Stage 2: Joint refinement with SBPLX
998- // SBPLX internally decomposes the high-dimensional space into
999- // lower-dimensional subspaces, making it far more efficient than
1000- // Nelder-Mead for n > 10-20.
1001- // -----------------------------------------------------------
1002- f_data .nPeaks = (int )nPeaks ; // Restore full peak count
1003-
1004959 nlopt_opt opt = nlopt_create (NLOPT_LN_SBPLX , n );
1005960 if (!opt )
1006961 return ERROR_MEMORY_ALLOCATION ;
1007962
1008963 nlopt_set_lower_bounds (opt , xl );
1009964 nlopt_set_upper_bounds (opt , xu );
1010- // Fix 2: Adaptive timeout — scale with nPeaks
965+ // Adaptive timeout — scale with nPeaks
1011966 double timeout = 2.0 + 1.0 * nPeaks ;
1012967 if (timeout > 30.0 )
1013968 timeout = 30.0 ;
@@ -1582,13 +1537,12 @@ static ErrorCode processImageFrame(int fileNr, char *allData, size_t *sizeArr,
15821537 ws -> rads [0 ] = rMeanVal ;
15831538 ws -> etas [0 ] = etaMeanVal ;
15841539 } else {
1585- rc = fit2DPeaks (nPeaks , nrPixelsThisRegion , ws -> z , ws -> usefulPixels ,
1586- ws -> maximaValues , ws -> maximaPositions ,
1587- ws -> integratedIntensity , ws -> imax , ws -> yCenArray ,
1588- ws -> zCenArray , ws -> rads , ws -> etas , params -> Ycen ,
1589- params -> Zcen , thresh , ws -> nrPx , ws -> otherInfo ,
1590- metadata -> NrPixels , & retVal , ws -> fitRs , ws -> fitEtas ,
1591- ws -> fitPeakBuf );
1540+ rc = fit2DPeaks (
1541+ nPeaks , nrPixelsThisRegion , ws -> z , ws -> usefulPixels , ws -> maximaValues ,
1542+ ws -> maximaPositions , ws -> integratedIntensity , ws -> imax , ws -> yCenArray ,
1543+ ws -> zCenArray , ws -> rads , ws -> etas , params -> Ycen , params -> Zcen , thresh ,
1544+ ws -> nrPx , ws -> otherInfo , metadata -> NrPixels , & retVal , ws -> fitRs ,
1545+ ws -> fitEtas , ws -> fitPeakBuf );
15921546 }
15931547
15941548 for (int i = 0 ; i < nPeaks ; i ++ ) {
0 commit comments