CheMPS2
Problem.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 <assert.h>
22 #include <iostream>
23 #include <math.h> // fabs
24 
25 #include "Problem.h"
26 #include "MPIchemps2.h"
27 
28 using std::cout;
29 using std::endl;
30 
31 CheMPS2::Problem::Problem(const Hamiltonian * Hamin, const int TwoSin, const int Nin, const int Irrepin){
32 
33  Ham = Hamin;
34  L = Ham->getL();
35  TwoS = TwoSin;
36  N = Nin;
37  Irrep = Irrepin;
38  bReorder = false;
39 
41  mx_elem = NULL;
42 
43 }
44 
46 
47  if (bReorder){
48  delete [] f1;
49  delete [] f2;
50  }
51 
52  if ( mx_elem != NULL ){ delete [] mx_elem; }
53 
54 }
55 
57 
58  if (bReorder){
59  delete [] f1;
60  delete [] f2;
61  bReorder = false;
62  }
63 
64  if (gSy()==7){ //Only if D2h of course
65 
66  bReorder = true;
67  f1 = new int[Ham->getL()];
68  f2 = new int[Ham->getL()];
69 
70  int DMRGirrepOrder[8];
71  DMRGirrepOrder[0] = 0; //Ag sigma
72  DMRGirrepOrder[1] = 5; //B1u sigma^*
73  DMRGirrepOrder[2] = 7; //B3u pi_x
74  DMRGirrepOrder[3] = 2; //B2g pi_x^*
75  DMRGirrepOrder[4] = 6; //B2u pi_y
76  DMRGirrepOrder[5] = 3; //B3g pi_y^*
77  DMRGirrepOrder[6] = 1; //B1g
78  DMRGirrepOrder[7] = 4; //Au
79 
80  int DMRGOrb = 0;
81  for (int irrep=0; irrep<8; irrep++){
82  for (int HamOrb=0; HamOrb<Ham->getL(); HamOrb++){
83  if (Ham->getOrbitalIrrep(HamOrb)==DMRGirrepOrder[irrep]){
84  f1[HamOrb] = DMRGOrb;
85  f2[DMRGOrb] = HamOrb;
86  DMRGOrb++;
87  }
88  }
89  }
90  assert( DMRGOrb==Ham->getL() );
91 
92  }
93 
94 }
95 
97 
98  if (bReorder){
99  delete [] f1;
100  delete [] f2;
101  bReorder = false;
102  }
103 
104  if (gSy()==5){ //Only if C2v of course
105 
106  bReorder = true;
107  f1 = new int[Ham->getL()];
108  f2 = new int[Ham->getL()];
109 
110  int DMRGirrepOrder[4];
111  DMRGirrepOrder[0] = 0; //A1
112  DMRGirrepOrder[1] = 2; //B1
113  DMRGirrepOrder[2] = 3; //B2
114  DMRGirrepOrder[3] = 1; //A2
115 
116  int DMRGOrb = 0;
117  {
118  const int irrep = 0; // Irrep = 0 = A1 : reverse the order of the orbitals
119  for (int HamOrb=Ham->getL()-1; HamOrb>=0; HamOrb--){
120  if (Ham->getOrbitalIrrep(HamOrb)==DMRGirrepOrder[irrep]){
121  f1[HamOrb] = DMRGOrb;
122  f2[DMRGOrb] = HamOrb;
123  DMRGOrb++;
124  }
125  }
126  }
127  for (int irrep=1; irrep<4; irrep++){
128  for (int HamOrb=0; HamOrb<Ham->getL(); HamOrb++){
129  if (Ham->getOrbitalIrrep(HamOrb)==DMRGirrepOrder[irrep]){
130  f1[HamOrb] = DMRGOrb;
131  f2[DMRGOrb] = HamOrb;
132  DMRGOrb++;
133  }
134  }
135  }
136  assert( DMRGOrb==Ham->getL() );
137 
138  /*
139  cout << "The new orbital order in c2v:" << endl;
140  for ( int DMRGOrb=0; DMRGOrb<Ham->getL()-1; DMRGOrb++ ){
141  cout << f2[DMRGOrb] << ", ";
142  }
143  cout << f2[Ham->getL()-1] << endl;
144  */
145 
146  }
147 
148 }
149 
151 
152  if (bReorder){
153  delete [] f1;
154  delete [] f2;
155  bReorder = false;
156  }
157 
158  bReorder = true;
159  f1 = new int[Ham->getL()]; // Is going to be the inverse of dmrg2ham
160  f2 = new int[Ham->getL()]; // Is going to be dmrg2ham copied
161 
162  // Set f1 entries negative to check all elements set
163  for ( int ham_orb = 0; ham_orb < Ham->getL(); ham_orb++ ){ f1[ ham_orb ] = -2; }
164  for ( int dmrg_orb = 0; dmrg_orb < Ham->getL(); dmrg_orb++ ){
165 
166  assert( dmrg2ham[ dmrg_orb ] >= 0 );
167  assert( dmrg2ham[ dmrg_orb ] < Ham->getL() );
168  f2[ dmrg_orb ] = dmrg2ham[ dmrg_orb ];
169  f1[ dmrg2ham[ dmrg_orb ] ] = dmrg_orb;
170 
171  }
172  // Check all elements f1 set
173  for ( int ham_orb = 0; ham_orb < Ham->getL(); ham_orb++ ){ assert( f1[ ham_orb ] >= 0 ); }
174 
175 }
176 
177 void CheMPS2::Problem::setup_reorder_dinfh(int * docc, const double sp_threshold){
178 
179  assert( gSy() == 7 ); // Only for d2h of course
180  const int num_irreps = 8;
181  const int irrep_ag = 0;
182  const int irrep_b1g = 1;
183  const int irrep_b2g = 2;
184  const int irrep_b3g = 3;
185  const int irrep_au = 4;
186  const int irrep_b1u = 5;
187  const int irrep_b2u = 6;
188  const int irrep_b3u = 7;
189 
190  double * sp_energies = new double[ Ham->getL() ];
191  int * dmrg2ham = new int[ Ham->getL() ];
192  int * partners = new int[ Ham->getL() ];
193 
194  // Get the single particle energies
195  for ( int ham_orb = 0; ham_orb < Ham->getL(); ham_orb++ ){
196  double value = Ham->getTmat( ham_orb, ham_orb );
197  for ( int irrep = 0; irrep < num_irreps; irrep++ ){
198  int counter = 0;
199  for ( int frozen_orb = 0; frozen_orb < Ham->getL(); frozen_orb++ ){
200  if ( Ham->getOrbitalIrrep( frozen_orb ) == irrep ){
201  if ( counter < docc[ irrep ] ){
202  value += 2 * Ham->getVmat( ham_orb, frozen_orb, ham_orb, frozen_orb )
203  - Ham->getVmat( ham_orb, ham_orb, frozen_orb, frozen_orb );
204  }
205  counter += 1;
206  }
207  }
208  }
209  sp_energies[ ham_orb ] = value;
210  }
211 
212  // To check that they have been set, put the partners to a negative value.
213  for ( int cnt = 0; cnt < Ham->getL(); cnt++ ){ partners[ cnt ] = -2; }
214  int dmrg_orb = 0;
215 
216  // Copy the b1g ( Delta_g ) orbitals
217  for ( int ham_orb = Ham->getL() - 1; ham_orb >= 0; ham_orb-- ){
218  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_b1g ){
219  dmrg2ham[ dmrg_orb ] = ham_orb;
220  for ( int partner_orb = 0; partner_orb < Ham->getL(); partner_orb++ ){
221  if ( Ham->getOrbitalIrrep( partner_orb ) == irrep_ag ){
222  if ( fabs( sp_energies[ ham_orb ] - sp_energies[ partner_orb ] ) < sp_threshold ){
223  partners[ dmrg_orb ] = partner_orb;
224  }
225  }
226  }
227  dmrg_orb++;
228  }
229  }
230 
231  // Copy the au ( Delta_u ) orbitals
232  for ( int ham_orb = 0; ham_orb < Ham->getL(); ham_orb++ ){
233  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_au ){
234  dmrg2ham[ dmrg_orb ] = ham_orb;
235  for ( int partner_orb = 0; partner_orb < Ham->getL(); partner_orb++ ){
236  if ( Ham->getOrbitalIrrep( partner_orb ) == irrep_b1u ){
237  if ( fabs( sp_energies[ ham_orb ] - sp_energies[ partner_orb ] ) < sp_threshold ){
238  partners[ dmrg_orb ] = partner_orb;
239  }
240  }
241  }
242  dmrg_orb++;
243  }
244  }
245  const int num_delta_ug = dmrg_orb;
246  assert( (num_delta_ug % 2) == 0 );
247 
248  // Copy the partner orbitals
249  for ( int cnt = 0; cnt < num_delta_ug; cnt++ ){
250  assert( partners[ cnt ] >= 0 ); // Check that each one found a partner
251  dmrg2ham[ dmrg_orb ] = partners[ cnt ];
252  dmrg_orb++;
253  }
254 
255  // Copy the remaining ag orbitals
256  for ( int ham_orb = Ham->getL() - 1; ham_orb >= 0; ham_orb-- ){
257  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_ag ){
258  bool is_a_partner = false;
259  for ( int cnt = 0; cnt < num_delta_ug; cnt++ ){
260  if ( ham_orb == partners[ cnt ] ){ is_a_partner = true; }
261  }
262  if ( is_a_partner == false ){
263  dmrg2ham[ dmrg_orb ] = ham_orb;
264  dmrg_orb++;
265  }
266  }
267  }
268 
269  // Copy the remaining b1u orbitals
270  for ( int ham_orb = 0; ham_orb < Ham->getL(); ham_orb++ ){
271  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_b1u ){
272  bool is_a_partner = false;
273  for ( int cnt = 0; cnt < num_delta_ug; cnt++ ){
274  if ( ham_orb == partners[ cnt ] ){ is_a_partner = true; }
275  }
276  if ( is_a_partner == false ){
277  dmrg2ham[ dmrg_orb ] = ham_orb;
278  dmrg_orb++;
279  }
280  }
281  }
282 
283  // Copy the b3u ( Pi_u, pi_x ) orbitals
284  for ( int ham_orb = Ham->getL() - 1; ham_orb >= 0; ham_orb-- ){
285  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_b3u ){
286  dmrg2ham[ dmrg_orb ] = ham_orb;
287  dmrg_orb++;
288  }
289  }
290 
291  // Copy the b2g ( Pi_g, pi_x^* ) orbitals
292  for ( int ham_orb = 0; ham_orb < Ham->getL(); ham_orb++ ){
293  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_b2g ){
294  dmrg2ham[ dmrg_orb ] = ham_orb;
295  dmrg_orb++;
296  }
297  }
298 
299  // Copy the b2u ( Pi_u, pi_y ) orbitals
300  for ( int ham_orb = Ham->getL() - 1; ham_orb >= 0; ham_orb-- ){
301  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_b2u ){
302  dmrg2ham[ dmrg_orb ] = ham_orb;
303  dmrg_orb++;
304  }
305  }
306 
307  // Copy the b3g ( Pi_g, pi_y^* ) orbitals
308  for ( int ham_orb = 0; ham_orb < Ham->getL(); ham_orb++ ){
309  if ( Ham->getOrbitalIrrep( ham_orb ) == irrep_b3g ){
310  dmrg2ham[ dmrg_orb ] = ham_orb;
311  dmrg_orb++;
312  }
313  }
314 
315  assert( dmrg_orb == Ham->getL() );
316  setup_reorder_custom( dmrg2ham );
317 
318  #ifdef CHEMPS2_MPI_COMPILATION
319  if ( MPIchemps2::mpi_rank() == MPI_CHEMPS2_MASTER )
320  #endif
321  {
322  cout << "Reordered the orbitals according to d(infinity)h:" << endl;
323  Irreps myIrreps( gSy() );
324  for ( dmrg_orb = 0; dmrg_orb < Ham->getL(); dmrg_orb++ ){
325  const int ham_orb = dmrg2ham[ dmrg_orb ];
326  cout << " DMRG orb " << dmrg_orb << " [" << myIrreps.getIrrepName(Ham->getOrbitalIrrep( ham_orb )) << "] has SP energy = " << sp_energies[ ham_orb ] << endl;
327  }
328  }
329 
330  delete [] dmrg2ham;
331  delete [] partners;
332  delete [] sp_energies;
333 
334 }
335 
336 int CheMPS2::Problem::gIrrep(const int nOrb) const{
337 
338  if (!bReorder){
339  return Ham->getOrbitalIrrep(nOrb);
340  }
341 
342  return Ham->getOrbitalIrrep(f2[nOrb]);
343 
344 }
345 
346 bool CheMPS2::Problem::gReorder() const{ return bReorder; }
347 int CheMPS2::Problem::gf1(const int HamOrb) const{ return (bReorder)?f1[HamOrb]:-1; }
348 int CheMPS2::Problem::gf2(const int DMRGOrb) const{ return (bReorder)?f2[DMRGOrb]:-1; }
349 
350 double CheMPS2::Problem::gMxElement(const int alpha, const int beta, const int gamma, const int delta) const{
351 
352  return mx_elem[ alpha + L * ( beta + L * ( gamma + L * delta ) ) ];
353 
354 }
355 
356 void CheMPS2::Problem::setMxElement(const int alpha, const int beta, const int gamma, const int delta, const double value){
357 
358  mx_elem[ alpha + L * ( beta + L * ( gamma + L * delta ) ) ] = value;
359 
360 }
361 
363 
364  if ( mx_elem == NULL ){ mx_elem = new double[ L*L*L*L ]; }
365  const double prefact = 1.0/(N-1);
366 
367  for (int orb1 = 0; orb1 < L; orb1++){
368  const int map1 = (( !bReorder ) ? orb1 : f2[ orb1 ]);
369  for (int orb2 = 0; orb2 < L; orb2++){
370  const int map2 = (( !bReorder ) ? orb2 : f2[ orb2 ]);
371  for (int orb3 = 0; orb3 < L; orb3++){
372  const int map3 = (( !bReorder ) ? orb3 : f2[ orb3 ]);
373  for (int orb4 = 0; orb4 < L; orb4++){
374  const int map4 = (( !bReorder ) ? orb4 : f2[ orb4 ]);
375  setMxElement( orb1, orb2, orb3, orb4, Ham->getVmat(map1,map2,map3,map4)
376  + prefact*((orb1==orb3)?Ham->getTmat(map2,map4):0)
377  + prefact*((orb2==orb4)?Ham->getTmat(map1,map3):0) );
378  }
379  }
380  }
381  }
382 
383 }
384 
386 
387  Irreps SymmInfo(gSy());
388  if ((gIrrep()<0) || (gIrrep()>=SymmInfo.getNumberOfIrreps())){
389  cout << "Problem::Problem() : Irrep out of bound : Irrep = " << gIrrep() << endl;
390  return false;
391  }
392  if (gTwoS()<0){
393  cout << "Problem::checkConsistency() : TwoS = " << gTwoS() << endl;
394  return false;
395  }
396  if (gN()<0){
397  cout << "Problem::checkConsistency() : N = " << gN() << endl;
398  return false;
399  }
400  if (gL()<0){
401  cout << "Problem::checkConsistency() : L = " << gL() << endl;
402  return false;
403  }
404  if (gN()>2*gL()){
405  cout << "Problem::checkConsistency() : N > 2*L ; N = " << gN() << " and L = " << gL() << endl;
406  return false;
407  }
408  if ( (gN()%2) != (gTwoS()%2) ){
409  cout << "Problem::checkConsistency() : N%2 != TwoS%2 ; N = " << gN() << " and TwoS = " << gTwoS() << endl;
410  return false;
411  }
412  if ( gTwoS() > gL() - abs(gN() - gL()) ){
413  cout << "Problem::checkConsistency() : TwoS > L - |N-L| ; N = " << gN() << " and TwoS = " << gTwoS() << " and L = " << gL() << endl;
414  return false;
415  }
416 
417  return true;
418 
419 }
420 
421 
void setMxElement(const int alpha, const int beta, const int gamma, const int delta, const double value)
Set the matrix elements: Note that each time you create a DMRG object, they will be overwritten with ...
Definition: Problem.cpp:356
int getNumberOfIrreps() const
Get the number of irreps for the currently activated group.
Definition: Irreps.cpp:94
void setup_reorder_dinfh(int *docc, const double sp_threshold=1e-5)
Reorder the orbitals for d(infinity)h. Previous reorderings are cleared.
Definition: Problem.cpp:177
bool gReorder() const
Get whether the Hamiltonian orbitals are reordered for the DMRG calculation.
Definition: Problem.cpp:346
int getOrbitalIrrep(const int nOrb) const
Get an orbital irrep number.
Definition: Hamiltonian.cpp:97
static int mpi_rank()
Get the rank of this MPI process.
Definition: MPIchemps2.h:131
double getVmat(const int index1, const int index2, const int index3, const int index4) const
Get a Vmat element.
bool checkConsistency() const
Check whether the given parameters L, N, and TwoS are not inconsistent and whether 0<=Irrep<nIrreps...
Definition: Problem.cpp:385
void setup_reorder_custom(int *dmrg2ham)
Reorder the orbitals to a custom ordering. Previous reorderings are cleared.
Definition: Problem.cpp:150
double getTmat(const int index1, const int index2) const
Get a Tmat element.
int gN() const
Get the targeted particle number.
Definition: Problem.h:68
int gTwoS() const
Get twice the targeted spin.
Definition: Problem.h:64
double gMxElement(const int alpha, const int beta, const int gamma, const int delta) const
Get a specific interaction matrix element.
Definition: Problem.cpp:350
int gf1(const int HamOrb) const
Get the DMRG index corresponding to a Ham index.
Definition: Problem.cpp:347
void SetupReorderC2v()
Reorder the orbitals, so that they form irrep blocks, with order of irreps A1 B1 B2 A2...
Definition: Problem.cpp:96
int gL() const
Get the number of orbitals.
Definition: Problem.h:51
void SetupReorderD2h()
Reorder the orbitals, so that they form irrep blocks, with order of irreps Ag B1u B3u B2g B2u B3g B1g...
Definition: Problem.cpp:56
virtual ~Problem()
Destructor.
Definition: Problem.cpp:45
void construct_mxelem()
Construct a table with the h-matrix elements (two-body augmented with one-body). Remember to recall t...
Definition: Problem.cpp:362
Problem(const Hamiltonian *Hamin, const int TwoSin, const int Nin, const int Irrepin)
Constructor.
Definition: Problem.cpp:31
int getL() const
Get the number of orbitals.
Definition: Hamiltonian.cpp:93
int gIrrep() const
Get the targeted irrep.
Definition: Problem.h:72
string getIrrepName(const int irrepNumber) const
Get the name of the irrep with number irrepNumber of the activated group. The irrep with number 0 is ...
Definition: Irreps.cpp:110
int gSy() const
Get the point group symmetry.
Definition: Problem.h:55
int gf2(const int DMRGOrb) const
Get the Ham index corresponding to a DMRG index.
Definition: Problem.cpp:348