/* FILE: exchangeptwise.h            -*-Mode: c++-*-
 *
 * 6 neighbor exchange energy on rectangular mesh, with
 * exchange coefficient A specified on a cell-by-cell
 * basis.  The effective coefficient between two neighboring
 * cells is calculated on the fly via 2.A_1.A_2/(A_1+A_2)
 */

#ifndef _OXS_EXCHANGEPTWISE
#define _OXS_EXCHANGEPTWISE

#include "atlas.h"
#include "key.h"
#include "chunkenergy.h"
#include "energy.h"
#include "mesh.h"
#include "meshvalue.h"
#include "simstate.h"
#include "threevector.h"
#include "rectangularmesh.h"
#include "scalarfield.h"
#include "util.h"

/* End includes */

class Oxs_ExchangePtwise:public Oxs_ChunkEnergy {
private:
  Oxs_OwnedPointer<Oxs_ScalarField> A_init;
  mutable OC_UINT4m mesh_id;
  mutable Oxs_MeshValue<OC_REAL8m> A;
  /// Exchange coefficient A is filled by A_init routine
  /// each time a change in the mesh is detected.

  // Support for threaded maxang calculations
  mutable std::vector<OC_REAL8m> maxdot;

  mutable OC_REAL8m energy_density_error_estimate; // Cached value,
  /// initialized when mesh changes.

  // Supplied outputs, in addition to those provided by Oxs_Energy.
  Oxs_ScalarOutput<Oxs_ExchangePtwise> maxspinangle_output;
  Oxs_ScalarOutput<Oxs_ExchangePtwise> stage_maxspinangle_output;
  Oxs_ScalarOutput<Oxs_ExchangePtwise> run_maxspinangle_output;
  void UpdateDerivedOutputs(const Oxs_SimState& state);
  String MaxSpinAngleStateName() const {
    String dummy_name = InstanceName();
    dummy_name += ":Max Spin Angle";
    return dummy_name;
  }
  String StageMaxSpinAngleStateName() const {
    String dummy_name = InstanceName();
    dummy_name += ":Stage Max Spin Angle";
    return dummy_name;
  }
  String RunMaxSpinAngleStateName() const {
    String dummy_name = InstanceName();
    dummy_name += ":Run Max Spin Angle";
    return dummy_name;
  }

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

  virtual void ComputeEnergy(const Oxs_SimState& state,
                             Oxs_ComputeEnergyData& oced) const {
    ComputeEnergyAlt(state,oced);
  }

  virtual void ComputeEnergyChunkInitialize
  (const Oxs_SimState& state,
   Oxs_ComputeEnergyDataThreaded& ocedt,
   Oc_AlignedVector<Oxs_ComputeEnergyDataThreadedAux>& thread_ocedtaux,
   int number_of_threads) const;

  virtual void ComputeEnergyChunkFinalize
  (const Oxs_SimState& state,
   Oxs_ComputeEnergyDataThreaded& ocedt,
   Oc_AlignedVector<Oxs_ComputeEnergyDataThreadedAux>& thread_ocedtaux,
   int number_of_threads) const;

  virtual void ComputeEnergyChunk(const Oxs_SimState& state,
                                  Oxs_ComputeEnergyDataThreaded& ocedt,
                                  Oxs_ComputeEnergyDataThreadedAux& ocedtaux,
                                  OC_INDEX node_start,OC_INDEX node_stop,
                                  int threadnumber) const;

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


#endif // _OXS_EXCHANGEPTWISE
