//cbeam_class.cpp   continuous beam analysis class GPLv3 - implementation

#include "cbeam_class.h"

cBeam::cBeam()
{
    npts = 100;                     //default points per span
    
    lfG=1.0;                        //default safety factors for permanant/live loads
    lfQ=1.0;

    lfG_min=1.0;                    //safety factors for disburdening loads
    lfQ_min=0.0;
}

cBeam::~cBeam()
{
}

bool cBeam::SetGeometry(vector<double> Li, double Ei, vector<double> Ii, vector<double> Ri)
{
    
    //set span lengths [L]
    L.clear();
    for (int i=0; i<Li.size(); i++)
        if (Li[i]>0) L.push_back(Li[i]);                    //check if length >0
    
    int nf=L.size();                                        //number of spans
    
    if (nf>0)   
    {
        //set elastic modulus [E]
        if (Ei>0.0001) E=Ei; else E=1;                      //set default if not given 
    
        //set moments of inertia [I]
        I.clear();
        for (int i=0; i<Ii.size(); i++)
            if (Ii[i]>0) I.push_back(Ii[i]);                //check if inertia >0
        
        if (I.size()!=nf)                                   //check if I fits to the span numbers
        {
            I.clear();
            if (Ii.size()==1) for (int i=0; i<nf; i++) I.push_back(Ii[0]);  //one I is sufficent
            else for (int i=0; i<nf; i++) I.push_back(1);                   //set default if not
        }
        
        //set constraints [R]
        R.clear();
        int n = (nf+1)*2;                                   //check if R fits to the span numbers
        int m = Ri.size(); 
        if (m>n) m=n;
        
        for (int i=0; i<m; i++) R.push_back(Ri[i]);         
        for (int i=m; i<n; i++) 
        {
            if (i%2==0) R.push_back(-1);                    //set default if not
            else R.push_back(0);
        }
      
        build_ksys(L,E,I,R);            //build the stiffness matrix for the given geometry
        build_res_matrix();             //build the result matrix for the given geometry
       
        return true;
    }
    
    else return false;
}


bool cBeam::SetGeometry(vector<double> Li)
{
    //creating empty values, if only spans are given
    double Ei=1;                                 
    vector<double> Ii;                           
    vector<double> Ri;     
    if (SetGeometry(Li,Ei,Ii,Ri)) return true; 
    else return false;
}                      
 

vector< vector<double> > cBeam::GetGeometry()
{
    
    vector< vector<double> > v;
    
    v.push_back(L); 
    v.push_back(vector<double>(L.size(),E)); 
    v.push_back(I); 
    v.push_back(R); 
    
    return v;
}


bool cBeam::SetLoads(vector< vector<double> > LMi)
{
    LMg.clear();
    LMq.clear();
    
    vector<double> ld;
    
    for (int i=0; i<LMi.size(); i++)
    {
        ld.clear();
        ld=LMi[i];
        
        if (ld.size()>2)                                        //span, type and 1 load must be given
        {
            if (ld[0]>0 && int(ld[0])<=L.size())                //load has to be on a span
            {
                for (int j=0; j<2; j++)
                {
                    if (ld.size()>2+j)
                    {
                        if(ld[2+j]!=0)                                  //if permanent/live load is given
                        {
                            vector<double> l;
                            l.push_back(ld[0]);                         //fill in span
                            l.push_back(ld[1]);                         //fill in type
                            l.push_back(ld[2+j]);                       //fill in permanent/live load
                    
                            double span=L[int(ld[0])-1];                //get length for this span
                            if (ld.size()>4)                            //fill in start if given or zero
                            {
                                if (ld[4]<0) ld[4]=0;                   //check if load sits on the span
                                if (ld[4]>span) ld[4]=span; 
                                l.push_back(ld[4]);
                            }
                            else l.push_back(0);                                 
                        
                            if (ld.size()>5)                            //fill in length if given or zero  
                            {
                                if (ld[1]<6)                            //check if load fits the span
                                {
                                    if (ld[5]<0) ld[5]=0;               
                                    if ((ld[4]+ld[5])>span) ld[5]=span-ld[4];
                                }
                                else                                    //lt6: length can be negative
                                {
                                    if (ld[5]>0) if ((ld[4]+ld[5])>span) ld[5]=span-ld[4];
                                    if (ld[5]<0) if ((ld[4]+ld[5])<0) ld[5]=-ld[4];
                                }
                                l.push_back(ld[5]);
                            }
                            else l.push_back(0);                    
                    
                            if (!((ld[1]==3 || ld[1]==6) && ld[2+j]*ld[5]==0))     //check if p*c=0
                            {
                                if (j==0) LMg.push_back(l);                //fill into permanent load matrix
                                if (j==1) LMq.push_back(l);                //fill into live load matrix
                            }
                        }
                    }
                }
            }
        }
    }

    if ((LMg.size()+LMq.size())>0) return true; 
    else return false;
}

