Использование динамического выделения памяти для симуляции атомов

Этот пример показывает, как сгенерировать код для алгоритма MATLAB ®, который запускает симуляцию прыгающих «атомов» и возвращает результат после ряда итераций. Нет верхних границ количества атомов, которые принимает алгоритм, поэтому этот пример использует преимущества динамического выделения памяти.

Необходимые условия

Для этого примера нет необходимых условий.

О run_atoms Функция

The run_atoms.m функция запускает симуляцию прыгающих атомов (также применяя гравитацию и потери энергии).

help run_atoms
  atoms = run_atoms(atoms,n)
  atoms = run_atoms(atoms,n,iter)
  Where 'atoms' the initial and final state of atoms (can be empty)
        'n' is the number of atoms to simulate.
        'iter' is the number of iterations for the simulation
           (if omitted it is defaulted to 3000 iterations.)

Настройка опций генерации кода

Создайте объект строения генерации кода

cfg = coder.config;
% Enable dynamic memory allocation for variable size matrices.
cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';

Настройка входных параметров примера

Создайте структуру шаблона 'Atom', чтобы предоставить компилятору необходимую информацию о типах входных параметров. Атом является структурой с четырьмя полями (x, y, vx, vy), задающими положение и скорость в Декартовых координатах.

atom = struct('x', 0, 'y', 0, 'vx', 0, 'vy', 0);

Сгенерируйте MEX-функцию для проверки

Используйте команду codegen со следующими аргументами:

-args {coder.typeof(atom, [1 Inf]),0,0} указывает, что первый аргумент является вектором-строкой атомов, где количество столбцов потенциально бесконечно. Второй и третий аргументы являются скалярными двойными значениями.

-config cfg включает динамическое выделение памяти, заданное переменной рабочей области cfg

codegen run_atoms -args {coder.typeof(atom, [1 Inf]),0,0} -config cfg -o run_atoms_mex
Code generation successful.

Запуск MEX-функции

MEX-функция моделирует 10000 атомов приблизительно за 1000 шагов итерации, учитывая пустой список атомов. Значение возврата является состоянием всех атомов после завершения симуляции.

atoms = repmat(atom,1,0); 
atoms = run_atoms_mex(atoms,10000,1000)
Iteration: 50
Iteration: 100
Iteration: 150
Iteration: 200
Iteration: 250
Iteration: 300
Iteration: 350
Iteration: 400
Iteration: 450
Iteration: 500
Iteration: 550
Iteration: 600
Iteration: 650
Iteration: 700
Iteration: 750
Iteration: 800
Iteration: 850
Iteration: 900
Iteration: 950
Iteration: 1000
Completed iterations: 1000
atoms=1×10000 struct array with fields:
    x
    y
    vx
    vy

Еще раз запустите MEX-функцию

Продолжите симуляцию с помощью еще 500 шагов итерации

atoms = run_atoms_mex(atoms,10000,500)
Iteration: 50
Iteration: 100
Iteration: 150
Iteration: 200
Iteration: 250
Iteration: 300
Iteration: 350
Iteration: 400
Iteration: 450
Iteration: 500
Completed iterations: 500
atoms=1×10000 struct array with fields:
    x
    y
    vx
    vy

Сгенерируйте автономную библиотеку кода С

Чтобы сгенерировать библиотеку C, создайте стандартный объект строения для библиотек:

cfg = coder.config('lib');

Включите динамическое выделение памяти

cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';

В MATLAB тип данных по умолчанию double. Однако в коде С обычно используются целые числа, поэтому передайте int32 целочисленные значения примера для представления количества атомов и итераций.

codegen run_atoms -args {coder.typeof(atom, [1 Inf]),int32(0),int32(0)} -config cfg
Code generation successful.

Смотрите сгенерированный код

При создании библиотеки код генерируется в папке codegen/lib/run_atoms/. Код в этой папке является автономным. Для взаимодействия с скомпилированным кодом С вам нужны только сгенерированные заголовочные файлы и файл библиотеки.

