/** * @brief Computes the contribution to the FSR scalar flux from a segment. * @details This method integrates the angular flux for a Track segment across * energy groups and polar angles, and tallies it into the FSR scalar * flux, and updates the Track's angular flux. * @param curr_segment a pointer to the Track segment of interest * @param azim_index a pointer to the azimuthal angle index for this segment * @param track_flux a pointer to the Track's angular flux * @param fsr_flux a pointer to the temporary FSR flux buffer */ void VectorizedSolver::tallyScalarFlux(segment* curr_segment, int azim_index, FP_PRECISION* track_flux, FP_PRECISION* fsr_flux) { int tid = omp_get_thread_num(); int fsr_id = curr_segment->_region_id; FP_PRECISION* delta_psi = &_delta_psi[tid*_num_groups]; FP_PRECISION* exponentials = &_thread_exponentials[tid*_polar_times_groups]; computeExponentials(curr_segment, exponentials); /* Set the FSR scalar flux buffer to zero */ memset(fsr_flux, 0.0, _num_groups * sizeof(FP_PRECISION)); /* Tally the flux contribution from segment to FSR's scalar flux */ /* Loop over polar angles */ for (int p=0; p < _num_polar; p++) { /* Loop over each energy group vector length */ for (int v=0; v < _num_vector_lengths; v++) { /* Loop over energy groups within this vector */ #pragma simd vectorlength(VEC_LENGTH) for (int e=v*VEC_LENGTH; e < (v+1)*VEC_LENGTH; e++) delta_psi[e] = track_flux(p,e) - _reduced_sources(fsr_id,e); /* Loop over energy groups within this vector */ #pragma simd vectorlength(VEC_LENGTH) for (int e=v*VEC_LENGTH; e < (v+1)*VEC_LENGTH; e++) delta_psi[e] *= exponentials(p,e); /* Loop over energy groups within this vector */ #pragma simd vectorlength(VEC_LENGTH) for (int e=v*VEC_LENGTH; e < (v+1)*VEC_LENGTH; e++) fsr_flux[e] += delta_psi[e] * _polar_weights(azim_index,p); /* Loop over energy groups within this vector */ #pragma simd vectorlength(VEC_LENGTH) for (int e=v*VEC_LENGTH; e < (v+1)*VEC_LENGTH; e++) track_flux(p,e) -= delta_psi[e]; } } /* Atomically increment the FSR scalar flux from the temporary array */ omp_set_lock(&_FSR_locks[fsr_id]); { #ifdef SINGLE vsAdd(_num_groups, &_scalar_flux(fsr_id,0), fsr_flux, &_scalar_flux(fsr_id,0)); #else vdAdd(_num_groups, &_scalar_flux(fsr_id,0), fsr_flux, &_scalar_flux(fsr_id,0)); #endif } omp_unset_lock(&_FSR_locks[fsr_id]); }
/** * @brief Computes the contribution to the FSR scalar flux from a Track segment. * @details This method integrates the angular flux for a Track segment across * energy groups and polar angles, and tallies it into the FSR scalar * flux, and updates the Track's angular flux. * @param curr_segment a pointer to the Track segment of interest * @param azim_index a pointer to the azimuthal angle index for this segment * @param track_flux a pointer to the Track's angular flux * @param fsr_flux a pointer to the temporary FSR flux buffer * @param fwd */ void VectorizedSolver::scalarFluxTally(segment* curr_segment, int azim_index, FP_PRECISION* track_flux, FP_PRECISION* fsr_flux, bool fwd){ int tid = omp_get_thread_num(); int fsr_id = curr_segment->_region_id; FP_PRECISION length = curr_segment->_length; FP_PRECISION* sigma_t = curr_segment->_material->getSigmaT(); /* The change in angular flux along this Track segment in the FSR */ FP_PRECISION delta_psi; FP_PRECISION* exponentials = &_thread_exponentials[tid*_polar_times_groups]; computeExponentials(curr_segment, exponentials); /* Set the FSR scalar flux buffer to zero */ memset(fsr_flux, 0.0, _num_groups * sizeof(FP_PRECISION)); /* Tally the flux contribution from segment to FSR's scalar flux */ /* Loop over polar angles */ for (int p=0; p < _num_polar; p++){ /* Loop over each energy group vector length */ for (int v=0; v < _num_vector_lengths; v++) { /* Loop over energy groups within this vector */ #pragma simd vectorlength(VEC_LENGTH) private(delta_psi) for (int e=v*VEC_LENGTH; e < (v+1)*VEC_LENGTH; e++) { delta_psi = (track_flux(p,e) - _reduced_source(fsr_id,e)) * exponentials(p,e); fsr_flux[e] += delta_psi * _polar_weights(azim_index,p); track_flux(p,e) -= delta_psi; } } } /* Atomically increment the FSR scalar flux from the temporary array */ omp_set_lock(&_FSR_locks[fsr_id]); { #ifdef SINGLE vsAdd(_num_groups, &_scalar_flux(fsr_id,0), fsr_flux, &_scalar_flux(fsr_id,0)); #else vdAdd(_num_groups, &_scalar_flux(fsr_id,0), fsr_flux, &_scalar_flux(fsr_id,0)); #endif } omp_unset_lock(&_FSR_locks[fsr_id]); return; }
/** * @brief Builds a linear interpolation table to compute exponentials for * each segment of each Track for each polar angle. */ void CPUSolver::buildExpInterpTable() { log_printf(INFO, "Building exponential interpolation table..."); FP_PRECISION azim_weight; _polar_weights = new FP_PRECISION[_num_azim*_num_polar]; /* Compute the total azimuthal weight for tracks at each polar angle */ #pragma omp parallel for private(azim_weight) schedule(guided) for (int i=0; i < _num_azim; i++) { azim_weight = _azim_weights[i]; for (int p=0; p < _num_polar; p++) _polar_weights(i,p) = azim_weight*_quad->getMultiple(p)*FOUR_PI; } /* Set size of interpolation table */ int num_array_values = 10 * sqrt(1./(8.*_source_convergence_thresh*1e-2)); _exp_table_spacing = 10. / num_array_values; _exp_table_size = _two_times_num_polar * num_array_values; _exp_table_max_index = _exp_table_size - _two_times_num_polar - 1.; log_printf(DEBUG, "Exponential interpolation table size: %i, max index: %i", _exp_table_size, _exp_table_max_index); /* Allocate array for the table */ _exp_table = new FP_PRECISION[_exp_table_size]; FP_PRECISION expon; FP_PRECISION intercept; FP_PRECISION slope; /* Create exponential linear interpolation table */ for (int i=0; i < num_array_values; i ++){ for (int p=0; p < _num_polar; p++){ expon = exp(- (i * _exp_table_spacing) / _quad->getSinTheta(p)); slope = - expon / _quad->getSinTheta(p); intercept = expon * (1 + (i * _exp_table_spacing)/_quad->getSinTheta(p)); _exp_table[_two_times_num_polar * i + 2 * p] = slope; _exp_table[_two_times_num_polar * i + 2 * p + 1] = intercept; } } /* Compute the reciprocal of the table entry spacing */ _inverse_exp_table_spacing = 1.0 / _exp_table_spacing; return; }
/** * @brief Updates the boundary flux for a Track given boundary conditions. * @details For reflective boundary conditions, the outgoing boundary flux * for the Track is given to the reflecting Track. For vacuum * boundary conditions, the outgoing flux tallied as leakage. * @param track_id the ID number for the Track of interest * @param azim_index a pointer to the azimuthal angle index for this segment * @param direction the Track direction (forward - true, reverse - false) * @param track_flux a pointer to the Track's outgoing angular flux */ void VectorizedSolver::transferBoundaryFlux(int track_id, int azim_index, bool direction, FP_PRECISION* track_flux) { int start; bool bc; FP_PRECISION* track_leakage; int track_out_id; /* Extract boundary conditions for this Track and the pointer to the * outgoing reflective Track, and index into the leakage array */ /* For the "forward" direction */ if (direction) { start = _tracks[track_id]->isReflOut() * _polar_times_groups; track_leakage = &_boundary_leakage(track_id,0); track_out_id = _tracks[track_id]->getTrackOut()->getUid(); bc = _tracks[track_id]->getBCOut(); } /* For the "reverse" direction */ else { start = _tracks[track_id]->isReflIn() * _polar_times_groups; track_leakage = &_boundary_leakage(track_id,_polar_times_groups); track_out_id = _tracks[track_id]->getTrackIn()->getUid(); bc = _tracks[track_id]->getBCIn(); } FP_PRECISION* track_out_flux = &_boundary_flux(track_out_id,0,0,start); /* Loop over polar angles and energy groups */ for (int p=0; p < _num_polar; p++) { /* Loop over each energy group vector length */ for (int v=0; v < _num_vector_lengths; v++) { /* Loop over energy groups within this vector */ #pragma simd vectorlength(VEC_LENGTH) for (int e=v*VEC_LENGTH; e < (v+1)*VEC_LENGTH; e++) { track_out_flux(p,e) = track_flux(p,e) * bc; track_leakage(p,e) = track_flux(p,e) * _polar_weights(azim_index,p) * (!bc); } } } }
/** * @brief Updates the boundary flux for a Track given boundary conditions. * @details For reflective boundary conditions, the outgoing boundary flux * for the Track is given to the reflecting Track. For vacuum * boundary conditions, the outgoing flux tallied as leakage. * @param track_id the ID number for the Track of interest * @param azim_index a pointer to the azimuthal angle index for this segment * @param direction the Track direction (forward - true, reverse - false) * @param track_flux a pointer to the Track's outgoing angular flux */ void CPUSolver::transferBoundaryFlux(int track_id, int azim_index, bool direction, FP_PRECISION* track_flux) { int start; int bc; FP_PRECISION* track_leakage; int track_out_id; /* Extract boundary conditions for this Track and the pointer to the * outgoing reflective Track, and index into the leakage array */ /* For the "forward" direction */ if (direction) { start = _tracks[track_id]->isReflOut() * _polar_times_groups; bc = (int)_tracks[track_id]->getBCOut(); track_leakage = &_boundary_leakage(track_id,0); track_out_id = _tracks[track_id]->getTrackOut()->getUid(); } /* For the "reverse" direction */ else { start = _tracks[track_id]->isReflIn() * _polar_times_groups; bc = (int)_tracks[track_id]->getBCIn(); track_leakage = &_boundary_leakage(track_id,_polar_times_groups); track_out_id = _tracks[track_id]->getTrackIn()->getUid(); } FP_PRECISION* track_out_flux = &_boundary_flux(track_out_id,0,0,start); /* Loop over polar angles and energy groups */ for (int e=0; e < _num_groups; e++) { for (int p=0; p < _num_polar; p++) { track_out_flux(p,e) = track_flux(p,e) * bc; track_leakage(p,e) = track_flux(p,e) * _polar_weights(azim_index,p) * (!bc); } } }
/** * @brief Computes the contribution to the FSR scalar flux from a Track segment. * @details This method integrates the angular flux for a Track segment across * energy groups and polar angles, and tallies it into the FSR * scalar flux, and updates the Track's angular flux. * @param curr_segment a pointer to the Track segment of interest * @param azim_index a pointer to the azimuthal angle index for this segment * @param track_flux a pointer to the Track's angular flux * @param fsr_flux a pointer to the temporary FSR flux buffer * @param fwd */ void CPUSolver::scalarFluxTally(segment* curr_segment, int azim_index, FP_PRECISION* track_flux, FP_PRECISION* fsr_flux, bool fwd){ int tid = omp_get_thread_num(); int fsr_id = curr_segment->_region_id; FP_PRECISION length = curr_segment->_length; FP_PRECISION* sigma_t = curr_segment->_material->getSigmaT(); /* The change in angular flux along this Track segment in the FSR */ FP_PRECISION delta_psi; FP_PRECISION exponential; /* Set the FSR scalar flux buffer to zero */ memset(fsr_flux, 0.0, _num_groups * sizeof(FP_PRECISION)); /* Loop over energy groups */ for (int e=0; e < _num_groups; e++) { /* Loop over polar angles */ for (int p=0; p < _num_polar; p++){ exponential = computeExponential(sigma_t[e], length, p); delta_psi = (track_flux(p,e)-_reduced_sources(fsr_id,e))*exponential; fsr_flux[e] += delta_psi * _polar_weights(azim_index,p); track_flux(p,e) -= delta_psi; } } if (_cmfd != NULL && _cmfd->isFluxUpdateOn()){ if (curr_segment->_cmfd_surface_fwd != -1 && fwd){ int pe = 0; /* Atomically increment the Cmfd Mesh surface current from the * temporary array using mutual exclusion locks */ omp_set_lock(&_cmfd_surface_locks[curr_segment->_cmfd_surface_fwd]); /* Loop over energy groups */ for (int e = 0; e < _num_groups; e++) { /* Loop over polar angles */ for (int p = 0; p < _num_polar; p++){ /* Increment current (polar and azimuthal weighted flux, group) */ _surface_currents(curr_segment->_cmfd_surface_fwd,e) += track_flux(p,e)*_polar_weights(azim_index,p)/2.0; pe++; } } /* Release Cmfd Mesh surface mutual exclusion lock */ omp_unset_lock(&_cmfd_surface_locks[curr_segment->_cmfd_surface_fwd]); } else if (curr_segment->_cmfd_surface_bwd != -1 && !fwd){ int pe = 0; /* Atomically increment the Cmfd Mesh surface current from the * temporary array using mutual exclusion locks */ omp_set_lock(&_cmfd_surface_locks[curr_segment->_cmfd_surface_bwd]); /* Loop over energy groups */ for (int e = 0; e < _num_groups; e++) { /* Loop over polar angles */ for (int p = 0; p < _num_polar; p++){ /* Increment current (polar and azimuthal weighted flux, group) */ _surface_currents(curr_segment->_cmfd_surface_bwd,e) += track_flux(p,e)*_polar_weights(azim_index,p)/2.0; pe++; } } /* Release Cmfd Mesh surface mutual exclusion lock */ omp_unset_lock(&_cmfd_surface_locks[curr_segment->_cmfd_surface_bwd]); } } /* Atomically increment the FSR scalar flux from the temporary array */ omp_set_lock(&_FSR_locks[fsr_id]); { for (int e=0; e < _num_groups; e++) _scalar_flux(fsr_id,e) += fsr_flux[e]; } omp_unset_lock(&_FSR_locks[fsr_id]); return; }
/** * @brief Builds a linear interpolation table to compute exponentials for * each segment of each Track for each polar angle. */ void CPUSolver::buildExpInterpTable() { log_printf(INFO, "Building exponential interpolation table..."); FP_PRECISION azim_weight; if (_polar_weights != NULL) delete [] _polar_weights; _polar_weights = new FP_PRECISION[_num_azim*_num_polar]; /* Compute the total azimuthal weight for tracks at each polar angle */ #pragma omp parallel for private(azim_weight) schedule(guided) for (int i=0; i < _num_azim; i++) { azim_weight = _azim_weights[i]; for (int p=0; p < _num_polar; p++) _polar_weights(i,p) = azim_weight*_quad->getMultiple(p)*FOUR_PI; } /* Find largest optical path length track segment */ FP_PRECISION tau = _track_generator->getMaxOpticalLength(); /* Expand tau slightly to accomodate track segments which have a * length very nearly equal to the maximum value */ tau *= 1.01; /* Set size of interpolation table */ int num_array_values = tau * sqrt(1./(8.*_source_convergence_thresh*1e-2)); _exp_table_spacing = tau / num_array_values; _exp_table_size = _two_times_num_polar * num_array_values; _exp_table_max_index = _exp_table_size - _two_times_num_polar - 1.; log_printf(DEBUG, "Exponential interpolation table size: %i, max index: %i", _exp_table_size, _exp_table_max_index); /* Allocate array for the table */ if (_exp_table != NULL) delete [] _exp_table; _exp_table = new FP_PRECISION[_exp_table_size]; FP_PRECISION expon; FP_PRECISION intercept; FP_PRECISION slope; /* Create exponential linear interpolation table */ for (int i=0; i < num_array_values; i ++){ for (int p=0; p < _num_polar; p++){ expon = exp(- (i * _exp_table_spacing) / _quad->getSinTheta(p)); slope = - expon / _quad->getSinTheta(p); intercept = expon * (1 + (i * _exp_table_spacing)/_quad->getSinTheta(p)); _exp_table[_two_times_num_polar * i + 2 * p] = slope; _exp_table[_two_times_num_polar * i + 2 * p + 1] = intercept; } } /* Compute the reciprocal of the table entry spacing */ _inverse_exp_table_spacing = 1.0 / _exp_table_spacing; return; }