%% Using Dynamic Memory Allocation for an Atoms Simulation
% This example shows how to generate code for a MATLAB® algorithm that runs a simulation of bouncing "atoms" and returns the result after a number of iterations. There are no upper bounds on the number of atoms that the algorithm accepts, so this example takes advantage of dynamic memory allocation.
%% Prerequisites
% There are no prerequisites for this example.
%% About the run_atoms Function
% The run_atoms.m function runs a simulation of bouncing atoms (also applying gravity and energy loss).

help run_atoms

%
%% Set Up Code Generation Options
% Create a code generation configuration object

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

%
%% Set Up Example Inputs
% Create a template structure 'Atom' to provide the compiler with the necessary information about input parameter types. An atom is a structure with four fields (x,y,vx,vy) specifying position and velocity in Cartesian coordinates.

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

%
%% Generate a MEX Function for Testing
% Use the command codegen with the following arguments:
% -args {coder.typeof(atom, [1 Inf]),0,0} indicates that the first argument is a row vector of atoms where the number of columns is potentially infinite. The second and third arguments are scalar double values.
% -config cfg enables dynamic memory allocation, defined by workspace variable cfg

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

%
%% Run the MEX Function
% The MEX function simulates 10000 atoms in approximately 1000 iteration steps given an empty list of atoms. The return value is the state of all the atoms after simulation is complete.

atoms = repmat(atom,1,0); 
atoms = run_atoms_mex(atoms,10000,1000)

%
%% Run the MEX Function Again
% Continue the simulation with another 500 iteration steps

atoms = run_atoms_mex(atoms,10000,500)

%
%% Generate a Standalone C Code Library
% To generate a C library, create a standard configuration object for libraries:

cfg = coder.config('lib');

% Enable dynamic memory allocation

cfg.DynamicMemoryAllocation = 'AllVariableSizeArrays';

% In MATLAB the default data type is double. However, integers are usually used in C code, so pass int32 integer example values to represent the number of atoms and iterations.

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

%
%% Inspect Generated Code
% When creating a library the code is generated in the folder codegen/lib/run_atoms/. The code in this folder is self contained. To interface with the compiled C code you need only the generated header files and the library file.

dir codegen/lib/run_atoms

%
%% Write a C Main Function
% Typically, the main function is platform-dependent code that performs rendering or some other processing. In this example, a pure ANSI-C function produces a file run_atoms_state.m which (when run) contains the final state of the atom simulation.

type run_atoms_main.c

%
%% Create a Configuration Object for Executables

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

%
%% Generate a Standalone Executable
% You must pass the function (run_atoms.m) as well as custom C code (run_atoms_main.c) The codegen command automatically generates C code from the MATLAB code, then calls the C compiler to bundle this generated code with the custom C code (run_atoms_main.c).

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

%
%% Run the Executable
% After simulation is complete, this produces the file atoms_state.txt. The TXT file is a 10000x4 matrix, where each row is the position and velocity of an atom (x, y, vx, vy) representing the current state of the whole system.

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

%
%% Fetch the State
% Running the executable produced atoms_state.txt. Now, recreate the structure array from the saved matrix:

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

%
%% Render the State
% Call run_atoms_mex with zero iterations to render only.

run_atoms_mex(atoms, 10000, 0);

% Copyright 2018 The MathWorks, Inc.