Program Listing for File NuMagSANSlib_RotationData.h#

↰ Return to documentation for file (src/InputData/RotData/NuMagSANSlib_RotationData.h)

// File         : NuMagSANSlib_RotationData.h
// Author       : Michael Philipp ADAMS, M.Sc.
// Company      : University of Luxembourg
// Department   : Department of Physics and Materials Sciences
// Group        : NanoMagnetism Group
// Group Leader : Prof. Andreas Michels
// Version      : 25 May 2026
// OS           : Linux Ubuntu
// Language     : CUDA C++

#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <math.h>
#include <string>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <stdexcept>
#include <math.h>
#include <chrono>
#include <dirent.h>
#include <unistd.h>

using namespace std;

// The RotationData structure allows rotations of individual objects in an
// ensemble. These rotations are distinct from the global two-angle rotation in
// the input configuration.

struct RotationData {

    // The three angles follow InputData::RotDataConvention. The default is the
    // historical Z-Y-Z convention
    // R(alpha, beta, gamma) = R_z(alpha) * R_y(beta) * R_z(gamma).
    // Rotations are active and act on column vectors as M = R * m and X = R * x.
    // Angles are expressed in radians.
    float* alpha;
    float* beta;
    float* gamma;

    // The RotMat variable compacts the three rotation angles to a direct
    // rotation matrix variable with the indice convention:
    // R = [R0, R3, R6;
    //     R1, R4, R7;
    //     R2, R5, R8]
    float* RotMat;

    unsigned long int* K; // number of objects
};

void allocate_RotationDataRAM(RotationData* RotData, RotDataProperties* RotDataProp, InputFileData* InputData) {

    unsigned long int K = RotDataProp->Number_Of_Elements;

    RotData->alpha = (float*)malloc(K * sizeof(float));
    RotData->beta = (float*)malloc(K * sizeof(float));
    RotData->gamma = (float*)malloc(K * sizeof(float));
    RotData->K = (unsigned long int*)malloc(sizeof(unsigned long int));
    RotData->RotMat = (float*)malloc(9 * K * sizeof(float));

    if (!RotData->alpha || !RotData->beta || !RotData->gamma || !RotData->K || !RotData->RotMat) {
        perror("Memory allocation failed");
        exit(EXIT_FAILURE);
    }
}

void DefaultSet_RotationDataRAM(RotationData* RotData, RotDataProperties* RotDataProp, InputFileData* InputData) {

    unsigned long int K = RotDataProp->Number_Of_Elements;

    *RotData->K = K;

    for (unsigned long int i = 0; i < K; i++) {
        // initialize angles with zeros
        RotData->alpha[i] = 0.0;
        RotData->beta[i] = 0.0;
        RotData->gamma[i] = 0.0;

        // initialize rotation matrices as identity matrices
        // for one set of angles alpha, beta, gamma at index i
        // the rotation matrix is stored as a single column array
        // with 9 entries following the index logic
        // R = [R_{0,i}, R_{3,i}, R_{6,i},
        //      R_{1,i}, R_{4,i}, R_{7,i},
        //      R_{2,i}, R_{5,i}, R_{8,i}]
        //   = [1, 0, 0,
        //      0, 1, 0,
        //      0, 0, 1]
        RotData->RotMat[9 * i + 0] = 1;
        RotData->RotMat[9 * i + 1] = 0;
        RotData->RotMat[9 * i + 2] = 0;

        RotData->RotMat[9 * i + 3] = 0;
        RotData->RotMat[9 * i + 4] = 1;
        RotData->RotMat[9 * i + 5] = 0;

        RotData->RotMat[9 * i + 6] = 0;
        RotData->RotMat[9 * i + 7] = 0;
        RotData->RotMat[9 * i + 8] = 1;
    }
}

