예제 #1
0
  /**
   * Transforms the specified array of times and marks. Known samples are those for which times are
   * zero, and times and marks for these known samples are used to compute times and marks for
   * unknown samples.
   *
   * @param times input/output array of times.
   * @param marks input/output array of marks.
   */
  public void apply(float[][][] times, int[][][] marks) {

    // Measure elapsed time in seconds.
    Stopwatch sw = new Stopwatch();
    sw.start();
    log.fine("TimeMarker3.apply: begin time=" + (int) sw.time());

    // Initialize all unknown times to infinity.
    for (int i3 = 0; i3 < _n3; ++i3) {
      for (int i2 = 0; i2 < _n2; ++i2) {
        for (int i1 = 0; i1 < _n1; ++i1) {
          if (times[i3][i2][i1] != 0.0f) times[i3][i2][i1] = INFINITY;
        }
      }
    }

    // Indices of known samples in random order.
    short[][] kk = indexKnownSamples(times);
    short[] k1 = kk[0];
    short[] k2 = kk[1];
    short[] k3 = kk[2];
    shuffle(k1, k2, k3);
    int nk = k1.length;

    // Array for the eikonal solution times.
    float[][][] t = new float[_n3][_n2][_n1];

    // Active list of samples used to compute times.
    ActiveList al = new ActiveList();

    // For all known samples, ...
    for (int ik = 0; ik < nk; ++ik) {
      if (ik % (1 + (nk - 1) / 100) == 0)
        log.fine("  apply: ik/nk=" + ik + "/" + nk + " time=" + (int) sw.time());
      int i1 = k1[ik];
      int i2 = k2[ik];
      int i3 = k3[ik];

      // Clear activated flags so we can tell which samples become activated.
      clearActivated();

      // Put the known sample with time zero into the active list.
      t[i3][i2][i1] = 0.0f;
      al.append(_s[i3][i2][i1]);

      // The mark for the known sample.
      int m = marks[i3][i2][i1];

      // Process the active list until empty.
      solve(al, t, m, times, marks);
    }

    // Log elapsed time.
    sw.stop();
    log.fine("TimeMarker3.apply: end time=" + (int) sw.time());
  }
예제 #2
0
 /*
  * Solves for times by processing samples in the active list in parallel.
  */
 private void solveParallel(
     final ActiveList al,
     final float[][][] t,
     final int m,
     final float[][][] times,
     final int[][][] marks) {
   int mbmin = 64; // target minimum number of samples per block
   int nbmax = 256; // maximum number of blocks
   final float[][] dtask = new float[nbmax][];
   final ActiveList[] bltask = new ActiveList[nbmax];
   while (!al.isEmpty()) {
     final int n = al.size(); // number of samples in active (A) list
     final int mbmax = max(mbmin, 1 + (n - 1) / nbmax); // max samples per block
     final int nb = 1 + (n - 1) / mbmax; // number of blocks <= nbmax
     final int mb = 1 + (n - 1) / nb; // evenly distribute samples per block
     Parallel.loop(
         nb,
         new Parallel.LoopInt() { // for all blocks, ...
           public void compute(int ib) {
             if (bltask[ib] == null) { // if necessary for this block, make ...
               dtask[ib] = new float[6]; // work array for tensor coefficients
               bltask[ib] = new ActiveList(); // and an empty active list
             }
             int i = ib * mb; // beginning of block
             int j = min(i + mb, n); // beginning of next block (or end)
             for (int k = i; k < j; ++k) { // for each sample in block, ...
               Sample s = al.get(k); // get k'th sample from A list
               solveOne(t, m, times, marks, s, bltask[ib], dtask[ib]); // do sample
             }
             bltask[ib].setAllAbsent(); // needed when merging B lists below
           }
         });
     // Merge samples from all B lists to a new A list. All samples
     // in B lists are currently marked as absent in the A list. As
     // samples in B lists are appended to the A list, their absent
     // flags are set to false, so that no sample is appended more
     // than once to the new A list.
     al.clear();
     for (int ib = 0; ib < nb; ++ib) {
       if (bltask[ib] != null) {
         al.appendIfAbsent(bltask[ib]);
         bltask[ib].clear();
       }
     }
   }
 }
예제 #3
0
 void appendIfAbsent(ActiveList al) {
   if (_n + al._n > _a.length) growTo(2 * (_n + al._n));
   int n = al._n;
   for (int i = 0; i < n; ++i) {
     Sample s = al.get(i);
     if (s.absent) {
       _a[_n++] = s;
       s.absent = false;
     }
   }
 }
예제 #4
0
 /*
  * Solves for times by sequentially processing each sample in active list.
  */
 private void solveSerial(
     ActiveList al, float[][][] t, int m, float[][][] times, int[][][] marks) {
   float[] d = new float[6];
   ActiveList bl = new ActiveList();
   int ntotal = 0;
   while (!al.isEmpty()) {
     // al.shuffle(); // demonstrate that solution depends on order
     int n = al.size();
     ntotal += n;
     for (int i = 0; i < n; ++i) {
       Sample s = al.get(i);
       solveOne(t, m, times, marks, s, bl, d);
     }
     bl.setAllAbsent();
     al.clear();
     al.appendIfAbsent(bl);
     bl.clear();
   }
   trace("solveSerial: ntotal=" + ntotal);
   trace("             nratio=" + (float) ntotal / (float) (_n1 * _n2 * _n3));
 }
