# Copyright ENPC

if SearchText(`Release 3`,interface(version))<>0 then
	matadd:=add;
elif SearchText(`Release 4`,interface(version))<>0 then
	1;
else
  ERROR(`Unknown Release`)
fi;

read(`Euler.map`);
#----------------------------------------------------------------------------
# AND NOW THE WHEEL
#-----------------------------------------------------------------------------

#----------------------------------------------------------------------------
# TeX Notations for my problem 
#-----------------------------------------------------------------------------

ll:= {x = `x`  , y = `y` , z= `z`,theta = `\\theta`, phi = `\\phi`,psi = `\\psi`,param =`\\alpha`, t = `\\eta` , LL = `\\LL`, _t = `\\lambda` } :
addnotations(ll):

#----------------------------------------------------------------------------
# Lagrangian for The wheel problem : 
#---------------------------------------------------------------------------

# Number of parameters:
mpar:=5:
param:=[m,J[1],J[2],r,g]:
# Number of state variables
n:=6:

# Lagragian as a function of q[k], qd[k] k=1,..,n and
# param[m] m=1,..,mpar
# Lagrangian variables :
q := [ x,y,z,theta,phi,psi]:
qd := [ seq ( cat(q[i],`d`),i=1..n)]:
qdd:= [ seq ( cat(q[i],`dd`),i=1..n)]:

#-------------------------------------------
# Geometric computations 
#-------------------------------------------
Bx:=vector([1,0,0]):
By:=vector([0,1,0]):
Bz:=vector([0,0,1]):
Bu1:=vector([cos(theta),sin(theta),0]):
Bu:= matadd(Bu1,Bz,cos(phi),-sin(phi)):
Bw:= matadd(Bu1,Bz,sin(phi),cos(phi)):
Bv:=crossprod(Bw,Bu):
Bv:=map((i)->factor(combine(i,trig)),Bv):

R:=transpose(matrix(3,3,[eval(Bu),eval(Bv),eval(Bw)])):
Rinv:=map((i)->factor(combine(i,trig)),inverse(R)):

# Omega in the (x,y,z) base 

OmegaX:= matadd(Bz,matadd(Bv,Bw,phid,psid),thetad,1):

# Omega in the (u,v,w) base

Omega:=multiply(Rinv,OmegaX):
Omega:=map((i)->factor(combine(i,trig)),Omega):

# J[1]=J[2]=J_u : J[3]=J_w

EcJ:= J[1]*(Omega[1]^2+Omega[2]^2) +J[3]*Omega[3]^2:

L:=(1/2)*( param[1]*(qd[1]^2+qd[2]^2+qd[3]^2) + EcJ )
          -param[1]*param[5]*q[3]:

sorties(`systeme.tex`,`Lagrangian`,L):

# Lhs of Euler equations 

EL:=euler_equations(L,q,qd,qdd):
EE:=map((i)->rhs(i),EL):

# don't forget the LL macro in all.tex 

sorties(`systeme.tex`,`variables :`,` q ` = matrix(nops(q),1,q)):
sortiesM(`systeme.tex`,`Lhs of Euler Equations`,[seq(EL[i,1],i=1..nops(q))]):

#-----------------------------------------------------
# Rewritting the Euler equations to have a canonical form 
#           ..         .
# El= ME(q)  q + CE(q) q^2 + RE(q,...)
# Computation of ME,CE,RE 
#-----------------------------------------------------

XX:=CEuler(EE,q,qd,qdd):

# simplifying notations for output

sortiesI(`systeme.tex`,`$M(q)\\ddot{q}+C(q)\\dot{q}^2 +R(q,\\dot{q})$`):
sorties(`systeme.tex`,`M~:`,XX[1]):
sorties(`systeme.tex`,`C~:`,XX[2]):
sorties(`systeme.tex`,`R~:`,XX[3]):

#------------------------------------------------
# Constraints on the Wheel
#------------------------------------------------

# geometric constraints

hc:=[q[3]-param[4]*sin(q[5])]:

# dynamic constraints ( contains the derivative of geometric constraint )
# v_g + crossprod(OmegaX,Bu)=0

gg:=matadd(vector([qd[1],qd[2],qd[3]]),crossprod(OmegaX,Bu),1,r):
gg:=map((i)->simplify(expand(i)),gg):

nhc:=convert(gg,list):

sortiesM(`systeme.tex`,`Geometric Constraints hc=0,hc:`,hc);
sortiesM(`systeme.tex`,`Dynamic Constraints nhc=0,nhc`,nhc);

# Derivatives of constraints are of type Aprim qd = 0 

