
% 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