LCOV - code coverage report
Current view: top level - matrixtools - TransposeMatrix.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 77 92 83.7 %
Date: 2025-04-08 21:11:17 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-2017 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 "MatrixOperationBase.h"
      23             : #include "core/ActionRegister.h"
      24             : 
      25             : //+PLUMEDOC MCOLVAR TRANSPOSE
      26             : /*
      27             : Calculate the transpose of a matrix
      28             : 
      29             : This action takes a matrix in input and calculates the input matrix's [tranpose](https://en.wikipedia.org/wiki/Transpose).
      30             : The following example shows how you can use this to calculate coordination numbers of species A with species B and vice
      31             : versa.
      32             : 
      33             : ```plumed
      34             : # Calculate the contact matrix between the two groups
      35             : c1: CONTACT_MATRIX GROUPA=1-10 GROUPB=11-30 SWITCH={RATIONAL R_0=0.1}
      36             : # Calculate the cooordination numbers for the atoms in group A by multiplying by a vector of ones
      37             : onesB: ONES SIZE=20
      38             : coordA: MATRIX_VECTOR_PRODUCT ARG=c1,onesB
      39             : # Transpose the contact matrix
      40             : c1T: TRANSPOSE ARG=c1
      41             : # Calculate the coordination number for the atoms in group B by multiplying the transpose by a vector of ones
      42             : onesA: ONES SIZE=10
      43             : coordB: MATRIX_VECTOR_PRODUCT ARG=c1T,onesA
      44             : # Output the two vectors of coordination numbers to a file
      45             : PRINT ARG=coordA,coordB FILE=colvar
      46             : ```
      47             : 
      48             : Another useful example where the transpose can be used is shown below.  In this input the [DISTANCE](DISTANCE.md) command
      49             : is used to calculate the orientation of a collection of molecules.  We then can then use the [VSTACK](VSTACK.md), TRANSPOSE and the
      50             : [MATRIX_PRODUCT](MATRIX_PRODUCT.md) commands to calculate the dot products between all these vectors
      51             : 
      52             : ```plumed
      53             : # Calculate the vectors connecting these three pairs of atoms
      54             : d: DISTANCE COMPONENTS ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6
      55             : # Construct a matrix that contains all the components of the vectors calculated
      56             : v: VSTACK ARG=d.x,d.y,d.z
      57             : # Transpose v
      58             : vT: TRANSPOSE ARG=v
      59             : # And now calculate the 3x3 matrix of dot products
      60             : m: MATRIX_PRODUCT ARG=v,vT
      61             : # And output the matrix product to a file
      62             : PRINT ARG=m FILE=colvar
      63             : ```
      64             : 
      65             : */
      66             : //+ENDPLUMEDOC
      67             : 
      68             : namespace PLMD {
      69             : namespace matrixtools {
      70             : 
      71             : class TransposeMatrix : public MatrixOperationBase {
      72             : public:
      73             :   static void registerKeywords( Keywords& keys );
      74             : /// Constructor
      75             :   explicit TransposeMatrix(const ActionOptions&);
      76             : ///
      77         256 :   unsigned getNumberOfDerivatives() override {
      78         256 :     return 0;
      79             :   }
      80             : ///
      81             :   void prepare() override ;
      82             : ///
      83             :   void calculate() override ;
      84             : ///
      85             :   void apply() override ;
      86             : ///
      87             :   double getForceOnMatrixElement( const unsigned& jrow, const unsigned& krow ) const override;
      88             : };
      89             : 
      90             : PLUMED_REGISTER_ACTION(TransposeMatrix,"TRANSPOSE")
      91             : 
      92         279 : void TransposeMatrix::registerKeywords( Keywords& keys ) {
      93         279 :   MatrixOperationBase::registerKeywords( keys );
      94         558 :   keys.addInputKeyword("compulsory","ARG","vector/matrix","the label of the vector or matrix that should be transposed");
      95         558 :   keys.setValueDescription("vector/matrix","the transpose of the input matrix");
      96         279 : }
      97             : 
      98         162 : TransposeMatrix::TransposeMatrix(const ActionOptions& ao):
      99             :   Action(ao),
     100         162 :   MatrixOperationBase(ao) {
     101         162 :   if( getPntrToArgument(0)->isSymmetric() ) {
     102           0 :     error("input matrix is symmetric.  Transposing will achieve nothing!");
     103             :   }
     104             :   std::vector<unsigned> shape;
     105         162 :   if( getPntrToArgument(0)->getRank()==0 ) {
     106           0 :     error("transposing a scalar?");
     107         162 :   } else if( getPntrToArgument(0)->getRank()==1 ) {
     108          17 :     shape.resize(2);
     109          17 :     shape[0]=1;
     110          17 :     shape[1]=getPntrToArgument(0)->getShape()[0];
     111         145 :   } else if( getPntrToArgument(0)->getShape()[0]==1 ) {
     112          61 :     shape.resize(1);
     113          61 :     shape[0] = getPntrToArgument(0)->getShape()[1];
     114             :   } else {
     115          84 :     shape.resize(2);
     116          84 :     shape[0]=getPntrToArgument(0)->getShape()[1];
     117          84 :     shape[1]=getPntrToArgument(0)->getShape()[0];
     118             :   }
     119         162 :   addValue( shape );
     120         162 :   if( getPntrToArgument(0)->isPeriodic() ) {
     121             :     std::string smin, smax;
     122          24 :     getPntrToArgument(0)->getDomain( smin, smax );
     123          24 :     setPeriodic( smin, smax );
     124             :   } else {
     125         138 :     setNotPeriodic();
     126             :   }
     127         162 :   getPntrToComponent(0)->buildDataStore();
     128         162 :   if( shape.size()==2 ) {
     129         101 :     getPntrToComponent(0)->reshapeMatrixStore( shape[1] );
     130             :   }
     131         162 : }
     132             : 
     133        4821 : void TransposeMatrix::prepare() {
     134        4821 :   Value* myval = getPntrToComponent(0);
     135             :   Value* myarg = getPntrToArgument(0);
     136        4821 :   if( myarg->getRank()==1 ) {
     137         586 :     if( myval->getShape()[0]!=1 || myval->getShape()[1]!=myarg->getShape()[0] ) {
     138           6 :       std::vector<unsigned> shape(2);
     139           6 :       shape[0] = 1;
     140           6 :       shape[1] = myarg->getShape()[0];
     141           6 :       myval->setShape( shape );
     142           6 :       myval->reshapeMatrixStore( shape[1] );
     143             :     }
     144        4235 :   } else if( myarg->getShape()[0]==1 ) {
     145        2392 :     if( myval->getShape()[0]!=myarg->getShape()[1] ) {
     146           6 :       std::vector<unsigned> shape(1);
     147           6 :       shape[0] = myarg->getShape()[1];
     148           6 :       myval->setShape( shape );
     149             :     }
     150        1843 :   } else if( myarg->getShape()[0]!=myval->getShape()[1] || myarg->getShape()[1]!=myval->getShape()[0] ) {
     151          19 :     std::vector<unsigned> shape(2);
     152          19 :     shape[0] = myarg->getShape()[1];
     153          19 :     shape[1] = myarg->getShape()[0];
     154          19 :     myval->setShape( shape );
     155          19 :     myval->reshapeMatrixStore( shape[1] );
     156             :   }
     157        4821 : }
     158             : 
     159        4225 : void TransposeMatrix::calculate() {
     160             :   // Retrieve the non-zero pairs
     161             :   Value* myarg=getPntrToArgument(0);
     162        4225 :   Value* myval=getPntrToComponent(0);
     163        4225 :   if( myarg->getRank()<=1 || myval->getRank()==1 ) {
     164        2389 :     if( myarg->getRank()<=1 && myval->getShape()[1]!=myarg->getShape()[0] ) {
     165           0 :       std::vector<unsigned> shape( 2 );
     166           0 :       shape[0] = 1;
     167           0 :       shape[1] = myarg->getShape()[0];
     168           0 :       myval->setShape( shape );
     169           0 :       myval->reshapeMatrixStore( shape[1] );
     170        2389 :     } else if( myval->getRank()==1 && myval->getShape()[0]!=myarg->getShape()[1] ) {
     171           0 :       std::vector<unsigned> shape( 1 );
     172           0 :       shape[0] = myarg->getShape()[1];
     173           0 :       myval->setShape( shape );
     174             :     }
     175        2389 :     unsigned nv=myarg->getNumberOfValues();
     176       49015 :     for(unsigned i=0; i<nv; ++i) {
     177       46626 :       myval->set( i, myarg->get(i) );
     178             :     }
     179             :   } else {
     180        1836 :     if( myarg->getShape()[0]!=myval->getShape()[1] || myarg->getShape()[1]!=myval->getShape()[0] ) {
     181           0 :       std::vector<unsigned> shape( 2 );
     182           0 :       shape[0] = myarg->getShape()[1];
     183           0 :       shape[1] = myarg->getShape()[0];
     184           0 :       myval->setShape( shape );
     185           0 :       myval->reshapeMatrixStore( shape[1] );
     186             :     }
     187             :     std::vector<double> vals;
     188             :     std::vector<std::pair<unsigned,unsigned> > pairs;
     189        1836 :     std::vector<unsigned> shape( myval->getShape() );
     190        1836 :     unsigned nedge=0;
     191        1836 :     myarg->retrieveEdgeList( nedge, pairs, vals );
     192     2758860 :     for(unsigned i=0; i<nedge; ++i) {
     193     2757024 :       myval->set( pairs[i].second*shape[1] + pairs[i].first, vals[i] );
     194             :     }
     195             :   }
     196        4225 : }
     197             : 
     198        4144 : void TransposeMatrix::apply() {
     199        4144 :   if( doNotCalculateDerivatives() ) {
     200             :     return;
     201             :   }
     202             : 
     203             :   // Apply force on the matrix
     204        1930 :   if( getPntrToComponent(0)->forcesWereAdded() ) {
     205             :     Value* myarg=getPntrToArgument(0);
     206        1930 :     Value* myval=getPntrToComponent(0);
     207        1930 :     if( myarg->getRank()<=1 || myval->getRank()==1 ) {
     208         588 :       unsigned nv=myarg->getNumberOfValues();
     209        2408 :       for(unsigned i=0; i<nv; ++i) {
     210        1820 :         myarg->addForce( i, myval->getForce(i) );
     211             :       }
     212             :     } else {
     213        1342 :       MatrixOperationBase::apply();
     214             :     }
     215             :   }
     216             : }
     217             : 
     218     4124572 : double TransposeMatrix::getForceOnMatrixElement( const unsigned& jrow, const unsigned& kcol ) const {
     219     4124572 :   return getConstPntrToComponent(0)->getForce(kcol*getConstPntrToComponent(0)->getShape()[1]+jrow);
     220             : }
     221             : 
     222             : 
     223             : }
     224             : }

Generated by: LCOV version 1.16