/* Write a CASTEP den_fmt file
 * will write grids until the first change in grid size
 */


/* Copyright (c) 2017-2023 MJ Rutter 
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3
 * of the Licence, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see http://www.gnu.org/licenses/
 */ 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include "c2xsf.h"

void denfmt_write(FILE* outfile, struct unit_cell *c, struct contents *m,
                struct grid *g){
  double abc[6],scale;
  unsigned int i,j,k,ii,offset,ngrids,nfft[3],npts,same,nspins;
  char *fmt,*vfmt;
  struct grid *gptr;

  if (flags&HIPREC){
    fmt="  %.15f";
    vfmt="  %.15f  %.15f  %.15f  %.15f";
  }
  else{
    fmt="  % 12.6f";
    vfmt="  % 12.6f  % 12.6f  % 12.6f  % 12.6f";
  }
  
  cart2abc(c,NULL,abc,NULL);
  
  fprintf(outfile," BEGIN header\n \n");

  fprintf(outfile,"           Real Lattice(A)               "
          "Lattice parameters(A)    Cell Angles\n");

  fprintf(outfile," %11.7f %11.7f %11.7f     a = %11.6f  alpha = %11.6f\n",
          c->basis[0][0],c->basis[0][1],c->basis[0][2],abc[0],abc[3]);
  fprintf(outfile," %11.7f %11.7f %11.7f     b = %11.6f  beta  = %11.6f\n",
          c->basis[1][0],c->basis[1][1],c->basis[1][2],abc[1],abc[4]);
  fprintf(outfile," %11.7f %11.7f %11.7f     c = %11.6f  gamma = %11.6f\n",
          c->basis[2][0],c->basis[2][1],c->basis[2][2],abc[2],abc[5]);

  fprintf(outfile," \n");

  ngrids=0;
  nspins=0;
  gptr=g;
  for(i=0;i<3;i++) nfft[i]=g->size[i];
  same=1;
  while(gptr){
    if ((gptr->data)&&(gptr->comps==1)){
      for(i=0;i<3;i++) if (gptr->size[i]!=nfft[i]) same=0;
      if (same) ngrids++;
      else break;
    }
    gptr=gptr->next;
  }
  gptr=g;
  if (!same) fprintf(stderr,"Some grids missed as different sizes present\n");
  if (ngrids==0)
    error_exit("no writable data found");
  if ((gptr->comps==1)&&(gptr->data)&&(gptr->next)&&(gptr->next->comps==3)&&
      (gptr->next->data)&&(gptr->next->size[0]==nfft[0])&&
      (gptr->next->size[1]==nfft[1])&&(gptr->next->size[2]==nfft[2])){
    nspins=4;
    ngrids=1;
  }
/* Jmol detects den_fmt files by the existence of the string "! nspins",
 * so we cannot use the more accurate comment "! ngrids"
 */
/*  fprintf(outfile,"   %d             ! ngrids\n",ngrids); */
  if (nspins==4)
    fprintf(outfile,"   1   T                        "
	    "! nspins, non-collinear spin\n");
  else
    fprintf(outfile,"   %d             ! nspins (really ngrids)\n",ngrids);
  fprintf(outfile,"  %d   %d   %d   ! grid size along <a,b,c>\n",nfft[0],
          nfft[1],nfft[2]);
  fprintf(outfile," END header: data is \"<a b c>");

  if (debug) fprintf(stderr,"Writing %d grids:",ngrids);

  for (i=0;i<ngrids;i++){
    if (gptr->name){
      if (!strncasecmp(gptr->name,"Density",7)){
        fprintf(outfile," charge");
        if (debug) fprintf(stderr," charge");
      }
      else if (!strncasecmp(gptr->name,"Spin",4)){
        fprintf(outfile," spin");
        if (debug) fprintf(stderr," spin");
      }
      else{
        fprintf(outfile," (%s)",gptr->name);
        if (debug) fprintf(stderr," (%s)",gptr->name);
      }
    }
    else{
        fprintf(outfile," (unknown)");
        if (debug) fprintf(stderr," (unknown)");
    }
    if (nspins==4) fprintf(outfile," spin_vector");
    gptr=gptr->next;
  }
  fprintf(outfile,"\"\n");
  if (debug) fprintf(stderr,"\n");
  fprintf(outfile," \n");

  /* Now write the data */

  scale=c->vol;
  if (g->name){
    if ((ngrids<=2)&&(!strncmp(g->name,"ELF",3))) scale=1;
    if ((ngrids<=2)&&(!strncmp(g->name,"ESP",3))) scale=1/H_eV;
    if ((ngrids<=2)&&(!strncmp(g->name,"Potential",9))) scale=1/H_eV;
  }
  if (flags&RAW) scale=1;

  if (debug) fprintf(stderr,"Scaling on writing by %lf\n",scale);

  npts=nfft[0]*nfft[1]*nfft[2];
  for(i=1;i<=nfft[2];i++)
    for(j=1;j<=nfft[1];j++)
      for(k=1;k<=nfft[0];k++){
        fprintf(outfile,"  %4d  %4d  %4d  ",k,j,i);
        gptr=g;
        offset=(i-1)+(j-1)*nfft[2]+(k-1)*nfft[2]*nfft[1];
	if (nspins==4){
	  fprintf(outfile,vfmt,gptr->data[offset]*scale,
		  gptr->next->data[offset]*scale,
		  gptr->next->data[offset+npts]*scale,
		  gptr->next->data[offset+2*npts]*scale);
	}
	else{
	  for(ii=0;ii<ngrids;ii++){
	    fprintf(outfile,fmt,gptr->data[offset]*scale);
	    gptr=gptr->next;
	  }
	}
        fprintf(outfile,"\n");
      }
}
