/* FILE: simpledemag.h            -*-Mode: c++-*-
 * version 2.0
 *
 * Average H demag field across rectangular cells.  Simple
 * implementation that does not take advantage of any memory
 * saving or calculation speed improvements possible using
 * symmetries in interaction tensor or realness of data in
 * spatial domain.
 *
 * This file is based on appriopriate Oxs_SimpleDemag file, which was written
 * by Mike Donahue as part of the OOMMF package.
 * For the latest information about OOMMF software, see 
 * <URL:http://math.nist.gov/oommf/>.
 *
 * In 2006 the Periodic Boundary Condition (PBC) functionality
 * was added by Kristof Lebecki (nick KL(m)).
 * With large help of Mike Donahue, of course.
 * See the kl_pbc_util.h file for more information.
 *
 */

#ifndef _KLM_SIMPLEDEMAG_PBC
#define _KLM_SIMPLEDEMAG_PBC

#include "key.h"
#include "energy.h"
#include "fft.h"
#include "mesh.h"
#include "meshvalue.h"
#include "simstate.h"
#include "threevector.h"
#include "rectangularmesh.h"

/* End includes */

class Klm_SimpleDemag_PBC:public Oxs_Energy {
private:
  // KL(m) parameters
  // Repetition distance for z-direction. In cell meters.
  // If 0.0 (or absent): use sample z-length
  REAL4m zPeriod_param;
  
  // Fitted accurancy/error (absolute) of the calculations: "image" & "dipole".
  // The errors are fitted with following function (r is the distance cell-cell):
  //      A * r^p
  // You should put a value here basing on previous results analysis.
  // Different values for diagonal (like nXX) and off-diag elements (like nYZ)
  REAL4m error_A_img_diag;  
//  REAL4m error_p_img_diag;  we fix it
  REAL4m error_A_dip_diag;  
//  REAL4m error_p_dip_diag;  
  REAL4m error_A_img_OFFdiag;  
//  REAL4m error_p_img_OFFdiag;  
  REAL4m error_A_dip_OFFdiag;  
//  REAL4m error_p_dip_OFFdiag;  
  
  // The summation will be done until the *cont* error is below a certain 
  // fraction of the actual tensor value:
  //     error_inf_tail < err_ratio_cont_to_N * N
  REAL4m err_ratio_cont_to_N;  
  // Safety stopper in that case (for instance in the case where N==0)
  UINT4m max_no_sum_elements;  
  
  // Fixed number of repetitions in the summation.
  // If set (i.e, non-zero), then this criteria is used
  // instead of the err_ratio_cont_to_N checking
  UINT4m no_of_sum_elements;  
  // Include inifinite tails computation?
  // This is evidently for debugging purposes only
  BOOL include_inf_tails;
  
  // Tensor file storage for future use.
  // The tensor will be kept in two files differing by ID (1 or 2). 
  // 1. If the tensor_file_name is a directory (ends with a slash "/"),
  //    then the files will we writen in this path 
  //    using a geometry-based pattern to distinguish them.
  // 2. Otherwise the files will be created basing on a scheme:
  //    tensor_file_name<ID>tensor_file_suffix
  // Allways the ID will be placed before tensor_file_suffix.
  String tensor_file_name;
  String tensor_file_suffix;
  // Script name for showing the progress. With full path.
  // If epmty/not-present: no progress show.
  String progress_script;
  // Want to speed up the calculations by reducing the z-size 
  // of the evaluated tensor?
  // This can be done only for the case when zdim=NextPowerOfTwo(zim)
  // Choosing 'always' will cause error in other cases
  // Default: 'sometimes' (i.e. when possible)
  // Only implemented for SimpleDemag, so far.
  String turbo;
  // to perform deeper statistics, or not?
  BOOL compute_stats;
  // End of parameters.
  // KL(m) end
  //
  mutable UINT4m xdim;    // Natural size
  mutable UINT4m ydim;
  mutable UINT4m zdim;
  mutable UINT4m totalsize;
  mutable UINT4m pxdim;   // Padded size
  mutable UINT4m pydim;
  mutable UINT4m pzdim;
  mutable UINT4m ptotalsize;
  mutable UINT4m mesh_id;
  // The A## arrays hold demag coefficients, transformed into
  // frequency domain.  These are held long term.  Mx, My, Mz
  // and Hcomp are used as temporary space to convert M into
  // H.
  mutable Oxs_Complex *A00;
  mutable Oxs_Complex *A01;
  mutable Oxs_Complex *A02;
  mutable Oxs_Complex *A11;
  mutable Oxs_Complex *A12;
  mutable Oxs_Complex *A22;
  mutable Oxs_Complex *Mx;
  mutable Oxs_Complex *My;
  mutable Oxs_Complex *Mz;
  mutable Oxs_Complex *Hcomp;
  mutable Oxs_FFT3D fft; // All transforms are same size, so we need
  /// only one Oxs_FFT3D object.
  
  void FillCoefficientArrays(const Oxs_Mesh* mesh) const;
  /// Conceptually const.

  UINT4m NextPowerOfTwo(UINT4m n) const;  // Helper function
  void ReleaseMemory() const; // Conceptually const.

protected:
  virtual void GetEnergy(const Oxs_SimState& state,
			 Oxs_EnergyData& oed) const;

public:
  virtual const char* ClassName() const; // ClassName() is
  /// automatically generated by the OXS_EXT_REGISTER macro.
  Klm_SimpleDemag_PBC(const char* name,  // Child instance id
		  Oxs_Director* newdtr,  // App director
		  const char* argstr);   // MIF input block parameters
  virtual ~Klm_SimpleDemag_PBC() { ReleaseMemory(); }
  virtual BOOL Init();
};


#endif // _KLM_SIMPLEDEMAG_PBC
