AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79103079
Accepted
Varga
Varga
Asked: 2024-10-19 01:19:20 +0800 CST2024-10-19 01:19:20 +0800 CST 2024-10-19 01:19:20 +0800 CST

波浪模拟过程中大规模计算的优化与加速

  • 772

有一个任务:模拟海面上的波浪(3D 情况)。我遇到的问题是,当模拟大片海洋(1 公里 x 1 公里)的波浪时,程序需要很长时间才能执行。事实上它根本没有执行。因为在等待结果的半个小时里,它从未被计算过。

我的代码示例:

clear,clc
%% Data 
x = 0:1:100; % coordinates х [m]
y = 0:1:100; % coordinates y [m]
g = 9.81; % gravitational constant [m/s^2]
speed = 5; % wind velocity [m/s]
w0 = (g / speed); % norm.frequency [Hz]
dw = 0.1; % frequency step [rad/s]
w = 0.8:dw:11.1; % frequency [rad/s] 
dtt = pi / 18; % angular step [rad]
theta = 0:dtt:pi; % direction angles, angles between the wavevector & coordintae axis [rad]

%% P-M spectrum, Frequency-Angular spectrum & Amplitude
Psi = 8.1e-3 .* ((w/w0).^(-5)) .* exp((-0.74) ./ ((w/w0).^(4))); % P-M spectrum [none]
Phi = ((speed)^(5)/g^(3)) * Psi; % self-similar spectrum [s*m^2]
Sw = Phi / 2; % frequency spectrum [s*m^2]

St = cos(theta).^(4); % angular spectrum [none]
Norm = trapz(dtt, St); % norm.coefficient [none]
Swt = Sw .* St'; % frequency-angular spectrum [s*m^2]

eta0 = sqrt((Swt * dw * dtt) ./ Norm); % amplitude [m]

figure(1);
subplot(2,1,1)
plot(w, Psi);
title('$$\Psi$$($$\omega$$) - P-M spectrum', 'Interpreter', 'LaTex');
xlabel('\omega [rad/s]');
ylabel('\Psi [none]');
grid on;
subplot(2,1,2)
plot(w, Swt); 
title('$$S(\omega , \theta)$$($$\omega$$) - frequency-angular spectrum', 'Interpreter', 'LaTex');
xlabel('\omega [rad/s]');
ylabel('S(\omega,\theta) [s*m^2]');
grid on;

%% Setting the initial phase parameter
phase = 2*pi*rand(length(theta),length(w)); %% random initial phase ranging from 0 to 2pi [rad]

%% Surface Waving [Linear, 3D (eta & x,y)] at different harmonics & random phase (at one moment in time), different directions of the wavevector (multiple angles)
t = 0; % time moment [s]
Kabs = (w.^2) / g; % wavevector module [rad/m]
Kx = Kabs .* cos(theta)'; % projection of the wavevector onto the x-axis [rad/m]
Ky = Kabs .* sin(theta)'; % projection of the wavevector onto the y-axis [rad/m]

eta = zeros(length(x),length(y),length(theta),length(w)); % reserving space for calculation results
tic
for i = 1:length(x)
    for j = 1:length(y)
        eta(i,j,:,:) = eta0 .* cos(w * t - Kx .* i - Ky .* j + phase);
    end
end
toc
% sum(sum(eta,4),3) - double sum of eta over all harmonics (frequencies) and wavevector directions (angles theta),
% where '4' и '3' summation indicator for variable frequency and angle
etaW = sum(eta,4);
etaWA = sum(etaW,3);

figure(2)
surf(x,y,etaWA);
title('\eta(x,y) - surface waving');
xlabel('x [m]');
ylabel('y [m]');
zlabel('\eta [m]');
cbar = colorbar;
cbar.Label.String = '\eta [m]';
grid on
shading flat

我能够使用的代码优化方法之一是创建一个“空”的 4D 数组(零的 4D 数组)eta = zeros(length(x),length(y),length(theta),length(w));,在执行循环后,计算结果将填充到该数组中:

