# -*- encoding=utf-8 -*-
# 2020 (c) Vasileios Angelidakis <v.angelidakis2@ncl.ac.uk>

# Collapse of a zero-porosity packing of cuboidal blocks in a Jenga-like tower, using the Potential Blocks.

recordVTK=False
# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
if recordVTK:
	# Create vtk directory
	import os
	import errno
	try:
		os.mkdir('./vtk/')
	except OSError as exc:
		if exc.errno != errno.EEXIST:
			raise
		pass

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Contact stiffnesses and Engines
kn=1e7
ks=kn/1.5
kn_i=5*kn
ks_i=5*ks

init=1e-6 # initial overlap distance

O.engines=[
	ForceResetter(),
	InsertionSortCollider([PotentialBlock2AABB()],verletDist=0.00), #0.01
	InteractionLoop(
		[Ig2_PB_PB_ScGeom(calContactArea=True)],
		[Ip2_FrictMat_FrictMat_KnKsPBPhys(kn_i=kn_i,ks_i=ks_i,Knormal=kn,Kshear=ks,viscousDamping=0.00)],
		[Law2_SCG_KnKsPBPhys_KnKsPBLaw(initialOverlapDistance=init,allowViscousAttraction=False,label='law')]
	),
	NewtonIntegrator(damping=0.1,exactAsphericalRot=True,gravity=[0,0,-9.81],label='newton'),
]

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Material
O.materials.append(FrictMat(young=-1,poisson=-1,frictionAngle=radians(10.0),density=400,label='frictional')) 

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Generate building blocks
length = 0.075 #m = 7.5cm
width  = 0.025 #m = 2.5cm
height = 0.015 #m = 1.5cm

# Piece blocks into a tower
for i in range(0,18): #18 layers
	for j in range(0,3): #3 pieces per layer
		r=0.5*width/2.
		b=Body()
		b.aspherical=True
		color=Vector3(random.random(),random.random(),random.random())
		b.shape=PotentialBlock(r=r, R=0.0, a=[1,-1,0,0,0,0], b=[0,0,1,-1,0,0], c=[0,0,0,0,1,-1], d=[length/2.-r+init,length/2.-r+init,width/2.-r+init,width/2.-r+init,height/2.-r+init,height/2.-r+init], isBoundary=False, color=color, AabbMinMax=True, fixedNormal=False)
		utils._commonBodySetup(b, b.shape.volume, b.shape.inertia, material='frictional',pos=[0,0,0], fixed=False)
		if (i % 2) == 0:
			b.state.pos = [0, width*j-width, height/2.+height*i]
			b.state.ori = b.shape.orientation
		else:
			b.state.pos = [width*j-width, 0, height/2.+height*i]
			b.state.ori = Quaternion((0,0,1),radians(90))
		O.bodies.append(b)

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Move block 10 on top
O.bodies[10].state.pos=[0, width*2-width, height/2.+height*18]
O.bodies[10].state.ori = O.bodies[10].shape.orientation

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Generate fixed plate
width = 5 * length #half width
thickness = 0.3 * length
r = 0.5 * thickness

bbb=Body()
bbb.shape=PotentialBlock(r=r, R=0.0, a=[1,-1,0,0,0,0], b=[0,0,1,-1,0,0], c=[0,0,0,0,1,-1], d=[width/2.-r,width/2.-r,width/2.-r,width/2.-r,thickness/2.-r,thickness/2.-r], id=len(O.bodies), isBoundary=True, color=[0,0.5,1], AabbMinMax=True, wire=False, fixedNormal=True, boundaryNormal=[0,0,1])
utils._commonBodySetup(bbb, bbb.shape.volume, bbb.shape.inertia, material='frictional', pos=[0,0,-thickness/2.], fixed=True)
O.bodies.append(bbb)

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Visualisation
from yade import qt
qt.Controller()
v=qt.View()

v.eyePosition=Vector3(1.3*width,-1.3*width,1.5*length)
v.upVector=Vector3(0,0,1)
v.viewDir=Vector3(-sqrt(2)/2,sqrt(2)/2,0)

v.ortho=False
v.sceneRadius=width

rndr=yade.qt.Renderer()
rndr.lightPos*=-1

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Timestep
#O.dt = sqrt(0.3*O.bodies[0].state.mass/kn)
O.dt=5e-5

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
# Pull block 11 along its long axis
O.engines=O.engines+[TranslationEngine(ids=[11],translationAxis=[0,1,0],velocity=5,label='tEngine')]

# Bring block 11 on top, once removed
def bringOnTop():
	if O.bodies[11].state.pos[1]>length:
		tEngine.dead=True
		O.bodies[11].state.vel=[0,0,0]
		O.bodies[11].state.pos=[0, width*1-width, height/2.+height*18]
		O.bodies[11].state.ori = O.bodies[11].shape.orientation
		bOT.dead=True
		eFP.dead=False

O.engines=O.engines+[PyRunner(iterPeriod=1,command='bringOnTop()',label='bOT')]


def eraseFallenParticles():
	for b in O.bodies:
		if sqrt(b.state.pos[0]**2+b.state.pos[1]**2)>2*length:
			O.bodies.erase(b.id)
O.engines=O.engines+[PyRunner(iterPeriod=500,command='eraseFallenParticles()',dead=True,label='eFP')]

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
if recordVTK:
	# Take snapshots
#	O.engines=O.engines+[SnapshotEngine(iterPeriod=100,fileBase='vtk/jenga-',firstIterRun=10,label='snapshooter')]

	# Export VTK results
	from yade import export
	vtkExporter = export.VTKExporter('./vtk/jengaTowerExample')

	def vtkExport():
		vtkExporter.exportPotentialBlocks(what=dict(n='b.id'))

	O.engines=O.engines+[PyRunner(iterPeriod=500,command='vtkExport()')]

# ────────────────────────────────────────────────────────────────────────────────────────────────────────── #
O.saveTmp()
O.run()