//get permanent loads
vector< vector<double> > cBeam::GetLoadsG()
{
    return LMg;
}

//get live loads
vector< vector<double> > cBeam::GetLoadsQ()
{
    return LMq;
}

void cBeam::SetLoadFactors(double g, double q)
{
    lfG=g;
    lfQ=q; 
}

void cBeam::SetLoadFactors(double g, double q, double g_min, double q_min)
{
    lfG=g;
    lfQ=q;
    lfG_min=g_min;
    lfQ_min=q_min;      //keep this zero, if you want to have save results
}


bool cBeam::Solve()
{
	int nf=L.size();
	if (nf!=0)                     //check if someone called this without setting geometry
    {
        int lmG=LMg.size();
        int lmQ=LMq.size();
        int lmSize = lmG+lmQ;

	    vector< vector<double> > LM; 
        vector< vector<double> > w(lmSize,vector<double>(5,0)); 
	    vector< vector<double> > wmax(lmSize,vector<double>(5,0));
	    vector< vector<double> > wmin(lmSize,vector<double>(5,0)); 

	    for (int i=0; i<lmG; i++)
	    {
            for (int j=0; j<5; j++)  wmax[i][j]=LMg[i][j];
            wmax[i][2] *=lfG;        //permanent load factor (max)
		
            for (int j=0; j<5; j++)  wmin[i][j]=LMg[i][j];
		    wmin[i][2] *=lfG_min;   //permanent load factor (min)
	    }
	
	    for (int i=lmG; i<lmSize; i++)  
	    {
            for (int j=0; j<5; j++)  wmax[i][j]=LMq[i-lmG][j]; 
		    wmax[i][2] *=lfQ;         //live load factor (max)
		    for (int j=0; j<5; j++)  wmin[i][j]=LMq[i-lmG][j]; 
		    wmin[i][2] *=lfQ_min;     //live load factor (min)
	    }
	    
	    int nSpan;
	
	    //load case 1: permanent loads
	    cba_solve(wmin);
        for (int i=0; i<nf+1; i++) Rf[1][i]=Rf[0][i];    // initialize Rf min=max
    
	    // load case 2: maximum support hogging and reaction
	    for (int i=0; i<nf-1; i++)
	    {
            for (int j=0; j<lmSize; j++) 
			    for (int k=0; k<5; k++) 
                    w[j][k]=wmin[j][k];
		    nSpan=i+1;
		    for (int j=0; j<lmSize; j++) 
			if ((wmax[j][0] == nSpan) || (wmax[j][0] == nSpan+1))
				for (int k=0; k<5; k++) w[j][k]=wmax[j][k];
		    cba_solve(w);
        }

	    //load case 3: odd numbered spans
        for (int i=0; i<lmSize; i++) 
	       for (int j=0; j<5; j++)
	           w[i][j]=wmax[i][j];
	
	    for (int i=1; i<nf; i=i+2)
	    {
	       nSpan=i+1;
	       for (int j=0; j<lmSize; j++) 
	       if ((wmax[j][0] == nSpan))
                for (int k=0; k<5; k++) w[j][k]=wmin[j][k];
	    }
	    cba_solve(w);
	
	    //load case 4: even numbered spans
	    for (int i=0; i<lmSize; i++) 
	       for (int j=0; j<5; j++)
	           w[i][j]=wmin[i][j];
	    for (int i=1; i<nf; i=i+2)
	    {
		  nSpan=i+1;
		  for (int j=0; j<lmSize; j++) 
			if ((wmin[j][0] == nSpan))
				for (int k=0; k<5; k++) w[j][k]=wmax[j][k];
	    }
	    cba_solve(w);
	
	   //load case 5: max load
	   cba_solve(wmax);
	   
	   return true;
    }
	else return false;
}
 