eta = zeros(length(x),length(y),length(theta),length(w)); % reserving space for calculation results
tic
for i = 1:length(x)
    for j = 1:length(y)
        eta(i,j,:,:) = eta0 .* cos(w * t - Kx .* i - Ky .* j + phase);
    end
end
toc

然后我按频率和角度变量总结结果:

etaW = sum(eta,4);
etaWA = sum(etaW,3);

这样就提前为结果准备好了地方。这有点帮助。例如,x = 0:1:100; y = 0:1:100;使用此方法对一个区域(100 mx 100 m)的代码执行时间为 0.7 秒(不使用则为 3.9 秒)。对于一个区域x = 0:1:500; y = 0:1:500;(500 mx 500 m),执行时间约为 19 秒(不使用则...我不知道,我没有等待代码执行,但结果发现它很长)。但是,对于一个区域x = 0:1:1000; y = 0:1:1000;(1000 mx 1000 m),我很长时间都没有得到想要的结果(感觉根本得不到)。

在我的情况下,还有其他方法可以实现所需的结果并优化我的代码,以便它可以应对如此规模的数据(同时,无需改变数组中的步骤)?

注意:我的电脑有 16 GB 的 RAM。我的第二台电脑(我最初用来进行计算的那台电脑)在执行程序时完全挂断了,所以我不得不“手动”重启它。所以我猜它的 RAM 更少了。

matlab
  • 1 1 个回答
  • 36 Views

1 个回答

  • Voted
  1. Best Answer
    Cris Luengo
    2024-10-19T22:12:11+08:002024-10-19T22:12:11+08:00

    您需要一个 2D 输出数组,不要计算完整的 4D 数组然后投影它。相反,请在循环中计算投影。

    1000x1000 输出的情况下的中间 4D 数组超过 15 GB,这意味着您的 16 GB 系统无法将其全部保存在内存中(因为 MATLAB 和 OS 也需要一些空间),并且会将部分内容交换到磁盘。

    如果循环按 索引数组,那么eta(:,:,i,j)情况就不会那么糟糕,因为您正在写入连续的内存部分。但是由于您索引了eta(i,j,:,:),因此每次循环迭代都会写入整个 15 GB 内存块中的字节。因此,每次循环迭代都会让您的系统从磁盘读取并将大部分数组写回磁盘。这显然会大大减慢速度,并被称为“抖动”,因为在旋转硬盘的时代,这会产生很大的噪音。

    一般来说,在编写循环时,您应该始终考虑数组元素在内存中的顺序,并尽可能按内存顺序循环访问数组元素。这可以优化系统缓存的使用。在 MATLAB 中,数组的第一维元素在内存中连续存储。因此,您不希望第一维索引成为外循环,也不希望将最后一维的元素作为单个块进行访问。

    在循环内部进行投影,而不是

    eta = zeros(length(x),length(y),length(theta),length(w));
    for i = 1:length(x)
        for j = 1:length(y)
            eta(i,j,:,:) = eta0 .* cos(w * t - Kx .* i - Ky .* j + phase);
        end
    end
    etaW = sum(eta,4);
    etaWA = sum(etaW,3);
    

    写

    etaWA = zeros(length(x),length(y));
    for j = 1:length(y)
        for i = 1:length(x)
            etaWA(i,j) = sum(eta0 .* cos(w * t - Kx .* i - Ky .* j + phase), 'all');
        end
    end
    

    请注意,我不仅sum在循环内部(而不是在循环末尾)添加了所有维度。我还交换了循环顺序,以便内部循环遍历第一个维度。这是在 MATLAB 中进行循环的最有效方法。

    顺便说一句,“为计算结果保留空间”至关重要。这在 MATLAB 中称为预分配,可避免反复扩大数组时产生的大量工作。

    • 1

相关问题

  • 具有复数的 matlab accumarray

  • 当散点图符号在图中半透明时如何使Matlab图例显示不透明的绘图符号

  • 使用具有相同形状的一维卷积,因此它可以与 FFT 一起使用吗?

  • 使用文件范围变量进行单元测试,无需类

  • 在 MATLAB 2022 中使用 ode45 时出现未定义的结果 (NaN)

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve