HubbardGPU
Hubbard diagonalisation on the GPU (and CPU)
 All Classes Files Functions Variables Typedefs Friends Macros
helpers.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2014 Ward Poelmans
2 
3  This file is part of Hubbard-GPU.
4 
5  Hubbard-GPU 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 3 of the License, or
8  (at your option) any later version.
9 
10  Hubbard-GPU 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
16  along with Hubbard-GPU. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <iostream>
20 #include <algorithm>
21 #include <sstream>
22 #include <assert.h>
23 #include <hdf5.h>
24 #include "helpers.h"
25 
26 // macro to help check return status of HDF5 functions
27 #define HDF5_STATUS_CHECK(status) { \
28  if(status < 0) \
29  std::cerr << __FILE__ << ":" << __LINE__ << \
30  ": Problem with writing to file. Status code=" \
31  << status << std::endl; \
32 }
33 
34 // constant used in BasisList
35 const int BasisList::EMPTY = -1;
36 
42 {
43  this->n = 0;
44  this->m = 0;
45 }
46 
51 matrix::matrix(int n_, int m_)
52 {
53  assert(n_ && m_);
54  this->n = n_;
55  this->m = m_;
56  mat.reset(new double [n*m]);
57 }
58 
62 matrix::matrix(const matrix &orig)
63 {
64  n = orig.n;
65  m = orig.m;
66  mat.reset(new double [n*m]);
67  std::memcpy(mat.get(), orig.getpointer(), n*m*sizeof(double));
68 }
69 
75 {
76  n = orig.n;
77  m = orig.m;
78  mat = std::move(orig.mat);
79 }
80 
82 {
83  n = orig.n;
84  m = orig.m;
85  mat.reset(new double [n*m]);
86  std::memcpy(mat.get(), orig.getpointer(), n*m*sizeof(double));
87  return *this;
88 }
89 
95 {
96  for(int i=0;i<n*m;i++)
97  mat[i] = val;
98 
99  return *this;
100 }
101 
105 int matrix::getn() const
106 {
107  return n;
108 }
109 
113 int matrix::getm() const
114 {
115  return m;
116 }
117 
118 double matrix::operator()(int x,int y) const
119 {
120  assert(x<n && y<m);
121  return mat[x+y*n];
122 }
123 
124 double& matrix::operator()(int x,int y)
125 {
126  assert(x<n && y<m);
127  return mat[x+y*n];
128 }
129 
130 double& matrix::operator[](int x)
131 {
132  assert(x<n*m);
133  return mat[x];
134 }
135 
136 double matrix::operator[](int x) const
137 {
138  assert(x<n*m);
139  return mat[x];
140 }
141 
142 double* matrix::getpointer() const
143 {
144  return mat.get();
145 }
146 
152 matrix& matrix::prod(matrix const &A, matrix const &B)
153 {
154  char trans = 'N';
155 
156  double alpha = 1.0;
157  double beta = 0.0;
158 
159  assert(A.n == n && B.m == m);
160 
161  dgemm_(&trans,&trans,&A.n,&B.m,&A.m,&alpha,A.mat.get(),&A.n,B.mat.get(),&B.n,&beta,mat.get(),&A.n);
162 
163  return *this;
164 }
165 
171 std::unique_ptr<double []> matrix::svd()
172 {
173  char jobu = 'A';
174  char jobvt = 'N';
175 
176  int count_sing = std::min(n,m);
177 
178  std::unique_ptr<double []> sing_vals(new double[count_sing]);
179 
180  // MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)).
181  int lwork = std::max( 3*count_sing + std::max(n,m), 5*count_sing);
182  std::unique_ptr<double []> work(new double[lwork]);
183 
184  std::unique_ptr<double []> vt(new double[n*n]);
185 
186  int info;
187 
188  dgesvd_(&jobu,&jobvt,&n,&m,mat.get(),&n,sing_vals.get(),vt.get(),&n,0,&m,work.get(),&lwork,&info);
189 
190  if(info)
191  std::cerr << "svd failed. info = " << info << std::endl;
192 
193  // overwrite the matrix with the right singular vectors
194  m = n;
195  mat = std::move(vt);
196 
197  return sing_vals;
198 }
199 
200 void matrix::Print() const
201 {
202  for(int i=0;i<n;i++)
203  for(int j=0;j<m;j++)
204  std::cout << i << " " << j << "\t" << (*this)(i,j) << std::endl;
205 }
206 
207 
214 KBlock::KBlock(int K, int L, int Nu, int Nd)
215 {
216  this->K = K;
217  this->L = L;
218  this->Nu = Nu;
219  this->Nd = Nd;
220 }
221 
222 KBlock::KBlock(const KBlock &orig)
223 {
224  K = orig.K;
225  L = orig.L;
226  Nu = orig.Nu;
227  Nd = orig.Nd;
228 
229  basis = orig.basis;
230 }
231 
233 {
234  K = orig.K;
235  L = orig.L;
236  Nu = orig.Nu;
237  Nd = orig.Nd;
238 
239  basis = std::move(orig.basis);
240 }
241 
242 myint KBlock::getUp(int index) const
243 {
244  assert(index<getdim());
245  return basis[index].first;
246 }
247 
248 myint KBlock::getDown(int index) const
249 {
250  assert(index<getdim());
251  return basis[index].second;
252 }
253 
254 int KBlock::getdim() const
255 {
256  return basis.size();
257 }
258 
259 int KBlock::getK() const
260 {
261  return K;
262 }
263 
264 int KBlock::getL() const
265 {
266  return L;
267 }
268 
274 const std::pair<myint,myint>& KBlock::operator[](int index) const
275 {
276  assert(index < basis.size());
277  return basis[index];
278 }
279 
280 void KBlock::Print() const
281 {
282  int Hbc = BareHamiltonian::CountBits((1<<L)-1);
283 
284  for(int i=0;i<basis.size();i++)
285  std::cout << BareHamiltonian::print_bin(basis[i].first, Hbc) << "\t" << BareHamiltonian::print_bin(basis[i].first, Hbc) << std::endl;
286 }
287 
288 
295 MomBasis::MomBasis(int L, int Nu, int Nd)
296 {
297  this->L = L;
298  this->Nu = Nu;
299  this->Nd = Nd;
300 
301  int dim_up = BareHamiltonian::CalcDim(L, Nu);
302  int dim_down = BareHamiltonian::CalcDim(L, Nd);
303  dim = dim_up * dim_down;
304 
305  BuildBase();
306 }
307 
314 myint MomBasis::getUp(int K, int index) const
315 {
316  assert(K<L);
317  assert(index<basisblocks[K]->getdim());
318  return (*basisblocks[K])[index].first;
319 }
320 
327 myint MomBasis::getDown(int K, int index) const
328 {
329  assert(K<L);
330  assert(index<basisblocks[K]->getdim());
331  return (*basisblocks[K])[index].second;
332 }
333 
340 int MomBasis::findUp(int K, myint ket) const
341 {
342  assert(K<L);
343  for(unsigned int i=0;i<basisblocks[K]->getdim();i++)
344  if((*basisblocks[K])[i].first == ket)
345  return i;
346 
347  assert(0 && "Should never be reached");
348  return -1;
349 }
350 
357 int MomBasis::findDown(int K, myint ket) const
358 {
359  assert(K<L);
360  for(unsigned int i=0;i<basisblocks[K]->getdim();i++)
361  if((*basisblocks[K])[i].second == ket)
362  return i;
363 
364  assert(0 && "Should never be reached");
365  return -1;
366 }
367 
368 int MomBasis::getdim() const
369 {
370  return dim;
371 }
372 
377 int MomBasis::getdimK(int K) const
378 {
379  assert(K<L);
380  return basisblocks[K]->getdim();
381 }
382 
383 int MomBasis::getL() const
384 {
385  return L;
386 }
387 
388 int MomBasis::getNu() const
389 {
390  return Nu;
391 }
392 
393 int MomBasis::getNd() const
394 {
395  return Nd;
396 }
397 
398 void MomBasis::Print() const
399 {
400  for(int K=0;K<L;K++)
401  {
402  std::cout << "K = " << K << " (" << basisblocks[K]->getdim() << ")" << std::endl;
403 
404  basisblocks[K]->Print();
405  }
406 }
407 
408 void MomBasis::getvec(int K, int i, myint &upket, myint &downket) const
409 {
410  assert(K<L);
411  upket = (*basisblocks[K])[i].first;
412  downket = (*basisblocks[K])[i].second;
413 }
414 
415 const std::pair<myint, myint>& MomBasis::operator()(int K, int index) const
416 {
417  assert(K<L);
418  return (*basisblocks[K])[index];
419 }
420 
421 std::shared_ptr<class KBlock> MomBasis::getBlock(int K) const
422 {
423  assert(K<L);
424  return basisblocks[K];
425 }
426 
428 {
429  std::vector<myint> baseUp;
430  std::vector<myint> baseDown;
431 
432  int dim_up = BareHamiltonian::CalcDim(L, Nu);
433  int dim_down = BareHamiltonian::CalcDim(L, Nd);
434 
435  baseUp.reserve(dim_up);
436  baseDown.reserve(dim_down);
437 
438  myint Hb = 1 << L;
439 
440  for(myint i=0;i<Hb;i++)
441  {
443  baseDown.push_back(i);
444 
446  baseUp.push_back(i);
447  }
448 
449  std::vector< std::tuple<myint,myint,int> > totalmom;
450  totalmom.reserve(dim);
451 
452  // count momentum of earch state
453  for(unsigned int a=0;a<baseUp.size();a++)
454  for(unsigned int b=0;b<baseDown.size();b++)
455  {
456  auto calcK = [] (myint cur) -> int
457  {
458  int tot = 0;
459 
460  while(cur)
461  {
462  // select rightmost up state in the ket
463  myint ksp = cur & (~cur + 1);
464  // set it to zero
465  cur ^= ksp;
466 
467  tot += BareHamiltonian::CountBits(ksp-1);
468  }
469 
470  return tot;
471  };
472 
473  int K = calcK(baseUp[a]) + calcK(baseDown[b]);
474 
475  K %= L;
476 
477  totalmom.push_back(std::make_tuple(baseUp[a],baseDown[b],K));
478  }
479 
480  // not needed anymore, free the memory
481  baseUp.clear();
482  baseDown.clear();
483 
484  // sort to K
485  std::sort(totalmom.begin(), totalmom.end(),
486  [](const std::tuple<myint,myint,int> & a, const std::tuple<myint,myint,int> & b) -> bool
487  {
488  return std::get<2>(a) < std::get<2>(b);
489  });
490 
491  basisblocks.reserve(L);
492  for(int K=0;K<L;K++)
493  basisblocks.push_back(std::shared_ptr<class KBlock>(new KBlock(K,L,Nu,Nd)));
494 
495  std::for_each(totalmom.begin(), totalmom.end(), [this](std::tuple<myint,myint,int> elem)
496  {
497  auto tmp = std::make_pair(std::get<0>(elem), std::get<1>(elem));
498  basisblocks[std::get<2>(elem)]->basis.push_back(tmp);
499  });
500 }
501 
507 SubBasis::SubBasis(int K, MomBasis &orig, int dim)
508 {
509  this->L= orig.getL();
510  this->Nu = orig.getNu();
511  this->Nd = orig.getNd();
512 
513  int space_dim = orig.getdimK(K);
514 
515 // coeffs.reset(new matrix(space_dim,dim));
516 #pragma omp critical
517  {
518  std::cout << "Allocing SubBasis: " << space_dim * dim * sizeof(double) * 1.0/1024/1024 << " MB" << std::endl;
519  }
520  coeffs = std::unique_ptr<class matrix, class MyDeleter> (new matrix(space_dim,dim), MyDeleter(K, (Nu-Nd)/2));
521 
522 
523 // s_coeffs.reset(new SparseMatrix_CCS(space_dim,dim));
524 
525  assert(dim <= space_dim);
526 
527  (*coeffs) = 0;
528  for(int i=0;i<dim;i++)
529  (*coeffs)(i,i) = 1;
530 
531 // s_coeffs->NewCol();
532 // for(int i=0;i<dim;i++)
533 // {
534 // s_coeffs->PushToCol(i,1);
535 // s_coeffs->NewCol();
536 // }
537 // s_coeffs->NewCol();
538 
539  basis = std::move(orig.getBlock(K));
540 }
541 
543 {
544  L = orig.L;
545  Nu = orig.Nu;
546  Nd = orig.Nd;
547 
548 #pragma omp critical
549  if(orig.coeffs)
550  {
551  std::cout << "Allocing clone SubBasis: " << orig.coeffs->getn() * orig.coeffs->getm() * sizeof(double) * 1.0/1024/1024 << " MB" << std::endl;
552  coeffs = std::unique_ptr<class matrix, class MyDeleter> (new matrix(*orig.coeffs.get()), MyDeleter(orig.basis->getK(), (Nu-Nd)/2));
553  }
554 // coeffs.reset(new matrix(*orig.coeffs.get()));
555 
556 // if(orig.s_coeffs)
557 // s_coeffs.reset(new SparseMatrix_CCS(*orig.s_coeffs.get()));
558 
559  basis = orig.basis;
560 }
561 
563 {
564  L = orig.L;
565  Nu = orig.Nu;
566  Nd = orig.Nd;
567 
568  coeffs = std::move(orig.coeffs);
569  basis = std::move(orig.basis);
570 }
571 
573 {
574  L = orig.L;
575  Nu = orig.Nu;
576  Nd = orig.Nd;
577 
578 #pragma omp critical
579  if(orig.coeffs)
580  {
581  std::cout << "Allocing move SubBasis: " << orig.coeffs->getn() * orig.coeffs->getm() * sizeof(double) * 1.0/1024/1024 << " MB" << std::endl;
582 // coeffs.reset(new matrix(*orig.coeffs.get()));
583  coeffs = std::unique_ptr<class matrix, class MyDeleter> (new matrix(*orig.coeffs.get()), MyDeleter(orig.basis->getK(), (Nu-Nd)/2));
584  }
585 
586 // if(orig.s_coeffs)
587 // s_coeffs.reset(new SparseMatrix_CCS(*orig.s_coeffs.get()));
588 
589  basis = orig.basis;
590 
591  return *this;
592 }
593 
595 {
596  L = orig.L;
597  Nu = orig.Nu;
598  Nd = orig.Nd;
599 
600 // if(orig.s_coeffs)
601 // s_coeffs.reset(new SparseMatrix_CCS(*orig.s_coeffs.get()));
602 
603  coeffs = std::move(orig.coeffs);
604  basis = std::move(orig.basis);
605 
606  return *this;
607 }
608 
609 void SubBasis::Print() const
610 {
611  int Hbc = BareHamiltonian::CountBits((1<<L)-1);
612 
613  std::cout << "dim: " << getdim() << " in " << getspacedim() << std::endl;
614 // for(int s=0;s<getdim();s++)
615 // {
616 // for(int i=0;i<s_coeffs->NumOfElInCol(s);i++)
617 // std::cout << s_coeffs->GetElementRowIndexInCol(s, i) << "\t" << \
618 // BareHamiltonian::print_bin(basis->getUp(s_coeffs->GetElementRowIndexInCol(s,i)), Hbc) << " " << \
619 // BareHamiltonian::print_bin(basis->getDown(s_coeffs->GetElementRowIndexInCol(s,i)), Hbc) << std::endl;
620 //
621 // std::cout << std::endl;
622 // }
623 
624  for(int s=0;s<getdim();s++)
625  {
626  for(int i=0;i<getspacedim();i++)
627  std::cout << (*coeffs)(i,s) << "\t" << BareHamiltonian::print_bin(basis->getUp(i), Hbc) << " " << BareHamiltonian::print_bin(basis->getDown(i), Hbc) << std::endl;
628  std::cout << std::endl;
629  }
630 }
631 
635 int SubBasis::getdim() const
636 {
637  if(coeffs)
638  return coeffs->getm();
639  else
640  return s_coeffs->gm();
641 }
642 
647 {
648  if(coeffs)
649  return coeffs->getn();
650  else
651  return s_coeffs->gn();
652 }
653 
659 int SubBasis::getindex(myint upket, myint downket) const
660 {
661  for(int i=0;i<basis->getdim();i++)
662  if(upket == basis->getUp(i) && downket == basis->getDown(i))
663  return i;
664 
665  assert(0 && "Impossible index for subbasis");
666  return -1;
667 }
668 
675 {
676 // std::cout << "Doing slamin: K=" << orig.basis->getK() << " start Sz=" << (orig.Nu-orig.Nd)/2 << " final Sz=" << (Nu-Nd)/2 << std::endl;
677  matrix transform(getspacedim(),orig.getspacedim());
678  transform = 0;
679 
680  for(int i=0;i<orig.getspacedim();i++)
681  {
682  myint upket = orig.basis->getUp(i);
683  myint downket = orig.basis->getDown(i);
684  myint cur = upket;
685 
686  while(cur)
687  {
688  myint ksp = cur & (~cur + 1);
689  cur ^= ksp;
690 
691  // if spin down state is occupied, skip
692  if(downket & ksp)
693  continue;
694 
695  // will give trouble with 16 sites?
696  myint fullstate = (upket << L) + downket;
697 
698  int sign = BareHamiltonian::CountBits( ( ((ksp<<L)-1) ^ (ksp-1) ) & fullstate );
699 
700  if( sign & 0x1)
701  sign = -1;
702  else
703  sign = 1;
704 
705  int index = getindex(upket ^ ksp, downket | ksp);
706 
707  transform(index,i) = sign;
708  }
709  }
710 
711  coeffs->prod(transform, *orig.coeffs);
712 
713  // free the memory
714  orig = SubBasis();
715 
716  Normalize();
717 }
718 
719 void SubBasis::Get(int index, myint &upket, myint &downket) const
720 {
721  assert(index < basis->getdim());
722 
723  upket = basis->getUp(index);
724  downket = basis->getDown(index);
725 }
726 
727 std::pair<myint,myint> SubBasis::Get(int index) const
728 {
729  return (*basis)[index];
730 }
731 
732 double SubBasis::GetCoeff(int i, int j) const
733 {
734  return (*coeffs)(i,j);
735 }
736 
737 double& SubBasis::GetCoeff(int i, int j)
738 {
739  return (*coeffs)(i,j);
740 }
741 
742 void SubBasis::SetCoeff(int i, int j, double value)
743 {
744  (*coeffs)(i,j) = value;
745 }
746 
748 {
749  this->coeffs = std::unique_ptr<class matrix, class MyDeleter> (new matrix(std::move(coeffs)), MyDeleter(basis->getK(), (Nu-Nd)/2));
750 }
751 
756 {
757  for(int i=0;i<getdim();i++)
758  {
759  double norm;
760  int spacedim = getspacedim();
761  int inc = 1;
762 
763  norm = ddot_(&spacedim,&(*coeffs)[i*spacedim],&inc,&(*coeffs)[i*spacedim],&inc);
764  norm = 1.0/sqrt(norm);
765 
766  dscal_(&spacedim,&norm,&(*coeffs)[i*spacedim],&inc);
767  }
768 }
769 
775 {
776  s_coeffs.reset(new SparseMatrix_CCS(coeffs->getn(),coeffs->getm()));
777 
778  s_coeffs->ConvertFromMatrix(*coeffs);
779 
780  coeffs.reset(nullptr);
781 }
782 
788 {
789  assert(s_coeffs);
790  return (*s_coeffs);
791 }
792 
799 BasisList::BasisList(int L, int Nu, int Nd)
800 {
801  this->L= L;
802  this->Nu = Nu;
803  this->Nd = Nd;
804 
805  Smax = (Nu+Nd)/2;
806 
807  totS = ((Smax+1)*(Smax+2))/2;
808 
809  int n = L*totS;
810 
811  ind_list.resize(n, EMPTY);
812  list.resize(n);
813 }
814 
822 bool BasisList::Exists(int K, int S, int Sz) const
823 {
824  if( K >= L || S > Smax || Sz > S)
825  return false;
826 
827  if( ind_list[K*totS + (S*(S+1))/2 + Sz] != EMPTY )
828  return true;
829  else
830  return false;
831 }
832 
840 SubBasis& BasisList::Get(int K, int S, int Sz)
841 {
842  assert(Exists(K, S, Sz) && "Get on nonexisting block");
843 
844  return list[K*totS + (S*(S+1))/2 + Sz];
845 }
846 
856 void BasisList::Create(int K, int S, int Sz, MomBasis &orig, int dim)
857 {
858  list[K*totS + (S*(S+1))/2 + Sz] = SubBasis(K, orig, dim);
859  ind_list[K*totS + (S*(S+1))/2 + Sz] = 1;
860 }
861 
862 void BasisList::Print() const
863 {
864  for(int S=0;S<=Smax;S++)
865  for(int Sz=0;Sz<=S;Sz++)
866  for(int K=0;K<L;K++)
867  if(Exists(K,S,Sz))
868  {
869  std::cout << "Block: S=" << S << " Sz=" << Sz << " K=" << K << std::endl;
870  list[K*totS + (S*(S+1))/2 + Sz].Print();
871  }
872 }
873 
888 void BasisList::DoProjection(int K, int S, int Sz, MomBasis const &orig)
889 {
890  int dimK = orig.getdimK(K);
891  int dim = 0;
892 
893  for(int pS=S+1;pS<=Smax;pS++)
894  if(Exists(K,pS,Sz))
895  dim += Get(K,pS,Sz).getdim();
896 
897  assert(dim <= dimK);
898 
899  std::unique_ptr<matrix> proj_matrix(new matrix(dimK, dim));
900 
901  int s_count = 0;
902  for(int pS=S+1;pS<=Smax;pS++)
903  if(Exists(K,pS,Sz))
904  {
905  auto& cur_basis = Get(K,pS,Sz);
906 
907  assert(dimK == cur_basis.getspacedim());
908 
909  std::memcpy(&(*proj_matrix)(0,s_count), &(cur_basis.GetCoeff(0,0)), sizeof(double) * cur_basis.getdim() * cur_basis.getspacedim());
910 
911  s_count += cur_basis.getdim();
912  }
913 
914 #pragma omp critical
915  {
916  std::cout << "Doing SVD: K=" << K << " S=" << S << " Sz=" << Sz << std::endl;
917  }
918  // proj_matrix will change size!
919  auto sing_vals = proj_matrix->svd();
920 
921  int sing_vals_start = 0;
922  while(sing_vals_start < dim && fabs(sing_vals[sing_vals_start]) > 1e-10)
923  sing_vals_start++;
924 
925  auto &finalbasis = Get(K,S,Sz);
926 
927  assert(finalbasis.getdim() == (dimK-sing_vals_start));
928  assert(finalbasis.getspacedim() == dimK);
929 
930  std::memcpy(&finalbasis.GetCoeff(0,0), &(*proj_matrix)(0,sing_vals_start), sizeof(double) * dimK * finalbasis.getdim());
931 }
932 
936 void BasisList::Clean(int Sz)
937 {
938  for(int S=Smax;S>=Sz;S--)
939  for(int cur_Sz=Smax;cur_Sz>=Sz;cur_Sz--)
940  for(int K=0;K<L;K++)
941  if(Exists(K,S,cur_Sz))
942  {
943  std::cout << "Deleting: S=" << S << " Sz=" << cur_Sz << " K=" << K << std::endl;
944  list[K*totS + (S*(S+1))/2 + Sz] = SubBasis();
945  ind_list[K*totS + (S*(S+1))/2 + cur_Sz] = EMPTY;
946  }
947 }
948 
953 {
954  int n = L*totS;
955 
956  for(int i=0;i<n;i++)
957  ind_list[i] = EMPTY;
958 
959  list.clear();
960 }
961 
970 SpinBasis::SpinBasis(int L,int Nu,int Nd,BasisList &orig)
971 {
972  this->L = L;
973  this->Nu = Nu;
974  this->Nd = Nd;
975 
976  int Sz=(Nu-Nd) >= 0 ? (Nu-Nd)/2 : (Nd-Nu)/2;
977  int Smax = (Nu+Nd)/2;
978 
979  // upper boundary: all S for every K block
980  basis.reserve(L*Smax);
981  ind.reserve(L*Smax);
982 
983  for(int K=0;K<L;K++)
984  for(int S=0;S<=Smax;S++)
985  if(orig.Exists(K,S,Sz))
986  {
987  basis.push_back(std::move(orig.Get(K,S,Sz)));
988  ind.push_back(std::make_pair(K,S));
989  }
990 
991  std::for_each(basis.begin(), basis.end(), [](SubBasis& x) { x.ToSparseMatrix(); });
992 
993  orig.MakeEmpty();
994 }
995 
1000 SpinBasis::SpinBasis(const char *filename)
1001 {
1002  ReadBasis(filename);
1003 }
1004 
1009 {
1010  return basis.size();
1011 }
1012 
1017 void SpinBasis::SaveBasis(const char *filename) const
1018 {
1019  hid_t file_id, group_id, dataset_id, dataspace_id, attribute_id, matspace_id;
1020  herr_t status;
1021 
1022  file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
1023  HDF5_STATUS_CHECK(file_id);
1024 
1025  group_id = H5Gcreate(file_id, "/SpinBasis", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1026  HDF5_STATUS_CHECK(group_id);
1027 
1028  dataspace_id = H5Screate(H5S_SCALAR);
1029 
1030  attribute_id = H5Acreate (group_id, "L", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1031  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &L );
1032  HDF5_STATUS_CHECK(status);
1033  status = H5Aclose(attribute_id);
1034  HDF5_STATUS_CHECK(status);
1035 
1036  attribute_id = H5Acreate (group_id, "Nu", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1037  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &Nu );
1038  HDF5_STATUS_CHECK(status);
1039  status = H5Aclose(attribute_id);
1040  HDF5_STATUS_CHECK(status);
1041 
1042  attribute_id = H5Acreate (group_id, "Nd", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1043  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &Nd );
1044  HDF5_STATUS_CHECK(status);
1045  status = H5Aclose(attribute_id);
1046  HDF5_STATUS_CHECK(status);
1047 
1048  int num = basis.size();
1049  attribute_id = H5Acreate (group_id, "num", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1050  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &num );
1051  HDF5_STATUS_CHECK(status);
1052  status = H5Aclose(attribute_id);
1053  HDF5_STATUS_CHECK(status);
1054 
1055  for(int i=0;i<basis.size();i++)
1056  {
1057  hsize_t dimarr = basis[i].coeffs->getn()*basis[i].coeffs->getm();
1058 
1059  matspace_id = H5Screate_simple(1, &dimarr, NULL);
1060 
1061  std::stringstream name;
1062 
1063  name << i;
1064 
1065  dataset_id = H5Dcreate(group_id, name.str().c_str(), H5T_IEEE_F64LE, matspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1066 
1067  assert(basis[i].coeffs);
1068  status = H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, basis[i].coeffs->getpointer());
1069  HDF5_STATUS_CHECK(status);
1070 
1071  int K = ind[i].first;
1072  int S = ind[i].second;
1073 
1074  attribute_id = H5Acreate (dataset_id, "K", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1075  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &K );
1076  HDF5_STATUS_CHECK(status);
1077  status = H5Aclose(attribute_id);
1078  HDF5_STATUS_CHECK(status);
1079 
1080  attribute_id = H5Acreate (dataset_id, "S", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1081  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &S );
1082  HDF5_STATUS_CHECK(status);
1083  status = H5Aclose(attribute_id);
1084  HDF5_STATUS_CHECK(status);
1085 
1086  int n = basis[i].coeffs->getn();
1087  attribute_id = H5Acreate (dataset_id, "n", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1088  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &n);
1089  HDF5_STATUS_CHECK(status);
1090  status = H5Aclose(attribute_id);
1091  HDF5_STATUS_CHECK(status);
1092 
1093  int m = basis[i].coeffs->getm();
1094  attribute_id = H5Acreate (dataset_id, "m", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT);
1095  status = H5Awrite (attribute_id, H5T_NATIVE_INT, &m);
1096  HDF5_STATUS_CHECK(status);
1097  status = H5Aclose(attribute_id);
1098  HDF5_STATUS_CHECK(status);
1099 
1100  status = H5Sclose(matspace_id);
1101  HDF5_STATUS_CHECK(status);
1102 
1103  status = H5Dclose(dataset_id);
1104  HDF5_STATUS_CHECK(status);
1105  }
1106 
1107  status = H5Sclose(dataspace_id);
1108  HDF5_STATUS_CHECK(status);
1109 
1110  status = H5Gclose(group_id);
1111  HDF5_STATUS_CHECK(status);
1112 
1113  status = H5Fclose(file_id);
1114  HDF5_STATUS_CHECK(status);
1115 }
1116 
1117 void SpinBasis::ReadBasis(const char *filename)
1118 {
1119  hid_t file_id, group_id, attribute_id, dataset_id;
1120  herr_t status;
1121 
1122  file_id = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT);
1123  HDF5_STATUS_CHECK(file_id);
1124 
1125  group_id = H5Gopen(file_id, "/SpinBasis", H5P_DEFAULT);
1126  HDF5_STATUS_CHECK(group_id);
1127 
1128  attribute_id = H5Aopen(group_id, "L", H5P_DEFAULT);
1129  HDF5_STATUS_CHECK(attribute_id);
1130  status = H5Aread(attribute_id, H5T_NATIVE_INT, &L);
1131  HDF5_STATUS_CHECK(status);
1132  status = H5Aclose(attribute_id);
1133  HDF5_STATUS_CHECK(status);
1134 
1135  attribute_id = H5Aopen(group_id, "Nu", H5P_DEFAULT);
1136  HDF5_STATUS_CHECK(attribute_id);
1137  status = H5Aread(attribute_id, H5T_NATIVE_INT, &Nu);
1138  HDF5_STATUS_CHECK(status);
1139  status = H5Aclose(attribute_id);
1140  HDF5_STATUS_CHECK(status);
1141 
1142  attribute_id = H5Aopen(group_id, "Nd", H5P_DEFAULT);
1143  HDF5_STATUS_CHECK(attribute_id);
1144  status = H5Aread(attribute_id, H5T_NATIVE_INT, &Nd);
1145  HDF5_STATUS_CHECK(status);
1146  status = H5Aclose(attribute_id);
1147  HDF5_STATUS_CHECK(status);
1148 
1149  MomBasis pbase(L, Nu, Nd);
1150 
1151  int num;
1152  attribute_id = H5Aopen(group_id, "num", H5P_DEFAULT);
1153  HDF5_STATUS_CHECK(attribute_id);
1154  status = H5Aread(attribute_id, H5T_NATIVE_INT, &num);
1155  HDF5_STATUS_CHECK(status);
1156  status = H5Aclose(attribute_id);
1157  HDF5_STATUS_CHECK(status);
1158 
1159  basis.resize(num);
1160  ind.reserve(num);
1161 
1162  for(int i=0;i<num;i++)
1163  {
1164  basis[i].L = L;
1165  basis[i].Nu = Nu;
1166  basis[i].Nd = Nd;
1167 
1168  std::stringstream name;
1169  name << i;
1170 
1171  int S, K;
1172 
1173  dataset_id = H5Dopen(group_id, name.str().c_str(), H5P_DEFAULT);
1174  HDF5_STATUS_CHECK(dataset_id);
1175 
1176  attribute_id = H5Aopen(dataset_id, "K", H5P_DEFAULT);
1177  HDF5_STATUS_CHECK(attribute_id);
1178  status = H5Aread(attribute_id, H5T_NATIVE_INT, &K);
1179  HDF5_STATUS_CHECK(status);
1180  status = H5Aclose(attribute_id);
1181  HDF5_STATUS_CHECK(status);
1182 
1183  attribute_id = H5Aopen(dataset_id, "S", H5P_DEFAULT);
1184  HDF5_STATUS_CHECK(attribute_id);
1185  status = H5Aread(attribute_id, H5T_NATIVE_INT, &S);
1186  HDF5_STATUS_CHECK(status);
1187  status = H5Aclose(attribute_id);
1188  HDF5_STATUS_CHECK(status);
1189 
1190  ind.push_back(std::make_pair(K,S));
1191 
1192  basis[i].basis = pbase.getBlock(K);
1193 
1194  int n,m;
1195  attribute_id = H5Aopen(dataset_id, "n", H5P_DEFAULT);
1196  HDF5_STATUS_CHECK(attribute_id);
1197  status = H5Aread(attribute_id, H5T_NATIVE_INT, &n);
1198  HDF5_STATUS_CHECK(status);
1199  status = H5Aclose(attribute_id);
1200  HDF5_STATUS_CHECK(status);
1201 
1202  attribute_id = H5Aopen(dataset_id, "m", H5P_DEFAULT);
1203  HDF5_STATUS_CHECK(attribute_id);
1204  status = H5Aread(attribute_id, H5T_NATIVE_INT, &m);
1205  HDF5_STATUS_CHECK(status);
1206  status = H5Aclose(attribute_id);
1207  HDF5_STATUS_CHECK(status);
1208 
1209  basis[i].coeffs.reset(new matrix(n,m));
1210  (*basis[i].coeffs) = -2;
1211 
1212  status = H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, basis[i].coeffs->getpointer() );
1213  HDF5_STATUS_CHECK(status);
1214 
1215  status = H5Dclose(dataset_id);
1216  HDF5_STATUS_CHECK(status);
1217  }
1218 
1219  status = H5Gclose(group_id);
1220  HDF5_STATUS_CHECK(status);
1221 
1222  status = H5Fclose(file_id);
1223  HDF5_STATUS_CHECK(status);
1224 
1225  std::for_each(basis.begin(), basis.end(), [](SubBasis& x) { x.ToSparseMatrix(); });
1226 }
1227 
1228 
1234 std::pair<int,int> SpinBasis::getKS(int index) const
1235 {
1236  return ind[index];
1237 }
1238 
1243 const SubBasis& SpinBasis::getBlock(int index) const
1244 {
1245  return basis[index];
1246 }
1247 
1248 /* vim: set ts=8 sw=4 tw=0 expandtab :*/