Microscopic models : granular and social force model

cromosim.micro.check_people_in_box(dom, box, xyrv, dest_names, rng, verbose=True)[source]

To check that people coordinates are in the given box (test 1) and in an usable space i.e. in an area accessible and not concerned by obstacles (test 2). On the other hand, one moves the individuals which do not satisfy these two tests.

Parameters
dom: Domain

contains everything for managing the domain

box: list

coordinates of the box [xmin, xmax, ymin, ymax]

xyrv: numpy array

people coordinates, radius and velocity coefficient: x,y,r,v

dest_names: numpy array

people destination names

rng: RandomState

scipy random state object (see scipy.random.RandomState)

verbose: boolean

logs for debug

Returns
xyrv: numpy array

new people coordinates x y r

cromosim.micro.compute_contacts(dom, xyrv, dmax)[source]

This function uses a KDTree method to find the contacts between individuals. Moreover the contacts with the walls are also determined from the wall distance (obtained by the fast-marching method).

Parameters
dom: Domain

contains everything for managing the domain

xyrv: numpy array

people coordinates, radius and velocity coefficient: x,y,r,v

dmax: float

threshold value used to consider a contact as active i.e. dij<dmax

Returns
contacts: numpy array

all the contacts i,j,dij,eij_x,eij_y such that dij<dmax and i<j (no duplication)

cromosim.micro.compute_forces(F, Fwall, xyrv, contacts, U, Vd, lambda_, delta, k, eta)[source]

This function computes all the forces (isentropic interaction and friction) and sums them. The correcting pre-factor due to the vision angle is also used into the social force term.

Parameters
F: float

social trend of an individual to keep apart from another (homogeneous to a force)

Fwall: float

social trend of an individual to keep apart from a wall (homogeneous to a force)

xyrv: numpy array

people coordinates, radius and velocity coefficient: x,y,r,v

contacts: numpy array

all the contacts: i,j,dij,eij_x,eij_y

U: numpy array

people velocities

Vd: numpy array

people desired velocities

lambda_: float

quantifies the directional dependence when the vision angle is considered (between [0,1], if equal to 1 the fully isotropic case is recovered)

delta: float

maintains a certain distance between neighbors

k: float

used when there is overlapping, k is a stiffness constant of individuals seen as deformable bodies

eta: float

friction coefficient

Returns
Forces: numpy array

sum of all forces for each individual

cromosim.micro.create_people_in_box(nn, box, dest_name, radius_distribution, velocity_distribution, dom, rng, verbose=True)[source]

To create nn persons in a given box. The overlaps are not treated for the moment but one checks that the individuals are located in an area where  the desired velocity is well defined (outside inaccessible areas or obstacles). If it is not the case, one changes their coordinates in consequence.

Parameters
nn: integer

number of individuals to create

box: list

coordinates of the box [xmin, xmax, ymin, ymax]

dest_name: string

destination name for all individuals in this group

radius_distribution: list

distribution with its parameters

velocity_distribution: list

distribution with its parameters

dom: Domain

contains everything for managing the domain

rng: RandomState

scipy random state object (see scipy.random.RandomState)

verbose: boolean

logs for debug

Returns
p: numpy array

new people coordinates, radius and velocity coefficient x y r v

dest_names: numpy array

people destination names

cromosim.micro.find_duplicate_people(all_people, domains)[source]

This function determines people who have to be duplicated due to their presence in transit boxes (in Destination object)

Parameters
all_people: dict
Has one dictionary "people" by domain which has at least:
  • "xyrv": people coordinates and radius

  • "destinations": destination for each individual

domains: dict

Contains all the Domain objets

Returns
virtual_people: dict

all duplicated people

cromosim.micro.move_people(time, dt, people, sensors)[source]

Updates the people positions according to the new velocities U. If there exists crosslines (i.e. sensors), computes also the id, time, direction and impact points for the individuals who cross the lines.

Parameters
time: float

current time

dt: float

time step

people: dict

dictionary containing everything related to individuals ("xyrv", "U",…)

sensors: dict

dictionary containing everything related to sensors ("line",…)

Returns
people: dict

dictionary updated with new people positions after moving

sensors: dict
dictionary enriched by:
  • "id": people id who cross the sensor lines

  • "times": times when people cross the sensor lines

  • "xy": impact points for people crossing the sensor lines

  • "dir": directions for people crossing the sensor lines (entry or exit)

cromosim.micro.people_initialization(dom, groups, dt, dmin_people=0, dmin_walls=0, seed=0, itermax=10, projection_method='cvxopt', verbose=True)[source]

To initialize people.

Parameters
dom: Domain

contains everything for managing the domain

groups: dict
contains all groups related to this domain. A group contains:
  • "nb": number of persons

  • "radius_distribution": ["uniform",min,max] or ["normal",mean,std_dev]

  • "velocity_distribution": ["uniform",min,max] or ["normal",mean,std_dev]

  • "box": [xmin,xmax,ymin,ymax]

  • "destination": initial destination

dt: float

time step

dmin_people: float

minimal distance allowed between individuals (0 by default)

dmin_walls: float

minimal distance allowed between an individual and a wall

seed: integer

seed to initialize the RandomState (0 by default means different seed at each run)

itermax: integer

maximal number of Uzawa projections (10 by default)

projection_method: string

optimizer name for the projection step: "cvxopt", "uzawa" or "mosek"

verbose: boolean

logs for debug

Returns
people: dict
people dictionary which contains:
  • "xyrv": coordinates, radius and velocity coefficient for each individual

  • "destinations": destination for each individual

  • "gpid": group id