//rewrite result matrix for output
vector< vector <double> > cBeam::GetResults()
{
    int nf=L.size();
    vector< vector<double> > r(7);

    double px=0;
    for (int i=0; i<nf; i++)
    {
        //rebuild px along the whole beam
        if (i>0) px+=L[i-1];
        for (int j=0; j<npts+1; j++)
        {
            r[0].push_back(px+Res[0][i][j]);
            for (int k=1; k<=6; k++) r[k].push_back(Res[k][i][j]);
        }
    }
    return r;
}

//return maximum value per span
vector< vector <double> > cBeam::GetMax()
{
    int nf=L.size();
    vector< vector<double> > r(7);

    //get x(Mmax)
    for (int i=0; i<nf; i++)
    {
        double res=0;
        int pos=0;
        for (int j=0; j<npts+1; j++)
        {
            if (Res[1][i][j]>res)
            {
                res = Res[1][i][j];
                pos = j;
            }
        }
        r[0].push_back(Res[0][i][pos]);
    }

    // get max/min values
    for (int i=0; i<nf; i++)
    {
        for (int k=1; k<=6; k++)
        {
            double res=0;
            for (int j=0; j<npts+1; j++)
            {
                if (k%2!=0 && Res[k][i][j]>res) res = Res[k][i][j];     //max
                if (k%2==0 && Res[k][i][j]<res) res = Res[k][i][j];     //min
            }
            r[k].push_back(res);
        }
    }

    return r;
}


//return support reactions
vector< vector <double> > cBeam::GetReaction()
{
    return Rf;
}


//------------------------- private functions for calculating ----------------------------

//calculate stiffness matrix of one beam element
vector< vector<double> > cBeam::k_beam(double Lb, double Ib, double Eb)
{
    vector< vector<double> > kb(4,vector<double>(4,0));

    double kfv, kmv, kft, kmt, kmth;
    kfv = 12*Eb*Ib/pow(Lb,3);
    kmv = 6*Eb*Ib/pow(Lb,2);
    kft = kmv;
    kmt = 4*Eb*Ib/Lb;
    kmth = 2*Eb*Ib/Lb;

    kb[0][0]=kfv;    kb[0][1]=kft;    kb[0][2]=-kfv;   kb[0][3]=kft;
    kb[1][0]=kmv;    kb[1][1]=kmt;    kb[1][2]=-kmv;   kb[1][3]=kmth;
    kb[2][0]=-kfv;   kb[2][1]=-kft;   kb[2][2]=kfv;    kb[2][3]=-kft;
    kb[3][0]=kft;    kb[3][1]=kmth;   kb[3][2]=-kft;   kb[3][3]=kmt;

    return kb;
}


//building the global stiffness matrix
void cBeam::build_ksys(vector<double> L, double E, vector<double> I, vector<double> R)
{
    ksys.clear();
    int N = L.size();
    int ndof=2*(N+1);
    int dof_i;

    for (int i=0; i<ndof; i++) ksys.push_back(vector<double>(ndof,0));    //zero matrix

    vector< vector<double> > kb(4,vector<double>(4,0));

    for (int i=0; i<N; i++)
    {
        kb.clear();
        kb = k_beam(L[i],I[i],E);                                       //calculate beam stiffness

        dof_i = 2*i;

        for (int j=0; j<4; j++)                                         //assign to stiffness matrix
            for (int k=0; k<4; k++)
                ksys[dof_i+j][dof_i+k] = ksys[dof_i+j][dof_i+k] + kb[j][k];
    }

    for (int i=0; i<ndof; i++)                                          //apply constraints
    {
        if (R[i] < 0)
        {
            for (int j=0; j<ndof; j++)
            {
                ksys[i][j]=0;
                ksys[j][i]=0;
            }
            ksys[i][i]=1;
        }
        if (R[i] > 0) ksys[i][i] = ksys[i][i]+ R[i];                  //spring supports
    }

}


