# -*- encoding=utf-8 -*-
# © Václav Šmilauer <eudoxos@arcig.cz>
#
# Test case for sphere-facet interaction preserving the original contact orientation.
# Z-gravity is being increased every 4000 iterations, the sphere dives more into the facet and stabilizes,
# etc. This process continues even if the sphere center passes on the other side of the facet and,
# (if distant transient interactions are allowed in the collider) if the sphere passes in its entirety to
# the other side of the facet. The interaction, however, still pushes in the same sense.
#
# After the gravity reaches some value, it is reset and the sphere should be pushed from the facet towards
# its original position. When the contact on the original side is lost, the interaction should be deleted.
#
#
# The only tunable sign places the sphere either on the top ot at the bottom of the facet
# and sets gravity accordingly. It can be +1 or -1
#
from __future__ import print_function
sign = -1
#

## PhysicalParameters
Young = 7e6
Poisson = 0.2
Density = 2700

# Append a material
mat = O.materials.append(FrictMat(young=Young, poisson=Poisson, density=Density, frictionAngle=radians(26)))

O.engines = [
        ForceResetter(),
        InsertionSortCollider([Bo1_Sphere_Aabb(), Bo1_Facet_Aabb()]),
        InteractionLoop(
                [Ig2_Facet_Sphere_ScGeom()],
                [Ip2_FrictMat_FrictMat_FrictPhys()],
                [Law2_ScGeom_FrictPhys_CundallStrack()],
        ),
        NewtonIntegrator(damping=.3, gravity=(0, 0, -10), label='integrator'),
        PyRunner(iterPeriod=4000, command='setGravity()'),
]
O.bodies.append(
        [
                facet([[-1, -1, 0], [1, -1, 0], [0, 1, 0]], fixed=True, color=[1, 0, 0], material=mat),
                sphere([0, 0, sign * .49999], radius=.5, wire=True, material=mat),
        ]
)
O.timingEnabled = True
O.saveTmp()
O.dt = 1e-4

print('** virgin dispatch matrix:')
O.engines[2].lawDispatcher.dispMatrix()
print('** class indices')
O.run(1000, True)
print('** used dispatch matrix')
O.engines[2].lawDispatcher.dispMatrix()


def setGravity():
	gz = integrator.gravity[2]
	integrator.gravity = [0, 0, 1.05 * gz]
	if abs(gz) >= 2500:
		print("Gravity reset & slow down")
		O.dt = 1e-6
		integrator.gravity = [0, 0, 0]
	if abs(gz) > 0:
		print(gz)


try:
	from yade import qt
	renderer = qt.Renderer()
	renderer.intrGeom = True
	qt.Controller()
except ImportError:
	pass

from yade import timing
O.run(100000, True)
timing.stats()
timing.reset()
O.loadTmp()
O.run(100000, True)
timing.stats()