void allocate_RotationDataGPU(RotationData* RotData, RotationData* RotData_gpu) {

    unsigned long int K = *RotData->K;

    cudaMalloc(&RotData_gpu->alpha, K * sizeof(float));
    cudaMalloc(&RotData_gpu->beta, K * sizeof(float));
    cudaMalloc(&RotData_gpu->gamma, K * sizeof(float));
    cudaMalloc(&RotData_gpu->K, sizeof(unsigned long int));
    cudaMalloc(&RotData_gpu->RotMat, 9 * K * sizeof(float));

    cudaMemcpy(RotData_gpu->K, RotData->K, sizeof(unsigned long int), cudaMemcpyHostToDevice);
    cudaMemcpy(RotData_gpu->RotMat, RotData->RotMat, 9 * K * sizeof(float), cudaMemcpyHostToDevice);

    LogSystem::write("");
    LogSystem::write("copy data from RAM to GPU...");
    cudaMemcpy(RotData_gpu->alpha, RotData->alpha, K * sizeof(float), cudaMemcpyHostToDevice);
    LogSystem::write("   angle_1 done...");
    cudaMemcpy(RotData_gpu->beta, RotData->beta, K * sizeof(float), cudaMemcpyHostToDevice);
    LogSystem::write("   angle_2 done...");
    cudaMemcpy(RotData_gpu->gamma, RotData->gamma, K * sizeof(float), cudaMemcpyHostToDevice);
    LogSystem::write("   angle_3 done...");
    LogSystem::write("");
    LogSystem::write("data transfer finished...");
    LogSystem::write("");

    cudaMalloc(&RotData_gpu, sizeof(RotationData));
    cudaMemcpy(RotData_gpu, RotData, sizeof(RotationData), cudaMemcpyHostToDevice);
}

void copy_RotationDataRAM2GPU(RotationData* RotData, RotationData* RotData_gpu) {

    unsigned long int K = *RotData->K;

    cudaMemcpy(RotData_gpu->K, RotData->K, sizeof(unsigned long int), cudaMemcpyHostToDevice);
    cudaMemcpy(RotData_gpu->RotMat, RotData->RotMat, 9 * K * sizeof(float), cudaMemcpyHostToDevice);

    LogSystem::write("");
    LogSystem::write("copy data from RAM to GPU...");
    cudaMemcpy(RotData_gpu->alpha, RotData->alpha, K * sizeof(float), cudaMemcpyHostToDevice);
    LogSystem::write("   angle_1 done...");
    cudaMemcpy(RotData_gpu->beta, RotData->beta, K * sizeof(float), cudaMemcpyHostToDevice);
    LogSystem::write("   angle_2 done...");
    cudaMemcpy(RotData_gpu->gamma, RotData->gamma, K * sizeof(float), cudaMemcpyHostToDevice);
    LogSystem::write("   angle_3 done...");
    LogSystem::write("");
    LogSystem::write("data transfer finished...");
    LogSystem::write("");
}

void RotMat_select(unsigned long int idx, float* RotMat, float* RotMat_idx) {

    // this function extracts a single rotation matrix from the large
    // rotation matrix vector at given index idx

    RotMat_idx[0] = RotMat[9 * idx + 0];
    RotMat_idx[1] = RotMat[9 * idx + 1];
    RotMat_idx[2] = RotMat[9 * idx + 2];
    RotMat_idx[3] = RotMat[9 * idx + 3];
    RotMat_idx[4] = RotMat[9 * idx + 4];
    RotMat_idx[5] = RotMat[9 * idx + 5];
    RotMat_idx[6] = RotMat[9 * idx + 6];
    RotMat_idx[7] = RotMat[9 * idx + 7];
    RotMat_idx[8] = RotMat[9 * idx + 8];
}

