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

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

Предпосылки

Нет никаких предпосылок для этого примера.

О функции run_atoms

Функция 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

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

MEX-функция моделирует 10 000 атомов приблизительно на 1 000 шагов итерации, учитывая пустой список атомов. Возвращаемое значение является состоянием всех атомов после того, как симуляция будет завершена.

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 = 1x10000 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 = 1x10000 struct array with fields:
    x
    y
    vx
    vy

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

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

cfg = coder.config('lib');

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

cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';

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

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

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

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

dir codegen/lib/run_atoms
.                       rt_nonfinite.c          run_atoms_emxutil.h     
..                      rt_nonfinite.h          run_atoms_emxutil.o     
buildInfo.mat           rt_nonfinite.o          run_atoms_initialize.c  
codeInfo.mat            rtw_proj.tmw            run_atoms_initialize.h  
codedescriptor.dmr      rtwtypes.h              run_atoms_initialize.o  
examples                run_atoms.a             run_atoms_ref.rsp       
interface               run_atoms.c             run_atoms_rtw.mk        
rtGetInf.c              run_atoms.h             run_atoms_terminate.c   
rtGetInf.h              run_atoms.o             run_atoms_terminate.h   
rtGetInf.o              run_atoms_emxAPI.c      run_atoms_terminate.o   
rtGetNaN.c              run_atoms_emxAPI.h      run_atoms_types.h       
rtGetNaN.h              run_atoms_emxAPI.o      
rtGetNaN.o              run_atoms_emxutil.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), команда codegen автоматически генерирует код С из кода MATLAB, затем вызывает компилятор C, чтобы связать этот сгенерированный код пользовательским кодом С (run_atoms_main.c).

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

Запустите исполняемый файл

После того, как симуляция завершена, это производит файл 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);