//empty and build result matrix
void cBeam::build_res_matrix()
{
    int nf=L.size();

    //support reactions
    Rf.clear();
    Rf.assign(2,vector<double>(nf+1,0));

    //calculate x=L[i]/npts along the beam
    vector< vector<double> > px(nf,vector<double>(npts+1,0));
    for (int i=0; i<nf; i++)
    {
        px[i][0]=0;
        for (int j=1; j<npts; j++) px[i][j]=px[i][j-1]+L[i]/npts;
        px[i][npts]=L[i];
    }

    //empty result matrix and assign px
    Res.clear();
    vector< vector<double> > zero(nf,vector<double>(npts+1,0));
    Res.push_back(px);
    for (int i=0; i<6; i++) Res.push_back(zero);
}


//solve the continuous beam problem for a given load matrix
void cBeam::cba_solve(vector< vector<double> > LM)
{
    int N = L.size();
    int ndof=2*(N+1);
    int dof_i;

    vector<double> m(ndof,0);           //zero right hand side
    vector<double> nl(4,0);             //nodal loads
   
    for (int i=0; i<N; i++)
    {
        dof_i = 2*i;
        
        nl.clear();
        nl=get_cnl(i, LM);                              //get nodal loads for this load case
        
        for (int j=0; j<4; j++) m[dof_i+j]-=nl[j];
    }
    
    
    for (int i=0; i<ndof; i++)                          //constraints
        if (R[i] < 0) m[i] = 0;                         //here for specified displacements
  
    m=solve_glsys(ksys,m);                              //solve -> m


    //calculate member end actions
    vector<double> dmbr(4,0);   // end deformations
    vector<double> fmbr(4,0);   // end forces
    vector<double> rf(N+1,0);     // reaction forces
    vector< vector<double> > kb(4,vector<double>(4,0)); 
  
    for (int i=0; i<N; i++)
    {
        kb=k_beam(L[i],I[i],E);
 
        dof_i=2*i;
        for (int j=0; j<4; j++) dmbr[j]=m[dof_i+j];  
       
        nl=get_cnl(i, LM);                      // Reduced Load Matrix for this span -> nl

        for (int j=0; j<4; j++) fmbr[j]=0;
        
        for (int j=0; j<4; j++)
        {
            for (int k=0; k<4; k++) fmbr[j]+=kb[j][k]*dmbr[k]; 
            fmbr[j]+=nl[j];
        }
       
        rf[i]+=fmbr[0];                     //reaction forces
        rf[i+1]+=fmbr[2];
      
        set_mbr_values(i,fmbr,dmbr,LM);       // set member forces
    }
    
    for (int i=0; i<N+1; i++)   // max/min Rf
    {
        if (rf[i]>Rf[0][i]) Rf[0][i]=rf[i];           //max
        if (rf[i]<Rf[1][i]) Rf[1][i]=rf[i];           //min
    }
 
}


//solve the system of linear equations using lu decomposition
vector<double> cBeam::solve_glsys (vector< vector<double> > A, vector<double> b)
{
    int n=A.size();
    vector<double> x(n,0);

    for (int i=0; i<n; i++)
    {
        for (int j=i+1; j<n; j++)
        {
            A[j][i]/=A[i][i];
            for (int k=i+1; k<n; k++) A[j][k]-=A[j][i]*A[i][k];
        }
    }

    for (int j=0; j<n; j++) for (int k=0; k<j; k++) b[j]=b[j]-A[j][k]*b[k];
    for (int j=n-1; j>=0; j--)
    {
        for (int k=j+1; k<n; k++) b[j]=b[j]-A[j][k]*b[k];
        b[j]=b[j]/A[j][j];
    }
    x=b;
    return x;
}