rng: RandomState

scipy random state object (see scipy.random.RandomState)

cromosim.micro.people_update_destination(all_people, domains, thld, box=None)[source]

This function updates people destinations and domains

Parameters
all_people: dict
Has one dictionary "people" by domain which has at least:
  • "xyrv": people coordinates and radius

  • "destinations": destination for each individual

domains: dict

Contains all the Domain objets

thld: float

threshold value used to decide if an individual has reached its destination

box: numpy array

box used to remove people outside

Returns
all_people: dict

all people in all domains updated

cromosim.micro.plot_people(ifig, dom, people, contacts, colors, time=- 1, axis=None, virtual_people=None, plot_people=True, plot_contacts=True, plot_velocities=False, plot_desired_velocities=False, plot_paths=False, plot_sensors=False, sensors=[], savefig=False, filename='fig.png', dpi=150, cmap='winter')[source]

This function draws spheres for the individuals, lines for the active contacts and arrows for the (desired or real) velocities.

Parameters
ifig: int

figure number

dom: Domain

contains everything for managing the domain

people: dict

contains everything concerning people: x, y, r, v, U,...

contacts: numpy array

all the contacts: i, j, dij, eij_x, eij_y

colors: numpy array

scalar field used to define people colors

time: float

time in seconds

virtual_people: dict

contains everything concerning virtual people: x, y, r,...

axis: numpy array

matplotlib axis: [xmin, xmax, ymin, ymax]

plot_people: boolean

draws spheres for people if true

plot_paths: boolean

draws people paths if true

plot_sensors: boolean

draws sensor lines if true

sensors: numpy array

sensor line coordinates (see also the sensor function below)

savefig: boolean

writes the figure as a png file if true

filename: string

png filename used to write the figure

dpi: integer

number of pixel per inch for the saved figure

cmap: string

matplotlib colormap name

cromosim.micro.plot_sensors(ifig, sensors, time, flux_timestep=1, savefig=False, filename='fig.png', dpi=150, cmap='winter')[source]

This function traces, for each sensor, a graph with the passage times of the individuals crossing the counting line, as well as the incoming and outgoing flows.

Parameters
ifig: int

figure number

sensors: dict

contains for each sensor, the date, position and direction of an individual who cut the counting line

time: float

time in seconds

flux_timestep: float

timestep for the fluxes: number of persons per flux_timestep seconds

savefig: boolean

writes the figure as a png file if true

filename: string

png filename used to write the figure

dpi: integer

number of pixel per inch for the saved figure

cmap: string

matplotlib colormap name

cromosim.micro.projection(dt, xyrv, contacts, Vd, dmin_people=0, dmin_walls=0, nb_iter_max=100000, rho=0.1, tol=0.01, log=False, method='cvxopt')[source]

From the desired velocities Vd, this projection step consists of computing the global velocity field defined as the closest velocity to the desired one among all the feasible fields (i.e. fields which do not lead  to disks overlapping).

Parameters
dt: float

time step

xyrv: numpy array

people coordinates, radius and velocity coefficient: x,y,r,v

contacts: numpy array

all the contacts: i,j,dij,eij_x,eij_y

Vd: numpy array

people desired velocities

dmin_people: float

minimum distance guaranteed between individuals

dmin_walls: float

minimum distance guaranteed between an individual and a wall

nb_iter_max: integer

maximum number of iterations allowed

rho: float

parameter of the Uzawa method

tol: float

tolerance wished

log: boolean

to print the final accuracy, number of iterations,…

method: string

optimization algorithm: "cvxopt" (default) or "uzawa" (or "mosek" if installed with a license file).

Returns
info: integer

number of iterations needed

B: numpy array

constraint matrix

U: numpy array

new people velocities ensuring that there is no overlap between individuals

L: numpy array

Lagrange multipliers (only when method="uzawa", None otherwise)

P: numpy array

pressure on each individual (only when method="uzawa", None otherwise)

cromosim.micro.remove_overlaps_in_box(dom, box, xyrv, dest_names, dt, rng, projection_method='cvxopt', dmin_people=0, dmin_walls=0, itermax=10, verbose=True)[source]

To remove the overlaps between individuals (spheres) in the given box. Several projections are used to give a better robustness to this process when the number of overlaps is very high e.g. during the initialization when the individuals have random positions.

Parameters
dom: Domain

contains everything for managing the domain

box: list

coordinates of the box [xmin, xmax, ymin, ymax]

xyrv: numpy array

people coordinates x y, radius r and velocity coefficient v

dest_names: numpy array

people destination names

dt: float

time step

rng: RandomState

scipy random state object (see scipy.random.RandomState)

dmin_people: float

minimal distance allowed between individuals

dmin_walls: float

minimal distance allowed between an individual and a wall

itermax: integer

maximal number of Uzawa projections (10 by default)

verbose: boolean

logs for debug

Returns
xyrv: numpy array

new people coordinates x y, same radius r and velocity coefficient v

cromosim.micro.sensor(door, xy0, xy1, t0, t1)[source]

Compute the number of entries/exits through a door as a pedestrian sensor could do

Parameters
door: numpy array

door coordinates [x0,y0,x1,y1]

t0: float

time

t1: float

time

xy0: numpy array

people coordinates at time t0

xy1: numpy array

people coordinates at time t1

Returns
id: numpy array

index of persons who go through the door

p: numpy array

coordinates of intersection points between the door and people trajectories

io: numpy array

the exit direction is the normal direction, 1 = exit, -1 = entry

times: numpy array

exit or entry times

entries: int

number of entries

exits: int

number of exits