
     ij                     d    d Z ddlZddlZddlZddlZddlZddlZd Zd Z	d Z
d Zd Z	 	 dd
ZdS )a  Streamplots (3D) --- :mod:`MDAnalysis.visualization.streamlines_3D`
===================================================================

:Authors: Tyler Reddy and Matthieu Chavent
:Year: 2014
:Copyright: Lesser GNU Public License v2.1+


The :func:`generate_streamlines_3d` function can generate a 3D flow field from
a MD trajectory, for instance, lipid molecules in a virus capsid. It can make
use of multiple cores to perform the analyis in parallel (using
:mod:`multiprocessing`).

.. rubric: References

.. footbibliography::

See Also
--------
MDAnalysis.visualization.streamlines : streamplots in 2D


.. autofunction:: generate_streamlines_3d

    Nc                    t          j        | |          }|                    d          }|j        }|d                                         |d                                         |d                                         |d                                         |d                                         |d                                         g\  }}}}	}
}||z
  ||z   ||z
  |	|z   |
|z
  ||z   f}|S )a  Calculate the extent of the atom coordinates + buffer.

    A function for the parent process which should take the input trajectory
    and calculate the limits of the container for the system and return these
    limits.

    Parameters
    ----------
    topology_file_path : str
        topology file name
    trajectory_file_path : str
        trajectory file name
    buffer_value : float
        buffer value (padding) in +/- {x, y, z}
    all.r   .   .   )
MDAnalysisUniverseselect_atoms	positionsminmax)topology_file_pathtrajectory_file_pathbuffer_valueuniverse_objectall_atom_selectionall_atom_coordinate_arrayx_minx_maxy_miny_maxz_minz_maxtuple_of_limitss                q/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/MDAnalysis/visualization/streamlines_3D.pydetermine_container_limitsr   ;   s   $ !)0 O )55  !3 <!&)--//!&)--//!&)--//!&)--//!&)--//!&)--//0,E5%u 	O     c                 T    | \  }}}}}}t           j        |||||||||f         }|S )u  Produce a 3D grid for the simulation system.

    The partitioning is based on the tuple of Cartesian Coordinate limits
    calculated in an earlier step.

    Parameters
    ----------
    tuple_of_limits : tuple
        ``x_min, x_max, y_min, y_max, z_min, z_max``
    grid_spacing : float
        grid size in all directions in ångström

    Returns
    -------
    grid : array
        ``numpy.mgrid[x_min:x_max:grid_spacing, y_min:y_max:grid_spacing, z_min:z_max:grid_spacing]``

    )npmgrid)	r   grid_spacingr   r   r   r   r   r   grids	            r   produce_gridr%   g   sL    & 0?,E5%u8eL eL eL 	"D
 Kr   c           
         | \  }}}|j         d         }|j         d         }t          d |j         D                       }g }|D ]+}	|	                                }
|                    |
           ,g }|D ]+}|                                }|                    |           ,g }|D ]+}|                                }|                    |           ,g }t	          |||          D ]7\  }}}|                    t          t	          |||                               8t          j        |          }d}i }d}||dz
  k     r||         }||dz            }d}||j         d         |z
  k     rQd}||dz
  k     r0g }|||dz   df                                         }|||dz   df                                         }|||z   d|z   |z   df                                         } |||z   d|z   |z   df                                         }!||| |!fD ]}"|	                    |"           t          j        |          }#|#j         dk    s
J d            t          j
        t          j        |          d	          }$|$|d
||<   |dz  }|dz  }|dz  }||dz
  k    r|dz  }||dz
  k     0||j         d         |z
  k     Q|dz  }||dz
  k     t          |          }%t          j        d|%          }&t          j        |&|          }'g }(d})|'D ]n}*i }+t          |*          },d}-|-|,k     r9|                                \  }.}/|+                    |.|/i           |-dz  }-|-|,k     9|(                    |+           |)dz  })o|(|%||fS )a  Split the grid into blocks of vertices.

    Take the overall `grid` for the system and split it into lists of cube
    vertices that can be distributed to each core.

    Parameters
    ----------
    grid : numpy.array
        3D array
    num_cores : int
        number of partitions to generate

    Returns
    -------
    list_dictionaries_for_cores : list of dict
    total_cubes : int
    num_sheets : int
    delta_array_shape : tuple

    r   c                     g | ]}|d z
  S )r    ).0ns     r   
