function m = gpt_reactiondiffusiontentacles_20121211( m )
%m = gpt_reactiondiffusiontentacles_20121211( m )
%   Morphogen interaction function.
%   Written at 2012-12-11 10:49:02.
%   GFtbox revision 4418, .

% The user may edit any part of this function between delimiters
% of the form "USER CODE..." and "END OF USER CODE...".  The
% delimiters themselves must not be moved, edited, deleted, or added.

    if isempty(m), return; end

    fprintf( 1, '%s found in %s\n', mfilename(), which(mfilename()) );

    try
        m = local_setproperties( m );
    catch
    end

    realtime = m.globalDynamicProps.currenttime;

%%% USER CODE: INITIALISATION

% In this section you may modify the mesh in any way whatsoever.
    if Steps(m)==0 % First iteration
    end
%%% END OF USER CODE: INITIALISATION

%%% SECTION 1: ACCESSING MORPHOGENS AND TIME.
%%% AUTOMATICALLY GENERATED CODE: DO NOT EDIT.

    if isempty(m), return; end

    setGlobals();
    global gNEW_KA_PAR gNEW_KA_PER gNEW_KB_PAR gNEW_KB_PER
    global gNEW_K_NOR gNEW_POLARISER gNEW_STRAINRET gNEW_ARREST
    dt = m.globalProps.timestep;
    polariser_i = gNEW_POLARISER;
    P = m.morphogens(:,polariser_i);
    [kapar_i,kapar_p,kapar_a,kapar_l] = getMgenLevels( m, 'KAPAR' );
    [kaper_i,kaper_p,kaper_a,kaper_l] = getMgenLevels( m, 'KAPER' );
    [kbpar_i,kbpar_p,kbpar_a,kbpar_l] = getMgenLevels( m, 'KBPAR' );
    [kbper_i,kbper_p,kbper_a,kbper_l] = getMgenLevels( m, 'KBPER' );
    [knor_i,knor_p,knor_a,knor_l] = getMgenLevels( m, 'KNOR' );
    [strainret_i,strainret_p,strainret_a,strainret_l] = getMgenLevels( m, 'STRAINRET' );
    [arrest_i,arrest_p,arrest_a,arrest_l] = getMgenLevels( m, 'ARREST' );
    [a_i,a_p,a_a,a_l] = getMgenLevels( m, 'A' );
    [b_i,b_p,b_a,b_l] = getMgenLevels( m, 'B' );
    [beta_i,beta_p,beta_a,beta_l] = getMgenLevels( m, 'BETA' );
    [id_edge_i,id_edge_p,id_edge_a,id_edge_l] = getMgenLevels( m, 'ID_EDGE' );
    [a_var_i,a_var_p,a_var_a,a_var_l] = getMgenLevels( m, 'A_VAR' );
    [b_var_i,b_var_p,b_var_a,b_var_l] = getMgenLevels( m, 'B_VAR' );
    [beta_var_i,beta_var_p,beta_var_a,beta_var_l] = getMgenLevels( m, 'BETA_VAR' );
    [agrad_i,agrad_p,agrad_a,agrad_l] = getMgenLevels( m, 'AGRAD' );
    [s_leftright_i,s_leftright_p,s_leftright_a,s_leftright_l] = getMgenLevels( m, 'S_LEFTRIGHT' );
    [id_left_i,id_left_p,id_left_a,id_left_l] = getMgenLevels( m, 'ID_LEFT' );
    [id_right_i,id_right_p,id_right_a,id_right_l] = getMgenLevels( m, 'ID_RIGHT' );

% Mesh type: rectangle
%            base: 0
%      randomness: 0.1
%         version: 1
%           xdivs: 30
%          xwidth: 30
%           ydivs: 30
%          ywidth: 30

%            Morphogen    Diffusion   Decay   Dilution   Mutant
%            --------------------------------------------------
%                KAPAR         ----    ----       ----     ----
%                KAPER         ----    ----       ----     ----
%                KBPAR         ----    ----       ----     ----
%                KBPER         ----    ----       ----     ----
%                 KNOR         ----    ----       ----     ----
%            POLARISER         ----    ----       ----     ----
%            STRAINRET         ----    ----       ----     ----
%               ARREST         ----    ----       ----     ----
%                    A        0.391    ----       ----     ----
%                    B       0.0977    ----       ----     ----
%                 BETA         ----    ----       ----     ----
%              ID_EDGE         ----    ----       ----     ----
%                A_VAR         ----    ----       ----     ----
%                B_VAR         ----    ----       ----     ----
%             BETA_VAR         ----    ----       ----     ----
%                AGRAD         ----    ----       ----     ----
%          S_LEFTRIGHT       0.0977    ----       ----     ----
%              ID_LEFT         ----    ----       ----     ----
%             ID_RIGHT         ----    ----       ----     ----


%%% USER CODE: MORPHOGEN INTERACTIONS