예제 #5
0
  /*
   * Processes one sample from the A list.
   * Appends samples not yet converged to the B list.
   */
  private void solveOne(
      float[][][] t,
      int m,
      float[][][] times,
      int[][][] marks,
      Sample s,
      ActiveList bl,
      float[] d) {
    // Sample indices.
    int i1 = s.i1;
    int i2 = s.i2;
    int i3 = s.i3;

    // Current time and new time computed from all four neighbors.
    float ti = currentTime(t, i1, i2, i3);
    float ci = computeTime(t, i1, i2, i3, K1S[6], K2S[6], K3S[6], d);
    t[i3][i2][i1] = ci;

    // If new and current times are close enough (converged), then ...
    if (ci >= ti * ONE_MINUS_EPSILON) {

      // Neighbors may need to be activated if computed time is small
      // relative to the minimum time computed so far. The factor 1.5
      // improves accuracy for large anisotropy. Cost increases as the
      // square of this factor, so we do not want it to be too large.
      boolean checkNabors = ci <= 1.5f * times[i3][i2][i1];

      // If computed time less than minimum time, mark this sample.
      if (ci < times[i3][i2][i1]) {
        times[i3][i2][i1] = ci;
        marks[i3][i2][i1] = m;
      }

      // If necessary, check the neighbors.
      if (checkNabors) {

        // For all six neighbors, ...
        for (int k = 0; k < 6; ++k) {

          // Neighbor sample indices; skip if out of bounds.
          int j1 = i1 + K1[k];
          if (j1 < 0 || j1 >= _n1) continue;
          int j2 = i2 + K2[k];
          if (j2 < 0 || j2 >= _n2) continue;
          int j3 = i3 + K3[k];
          if (j3 < 0 || j3 >= _n3) continue;

          // Skip neighbor sample if computed time would be too big.
          // if (!doComputeTime(t,times,j1,j2)) continue;

          // Current and computed times for the neighbor.
          float tj = currentTime(t, j1, j2, j3);
          float cj = computeTime(t, j1, j2, j3, K1S[k], K2S[k], K3S[k], d);

          // If computed time is significantly less than current time, ...
          if (cj < tj * ONE_MINUS_EPSILON) {

            // Replace the current time.
            t[j3][j2][j1] = cj;

            // Append neighbor to the B list, thereby activating it.
            bl.append(_s[j3][j2][j1]);
          }
        }
      }
    }

    // Else, if not converged, append this sample to the B list.
    else {
      bl.append(s);
    }
  }
예제 #6
0
  /*
   * Solves for times by processing samples in the active list in parallel.
   */
  private void solveParallelX(
      final ActiveList al,
      final float[][][] t,
      final int m,
      final float[][][] times,
      final int[][][] marks) {
    int nthread = Runtime.getRuntime().availableProcessors();
    ExecutorService es = Executors.newFixedThreadPool(nthread);
    CompletionService<Void> cs = new ExecutorCompletionService<Void>(es);
    ActiveList[] bl = new ActiveList[nthread];
    float[][] d = new float[nthread][];
    for (int ithread = 0; ithread < nthread; ++ithread) {
      bl[ithread] = new ActiveList();
      d[ithread] = new float[6];
    }
    final AtomicInteger ai = new AtomicInteger();
    int ntotal = 0;
    // int niter = 0;
    while (!al.isEmpty()) {
      ai.set(0); // initialize the shared block index to zero
      final int n = al.size(); // number of samples in active (A) list
      ntotal += n;
      final int mb = 32; // size of blocks of samples
      final int nb = 1 + (n - 1) / mb; // number of blocks of samples
      int ntask = min(nb, nthread); // number of tasks (threads to be used)
      for (int itask = 0; itask < ntask; ++itask) { // for each task, ...
        final ActiveList bltask = bl[itask]; // task-specific B list
        final float[] dtask = d[itask]; // task-specific work array
        cs.submit(
            new Callable<Void>() { // submit new task
              public Void call() {
                for (int ib = ai.getAndIncrement(); ib < nb; ib = ai.getAndIncrement()) {
                  int i = ib * mb; // beginning of block
                  int j = min(i + mb, n); // beginning of next block (or end)
                  for (int k = i; k < j; ++k) { // for each sample in block, ...
                    Sample s = al.get(k); // get k'th sample from A list
                    solveOne(t, m, times, marks, s, bltask, dtask); // process sample
                  }
                }
                bltask.setAllAbsent(); // needed when merging B lists below
                return null;
              }
            });
      }
      try {
        for (int itask = 0; itask < ntask; ++itask) cs.take();
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      }

      // Merge samples from all B lists to a new A list. As samples
      // are appended, their absent flags are set to false, so that
      // each sample is appended no more than once to the new A list.
      al.clear();
      for (int itask = 0; itask < ntask; ++itask) {
        al.appendIfAbsent(bl[itask]);
        bl[itask].clear();
      }
      // ++niter;
    }
    es.shutdown();
    // trace("solveParallel: ntotal="+ntotal);
    // trace("               nratio="+(float)ntotal/(float)(_n1*_n2*_n3));
  }