コード例 #1
0
ファイル: Solver.cpp プロジェクト: geoffmomin/OpenMOC
/**
 * @brief Computes keff by performing a series of transport sweep and
 *        source updates.
 * @details This is the main method exposed to the user through the Python
 *          interface to run a simulation. The method makes an initial guess
 *          for the scalar and boundary fluxes and peforms transport sweeps
 *          and source updates until convergence. The method may be called
 *          by the user from Python as follows:
 *
 * @code
 *          max_iters = 1000
 *          solver.convergeSource(max_iters)
 * @endcode
 *
 * @param max_iterations the maximum number of source iterations to allow
 * @return the value of the computed eigenvalue \f$ k_{eff} \f$
 */
FP_PRECISION Solver::convergeSource(int max_iterations) {

  /* Error checking */
  if (_geometry == NULL)
    log_printf(ERROR, "The Solver is unable to converge the source "
               "since it does not contain a Geometry");

  if (_track_generator == NULL)
    log_printf(ERROR, "The Solver is unable to converge the source "
               "since it does not contain a TrackGenerator");

  log_printf(NORMAL, "Converging the source...");

  /* Clear all timing data from a previous simulation run */
  clearTimerSplits();

  /* Start the timer to record the total time to converge the source */
  _timer->startTimer();

  /* Counter for the number of iterations to converge the source */
  _num_iterations = 0;

  /* An initial guess for the eigenvalue */
  _k_eff = 1.0;

  /* The residual on the source */
  FP_PRECISION residual = 0.0;

  /* The old residual and k_eff */
  FP_PRECISION residual_old = 1.0;
  FP_PRECISION keff_old = 1.0;

  /* Initialize data structures */
  initializePolarQuadrature();
  initializeFluxArrays();
  initializeSourceArrays();
  buildExpInterpTable();
  initializeFSRs();

  if (_cmfd != NULL && _cmfd->isFluxUpdateOn())
    initializeCmfd();

  /* Check that each FSR has at least one segment crossing it */
  checkTrackSpacing();

  /* Set scalar flux to unity for each region */
  flattenFSRSources(1.0);
  flattenFSRFluxes(1.0);
  zeroTrackFluxes();

  /* Source iteration loop */
  for (int i=0; i < max_iterations; i++) {

    log_printf(NORMAL, "Iteration %d: \tk_eff = %1.6f"
               "\tres = %1.3E", i, _k_eff, residual);

    normalizeFluxes();
    residual = computeFSRSources();
    transportSweep();
    addSourceToScalarFlux();

    /* Solve CMFD diffusion problem and update MOC flux */
    if (_cmfd != NULL && _cmfd->isFluxUpdateOn()){
      _k_eff = _cmfd->computeKeff(i);
      _cmfd->updateBoundaryFlux(_tracks, _boundary_flux, _tot_num_tracks);
    }
    else
      computeKeff();

    _num_iterations++;

    /* Check for convergence of the fission source distribution */
    if (i > 1 && residual < _source_convergence_thresh) {
      _timer->stopTimer();
      _timer->recordSplit("Total time to converge the source");
      return _k_eff;
    }
  }

  _timer->stopTimer();
  _timer->recordSplit("Total time to converge the source");

  log_printf(WARNING, "Unable to converge the source after %d iterations",
             max_iterations);

  return _k_eff;
}
コード例 #2
0
ファイル: CPUSolver.cpp プロジェクト: soft-lean/OpenMOC
/**
 * @brief This method performs one transport sweep of all azimuthal angles,
 *        Tracks, Track segments, polar angles and energy groups.
 * @details The method integrates the flux along each Track and updates the
 *          boundary fluxes for the corresponding output Track, while updating
 *          the scalar flux in each flat source region.
 */
void CPUSolver::transportSweep() {

  int tid;
  int min_track, max_track;
  Track* curr_track;
  int azim_index;
  int num_segments;
  segment* curr_segment;
  segment* segments;
  FP_PRECISION* track_flux;

  log_printf(DEBUG, "Transport sweep with %d OpenMP threads", _num_threads);

  /* Initialize flux in each FSr to zero */
  flattenFSRFluxes(0.0);

  if (_cmfd->getMesh()->getCmfdOn())
    zeroSurfaceCurrents();

  /* Loop over azimuthal angle halfspaces */
  for (int i=0; i < 2; i++) {

    /* Compute the minimum and maximum Track IDs corresponding to
     * this azimuthal angular halfspace */
    min_track = i * (_tot_num_tracks / 2);
    max_track = (i + 1) * (_tot_num_tracks / 2);

    /* Loop over each thread within this azimuthal angle halfspace */
    #pragma omp parallel for private(curr_track, azim_index, num_segments, \
      curr_segment, segments, track_flux, tid) schedule(guided)
    for (int track_id=min_track; track_id < max_track; track_id++) {

      tid = omp_get_thread_num();

      /* Initialize local pointers to important data structures */
      curr_track = _tracks[track_id];
      azim_index = curr_track->getAzimAngleIndex();
      num_segments = curr_track->getNumSegments();
      segments = curr_track->getSegments();
      track_flux = &_boundary_flux(track_id,0,0,0);

      /* Loop over each Track segment in forward direction */
      for (int s=0; s < num_segments; s++) {
        curr_segment = &segments[s];
        scalarFluxTally(curr_segment, azim_index, track_flux,
                        &_thread_fsr_flux(tid),true);
      }

      /* Transfer boundary angular flux to outgoing Track */
      transferBoundaryFlux(track_id, azim_index, true, track_flux);

      /* Loop over each Track segment in reverse direction */
      track_flux += _polar_times_groups;

      for (int s=num_segments-1; s > -1; s--) {
        curr_segment = &segments[s];
        scalarFluxTally(curr_segment, azim_index, track_flux,
                        &_thread_fsr_flux(tid),false);
      }

      /* Transfer boundary angular flux to outgoing Track */
      transferBoundaryFlux(track_id, azim_index, false, track_flux);
    }
  }

  return;
}