Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2015-2023 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 "DimensionalityReductionBase.h" 23 : #include "reference/ReferenceConfiguration.h" 24 : #include "core/PlumedMain.h" 25 : #include "core/Atoms.h" 26 : 27 : namespace PLMD { 28 : namespace dimred { 29 : 30 23 : void DimensionalityReductionBase::registerKeywords( Keywords& keys ) { 31 23 : analysis::AnalysisBase::registerKeywords( keys ); 32 46 : keys.add("compulsory","NLOW_DIM","number of low-dimensional coordinates required"); 33 46 : keys.addOutputComponent("coord","default","the low-dimensional projections of the various input configurations"); 34 23 : } 35 : 36 16 : DimensionalityReductionBase::DimensionalityReductionBase( const ActionOptions& ao ): 37 : Action(ao), 38 : analysis::AnalysisBase(ao), 39 16 : dimredbase(NULL) 40 : { 41 : // Check that some dissimilarity information is available 42 16 : if( my_input_data ) { 43 27 : if( getName()!="PCA" && !dissimilaritiesWereSet() ) error("dissimilarities have not been calcualted in input actions"); 44 : // Now we check if the input was a dimensionality reduction object 45 15 : dimredbase = dynamic_cast<DimensionalityReductionBase*>( my_input_data ); 46 : } 47 : 48 : // Retrieve the dimension in the low dimensionality space 49 16 : nlow=0; 50 16 : if( dimredbase ) { 51 5 : nlow=dimredbase->nlow; 52 5 : log.printf(" projecting in %u dimensional space \n",nlow); 53 22 : } else if( keywords.exists("NLOW_DIM") ) { 54 10 : parse("NLOW_DIM",nlow); 55 10 : if( nlow<1 ) error("dimensionality of low dimensional space must be at least one"); 56 10 : log.printf(" projecting in %u dimensional space \n",nlow); 57 : } 58 : // Now add fake components to the underlying ActionWithValue for the arguments 59 : std::string num; 60 45 : for(unsigned i=0; i<nlow; ++i) { 61 87 : Tools::convert(i+1,num); addComponent( "coord-" + num ); componentIsNotPeriodic( "coord-" + num ); 62 : } 63 16 : } 64 : 65 2 : std::vector<Value*> DimensionalityReductionBase::getArgumentList() { 66 : std::vector<Value*> arglist( analysis::AnalysisBase::getArgumentList() ); 67 6 : for(unsigned i=0; i<nlow; ++i) arglist.push_back( getPntrToComponent(i) ); 68 2 : return arglist; 69 : } 70 : 71 1050 : void DimensionalityReductionBase::getProjection( const unsigned& idata, std::vector<double>& point, double& weight ) { 72 1050 : if( point.size()!=nlow ) point.resize( nlow ); 73 3150 : weight = getWeight(idata); for(unsigned i=0; i<nlow; ++i) point[i]=projections(idata,i); 74 1050 : } 75 : 76 19 : void DimensionalityReductionBase::performAnalysis() { 77 19 : log.printf("Generating projections required by action %s \n",getLabel().c_str() ); 78 : // Resize the tempory array (this is used for out of sample) 79 19 : dtargets.resize( getNumberOfDataPoints() ); 80 : // Resize the projections array 81 19 : projections.resize( getNumberOfDataPoints(), nlow ); 82 : // Retrieve the projections from the previous calculation 83 19 : if( dimredbase ) { 84 6 : std::vector<double> newp( nlow ); double w; 85 1056 : for(unsigned i=0; i<getNumberOfDataPoints(); ++i) { 86 1050 : dimredbase->getProjection( i, newp, w ); plumed_dbg_assert( newp.size()==nlow ); 87 3150 : for(unsigned j=0; j<nlow; ++j) projections(i,j)=newp[j]; 88 : } 89 : } 90 : // Calculate matrix of dissimilarities 91 19 : Matrix<double> targets( getNumberOfDataPoints(), getNumberOfDataPoints() ); targets=0; 92 2686 : for(unsigned i=1; i<getNumberOfDataPoints(); ++i) { 93 367354 : for(unsigned j=0; j<i; ++j) targets(i,j)=targets(j,i)=getDissimilarity( i, j ); 94 : } 95 : // This calculates the projections of the points 96 19 : calculateProjections( targets, projections ); 97 : // Now set the projection values in the underlying object 98 19 : if( my_input_data ) { 99 2620 : for(unsigned idat=0; idat<getNumberOfDataPoints(); ++idat) { 100 2602 : analysis::DataCollectionObject& myref=AnalysisBase::getStoredData(idat,false); std::string num; 101 7804 : for(unsigned i=0; i<nlow; ++i) { Tools::convert(i+1,num); myref.setArgument( getLabel() + ".coord-" + num, projections(idat,i) ); } 102 : } 103 : } 104 19 : log.printf("Generated projections required by action %s \n",getLabel().c_str() ); 105 19 : } 106 : 107 0 : double DimensionalityReductionBase::calculateStress( const std::vector<double>& p, std::vector<double>& d ) { 108 : 109 : // Zero derivative and stress accumulators 110 0 : for(unsigned i=0; i<p.size(); ++i) d[i]=0.0; 111 0 : double stress=0; std::vector<double> dtmp( p.size() ); 112 : 113 : // Now accumulate total stress on system 114 0 : for(unsigned i=0; i<dtargets.size(); ++i) { 115 0 : if( dtargets[i]<epsilon ) continue ; 116 : 117 : // Calculate distance in low dimensional space 118 : double dd=0; 119 0 : for(unsigned j=0; j<p.size(); ++j) { dtmp[j]=p[j]-projections(i,j); dd+=dtmp[j]*dtmp[j]; } 120 0 : dd = std::sqrt(dd); 121 : 122 : // Now do transformations and calculate differences 123 0 : double ddiff = dd - dtargets[i]; 124 : 125 : // Calculate derivatives 126 0 : double pref = 2.*getWeight(i) / dd; 127 0 : for(unsigned j=0; j<p.size(); ++j) d[j] += pref*ddiff*dtmp[j]; 128 : 129 : // Accumulate the total stress 130 0 : stress += getWeight(i)*ddiff*ddiff; 131 : } 132 0 : return stress; 133 : } 134 : 135 : } 136 : }