% In this section you may modify the mesh in any way that does not
% alter the set of nodes.

    % When USE_DIFFUSION is true, GFtbox's own diffusion calculation is
    % used.  When false, the weighted-average-neighbourhood approximation
    % is performed in the interaction function, and no GFtbox diffusion is
    % performed.
    USE_DIFFUSION = true;
    
    if Steps(m)==0  % Initialisation code.
        [xnum,xmin,xstep,xsz,xclumpindex] = clumplinear( m.nodes(:,1) );
        [ynum,ymin,ystep,ysz,yclumpindex] = clumplinear( m.nodes(:,2) );
        
        % These parameters are from AIH's reaction-diffusion code.
        m.userdata = setFromStruct( m.userdata, ...
            struct( 'Da', 0.25, ... % Diffusion constant of a.
                    'Db', 0.0625, ... % Diffusion constant of b.
                    'speed', 0.03125, ... % Constant
                    'BC', 4, ... % Boundary condition: edge cells are held to this value.
                    'MinC', 0, ... % Values of a and b are forced to be at least this value.
                    'MaxC', 10000, ... % Values of a and b are forced to be at most this value.
                    'N', xnum*ynum, ... % Number of vertexes each way.
                    'dt', dt, ... % Time step
                    'mean_beta', 12, ... % Mean of a fixed distribution.
                    'noise_beta', 0.1, ... % Standard deviation of a fixed distribution.
                    'init_a', 4, ... % Initial value of substance a
                    'init_b', 4, ... % Initial value of substance b
                    'xnum', xnum, ... % Number of X values.
                    'ynum', ynum, ... % Number of Y values.
                    'xstep', xstep, ... % X spacing
                    'ystep', ystep ... % Y spacing
                  ) );

        % Identity factor for left edge.
        id_left_p(:) = 0;
        id_left_p(xclumpindex==1) = 1;

        % Identity factor for right edge.
        id_right_p(:) = 0;
        id_right_p(xclumpindex==xnum) = 1;

        % Diffusing factor clamped at left and right.  We start this off
        % with a linear gradient, because that's what it will end up being,
        % so why wait?
        s_leftright_p = m.nodes(:,1);
        s_leftright_p = max( s_leftright_p ) - s_leftright_p;
        s_leftright_p = s_leftright_p/max(s_leftright_p);
        m.morphogenclamp( (id_left_p > 0) | (id_right_p > 0), s_leftright_i ) = 1;

        % Identity factor true at all edges.  This is used to set up
        % boundary conditions on A and B at the edges.
        id_edge_p(:) = 0;
        id_edge_p(xclumpindex==1) = 1;
        id_edge_p(xclumpindex==xnum) = 1;
        id_edge_p(yclumpindex==1) = 1;
        id_edge_p(yclumpindex==ynum) = 1;

        % An initial noise perturbation to break the symmetry.
        beta_p = m.userdata.mean_beta + randn(size(m.nodes,1),1) * m.userdata.noise_beta;
        
        % A and B are initially uniform.  Maybe we should set them to be
        % initially uniform plus some noise, instead of using BETA?
        a_p(:) = m.userdata.init_a;
        b_p(:) = m.userdata.init_b;
    else
        % Executed on every iteration after the first.
        % Reaction-diffusion equations.
        ab = a_p .* b_p;
        da = m.userdata.speed*(16 - ab);
        db = m.userdata.speed*(ab - b_p - beta_p);
        if ~USE_DIFFUSION
            a_square = reshape( a_p, m.userdata.xnum, m.userdata.ynum );
            b_square = reshape( b_p, m.userdata.xnum, m.userdata.ynum );
            da = da + (m.userdata.Da/4) * reshape(del2(a_square),[],1);
            db = db + (m.userdata.Db/4) * reshape(del2(b_square),[],1);
        end
        a_p = a_p + m.userdata.dt*da;
        b_p = b_p + m.userdata.dt*db;
        a_p = min( max( a_p, m.userdata.MinC ), m.userdata.MaxC );
        b_p = min( max( b_p, m.userdata.MinC ), m.userdata.MaxC );
        a_p(id_edge_p==1) = m.userdata.BC;
        b_p(id_edge_p==1) = m.userdata.BC;
        
        % The equations in more mathematical notation:
        % da = speed*(16 - a*b) + (Da/4)*Del2(a)
        % db = speed*(ab - b - beta) + (Db/4)*Del2(b)
    end
    a_var_p = a_p - min(a_p); % m.userdata.BC;
    b_var_p = b_p - min(b_p); % m.userdata.BC;
    beta_var_p = beta_p - m.userdata.mean_beta;
    m = leaf_setproperty( m, 'diffusionEnabled', USE_DIFFUSION );
    if USE_DIFFUSION
        FUDGE_FACTOR = 1/16;  % Because of confusion about factor of 4 in AIH's code.
        SPACE_SCALE = 5;  % The scale of the pattern is proportional to this number.
        diffusionScale = FUDGE_FACTOR * SPACE_SCALE^2 * (m.userdata.xstep * m.userdata.ystep)^2;
        % The diffusion rate for S_LEFTRIGHT is just a guess at what is
        % reasonable.
        m = leaf_mgen_conductivity( m, 'A', m.userdata.Da * diffusionScale, ...
                                       'B', m.userdata.Db * diffusionScale, ...
                                       'S_LEFTRIGHT', m.userdata.Db * diffusionScale );
    else
        m = leaf_mgen_conductivity( m, 'A', 0, 'B', 0 );
    end
    
    if Steps(m)==200
        % Turn off the noise perturbation once the patterning gets going,
        % to ensure that the noise plays no role in maintaining the pattern
        % thereafter.
        beta_p(:) = m.userdata.mean_beta;
    end
    
    % Calculate the gradient of A and display it in the form of a
    % morphogen.
    grad_a = mgenCellGradient( m, a_i );
    agrad_p = perFEtoperVertex( m, sqrt( sum( grad_a.^2, 2 ) ) );

    GROWTHSTART = 1000;  % No growth until this time.
    GROWTHRATE = 0.01;   % General magnitude of growth rate.
    
    % Select a model.
  % MODELNAME = 'GROWTH_UNIFORM';
    MODELNAME = 'GROWTH_PEAKS';
    POLARISED = true;
    
    if realtime >= GROWTHSTART
        m = leaf_mgen_dilution( m, { 'A', 'B', 'S_LEFTRIGHT' }, false );
        switch MODELNAME
            case 'GROWTH_UNIFORM'
                % Left-to-right polarisation in absolute space.  Growth is
                % either uniform or determined by B. This is  to test
                % whether the reaction-diffusion system generates new peaks
                % as the mesh expands.
              % kapar_p = GROWTHRATE;
                kapar_p = GROWTHRATE * (1 + tanh( (b_p-6)/3 ))/2;
                P = m.nodes(:,1);
                P = P - min(P);
            case 'GROWTH_PEAKS'
                % The morphogen AGRAD is set to the gradient of A.
                % The polariser is a weighted sum of AGRAD and S_LEFTRIGHT.
                agrad_vec = mgenCellGradient( m, a_i );
                agrad_p = perFEtoperVertex( m, sqrt( sum( agrad_vec.^2, 2 ) ) );
                pa = 1;
                plr = 0; % 30;
                if POLARISED
                    P = pa*a_p + plr*s_leftright_p;
                else
                    P(:) = 0;
                end
                
                % Growth is proportional to AGRAD.  This is normalised to
                % have GROWTHRATE as its maximum value.  To do this on
                % every iteration is biologically unrealistic.  What it
                % should be is some fixed multiple of AGRAD, to be
                % determined by experiment.
                maxagrad = max(agrad_p);
                if maxagrad==0
                    kapar_p(:) = 0;
                else
                    kapar_p = agrad_p * (GROWTHRATE/maxagrad);
                end
        end
        if true || POLARISED
            kaper_p(:) = 0;
        else
            kapar_p = kapar_p/2;
            kaper_p = kapar_p;
        end
        kbpar_p = kapar_p;
        kbper_p = kaper_p;
    end