<listcomp>zsplit_grid.<locals>.<listcomp>   s       1Q   r   r   r	   .)      z vertex_array has incorrect shapeaxis)centroidvertex_list)shapetupleflattenappendziplistr!   arraytolistextendaveragelenarangearray_splitpopitemupdate)0r$   	num_coresxyznum_z_values
num_sheetsdelta_array_shapeordered_list_per_sheet_x_valuesx_sheet array_all_x_values_current_sheetordered_list_per_sheet_y_values	y_columns array_all_y_values_current_sheetordered_list_per_sheet_z_valuesz_slices array_all_z_values_current_sheet,ordered_list_cartesian_coordinates_per_sheetx_sheet_coordsy_sheet_coordsz_sheet_coords(array_ordered_cartesian_coords_per_sheetcurrent_base_sheet"dictionary_cubes_centroids_indicescube_countercurrent_base_sheet_arraycurrent_top_sheet_arraycurrent_indexcolumn_z_levelcurrent_list_cube_verticesfirst_two_vertices_base_sheetfirst_two_vertices_top_sheetnext_two_vertices_base_sheetnext_two_vertices_top_sheet
vertex_setvertex_arraycube_centroidtotal_cubespseudo_cube_indices sublist_of_cube_indices_per_corelist_dictionaries_for_coressubdictionary_counterarray_cube_indicescurrent_core_dictionaryitems_to_popitems_poppedkeyvalues0                                                   r   
split_gridrq      sR   , GAq!72;LJ       ')# 	

 
 ,3??+<+<('..,	
 	
 	
 	
 ')# 
 
	+4+<+<+>+>('..,	
 	
 	
 	
 ')# 
 
+3+;+;+=+=('..,	
 	
 	
 	
 460:='''; ; 
 
6
 	5;;^^^DDEE	
 	
 	
 	
 02x40 0, )+&L
zA~
-
-#K$
  #K"#
 6<Q?,NNN   !<!#333-/*0H!MA$55s:1&(( . 0G!MA$55s:0&(( - 0H!"#%&"&##&$$ 	0 &(( - /F!"#%&"&##&$$ 	/ &(( , 200/	# B BJ /55jAAAA!x(BCC#) .    6   !#
H788q! ! ! !.#=D D2<@ !"!#"lQ&666 "Q&Ma !<!#333 6<Q?,NNNn 	a zA~
-
-@ 899K )A{33')~Y( ($ #%> 	# 	#"$-..\));CCEEJC#**C<888AL \)) 	$**+BCCC"#	 r   c                 V   
 g }g }d 

fd}d }	 || |            |	||           |S )znRun the analysis on one core.

    The code to perform on a given core given the dictionary of cube data.
    c                 *   t          j        |          }t          j        j                            |d                                          dz  }t          j        j                            ||t           j        ddf                   }t           j	        
                    |                                |                                ddd           t          j        t          j        | |                    }|d         }t          j        ||k              }|d	         }	t          j        |	|k              }
|d
         }t          j        ||k              }t          j        |d         |
d                   }t          j        ||d                   }|S )z7Determine if an array of coordinates are within a cube.	euclidean       @Nr   ga2U0*#?zJnot all cube vertex to centroid distances are the same, so not a true cube)rtolatolerr_msgr   r   r   )r!   r9   scipyspatialdistancepdistr   cdistnewaxistestingassert_allcloser   absolutesubtractwhereintersect1d)array_point_coordinateslist_cube_verticesre   array_cube_verticescube_half_side_length)array_cube_vertex_distances_from_centroidabsolute_delta_coordsabsolute_delta_x_coordsindices_delta_x_acceptableabsolute_delta_y_coordsindices_delta_y_acceptableabsolute_delta_z_coordsindices_delta_z_acceptable!intersection_xy_acceptable_arrays&overall_indices_points_in_current_cubes                  r   point_in_cubez$per_core_work.<locals>.point_in_cube8  s    !h'9::M"((#[ cee 	 M"((#]2:qqq=%A  	2
 	
""599;;599;;! 	# 	
 	
 	
 !#K/??!
 !
 #8"?%'X#'<<&
 &
" #8"?%'X#'<<&
 &
" #8"?%'X#'<<&
 &
" -/N&q)+Ea+H-
 -
) 24-/I!/L2
 2
. 65r   c                     d}|                                 D ]b\  }} | |d         |d                   }||d<   t          |          dk    r"t          j        | |         d          }||d<   nd|d<   |dz  }cdS )	a=  Basically update the cube dictionary objects assigned to this core to contain a new key/value pair
        corresponding to the indices of the relevant particles that fall within a given cube. Also, for a given cube,
        store a key/value pair for the centroid of the particles that fall within the cube.
        r   r2   r1   start_frame_index_list_in_cuber/   !centroid_of_particles_first_frameNr   )itemsr=   r!   r<   )%array_simulation_particle_coordinatesdictionary_cube_data_this_corerY   ro   cubeindex_list_in_cubecentroid_particles_in_cuber   s          r   +update_dictionary_point_in_cube_start_framezBper_core_work.<locals>.update_dictionary_point_in_cube_start_framei  s     7==?? 	 	IC!.5]#Z " "
 6HD12&''!++-/Z9:LM. . .*
 / 899 =A89ALL'	 	r   c                 "   d}|                                 D ]w\  }}|d         d|d<   d|d<   d|d<   nU| |d                  }t          j        |d          }||d	<   ||d         z
  }|d         |d<   |d
         |d<   |d         |d<   |d
z  }xdS )zWUpdate the cube dictionary objects again as appropriate for the second and final frame.r   r   Ndxdydzr   r/    centroid_of_paticles_final_framer   r	   )r   r!   r<   )r   r   rY   ro   r   8new_coordinate_array_for_particles_starting_in_this_cube0new_centroid_for_particles_starting_in_this_cubedelta_centroid_array_this_cubes           r   update_dictionary_end_framez2per_core_work.<locals>.update_dictionary_end_frame  s     7==?? 	 	IC78@T
T
T

 :=> I
 DF:LD D D@
 E 78 E>?@ / <A>T
;A>T
;A>T
ALL5	 	r   r)   )start_frame_coord_arrayend_frame_coord_arrayr   MDA_selectionstart_frame	end_framelist_previous_frame_centroidslist_previous_frame_indicesr   r   r   s             @r   per_core_workr   (  s     %'!"$/6 /6 /6b    :  J 0/!?    =   *)r   c                     t          j        | |          }|                    |          }|j        D ]5}|j        |k    r n'|j        |k    r|j        }"|j        |k    r|j        }	56||	fS )a  Generate coordinate arrays.

    To reduce memory footprint produce only a single MDA selection and get
    desired coordinate arrays; can later send these coordinate arrays to all
    child processes rather than having each child process open a trajectory and
    waste memory.

    )r
   r   r   
trajectoryframer   )
r   r   r   r   r   r   relevant_particlests2start_frame_relevant_particle_coordinate_array_xyz0end_frame_relevant_particle_coordinate_array_xyzs
             r   (produce_coordinate_arrays_single_processr     s     !)0 O )55mDD(  8iE8{""", ?> X""", =< :8 r   ru   maximumc           
      B  " |dk    rt          j                    }n|}t          j        dd           i ""fd}||||	|
|f}t	          ||          }t          ||          \  }}}}t          | ||||          \  }}t          j        |          }|D ]%}|                    t          ||||||f|           &|
                                 |                                 t          t          |          t          |d	z
            z            }t          j        |          }t          j        |          }t          j        |          }d
}d
}d
}d
} t          d
|          D ]r}!"|!         d         ||||f<   "|!         d         ||||f<   "|!         d         ||||f<   |d	z  }| d	z  } ||d         k    rd
}|d	z  }||d	         k    r|d	z  }d
}d
}d
} sd|t!          |          |k    <   d|t!          |          |k    <   d|t!          |          |k    <   |||fS )a  Produce the x, y and z components of a 3D streamplot data set.

    Parameters
    ----------
    topology_file_path : str
            Absolute path to the topology file
    trajectory_file_path : str
            Absolute path to the trajectory file. It will normally be desirable
            to filter the trajectory with a tool such as GROMACS
            :program:`g_filter` (see :footcite:p:`Chavent2014`)
    grid_spacing : float
            The spacing between grid lines (angstroms)
    MDA_selection : str
            MDAnalysis selection string
    start_frame : int
            First frame number to parse
    end_frame : int
            Last frame number to parse
    xmin : float
            Minimum coordinate boundary for x-axis (angstroms)
    xmax : float
            Maximum coordinate boundary for x-axis (angstroms)
    ymin : float
            Minimum coordinate boundary for y-axis (angstroms)
    ymax : float
            Maximum coordinate boundary for y-axis (angstroms)
    maximum_delta_magnitude : float
            Absolute value of the largest displacement tolerated for the
            centroid of a group of particles ( angstroms). Values above this
            displacement will not count in the streamplot (treated as
            excessively large displacements crossing the periodic boundary)
    num_cores : int or 'maximum' (optional)
            The number of cores to use. (Default 'maximum' uses all available
            cores)

    Returns
    -------
    dx_array : array of floats
            An array object containing the displacements in the x direction
    dy_array : array of floats
            An array object containing the displacements in the y direction
    dz_array : array of floats
            An array object containing the displacements in the z direction

    Examples
    --------
    Generate 3D streamlines and visualize in `mayavi`_::

        import numpy as np

        import MDAnalysis
        import MDAnalysis.visualization.streamlines_3D

        import mayavi, mayavi.mlab

        # assign coordinate system limits and grid spacing:
        x_lower,x_upper = -8.73, 1225.96
        y_lower,y_upper = -12.58, 1224.34
        z_lower,z_upper = -300, 300
        grid_spacing_value = 20

        x1, y1, z1 = MDAnalysis.visualization.streamlines_3D.generate_streamlines_3d(
                        'testing.gro', 'testing_filtered.xtc',
                         xmin=x_lower, xmax=x_upper,
                         ymin=y_lower, ymax=y_upper,
                         zmin=z_lower, zmax=z_upper,
                         grid_spacing=grid_spacing_value, MDA_selection = 'name PO4',
                         start_frame=2, end_frame=3, num_cores='maximum')

        x, y, z = np.mgrid[x_lower:x_upper:x1.shape[0]*1j,
                          y_lower:y_upper:y1.shape[1]*1j,
                          z_lower:z_upper:z1.shape[2]*1j]

        # plot with mayavi:
        fig = mayavi.mlab.figure(bgcolor=(1.0, 1.0, 1.0), size=(800, 800), fgcolor=(0, 0, 0))
        for z_value in np.arange(z_lower, z_upper, grid_spacing_value):
            st = mayavi.mlab.flow(x, y, z, x1, y1, z1, line_width=1,
                                  seedtype='plane', integration_direction='both')
            st.streamline_type = 'tube'
            st.tube_filter.radius = 2
            st.seed.widget.origin = np.array([ x_lower,  y_upper,   z_value])
            st.seed.widget.point1 = np.array([ x_upper, y_upper,  z_value])
            st.seed.widget.point2 = np.array([ x_lower, y_lower,  z_value])
            st.seed.widget.resolution = int(x1.shape[0])
            st.seed.widget.enabled = False
        mayavi.mlab.axes(extent = [0, 1200, 0, 1200, -300, 300])
        fig.scene.z_plus_view()
        mayavi.mlab.savefig('test_streamplot_3D.png')
        # more compelling examples can be produced for vesicles and other spherical systems

    .. image:: test_streamplot_3D.png

    See Also
    --------
    MDAnalysis.visualization.streamlines.generate_streamlines


    .. _mayavi: http://docs.enthought.com/mayavi/mayavi/
    r   warnraise)r   overc                 2                         |            d S )N)rA   )process_dictparent_cube_dictionarys    r   log_result_to_parentz5generate_streamlines_3d.<locals>.log_result_to_parentW  s    %%l33333r   )r   r#   )r$   rB   )argscallbackr   r   r   r   r   r	   g      ?)multiprocessing	cpu_countr!   seterrr%   rq   r   Poolapply_asyncr   closejoinintfloatzerosrangeabs)#r   r   r#   r   r   r   xminxmaxyminymaxzminzmaxmaximum_delta_magnituderB   r   r   r$   ri   rf   rG   rH   r   r   poolsub_dictionary_of_cube_datacubes_per_sheetdx_arraydy_arraydz_arraycurrent_sheety_index_current_sheetz_index_current_columntotal_cubes_current_sheetcube_numberr   s#                                     @r   generate_streamlines_3dr     s   h I#-//			I&w''''4 4 4 4 4 T4tT:O 'l  D
 		222 Lj:K
 	1 	
 	
 32 	**D'B 
 
#'%+ * 	 	
 	
 	
 	
 	JJLLLIIKKK %,,uZ!^/D/DDEEOx)**Hx)**Hx)**HM !Q,, . . #;/5 	02HH	

 #;/5 	02HH	

 #;/5 	02HH	
 	!#!Q&!!%6q%999%&"!Q&!%):1)==="()%)*&,-) :=HS]]5569<HS]]5569<HS]]556h))r   )ru   r   )__doc__r   numpyr!   numpy.testingry   scipy.spatial.distancer
   r   r%   rq   r   r   r   r)   r   r   <module>r      s   0 2                     ) ) )X  8b b bJI* I* I*X$ $ $h  R* R* R* R* R* R*r   