//get nodal loads = [Va, Ma, Vb, Mb]
vector<double> cBeam::get_cnl(int iSpan, vector< vector<double> > LM)
{
    vector<double> nl(4,0);

    double l, p, a, b, c, s, t;
    int loadtype;
    
    l=L[iSpan];
    
    for (int i=0; i<LM.size(); i++) 
    {      
        if (LM[i][0] == (iSpan+1))
        {
            loadtype=int(LM[i][1]);
            p=LM[i][2];
            a=LM[i][3];
            c=LM[i][4];
            
            switch (loadtype)
            {
                case 1:                     //uniformly distributed loads

                    nl[0] += p*l/2;
                    nl[1] += p*pow(l,2)/12;
                    nl[2] += p*l/2;
                    nl[3] += -p*pow(l,2)/12;
                    break;

               case 2:                      //point loads
                    b=l-a;
                    
                    nl[0] += p/pow(l,3)*(b*pow(l,2)-pow(a,2)*b+a*pow(b,2));
                    nl[1] += p*a*pow(b,2)/pow(l,2);
                    nl[2] += p/pow(l,3)*(a*pow(l,2)-pow(b,2)*a+b*pow(a,2));;
                    nl[3] += -p*pow(a,2)*b/pow(l,2);
                    break;

                case 3:                      //partial udls

                    s=a+c/2;
                    t=l-s;

                    nl[0] += p*c*((2*s+l)*pow(t,2)+pow(c,2)*(s-t)/4)/pow(l,3);
                    nl[1] += p*c*(s*pow(t,2)+(s-2*t)*pow(c,2)/12)/pow(l,2);
                    nl[2] += p*c*((2*t+l)*pow(s,2)+pow(c,2)*(t-s)/4)/pow(l,3);
                    nl[3] += -p*c*(t*pow(s,2)+(t-2*s)*pow(c,2)/12)/pow(l,2);
                    break;

                case 4:                      //moment loads

                    b=l-a;

                    nl[0] += p*6*a*b/pow(l,3);
                    nl[1] += (p*b/pow(l,2))*(2*a-b);
                    nl[2] += -p*6*a*b/pow(l,3);
                    nl[3] += (p*a/pow(l,2))*(2*b-a);
                    break;

                case 5:                      //trapezoidal loads

                    b=l-(a+c);

                    nl[0] += p*(l+(pow(a,3)-pow(b,3))/(2*pow(l,2))+(pow(b,4)-pow(a,4))/(5*pow(l,3))-a)/2;
                    nl[1] += p*(pow(l,2)+(2*pow(a,3)-pow(b,3))/l+(3*pow(b,4)-3*pow(a,4))/(5*pow(l,2))-2*pow(a,2))/12;
                    nl[2] += p*(l+(pow(b,3)-pow(a,3))/(2*pow(l,2))+(pow(a,4)-pow(b,4))/(5*pow(l,3))-b)/2;
                    nl[3] += -p*(pow(l,2)+(2*pow(b,3)-pow(a,3))/l+(3*pow(a,4)-3*pow(b,4))/(5*pow(l,2))-2*pow(b,2))/12;
                    break;

                case 6:                      //partial triangular loads

                    if (c>0) s=a+c/3;               //descending
                    else { a+=c; s=a-2*c/3; }       //ascending
                    t=l-s;

                    nl[0] += p*fabs(c)*((2*s+l)*pow(t,2)+pow(c,2)*(s-t)/6+2*pow(c,3)/135)/(2*pow(l,3));
                    nl[1] += p*fabs(c)*(s*pow(t,2)+pow(c,2)*(s-2*t)/18+pow(c,3)/135)/(2*pow(l,2));
                    nl[2] += p*fabs(c)*((2*t+l)*pow(s,2)+pow(c,2)*(t-s)/6-2*pow(c,3)/135)/(2*pow(l,3));
                    nl[3] += -p*fabs(c)*(t*pow(s,2)+pow(c,2)*(t-2*s)/18-pow(c,3)/135)/(2*pow(l,2));
                    break;
            }
        }
    }
    return nl;
}