Aprim:=genmatrix(nhc,qd):

sorties(`systeme.tex`,`Constraints : $A'(q)\\dot{q}$`,Aprim);

#----------------------------------------------
# Computing SS:=S(q);
# S(q) will solve Aprim S(q) = 0 
# in The Euler equations  Equ= A(q)' lambda + u 
# the term A(q)lambda can be eliminated 
# if we left-multiply euler equations by S(q)'
#----------------------------------------------
ncont:=3;
SS:=linsolve(Aprim,matrix(ncont,1,0)):

sorties(`systeme.tex`,` S(q)`,SS);

#------------------------------------------------------------------------
# The constraints are now dotq=S(q)eta 
# can be used to see that eta =[phi,theta,psi]
# ( eta[i] is the maple variable ti )
# but the indices can be mixed and linsolve doesn't 
# always return the same result 
# We have to check the correspondance between t.sig(i)=[phi,theta,psi]
# and to change SS to have a good corespondance 
#-------------------------------------------------------------------------
knsize:=3;
permut:={seq(SS[i+3,1]=t_s[i],i=1..knsize)}:
SS:=subs(permut,eval(SS)):
permut:={seq(t_s[i]=t[i],i=1..knsize)}:
SS:=subs(permut,eval(SS)):

S:= genmatrix(convert(convert(SS,vector),list),[seq( t[i],i=1..knsize)]):
sorties(`systeme.tex`,`$\\dot{q}=S(q)\\eta$ Kernel of $A(q)'$~:`,S):

#-----------------------------------------------------
# this multiplication eliminates the term A(q) lambda 
# in the Euler equations 
#-----------------------------------------------------

E1:=multiply(transpose(S),EE):

# sortiesM(`systeme.tex`,`$S(q)^T E$`,E1);

#-----------------------------------------------------
# since Aprim(q) dotq=0 
# .
# q= S(q) eta ; here  eta = [t1,t2]
#                                 ..
# we use this equation to compute q
# Warning : t1 and t2 are time dependent
#-----------------------------------------------------

qt  := [ seq (t[i]  ,i=1..knsize)]:
qtd := [ seq (td[i] ,i=1..knsize)]:
qtdd:= [ seq (tdd[i],i=1..knsize)]:

qqdd:=map((x,y,z,t)-> time_diff(x,y,z,t),eval(SS),
	[op(q),op(qt)],[op(qd),op(qtd)],[op(qdd),op(qtdd)]):

#-----------------------------------------------------
#       ..                       .
# using  q= d/dt [ S(q) eta] and q= S(q) eta 
# we can subsitute these expressions in E1
#-----------------------------------------------------

E2:=subs(seq(qdd[i]=qqdd[i,1],i=1..nops(qdd)),eval(E1)):
E3:=subs(seq(qd[i]=SS[i,1],i=1..nops(qd)),eval(E2)):

#-----------------------------------------------------
# The global system is now 
#             .
#  E3 = 0 and q= S(q) eta 
#-----------------------------------------------------

E3:=map((x)-> simplify(x),E3):

sortiesM(`systeme.tex`,
	`$S(q)^T E$ simplified with $\\dot{q}=S(q)\\eta $`,E3);

#------------------------------------------------------------------
# Trying to find canonical representation 
# for the simplified euler equations
#            .
# El= ME(q)  t + RE(q,t)
# we use CEuler with a little trick in the parameter call qt,qt,qtd
#------------------------------------------------------------------

XX1:=CEulerP(E3,qt,qt,qtd):

MM3:=map((i)->factor(combine(i,trig)),XX1[1]):
RR3:=map((i)->factor(combine(i,trig)),XX1[2]):

sortiesI(`systeme.tex`,`a cononical form $M(q)\\dot{t}+R(q,t)$`);
sorties(`systeme.tex`,`C:`,MM3);
sorties(`systeme.tex`,`R:`,RR3);

#-----------------------------------------------------
# FORTRAN GENERATION 
#-----------------------------------------------------

#-----------------------------------------------------
# First routine wheel(neq,t,z,zdot)
# z= [ A,dotA, X] ou A=[theta,phi,psi] X=x,y
#       |0  I  0  |
# zdot =|0  0  0  | + Y
#       |0 S1(q) 0|   ( S1 : 2-first rows of S)
# where Y solves M(q)Y + C(q)dotA^2 + R =0 
#-----------------------------------------------------
kn:=knsize:

fvar:= {theta= z[1],phi=z[2],psi=z[3],t[1]=z[4],
	t[2]=z[5],t[3]=z[6],x=z[7],y=z[8]}:
MM3F:=subs(fvar,eval(MM3)):

 # don't forget the minus sign 
RR3F:=map((x)-> -x ,subs(fvar,eval(RR3))):
SSF:=subs(fvar,eval(SS)):

flist:=[subroutinem,`wheel`,[`neq`,`t`,`z`,`zdot`],
           [
            [ declaref,`implicit double precision`,[`(t)`] ],
            [ parameterf,[`kn=`.kn]],
            [ declaref,doubleprecision,[`t,z(8),zdot(8),r,j(3),m`]],
            [ declaref,doubleprecision,[`me3s(kn,kn)`]],
            [ declaref,doubleprecision,[`const(kn,1),w(3*kn),rcond`]],
            [ declaref,integer,[`i,k,neq,ierr`]],
            [ declaref,`data g`,[`/ 9.81/`]],
            [ declaref,`data r`,[`/ 1.0/`] ],
            [ declaref,`data m`,[`/ 1.0/`] ],
            [ declaref,`data j`,[`/ 0.3,0.4,1.0/`] ],
            [ matrixm,`me3s`,MM3F ] ,
            [ matrixm,`const`,RR3F ] , 
	    [ dom , `i ` ,1,`kn `,1,[ equalf,`zdot(i)`,`z(i+kn)`]],
	    [commentf,` we must solve  M z =const `],
	    [ callf , `dlslv`,[`me3s,kn,kn,Const,kn,1,w, rcond,ierr,1`]],
	    [ if_then_m,ierr<>0,[
		[writef,6,ff_w,[]],
		[formatf,ff_w,[`'Ill conditioned matrix!'`]]]],
	    [ dom , `i ` ,1,`kn `,1,[ equalf,`zdot(kn+i)`,`const(i,1)`]],
	    [ equalf, zdot(7),SSF[1,1]],
	    [ equalf, zdot(8),SSF[2,1]],
	    [returnf]]]:


Gener(`wheel.f`,flist):

#-----------------------------------------------------
# second routine wheelg(n,k,uf,vf,wf,xx)
# n,k integer 
# uf,vf,wf ==> matrices of size (n,k)
# xx solution of ode => matrix of size(8,k)
# This routines will computes the coordinates of trajectories of n-points 
# in the (x,y,z) space , givent their trajectories in the (u,v,w) space 
# xx(:,t) gives is the evolution of the wheel 
# uf,vf,wf : on entry the coordinates in the (u,v,w) space 
# uf,vf,wf : on output the coordinates in the (x,y,z) space 
#-----------------------------------------------------

ffvar:= {theta= xx[1,i2],phi=xx[2,i2],psi=xx[3,i2],t[1]=xx[4,i2],
	t[2]=xx[5,i2],t[3]=xx[6,i2],x=xx[7,i2],y=xx[8,i2],

	uf = uf[i1,i2],vf = vf[i1,i2] ,wf= wf[i1,i2] }:


Z:=multiply(R,vector([uf,vf,wf])):
Z:=matadd(vector([x,y,r*sin(phi)]),Z,1,r):
ZF:=subs(ffvar,eval(Z)):

fffvar:={ cos(xx[1,i2])=cs1,cos(xx[2,i2])=cs2,sin(xx[1,i2])=si1,sin(xx[2,i2])=si2}:
ZF:=subs(fffvar,eval(ZF)):

flist:=[subroutinem,`wheelg`,[`n,k,uf,vf,wf,xx`],
           [
            [ declaref,`implicit double precision`,[`(t)`] ],
            [ declaref,doubleprecision,[`uf(n,k),vf(n,k),wf(n,k)`]],
            [ declaref,doubleprecision,[`uu,vv,ww,r`]],
            [ declaref,integer,[`n,k,i1,i2`]],
            [ declaref,doubleprecision,[`xx(8,k)`]],
            [ declaref,`data r`,[`/ 1.0/`] ],
	    [ dom , `i1 ` ,1,`n `,1,[
		[ dom , `i2 ` ,1,`k `,1,
			[
			 op(map((x)-> [ equalf,rhs(x),lhs(x) ],fffvar)),
			 [ equalf,`uu`,ZF[1]],
			 [ equalf,`vv`,ZF[2]],
			 [ equalf,`ww`,ZF[3]],
			 [ equalf,`uf(i1,i2)`,`uu`],
			 [ equalf,`vf(i1,i2)`,`vv`],
			 [ equalf,`wf(i1,i2)`,`ww`]]]]],
	    [returnf]]]:


Gener(`wheelg.f`,flist):