dir codegen/lib/run_atoms
.                       rtGetNaN.h              run_atoms_emxAPI.h      
..                      rtGetNaN.o              run_atoms_emxAPI.o      
.gitignore              rt_nonfinite.c          run_atoms_emxutil.c     
_clang-format           rt_nonfinite.h          run_atoms_emxutil.h     
buildInfo.mat           rt_nonfinite.o          run_atoms_emxutil.o     
codeInfo.mat            rtw_proj.tmw            run_atoms_initialize.c  
codedescriptor.dmr      rtwtypes.h              run_atoms_initialize.h  
compileInfo.mat         run_atoms.a             run_atoms_initialize.o  
defines.txt             run_atoms.c             run_atoms_rtw.mk        
examples                run_atoms.h             run_atoms_terminate.c   
interface               run_atoms.o             run_atoms_terminate.h   
rtGetInf.c              run_atoms_data.c        run_atoms_terminate.o   
rtGetInf.h              run_atoms_data.h        run_atoms_types.h       
rtGetInf.o              run_atoms_data.o        
rtGetNaN.c              run_atoms_emxAPI.c      

Запись основной функции на C

Как правило, основной функцией является зависящий от платформы код, который выполняет визуализацию или некоторую другую обработку. В этом примере чистая функция ANSI-C создает файл run_atoms_state.m который (при запуске) содержит окончательное состояние симуляции атома.

type run_atoms_main.c
/* Include standard C libraries */
#include <stdio.h>

/* The interface to the main function we compiled. */
#include "codegen/exe/run_atoms/run_atoms.h"

/* The interface to EMX data structures. */
#include "codegen/exe/run_atoms/run_atoms_emxAPI.h"

int main(int argc, char **argv)
{
    FILE *fid;
    int i;
    emxArray_Atom *atoms;
 
    /* Main arguments unused */
    (void) argc;
    (void) argv;
    
    /* Initially create an empty row vector of atoms (1 row, 0 columns) */
    atoms = emxCreate_Atom(1, 0);
    
    /* Call the function to simulate 10000 atoms in 1000 iteration steps */
    run_atoms(atoms, 10000, 1000);
    
    /* Call the function again to do another 500 iteration steps */
    run_atoms(atoms, 10000, 500);
    
    /* Print the result to a file */
    fid = fopen("atoms_state.txt", "w");
    for (i = 0; i < atoms->size[1]; i++) {
        fprintf(fid, "%f %f %f %f\n",
            atoms->data[i].x, atoms->data[i].y, atoms->data[i].vx, atoms->data[i].vy);
    }
    
    /* Close the file */
    fclose(fid);
    
    /* Free memory */
    emxDestroyArray_Atom(atoms);
    return(0);
}

Создайте объект Строения для исполняемых файлов

cfg = coder.config('exe');
cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';

Сгенерируйте независимый исполняемый файл

Вы должны передать функцию (run_atoms.m) а также пользовательский код С (run_atoms_main.c) The codegen команда автоматически генерирует код C из кода MATLAB, затем вызывает компилятор C, чтобы связать этот сгенерированный код с пользовательским кодом C (run_atoms_main.c).

codegen run_atoms run_atoms_main.c -args {coder.typeof(atom, [1 Inf]),int32(0),int32(0)} -config cfg
Code generation successful.

Запуск исполняемого файла

После завершения симуляции это создает файл atoms_state.txt. Файл TXT 10000x4 матрица, где каждая строка - положение и скорость атома (x, y, vx, vy) представление текущего состояния целой системы.

system(['.' filesep 'run_atoms']);

Получение состояния

Выполнение исполняемого файла, созданного atoms_state.txt. Теперь воссоздайте массив структуры из сохраненной матрицы:

load atoms_state.txt -ascii
clear atoms
for i = 1:size(atoms_state,1)
    atoms(1,i).x  = atoms_state(i,1);
    atoms(1,i).y  = atoms_state(i,2);
    atoms(1,i).vx = atoms_state(i,3);
    atoms(1,i).vy = atoms_state(i,4);
end

Визуализация состояния

Функции run_atoms_mex с нулем итераций только для визуализации.

run_atoms_mex(atoms, 10000, 0);

Figure MATLAB Coder Atoms contains an axes. The axes contains an object of type image.