// sets M, V, rt, def of member 
void cBeam::set_mbr_values(int iSpan, vector<double> fmbr, vector<double> dmbr, vector< vector<double> > LM)           
{
    vector<double> x(npts+1,0); 
    for (int i=0; i<npts+1; i++) x[i]=Res[0][iSpan][i];

    vector<double> Mt(npts+1,0);
    vector<double> Vt(npts+1,0);
    vector<double> Rt(npts+1,0);
    vector<double> Dt(npts+1,0);
 
    double l, p, a, b, c, Va, Ra;            //values caused by applied loads
    int loadtype;

    l=L[iSpan];

    for (int i=0; i<LM.size(); i++)
    {
        if (LM[i][0] == (iSpan+1))
        {
            loadtype=int(LM[i][1]);
            p=LM[i][2];
            a=LM[i][3];
            c=LM[i][4];

            switch (loadtype)
            {
                case 0: 
                    
                    break;
  
                case 1:                     //uniformly distributed loads
 
                    Va=p*l/2;
                    Ra=-p*pow(l,3)/24;
  
                    for (int j=0; j<npts+1; j++)
                    {
                        Vt[j]+=Va - p*x[j];
                        Mt[j]+=Va*x[j] - (p/2)*pow(x[j],2);
                        Rt[j]+=(Va/2)*pow(x[j],2) - (p/6)*pow(x[j],3) + Ra;
                        Dt[j]+=(Va/6)*pow(x[j],3) - (p/24)*pow(x[j],4) + Ra*x[j];
                    }
                    break;

                case 2:                      //point loads

                    b=l-a;
                    Va = p*b/l;
                    Ra = p*b*(pow(b,2)-pow(l,2))/(6*l);

                    for (int j=0; j<npts+1; j++)
                    {
                        if (a>0)
                        {
                            Vt[j]+=Va;
                            Mt[j]+=Va*x[j];
                            Rt[j]+=(Va/2)*pow(x[j],2) + Ra;
                            Dt[j]+=(Va/6)*pow(x[j],3) + Ra*x[j];

                            if (x[j]>a)
                            {
                                Vt[j]-=p;
                                Mt[j]-=p*(x[j]-a);
                                Rt[j]-=(p/2)*pow((x[j]-a),2);
                                Dt[j]-=(p/6)*pow((x[j]-a),3);
                            }
                        }
                    }
                    break;
 
                case 3:                      //partial udls
                    
                    b = c+a;
                    Va = (l-b+c/2)*c*p/l;
                    Ra=-((Va/6)*pow(l,3)+(p/24)*pow((l-b),4)-(p/24)*pow((l-a),4))/l;
                    
                    for (int j=0; j<npts+1; j++)
                    {
                        Vt[j]+=Va;
                        Mt[j]+=Va*x[j];
                        Rt[j]+=(Va/2)*pow(x[j],2)+ Ra;
                        Dt[j]+=(Va/6)*pow(x[j],3)+ Ra*x[j];
                        
                        if (x[j]>a)
                        {
                            Vt[j]-=p*(x[j]-a);
                            Mt[j]-=(p/2)*pow((x[j]-a),2);
                            Rt[j]-=(p/6)*pow((x[j]-a),3);
                            Dt[j]-=(p/24)*pow((x[j]-a),4);
                        
                            if (x[j]>b)
                            {
                                Vt[j]+=p*(x[j]-b);
                                Mt[j]+=(p/2)*pow((x[j]-b),2);
                                Rt[j]+=(p/6)*pow((x[j]-b),3);
                                Dt[j]+=(p/24)*pow((x[j]-b),4);
                            }
                        }
                    }
                    break;

                case 4:                      //moment load

                    b = l-a;
                    Va = p/l;
                    Ra = (p/6)*(3*pow(b,2)/l-l);

                    for (int j=0; j<npts+1; j++)
                    {
                        Vt[j]+=Va;                       
                        if (x[j]<a)
                        {
                            Mt[j]+=Va*x[j];
                            Rt[j]+=(Va/2)*pow(x[j],2) + Ra;
                            Dt[j]+=(Va/6)*pow(x[j],3) + Ra*x[j];
                        }
                        else
                        {
                            Mt[j]+=Va*x[j]-p;
                            Rt[j]+=(Va/2)*pow(x[j],2) - p*(x[j]-a) + Ra;
                            Dt[j]+=(Va/6)*pow(x[j],3) - (p/2)*pow((x[j]-a),2) + Ra*x[j];
                        }
                    }
                    break;
                    
                case 5:                      //trapezoidal loads

                    b=l-(a+c);
                    Va = p/2 *(l+(pow(a,2)-pow(b,2))/(3*l)-a);
                    Ra = -p/24*(pow(l,3)-(2*pow(b,2)+4*pow(a,2))*l/3+(pow(b,4)-pow(a,4))/(5*l)+pow(a,3));

                    for (int j=0; j<npts+1; j++)
                    {
                        if (a>0)
                        {
                            Vt[j]+=Va       -(p/2)*pow(x[j],2)/a;
                            Mt[j]+=Va*x[j]  -(p/6)*pow(x[j],3)/a;
                            Rt[j]+=Ra       +(Va/2)*pow(x[j],2) -(p/24)*pow(x[j],4)/a;
                            Dt[j]+=Ra*x[j]  +(Va/6)*pow(x[j],3) -(p/120)*pow(x[j],5)/a;

                            if (x[j]>a)
                            {
                                Vt[j]+=(p/2)   *(pow(x[j]-a,2))/a;
                                Mt[j]+=(p/6)   *(pow(x[j]-a,3))/a;
                                Rt[j]+=(p/24)  *(pow(x[j]-a,4))/a;
                                Dt[j]+=(p/120) *(pow(x[j]-a,5))/a;
                            }
                        }
                        else
                        {
                            Vt[j]+=Va       -p*x[j];
                            Mt[j]+=Va*x[j]  -(p/2)*pow(x[j],2);
                            Rt[j]+=Ra       +(Va/2)*pow(x[j],2)   -(p/6)*pow(x[j],3);
                            Dt[j]+=Ra*x[j]  +(Va/6)*pow(x[j],3)   -(p/24)*pow(x[j],4);
                        }

                        if (x[j]>(a+c))
                        {
                            Vt[j]+=(p/2)   *(pow(x[j]-(a+c),2))/b;
                            Mt[j]+=(p/6)   *(pow(x[j]-(a+c),3))/b;
                            Rt[j]+=(p/24)  *(pow(x[j]-(a+c),4))/b;
                            Dt[j]+=(p/120) *(pow(x[j]-(a+c),5))/b;
                        }
                    }    
                    break;
                    
                case 6:                      //partial triangular loads

                    if (c>0)    //descending
                    {
                        b=l-(a+c);
                        double Va = p*c*(b+2*c/3)/(2*l);
                        double Ra = -p*c*(pow(l,2)*(2*c/3+b)-2*pow(c,3)/5-3*b*pow(c,2)/2-2*pow(b,2)*c-pow(b,3))/(12*l);

                        for (int j=0; j<npts+1; j++)
                        {
                            Vt[j]+=Va;
                            Mt[j]+=Va*x[j];
                            Rt[j]+=Ra       +(Va/2)*pow(x[j],2);
                            Dt[j]+=Ra*x[j]  +(Va/6)*pow(x[j],3);

                            if (x[j]>a)
                            {
                                Vt[j]+=(p/2)*(pow(x[j]-a,2)/c)      -p*(x[j]-a);
                                Mt[j]+=(p/6)*(pow(x[j]-a,3)/c)      -(p/2)*pow(x[j]-a,2);
                                Rt[j]+=(p/24)*(pow(x[j]-a,4)/c)     -(p/6)*pow(x[j]-a,3);
                                Dt[j]+=(p/120)*(pow(x[j]-a,5)/c)    -(p/24)*pow(x[j]-a,4);

                                if (x[j]>(a+c))
                                {
                                    Vt[j]-=(p/2)   *(pow(x[j]-(a+c),2)/c);
                                    Mt[j]-=(p/6)   *(pow(x[j]-(a+c),3)/c);
                                    Rt[j]-=(p/24)  *(pow(x[j]-(a+c),4)/c);
                                    Dt[j]-=(p/120) *(pow(x[j]-(a+c),5)/c);
                                }
                            }
                        }
                    }

                    else if (c<0)   //ascending
                    {
                        a+=c;
                        c=fabs(c);

                        b=l-(a+c);
                        double Va = p*c*(b+c/3)/(2*l);
                        double Ra = -p*c*(pow(l,2)*(c/3+b)-pow(c,3)/10-b*pow(c,2)/2-pow(b,2)*c-pow(b,3))/(12*l);

                        for (int j=0; j<npts+1; j++)
                        {
                            Vt[j]+=Va;
                            Mt[j]+=Va*x[j];
                            Rt[j]+=Ra       +(Va/2)*pow(x[j],2);
                            Dt[j]+=Ra*x[j]  +(Va/6)*pow(x[j],3);

                            if (x[j]>a)
                            {
                                Vt[j]-=(p/2)*(pow(x[j]-a,2)/c);
                                Mt[j]-=(p/6)*(pow(x[j]-a,3)/c);
                                Rt[j]-=(p/24)*(pow(x[j]-a,4)/c);
                                Dt[j]-=(p/120)*(pow(x[j]-a,5)/c);

                                if (x[j]>(a+c))
                                {
                                    Vt[j]+=(p/2)   *(pow(x[j]-(a+c),2)/c)   +p*(x[j]-(a+c));
                                    Mt[j]+=(p/6)   *(pow(x[j]-(a+c),3)/c)   +(p/2)*pow(x[j]-(a+c),2);
                                    Rt[j]+=(p/24)  *(pow(x[j]-(a+c),4)/c)   +(p/6)*pow(x[j]-(a+c),3);
                                    Dt[j]+=(p/120) *(pow(x[j]-(a+c),5)/c)   +(p/24)*pow(x[j]-(a+c),4);
                                }
                            }
                        }
                    }
                    break;              
            }   
        }   
    }    

    //add results at npts for the two moments applied at each end, Ma and Mb
    double Ma=fmbr[1];
    double Mb=fmbr[3];

    Va = (Ma+Mb)/l;
    Ra = Ma*l/3 - Mb*l/6;

    for (int j=0; j<npts+1; j++)
    {
        Vt[j]+=Va;
        Mt[j]+=Va*x[j]-Ma;
        Rt[j]+=(Va/2)*pow(x[j],2) - Ma*x[j] + Ra;
        Dt[j]+=(Va/6)*pow(x[j],3) - (Ma/2)*pow(x[j],2) + Ra*x[j];

        Rt[j]/=(E*I[iSpan]);
        Dt[j]/=(E*I[iSpan]);
    }

   //add end displacements
    for (int i=0; i<npts+1; i++)
    {
        Dt[i]+=dmbr[0]*(2/pow(l,3)*pow(x[i],3) - 3/pow(l,2)*pow(x[i],2) +1);
        Dt[i]+=dmbr[2]*(-2/pow(l,3)*pow(x[i],3) + 3/pow(l,2)*pow(x[i],2));
    }

    //put into result matrix
    double ResValue=0;
    for (int i=0; i<npts+1; i++)
    {
        //moments
        ResValue=Mt[i];
        if (ResValue > Res[1][iSpan][i]) Res[1][iSpan][i]=ResValue;
        if (ResValue < Res[2][iSpan][i]) Res[2][iSpan][i]=ResValue;

        //shear
        ResValue=Vt[i];
        if (ResValue > Res[3][iSpan][i]) Res[3][iSpan][i]=ResValue;
        if (ResValue < Res[4][iSpan][i]) Res[4][iSpan][i]=ResValue;

        //deformations - in force direction positive
        ResValue=-Dt[i];
        if (ResValue > Res[5][iSpan][i]) Res[5][iSpan][i]=ResValue;
        if (ResValue < Res[6][iSpan][i]) Res[6][iSpan][i]=ResValue;
    }
}






