一位鹿人 2024-11-03 15:02 采纳率: 76%
浏览 10
已结题

MPI读入tif文件并将文件路径分配给各进程时遇到问题

在dataset文件夹中,有36个tif文件,命名为tile_01.tif到tile_36.tif,都是包含六个波段数据的卫星图像,来源于Kaggle Sentinel-2野火数据集。我想使用MPI读入这些文件,将这些文件分配给各个进程,读取每个文件第一个波段并计算其均值,而后使用MPI_Reduce再对这些均值取平均。但是在分配文件给进程时,我发现文件路径没有被正确地传输。这种情况应该怎样处理?
我的代码如下:

#include <iostream>
#include <gdal.h>
#include <gdal_priv.h>
#include <cpl_conv.h>
#include <mpi.h>
#include <vector>
#include <filesystem>
#include <chrono>
#include <cstring>

double calculate_band_mean(const std::string& filename) {
    GDALDatasetH dataset = GDALOpen(filename.c_str(), GA_ReadOnly);
    if (dataset == nullptr) {
        std::cerr << "Failed to open file: " << filename << std::endl;
        return 0.0; // 返回 0 表示读取失败
    }

    GDALRasterBandH band = GDALGetRasterBand(dataset, 1);
    int x_size = GDALGetRasterBandXSize(band);
    int y_size = GDALGetRasterBandYSize(band);

    std::vector<float> data(x_size * y_size);


    double sum = 0;
    int count = 0;

    for (float value : data) {
        if (value != 0 && value <= 1 && value >= -1) {
            sum += value;
            count++;
        }
    }

    GDALClose(dataset);
    return (count > 0) ? (sum / count) : 0.0;
}

int main(int argc, char **argv) {
    MPI_Init(&argc, &argv);
    int rank, size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    GDALAllRegister();
    
    auto start_time = std::chrono::high_resolution_clock::now();

    // 文件路径
    std::string input_directory = "dataset"; // 数据集路径为 "dataset"
    std::vector<std::string> image_files;

    // 仅在 rank 0 时获取文件列表
    if (rank == 0) {
        for (const auto &entry : std::filesystem::directory_iterator(input_directory)) {
            if (entry.path().extension() == ".tif") {
                image_files.push_back(entry.path().string());
            }
        }
    }

    // 广播文件数量
    int image_count = image_files.size();
    MPI_Bcast(&image_count, 1, MPI_INT, 0, MPI_COMM_WORLD);

    // 计算每个进程要处理的文件数量
    std::vector<int> sendcounts(size, 0);
    std::vector<int> displs(size, 0);

    int files_per_process = image_count / size;
    int remaining_files = image_count % size;

    for (int i = 0; i < size; ++i) {
        sendcounts[i] = files_per_process + (i < remaining_files ? 1 : 0);
        displs[i] = (i > 0) ? displs[i - 1] + sendcounts[i - 1] : 0;
    }

    // 创建用于发送的字符数组
    std::vector<char> all_image_files;
    if (rank == 0) {
        int total_length = 0;
        for (const auto& filename : image_files) {
            total_length += filename.length() + 1; // +1 for null terminator
        }
        all_image_files.resize(total_length);
        char* ptr = all_image_files.data();
        for (const auto& filename : image_files) {
            strcpy(ptr, filename.c_str());
            ptr += filename.length() + 1; // Move pointer to next string position
        }
    }

    // 使用 MPI_Scatterv 分发文件路径
    std::vector<char> local_image_files(sendcounts[rank] * 256); // 假设每个路径最长256个字符
    MPI_Scatterv(all_image_files.data(), sendcounts.data(), displs.data(), MPI_CHAR, 
                  local_image_files.data(), sendcounts[rank] * 256, MPI_CHAR, 0, MPI_COMM_WORLD);

    // 将接收到的字符数组转换为字符串
    std::vector<std::string> local_files;
    for (int i = 0; i < sendcounts[rank]; ++i) {
        local_files.push_back(std::string(local_image_files.data() + i * 256));
    }

    // 处理接收到的文件
    double local_mean = 0.0;
    for (const auto& file : local_files) {
        local_mean += calculate_band_mean(file);
    }

    // 使用 MPI_Reduce 收集均值
    double global_mean = 0.0;
    MPI_Reduce(&local_mean, &global_mean, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

    // 在 rank 0 时计算平均值
    if (rank == 0) {
        global_mean /= image_count; // 计算整体平均值
        std::cout << "Mean of the first band across all images: " << global_mean << std::endl;
    }

    auto end_time = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> duration = end_time - start_time;
    if (rank == 0) {
        std::cout << "Total execution time: " << duration.count() << " seconds" << std::endl;
    }

    MPI_Finalize();
    return 0;
}

编译运行后,终端报错如下图:

img

img

  • 写回答

27条回答 默认 最新

  • 专家-皆知 2024-11-03 15:08
    关注
    获得0.30元问题酬金

    以下回复引自免费微信小程序:皆我百晓生。 如问题解决,还请采纳。如仍有疑问,请回复留言或私信博主,以便获得更精准的帮助。

    以下是一个解决MPI读取TIF文件并分配各个进程路径的问题的基本步骤:

    1. 使用MPIEXEC工具启动一个命令行程序。
    2. 运行这个命令:
      MPIEXEC -N 4 ./PROCESS_MPI_READ.SH DATASET
      
      其中,./PROCESS_MPI_READ.SH 是你的主脚本文件,它将读取TIF文件并将路径分配给每个进程。

    运行结果:

    $ MPIEXEC -N 4 ./PROCESS_MPI_READ.SH DATASET
    

    如果出现问题,可能需要调整命令行参数或尝试其他方法来解决问题。

    如果你在运行过程中遇到了任何错误,可以查看MPIEXEC输出的日志信息以获取更多详细信息。例如,你可以查看MPIEXEC日志中的LOG项,或者检查MPIEXEC的错误消息。

    注意: 在运行上述命令之前,确保你已经正确配置了MPI和KERNELS,以及它们的环境变量。这包括确保MPI_HOME是正确的,以及确保KAGGLE_SUBDIR是正确的。

    评论

报告相同问题?

问题事件

  • 系统已结题 11月11日
  • 创建了问题 11月3日

悬赏问题

  • ¥15 我这个代码哪里有问题 acm 平台上显示错误 90%,我自己运行好像没什么问题
  • ¥50 C#编程中使用printDocument类实现文字排版打印问题
  • ¥15 找会编程的帅哥美女 可以用MATLAB里面的simulink编程,用Keil5编也可以。
  • ¥15 已知隐函数其中一个变量τ的具体值,求另一个变量
  • ¥15 r语言Hurst指数
  • ¥15 Acrn IVSHMEM doorbell问题
  • ¥15 yolov5中的val测试集训练时数量变小问题
  • ¥15 MPLS/VPN实验中MPLS的配置问题
  • ¥15 materialstudio氢键计算问题
  • ¥15 echarts图表制作