@@ -856,12 +856,13 @@ void PGrid::cc_pack_ndot(const int nb, const int nn, double *a, double *b, doubl
856856{
857857 int one = 1 ;
858858 // int ng = 2*(nida[nb]+nidb[nb]);
859- int ng = 2 * (nida[nb] + nidb[nb]);
860- int ng0 = 2 * nida[nb];
859+ int ng = 2 * (nida[nb] + nidb[nb]);
860+ int ng0 = 2 * nida[nb];
861861
862- for (int i = 0 ; i < nn; ++i) {
863- sum[i] = 2.0 * DDOT_PWDFT (ng, &(a[i * ng]), one, b, one);
864- sum[i] -= DDOT_PWDFT (ng0, &(a[i * ng]), one, b, one);
862+ for (size_t i=0 ; i<nn; ++i)
863+ {
864+ sum[i] = 2.0 *DDOT_PWDFT (ng, &(a[i * ng]), one, b, one);
865+ sum[i] -= DDOT_PWDFT (ng0, &(a[i * ng]), one, b, one);
865866 }
866867
867868 parall->Vector_SumAll (1 , nn, sum);
@@ -3879,17 +3880,36 @@ void PGrid::tc_pack_Mul(const int nb, const double *a, double *c) {
38793880 * PGrid:tcc_pack_aMulAdd *
38803881 * *
38813882 ********************************/
3882- void PGrid::tcc_pack_aMulAdd (const int nb, const double alpha, const double *a, const double *b, double *c)
3883+ /* *
3884+ * @brief Performs an interleaved multiply-accumulate: c = c + (alpha * a[i] * b[2i:2i+1])
3885+ *
3886+ * This function scales the components of the interleaved array 'b' by the scalar
3887+ * value 'a[i]' and the global constant 'alpha', adding the result to 'c'.
3888+ *
3889+ * @param nb The index of the band/neighboring block.
3890+ * @param alpha A global scaling factor.
3891+ * @param a Pointer to input real scalars (Size: N).
3892+ * @param b Pointer to interleaved input [Re, Im, Re, Im...] (Size: 2N).
3893+ * @param c Pointer to output array for accumulation (Size: 2N).
3894+ *
3895+ * @note Use of __restrict__ allows the compiler to use SIMD vectorization.
3896+ */
3897+ void PGrid::tcc_pack_aMulAdd (const int nb, const double alpha,
3898+ const double *__restrict__ a,
3899+ const double *__restrict__ b,
3900+ double *__restrict__ c)
38833901{
3884- int i, ii;
3885- int ng = nida[nb] + nidb[nb];
3902+ const size_t ng = nida[nb] + nidb[nb];
38863903
3887- ii=0 ;
3888- for (i=0 ; i<ng; ++i)
3904+ for (size_t i = 0 ; i < ng; ++i)
38893905 {
3890- c[ii] += alpha*b[ii] * a[i];
3891- c[ii+1 ] += alpha*b[ii+1 ]*a[i];
3892- ii += 2 ;
3906+ // Calculate the effective weight once per scalar element
3907+ const double weight = alpha * a[i];
3908+ const size_t idx = 2 * i;
3909+
3910+ // Perform the accumulation
3911+ c[idx] += weight * b[idx];
3912+ c[idx + 1 ] += weight * b[idx + 1 ];
38933913 }
38943914}
38953915
@@ -3898,19 +3918,39 @@ void PGrid::tcc_pack_aMulAdd(const int nb, const double alpha, const double *a,
38983918 * PGrid:tcc_pack_iMul *
38993919 * *
39003920 ********************************/
3901- void PGrid::tcc_pack_iMul (const int nb, const double *a, const double *b,
3902- double *c) {
3903- int i, ii;
3904- int ng = nida[nb] + nidb[nb];
3921+ /* *
3922+ * @brief Performs an interleaved real-to-complex expansion and multiplication.
3923+ *
3924+ * Calculates: i * a[i] * (b_re[i] + i * b_im[i])
3925+ * = (-a[i] * b_im[i]) + i * (a[i] * b_re[i])
3926+ *
3927+ * @param nb The index of the band/neighboring block.
3928+ * @param a Pointer to input real scalars (Size: N).
3929+ * @param b Pointer to interleaved input [Re, Im, Re, Im...] (Size: 2N).
3930+ * @param c Pointer to output expanded components (Size: 2N).
3931+ *
3932+ * @note The arrays 'b' and 'c' must be of size at least 2*(nida[nb]+nidb[nb]).
3933+ */
3934+ void PGrid::tcc_pack_iMul (const int nb, const double *__restrict__ a, const double *__restrict__ b, double *__restrict__ c)
3935+ {
3936+ const size_t ng = nida[nb] + nidb[nb];
39053937
3906- ii = 0 ;
3907- for (i = 0 ; i < ng; ++i) {
3908- c[ii] = -b[ii + 1 ] * a[i];
3909- c[ii + 1 ] = b[ii] * a[i];
3910- ii += 2 ;
3911- }
3938+ // Using __restrict__ (if using GCC/Clang/MSVC) tells the compiler
3939+ // that the pointers do not overlap, enabling much better SIMD optimization.
3940+
3941+ for (size_t i = 0 ; i < ng; ++i)
3942+ {
3943+ const double scalar = a[i];
3944+ const size_t base_idx = 2 * i;
3945+
3946+ // Real part of result: -a * Im(b)
3947+ c[base_idx] = -scalar * b[base_idx + 1 ];
3948+ // Imaginary part of result: a * Re(b)
3949+ c[base_idx + 1 ] = scalar * b[base_idx];
3950+ }
39123951}
39133952
3953+
39143954/* ******************************************
39153955 * *
39163956 * PGrid:tcr_pack_iMul_unpack_fft *
@@ -3956,19 +3996,37 @@ void PGrid::tcr_pack_iMul_unpack_fft(const int nb, const double *a, const double
39563996 * PGrid:tc_pack_iMul *
39573997 * *
39583998 ********************************/
3959- void PGrid::tc_pack_iMul (const int nb, const double *a, double *c)
3999+ /* *
4000+ * @brief Performs an in-place interleaved complex rotation and scaling.
4001+ *
4002+ * Computes: c[2i : 2i+1] = c[2i : 2i+1] * (i * a[i])
4003+ * Which expands to:
4004+ * c[2i] = -a[i] * Im(c_old)
4005+ * c[2i+1] = a[i] * Re(c_old)
4006+ *
4007+ * @param nb The index of the band/neighboring block.
4008+ * @param a Pointer to input real scalars (Size: N).
4009+ * @param c Pointer to interleaved complex array to be modified in-place (Size: 2N).
4010+ *
4011+ * @note Use of __restrict__ is critical here to allow the compiler to
4012+ * vectorize despite 'a' and 'c' being different pointers.
4013+ */
4014+ void PGrid::tc_pack_iMul (const int nb, const double *__restrict__ a, double *__restrict__ c)
39604015{
3961- double x, y;
3962- int ng = nida[nb] + nidb[nb];
3963- int ii = 0 ;
3964- for (auto i=0 ; i<ng; ++i)
4016+ const size_t ng = nida[nb] + nidb[nb];
4017+
4018+ for (size_t i = 0 ; i < ng; ++i)
39654019 {
3966- x = c[ii];
3967- y = c[ii+1 ];
3968-
3969- c[ii] = -y*a[i];
3970- c[ii+1 ] = x*a[i];
3971- ii += 2 ;
4020+ const size_t idx = 2 * i;
4021+ const double scale = a[i];
4022+
4023+ // We must capture the original values before overwriting c[idx]
4024+ // This is essentially what your x and y did, but more explicit.
4025+ const double re = c[idx];
4026+ const double im = c[idx + 1 ];
4027+
4028+ c[idx] = -scale * im;
4029+ c[idx + 1 ] = scale * re;
39724030 }
39734031}
39744032
@@ -3977,6 +4035,19 @@ void PGrid::tc_pack_iMul(const int nb, const double *a, double *c)
39774035 * PGrid:ttc_pack_MulSum2 *
39784036 * *
39794037 ********************************/
4038+ /* *
4039+ * @brief Performs weighted accumulation into interleaved array: c = c + (b * a[i])
4040+ *
4041+ * For each index i from 0 to ng-1:
4042+ * c[2i] += b[2i] * a[i]
4043+ * c[2i+1] += b[2i+1] * a[i]
4044+ *
4045+ * @param nb The index of the band/neighboring block.
4046+ * @param a Pointer to input real scalars (Size: N).
4047+ * @param b Pointer to interleaved input array (Size: 2N).
4048+ * @param c Pointer to output array for accumulation (Size: Must be at least 2N).
4049+ *
4050+ */
39804051void PGrid::tcc_pack_MulSum2 (const int nb, const double *a, const double *b, double *c)
39814052{
39824053 int ng = nida[nb] + nidb[nb];
@@ -4035,27 +4106,65 @@ double PGrid::ttt_pack_MulDot(const int nb, const double *a, const double *b, co
40354106 * PGrid:cc_pack_Sum2 *
40364107 * *
40374108 ********************************/
4038- void PGrid::cc_pack_Sum2 (const int nb, const double *a, double *b)
4109+ /* *
4110+ * @brief Performs vector addition in-place: b = b + a.
4111+ *
4112+ * This function adds elements of array 'a' to array 'b'.
4113+ *
4114+ * @param nb The index of the band/neighboring block.
4115+ * @param a Pointer to input array (Size: ng).
4116+ * @param b Pointer to output array (Size: ng) - modified in-place.
4117+ *
4118+ * @note Using __restrict__ is critical here to enable SIMD vectorization.
4119+ */
4120+ void PGrid::cc_pack_Sum2 (const int nb, const double *__restrict__ a, double *__restrict__ b)
40394121{
4040- int ng = 2 *(nida[nb] + nidb[nb]);
4122+ // Use size_t to prevent overflow on large datasets
4123+ const size_t ng = 2 * (static_cast <size_t >(nida[nb]) + static_cast <size_t >(nidb[nb]));
40414124
4042- for (auto i=0 ; i<ng; ++i)
4125+ // The compiler can now use AVX/SSE instructions to add 4-8 doubles at a time
4126+ for (size_t i = 0 ; i < ng; ++i)
4127+ {
40434128 b[i] += a[i];
4129+ }
40444130}
40454131
4132+
40464133/* *******************************
40474134 * *
40484135 * PGrid:cccc_pack_Sum *
40494136 * *
40504137 ********************************/
4051- void PGrid::cccc_pack_Sum (const int nb, const double *a, const double *b, const double *c, double *d)
4138+ /* *
4139+ * @brief Performs element-wise sum of three arrays into a fourth: d = a + b + c.
4140+ *
4141+ * This function is a high-throughput streaming operation.
4142+ *
4143+ * @param nb The index of the band/neighboring block.
4144+ * @param a Pointer to input array 1 (Size: ng).
4145+ * @param b Pointer to input array 2 (Size: ng).
4146+ * @param c Pointer to input array 3 (Size: ng).
4147+ * @param d Pointer to output array (Size: ng) - modified in-place.
4148+ *
4149+ * @note Using __restrict__ is critical here to allow the compiler to use SIMD.
4150+ */
4151+ void PGrid::cccc_pack_Sum (const int nb,
4152+ const double *__restrict__ a,
4153+ const double *__restrict__ b,
4154+ const double *__restrict__ c,
4155+ double *__restrict__ d)
40524156{
4053- int ng = 2 *(nida[nb] + nidb[nb]);
4157+ // Use size_t to prevent overflow on very large grids
4158+ const size_t ng = 2 * (static_cast <size_t >(nida[nb]) + static_cast <size_t >(nidb[nb]));
40544159
4055- for (auto i=0 ; i<ng; ++i)
4056- d[i] = (a[i] + b[i] + c[i]);
4160+ // The compiler can now use AVX instructions to process multiple elements per cycle
4161+ for (size_t i = 0 ; i < ng; ++i)
4162+ {
4163+ d[i] = a[i] + b[i] + c[i];
4164+ }
40574165}
40584166
4167+
40594168/* *******************************
40604169 * *
40614170 * PGrid:c_pack_addzeros *
0 commit comments