void RotMat_store(unsigned long int idx, float* RotMat, float* RotMat_idx) {

    // this function stores a single rotation matrix to the large
    // rotation matrix vector at given index idx

    RotMat[9 * idx + 0] = RotMat_idx[0];
    RotMat[9 * idx + 1] = RotMat_idx[1];
    RotMat[9 * idx + 2] = RotMat_idx[2];
    RotMat[9 * idx + 3] = RotMat_idx[3];
    RotMat[9 * idx + 4] = RotMat_idx[4];
    RotMat[9 * idx + 5] = RotMat_idx[5];
    RotMat[9 * idx + 6] = RotMat_idx[6];
    RotMat[9 * idx + 7] = RotMat_idx[7];
    RotMat[9 * idx + 8] = RotMat_idx[8];
}

void read_RotationData(RotationData* RotData, RotDataProperties* RotDataProp, InputFileData* InputData) {

    LogSystem::write("");
    LogSystem::write("read RotationData...");

    unsigned long int K = *RotData->K;

    string filename;
    unsigned long int n = 0;
    float angle_1_buf, angle_2_buf, angle_3_buf;
    ifstream fin;

    filename = RotDataProp->GlobalFilePath;
    LogSystem::write(filename);

    fin.open(filename);
    n = 0;
    // read in the data
    while (fin >> angle_1_buf >> angle_2_buf >> angle_3_buf) {
        RotData->alpha[n] = angle_1_buf;
        RotData->beta[n] = angle_2_buf;
        RotData->gamma[n] = angle_3_buf;
        n += 1;
    }

    float RotMat_buf[9];
    for (unsigned long int k = 0; k < K; k++) {

        RotMat_select(k, RotData->RotMat, RotMat_buf);

        Multiply_RotmatEuler_3x3(RotData->alpha[k], RotData->beta[k], RotData->gamma[k], InputData->RotDataConvention,
                                 RotMat_buf);

        RotMat_store(k, RotData->RotMat, RotMat_buf);
    }

    fin.close();
    LogSystem::write("read (angle_1, angle_2, angle_3) RotationData finished...");
}

void init_RotationData(RotationData* RotData, RotationData* RotData_gpu, RotDataProperties* RotDataProp,
                       InputFileData* InputData) {

    allocate_RotationDataRAM(RotData, RotDataProp, InputData);
    DefaultSet_RotationDataRAM(RotData, RotDataProp, InputData);
    read_RotationData(RotData, RotDataProp, InputData);
    allocate_RotationDataGPU(RotData, RotData_gpu);
}

void init_RotationDataMemory(RotationData* RotData, RotationData* RotData_gpu, RotDataProperties* RotDataProp,
                             InputFileData* InputData) {

    allocate_RotationDataRAM(RotData, RotDataProp, InputData);
    DefaultSet_RotationDataRAM(RotData, RotDataProp, InputData);
    allocate_RotationDataGPU(RotData, RotData_gpu);
}

void new_read_RotationData(RotationData* RotData, RotationData* RotData_gpu, RotDataProperties* RotDataProp,
                           InputFileData* InputData) {

    DefaultSet_RotationDataRAM(RotData, RotDataProp, InputData);
    read_RotationData(RotData, RotDataProp, InputData);
    copy_RotationDataRAM2GPU(RotData, RotData_gpu);
}

void free_RotationData(RotationData* RotData, RotationData* RotData_gpu) {

    LogSystem::write("free RotationData...");

    free(RotData->alpha);
    free(RotData->beta);
    free(RotData->gamma);
    free(RotData->K);
    free(RotData->RotMat);

    cudaDeviceSynchronize();
    cudaFree(RotData_gpu->alpha);

    cudaDeviceSynchronize();
    cudaFree(RotData_gpu->beta);

    cudaDeviceSynchronize();
    cudaFree(RotData_gpu->gamma);

    cudaDeviceSynchronize();
    cudaFree(RotData_gpu->K);

    cudaDeviceSynchronize();
    cudaFree(RotData_gpu->RotMat);

    cudaDeviceSynchronize();

    LogSystem::write("free RotationData finished.");
}