CheMPS2
TensorO.cpp
1 /*
2  CheMPS2: a spin-adapted implementation of DMRG for ab initio quantum chemistry
3  Copyright (C) 2013-2016 Sebastian Wouters
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License along
16  with this program; if not, write to the Free Software Foundation, Inc.,
17  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include <stdlib.h>
21 #include <math.h>
22 #include <algorithm>
23 
24 #include "TensorO.h"
25 #include "Lapack.h"
26 
27 CheMPS2::TensorO::TensorO( const int boundary_index, const bool moving_right, const SyBookkeeper * book_up, const SyBookkeeper * book_down ) :
28 TensorOperator( boundary_index,
29  0, //two_j
30  0, //n_elec
31  0, //n_irrep
32  moving_right,
33  true, //prime_last (doesn't matter for spin-0 tensors)
34  false, //jw_phase (no operators)
35  book_up,
36  book_down ){ }
37 
39 
40 void CheMPS2::TensorO::update_ownmem( TensorT * mps_tensor_up, TensorT * mps_tensor_down, TensorO * previous ){
41 
42  clear();
43 
44  if ( moving_right ){
45 
46  const int dimL = std::max( bk_up->gMaxDimAtBound( index - 1 ), bk_down->gMaxDimAtBound( index - 1 ) );
47  const int dimR = std::max( bk_up->gMaxDimAtBound( index ), bk_down->gMaxDimAtBound( index ) );
48 
49  #pragma omp parallel
50  {
51  double * workmem = new double[ dimL * dimR ];
52 
53  #pragma omp for schedule(dynamic)
54  for ( int ikappa = 0; ikappa < nKappa; ikappa++ ){
55  update_moving_right( ikappa, previous, mps_tensor_up, mps_tensor_down, workmem );
56  }
57 
58  delete [] workmem;
59  }
60  } else {
61 
62  const int dimL = std::max( bk_up->gMaxDimAtBound( index ), bk_down->gMaxDimAtBound( index ) );
63  const int dimR = std::max( bk_up->gMaxDimAtBound( index + 1 ), bk_down->gMaxDimAtBound( index + 1 ) );
64 
65  #pragma omp parallel
66  {
67  double * workmem = new double[ dimL * dimR ];
68 
69  #pragma omp for schedule(dynamic)
70  for ( int ikappa = 0; ikappa < nKappa; ikappa++ ){
71  update_moving_left( ikappa, previous, mps_tensor_up, mps_tensor_down, workmem );
72  }
73 
74  delete [] workmem;
75  }
76  }
77 
78 }
79 
80 void CheMPS2::TensorO::create( TensorT * mps_tensor_up, TensorT * mps_tensor_down ){
81 
82  clear();
83 
84  if ( moving_right ){
85  #pragma omp parallel for schedule(dynamic)
86  for ( int ikappa = 0; ikappa < nKappa; ikappa++ ){ create_right( ikappa, mps_tensor_up, mps_tensor_down ); }
87  } else {
88  #pragma omp parallel for schedule(dynamic)
89  for ( int ikappa = 0; ikappa < nKappa; ikappa++ ){ create_left( ikappa, mps_tensor_up, mps_tensor_down ); }
90  }
91 
92 }
93 
94 void CheMPS2::TensorO::create_right( const int ikappa, TensorT * mps_tensor_up, TensorT * mps_tensor_down ){
95 
96  const int NR = sector_nelec_up[ ikappa ];
97  const int IR = sector_irrep_up[ ikappa ];
98  const int TwoSR = sector_spin_up [ ikappa ];
99 
100  int dimRup = bk_up->gCurrentDim( index, NR, TwoSR, IR );
101  int dimRdown = bk_down->gCurrentDim( index, NR, TwoSR, IR );
102 
103  for ( int geval = 0; geval < 4; geval++ ){
104  int IL, TwoSL, NL;
105  switch ( geval ){
106  case 0:
107  NL = NR;
108  TwoSL = TwoSR;
109  IL = IR;
110  break;
111  case 1:
112  NL = NR - 2;
113  TwoSL = TwoSR;
114  IL = IR;
115  break;
116  case 2:
117  NL = NR - 1;
118  TwoSL = TwoSR - 1;
119  IL = Irreps::directProd( IR, bk_up->gIrrep( index - 1 ) ); // bk_up and bk_down treat the same orbitals and ordering
120  break;
121  case 3:
122  NL = NR - 1;
123  TwoSL = TwoSR + 1;
124  IL = Irreps::directProd( IR, bk_up->gIrrep( index - 1 ) ); // bk_up and bk_down treat the same orbitals and ordering
125  break;
126  }
127 
128  int dimLup = bk_up->gCurrentDim( index - 1, NL, TwoSL, IL );
129  int dimLdown = bk_down->gCurrentDim( index - 1, NL, TwoSL, IL );
130  if (( dimLup > 0 ) && ( dimLdown > 0 ) && ( dimLup == dimLdown )){
131 
132  double alpha = 1.0;
133  double beta = 1.0; //add
134  char trans = 'T';
135  char notrans = 'N';
136  double * Tup = mps_tensor_up->gStorage( NL, TwoSL, IL, NR, TwoSR, IR );
137  double * Tdown = mps_tensor_down->gStorage( NL, TwoSL, IL, NR, TwoSR, IR );
138  dgemm_( &trans, &notrans, &dimRup, &dimRdown, &dimLup, &alpha, Tup, &dimLup, Tdown, &dimLdown, &beta, storage + kappa2index[ ikappa ], &dimRup );
139 
140  }
141  }
142 
143 }
144 
145 void CheMPS2::TensorO::create_left( const int ikappa, TensorT * mps_tensor_up, TensorT * mps_tensor_down ){
146 
147  const int NL = sector_nelec_up[ ikappa ];
148  const int IL = sector_irrep_up[ ikappa ];
149  const int TwoSL = sector_spin_up [ ikappa ];
150 
151  int dimLup = bk_up->gCurrentDim( index, NL, TwoSL, IL );
152  int dimLdown = bk_down->gCurrentDim( index, NL, TwoSL, IL );
153 
154  for ( int geval = 0; geval < 4; geval++ ){
155  int IR, TwoSR, NR;
156  switch ( geval ){
157  case 0:
158  NR = NL;
159  TwoSR = TwoSL;
160  IR = IL;
161  break;
162  case 1:
163  NR = NL + 2;
164  TwoSR = TwoSL;
165  IR = IL;
166  break;
167  case 2:
168  NR = NL + 1;
169  TwoSR = TwoSL - 1;
170  IR = Irreps::directProd( IL, bk_up->gIrrep( index ) ); // bk_up and bk_down treat the same orbitals and ordering
171  break;
172  case 3:
173  NR = NL + 1;
174  TwoSR = TwoSL + 1;
175  IR = Irreps::directProd( IL, bk_up->gIrrep( index ) ); // bk_up and bk_down treat the same orbitals and ordering
176  break;
177  }
178 
179  int dimRup = bk_up->gCurrentDim( index + 1, NR, TwoSR, IR );
180  int dimRdown = bk_down->gCurrentDim( index + 1, NR, TwoSR, IR );
181  if (( dimRup > 0 ) && ( dimRdown > 0 ) && ( dimRup == dimRdown )){
182 
183  double alpha = (( geval > 1 ) ? (( TwoSR + 1.0 ) / ( TwoSL + 1 )) : 1.0 );
184  double beta = 1.0; //add
185  char trans = 'T';
186  char notrans = 'N';
187  double * Tup = mps_tensor_up->gStorage( NL, TwoSL, IL, NR, TwoSR, IR );
188  double * Tdown = mps_tensor_down->gStorage( NL, TwoSL, IL, NR, TwoSR, IR );
189  dgemm_( &notrans, &trans, &dimLup, &dimLdown, &dimRup, &alpha, Tup, &dimLup, Tdown, &dimLdown, &beta, storage + kappa2index[ ikappa ], &dimLup );
190 
191  }
192  }
193 
194 }
195 
196 
int index
Index of the Tensor object. For TensorT: a site index; for other tensors: a boundary index...
Definition: Tensor.h:75
int * sector_nelec_up
The up particle number sector.
int gCurrentDim(const int boundary, const int N, const int TwoS, const int irrep) const
Get the current virtual dimensions.
const SyBookkeeper * bk_down
The bookkeeper of the lower MPS.
void create(TensorT *mps_tensor_up, TensorT *mps_tensor_down)
Clear and add the relevant terms to the TensorO.
Definition: TensorO.cpp:80
void update_ownmem(TensorT *mps_tensor_up, TensorT *mps_tensor_down, TensorO *previous)
Update the previous TensorO.
Definition: TensorO.cpp:40
bool moving_right
Whether or not moving right.
int * sector_spin_up
The up spin symmetry sector.
double * gStorage()
Get the pointer to the storage.
Definition: TensorT.cpp:134
void update_moving_left(const int ikappa, TensorOperator *previous, TensorT *mps_tensor_up, TensorT *mps_tensor_down, double *workmem)
Update moving left.
static int directProd(const int Irrep1, const int Irrep2)
Get the direct product of the irreps with numbers Irrep1 and Irrep2: a bitwise XOR for psi4&#39;s convent...
Definition: Irreps.h:123
TensorO(const int boundary_index, const bool moving_right, const SyBookkeeper *book_up, const SyBookkeeper *book_down)
Constructor.
Definition: TensorO.cpp:27
int * sector_irrep_up
The up spin symmetry sector.
const SyBookkeeper * bk_up
The bookkeeper of the upper MPS.
int * kappa2index
kappa2index[kappa] indicates the start of tensor block kappa in storage. kappa2index[nKappa] gives th...
Definition: Tensor.h:84
int gMaxDimAtBound(const int boundary) const
Get the maximum virtual dimension at a certain boundary.
virtual ~TensorO()
Destructor.
Definition: TensorO.cpp:38
void clear()
Set all storage variables to 0.0.
int nKappa
Number of Tensor blocks.
Definition: Tensor.h:81
int gIrrep(const int orbital) const
Get an orbital irrep.
double * storage
The actual variables. Tensor block kappa begins at storage+kappa2index[kappa] and ends at storage+kap...
Definition: Tensor.h:78
void update_moving_right(const int ikappa, TensorOperator *previous, TensorT *mps_tensor_up, TensorT *mps_tensor_down, double *workmem)
Update moving right.