%%% END OF USER CODE: MORPHOGEN INTERACTIONS

%%% SECTION 3: INSTALLING MODIFIED VALUES BACK INTO MESH STRUCTURE
%%% AUTOMATICALLY GENERATED CODE: DO NOT EDIT.
    m.morphogens(:,polariser_i) = P;
    m.morphogens(:,kapar_i) = kapar_p;
    m.morphogens(:,kaper_i) = kaper_p;
    m.morphogens(:,kbpar_i) = kbpar_p;
    m.morphogens(:,kbper_i) = kbper_p;
    m.morphogens(:,knor_i) = knor_p;
    m.morphogens(:,strainret_i) = strainret_p;
    m.morphogens(:,arrest_i) = arrest_p;
    m.morphogens(:,a_i) = a_p;
    m.morphogens(:,b_i) = b_p;
    m.morphogens(:,beta_i) = beta_p;
    m.morphogens(:,id_edge_i) = id_edge_p;
    m.morphogens(:,a_var_i) = a_var_p;
    m.morphogens(:,b_var_i) = b_var_p;
    m.morphogens(:,beta_var_i) = beta_var_p;
    m.morphogens(:,agrad_i) = agrad_p;
    m.morphogens(:,s_leftright_i) = s_leftright_p;
    m.morphogens(:,id_left_i) = id_left_p;
    m.morphogens(:,id_right_i) = id_right_p;

%%% USER CODE: FINALISATION

% In this section you may modify the mesh in any way whatsoever.
%%% END OF USER CODE: FINALISATION

end


%%% USER CODE: SUBFUNCTIONS
% Here you may add any functions of your own, that you want to call from
% the interaction function, but never need to call from outside it.
% Whichever section they are called from, they must respect the same
% restrictions on what modifications they are allowed to make to the mesh.
% This comment can be deleted.
