LCOV - code coverage report
Current view: top level - contour - FindContour.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 56 58 96.6 %
Date: 2024-10-18 14:00:25 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-2020 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "FindContour.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "core/PlumedMain.h"
      25             : 
      26             : //+PLUMEDOC GRIDANALYSIS FIND_CONTOUR
      27             : /*
      28             : Find an isocontour in a smooth function.
      29             : 
      30             : As discussed in the part of the manual on \ref Analysis PLUMED contains a number of tools that allow you to calculate
      31             : a function on a grid.  The function on this grid might be a \ref HISTOGRAM as a function of a few collective variables
      32             : or it might be a phase field that has been calculated using \ref MULTICOLVARDENS.  If this function has one or two input
      33             : arguments it is relatively straightforward to plot the function.  If by contrast the data has a three or more dimensions
      34             : it can be difficult to visualize.
      35             : 
      36             : This action provides one tool for visualizing these functions.  It can be used to search for a set of points on a contour
      37             : where the function takes a particular values.  In other words, for the function \f$f(x,y)\f$ this action would find a set
      38             : of points \f$\{x_c,y_c\}\f$ that have:
      39             : 
      40             : \f[
      41             : f(x_c,y_c) - c = 0
      42             : \f]
      43             : 
      44             : where \f$c\f$ is some constant value that is specified by the user.  The points on this contour are detected using a variant
      45             : on the marching squares or marching cubes algorithm, which you can find information on here:
      46             : 
      47             : https://en.wikipedia.org/wiki/Marching_squares
      48             : https://en.wikipedia.org/wiki/Marching_cubes
      49             : 
      50             : As such, and unlike \ref FIND_CONTOUR_SURFACE or \ref FIND_SPHERICAL_CONTOUR, the function input to this action can have any dimension.
      51             : Furthermore, the topology of the contour will be determined by the algorithm and does not need to be specified by the user.
      52             : 
      53             : \par Examples
      54             : 
      55             : The input below allows you to calculate something akin to a Willard-Chandler dividing surface \cite wcsurface.
      56             : The simulation cell in this case contains a solid phase and a liquid phase.  The Willard-Chandler surface is the
      57             : surface that separates the parts of the box containing the solid from the parts containing the liquid.  To compute the position
      58             : of this surface  the \ref FCCUBIC symmetry function is calculated for each of the atoms in the system from on the geometry of the
      59             : atoms in the first coordination sphere of each of the atoms.  These quantities are then transformed using a switching function.
      60             : This procedure generates a single number for each atom in the system and this quantity has a value of one for atoms that are in
      61             : parts of the box that resemble the solid structure and zero for atoms that are in parts of the box that resemble the liquid.
      62             : The position of a virtual atom is then computed using \ref CENTER_OF_MULTICOLVAR and a phase field model is constructed using
      63             : \ref MULTICOLVARDENS.  These procedure ensures that we have a continuous function that gives a measure of the average degree of
      64             : solidness at each point in the simulation cell.  The Willard-Chandler dividing surface is calculated by finding a a set of points
      65             : at which the value of this phase field is equal to 0.5.  This set of points is output to file called mycontour.dat.  A new contour
      66             : is found on every single step for each frame that is read in.
      67             : 
      68             : \plumedfile
      69             : UNITS NATURAL
      70             : FCCUBIC ...
      71             :   SPECIES=1-96000 SWITCH={CUBIC D_0=1.2 D_MAX=1.5}
      72             :   ALPHA=27 PHI=0.0 THETA=-1.5708 PSI=-2.35619 LABEL=fcc
      73             : ... FCCUBIC
      74             : 
      75             : tfcc: MTRANSFORM_MORE DATA=fcc LOWMEM SWITCH={SMAP R_0=0.5 A=8 B=8}
      76             : center: CENTER_OF_MULTICOLVAR DATA=tfcc
      77             : 
      78             : dens: MULTICOLVARDENS ...
      79             :   DATA=tfcc ORIGIN=center DIR=xyz
      80             :   NBINS=80,80,80 BANDWIDTH=1.0,1.0,1.0 STRIDE=1 CLEAR=1
      81             : ...
      82             : 
      83             : FIND_CONTOUR GRID=dens CONTOUR=0.5 FILE=mycontour.xyz
      84             : \endplumedfile
      85             : 
      86             : */
      87             : //+ENDPLUMEDOC
      88             : 
      89             : namespace PLMD {
      90             : namespace contour {
      91             : 
      92             : PLUMED_REGISTER_ACTION(FindContour,"FIND_CONTOUR")
      93             : 
      94           5 : void FindContour::registerKeywords( Keywords& keys ) {
      95           5 :   ContourFindingBase::registerKeywords( keys ); ActionWithValue::useCustomisableComponents(keys);
      96             : // We want a better way of doing this bit
      97          10 :   keys.add("compulsory","BUFFER","0","number of buffer grid points around location where grid was found on last step.  If this is zero the full grid is calculated on each step");
      98           5 : }
      99             : 
     100           2 : FindContour::FindContour(const ActionOptions&ao):
     101             :   Action(ao),
     102           2 :   ContourFindingBase(ao)
     103             : {
     104           2 :   parse("BUFFER",gbuffer);
     105           2 :   if( gbuffer>0 ) log.printf("  after first step a subset of only %u grid points around where the countour was found will be checked\n",gbuffer);
     106           2 :   checkRead();
     107             : 
     108           2 :   gridtools::ActionWithGrid* ag=dynamic_cast<gridtools::ActionWithGrid*>( getPntrToArgument(0)->getPntrToAction() );
     109           2 :   std::vector<std::string> argn( ag->getGridCoordinateNames() );
     110             : 
     111           2 :   std::vector<unsigned> shape(1); shape[0]=0;
     112           8 :   for(unsigned i=0; i<argn.size(); ++i ) {
     113           6 :     addComponent( argn[i], shape ); componentIsNotPeriodic( argn[i] ); getPntrToComponent(i)->buildDataStore();
     114             :   }
     115             :   // Check for task reduction
     116           2 :   updateTaskListReductionStatus();
     117           2 : }
     118             : 
     119           3 : std::string FindContour::getOutputComponentDescription( const std::string& cname, const Keywords& keys ) const {
     120           6 :   return "a vector of coordinates for the contour along the " + cname + " direction";
     121             : }
     122             : 
     123           1 : void FindContour::setupValuesOnFirstStep() {
     124           1 :   std::vector<unsigned> shape(1); shape[0] = getPntrToArgument(0)->getRank()*getPntrToArgument(0)->getNumberOfValues();
     125           4 :   for(unsigned i=0; i<getNumberOfComponents(); ++i) getPntrToComponent(i)->setShape( shape );
     126           1 :   active_cells.resize( shape[0] );
     127           1 : }
     128             : 
     129           0 : unsigned FindContour::getNumberOfDerivatives() {
     130           0 :   return 0;
     131             : }
     132             : 
     133           2 : void FindContour::areAllTasksRequired( std::vector<ActionWithVector*>& task_reducing_actions ) {
     134           2 :   task_reducing_actions.push_back(this);
     135           2 : }
     136             : 
     137           2 : void FindContour::getNumberOfTasks( unsigned& ntasks ) {
     138           2 :   ntasks = active_cells.size();
     139             : 
     140             :   Value* gval=getPntrToArgument(0);
     141           2 :   unsigned npoints = gval->getNumberOfValues();
     142           2 :   std::vector<unsigned> ind( gval->getRank() );
     143           2 :   std::vector<unsigned> ones( gval->getRank(), 1 );
     144           2 :   std::vector<unsigned> nbin( getInputGridObject().getNbin( false ) );
     145             :   unsigned num_neighbours; std::vector<unsigned> neighbours;
     146             : 
     147             :   std::fill( active_cells.begin(), active_cells.end(), 0 );
     148       10978 :   for(unsigned i=0; i<npoints; ++i) {
     149             :     // Get the index of the current grid point
     150       10976 :     getInputGridObject().getIndices( i, ind );
     151       10976 :     getInputGridObject().getNeighbors( ind, ones, num_neighbours, neighbours );
     152             :     // Get the value of a point on the grid
     153       10976 :     double val1=gval->get( i ) - contour;
     154             :     bool edge=false;
     155       43904 :     for(unsigned j=0; j<gval->getRank(); ++j) {
     156             :       // Make sure we don't search at the edge of the grid
     157       32928 :       if( !getInputGridObject().isPeriodic(j) && (ind[j]+1)==nbin[j] ) continue;
     158       32928 :       else if( (ind[j]+1)==nbin[j] ) { edge=true; ind[j]=0; }
     159       30968 :       else ind[j]+=1;
     160       32928 :       double val2=gval->get( getInputGridObject().getIndex(ind) ) - contour;
     161       32928 :       if( val1*val2<0 ) active_cells[gval->getRank()*i + j] = 1;
     162       32928 :       if( getInputGridObject().isPeriodic(j) && edge ) { edge=false; ind[j]=nbin[j]-1; }
     163       30968 :       else ind[j]-=1;
     164             :     }
     165             :   }
     166           2 : }
     167             : 
     168       32928 : int FindContour::checkTaskStatus( const unsigned& taskno, int& flag ) const {
     169       32928 :   if( active_cells[taskno]>0 ) return 1;
     170             :   return 0;
     171             : }
     172             : 
     173        1108 : void FindContour::performTask( const unsigned& current, MultiValue& myvals ) const {
     174             :   // Retrieve the initial grid point coordinates
     175        1108 :   unsigned gpoint = std::floor( current / getPntrToArgument(0)->getRank() );
     176        1108 :   std::vector<double> point( getPntrToArgument(0)->getRank() );
     177        1108 :   getInputGridObject().getGridPointCoordinates( gpoint, point );
     178             : 
     179             :   // Retrieve the direction we are searching for the contour
     180        1108 :   unsigned gdir = current%(getPntrToArgument(0)->getRank() );
     181        1108 :   std::vector<double> direction( getPntrToArgument(0)->getRank(), 0 );
     182        1108 :   direction[gdir] = 0.999999999*getInputGridObject().getGridSpacing()[gdir];
     183             : 
     184             :   // Now find the contour
     185             :   findContour( direction, point );
     186             :   // And transfer to the store data vessel
     187        4432 :   for(unsigned i=0; i<getPntrToArgument(0)->getRank(); ++i) myvals.setValue( getConstPntrToComponent(i)->getPositionInStream(), point[i] );
     188        1108 : }
     189             : 
     190             : }
     191             : }

Generated by: LCOV version 1.16