1919
2020import java .util .ArrayList ;
2121import java .util .List ;
22+ import java .util .concurrent .Callable ;
23+ import java .util .concurrent .ExecutionException ;
24+ import java .util .concurrent .ExecutorService ;
25+ import java .util .concurrent .Executors ;
26+ import java .util .concurrent .Future ;
2227
2328import org .aavso .tools .vstar .data .ValidObservation ;
2429import org .aavso .tools .vstar .exception .AlgorithmError ;
@@ -60,6 +65,8 @@ public class WeightedWaveletZTransform implements IAlgorithm {
6065 private static final double WEIGHT_CUTOFF = 1.0e-9 ;
6166 private static final double NEG_LOG_WEIGHT_CUTOFF = -Math .log (WEIGHT_CUTOFF );
6267 private static final int MAX_AVAILABLE_THREADS = Math .max (1 , Runtime .getRuntime ().availableProcessors ());
68+ private static final long MIN_PARALLEL_GRID_POINTS = 5000L ;
69+ private static final int MIN_PARALLEL_OBSERVATIONS = 1000 ;
6370
6471 // Observations to be analysed.
6572 private List <ValidObservation > obs ;
@@ -77,7 +84,6 @@ public class WeightedWaveletZTransform implements IAlgorithm {
7784 private double maxWWZ ;
7885
7986 private double dcon ;
80- private double dmat [][] = new double [3 ][3 ];
8187 private double dt [];
8288 private double dx [];
8389 private double fhi ;
@@ -88,7 +94,7 @@ public class WeightedWaveletZTransform implements IAlgorithm {
8894 private int numdat ;
8995 private double tau [];
9096
91- private boolean interrupted ;
97+ private volatile boolean interrupted ;
9298 private int threadCount ;
9399
94100 /**
@@ -200,6 +206,14 @@ public int getMaxAvailableThreads() {
200206 return MAX_AVAILABLE_THREADS ;
201207 }
202208
209+ /**
210+ * Recommended thread count for UI defaults. This reflects machine capacity;
211+ * execute() applies a workload heuristic and may still choose fewer threads.
212+ */
213+ public static int getRecommendedThreadCount () {
214+ return MAX_AVAILABLE_THREADS ;
215+ }
216+
203217 /**
204218 * @return the stats
205219 */
@@ -442,51 +456,46 @@ public void make_freqs_from_period_range(double minPer, double maxPer,
442456 }
443457
444458 /**
445- * Invert the 3×3 symmetric matrix in dmat (in-place).
446- * Uses a closed-form cofactor formula. Faster than Gauss-Jordan for fixed 3×3,
447- * no pivoting logic, and avoids the per-(tau,freq) loop overhead.
459+ * Invert a 3x3 symmetric matrix in place.
448460 */
449- private void matinv () throws InterruptedException {
461+ private void matinv (double [][] mat ) throws InterruptedException {
450462 if (useLegacyMatinv ) {
451- matinvGaussJordan ();
463+ matinvGaussJordan (mat );
452464 return ;
453465 }
454- // Symmetric 3×3: a=dmat[0][0], b=dmat[0][1], c=dmat[0][2], d=dmat[1][1], e=dmat[1][2], f=dmat[2][2]
455- double a = dmat [0 ][0 ], b = dmat [0 ][1 ], c = dmat [0 ][2 ];
456- double d = dmat [1 ][1 ], e = dmat [1 ][2 ], f = dmat [2 ][2 ];
466+ double a = mat [0 ][0 ], b = mat [0 ][1 ], c = mat [0 ][2 ];
467+ double d = mat [1 ][1 ], e = mat [1 ][2 ], f = mat [2 ][2 ];
457468
458- // det = a(df - e²) - b(bf - ce) + c(be - cd)
459469 double det = a * (d * f - e * e ) - b * (b * f - c * e ) + c * (b * e - c * d );
460470 if (Math .abs (det ) <= 1.0e-14 ) {
461- return ; // singular, leave dmat unchanged (matches previous behaviour)
471+ return ;
462472 }
463473 double invDet = 1.0 / det ;
464474
465475 if (interrupted ) {
466476 throw new InterruptedException ();
467477 }
468478
469- // Adjugate (symmetric for symmetric input), then inv = adj/det
470479 double a00 = (d * f - e * e ) * invDet ;
471480 double a01 = (c * e - b * f ) * invDet ;
472481 double a02 = (b * e - c * d ) * invDet ;
473482 double a11 = (a * f - c * c ) * invDet ;
474483 double a12 = (c * b - a * e ) * invDet ;
475484 double a22 = (a * d - b * b ) * invDet ;
476485
477- dmat [0 ][0 ] = a00 ;
478- dmat [0 ][1 ] = a01 ;
479- dmat [0 ][2 ] = a02 ;
480- dmat [1 ][0 ] = a01 ;
481- dmat [1 ][1 ] = a11 ;
482- dmat [1 ][2 ] = a12 ;
483- dmat [2 ][0 ] = a02 ;
484- dmat [2 ][1 ] = a12 ;
485- dmat [2 ][2 ] = a22 ;
486+ mat [0 ][0 ] = a00 ;
487+ mat [0 ][1 ] = a01 ;
488+ mat [0 ][2 ] = a02 ;
489+ mat [1 ][0 ] = a01 ;
490+ mat [1 ][1 ] = a11 ;
491+ mat [1 ][2 ] = a12 ;
492+ mat [2 ][0 ] = a02 ;
493+ mat [2 ][1 ] = a12 ;
494+ mat [2 ][2 ] = a22 ;
486495 }
487496
488- /** Legacy Gauss-Jordan 3×3 in-place inverse; used only when useLegacyMatinv is true (benchmark). */
489- private void matinvGaussJordan () throws InterruptedException {
497+ /** Legacy Gauss-Jordan 3x3 in-place inverse; used only when useLegacyMatinv is true (benchmark). */
498+ private void matinvGaussJordan (double [][] mat ) throws InterruptedException {
490499 double dsol [][] = new double [3 ][3 ];
491500 double dfac ;
492501 int ndim = 2 ;
@@ -500,13 +509,13 @@ private void matinvGaussJordan() throws InterruptedException {
500509 }
501510 }
502511 for (int i = 0 ; i <= ndim ; i ++) {
503- if (dmat [i ][i ] == 0.0 ) {
512+ if (mat [i ][i ] == 0.0 ) {
504513 if (i == ndim )
505514 return ;
506515 for (int j = i + 1 ; j <= ndim ; j ++) {
507- if (dmat [j ][i ] != 0.0 ) {
516+ if (mat [j ][i ] != 0.0 ) {
508517 for (int k = 0 ; k <= ndim ; k ++) {
509- dmat [i ][k ] = dmat [i ][k ] + dmat [j ][k ];
518+ mat [i ][k ] = mat [i ][k ] + mat [j ][k ];
510519 dsol [i ][k ] = dsol [i ][k ] + dsol [j ][k ];
511520 }
512521 }
@@ -515,16 +524,16 @@ private void matinvGaussJordan() throws InterruptedException {
515524 throw new InterruptedException ();
516525 }
517526 }
518- dfac = dmat [i ][i ];
527+ dfac = mat [i ][i ];
519528 for (int j = 0 ; j <= ndim ; j ++) {
520- dmat [i ][j ] = dmat [i ][j ] / dfac ;
529+ mat [i ][j ] = mat [i ][j ] / dfac ;
521530 dsol [i ][j ] = dsol [i ][j ] / dfac ;
522531 }
523532 for (int j = 0 ; j <= ndim ; j ++) {
524533 if (j != i ) {
525- dfac = dmat [j ][i ];
534+ dfac = mat [j ][i ];
526535 for (int k = 0 ; k <= ndim ; k ++) {
527- dmat [j ][k ] = dmat [j ][k ] - (dmat [i ][k ] * dfac );
536+ mat [j ][k ] = mat [j ][k ] - (mat [i ][k ] * dfac );
528537 dsol [j ][k ] = dsol [j ][k ] - (dsol [i ][k ] * dfac );
529538 }
530539 if (interrupted ) {
@@ -535,7 +544,7 @@ private void matinvGaussJordan() throws InterruptedException {
535544 }
536545 for (int i = 0 ; i <= ndim ; i ++) {
537546 for (int j = 0 ; j <= ndim ; j ++) {
538- dmat [i ][j ] = dsol [i ][j ];
547+ mat [i ][j ] = dsol [i ][j ];
539548 }
540549 if (interrupted ) {
541550 throw new InterruptedException ();
@@ -544,8 +553,80 @@ private void matinvGaussJordan() throws InterruptedException {
544553 }
545554
546555 private void wwt () throws InterruptedException {
556+ final WWZStatistic [] statsOut = new WWZStatistic [ntau * nfreq ];
557+ final WWZStatistic [] maxOut = new WWZStatistic [ntau ];
558+ final int effectiveThreadCount = getEffectiveThreadCount ();
559+
560+ if (effectiveThreadCount <= 1 || ntau <= 1 ) {
561+ processTauRange (1 , ntau , statsOut , maxOut );
562+ } else {
563+ int threads = Math .min (effectiveThreadCount , ntau );
564+ ExecutorService executor = Executors .newFixedThreadPool (threads );
565+ List <Future <Void >> futures = new ArrayList <Future <Void >>();
566+ int chunk = (ntau + threads - 1 ) / threads ;
567+ for (int t = 0 ; t < threads ; t ++) {
568+ final int tauStart = 1 + t * chunk ;
569+ final int tauEnd = Math .min (ntau , tauStart + chunk - 1 );
570+ if (tauStart > tauEnd ) {
571+ continue ;
572+ }
573+ futures .add (executor .submit (new Callable <Void >() {
574+ @ Override
575+ public Void call () throws Exception {
576+ processTauRange (tauStart , tauEnd , statsOut , maxOut );
577+ return null ;
578+ }
579+ }));
580+ }
581+ try {
582+ for (Future <Void > f : futures ) {
583+ f .get ();
584+ }
585+ } catch (ExecutionException e ) {
586+ Throwable cause = e .getCause ();
587+ interrupted = true ;
588+ if (cause instanceof InterruptedException ) {
589+ throw (InterruptedException ) cause ;
590+ }
591+ throw new RuntimeException (cause );
592+ } catch (InterruptedException e ) {
593+ interrupted = true ;
594+ throw e ;
595+ } finally {
596+ executor .shutdownNow ();
597+ }
598+ }
599+
600+ stats = new ArrayList <WWZStatistic >(statsOut .length );
601+ maximalStats = new ArrayList <WWZStatistic >(maxOut .length );
602+ for (WWZStatistic stat : statsOut ) {
603+ if (stat != null ) {
604+ stats .add (stat );
605+ }
606+ }
607+ for (WWZStatistic maxStat : maxOut ) {
608+ if (maxStat != null ) {
609+ maximalStats .add (maxStat );
610+ }
611+ }
612+ }
613+
614+ private int getEffectiveThreadCount () {
615+ if (threadCount <= 1 ) {
616+ return 1 ;
617+ }
618+ long gridPoints = (long ) ntau * (long ) Math .max (1 , nfreq );
619+ if (gridPoints < MIN_PARALLEL_GRID_POINTS || numdat < MIN_PARALLEL_OBSERVATIONS ) {
620+ return 1 ;
621+ }
622+ return threadCount ;
623+ }
624+
625+ private void processTauRange (int itau1 , int itau2 , WWZStatistic [] statsOut , WWZStatistic [] maxOut )
626+ throws InterruptedException {
547627 double dvec [] = new double [3 ];
548628 double dcoef [] = new double [3 ];
629+ double [][] dmat = new double [3 ][3 ];
549630 int itau , ifreq , idat ;
550631 double domega , dweight2 , dz , dweight ;
551632 double dcc , dcw , dss , dsw , dxw , dvarw ;
@@ -569,8 +650,6 @@ private void wwt() throws InterruptedException {
569650 double dz2Cutoff = (dcon > 0.0 ) ? (NEG_LOG_WEIGHT_CUTOFF / dcon ) : Double .POSITIVE_INFINITY ;
570651
571652 int ndim = 2 ;
572- int itau1 = 1 ;
573- int itau2 = ntau ;
574653 int ifreq1 = 1 ;
575654 int ifreq2 = nfreq ;
576655
@@ -679,7 +758,7 @@ private void wwt() throws InterruptedException {
679758 }
680759 }
681760
682- matinv ();
761+ matinv (dmat );
683762
684763 for (n1 = 0 ; n1 <= ndim ; n1 ++) {
685764 for (n2 = 0 ; n2 <= ndim ; n2 ++) {
@@ -724,7 +803,7 @@ private void wwt() throws InterruptedException {
724803 WWZStatistic stat = new WWZStatistic (dtau , dfre , dpowz , damp ,
725804 dcoef [0 ], dneff );
726805
727- stats . add ( stat ) ;
806+ statsOut [( itau - 1 ) * nfreq + ( ifreq - 1 )] = stat ;
728807
729808 if (dpowz > dmz ) {
730809 dmz = dpowz ;
@@ -739,7 +818,7 @@ private void wwt() throws InterruptedException {
739818 WWZStatistic maximalStat = new WWZStatistic (dtau , dmfre , dmz ,
740819 dmamp , dmcon , dmneff );
741820
742- maximalStats . add ( maximalStat ) ;
821+ maxOut [ itau - 1 ] = maximalStat ;
743822 }
744823 }
745824
0 commit comments