o
    Ďi                     @   sf   d Z dZddlZddlZddlZddlmZ dd Z	dd Z
d	d
 ZG dd deZG dd dZdS )z A Parallelised Implementation of K-D Trees

Code extended from http://folk.uio.no/sturlamo/python/multiprocessing-tutorial.pdf
zAjay Thampi    N)cKDTreec                 C   s   t |  S )z_
    Function that converts a shared memory array (multiprocessing.Array) to a numpy array
    )np
frombufferget_obj)shmem_array r   W/home/jeff/fluffinator/venv/lib/python3.10/site-packages/reverse_geocoder/cKDTree_MP.pyshmem_as_nparray   s   r	   c                 C   s   zgt |||f}t |||f}t |||	f}t |||	f}t||d}| D ]7}|j||ddf |	|
||d\}}|jd }|jd }||d||d||ddf< ||ddf< q-W dS    | jd7  _Y dS )zi
    Function that parallelly queries the K-D tree based on chunks of data returned by the scheduler
    leafsizeN)kepspdistance_upper_boundr      )r	   reshaper   queryshapevalue)	schedulerdatandatandimr   xnxdir   r   r   dubierr_data_x_d_ikdtreesd_outi_outm_dm_ir   r   r   _pquery   s   $

4r)   c                   C   s    zt  W S  ty   Y dS w )z
    Function to get the number of CPUs / cores. This is used to determine the number of processes to spawn.
    Default (if not implemented) = 2
       )mp	cpu_countNotImplementedErrorr   r   r   r   num_cpus&   s
   
r.   c                       s6   e Zd ZdZd
 fdd	Zdddejfdd	Z  ZS )
cKDTree_MPz) 
    The parallelised cKDTree class
       c                    sn   t |}|j\}}ttj|| | _t| j	||f}||ddddf< || _
tt| j||d dS )zX Class Instantiation
        Arguments are based on scipy.spatial.cKDTree class
        Nr
   )r   arrayr   r+   Arrayctypesc_double
shmem_datar	   r   	_leafsizesuperr/   __init__)self	data_listr   r   nmr   	__class__r   r   r8   4   s   

zcKDTree_MP.__init__r   r   r*   c                    sN  t |}|j\}}ttj|| }	ttj|| }
ttj|| }t|	||f}t|
||f}t|}|dkrF|||f}||ddddf< t	 }t
||}ttjd}|| j| j| j| j|	||
||||||f  fddt|D }|D ]}|  q|D ]}|  q|jdkrtd|j | |t fS )z;
        Function to parallelly query the K-D Tree
        r   Nr   c                    s   g | ]	}t jt d qS ))targetargs)r+   Processr)   ).0_
query_argsr   r   
<listcomp>`   s    z%cKDTree_MP.pquery.<locals>.<listcomp>z%d errors in worker processes)r   r1   r   r+   r2   r3   r4   r	   r   r.   	SchedulerValuec_intr5   r;   r<   r   rangestartjoinr   RuntimeErrorcopyastypeint)r9   x_listr   r   r   r   r   r   mxshmem_xshmem_dshmem_ir    r!   r"   nprocsr   r   poolr   rD   r   pqueryB   s4   



zcKDTree_MP.pquery)r0   )	__name__
__module____qualname____doc__r8   r   infrX   __classcell__r   r   r=   r   r/   0   s    r/   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )rG   z
    Scheduler that returns chunks of data to be queries on the K-D Tree.
    The number of chunks is determined by the number of processes.
    c                 C   sL   t tj|| _t tjd| _t  | _|| }|dkr|n|}|| _d S )Nr   r*   )	r+   RawValuer3   rI   _ndata_startLock_lock_chunk)r9   r   rV   	min_chunkr   r   r   r8   m   s   

zScheduler.__init__c                 C   s   | S )Nr   )r9   r   r   r   __iter__u   s   zScheduler.__iter__c                 C      | j   | jj}| jj}| j}|r=||kr!|}|| }d| j_n|}|| }|| | j_|| | j_| j   t||S | j   tNr   	rc   acquirer`   r   ra   rd   releasesliceStopIterationr9   r   rK   chunk_s0_s1r   r   r   nextx   "   




zScheduler.nextc                 C   rg   rh   ri   rn   r   r   r   __next__   rs   zScheduler.__next__N)rY   rZ   r[   r\   r8   rf   rr   rt   r   r   r   r   rG   h   s    rG   )r\   
__author__numpyr   multiprocessingr+   r3   scipy.spatialr   r	   r)   r.   r/   rG   r   r   r   r   <module>   s    
8