Task: Implement boundary.F for EinsteinInitialData/Exact thorn

thorn_name: EinsteinInitialData/Exact
src_filename: boundary.F
interface: # Interface definition for thorn Exact
# $Header$

implements: exact
inherits: admbase grid coordgauge staticconformal
friend: ADMCoupling

# evolution thorns need to include these files
# to get our terms in the stress-energy tensor
INCLUDES SOURCE: Scalar_CalcTmunu.inc in CalcTmunu.inc
INCLUDES       : Scalar_CalcTmunu_temps.inc in CalcTmunu_temps.inc

USES INCLUDE   : Slicing.h

################################################################################

#
# copies of our parameters (with keywords decoded into integers)
# for the use of the src/include/Scalar_CalcTmunu.inc code
# (see comments in param.ccl for why we need this)
#
protected:

int Exact_pars_int type=SCALAR
{
# ***** exact_model decoded to an integer
decoded_exact_model

# ***** parameters for models which have nonzero stress-energy tensor terms

### this metric doesn't work and has been moved to ../archive/
### parameters for Robertson-Walker spacetime
##Robertson_Walker___k
##Robertson_Walker___pressure
} "parameters copied to grid scalars so CalcTmunu code sees them in evolution thorns"

real Exact_pars_real type=SCALAR
{
# parameters for Schwarzschild-Lemaitre metric
# (Schwarzschild black hole with cosmological constant)
Schwarzschild_Lemaitre___Lambda
Schwarzschild_Lemaitre___mass
# parameters for Lemaitre-type spacetime
Lemaitre___kappa
Lemaitre___Lambda
Lemaitre___epsilon0
Lemaitre___R0
### this metric doesn't work and has been moved to ../archive/
### parameters for Robertson-Walker spacetime
##Robertson_Walker___R0
##Robertson_Walker___rho
# parameters for de Sitter spacetime
de_Sitter___scale
# parameters for de Sitter spacetime with cosmological constant
de_Sitter_Lambda___scale
# parameters for anti-de Sitter spacetime with cosmological constant
anti_de_Sitter_Lambda___scale
# parameters for Bertotti spacetime
Bertotti___Lambda
# parameters for Kasner-like spacetime
Kasner_like___q
# parameters for generalized Kasner spacetime
Kasner_generalized___p1
Kasner_generalized___p2
# parameters for constant density (Schwarzschild) star
constant_density_star___mass
constant_density_star___radius
} "parameters copied to grid scalars so CalcTmunu code sees them in evolution thorns"

################################################################################
##
### Robertson-Walker metric doesn't work and has been moved to ../archive/
###
### temp variable for some of the stress-energy tensor computations
###
##protected:
##real Exact_robwal_var TYPE=GF
##{
##   raza
##} "Raza universului Robertson Walker"
##
################################################################################

private:

real Exact_slice type=GF
{
  slicex,
  slicey,
  slicez,
  slicet
} "Position of an arbitrary slice in exact solution spacetime"

real Exact_slicetemp1 type=GF
{
  slicetmp1x,
  slicetmp1y,
  slicetmp1z,
  slicetmp1t
} "Temporary grid functions 1"

real Exact_slicetemp2 type=GF
{
  slicetmp2x,
  slicetmp2y,
  slicetmp2z,
  slicetmp2t
} "Temporary grid functions 2"

schedule: # Schedule definitions for thorn Exact
# $Header$

# these are just grid scalars, so there's no harm in leaving storage
# for them on all the time
STORAGE: Exact_pars_int
STORAGE: Exact_pars_real

# This is a grid function, so turning storage for on all the time
# is painful.  But this thorn's src/include/Scalar_CalcTmunu.inc
# code *does* use it...
## this metric doesn't work and has been moved to ./archive/
## STORAGE: Exact_robwal_var

#######################################################################
# PARAMCHECK
#######################################################################

Schedule Exact_ParamCheck at PARAMCHECK
{
LANG: C
OPTIONS: global
} "do consistency checks on our parameters"

#######################################################################
# INITIAL DATA
#######################################################################

# decode/copy parameters into grid scalars
# (to share them properly so Calc_Tmunu code can see them even
#  though it's compiled in other thorns)
Schedule Exact__decode_pars in ADMBase_InitialData
{
LANG: Fortran
} "decode/copy thorn Exact parameters into grid scalars"

# Initial data (g and K) from a trivial slice through an exact solution.

if (CCTK_Equals(initial_data,"exact"))
{
  schedule Exact__initialize in ADMBase_InitialData after Exact__decode_pars
  {
    LANG: Fortran
  } "Set initial data from exact solution on a trivial slice"
}

# Initial data from an arbitrary slice through an exact solution, 
# but NOT evolving the slice afterwards.
# Note we only need storage for the slice itself, and only at startup.

if ( (CCTK_Equals(initial_data,"slice")) && ! (CCTK_Equals(evolution_method,"slice")) )
{
  schedule Exact__slice_initialize in ADMBase_InitialData after Exact__decode_pars
  {
    STORAGE: Exact_slice
    LANG: Fortran
  } "Set initial data from exact solution on an arbitrary slice"
}

#######################################################################
# LAPSE AND SHIFT
#######################################################################

# Lapse and/or shift from a trivial slice through an exact solution.
# At the initial time:

if ( (CCTK_Equals(initial_lapse,"exact")) || (CCTK_Equals(initial_shift,"exact")) || (CCTK_Equals(initial_dtlapse,"exact")) || (CCTK_Equals(initial_dtshift,"exact")) )
{
  schedule Exact__gauge in ADMBase_InitialGauge
  {
    LANG: Fortran
  } "Set initial lapse and/or shift from exact solution on a trivial slice"
}

# During the evolution:

if ( (CCTK_Equals(lapse_evolution_method,"exact")) || (CCTK_Equals(shift_evolution_method,"exact")) || (CCTK_Equals(dtlapse_evolution_method,"exact")) || (CCTK_Equals(dtshift_evolution_method,"exact")) )
{
  schedule Exact__RegisterSlicing at CCTK_STARTUP
  {
    LANG: C
    OPTIONS: global
  } "Register slicings"

  # Necessary if MoL is not used
  schedule Exact__gauge at CCTK_PRESTEP
  {
    LANG: Fortran
  } "Set evolution lapse and/or shift from exact solution on a trivial slice"

  # Necessary if MoL is used
  schedule Exact__gauge in MoL_PostStep BEFORE ADMBase_SetADMVars
  {
    LANG: Fortran
  } "Set evolution lapse and/or shift from exact solution on a trivial slice"
}

#######################################################################
# EVOLUTION
#######################################################################

# Fake the evolution of g and K by evolving the slice and 
# reading them off from the slice again. We need the slice and two
# temporary copies throughout. Note that if we set evolution_system 
# = "slice" without also setting initial_data = "slice", nothing will
# happen as a failsafe, and Cactus should complain about not having an
# evolution routine. Setting initial_data = "slice" on its own is ok though.

if ( (CCTK_Equals(evolution_method,"slice")) && (CCTK_Equals(initial_data,"slice")) )
{
  STORAGE: Exact_slice
  STORAGE: Exact_slicetemp1
  STORAGE: Exact_slicetemp2

  schedule Exact__slice_initialize in ADMBase_InitialData after Exact__decode_pars
  {
    LANG: Fortran
  } "Set initial data from exact solution on arbitrary slice"

  schedule Exact__slice_evolve at CCTK_EVOL
  {
    LANG: Fortran
  } "Evolve arbitrary slice and extract Cauchy data"
}

# Fake the evolution of an exact solution, by setting g and K according
# to the exact solution at CCTK_PRESTEP.

if (CCTK_Equals(evolution_method,"exact"))
{
  schedule Exact__initialize at CCTK_PRESTEP
  {
    LANG: Fortran
  } "Set data from exact solution on an exact slice"
  # Necessary if MoL is used
  schedule Exact__initialize in MoL_PostStep BEFORE ADMBase_SetADMVars
  {
    LANG: Fortran
  } "Set data from exact solution on an exact slice"
}

#######################################################################
# BOUNDARY DATA
#######################################################################

if (CCTK_Equals(overwrite_boundary,"exact"))
{
  schedule Exact__boundary at CCTK_POSTSTEP
  {
    LANG: Fortran
  } "Overwrite g and K on the boundary with exact solution data"
}

param: # parameter definitions for thorn Exact
# $Header$

shares: admbase

################################################################################
##### keyword parameters from other thorns #####################################
################################################################################

USES KEYWORD metric_type

EXTENDS KEYWORD initial_data 
{
  "exact" :: "Initial data from exact solution"
  "slice" :: "Initial data from exact solution on arbitrary slice"
}

EXTENDS KEYWORD lapse_evolution_method
{
  "exact" :: "Use lapse from exact solution"
}
EXTENDS KEYWORD shift_evolution_method
{
  "exact" :: "Use shift from exact solution"
}

EXTENDS KEYWORD dtlapse_evolution_method
{
  "exact" :: "Use lapse from exact solution"
}
EXTENDS KEYWORD dtshift_evolution_method
{
  "exact" :: "Use shift from exact solution"
}

EXTENDS KEYWORD initial_lapse
{
  "exact" :: "Initial lapse from exact solution"
}
EXTENDS KEYWORD initial_shift
{
  "exact" :: "Initial shift from exact solution"
}
EXTENDS KEYWORD initial_dtlapse
{
  "exact" :: "Initial dtlapse from exact solution"
}
EXTENDS KEYWORD initial_dtshift
{
  "exact" :: "Initial dtshift from exact solution"
}

EXTENDS KEYWORD evolution_method
{
  "exact" :: "Fake an evolution by setting exact data at every timestep"
  "slice" :: "Evolve arbitrary slice and extract Cauchy data"
}

shares: StaticConformal

USES KEYWORD conformal_storage

################################################################################
##### parameters for the blended boundary conditions ###########################
################################################################################

private:

BOOLEAN exblend_Ks "Blend the K variables with the exact solution?"
{
} "yes"

BOOLEAN exblend_gs "Blend the g variables with the exact solution?"
{
} "yes"

BOOLEAN exblend_gauge "Blend the lapse and shift with the exact solution?"
{
} "yes"

REAL exblend_rout "Outer boundary of blending region"
{
*:* :: "Positive means radial value, negative means use outer bound of grid"
} -1.0

REAL exblend_width "Width of blending zone"
{
*:* :: "Positive means width in radius, negative means width = exbeldn_width*dx"
} -3.0

################################################################################
##### parameters for slice initialize ##########################################
################################################################################

private:

REAL slice_Gauss_ampl "Amplitude of Gauss slice in exact"
{
0.0:* :: "Positive please"
} 0.0

REAL slice_Gauss_width "Width of Gauss slice in exact"
{
0.0:* :: "Positive please"
} 1.0

# this parameter is used directly in our schedule.ccl file
KEYWORD overwrite_boundary "Overwrite g and K on the boundary"
{
  "no"    :: "Do nothing"
  "exact" :: "Use boundary data from an exact solution on a trivial slice"
} "no"

################################################################################
##### parameters for calculating the extrinsic curvature #######################
################################################################################

private:

INT exact_order "finite differencing order"
{
2 :: "2"
4 :: "4"
} 2

REAL exact_eps "finite differencing stencil size (in terms of the grid spacing)"
{
(0.0:* :: "Positive please"
} 1.0e-6

################################################################################
##### parameters for boosting any non-stress-energy-tensor model ###############
################################################################################

private:

REAL boost_vx "x component of boost velocity"
{
*:* :: "any real number"
} 0.0
REAL boost_vy "y component of boost velocity"
{
*:* :: "any real number"
} 0.0
REAL boost_vz "z component of boost velocity"
{
*:* :: "any real number"
} 0.0

################################################################################
##### parameters for adding to the shift of any model ##########################
################################################################################

private:

REAL shift_add_x "x component of added shift"
{
*:* :: "any real number"
} 0.0
REAL shift_add_y "y component of added shift"
{
*:* :: "any real number"
} 0.0
REAL shift_add_z "z component of added shift"
{
*:* :: "any real number"
} 0.0

################################################################################
##### parameters for rotating any model ########################################
################################################################################

private:

REAL rotation_euler_phi "Euler angle phi (first rotation, about z axis) (irrelevant for axisymmetric models)"
{
*:* :: "any real number"
} 0.0
REAL rotation_euler_theta "Euler angle theta (second rotation, about x axis)"
{
*:* :: "any real number"
} 0.0
REAL rotation_euler_psi "Euler angle psi (third rotation, about z axis)"
{
*:* :: "any real number"
} 0.0

################################################################################
##### general comments #########################################################
################################################################################

#
# All remaining parameters *should* be visible only to this thorn
# and its friends.  In particular, the stress-energy tensor code in
# src/include/Scalar_CalcTmunu.inc needs to look at various parameters to
# see what to do... and (via the magic of #include and the Cactus
# USES INCLUDE SOURCE mechanism) this code is effectively part of
# various evolution thorns.
#
# Alas, Cactus doesn't (yet) provide any way for a (this) thorn to "push"
# parameters into friends without the friends having to know where the
# pushed parameters came from... and we don't want the evolution thorns
# themselves to have to know our name and those of all the other thorns
# which provide pieces of the stress-energy tensor.
#
# Instead, we use a kludge: we copy all the relevant parameters
# (exact_model and all those for models which have stress-energy tensor
# computations) into restricted grid scalars.  These _are_ "pushed" into
# friends... and because friendship is transitive, it suffices for us to
# be friends of ADMCoupling.
#
# Since grid scalars can't be varying-length character strings, we also
# have to decode keyword parameters into integers in this process.  The
# values for those integers are given by #define constants in
# src/include/param_defs.inc .
#

################################################################################

#
# ***** naming conventions *****
#
# A "model" refers to the combination of a spacetime and a coordinate
# system; we use the model name "spacetime/coordinates" in cases where
# we have the same spacetime in different coordinate systems.
#
# We use "spacetime+Lambda" to describe a with-cosmological-constant
# variant of a given spacetime.
#
# All the parameters for individual models have names which begin
# with the model name (with any '/' or '-' characters converted to '_'),
# followed by '__'.  The description comment for each parameter begins
# with the model name followed by ':'.  For example:
#
#	REAL Schwarzschild_EF__mass "Schwarzschild/EF: BH mass"
#	{
#	*:* :: "any real number"
#	} 1.0
#

################################################################################
##### exact_model ##############################################################
################################################################################

restricted:

#
# see the file  doc/how_to_add_a_new_model  for instructions on adding
# a new model
#
KEYWORD exact_model "The exact solution/coordinates used in thorn exact"
{
#
# Minkowski spacetime
#
"Minkowski"                    :: "Minkowski spacetime"
"Minkowski/shift"              :: "Minkowski spacetime with time-dependent shift vector"
"Minkowski/funny"              :: "Minkowski spacetime in non-trivial spatial coordinates"
"Minkowski/gauge wave"         :: "Minkowski spacetime in gauge-wave coordinates"
"Minkowski/shifted gauge wave" :: "Minkowski spacetime in shifted gauge-wave coordinates"
"Minkowski/conf wave"          :: "Minkowski spacetime with 'waves' in conformal factor"
#
# black hole spacetimes
#
"Schwarzschild/EF"           :: "Schwarzschild spacetime in Eddington-Finkelstein coordinates"
"Schwarzschild/PG"           :: "Schwarzschild spacetime in Painleve-Gullstrand coordinates"
"Schwarzschild/BL"           :: "Schwarzschild spacetime in Brill-Lindquist coordinates"
"Schwarzschild/Novikov"      :: "Schwarzschild spacetime in Novikov coordinates"
"Schwarzschild-Lemaitre"     :: "Schwarzschild metric in Schwarzschild coordinates, with cosmological constant"
"Kerr/Boyer-Lindquist"       :: "Kerr spacetime in Boyer-Lindquist coordinates"
"Kerr/Kerr-Schild"           :: "Kerr spacetime in Kerr-Schild coordinates"
"Kerr/Kerr-Schild/spherical" :: "Kerr spacetime in distorted Kerr-Schild coordinates such that the horizon is a coordinate sphere"
"multi-BH"                   :: "Majumdar-Papapetrou or Kastor-Traschen maximally charged multi BH solutions"
"Alvi"                       :: "Alvi post-Newtonian 2BH spacetime (not fully implemented yet)"
"Thorne-fakebinary"          :: "Thorne's fake-binary spacetime (non-Einstein)"
#
# cosmological spacetimes
#
"Lemaitre"              :: "Lemaitre-type spacetime"
##"Robertson-Walker"      :: "Robertson-Walker spacetime"
"de Sitter"             :: "de Sitter spacetime (R-W cosmology, near t=0, p=0)"
"de Sitter+Lambda"      :: "de Sitter spacetime with cosmological constant"
"anti-de Sitter+Lambda" :: "anti-de Sitter spacetime with cosmological constant"
"Bianchi I"             :: "approximate Bianchi type I spacetime"
"Goedel"                :: "Goedel spacetime"
"Bertotti"              :: "Bertotti spacetime"
"Kasner-like"           :: "Kasner-like spacetime"
"Kasner-axisymmetric"   :: "axisymmetric Kasner spacetime"
"Kasner-generalized"    :: "generalized Kasner spacetime"
"Gowdy-wave"	        :: "Gowdy spacetime with polarized wave on a torus"
"Milne"                 :: "Milne spacetime for pre-big-bang cosmology"
#
# miscelaneous spacetimes
#
"boost-rotation symmetric" :: "boost-rotation symmetric spacetime"
"bowl"                     :: "bowl (bag-of-gold) spacetime (non-Einstein)"
"constant density star"    :: "constant density (Schwarzschild) star"
} "Minkowski"

################################################################################
##### Minkowski spacetime ######################################################
################################################################################

#
# parameters for Minkowski spacetime (trivial txyz coordinates)
#

# there are no parameters

################################################################################

#
# parameters for Minkowski spacetime with time-dependent shift vector
#

REAL Minkowski_shift__amplitude "Minkowski/shift: amplitude of Gaussian"
{
(-1:1) :: "any real number < 1 in absolute value"
} 0.5

REAL Minkowski_shift__sigma "Minkowski/shift: width of Gaussian"
{
(0.0:* :: "any real number > 0"
} 1.0

################################################################################

#
# parameters for Minkowski spacetime with non-trivial spatial coordinates
#

# FIXME: can this also be negative, i.e. range (-1,1)?
REAL Minkowski_funny__amplitude "Minkowski/funny: amplitude of Gaussian"
{
0.0:1.0) :: "any real number in the range [0,1)"
} 0.5

REAL Minkowski_funny__sigma "Minkowski/funny: width of Gaussian"
{
(0.0: :: "any real number > 0"
} 1.0

################################################################################

#
# parameters for Minkowski spacetime in gauge-wave coordinates
#

KEYWORD Minkowski_gauge_wave__what_fn \
  "Minkowski/gauge wave: what function to use"
{
"sin"      :: "1-a*sin(x)"
"expsin"   :: "exp(a*sin(x)*cos(t))"
"Gaussian" :: "1-a*exp(-x**2)"
} "sin"
 
REAL Minkowski_gauge_wave__amplitude \
  "Minkowski/gauge wave: amplitude of the wave"
{
*:* :: "any real number"
} 0.5
  
REAL Minkowski_gauge_wave__omega \
  "Minkowski/gauge wave: angular frequency of the wave in time"
{
*:* :: "any real number"
} 1.0
    
BOOLEAN Minkowski_gauge_wave__diagonal \
  "Minkowski/gauge wave: should the wave run diagonally across the grid?"
{
} "no"
   
REAL Minkowski_gauge_wave__lambda \
  "Minkowski/gauge wave: wavelength of waves"
{
*:* :: "any real number"
} 0.5    

REAL Minkowski_gauge_wave__phase \
  "Minkowski/gauge wave: phase shift of wave"
{
*:* :: "any real number"
} 0.0

################################################################################

#
# parameters for Minkowski spacetime in gauge-wave coordinates
#

REAL Minkowski_conf_wave__amplitude \
  "Minkowski/conf wave: amplitude of the variation of the conformal factor"
{
  0:* :: "any positive real number"
} 0.5

REAL Minkowski_conf_wave__wavelength \
  "Minkowski/conf wave: wave length in cactus units"
{
  0:* :: "any positive real number"
} 1.0

INT Minkowski_conf_wave__direction \
  "Minkowski/conf wave: direction of 'wave' 0,1,2 : x,y,z"
{
  0:2 :: "0, 1 or 2 for x, y or z"
} 0

################################################################################
##### black hole spacetimes ####################################################
################################################################################

#
# parameters for Schwarzschild metric in Eddington-Finkelstein coordinates
#

REAL Schwarzschild_EF__mass "Schwarzschild/EF: BH mass"
{
*:* :: "any real number"
} 1.0

REAL Schwarzschild_EF__epsilon "Schwarzschild/EF: numerical fudge"
{
0.0:* :: "any real number >= 0.0"
} 1.e-16

################################################################################

#
# parameters for Schwarzschild metric in Painleve-Gustrand coordinates
#

REAL Schwarzschild_PG__mass "Schwarzschild/PG: BH mass"
{
(0.0:* :: "any real number > 0.0"
} 1.0

REAL Schwarzschild_PG__epsilon "Schwarzschild/PG: numerical fudge"
{
0.0:* ::  "any real number >= 0.0"
} 1.e-16

################################################################################

#
# parameters for Schwarzschild metric in Brill-Lindquist coordinates
#

REAL Schwarzschild_BL__mass "Schwarzschild/BL: BH mass"
{
(0.0:* :: "any real number > 0.0"
} 1.0

REAL Schwarzschild_BL__epsilon "Schwarzschild/BL: numerical fudge"
{
0.0:* :: "any real number >= 0.0"
} 1.e-16

################################################################################

# parameters for Schwarzschild metric in Novikov coordinates

REAL Schwarzschild_Novikov__mass "Schwarzschild/Novikov: BH mass"
{
(0.0:* :: "any real number > 0.0"
} 1.0

REAL Schwarzschild_Novikov__epsilon "Schwarzschild/Novikov: numerical fudge"
{
0.0:* :: "any real number >= 0.0"
} 1.e-16

################################################################################

# parameters for Schwarzschild-Lemaitre metric
# (Schwarzschild black hole with cosmological constant)

REAL Schwarzschild_Lemaitre__Lambda "Schwarzschild-Lemaitre: cosmological constant"
{
*:* :: "any real number"
} 1.0

REAL Schwarzschild_Lemaitre__mass "Schwarzschild-Lemaitre: BH mass"
{
(0.0:* :: "any real number > 0"
} 1.0

################################################################################

# parameters for Kerr metric in Boyer-Lindquist coordinates

REAL Kerr_BoyerLindquist__spin \
  "Kerr/Boyer-Lindquist: dimensionless spin parameter a = J/m^2"
{
-1.0:1.0 :: "dimensionless spin parameter a = J/m^2 for Kerr black hole"
} 0.6

REAL Kerr_BoyerLindquist__mass "Kerr/Boyer-Lindquist: BH mass"
{
(0.0:* :: "any real number > 0"
} 1.0

################################################################################

#
# parameters for Kerr metric in Kerr-Schild coordinates
#

# the black hole is boosted in the z direction with this velocity,
# i.e., the black hole is located at x=0, y=0, and z=vt
REAL Kerr_KerrSchild__boost_v "Kerr/Kerr-Schild: boost velocity of black hole in z direction"
{
(-1:1) :: "any real number with absolute value < 1"
} 0.0

REAL Kerr_KerrSchild__epsilon "Kerr/Kerr-Schild: numerical fudge"
{
0.0:* :: "any real number >= 0.0"
} 1.e-16

INT Kerr_KerrSchild__power "Kerr/Kerr-Schild: power (exponent) of numerical fudge"
{
1:* :: ""
} 4

BOOLEAN Kerr_KerrSchild__parabolic "Kerr/Kerr-Schild: use a parabolic singularity-avoiding term"
{
} "no"

REAL Kerr_KerrSchild__mass "Kerr/Kerr-Schild: BH mass"
{
(0.0:* :: "any real number > 0"
} 1.0

REAL Kerr_KerrSchild__spin \
  "Kerr/Kerr-Schild: dimensionless spin parameter a = J/m^2"
{
-1.0:1.0 :: "dimensionless spin parameter a = J/m^2 for Kerr black hole"
} 0.6

REAL Kerr_KerrSchild__x \
  "Kerr/Kerr-Schild: x-coordinate of black hole"
{
(*:*) :: ""
} 0.0

REAL Kerr_KerrSchild__y \
  "Kerr/Kerr-Schild: y-coordinate of black hole"
{
(*:*) :: ""
} 0.0

REAL Kerr_KerrSchild__z \
  "Kerr/Kerr-Schild: z-coordinate of black hole"
{
(*:*) :: ""
} 0.0

REAL Kerr_KerrSchild__t \
  "Kerr/Kerr-Schild: time offset of black hole"
{
(*:*) :: ""
} 0.0

################################################################################

#
# parameters for Majumdar-Papapetrou or Kastor-Traschen
# maximally-charged multiple black hole solution
#

INT multi_BH__nBH "multi-BH: number of black holes 0-4"
{
0:4 :: "any integer in the range [0,4]"
} 0

REAL multi_BH__Hubble "multi-BH: Hubble constant = +/- sqrt{Lambda/3}"
{
*:* :: "any real number"
} 0.0

# black hole #1
REAL multi_BH__mass1 "multi-BH: mass of black hole number 1"
{
0.0: :: "any real number >= 0"
} 0.0
REAL multi_BH__x1 "multi-BH: x coord of black hole number 1"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__y1 "multi-BH: y coord of black hole number 1"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__z1 "multi-BH: z coord of black hole number 1"
{
*:* :: "any real number"
} 0.0

# black hole #2
REAL multi_BH__mass2 "multi-BH: mass of black hole number 2"
{
0.0: :: "any real number >= 0"
} 0.0
REAL multi_BH__x2 "multi-BH: x coord of black hole number 2"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__y2 "multi-BH: y coord of black hole number 2"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__z2 "multi-BH: z coord of black hole number 2"
{
*:* :: "any real number"
} 0.0

# black hole #3
REAL multi_BH__mass3 "multi-BH: mass of black hole number 3"
{
0.0: :: "any real number >= 0"
} 0.0
REAL multi_BH__x3 "multi-BH: x coord of black hole number 3"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__y3 "multi-BH: y coord of black hole number 3"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__z3 "multi-BH: z coord of black hole number 3"
{
*:* :: "any real number"
} 0.0

# black hole #4
REAL multi_BH__mass4 "multi-BH: mass of black hole number 4"
{
0.0:* :: "any real number >= 0"
} 0.0
REAL multi_BH__x4 "multi-BH: x coord of black hole number 4"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__y4 "multi-BH: y coord of black hole number 4"
{
*:* :: "any real number"
} 0.0
REAL multi_BH__z4 "multi-BH: z coord of black hole number 4"
{
*:* :: "any real number"
} 0.0

################################################################################

#
# parameters for Alvi spacetime
#

REAL Alvi__mass1 "Alvi: mass of BH number 1"
{
0.0:* :: "any real number >= 0"
} 1.0

REAL Alvi__mass2 "Alvi: mass of BH number 2"
{
0.0:* :: "any real number >= 0"
} 1.0

REAL Alvi__separation "Alvi: spatial separation of the black holes"
{
0.0:* :: "must be greater than m1+m2 + 2 sqrt(m1 m2)"
} 20.0

################################################################################

#
# parameters for Thorne's fake binary solution
#

KEYWORD Thorne_fakebinary__atype "Thorne-fakebinary: binary type"
{
  "constant"   :: ""
  "quadrupole" :: ""
} "constant"

BOOLEAN Thorne_fakebinary__retarded "Thorne-fakebinary: use retarded time?"
{
} "no"

# FIXME: can this really be exactly 0.0?
REAL Thorne_fakebinary__epsilon "Thorne-fakebinary: numerical fudge"
{
0.0:* :: "any real number >= 0.0"
} 1.e-16

REAL Thorne_fakebinary__separation "Thorne-fakebinary: initial separation"
{
(0.0:* :: "any real number > 0"
} 5.0

REAL Thorne_fakebinary__Omega0 "Thorne-fakebinary: initial angular frequency"
{
(0.0:* :: "any real number > 0"
} 1.0

REAL Thorne_fakebinary__mass "Thorne-fakebinary: mass"
{
(0.0:* :: "any real number > 0"
} 1.0

# FIXME: can this really be exactly 0.0?
REAL Thorne_fakebinary__smoothing \
  "Thorne-fakebinary: smoothing for Newtonian potential"
{
0.0:* :: "any real number >= 0"
} 0.0

################################################################################
##### cosmological spacetimes ##################################################
################################################################################

#
# parameters for Lemaitre-type spacetime
#

REAL Lemaitre__kappa "Lemaitre: multiplicative factor in equation of state"
{
*:* :: "any real number"
} -0.5

REAL Lemaitre__Lambda "Lemaitre: cosmological constant"
{
*:* :: "any real number"
} 1.0

REAL Lemaitre__epsilon0 "Lemaitre: density of the universe at time t=0"
{
0.0:* :: "any real number >= 0"
} 1.0

REAL Lemaitre__R0 "Lemaitre: scale factor (radius) of the universe at time t=0"
{
(0.0:* :: "any positive real number"
} 1.0

################################################################################
##
###
### parameters for Robertson-Walker spacetime
###
##
##REAL Robertson_Walker__R0 \
##  "Robertson-Walker: scale factor (radius) of the universe at time t=0"
##{
##(0.0:* :: "any positive real number"
##} 0.1
##
##REAL Robertson_Walker__rho "Robertson-Walker: density parameter"
##{
##0.0:* :: "any real number >= 0"
##} 0.1
##
##INT Robertson_Walker__k "Robertson-Walker: geometry type parameter"
##{
##-1:1:1 :: "one of the values -1, 0, 1"
##} 0
##
### true ==> include pressure terms (radiation-dominated universe)
### false ==> don't include pressure terms (matter-dominated universe)
##BOOLEAN Robertson_Walker__pressure \
##  "Robertson-Walker: are pressure terms included?"
##{
##} "true"
##
################################################################################

#
# parameters for de Sitter spacetime
#

REAL de_Sitter__scale "de Sitter: multiplicative scale factor"
{
(0.0:* :: "any positive real number"
} 0.1

################################################################################

#
# parameters for de Sitter spacetime with cosmological constant
#

REAL de_Sitter_Lambda__scale "de Sitter+Lambda: multiplicative scale factor"
{
(0.0:* :: "any positive real number"
} 0.1

################################################################################

#
# parameters for anti-de Sitter spacetime with cosmological constant
#

REAL anti_de_Sitter_Lambda__scale \
  "anti-de Sitter+Lambda: multiplicative scale factor"
{
(0.0:* :: "any positive real number"
} 0.1

################################################################################

#
# parameters for Bianchi type I cosmology
#

REAL Bianchi_I__scale "Bianchi I: multiplicative scale factor"
{
(0.0:* :: "any positive real number"
} 0.1

################################################################################

#
# parameters for Goedel spacetime
#

REAL Goedel__scale "Goedel: multiplicative scale factor"
{
(0.0:* :: "any positive real number"
} 0.1

################################################################################

#
# parameters for Bertotti spacetime
#

REAL Bertotti__Lambda "Bertotti: cosmological constant"
{
*:* :: "any real number"
} -1.0

################################################################################

#
# parameters for Kasner-like spacetime
#

# FIXME: can we somehow use the expression 2.0/3.0 for the default value?
REAL Kasner_like__q "Kasner-like: q parameter"
{
*:* :: "any real number"
} 0.66666666666666666666

################################################################################

#
# parameters for axisymmetric Kasner spacetime
#

# there are no parameters

################################################################################

#
# parameters for generalized Kasner spacetime
#

REAL Kasner_generalized__p1 "Kasner-generalized: x exponent parameter"
{
-1.0:1.0 :: "any real number in the range [-1,1]"
} 0.1

REAL Kasner_generalized__p2 "Kasner-generalized: y exponent parameter"
{
-1.0:1.0 :: "any real number in the range [-1,1]"
} 0.1

################################################################################

#
# parameters for Gowdy polarized wave spacetime
#

REAL Gowdy_wave__amplitude "Gowdy-wave: amplitude parameter"
{
*:* :: "any real number"
} 0.0

################################################################################

#
# parameters for Milne spacetime
#

# there are no parameters

################################################################################
##### miscellaneous spacetimes #################################################
################################################################################

#
# parameters for boost-rotation symmetricmetric spacetime
#

REAL boost_rotation_symmetric__scale "boost-rotation symmetric: length scale"
{
0.0:* :: "Positive please"
} 1.0

REAL boost_rotation_symmetric__amp \
  "boost-rotation symmetric: dimensionless amplitude"
{
0.0:* :: "Positive please"
} 0.1

REAL boost_rotation_symmetric__min_d \
  "boost-rotation symmetric: dimensionless safety distance"
{
(0.0:* :: "any positive real number"
} 0.01

################################################################################

#
# parameters for bowl (bag-of-gold) spacetime (non-Einstein)
#

KEYWORD bowl__shape "bowl: what shape of bowl should we use?"
{
  "Gaussian" :: "Gaussian bowl"
  "Fermi"    :: "Fermi-function bowl"
} "Gaussian"

BOOLEAN bowl__evolve "bowl: are we evolving the metric?"
{
} "false"

# FIXME: can this really be arbitrarily large?
# FIXME: can this be negative?
REAL bowl__strength "bowl: deformation strength"
{
0.0:* :: "any real number >= 0"
} 0.5

REAL bowl__center "bowl: deformation center"
{
(0.0:* :: "any positive real number"
} 2.5

# n.b. for bowl__shape = "Gaussian", this parameter is actually
#      sqrt(2) times the standard deviation of the Gaussian
REAL bowl__sigma "bowl: width of deformation"
{
(0.0:* :: "any positive real number"
} 1.0

REAL bowl__x_scale "bowl: scale for x coordinate"
{
(0.0:* :: "any positive real number"
} 1.0

REAL bowl__y_scale "bowl: scale for y coordinate"
{
(0.0:* :: "any positive real number"
} 1.0

REAL bowl__z_scale "bowl: scale for z coordinate"
{
(0.0:* :: "any positive real number"
} 1.0

REAL bowl__t0 "bowl: center of Fermi step in time"
{
*:* :: "any real number"
} 1.0

REAL bowl__sigma_t "bowl: width of Fermi step in time"
{
(0.0:* :: "any positive real number"
} 1.0

################################################################################

#
# parameters for constant density (Schwarzschild) star
#

REAL constant_density_star__mass "constant density star: mass of star"
{
(0.0:* :: "any positive real number"
} 1.0

# FIXME: is this default value ok? (does it give a star or a BH?)
REAL constant_density_star__radius "constant density star: radius of star"
{
(0.0:* :: "any positive real number"
} 1.0

################################################################################

configuration: # Configuration definition for thorn Exact
# $Header$

REQUIRES THORNS: CoordGauge

context: gauge.F:
```
C     This routine sets the lapse and/or shift by calling a routine
C     that does it pointwise. Note that it could be easily modified
C     to set the Bona-Masso variables B_xx etc. 
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

      subroutine Exact__gauge(CCTK_ARGUMENTS)

      implicit none

      DECLARE_CCTK_ARGUMENTS
      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

      integer i,j,k
      integer nx,ny,nz
      logical set_lapse, set_dtlapse, set_shift, set_dtshift

      CCTK_REAL tt, xx, yy, zz
      CCTK_REAL gxxtmp, gyytmp, gzztmp, 
     $     gxytmp, gyztmp, gxztmp,
     $     hxxtmp, hyytmp, hzztmp, 
     $     hxytmp, hyztmp, hxztmp,
     $     dxgxxtmp, dxgyytmp, dxgzztmp, 
     $     dxgxytmp, dxgyztmp, dxgxztmp,
     $     dygxxtmp, dygyytmp, dygzztmp, 
     $     dygxytmp, dygyztmp, dygxztmp,
     $     dzgxxtmp, dzgyytmp, dzgzztmp, 
     $     dzgxytmp, dzgyztmp, dzgxztmp,
     $     alptmp, dtalptmp, axtmp, aytmp, aztmp, 
     $     betaxtmp, betaytmp, betaztmp,
     $     dtbetaxtmp, dtbetaytmp, dtbetaztmp,
     $     bxxtmp, bxytmp, bxztmp, 
     $     byxtmp, byytmp, byztmp, 
     $     bzxtmp, bzytmp, bzztmp
      CCTK_REAL
     $     exact_psi,
     $     exact_psix, exact_psiy, exact_psiz,
     $     exact_psixx, exact_psiyy, exact_psizz,
     $     exact_psixy, exact_psiyz, exact_psixz
      LOGICAL is_initial_slice, is_later_slice

C     are we on the initial slice or some later slice?
C     n.b. the logical expressions later in this function involving
C          these flags below would be *so* much nicer if Fortran
C          grokked C-style conditional expressions... :) :)
      is_initial_slice = cctk_iteration .eq. 0
      is_later_slice   = cctk_iteration .ne. 0

C     Grid parameters.
      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

C     This code used to set  t = time + dt/2  to get 2nd order accuracy,
C     but this leads to the initial data being set at the wrong time. :(
C     In the context of MoL, we want to set variables at the standard Cactus
C     time (cctk_time), because MoL takes care of calling us at each MoL
C     iteration, and updating the field variables appropriately.
C
C     Alas, setting at cctk_time probably gives O(dt) errors for non-MoL
C     evoutions where Exact is used to set stuff at each time step.
C     Fixing this [unless we just declare all non-MoL stuff obselete :) ]
C     probably requires cleaning up our (++messy)  schedule.ccl , which
C     is why this remains a bug for now... :( :(

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

C
C     Set lapse and/or shift?
C
      if ( is_initial_slice ) then
         set_lapse   = CCTK_Equals(initial_lapse,   "exact").ne.0
         set_shift   = CCTK_Equals(initial_shift,   "exact").ne.0
         set_dtlapse = CCTK_Equals(initial_dtlapse, "exact").ne.0
         set_dtshift = CCTK_Equals(initial_dtshift, "exact").ne.0
      end if
      if ( is_later_slice ) then
         set_lapse   = CCTK_Equals(lapse_evolution_method, "exact").ne.0
         set_shift   = CCTK_Equals(shift_evolution_method, "exact").ne.0
         set_dtlapse = CCTK_Equals(dtlapse_evolution_method, "exact").ne.0
         set_dtshift = CCTK_Equals(dtshift_evolution_method, "exact").ne.0
      end if

      if ( set_lapse .or. set_shift .or. set_dtlapse .or. set_dtshift) then

C$omp    parallel do private (
C$omp$     i, j, k,
C$omp$     tt, xx, yy, zz,
C$omp$     alptmp, dtalptmp, axtmp, aytmp, aztmp, 
C$omp$     betaxtmp, betaytmp, betaztmp,
C$omp$     dtbetaxtmp, dtbetaytmp, dtbetaztmp,
C$omp$     bxxtmp, bxytmp, bxztmp, 
C$omp$     byxtmp, byytmp, byztmp, 
C$omp$     bzxtmp, bzytmp, bzztmp,
C$omp$     dxgxxtmp, dxgyytmp, dxgzztmp, 
C$omp$     dxgxytmp, dxgyztmp, dxgxztmp,
C$omp$     dygxxtmp, dygyytmp, dygzztmp, 
C$omp$     dygxytmp, dygyztmp, dygxztmp,
C$omp$     dzgxxtmp, dzgyytmp, dzgzztmp, 
C$omp$     dzgxytmp, dzgyztmp, dzgxztmp,
C$omp$     exact_psi,
C$omp$     exact_psix, exact_psiy, exact_psiz,
C$omp$     exact_psixx, exact_psiyy, exact_psizz,
C$omp$     exact_psixy, exact_psiyz, exact_psixz)
         do k=1,nz
            do j=1,ny
               do i=1,nx

                  tt = cctk_time
                  xx = x(i,j,k) - cctk_time * shift_add_x
                  yy = y(i,j,k) - cctk_time * shift_add_y
                  zz = z(i,j,k) - cctk_time * shift_add_z

C     Initialize the psi of exact
C     (also to tell the models about the conformal_state)
                  if (conformal_state .ne. 0) then
                    exact_psi = 1.0D0
                  else
                    exact_psi = 0.0D0
                  end if
                  exact_psix = 0.0D0
                  exact_psiy = 0.0D0
                  exact_psiz = 0.0D0
                  exact_psixx = 0.0D0
                  exact_psiyy = 0.0D0
                  exact_psizz = 0.0D0
                  exact_psixy = 0.0D0
                  exact_psiyz = 0.0D0
                  exact_psixz = 0.0D0

                  call Exact__Bona_Masso_data(
     $                 decoded_exact_model,
     $                 xx, yy, zz, tt,
     $                 gxxtmp, gyytmp, gzztmp, 
     $                 gxytmp, gyztmp, gxztmp,
     $                 hxxtmp, hyytmp, hzztmp, 
     $                 hxytmp, hyztmp, hxztmp,
     $                 exact_psi,
     $                 exact_psix, exact_psiy, exact_psiz,
     $                 exact_psixx, exact_psiyy, exact_psizz,
     $                 exact_psixy, exact_psiyz, exact_psixz,
     $                 dxgxxtmp, dxgyytmp, dxgzztmp, 
     $                 dxgxytmp, dxgyztmp, dxgxztmp,
     $                 dygxxtmp, dygyytmp, dygzztmp, 
     $                 dygxytmp, dygyztmp, dygxztmp,
     $                 dzgxxtmp, dzgyytmp, dzgzztmp, 
     $                 dzgxytmp, dzgyztmp, dzgxztmp,
     $                 alptmp, dtalptmp, axtmp, aytmp, aztmp, 
     $                 betaxtmp, betaytmp, betaztmp,
     $                 dtbetaxtmp, dtbetaytmp, dtbetaztmp,
     $                 bxxtmp, bxytmp, bxztmp, 
     $                 byxtmp, byytmp, byztmp, 
     $                 bzxtmp, bzytmp, bzztmp)

                  if ( set_lapse ) then
                     alp(i,j,k) = alptmp
                  end if
                  if ( set_shift ) then
                     betax(i,j,k) = betaxtmp + shift_add_x
                     betay(i,j,k) = betaytmp + shift_add_y
                     betaz(i,j,k) = betaztmp + shift_add_z
                  end if
                  if ( set_dtlapse ) then
                     dtalp(i,j,k) = dtalptmp
                  end if
                  if ( set_dtshift ) then
                     dtbetax(i,j,k) = dtbetaxtmp
                     dtbetay(i,j,k) = dtbetaytmp
                     dtbetaz(i,j,k) = dtbetaztmp
                  end if
               end do
            end do
         end do

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

      else
         call CCTK_WARN(1,'Exact__gauge has been called without doing anything')
      end if

      return
      end

```

ParamCheck.c:
```
 /*@@
   @file      ParamCheck.c
   @date      Ues April 30 2002
   @author    Gabrielle Allen
   @desc 
   Parameter checking stuff for Exact
   @enddesc
   @version $Header$
 @@*/

#include "cctk.h"

#include "cctk_Arguments.h"
#include "cctk_Parameters.h"

static const char *rcsid = "$Header$";

CCTK_FILEVERSION(AEIDevelopment_Exact_ParamCheck_c)

/********************************************************************
 *********************     Local Data Types   ***********************
 ********************************************************************/

/********************************************************************
 ********************* Local Routine Prototypes *********************
 ********************************************************************/

/********************************************************************
 ***************** Scheduled Routine Prototypes *********************
 ********************************************************************/

void Exact_ParamCheck(CCTK_ARGUMENTS);

/********************************************************************
 ********************* Other Routine Prototypes *********************
 ********************************************************************/

/********************************************************************
 *********************     Local Data   *****************************
 ********************************************************************/

/********************************************************************
 *********************     External Routines   **********************
 ********************************************************************/

 /*@@
   @routine    Exact_ParamCheck
   @date       Tue April 30 2002
   @author     Tom Goodale
   @desc 
   Scheduled routine to detect invalid parameter settings.
   @enddesc 
   @calls     
   @calledby   
   @history 
   @hdate      Tue Jun 11 18:25:49 CEST 2002
   @hauthor    Jonathan Thornburg
   @desc       Add a test that we're not trying to set the shift
               with storage *not* present for it
   @enddesc
   @endhistory 
 
 @@*/
void Exact_ParamCheck(CCTK_ARGUMENTS)
{
  DECLARE_CCTK_PARAMETERS;
/*
  if(! CCTK_EQUALS(metric_type, "physical"))
  {
    CCTK_PARAMWARN("Unknown ADMBase::metric_type - known types are \"physical\"");
  }
*/
  if (    (CCTK_EQUALS(shift_evolution_method, "exact")
	|| CCTK_EQUALS(shift_evolution_method, "slice")
	|| CCTK_EQUALS(initial_data, "slice"))
       && CCTK_EQUALS(initial_shift, "none") )
  {
    CCTK_PARAMWARN(
"\n"
"   You set  ADMBase::shift_evolution_method = \"exact\" , which means\n"
"   this thorn (Exact) should set the shift vector from the exact solution.\n"
"   But you also set  ADMBase::initial_shift = \"none\" , which means\n"
"   storage for the shift vector is turned off!  You need to either specify\n"
"   a different  ADMBase::shift_evolution_method , and/or turn on storage\n"
"   for the shift vector by setting  ADMBase::initial_shift  to something\n"
"   other than \"none\".\n"
		  );
  }
}

/********************************************************************
 *********************     Local Routines   *************************
 ********************************************************************/

```

metric.F:
```
c This subroutine calculates the 4-metric and its inverse at an event,
c for a given model, by decoding  decoded_exact_model  and calling the
c appropriate subroutine for that model.
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

#include "param_defs.inc"

      subroutine Exact__metric_for_model(
     $     decoded_exact_model,
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz,
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $     gutt, gutx, guty, gutz,
     $     guxx, guyy, guzz, guxy, guyz, guxz,
     $     psi, Tmunu_flag)

      implicit none
      DECLARE_CCTK_FUNCTIONS

c arguments
      CCTK_INT decoded_exact_model
      CCTK_REAL x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz,
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $     gutt, gutx, guty, gutz,
     $     guxx, guyy, guzz, guxy, guyz, guxz
      CCTK_REAL psi
      LOGICAL   Tmunu_flag

c local variables
      character*100 warn_buffer

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c Minkowski spacetime
c

      if     (decoded_exact_model .eq. EXACT__Minkowski) then
         call Exact__Minkowski(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Minkowski_shift) then
         call Exact__Minkowski_shift(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Minkowski_funny) then
         call Exact__Minkowski_funny(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Minkowski_gauge_wave) then
         call Exact__Minkowski_gauge_wave(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Minkowski_shifted_gauge_wave) then
         call Exact__Minkowski_shifted_gauge_wave(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Minkowski_conf_wave) then
         call Exact__Minkowski_conf_wave(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c black hole spacetimes
c

      elseif (decoded_exact_model .eq. EXACT__Schwarzschild_EF) then
         call Exact__Schwarzschild_EF(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Schwarzschild_PG) then
         call Exact__Schwarzschild_PG(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Schwarzschild_BL) then
         call Exact__Schwarzschild_BL(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Schwarzschild_Novikov) then
         call Exact__Schwarzschild_Novikov(x,y,z,t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Kerr_BoyerLindquist) then
         call Exact__Kerr_BoyerLindquist(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Kerr_KerrSchild) then
         call Exact__Kerr_KerrSchild(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Kerr_KerrSchild_spherical) then
         call Exact__Kerr_KerrSchild_spherical(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Schwarzschild_Lemaitre) then
         call Exact__Schwarzschild_Lemaitre(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__multi_BH) then
         call Exact__multi_BH(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

c
c not fully implemented yet -- see Nina Jansen for details
c
c     elseif (decoded_exact_model .eq. EXACT__Alvi) then
c        call Exact__Alvi(
c    $        x, y, z, t,
c    $        gdtt, gdtx, gdty, gdtz,
c    $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
c    $        gutt, gutx, guty, gutz,
c    $        guxx, guyy, guzz, guxy, guyz, guxz,
c    $        psi, Tmunu_flag)
c

      elseif (decoded_exact_model .eq. EXACT__Thorne_fakebinary) then
         call Exact__Thorne_fakebinary(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c cosmological spacetimes
c

      elseif (decoded_exact_model .eq. EXACT__Lemaitre) then
         call Exact__Lemaitre(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__de_Sitter) then
         call Exact__de_Sitter(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__de_Sitter_Lambda) then
         call Exact__de_Sitter_Lambda(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__anti_de_Sitter_Lambda) then
         call Exact__anti_de_Sitter_Lambda(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Bianchi_I) then
         call Exact__Bianchi_I(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Goedel) then
         call Exact__Goedel(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Bertotti) then
         call Exact__Bertotti(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Kasner_like) then
         call Exact__Kasner_like(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Kasner_axisymmetric) then
         call Exact__Kasner_axisymmetric(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Kasner_generalized) then
         call Exact__Kasner_generalized(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Gowdy_wave) then
         call Exact__Gowdy_wave(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__Milne) then
         call Exact__Milne(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c miscellaneous spacetimes
c

      elseif (decoded_exact_model .eq. EXACT__boost_rotation_symmetric) then
         call Exact__boost_rotation_symmetric(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__bowl) then
         call Exact__bowl(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

      elseif (decoded_exact_model .eq. EXACT__constant_density_star) then
         call Exact__constant_density_star(
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi, Tmunu_flag)

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

      else
         write (warn_buffer, '(a,i8)')
     $         'Unknown decoded_exact_model = ', decoded_exact_model
         call CCTK_WARN(0, warn_buffer)
      endif

      return
      end

```

xyz_blended_boundary.F:
```
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

      subroutine Exact__xyz_blended_boundary(CCTK_ARGUMENTS)

      implicit none

      DECLARE_CCTK_ARGUMENTS
      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

      logical doKij, doGij, doLapse, doShift

      integer i,j,k
      integer nx,ny,nz
      integer ninterps

      CCTK_REAL xblend, yblend, zblend
      CCTK_REAL xmin, xmax, ymin, ymax, zmin, zmax
      CCTK_REAL xfrac, yfrac, zfrac, onemxfrac, onemyfrac, onemzfrac
      CCTK_REAL oonints
      CCTK_REAL sfrac, onemsfrac
      CCTK_REAL gxxe, gyye, gzze, gxye, gyze, gxze
      CCTK_REAL kxxe, kyye, kzze, kxye, kyze, kxze
      CCTK_REAL dxgxxe, dxgyye, dxgzze, dxgxye, dxgyze, dxgxze
      CCTK_REAL dygxxe, dygyye, dygzze, dygxye, dygyze, dygxze
      CCTK_REAL dzgxxe, dzgyye, dzgzze, dzgxye, dzgyze, dzgxze
      CCTK_REAL alpe, dtalpe, axe, aye, aze
      CCTK_REAL betaxe,betaye,betaze, dtbetaxe,dtbetaye,dtbetaze
      CCTK_REAL bxxe,bxye,bxze,byxe,byye,byze,bzxe,bzye,bzze
      CCTK_REAL det, uxx, uxy, uxz, uyy, uyz, uzz
      CCTK_REAL
     $     exact_psi,
     $     exact_psix, exact_psiy, exact_psiz,
     $     exact_psixx, exact_psiyy, exact_psizz,
     $     exact_psixy, exact_psiyz, exact_psixz

      CCTK_REAL dx,dy,dz,time
      integer ierr

C     Grid parameters.

      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

      dx = cctk_delta_space(1)
      dy = cctk_delta_space(2)
      dz = cctk_delta_space(3)

      time = cctk_time

C     Other parameters.

      doKij = (exblend_Ks.eq.1)
      doGij = (exblend_gs.eq.1)

      doLapse  = ((exblend_gauge.eq.1).and.
     $            (CCTK_Equals(lapse_evolution_method,"exact").ne.0))
      doShift  = ((exblend_gauge.eq.1).and.
     $            (CCTK_Equals(shift_evolution_method,"exact").ne.0))

      if (exblend_width.lt.0) then 
         xblend = - exblend_width*dx
         yblend = - exblend_width*dy
         zblend = - exblend_width*dz
      else
         xblend = exblend_width
         yblend = exblend_width
         zblend = exblend_width
      endif

      call CCTK_CoordRange(ierr,cctkGH,xmin,xmax,-1,"x","cart3d")
      call CCTK_CoordRange(ierr,cctkGH,ymin,ymax,-1,"y","cart3d")
      call CCTK_CoordRange(ierr,cctkGH,zmin,zmax,-1,"z","cart3d")

      do k=1,nz
         do j=1,ny
            do i=1,nx

c     We only do anything if in the blending region

               if (x(i,j,k) .ge. xmax - xblend .or.
     $             x(i,j,k) .le. xmin + xblend .or.
     $             y(i,j,k) .ge. ymax - yblend .or.
     $             y(i,j,k) .le. ymin + yblend .or.
     $             z(i,j,k) .ge. zmax - zblend .or.
     $             z(i,j,k) .le. zmin + zblend) then

C     Initialize the psi of exact
C     (also to tell the models about the conformal_state)
                  if (conformal_state .ne. 0) then
                    exact_psi = 1.0D0
                  else
                    exact_psi = 0.0D0
                  end if
                  exact_psix = 0.0D0
                  exact_psiy = 0.0D0
                  exact_psiz = 0.0D0
                  exact_psixx = 0.0D0
                  exact_psiyy = 0.0D0
                  exact_psizz = 0.0D0
                  exact_psixy = 0.0D0
                  exact_psiyz = 0.0D0
                  exact_psixz = 0.0D0

                  call Exact__Bona_Masso_data(
     $                 decoded_exact_model,
     $                 x(i,j,k), y(i,j,k), z(i,j,k), time,
     $                 gxxe, gyye, gzze, gxye, gyze, gxze,
     $                 kxxe, kyye, kzze, kxye, kyze, kxze,
     $                 exact_psi,
     $                 exact_psix, exact_psiy, exact_psiz,
     $                 exact_psixx, exact_psiyy, exact_psizz,
     $                 exact_psixy, exact_psiyz, exact_psixz,
     $                 dxgxxe, dxgyye, dxgzze, dxgxye, dxgyze, dxgxze,
     $                 dygxxe, dygyye, dygzze, dygxye, dygyze, dygxze,
     $                 dzgxxe, dzgyye, dzgzze, dzgxye, dzgyze, dzgxze,
     $                 alpe, dtalpe, axe, aye, aze,
     $                 betaxe, betaye, betaze, dtbetaxe, dtbetaye, dtbetaze,
     $                 bxxe, bxye, bxze, byxe, 
     $                 byye, byze, bzxe, bzye, bzze)

c     This sucks, but we want the exact vs so we can blend them also.

                  det = -(gxze**2*gyye) 
     &                 + 2.d0*gxye*gxze*gyze 
     &                 - gxxe*gyze**2 
     &                 - gxye**2*gzze 
     &                 + gxxe*gyye*gzze
  
                  uxx=(-gyze**2 + gyye*gzze)/det
                  uxy=(gxze*gyze - gxye*gzze)/det
                  uyy=(-gxze**2 + gxxe*gzze)/det
                  uxz=(-gxze*gyye + gxye*gyze)/det
                  uyz=(gxye*gxze - gxxe*gyze)/det
                  uzz=(-gxye**2 + gxxe*gyye)/det

c     OK so 6 blending cases. If frac = 1 we get all exact

                  ninterps = 0

                  xfrac     = 0.0D0
                  onemxfrac = 0.0D0
                  yfrac     = 0.0D0
                  onemyfrac = 0.0D0
                  zfrac     = 0.0D0
                  onemzfrac = 0.0D0

                  if (x(i,j,k) .le. xmin + xblend) then 
                     xfrac = 1.0D0 - (x(i,j,k)-xmin) / xblend
                     onemxfrac = 1.0D0 - xfrac
                     ninterps = ninterps + 1
                  endif

                  if (x(i,j,k) .ge. xmax - xblend) then 
                     xfrac = 1.0D0 - (xmax - x(i,j,k)) / xblend
                     onemxfrac = 1.0D0 - xfrac
                     ninterps = ninterps + 1
                  endif

                  if (y(i,j,k) .le. ymin + yblend) then 
                     yfrac = 1.0D0 - (y(i,j,k)-ymin) / yblend
                     onemyfrac = 1.0D0 - yfrac
                     ninterps = ninterps + 1
                  endif

                  if (y(i,j,k) .ge. ymax - yblend) then 
                     yfrac = 1.0D0 - (ymax - y(i,j,k)) / yblend
                     onemyfrac = 1.0D0 - yfrac
                     ninterps = ninterps + 1
                  endif

                  if (z(i,j,k) .le. zmin + zblend) then 
                     zfrac = 1.0D0 - (z(i,j,k)-zmin) / zblend
                     onemzfrac = 1.0D0 - zfrac
                     ninterps = ninterps + 1
                  endif

                  if (z(i,j,k) .ge. zmax - zblend) then 
                     zfrac = 1.0D0 - (zmax - z(i,j,k)) / zblend
                     onemzfrac = 1.0D0 - zfrac
                     ninterps = ninterps + 1
                  endif

                  oonints = 1.0D0 / ninterps

                  if (ninterps .eq. 0 .or. ninterps .gt. 3) then 
                     print *,"NINTERPS error", ninterps
                     call CCTK_WARN (0, "aborting")
                  endif
                     
                  sfrac = (xfrac + yfrac + zfrac) * oonints
                  onemsfrac = 1.0D0 - sfrac

c     Once again some c-preprocessor tricks based on the whole fortran
c     space thing...

#define INTPOINT(f,v) f(i,j,k) = sfrac * v  + onemsfrac * f(i,j,k)
#define intone(f) INTPOINT(f, f e)
#define int_grp(p) \
        intone(p xx) &&\
        intone(p xy) &&\
        intone(p xz) &&\
        intone(p yy) &&\
        intone(p yz) &&\
        intone(p zz)

                  if (doGij) then 
                     int_grp(g)
                  endif

                  if (doKij) then
                     int_grp(k)
                  endif

                  if (doLapse) then 
                     intone(alp)
                  endif

                  if (doShift.and.(shift_state.ne.0)) then 
                     intone(betax)
                     intone(betay)
                     intone(betaz)
                  endif

               endif            ! r > rinner

            enddo
         enddo
      enddo

      return
      end 

```

Bona_Masso_data.F:
```
c This routine calculates Bona-Masso initial data, making use of the
c subroutine Exact__metric() to calculate the spacetime metric and its
c inverse.  Note that this use of the Bona-Masso variables is independent
c of how (or even if) we are evolving the Einstein equations -- here
c the Bona-Masso variables are "just" used as intermediate variables.

c $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine  Exact__Bona_Masso_data(
     $     decoded_exact_model,
     $     x, y, z, t,
     $     gxx, gyy, gzz, gxy, gyz, gxz,
     $     hxx, hyy, hzz, hxy, hyz, hxz,
     $     psi, psix, psiy, psiz,
     $     psixx, psiyy, psizz, psixy, psiyz, psixz,
     $     dxgxx, dxgyy, dxgzz, dxgxy, dxgyz, dxgxz,
     $     dygxx, dygyy, dygzz, dygxy, dygyz, dygxz,
     $     dzgxx, dzgyy, dzgzz, dzgxy, dzgyz, dzgxz,
     $     alp, dtalp, ax, ay, az,
     $     betax, betay, betaz, dtbetax, dtbetay, dtbetaz,
     $     bxx, bxy, bxz, byx, byy, byz, bzx, bzy, bzz)

      implicit none
      CCTK_INT, parameter :: izero = 0
      integer, parameter :: ik = kind(izero)
      CCTK_INT decoded_exact_model
      logical psi_on
      CCTK_REAL x, y, z, t,
     $       gxx, gyy, gzz, gxy, gyz, gxz,
     $       hxx, hyy, hzz, hxy, hyz, hxz,
     $       psi, psix, psiy, psiz,
     $       psixx, psiyy, psizz, psixy, psiyz, psixz,
     $       dxgxx, dxgyy, dxgzz, dxgxy, dxgyz, dxgxz,
     $       dygxx, dygyy, dygzz, dygxy, dygyz, dygxz,
     $       dzgxx, dzgyy, dzgzz, dzgxy, dzgyz, dzgxz,
     $       alp, dtalp, ax, ay, az,
     $       betax, betay, betaz, dtbetax, dtbetay, dtbetaz,
     $       bxx, bxy, bxz, byx, byy, byz, bzx, bzy, bzz

C     gxx is g_xx etc.
C     hxx is K_xx etc.
C     dxgyy is (/2) dg_yy / dx (sic!)
C     alp is N, betax is N^x etc.
C     bxy is (/2) dN^y / dx (sic and sic!)
C     ax is dN / dx / N (sic!)

      CCTK_REAL
     $       gdtt, gdtx, gdty, gdtz, 
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guxz,
     $       dgdtt, dgdtx, dgdty, dgdtz,
     $       dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $       dgutt, dgutx, dguty, dgutz,
     $       dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $       dpsi

C     Save, if we have to provide the conformal factor

      psi_on = psi .gt. 0.0d0

C     Get the spacetime metric and its inverse at the base point.

      call Exact__metric(
     $     decoded_exact_model,
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gxx, gyy, gzz, gxy, gyz, gxz,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guxz,
     $     psi)

C     Calculate lapse and shift from the upper metric.

      alp = 1.d0 / sqrt(-gutt)

      betax = - gutx / gutt
      betay = - guty / gutt
      betaz = - gutz / gutt

C     In order to calculate the derivatives of the lapse and shift from
C     the contravariant metric, use g^tt = -1/N^2 and g^i0 = N^i / N^2
C     Note that ax is dN/dx / N and that bxy is 1/2 dN^y / dx.

C     Calculate x-derivatives. 

      call Exact__metric_deriv(
     $     decoded_exact_model,
     $     1_ik,
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi)

      dxgxx = 0.5d0 * dgdxx
      dxgyy = 0.5d0 * dgdyy
      dxgzz = 0.5d0 * dgdzz
      dxgxy = 0.5d0 * dgdxy
      dxgyz = 0.5d0 * dgdyz
      dxgxz = 0.5d0 * dgdxz

      ax = - 0.5d0 * dgutt / gutt

      bxx = 0.5d0 * (- dgutx * gutt + gutx * dgutt) / gutt**2
      bxy = 0.5d0 * (- dguty * gutt + guty * dgutt) / gutt**2
      bxz = 0.5d0 * (- dgutz * gutt + gutz * dgutt) / gutt**2

      if (psi_on) then
         psix = dpsi
      end if

C     Calculate y-derivatives.

      call Exact__metric_deriv(
     $     decoded_exact_model,
     $     2_ik,
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi)

      dygxx = 0.5d0 * dgdxx
      dygyy = 0.5d0 * dgdyy
      dygzz = 0.5d0 * dgdzz
      dygxy = 0.5d0 * dgdxy
      dygyz = 0.5d0 * dgdyz
      dygxz = 0.5d0 * dgdxz

      ay = - 0.5d0 * dgutt / gutt

      byx = 0.5d0 * (- dgutx * gutt + gutx * dgutt) / gutt**2
      byy = 0.5d0 * (- dguty * gutt + guty * dgutt) / gutt**2
      byz = 0.5d0 * (- dgutz * gutt + gutz * dgutt) / gutt**2

      if (psi_on) then
         psiy = dpsi
      end if

C     Calculate z-derivatives.

      call Exact__metric_deriv(
     $     decoded_exact_model,
     $     3_ik,
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi)

      dzgxx = 0.5d0 * dgdxx
      dzgyy = 0.5d0 * dgdyy
      dzgzz = 0.5d0 * dgdzz
      dzgxy = 0.5d0 * dgdxy
      dzgyz = 0.5d0 * dgdyz
      dzgxz = 0.5d0 * dgdxz

      az = - 0.5d0 * dgutt / gutt

      bzx = 0.5d0 * (- dgutx * gutt + gutx * dgutt) / gutt**2
      bzy = 0.5d0 * (- dguty * gutt + guty * dgutt) / gutt**2
      bzz = 0.5d0 * (- dgutz * gutt + gutz * dgutt) / gutt**2

      if (psi_on) then
         psiz = dpsi
      end if

C     Calculate t-derivatives, and extrinsic curvature.

      call Exact__metric_deriv(
     $     decoded_exact_model,
     $     0_ik,
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi)

      hxx = - 0.5d0 * dgdxx / alp
     $     + (dxgxx * betax + dygxx * betay + dzgxx * betaz
     $     + 2.d0 * (bxx * gxx + bxy * gxy + bxz * gxz)) / alp

      hyy = - 0.5d0 * dgdyy / alp
     $     + (dxgyy * betax + dygyy * betay + dzgyy * betaz
     $     + 2.d0 * (byx * gxy + byy * gyy + byz * gyz)) / alp

      hzz = - 0.5d0 * dgdzz / alp
     $     + (dxgzz * betax + dygzz * betay + dzgzz * betaz
     $     + 2.d0 * (bzx * gxz + bzy * gyz + bzz * gzz)) / alp

      hxy = - 0.5d0 * dgdxy / alp
     $     + (dxgxy * betax + dygxy * betay + dzgxy * betaz
     $     + bxx * gxy + bxy * gyy + bxz * gyz
     $     + byx * gxx + byy * gxy + byz * gxz) / alp

      hyz = - 0.5d0 * dgdyz / alp
     $     + (dxgyz * betax + dygyz * betay + dzgyz * betaz
     $     + byx * gxz + byy * gyz + byz * gzz
     $     + bzx * gxy + bzy * gyy + bzz * gyz) / alp

      hxz = - 0.5d0 * dgdxz / alp
     $     + (dxgxz * betax + dygxz * betay + dzgxz * betaz
     $     + bxx * gxz + bxy * gyz + bxz * gzz
     $     + bzx * gxx + bzy * gxy + bzz * gxz) / alp

C     Calculate time derivatives of  lapse and shift

C     alp = 1.d0 / sqrt(-gutt)
      dtalp = 0.5d0 / sqrt(-gutt)**3 * dgutt

C     betax = - gutx / gutt
C     betay = - guty / gutt
C     betaz = - gutz / gutt
      dtbetax = (- dgutx * gutt + gutx * dgutt) / gutt**2
      dtbetay = (- dguty * gutt + guty * dgutt) / gutt**2
      dtbetaz = (- dgutz * gutt + gutz * dgutt) / gutt**2

C     Calculate second derivatives of the conformal factor

      if (psi_on) then
        call Exact__metric_deriv2(
     $        decoded_exact_model,
     $        1_ik, 1_ik,
     $        x, y, z, t,
     $        dgdtt, dgdtx, dgdty, dgdtz,
     $        dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $        dgutt, dgutx, dguty, dgutz,
     $        dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $        psixx)
        call Exact__metric_deriv2(
     $        decoded_exact_model,
     $        1_ik, 2_ik,
     $        x, y, z, t,
     $        dgdtt, dgdtx, dgdty, dgdtz,
     $        dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $        dgutt, dgutx, dguty, dgutz,
     $        dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $        psixy)
        call Exact__metric_deriv2(
     $        decoded_exact_model,
     $        1_ik, 3_ik,
     $        x, y, z, t,
     $        dgdtt, dgdtx, dgdty, dgdtz,
     $        dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $        dgutt, dgutx, dguty, dgutz,
     $        dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $        psixz)
        call Exact__metric_deriv2(
     $        decoded_exact_model,
     $        2_ik, 2_ik,
     $        x, y, z, t,
     $        dgdtt, dgdtx, dgdty, dgdtz,
     $        dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $        dgutt, dgutx, dguty, dgutz,
     $        dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $        psiyy)
        call Exact__metric_deriv2(
     $        decoded_exact_model,
     $        2_ik, 3_ik,
     $        x, y, z, t,
     $        dgdtt, dgdtx, dgdty, dgdtz,
     $        dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $        dgutt, dgutx, dguty, dgutz,
     $        dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $        psiyz)
        call Exact__metric_deriv2(
     $        decoded_exact_model,
     $        3_ik, 3_ik,
     $        x, y, z, t,
     $        dgdtt, dgdtx, dgdty, dgdtz,
     $        dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $        dgutt, dgutx, dguty, dgutz,
     $        dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $        psizz)
        
      end if
      return
      end



      subroutine Exact__metric_deriv(
     $     decoded_exact_model,
     $     dir,
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi)
      
      implicit none
      DECLARE_CCTK_PARAMETERS
      
      CCTK_INT
     $     decoded_exact_model,
     $     dir
      CCTK_REAL
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi,
     $     gdtt_p, gdtx_p, gdty_p, gdtz_p, 
     $     gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $     gutt_p, gutx_p, guty_p, gutz_p, 
     $     guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $     psi_p,
     $     gdtt_m, gdtx_m, gdty_m, gdtz_m, 
     $     gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $     gutt_m, gutx_m, guty_m, gutz_m, 
     $     guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $     psi_m,
     $     gdtt_p_p, gdtx_p_p, gdty_p_p, gdtz_p_p, 
     $     gdxx_p_p, gdyy_p_p, gdzz_p_p, gdxy_p_p, gdyz_p_p, gdxz_p_p,
     $     gutt_p_p, gutx_p_p, guty_p_p, gutz_p_p, 
     $     guxx_p_p, guyy_p_p, guzz_p_p, guxy_p_p, guyz_p_p, guxz_p_p,
     $     psi_p_p,
     $     gdtt_m_m, gdtx_m_m, gdty_m_m, gdtz_m_m, 
     $     gdxx_m_m, gdyy_m_m, gdzz_m_m, gdxy_m_m, gdyz_m_m, gdxz_m_m,
     $     gutt_m_m, gutx_m_m, guty_m_m, gutz_m_m, 
     $     guxx_m_m, guyy_m_m, guzz_m_m, guxy_m_m, guyz_m_m, guxz_m_m,
     $     psi_m_m,
     $     eps,
     $     dx, dy, dz, dt
      
      eps = exact_eps
      
      dx = 0
      dy = 0
      dz = 0
      dt = 0
      if (dir.eq.0) dt = eps
      if (dir.eq.1) dx = eps
      if (dir.eq.2) dy = eps
      if (dir.eq.3) dz = eps
      
      if (exact_order .eq. 2) then
         
         call Exact__metric(
     $        decoded_exact_model,
     $        x-dx, y-dy, z-dz, t-dt,
     $        gdtt_m, gdtx_m, gdty_m, gdtz_m,
     $        gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $        gutt_m, gutx_m, guty_m, gutz_m,
     $        guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $        psi_m)
         call Exact__metric(
     $        decoded_exact_model,
     $        x+dx, y+dy, z+dz, t+dt,
     $        gdtt_p, gdtx_p, gdty_p, gdtz_p,
     $        gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $        gutt_p, gutx_p, guty_p, gutz_p,
     $        guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $        psi_p)
         
         dgdtt = (gdtt_p - gdtt_m) / (2*eps)
         dgdtx = (gdtx_p - gdtx_m) / (2*eps)
         dgdty = (gdty_p - gdty_m) / (2*eps)
         dgdtz = (gdtz_p - gdtz_m) / (2*eps)
         dgdxx = (gdxx_p - gdxx_m) / (2*eps)
         dgdyy = (gdyy_p - gdyy_m) / (2*eps)
         dgdzz = (gdzz_p - gdzz_m) / (2*eps)
         dgdxy = (gdxy_p - gdxy_m) / (2*eps)
         dgdyz = (gdyz_p - gdyz_m) / (2*eps)
         dgdxz = (gdxz_p - gdxz_m) / (2*eps)
         dgutt = (gutt_p - gutt_m) / (2*eps)
         dgutx = (gutx_p - gutx_m) / (2*eps)
         dguty = (guty_p - guty_m) / (2*eps)
         dgutz = (gutz_p - gutz_m) / (2*eps)
         dguxx = (guxx_p - guxx_m) / (2*eps)
         dguyy = (guyy_p - guyy_m) / (2*eps)
         dguzz = (guzz_p - guzz_m) / (2*eps)
         dguxy = (guxy_p - guxy_m) / (2*eps)
         dguyz = (guyz_p - guyz_m) / (2*eps)
         dguxz = (guxz_p - guxz_m) / (2*eps)
         dpsi  = (psi_p  - psi_m ) / (2*eps)
         
      else if (exact_order .eq. 4) then
         
         call Exact__metric(
     $        decoded_exact_model,
     $        x-2*dx, y-2*dy, z-2*dz, t-2*dt,
     $        gdtt_m_m, gdtx_m_m, gdty_m_m, gdtz_m_m,
     $        gdxx_m_m, gdyy_m_m, gdzz_m_m, gdxy_m_m, gdyz_m_m, gdxz_m_m,
     $        gutt_m_m, gutx_m_m, guty_m_m, gutz_m_m,
     $        guxx_m_m, guyy_m_m, guzz_m_m, guxy_m_m, guyz_m_m, guxz_m_m,
     $        psi_m_m)
         call Exact__metric(
     $        decoded_exact_model,
     $        x-dx, y-dy, z-dz, t-dt,
     $        gdtt_m, gdtx_m, gdty_m, gdtz_m,
     $        gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $        gutt_m, gutx_m, guty_m, gutz_m,
     $        guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $        psi_m)
         call Exact__metric(
     $        decoded_exact_model,
     $        x+dx, y+dy, z+dz, t+dt,
     $        gdtt_p, gdtx_p, gdty_p, gdtz_p,
     $        gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $        gutt_p, gutx_p, guty_p, gutz_p,
     $        guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $        psi_p)
         call Exact__metric(
     $        decoded_exact_model,
     $        x+2*dx, y+2*dy, z+2*dz, t+2*dt,
     $        gdtt_p_p, gdtx_p_p, gdty_p_p, gdtz_p_p,
     $        gdxx_p_p, gdyy_p_p, gdzz_p_p, gdxy_p_p, gdyz_p_p, gdxz_p_p,
     $        gutt_p_p, gutx_p_p, guty_p_p, gutz_p_p,
     $        guxx_p_p, guyy_p_p, guzz_p_p, guxy_p_p, guyz_p_p, guxz_p_p,
     $        psi_p_p)
         
         dgdtt = (- gdtt_p_p + 8*gdtt_p - 8*gdtt_m + gdtt_m_m) / (12*eps)
         dgdtx = (- gdtx_p_p + 8*gdtx_p - 8*gdtx_m + gdtx_m_m) / (12*eps)
         dgdty = (- gdty_p_p + 8*gdty_p - 8*gdty_m + gdty_m_m) / (12*eps)
         dgdtz = (- gdtz_p_p + 8*gdtz_p - 8*gdtz_m + gdtz_m_m) / (12*eps)
         dgdxx = (- gdxx_p_p + 8*gdxx_p - 8*gdxx_m + gdxx_m_m) / (12*eps)
         dgdyy = (- gdyy_p_p + 8*gdyy_p - 8*gdyy_m + gdyy_m_m) / (12*eps)
         dgdzz = (- gdzz_p_p + 8*gdzz_p - 8*gdzz_m + gdzz_m_m) / (12*eps)
         dgdxy = (- gdxy_p_p + 8*gdxy_p - 8*gdxy_m + gdxy_m_m) / (12*eps)
         dgdyz = (- gdyz_p_p + 8*gdyz_p - 8*gdyz_m + gdyz_m_m) / (12*eps)
         dgdxz = (- gdxz_p_p + 8*gdxz_p - 8*gdxz_m + gdxz_m_m) / (12*eps)
         dgutt = (- gutt_p_p + 8*gutt_p - 8*gutt_m + gutt_m_m) / (12*eps)
         dgutx = (- gutx_p_p + 8*gutx_p - 8*gutx_m + gutx_m_m) / (12*eps)
         dguty = (- guty_p_p + 8*guty_p - 8*guty_m + guty_m_m) / (12*eps)
         dgutz = (- gutz_p_p + 8*gutz_p - 8*gutz_m + gutz_m_m) / (12*eps)
         dguxx = (- guxx_p_p + 8*guxx_p - 8*guxx_m + guxx_m_m) / (12*eps)
         dguyy = (- guyy_p_p + 8*guyy_p - 8*guyy_m + guyy_m_m) / (12*eps)
         dguzz = (- guzz_p_p + 8*guzz_p - 8*guzz_m + guzz_m_m) / (12*eps)
         dguxy = (- guxy_p_p + 8*guxy_p - 8*guxy_m + guxy_m_m) / (12*eps)
         dguyz = (- guyz_p_p + 8*guyz_p - 8*guyz_m + guyz_m_m) / (12*eps)
         dguxz = (- guxz_p_p + 8*guxz_p - 8*guxz_m + guxz_m_m) / (12*eps)
         dpsi  = (- psi_p_p  + 8*psi_p  - 8*psi_m  + psi_m_m ) / (12*eps)
         
      else
         call CCTK_WARN (CCTK_WARN_ABORT, "internal error")
      end if
      
      end



      subroutine Exact__metric_deriv2(
     $     decoded_exact_model,
     $     dir1, dir2,
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi)
      
      implicit none
      DECLARE_CCTK_PARAMETERS
      
      CCTK_INT
     $     decoded_exact_model,
     $     dir1, dir2
      CCTK_REAL
     $     x, y, z, t,
     $     dgdtt, dgdtx, dgdty, dgdtz,
     $     dgdxx, dgdyy, dgdzz, dgdxy, dgdyz, dgdxz,
     $     dgutt, dgutx, dguty, dgutz,
     $     dguxx, dguyy, dguzz, dguxy, dguyz, dguxz,
     $     dpsi,
     $     gdtt_0, gdtx_0, gdty_0, gdtz_0, 
     $     gdxx_0, gdyy_0, gdzz_0, gdxy_0, gdyz_0, gdxz_0,
     $     gutt_0, gutx_0, guty_0, gutz_0, 
     $     guxx_0, guyy_0, guzz_0, guxy_0, guyz_0, guxz_0,
     $     psi_0,
     $     gdtt_p, gdtx_p, gdty_p, gdtz_p, 
     $     gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $     gutt_p, gutx_p, guty_p, gutz_p, 
     $     guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $     psi_p,
     $     gdtt_m, gdtx_m, gdty_m, gdtz_m, 
     $     gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $     gutt_m, gutx_m, guty_m, gutz_m, 
     $     guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $     psi_m,
     $     gdtt_p_p, gdtx_p_p, gdty_p_p, gdtz_p_p, 
     $     gdxx_p_p, gdyy_p_p, gdzz_p_p, gdxy_p_p, gdyz_p_p, gdxz_p_p,
     $     gutt_p_p, gutx_p_p, guty_p_p, gutz_p_p, 
     $     guxx_p_p, guyy_p_p, guzz_p_p, guxy_p_p, guyz_p_p, guxz_p_p,
     $     psi_p_p,
     $     gdtt_m_m, gdtx_m_m, gdty_m_m, gdtz_m_m, 
     $     gdxx_m_m, gdyy_m_m, gdzz_m_m, gdxy_m_m, gdyz_m_m, gdxz_m_m,
     $     gutt_m_m, gutx_m_m, guty_m_m, gutz_m_m, 
     $     guxx_m_m, guyy_m_m, guzz_m_m, guxy_m_m, guyz_m_m, guxz_m_m,
     $     psi_m_m,
     $     eps,
     $     dx, dy, dz, dt
      
      eps = exact_eps
      
      dx = 0
      dy = 0
      dz = 0
      dt = 0
      if (dir1.eq.0) dt = eps
      if (dir1.eq.1) dx = eps
      if (dir1.eq.2) dy = eps
      if (dir1.eq.3) dz = eps
      if (dir1.lt.0 .or. dir1.gt.3) then
         call CCTK_WARN (CCTK_WARN_ABORT, "internal error")
      end if
      if (dir2.lt.0 .or. dir2.gt.3) then
         call CCTK_WARN (CCTK_WARN_ABORT, "internal error")
      end if
      
      if (exact_order .eq. 2) then
         
         if (dir1 .eq. dir2) then
            
            call Exact__metric(
     $           decoded_exact_model,
     $           x-dx, y-dy, z-dz, t-dt,
     $           gdtt_m, gdtx_m, gdty_m, gdtz_m,
     $           gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $           gutt_m, gutx_m, guty_m, gutz_m,
     $           guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $           psi_m)
            call Exact__metric(
     $           decoded_exact_model,
     $           x, y, z, t,
     $           gdtt_0, gdtx_0, gdty_0, gdtz_0,
     $           gdxx_0, gdyy_0, gdzz_0, gdxy_0, gdyz_0, gdxz_0,
     $           gutt_0, gutx_0, guty_0, gutz_0,
     $           guxx_0, guyy_0, guzz_0, guxy_0, guyz_0, guxz_0,
     $           psi_0)
            call Exact__metric(
     $           decoded_exact_model,
     $           x+dx, y+dy, z+dz, t+dt,
     $           gdtt_p, gdtx_p, gdty_p, gdtz_p,
     $           gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $           gutt_p, gutx_p, guty_p, gutz_p,
     $           guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $           psi_p)
            
            dgdtt = (gdtt_m - 2*gdtt_0 + gdtt_p) / eps**2
            dgdtx = (gdtx_m - 2*gdtx_0 + gdtx_p) / eps**2
            dgdty = (gdty_m - 2*gdty_0 + gdty_p) / eps**2
            dgdtz = (gdtz_m - 2*gdtz_0 + gdtz_p) / eps**2
            dgdxx = (gdxx_m - 2*gdxx_0 + gdxx_p) / eps**2
            dgdyy = (gdyy_m - 2*gdyy_0 + gdyy_p) / eps**2
            dgdzz = (gdzz_m - 2*gdzz_0 + gdzz_p) / eps**2
            dgdxy = (gdxy_m - 2*gdxy_0 + gdxy_p) / eps**2
            dgdyz = (gdyz_m - 2*gdyz_0 + gdyz_p) / eps**2
            dgdxz = (gdxz_m - 2*gdxz_0 + gdxz_p) / eps**2
            dgutt = (gutt_m - 2*gutt_0 + gutt_p) / eps**2
            dgutx = (gutx_m - 2*gutx_0 + gutx_p) / eps**2
            dguty = (guty_m - 2*guty_0 + guty_p) / eps**2
            dgutz = (gutz_m - 2*gutz_0 + gutz_p) / eps**2
            dguxx = (guxx_m - 2*guxx_0 + guxx_p) / eps**2
            dguyy = (guyy_m - 2*guyy_0 + guyy_p) / eps**2
            dguzz = (guzz_m - 2*guzz_0 + guzz_p) / eps**2
            dguxy = (guxy_m - 2*guxy_0 + guxy_p) / eps**2
            dguyz = (guyz_m - 2*guyz_0 + guyz_p) / eps**2
            dguxz = (guxz_m - 2*guxz_0 + guxz_p) / eps**2
            dpsi  = (psi_m  - 2*psi_0  + psi_p ) / eps**2
            
         else
            
            call Exact__metric_deriv(
     $           decoded_exact_model,
     $           dir2,
     $           x-dx, y-dy, z-dz, t-dt,
     $           gdtt_m, gdtx_m, gdty_m, gdtz_m,
     $           gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $           gutt_m, gutx_m, guty_m, gutz_m,
     $           guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $           psi_m)
            call Exact__metric_deriv(
     $           decoded_exact_model,
     $           dir2,
     $           x+dx, y+dy, z+dz, t+dt,
     $           gdtt_p, gdtx_p, gdty_p, gdtz_p,
     $           gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $           gutt_p, gutx_p, guty_p, gutz_p,
     $           guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $           psi_p)
         
            dgdtt = (gdtt_p - gdtt_m) / (2*eps)
            dgdtx = (gdtx_p - gdtx_m) / (2*eps)
            dgdty = (gdty_p - gdty_m) / (2*eps)
            dgdtz = (gdtz_p - gdtz_m) / (2*eps)
            dgdxx = (gdxx_p - gdxx_m) / (2*eps)
            dgdyy = (gdyy_p - gdyy_m) / (2*eps)
            dgdzz = (gdzz_p - gdzz_m) / (2*eps)
            dgdxy = (gdxy_p - gdxy_m) / (2*eps)
            dgdyz = (gdyz_p - gdyz_m) / (2*eps)
            dgdxz = (gdxz_p - gdxz_m) / (2*eps)
            dgutt = (gutt_p - gutt_m) / (2*eps)
            dgutx = (gutx_p - gutx_m) / (2*eps)
            dguty = (guty_p - guty_m) / (2*eps)
            dgutz = (gutz_p - gutz_m) / (2*eps)
            dguxx = (guxx_p - guxx_m) / (2*eps)
            dguyy = (guyy_p - guyy_m) / (2*eps)
            dguzz = (guzz_p - guzz_m) / (2*eps)
            dguxy = (guxy_p - guxy_m) / (2*eps)
            dguyz = (guyz_p - guyz_m) / (2*eps)
            dguxz = (guxz_p - guxz_m) / (2*eps)
            dpsi  = (psi_p  - psi_m ) / (2*eps)
            
         end if
         
      else if (exact_order .eq. 4) then
         
         if (dir1 .eq. dir2) then
            
            call Exact__metric(
     $           decoded_exact_model,
     $           x-2*dx, y-2*dy, z-2*dz, t-2*dt,
     $           gdtt_m_m, gdtx_m_m, gdty_m_m, gdtz_m_m,
     $           gdxx_m_m, gdyy_m_m, gdzz_m_m, gdxy_m_m, gdyz_m_m, gdxz_m_m,
     $           gutt_m_m, gutx_m_m, guty_m_m, gutz_m_m,
     $           guxx_m_m, guyy_m_m, guzz_m_m, guxy_m_m, guyz_m_m, guxz_m_m,
     $           psi_m_m)
            call Exact__metric(
     $           decoded_exact_model,
     $           x-dx, y-dy, z-dz, t-dt,
     $           gdtt_m, gdtx_m, gdty_m, gdtz_m,
     $           gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $           gutt_m, gutx_m, guty_m, gutz_m,
     $           guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $           psi_m)
            call Exact__metric(
     $           decoded_exact_model,
     $           x, y, z, t,
     $           gdtt_0, gdtx_0, gdty_0, gdtz_0,
     $           gdxx_0, gdyy_0, gdzz_0, gdxy_0, gdyz_0, gdxz_0,
     $           gutt_0, gutx_0, guty_0, gutz_0,
     $           guxx_0, guyy_0, guzz_0, guxy_0, guyz_0, guxz_0,
     $           psi_0)
            call Exact__metric(
     $           decoded_exact_model,
     $           x+dx, y+dy, z+dz, t+dt,
     $           gdtt_p, gdtx_p, gdty_p, gdtz_p,
     $           gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $           gutt_p, gutx_p, guty_p, gutz_p,
     $           guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $           psi_p)
            call Exact__metric(
     $           decoded_exact_model,
     $           x+2*dx, y+2*dy, z+2*dz, t+2*dt,
     $           gdtt_p_p, gdtx_p_p, gdty_p_p, gdtz_p_p,
     $           gdxx_p_p, gdyy_p_p, gdzz_p_p, gdxy_p_p, gdyz_p_p, gdxz_p_p,
     $           gutt_p_p, gutx_p_p, guty_p_p, gutz_p_p,
     $           guxx_p_p, guyy_p_p, guzz_p_p, guxy_p_p, guyz_p_p, guxz_p_p,
     $           psi_p_p)
            
            dgdtt = (- gdtt_m_m - 16*gdtt_m + 30*gdtt_0 - 16*gdtt_p - gdtt_p_p) / (12*eps**2)
            dgdtx = (- gdtx_m_m - 16*gdtx_m + 30*gdtx_0 - 16*gdtx_p - gdtx_p_p) / (12*eps**2)
            dgdty = (- gdty_m_m - 16*gdty_m + 30*gdty_0 - 16*gdty_p - gdty_p_p) / (12*eps**2)
            dgdtz = (- gdtz_m_m - 16*gdtz_m + 30*gdtz_0 - 16*gdtz_p - gdtz_p_p) / (12*eps**2)
            dgdxx = (- gdxx_m_m - 16*gdxx_m + 30*gdxx_0 - 16*gdxx_p - gdxx_p_p) / (12*eps**2)
            dgdyy = (- gdyy_m_m - 16*gdyy_m + 30*gdyy_0 - 16*gdyy_p - gdyy_p_p) / (12*eps**2)
            dgdzz = (- gdzz_m_m - 16*gdzz_m + 30*gdzz_0 - 16*gdzz_p - gdzz_p_p) / (12*eps**2)
            dgdxy = (- gdxy_m_m - 16*gdxy_m + 30*gdxy_0 - 16*gdxy_p - gdxy_p_p) / (12*eps**2)
            dgdyz = (- gdyz_m_m - 16*gdyz_m + 30*gdyz_0 - 16*gdyz_p - gdyz_p_p) / (12*eps**2)
            dgdxz = (- gdxz_m_m - 16*gdxz_m + 30*gdxz_0 - 16*gdxz_p - gdxz_p_p) / (12*eps**2)
            dgutt = (- gutt_m_m - 16*gutt_m + 30*gutt_0 - 16*gutt_p - gutt_p_p) / (12*eps**2)
            dgutx = (- gutx_m_m - 16*gutx_m + 30*gutx_0 - 16*gutx_p - gutx_p_p) / (12*eps**2)
            dguty = (- guty_m_m - 16*guty_m + 30*guty_0 - 16*guty_p - guty_p_p) / (12*eps**2)
            dgutz = (- gutz_m_m - 16*gutz_m + 30*gutz_0 - 16*gutz_p - gutz_p_p) / (12*eps**2)
            dguxx = (- guxx_m_m - 16*guxx_m + 30*guxx_0 - 16*guxx_p - guxx_p_p) / (12*eps**2)
            dguyy = (- guyy_m_m - 16*guyy_m + 30*guyy_0 - 16*guyy_p - guyy_p_p) / (12*eps**2)
            dguzz = (- guzz_m_m - 16*guzz_m + 30*guzz_0 - 16*guzz_p - guzz_p_p) / (12*eps**2)
            dguxy = (- guxy_m_m - 16*guxy_m + 30*guxy_0 - 16*guxy_p - guxy_p_p) / (12*eps**2)
            dguyz = (- guyz_m_m - 16*guyz_m + 30*guyz_0 - 16*guyz_p - guyz_p_p) / (12*eps**2)
            dguxz = (- guxz_m_m - 16*guxz_m + 30*guxz_0 - 16*guxz_p - guxz_p_p) / (12*eps**2)
            dpsi  = (- psi_m_m  - 16*psi_m  + 30*psi_0  - 16*psi_p  - psi_p_p ) / (12*eps**2)
            
         else
            
            call Exact__metric_deriv(
     $           decoded_exact_model,
     $           dir2,
     $           x-2*dx, y-2*dy, z-2*dz, t-2*dt,
     $           gdtt_m_m, gdtx_m_m, gdty_m_m, gdtz_m_m,
     $           gdxx_m_m, gdyy_m_m, gdzz_m_m, gdxy_m_m, gdyz_m_m, gdxz_m_m,
     $           gutt_m_m, gutx_m_m, guty_m_m, gutz_m_m,
     $           guxx_m_m, guyy_m_m, guzz_m_m, guxy_m_m, guyz_m_m, guxz_m_m,
     $           psi_m_m)
            call Exact__metric_deriv(
     $           decoded_exact_model,
     $           dir2,
     $           x-dx, y-dy, z-dz, t-dt,
     $           gdtt_m, gdtx_m, gdty_m, gdtz_m,
     $           gdxx_m, gdyy_m, gdzz_m, gdxy_m, gdyz_m, gdxz_m,
     $           gutt_m, gutx_m, guty_m, gutz_m,
     $           guxx_m, guyy_m, guzz_m, guxy_m, guyz_m, guxz_m,
     $           psi_m)
            call Exact__metric_deriv(
     $           decoded_exact_model,
     $           dir2,
     $           x+dx, y+dy, z+dz, t+dt,
     $           gdtt_p, gdtx_p, gdty_p, gdtz_p,
     $           gdxx_p, gdyy_p, gdzz_p, gdxy_p, gdyz_p, gdxz_p,
     $           gutt_p, gutx_p, guty_p, gutz_p,
     $           guxx_p, guyy_p, guzz_p, guxy_p, guyz_p, guxz_p,
     $           psi_p)
            call Exact__metric_deriv(
     $           decoded_exact_model,
     $           dir2,
     $           x+2*dx, y+2*dy, z+2*dz, t+2*dt,
     $           gdtt_p_p, gdtx_p_p, gdty_p_p, gdtz_p_p,
     $           gdxx_p_p, gdyy_p_p, gdzz_p_p, gdxy_p_p, gdyz_p_p, gdxz_p_p,
     $           gutt_p_p, gutx_p_p, guty_p_p, gutz_p_p,
     $           guxx_p_p, guyy_p_p, guzz_p_p, guxy_p_p, guyz_p_p, guxz_p_p,
     $           psi_p_p)
            
            dgdtt = (- gdtt_p_p + 8*gdtt_p - 8*gdtt_m + gdtt_m_m) / (12*eps)
            dgdtx = (- gdtx_p_p + 8*gdtx_p - 8*gdtx_m + gdtx_m_m) / (12*eps)
            dgdty = (- gdty_p_p + 8*gdty_p - 8*gdty_m + gdty_m_m) / (12*eps)
            dgdtz = (- gdtz_p_p + 8*gdtz_p - 8*gdtz_m + gdtz_m_m) / (12*eps)
            dgdxx = (- gdxx_p_p + 8*gdxx_p - 8*gdxx_m + gdxx_m_m) / (12*eps)
            dgdyy = (- gdyy_p_p + 8*gdyy_p - 8*gdyy_m + gdyy_m_m) / (12*eps)
            dgdzz = (- gdzz_p_p + 8*gdzz_p - 8*gdzz_m + gdzz_m_m) / (12*eps)
            dgdxy = (- gdxy_p_p + 8*gdxy_p - 8*gdxy_m + gdxy_m_m) / (12*eps)
            dgdyz = (- gdyz_p_p + 8*gdyz_p - 8*gdyz_m + gdyz_m_m) / (12*eps)
            dgdxz = (- gdxz_p_p + 8*gdxz_p - 8*gdxz_m + gdxz_m_m) / (12*eps)
            dgutt = (- gutt_p_p + 8*gutt_p - 8*gutt_m + gutt_m_m) / (12*eps)
            dgutx = (- gutx_p_p + 8*gutx_p - 8*gutx_m + gutx_m_m) / (12*eps)
            dguty = (- guty_p_p + 8*guty_p - 8*guty_m + guty_m_m) / (12*eps)
            dgutz = (- gutz_p_p + 8*gutz_p - 8*gutz_m + gutz_m_m) / (12*eps)
            dguxx = (- guxx_p_p + 8*guxx_p - 8*guxx_m + guxx_m_m) / (12*eps)
            dguyy = (- guyy_p_p + 8*guyy_p - 8*guyy_m + guyy_m_m) / (12*eps)
            dguzz = (- guzz_p_p + 8*guzz_p - 8*guzz_m + guzz_m_m) / (12*eps)
            dguxy = (- guxy_p_p + 8*guxy_p - 8*guxy_m + guxy_m_m) / (12*eps)
            dguyz = (- guyz_p_p + 8*guyz_p - 8*guyz_m + guyz_m_m) / (12*eps)
            dguxz = (- guxz_p_p + 8*guxz_p - 8*guxz_m + guxz_m_m) / (12*eps)
            dpsi  = (- psi_p_p  + 8*psi_p  - 8*psi_m  + psi_m_m ) / (12*eps)
            
         end if
         
      else
         call CCTK_WARN (CCTK_WARN_ABORT, "internal error")
      end if
      
      end

```

decode_pars.F:
```
c/*@@
c @file		decode_pars.F
c @date		Fri Jun  7 19:47:46 CEST 2002
c @author	Jonathan Thornburg <jthorn@aei.mpg.de>
c @desc
c	Decode/copy parameters for this thorn into grid scalars
c	so we can share this with friends
c	so the Calc_Tmunu code in ../include/Scalar_CalcTmunu.inc
c	can use them in computing the stress-energy tensor
c
c	Actually we only have to copy those parameters which are
c	used by the Calc_Tmunu code.  For simplicity we decode
c	exact_model into the integer decoded_exact_model, then
c	copy only the per-model parameters for those models which
c	have stress-energy tensor code in ../include/Scalar_CalcTmunu.inc .
c
c @enddesc
c @version	$Header$
c@@*/

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

#include "param_defs.inc"

c/*@@
c @routine	Exact__decode_pars
c @date		Fri Jun  7 19:47:46 CEST 2002
c @author	Jonathan Thornburg <jthorn@aei.mpg.de>
c @desc
c	Decode/copy parameters for this thorn into grid scalars, so
c	we can share this with friends for the use of the Calc_Tmunu
c	code in ../include/Scalar_CalcTmunu.inc in computing the
c	stress-energy tensor.
c @enddesc
c @version	$Header$
c@@*/
	subroutine Exact__decode_pars(CCTK_ARGUMENTS)
	implicit none
	DECLARE_CCTK_ARGUMENTS
	DECLARE_CCTK_PARAMETERS
	DECLARE_CCTK_FUNCTIONS

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c decode  exact_model  into the integer  decoded_exact_model
c

c Minkowski spacetime
	if      (CCTK_Equals(exact_model, "Minkowski") .ne. 0) then
	     decoded_exact_model = EXACT__Minkowski
	elseif (CCTK_Equals(exact_model, "Minkowski/shift") .ne. 0) then
	     decoded_exact_model = EXACT__Minkowski_shift
	elseif (CCTK_Equals(exact_model, "Minkowski/funny") .ne. 0) then
	     decoded_exact_model = EXACT__Minkowski_funny
	elseif (CCTK_Equals(exact_model, "Minkowski/gauge wave") .ne. 0) then
	     decoded_exact_model = EXACT__Minkowski_gauge_wave
	elseif (CCTK_Equals(exact_model, "Minkowski/shifted gauge wave") .ne. 0) then
	     decoded_exact_model = EXACT__Minkowski_shifted_gauge_wave
	elseif (CCTK_Equals(exact_model, "Minkowski/conf wave") .ne. 0) then
	     decoded_exact_model = EXACT__Minkowski_conf_wave

c black hole spacetimes
	elseif (CCTK_Equals(exact_model, "Schwarzschild/EF") .ne. 0) then
	     decoded_exact_model = EXACT__Schwarzschild_EF
	elseif (CCTK_Equals(exact_model, "Schwarzschild/PG") .ne. 0) then
	     decoded_exact_model = EXACT__Schwarzschild_PG
	elseif (CCTK_Equals(exact_model, "Schwarzschild/BL") .ne. 0) then
	     decoded_exact_model = EXACT__Schwarzschild_BL
	elseif (CCTK_Equals(exact_model, "Schwarzschild/Novikov") .ne. 0) then
	     decoded_exact_model = EXACT__Schwarzschild_Novikov
	elseif (CCTK_Equals(exact_model, "Kerr/Boyer-Lindquist") .ne. 0) then
	     decoded_exact_model = EXACT__Kerr_BoyerLindquist
	elseif (CCTK_Equals(exact_model, "Kerr/Kerr-Schild") .ne. 0) then
	     decoded_exact_model = EXACT__Kerr_KerrSchild
	elseif (CCTK_Equals(exact_model, "Kerr/Kerr-Schild/spherical") .ne. 0) then
	     decoded_exact_model = EXACT__Kerr_KerrSchild_spherical
	elseif (CCTK_Equals(exact_model, "Schwarzschild-Lemaitre") .ne. 0) then
	     decoded_exact_model = EXACT__Schwarzschild_Lemaitre
	elseif (CCTK_Equals(exact_model, "multi-BH") .ne. 0) then
	     decoded_exact_model = EXACT__multi_BH
	elseif (CCTK_Equals(exact_model, "Alvi") .ne. 0) then
	     decoded_exact_model = EXACT__Alvi
	elseif (CCTK_Equals(exact_model, "Thorne-fakebinary") .ne. 0) then
	     decoded_exact_model = EXACT__Thorne_fakebinary

c cosmological spacetimes
	elseif (CCTK_Equals(exact_model, "Lemaitre") .ne. 0) then
	     decoded_exact_model = EXACT__Lemaitre
C this metric doesnt work and has been moved to ../archive/
CC	elseif (CCTK_Equals(exact_model, "Robertson-Walker") .ne. 0) then
CC	     decoded_exact_model = EXACT__Robertson_Walker
	elseif (CCTK_Equals(exact_model, "de Sitter") .ne. 0) then
	     decoded_exact_model = EXACT__de_Sitter
	elseif (CCTK_Equals(exact_model, "de Sitter+Lambda") .ne. 0) then
	     decoded_exact_model = EXACT__de_Sitter_Lambda
	elseif (CCTK_Equals(exact_model, "anti-de Sitter+Lambda") .ne. 0) then
	     decoded_exact_model = EXACT__anti_de_Sitter_Lambda
	elseif (CCTK_Equals(exact_model, "Bianchi I") .ne. 0) then
	     decoded_exact_model = EXACT__Bianchi_I
	elseif (CCTK_Equals(exact_model, "Goedel") .ne. 0) then
	     decoded_exact_model = EXACT__Goedel
	elseif (CCTK_Equals(exact_model, "Bertotti") .ne. 0) then
	     decoded_exact_model = EXACT__Bertotti
	elseif (CCTK_Equals(exact_model, "Kasner-like") .ne. 0) then
	     decoded_exact_model = EXACT__Kasner_like
	elseif (CCTK_Equals(exact_model, "Kasner-axisymmetric") .ne. 0) then
	     decoded_exact_model = EXACT__Kasner_axisymmetric
	elseif (CCTK_Equals(exact_model, "Kasner-generalized") .ne. 0) then
	     decoded_exact_model = EXACT__Kasner_generalized
	elseif (CCTK_Equals(exact_model, "Gowdy-wave") .ne. 0) then
	     decoded_exact_model = EXACT__Gowdy_wave
	elseif (CCTK_Equals(exact_model, "Milne") .ne. 0) then
	     decoded_exact_model = EXACT__Milne

c miscellaneous spacetimes
	elseif (CCTK_Equals(exact_model, "boost-rotation symmetric") .ne. 0) then
	     decoded_exact_model = EXACT__boost_rotation_symmetric
	elseif (CCTK_Equals(exact_model, "bowl") .ne. 0) then
	     decoded_exact_model = EXACT__bowl
	elseif (CCTK_Equals(exact_model, "constant density star") .ne. 0) then
	     decoded_exact_model = EXACT__constant_density_star
	else
	     call CCTK_WARN(0, "Unknown exact_model")
	endif

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for Schwarzschild-Lemaitre metric
c (Schwarzschiled black hole with cosmological constant)
c
	Schwarzschild_Lemaitre___Lambda = Schwarzschild_Lemaitre__Lambda
	Schwarzschild_Lemaitre___mass   = Schwarzschild_Lemaitre__mass

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for Lemaitre-type spacetime
c
	Lemaitre___kappa    = Lemaitre__kappa
	Lemaitre___Lambda   = Lemaitre__Lambda
	Lemaitre___epsilon0 = Lemaitre__epsilon0
	Lemaitre___R0       = Lemaitre__R0

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
CCC
CCC this metric doesnt work and has been moved to ../archive/
CCc
CCc parameters for Robertson-Walker spacetime
CCc
CC	Robertson_Walker___R0       = Robertson_Walker__R0
CC	Robertson_Walker___rho      = Robertson_Walker__rho
CC	Robertson_Walker___k        = Robertson_Walker__k
CC	Robertson_Walker___pressure = Robertson_Walker__pressure
CC
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for de Sitter spacetime
c
	de_Sitter___scale = de_Sitter__scale

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for de Sitter spacetime with cosmological constant
c
	de_Sitter_Lambda___scale = de_Sitter_Lambda__scale

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for anti-de Sitter spacetime with cosmological constant
c
	anti_de_Sitter_Lambda___scale = anti_de_Sitter_Lambda__scale

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for Bertotti spacetime
c
	Bertotti___Lambda = Bertotti__Lambda

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for Kasner-like spacetime
c
	Kasner_like___q = Kasner_like__q

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for generalized Kasner spacetime
c
	Kasner_generalized___p1 = Kasner_generalized__p1
	Kasner_generalized___p2 = Kasner_generalized__p2

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c parameters for constant density (Schwarzschild) star
c
	constant_density_star___mass   = constant_density_star__mass
	constant_density_star___radius = constant_density_star__radius

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

	return
	end

```

README:
```
Description of files in this directory
======================================

$Header$

This directory contains the main top-level files for thorn Exact.

There are subdirectories
include/	include files
		(n.b. all the code for the stress-energy tensor lives here)
metrics/	individual 4-metrics for the various models


The files in this directory are as follows:

Startup.c
	This is scheduled at STARTUP to register our slicing.

ParamCheck.c
	This is scheduled at PARAMCHECK to do some basic consistency
	checks on the parameters.

decode_pars.F77
	This is scheduled at INITIAL to decode/copy our parameters
	into protected grid scalars, for the benefit of the stress-energy
	tensor code in "include/Scalar_CalcTmunu.inc".  In particular,
	this code decodes the keyword parameter  exact_model  into
	the integer  decoded_exact_model  (which has one of the values
	#defined in  include/param_defs.inc ).

initialize.F77
	This contains the subroutine Exact__initialize(), which is
	top-level routine scheduled at INITIAL to set up an initial
	slice.  This basically just calls Exact__Bona_Masso_data()
	at each grid point, discarding everything it computes other
	than the 3-metric, the extrinsic curvature, and possibly
	the conformal factor and its spatial derivatives.

gauge.F77
	This contains code to set the lapse/shift from an exact solution
	either on the initial slice, or at each time step of an evolution.
	This works by calling  Exact__Bona_Masso_data()  at each grid
	point, discarding everything it computes except the lapse and
	the shift.

Bona_Masso_data.F77
	This contains the subroutine Exact__Bona_Masso_data(),
	which computes the ADM variables (3-metric, extrinsic curvature,
	lapse, shift) and some of their spatial derivatives
	(1st derivatives of the 3-metric and the lapse,
	2nd derivatives of the conformal factor and the shift vector)
	by calling  Exact__metric()  and finite differencing.
		[using a hard-coded 1.0e-6 grid spacing :( ]
	Note that despite the name and comments referring to the
	Bona-Masso variables, this subroutine doesn't appear to
	actually use the Bona-Masso variables (!).

boost.F77
	This contains the subroutine Exact__metric(), which calls
	Exact__metric_for_model() and then applies an optional
	Lorentz boost to the resulting 4-metric and its inverse.

metric.F77
	This contains the subroutine Exact__metric_for_model(); this
	decodes the decoded_exact_model parameter and calls the appropriate
	Exact__<model_name>_<coords>() subroutine to compute the 4-metric
	and its inverse at a point.  See the metrics/ subdirectory
	for these computations for the various models.

boundary.F77
	This is the top-level routine scheduled at POSTSTEP to
	implement exact-solution boundary conditions.

blended_boundary.F77
xyz_blended_boundary.F77
	These files implement the blended boundary conditions described
	in "doc/slice_evolver.tex".

slice_initialize.F
slice_evolve.F
slice_data.F
linear_extrap_one_bndry.F
	These routines are scheduled at INITIAL and EVOL to allow
	the computing of exact data on arbitrary slices.  See
	"doc/slice_evolver.tex" for details.

```

make.code.defn:
```
# Main make.code.defn file for thorn Exact
# $Header$

# Source files in this directory
SRCS = ParamCheck.c			\
       Startup.c			\
       decode_pars.F			\
       initialize.F			\
					\
       slice_initialize.F		\
       slice_evolve.F			\
       slice_data.F			\
					\
       gauge.F			\
       Bona_Masso_data.F		\
					\
       boost.F			\
       metric.F			\
					\
       boundary.F			\
       blended_boundary.F		\
       xyz_blended_boundary.F		\
       linear_extrap_one_bndry.F

# Subdirectories containing source files to be compiled
# n.b. ./include/ contains source fragments to be included in other
#      thorns for calculating T_mu_nu, but these source fragments
#      do *not* go in the SUBDIRS list here
SUBDIRS = metrics

```

linear_extrap_one_bndry.F:
```
c this subroutine linearly extrapolates one Cactus variable
c on one boundary of the Cactus grid box
C $Header$

#include "cctk.h"
#include "cctk_Arguments.h"
#include "Exact.inc"

c #define-ing the symbol EXACT_NO_F90 will turn this file into a no-op
#ifndef EXACT_NO_F90
      subroutine Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,var)

      implicit none

      DECLARE_CCTK_ARGUMENTS

      integer nx,ny,nz

      CCTK_REAL var(cctk_lsh(1),cctk_lsh(2),cctk_lsh(3))

C     Grid parameters.

      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

C     Linear extrapolation from the interiors to the boundaries.
C     Does not support octant or quadrant.

C     6 faces.

      if (cctk_bbox(1).eq.1 .and. nx.ge.4 ) then 
         var(1,:,:) = 2.d0 * var(2,:,:) - var(3,:,:)
      endif
      if (cctk_bbox(3).eq.1 .and. ny.ge.4 ) then 
         var(:,1,:) = 2.d0 * var(:,2,:) - var(:,3,:)
      endif
      if (cctk_bbox(5).eq.1 .and. nz.ge.4 ) then 
         var(:,:,1) = 2.d0 * var(:,:,2) - var(:,:,3)
      endif
      if (cctk_bbox(2).eq.1 .and. nx.ge.4 ) then 
         var(nx,:,:) = 2.d0 * var(nx-1,:,:) - var(nx-2,:,:)
      endif
      if (cctk_bbox(4).eq.1 .and. ny.ge.4 ) then 
         var(:,ny,:) = 2.d0 * var(:,ny-1,:) - var(:,ny-2,:)
      endif
      if (cctk_bbox(6).eq.1 .and. nz.ge.4 ) then 
         var(:,:,nz) = 2.d0 * var(:,:,nz-1) - var(:,:,nz-2)
      endif

C     12 edges.
C     4 round face x=min.
      if ( cctk_bbox(1).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(3).eq.1 .and. ny.ge.4 ) then 
         var(1,1,:) = 2.d0 * var(2,2,:) - var(3,3,:)
      end if

      if ( cctk_bbox(1).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(4).eq.1 .and. ny.ge.4 ) then 
         var(1,ny,:) = 2.d0 * var(2,ny-1,:) - var(2,ny-2,:)
      end if

      if ( cctk_bbox(1).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(5).eq.1 .and. nz.ge.4 ) then 
         var(1,:,1) = 2.d0 * var(2,:,2) - var(3,:,3)
      end if

      if ( cctk_bbox(1).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(6).eq.1 .and. nz.ge.4 ) then 
         var(1,:,nz) = 2.d0 * var(2,:,nz-1) - var(3,:,nz-2)
      end if

C     4 around face x=max.
      if ( cctk_bbox(2).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(3).eq.1 .and. ny.ge.4 ) then 
         var(nx,1,:) = 2.d0 * var(nx-1,2,:) - var(nx-2,3,:)
      end if

      if ( cctk_bbox(2).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(4).eq.1 .and. ny.ge.4 ) then 
         var(nx,ny,:) = 2.d0 * var(nx-1,ny-1,:) - var(nx-2,ny-2,:)
      end if

      if ( cctk_bbox(2).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(5).eq.1 .and. nz.ge.4 ) then 
         var(nx,:,1) = 2.d0 * var(nx-1,:,2) - var(nx-2,:,3)
      end if

      if ( cctk_bbox(2).eq.1 .and. nx.ge.4 
     $     .and. cctk_bbox(6).eq.1 .and. nz.ge.4 ) then 
         var(nx,:,nz) = 2.d0 * var(nx-1,:,nz-1) - var(nx-2,:,nz-2)
      end if

C     Remaining 2 in y=min.
      if ( cctk_bbox(3).eq.1 .and. ny.ge.4
     $     .and. cctk_bbox(5).eq.1 .and. nz.ge.4 ) then
         var(:,1,1) = 2.d0 * var(:,2,2) - var(:,3,3)
      end if

      if ( cctk_bbox(3).eq.1 .and. ny.ge.4
     $     .and. cctk_bbox(6).eq.1 .and. nz.ge.4 ) then 
         var(:,1,nz) = 2.d0 * var(:,2,nz-1) - var(:,2,nz-2)
      end if

C     Remaining 2 in y=ymax.      
      if ( cctk_bbox(4).eq.1 .and. ny.ge.4
     $     .and. cctk_bbox(5).eq.1 .and. nz.ge.4 ) then
         var(:,ny,1) = 2.d0 * var(:,ny-1,2) - var(:,ny-2,3)  
      end if

      if ( cctk_bbox(4).eq.1 .and. ny.ge.4
     $     .and. cctk_bbox(6).eq.1 .and. nz.ge.4 ) then 
         var(:,ny,nz) = 2.d0 * var(:,ny-1,nz-1) - var(:,ny-2,nz-2)
      end if

C     8 corners.

      if (nx.ge.4 .and. ny.ge.4 .and. nz.ge.4) then
         if (cctk_bbox(1).eq.1 .and. cctk_bbox(3).eq.1 .and. cctk_bbox(5).eq.1) then
            var(1,1,1) = 2.d0*var(2,2,2) - var(3,3,3)
         end if
         if (cctk_bbox(1).eq.1 .and. cctk_bbox(3).eq.1 .and. cctk_bbox(6).eq.1) then
            var(1,1,nz) = 2.d0*var(2,2,nz-1) - var(3,3,nz-2)
         end if
         if (cctk_bbox(1).eq.1 .and. cctk_bbox(4).eq.1 .and. cctk_bbox(5).eq.1) then
            var(1,ny,1) = 2.d0*var(2,ny-1,2) - var(3,ny-2,3)
         end if
         if (cctk_bbox(1).eq.1 .and. cctk_bbox(4).eq.1 .and. cctk_bbox(6).eq.1) then
            var(1,ny,nz) = 2.d0*var(2,ny-1,nz-1) - var(3,ny-2,nz-2)
         end if
        if (cctk_bbox(2).eq.1 .and. cctk_bbox(3).eq.1 .and. cctk_bbox(5).eq.1) then
            var(nx,1,1) = 2.d0*var(nx-1,2,2) - var(nx-2,3,3)
         end if
         if (cctk_bbox(2).eq.1 .and. cctk_bbox(3).eq.1 .and. cctk_bbox(6).eq.1) then
            var(nx,1,nz) = 2.d0*var(nx-1,2,nz-1) - var(nx-2,3,nz-2)
         end if
         if (cctk_bbox(2).eq.1 .and. cctk_bbox(4).eq.1 .and. cctk_bbox(5).eq.1) then
            var(nx,ny,1) = 2.d0*var(nx-1,ny-1,2) - var(nx-2,ny-2,3)
         end if
         if (cctk_bbox(2).eq.1 .and. cctk_bbox(4).eq.1 .and. cctk_bbox(6).eq.1) then
            var(nx,ny,nz) = 2.d0*var(nx-1,ny-1,nz-1) - var(nx-2,ny-2,nz-2)
         end if
      end if


      return
      end
#endif

```

slice_evolve.F:
```
C     Evolve the slice in the exact spacetime.
C $Header$

C
C Note that this code ignores any conformal factor set by the model,
C and thus wont work for models which try to set a conformal factor.
C At present "Minkowski/conf wave" is the only such model.
C

#include "cctk.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"
#include "Exact.inc"

      subroutine Exact__slice_evolve(CCTK_ARGUMENTS)
      implicit none
      DECLARE_CCTK_ARGUMENTS

c #define-ing the symbol EXACT_NO_F90 will turn this subroutine into a no-op
#ifndef EXACT_NO_F90
      integer i,j,k,m,n
      integer nx,ny,nz
      integer ierr

      CCTK_REAL s1d(4,3), nd(4), nu(4), norm, gd(4,4), gu(4,4)
      CCTK_REAL dx,dy,dz,dt
      CCTK_REAL local_psi

C     Grid parameters.

      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

      dx = CCTK_DELTA_SPACE(1)
      dy = CCTK_DELTA_SPACE(2)
      dz = CCTK_DELTA_SPACE(3)

      dt = CCTK_DELTA_TIME

C     Lax, or forward in time, step. 
C     dxA/dt has previously been stored in slicetmp2
C     by slice_data.

      slicetmp1x = slicex + 0.5d0 * dt * slicetmp2x
      slicetmp1y = slicey + 0.5d0 * dt * slicetmp2y
      slicetmp1z = slicez + 0.5d0 * dt * slicetmp2z
      slicetmp1t = slicet + 0.5d0 * dt * slicetmp2t

C     Synchronize and bound slice.

      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp1x)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp1y)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp1z)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp1t)

      call CCTK_SyncGroup(ierr,cctkGH,"Exact::Exact_slicetemp1")

C     Prepare leapfrog step.
C     Sum over interior points on the slice, now at midpoint slicetmp1.

      do k=2,nz-1
         do j=2,ny-1
            do i=2,nx-1

C     Calculate first derivatives of slice coordinates.

               s1d(1,1) = 0.5d0*(slicetmp1x(i+1,j,k) - slicetmp1x(i-1,j,k))/dx
               s1d(1,2) = 0.5d0*(slicetmp1x(i,j+1,k) - slicetmp1x(i,j-1,k))/dy
               s1d(1,3) = 0.5d0*(slicetmp1x(i,j,k+1) - slicetmp1x(i,j,k-1))/dz

               s1d(2,1) = 0.5d0*(slicetmp1y(i+1,j,k) - slicetmp1y(i-1,j,k))/dx
               s1d(2,2) = 0.5d0*(slicetmp1y(i,j+1,k) - slicetmp1y(i,j-1,k))/dy
               s1d(2,3) = 0.5d0*(slicetmp1y(i,j,k+1) - slicetmp1y(i,j,k-1))/dz

               s1d(3,1) = 0.5d0*(slicetmp1z(i+1,j,k) - slicetmp1z(i-1,j,k))/dx
               s1d(3,2) = 0.5d0*(slicetmp1z(i,j+1,k) - slicetmp1z(i,j-1,k))/dy
               s1d(3,3) = 0.5d0*(slicetmp1z(i,j,k+1) - slicetmp1z(i,j,k-1))/dz

               s1d(4,1) = 0.5d0*(slicetmp1t(i+1,j,k) - slicetmp1t(i-1,j,k))/dx
               s1d(4,2) = 0.5d0*(slicetmp1t(i,j+1,k) - slicetmp1t(i,j-1,k))/dy
               s1d(4,3) = 0.5d0*(slicetmp1t(i,j,k+1) - slicetmp1t(i,j,k-1))/dz

C     Now we need the exact solution metric in the preferred coordinates
C     x^A. 
               call Exact__metric(
     $              decoded_exact_model,
     $              slicetmp1x(i,j,k), slicetmp1y(i,j,k), slicetmp1z(i,j,k), 
     $              slicetmp1t(i,j,k),
     $              gd(4,4), gd(1,4), gd(2,4), gd(3,4),
     $              gd(1,1), gd(2,2), gd(3,3), gd(1,2), gd(2,3), gd(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), gu(1,2), gu(2,3), gu(1,3),
     $              local_psi)

C     Calculate n^A and dx^A/dt
#include "include/slice_normal.inc"

            end do
         end do
      end do

C     Synchronize and bound slicetmp2, which contains dx^A/dt.

      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2x)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2y)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2z)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2t)

      call CCTK_SyncGroup(ierr,cctkGH,"Exact::Exact_slicetemp2")

C Leapfrog step.

      slicex = slicex + dt * slicetmp2x
      slicey = slicey + dt * slicetmp2y
      slicez = slicez + dt * slicetmp2z
      slicet = slicet + dt * slicetmp2t

C     Synchronize and bound slice.

      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicex)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicey)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicez)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicet)

      call CCTK_SyncGroup(ierr,cctkGH,"Exact::Exact_slice")

C     Extract Cauchy data at the new position, and store dxA/dt 
C     for use in the next Lax step.

      call Exact__slice_data(CCTK_ARGUMENTS)
#endif

      return
      end

```

boost.F:
```
c This subroutine calculates the 4-metric and its inverse at an event,
c taking into account an optional Lorentz boost and an optional rotation.
c The model is first rotated and then boosted, such that the boost is
c applied to the rotated model.
c $Header$
c
c The coordinates are
c   Cx(a) = Cactus $x^a$
c   Mx(a) = Model  $X^a$
c The 4-metrics are
c   Cgdd(a,b) = Cactus $g_{ab}$            Cguu(a,b) = Cactus $g^{ab}$
c   Mgdd(a,b) = Model  $g_{ab}$            Mguu(a,b) = Model  $g^{ab}$
c
c For a definition of the Euler angles in the conventions used below, see
c    http://mathworld.wolfram.com/EulerAngles.html
c Another useful resource may be
c    http://en.wikipedia.org/wiki/Euler_angles
c although this uses (on 2006-11-29) different conventions.
c
c This file is copyright (c) 2003 by Jonathan Thornburg <jthorn@aei.mpg.de>.
c This file is covered by the GNU GPL license; see the files ../README
c and ../COPYING for details. 
c

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

#include "param_defs.inc"

      subroutine Exact__metric(
     $     decoded_exact_model,
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz,
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $     gutt, gutx, guty, gutz,
     $     guxx, guyy, guzz, guxy, guyz, guxz,
     $     psi)

      implicit none
      DECLARE_CCTK_FUNCTIONS
      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_INT decoded_exact_model
      CCTK_REAL x, y, z, t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz,
     $          gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $          gutt, gutx, guty, gutz,
     $          guxx, guyy, guzz, guxy, guyz, guxz,
     $          psi

c static local variables describing Lorentz transformation
      logical   firstcall
      data      firstcall /.true./
      CCTK_REAL gamma
      CCTK_REAL vv(3), nn(3)
      CCTK_REAL parallel(3,3), perp(3,3)
      CCTK_REAL Cx_par(3), Cx_perp(3)
      CCTK_REAL partial_Mx_wrt_Cx(0:3,0:3)
      CCTK_REAL partial_Cx_wrt_Mx(0:3,0:3)
      CCTK_REAL R(0:3,0:3)
      save      firstcall
      save      gamma
      save      vv
      save      parallel, perp
      save      partial_Mx_wrt_Cx
      save      partial_Cx_wrt_Mx
      save      R
c$omp threadprivate (firstcall, gamma, vv, parallel, perp, 
c$omp+               partial_Mx_wrt_Cx,partial_Cx_wrt_Mx, R)

c coordinates and 4-metric
      CCTK_REAL Cx(0:3)
      CCTK_REAL Cgdd(0:3,0:3), Cguu(0:3,0:3)
      CCTK_REAL Mx(0:3)
      CCTK_REAL Mgdd(0:3,0:3), Mguu(0:3,0:3)
      CCTK_REAL Nx(0:3)
      CCTK_REAL Ngdd(0:3,0:3), Nguu(0:3,0:3)

c misc temps
      CCTK_REAL vnorm, vnormsq
      CCTK_REAL delta_ij
      CCTK_REAL Cx_par_i, Cx_perp_i
      CCTK_REAL vdotCx
      CCTK_REAL Cgdd_ab, Cguu_ab
      CCTK_REAL cos_phi, sin_phi
      CCTK_REAL cos_theta, sin_theta
      CCTK_REAL cos_psi, sin_psi
      CCTK_REAL R_phi(0:3,0:3), R_theta(0:3,0:3), R_psi(0:3,0:3)
      character*1000 warn_buffer

c flags, array indices, etc
      logical Tmunu_flag
      integer i, j, k, l
      integer Ca, Cb, MA, MB

c constants
      integer n
      parameter (n = 3)

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c optimized fast-path if no Lorentz boost and no rotation
c
      if (       (boost_vx .eq. 0.0)
     $     .and. (boost_vy .eq. 0.0)
     $     .and. (boost_vz .eq. 0.0)
     $     .and. (rotation_euler_phi   .eq. 0.0)
     $     .and. (rotation_euler_theta .eq. 0.0)
     $     .and. (rotation_euler_psi   .eq. 0.0)) then
         call Exact__metric_for_model(
     $        decoded_exact_model,
     $        x, y, z, t,
     $        gdtt, gdtx, gdty, gdtz,
     $        gdxx, gdyy, gdzz, gdxy, gdyz, gdxz,
     $        gutt, gutx, guty, gutz,
     $        guxx, guyy, guzz, guxy, guyz, guxz,
     $        psi,
     $        Tmunu_flag)
         return
      end if

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c the rest of this function is the Lorentz-boost case:
c - Lorentz-transform Cactus coordinates --> Model coordinates
c - compute Model 4-metric and inverse at Model coordinates
c - tensor-transform 4-metric and inverse from Model coordinates
c   --> Cactus coordinates
c
c All the equations used are given in ../doc/documentation.tex
c

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c compute Lorentz transformation information on first call
c
      if (firstcall) then

c boost velocity
         vv(1) = boost_vx
         vv(2) = boost_vy
         vv(3) = boost_vz

c Lorentz gamma factor, unit vector in direction of boost velocity
         vnormsq = 0.0
         do i = 1,n
            vnormsq = vnormsq + vv(i)*vv(i)
         end do
         gamma = 1.0 / sqrt(1.0 - vnormsq)
         vnorm = sqrt(vnormsq)
         if (       (boost_vx .eq. 0.0)
     $        .and. (boost_vy .eq. 0.0)
     $        .and. (boost_vz .eq. 0.0)) then
            nn(1) = 1
            nn(2) = 0
            nn(3) = 0
         else
            do i = 1,n
               nn(i) = vv(i) / vnorm
            end do
         end if

c projection operators parallel(*,*) and perp(*,*)
         do j = 1,n
            do i = 1,n
               parallel(i,j) = nn(i) * nn(j)
               if (i .eq. j) then
                  delta_ij = 1.0
               else
                  delta_ij = 0.0
               end if
               perp(i,j) = delta_ij - parallel(i,j)
            end do
         end do

c partial derivatives of Model coordinates with respect to Cactus coordinates
         partial_Mx_wrt_Cx(0,0) = gamma
         do i = 1,n
            partial_Mx_wrt_Cx(0,i) = -gamma*vv(i)
         end do
         do i = 1,n
            partial_Mx_wrt_Cx(i,0) = -gamma*vv(i)
            do j=1,n
               partial_Mx_wrt_Cx(i,j) = gamma*parallel(i,j) + perp(i,j)
            end do
         end do

c partial derivatives of Cactus coordinates with respect to Model coordinates
         partial_Cx_wrt_Mx(0,0) = gamma
         do i = 1,n
            partial_Cx_wrt_Mx(0,i) = + gamma*vv(i)
         end do
         do i = 1,n
            partial_Cx_wrt_Mx(i,0) = + gamma*vv(i)
            do j=1,n
               partial_Cx_wrt_Mx(i,j) = gamma*parallel(i,j) + perp(i,j)
            end do
         end do

c Sines and cosines of rotation angles
         cos_phi   = cos (rotation_euler_phi)
         sin_phi   = sin (rotation_euler_phi)
         cos_theta = cos (rotation_euler_theta)
         sin_theta = sin (rotation_euler_theta)
         cos_psi   = cos (rotation_euler_psi)
         sin_psi   = sin (rotation_euler_psi)

c Set up individual rotation matrices
         R_phi(0,0) = 1
         R_phi(0,1) = 0
         R_phi(0,2) = 0
         R_phi(0,3) = 0
         R_phi(1,0) = 0
         R_phi(1,1) = + cos_phi
         R_phi(1,2) = + sin_phi
         R_phi(1,3) = 0
         R_phi(2,0) = 0
         R_phi(2,1) = - sin_phi
         R_phi(2,2) = + cos_phi
         R_phi(2,3) = 0
         R_phi(3,0) = 0
         R_phi(3,1) = 0
         R_phi(3,2) = 0
         R_phi(3,3) = 1

         R_theta(0,0) = 1
         R_theta(0,1) = 0
         R_theta(0,2) = 0
         R_theta(0,3) = 0
         R_theta(1,0) = 0
         R_theta(1,1) = 1
         R_theta(1,2) = 0
         R_theta(1,3) = 0
         R_theta(2,0) = 0
         R_theta(2,1) = 0
         R_theta(2,2) = + cos_theta
         R_theta(2,3) = + sin_theta
         R_theta(3,0) = 0
         R_theta(3,1) = 0
         R_theta(3,2) = - sin_theta
         R_theta(3,3) = + cos_theta

         R_psi(0,0) = 1
         R_psi(0,1) = 0
         R_psi(0,2) = 0
         R_psi(0,3) = 0
         R_psi(1,0) = 0
         R_psi(1,1) = + cos_psi
         R_psi(1,2) = + sin_psi
         R_psi(1,3) = 0
         R_psi(2,0) = 0
         R_psi(2,1) = - sin_psi
         R_psi(2,2) = + cos_psi
         R_psi(2,3) = 0
         R_psi(3,0) = 0
         R_psi(3,1) = 0
         R_psi(3,2) = 0
         R_psi(3,3) = 1

c Combine individual rotation matrices
         do i = 0,n
            do j = 0,n
               R(i,j) = 0
               do k = 0,n
                  do l = 0,n
                     R(i,j) = R(i,j) + R_psi(i,k) * R_theta(k,l) * R_phi(l,j)
                  end do
               end do
            end do
         end do

c     Notes that help me (Erik Schnetter) think:
c     This considers a rotation with phi=0, theta=pi/2, psi=0.
c     Nx(i) = Nx(i) + R(j,i) * Mx(j)
c     Nx(1) = - Mx(3)
c     Nx(3) =   Mx(1)
c     Mgxx(1,1) =   Ngxx(3,3)
c     Mgxx(1,3) = - Ngxx(1,3)
c     Mgxx(3,3) =   Ngxx(1,1)
c     Mgxx(i,j) = R(i,k) R(j,l) Ngxx(k,l)  [correct]
c     Mgxx(i,j) = R(k,i) R(l,j) Ngxx(k,l)  [correct]
c     Mbetax(1) = - Nbetax(3)
c     Mbetax(3) =   Nbetax(1)
c     Mbetax(i) + R(i,j) Nbetax(j)   [wrong]
c     Mbetax(i) + R(j,i) Nbetax(j)   [correct]

         firstcall = .false.
      end if

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c
c compute flat-space components of Cx(*) parallel and perpendicular to vv(*)
c
      Cx(0) = t
      Cx(1) = x
      Cx(2) = y
      Cx(3) = z

      do i=1,n
         Cx_par_i  = 0.0
         Cx_perp_i = 0.0
         do j=1,n
            Cx_par_i  = Cx_par_i  + parallel(i,j)*Cx(j)
            Cx_perp_i = Cx_perp_i + perp    (i,j)*Cx(j)
         end do
         Cx_par (i) = Cx_par_i
         Cx_perp(i) = Cx_perp_i
      end do

c
c Lorentz-transform and rotate the Cactus coordinate
c to get the Model coordinates
c

c Boost
      vdotCx = 0.0
      do i = 1,n
         vdotCx = vdotCx + vv(i)*Cx(i)
      end do

      Mx(0) = gamma * (Cx(0) - vdotCx)
      do i=1,n
         Mx(i) = gamma * (Cx_par(i) - vv(i)*Cx(0)) + Cx_perp(i)
      end do

c Rotation
      do i=0,n
         Nx(i) = 0
         do j = 0,n
            Nx(i) = Nx(i) + R(i,j) * Mx(j)
         end do
      end do


c
c compute the Model 4-metric and inverse 4-metric at the Model coordinates
c
      call Exact__metric_for_model(
     $     decoded_exact_model,
     $     Nx(1), Nx(2), Nx(3), Nx(0),
     $     Ngdd(0,0), Ngdd(0,1), Ngdd(0,2), Ngdd(0,3),
     $     Ngdd(1,1), Ngdd(2,2), Ngdd(3,3),
     $     Ngdd(1,2), Ngdd(2,3), Ngdd(1,3),
     $     Nguu(0,0), Nguu(0,1), Nguu(0,2), Nguu(0,3),
     $     Nguu(1,1), Nguu(2,2), Nguu(3,3),
     $     Nguu(1,2), Nguu(2,3), Nguu(1,3),
     $     psi, Tmunu_flag)

      if (Tmunu_flag) then
         write (warn_buffer, '(a,i8,a,a)')
     $        'exact_model = ', decoded_exact_model,
     $        'sets the stress-energy tensor',
     $        ' ==> we cannot Lorentz-boost or rotate it!'
         call CCTK_WARN(0, warn_buffer)
      end if

c
c symmetrize the Model 4-metric and inverse 4-metric arrays
c (the Exact__metric_for_model() call only set the upper triangles)
c
      Ngdd(1,0) = Ngdd(0,1)
      Ngdd(2,0) = Ngdd(0,2)
      Ngdd(2,1) = Ngdd(1,2)
      Ngdd(3,0) = Ngdd(0,3)
      Ngdd(3,1) = Ngdd(1,3)
      Ngdd(3,2) = Ngdd(2,3)

      Nguu(1,0) = Nguu(0,1)
      Nguu(2,0) = Nguu(0,2)
      Nguu(2,1) = Nguu(1,2)
      Nguu(3,0) = Nguu(0,3)
      Nguu(3,1) = Nguu(1,3)
      Nguu(3,2) = Nguu(2,3)

c
c tensor-transorm (the upper triangle of) the 4-metric and inverse 4-metric
c

c Rotations
      do i = 0,n
         do j = 0,n
            Mgdd(i,j) = 0
            Mguu(i,j) = 0
            do k = 0,n
               do l = 0,n
                  Mgdd(i,j) = Mgdd(i,j) + R(k,i) * R(l,j) * Ngdd(k,l)
c     The inverse of R is also its transpose.  That means that the
c     transpose of the inverse, which you would use for g^ij, is just R
c     again.
                  Mguu(i,j) = Mguu(i,j) + R(k,i) * R(l,j) * Nguu(k,l)
               end do
            end do
         end do
      end do

c Boost
      do Ca = 0,n
         do Cb = Ca,n
            Cgdd_ab = 0.0
            do Ma = 0,n
               do Mb = 0,n
                  Cgdd_ab = Cgdd_ab
     $                 +  Mgdd(Ma,Mb)
     $                    * partial_Mx_wrt_Cx(Ma,Ca)
     $                    * partial_Mx_wrt_Cx(Mb,Cb)
               end do
            end do
            Cgdd(Ca,Cb) = Cgdd_ab
         end do
      end do

      do Ca = 0,n
         do Cb = Ca,n
            Cguu_ab = 0.0
            do Ma = 0,n
               do Mb = 0,n
                  Cguu_ab = Cguu_ab
     $                 +  Mguu(Ma,Mb)
     $                    * partial_Cx_wrt_Mx(Ca,Ma)
     $                    * partial_Cx_wrt_Mx(Cb,Mb)
               end do
            end do
            Cguu(Ca,Cb) = Cguu_ab
         end do
      end do

c
c unpack the Cactus-coordinates 4-metric and inverse 4-metric
c into the corresponding output arguments
c
      gdtt = Cgdd(0,0)
      gdtx = Cgdd(0,1)
      gdty = Cgdd(0,2)
      gdtz = Cgdd(0,3)
      gdxx = Cgdd(1,1)
      gdxy = Cgdd(1,2)
      gdxz = Cgdd(1,3)
      gdyy = Cgdd(2,2)
      gdyz = Cgdd(2,3)
      gdzz = Cgdd(3,3)

      gutt = Cguu(0,0)
      gutx = Cguu(0,1)
      guty = Cguu(0,2)
      gutz = Cguu(0,3)
      guxx = Cguu(1,1)
      guxy = Cguu(1,2)
      guxz = Cguu(1,3)
      guyy = Cguu(2,2)
      guyz = Cguu(2,3)
      guzz = Cguu(3,3)

      end

```

initialize.F:
```
C     Wrapper for boostrotdata. Calls it and vectorini.
C     Sets Cauchy data, lapse and shift, and what else is needed
C     in the Bona-Masso formalism, at an initial time.
C $Header$
      
#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

      subroutine Exact__initialize(CCTK_ARGUMENTS)

      implicit none

      DECLARE_CCTK_ARGUMENTS
      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

      integer i,j,k
      integer nx,ny,nz

      CCTK_REAL tt, xx, yy, zz
      CCTK_REAL alpjunk, dtalpjunk, axjunk, ayjunk, azjunk, 
     $     betaxjunk, betayjunk, betazjunk,
     $     dtbetaxjunk, dtbetayjunk, dtbetazjunk,
     $     bxxjunk, bxyjunk, bxzjunk, 
     $     byxjunk, byyjunk, byzjunk, 
     $     bzxjunk, bzyjunk, bzzjunk
      CCTK_REAL 
     $     dxgxxjunk, dxgyyjunk, dxgzzjunk, 
     $     dxgxyjunk, dxgyzjunk, dxgxzjunk,
     $     dygxxjunk, dygyyjunk, dygzzjunk, 
     $     dygxyjunk, dygyzjunk, dygxzjunk,
     $     dzgxxjunk, dzgyyjunk, dzgzzjunk, 
     $     dzgxyjunk, dzgyzjunk, dzgxzjunk
      CCTK_REAL
     $     exact_psi,
     $     exact_psix, exact_psiy, exact_psiz,
     $     exact_psixx, exact_psiyy, exact_psizz,
     $     exact_psixy, exact_psiyz, exact_psixz

      call CCTK_INFO('setting exact data on slice')

C     Set conformal state
      if (CCTK_EQUALS(metric_type, "static conformal")) then
        conformal_state=1
        if (CCTK_EQUALS(conformal_storage,"factor+derivs")) then
          conformal_state = 2
        else if
     $     (CCTK_EQUALS(conformal_storage, "factor+derivs+2nd derivs"))
     $     then
          conformal_state = 3
        end if
      end if

C     Note I assume time has been initialized to physical time.
C     Set data pointwise.

      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

C$omp parallel do private(
C$omp$     i, j, k,
C$omp$     tt, xx, yy, zz,
C$omp$     alpjunk, dtalpjunk, axjunk, ayjunk, azjunk, 
C$omp$     betaxjunk, betayjunk, betazjunk,
C$omp$     dtbetaxjunk, dtbetayjunk, dtbetazjunk,
C$omp$     bxxjunk, bxyjunk, bxzjunk, 
C$omp$     byxjunk, byyjunk, byzjunk, 
C$omp$     bzxjunk, bzyjunk, bzzjunk,
C$omp$     dxgxxjunk, dxgyyjunk, dxgzzjunk, 
C$omp$     dxgxyjunk, dxgyzjunk, dxgxzjunk,
C$omp$     dygxxjunk, dygyyjunk, dygzzjunk, 
C$omp$     dygxyjunk, dygyzjunk, dygxzjunk,
C$omp$     dzgxxjunk, dzgyyjunk, dzgzzjunk, 
C$omp$     dzgxyjunk, dzgyzjunk, dzgxzjunk,
C$omp$     exact_psi,
C$omp$     exact_psix, exact_psiy, exact_psiz,
C$omp$     exact_psixx, exact_psiyy, exact_psizz,
C$omp$     exact_psixy, exact_psiyz, exact_psixz)
      do k=1,nz
         do j=1,ny
            do i=1,nx

               tt = cctk_time
               xx = x(i,j,k) - cctk_time * shift_add_x
               yy = y(i,j,k) - cctk_time * shift_add_y
               zz = z(i,j,k) - cctk_time * shift_add_z

C     Initialize the psi of exact
C     (also to tell the models about the conformal_state)
               if (conformal_state .ne. 0) then
                 exact_psi = 1.0D0
               else
                 exact_psi = 0.0D0
               end if
               exact_psix = 0.0D0
               exact_psiy = 0.0D0
               exact_psiz = 0.0D0
               exact_psixx = 0.0D0
               exact_psiyy = 0.0D0
               exact_psizz = 0.0D0
               exact_psixy = 0.0D0
               exact_psiyz = 0.0D0
               exact_psixz = 0.0D0

               call Exact__Bona_Masso_data(
     $              decoded_exact_model,
     $              xx, yy, zz, tt,
     $              gxx(i,j,k), gyy(i,j,k), gzz(i,j,k), 
     $              gxy(i,j,k), gyz(i,j,k), gxz(i,j,k),
     $              kxx(i,j,k), kyy(i,j,k), kzz(i,j,k), 
     $              kxy(i,j,k), kyz(i,j,k), kxz(i,j,k),
     $              exact_psi,
     $              exact_psix, exact_psiy, exact_psiz,
     $              exact_psixx, exact_psiyy, exact_psizz,
     $              exact_psixy, exact_psiyz, exact_psixz,
     $              dxgxxjunk, dxgyyjunk, dxgzzjunk, 
     $              dxgxyjunk, dxgyzjunk, dxgxzjunk,
     $              dygxxjunk, dygyyjunk, dygzzjunk, 
     $              dygxyjunk, dygyzjunk, dygxzjunk,
     $              dzgxxjunk, dzgyyjunk, dzgzzjunk, 
     $              dzgxyjunk, dzgyzjunk, dzgxzjunk,
     $              alpjunk, dtalpjunk, axjunk, ayjunk, azjunk, 
     $              betaxjunk, betayjunk, betazjunk,
     $              dtbetaxjunk, dtbetayjunk, dtbetazjunk,
     $              bxxjunk, bxyjunk, bxzjunk,
     $              byxjunk, byyjunk, byzjunk,
     $              bzxjunk, bzyjunk, bzzjunk)

C     Save the conformal factor if wanted
               if (conformal_state .ne. 0) then
                 psi(i,j,k) = exact_psi
                 if (conformal_state .gt. 1) then
                   psix(i,j,k) = exact_psix
                   psiy(i,j,k) = exact_psiy
                   psiz(i,j,k) = exact_psiz
                   if (conformal_state .gt. 2) then
                     psixx(i,j,k) = exact_psixx
                     psiyy(i,j,k) = exact_psiyy
                     psizz(i,j,k) = exact_psizz
                     psixy(i,j,k) = exact_psixy
                     psiyz(i,j,k) = exact_psiyz
                     psixz(i,j,k) = exact_psixz
                   end if
                 end if
               end if

            end do
         end do
      end do
      
C     Tell the code there is no need to treat the conformal factor
C     as a separate field. That is, we have set the physical metric here.
c     Commented out in einstein revamp, now Exact does not inherit anything
c     about the conformal factor
c     Now it does again (see above, knarf)

      return
      end

```

slice_data.F:
```
C     Extract Cauchy data from the slice x^A(x^i) stored in slicex,
C     slicey, slicez, slicet, and calculate dx^A/dt.
C $Header$

#include "cctk.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"
#include "Exact.inc"

      subroutine Exact__slice_data(CCTK_ARGUMENTS)
      implicit none
      DECLARE_CCTK_ARGUMENTS

c #define-ing the symbol EXACT_NO_F90 will turn this subroutine into a no-op
#ifndef EXACT_NO_F90
      integer i, j, k, l, m, n, p, q
      integer nx,ny,nz
      integer ierr

      CCTK_REAL s1d(4,3), nd(4), nu(4), norm, gd(4,4), gu(4,4), g3(3,3),
     $   gd_p(4,4), gd_m(4,4), gd1d(4,4,4), s2d(4,3,3), k3(3,3), 
     $   ex_eps, dx, dy, dz, exact_psi
      parameter (ex_eps=1.d-6)

C     Grid parameters.

      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

      dx = CCTK_DELTA_SPACE(1)
      dy = CCTK_DELTA_SPACE(2)
      dz = CCTK_DELTA_SPACE(3)

C     Sum over interior points on the slice.

      do k=2,nz-1
         do j=2,ny-1
            do i=2,nx-1

C     Calculate first derivatives of slice coordinates.

               s1d(1,1) = 0.5d0 * (slicex(i+1,j,k) - slicex(i-1,j,k))/dx
               s1d(1,2) = 0.5d0 * (slicex(i,j+1,k) - slicex(i,j-1,k))/dy
               s1d(1,3) = 0.5d0 * (slicex(i,j,k+1) - slicex(i,j,k-1))/dz

               s1d(2,1) = 0.5d0 * (slicey(i+1,j,k) - slicey(i-1,j,k))/dx
               s1d(2,2) = 0.5d0 * (slicey(i,j+1,k) - slicey(i,j-1,k))/dy
               s1d(2,3) = 0.5d0 * (slicey(i,j,k+1) - slicey(i,j,k-1))/dz

               s1d(3,1) = 0.5d0 * (slicez(i+1,j,k) - slicez(i-1,j,k))/dx
               s1d(3,2) = 0.5d0 * (slicez(i,j+1,k) - slicez(i,j-1,k))/dy
               s1d(3,3) = 0.5d0 * (slicez(i,j,k+1) - slicez(i,j,k-1))/dz

               s1d(4,1) = 0.5d0 * (slicet(i+1,j,k) - slicet(i-1,j,k))/dx
               s1d(4,2) = 0.5d0 * (slicet(i,j+1,k) - slicet(i,j-1,k))/dy
               s1d(4,3) = 0.5d0 * (slicet(i,j,k+1) - slicet(i,j,k-1))/dz

C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               
C     Now we need the exact solution metric in the preferred coordinates x^A.

               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k), slicey(i,j,k), slicez(i,j,k), 
     $              slicet(i,j,k),
     $              gd(4,4), gd(1,4), gd(2,4), gd(3,4),
     $              gd(1,1), gd(2,2), gd(3,3), gd(1,2), gd(2,3), gd(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), gu(1,2), gu(2,3), gu(1,3),
     $              exact_psi)

C     Calculate n^A and dx^A/dt

#include "include/slice_normal.inc"

C     Calculate g_ij = X^A,i X^B,j g_AB, at first in a temp.

               g3 = 0.d0

               do p=1,3
                  do q=p,3
                     do m=1,4
                        do n=1,4
                           g3(p,q) = g3(p,q) 
     $                          + s1d(m,p) * s1d(n,q) * gd(m,n)
                        end do
                     end do
                  end do
               end do

               gxx(i,j,k) = g3(1,1)
               gxy(i,j,k) = g3(1,2)
               gxz(i,j,k) = g3(1,3)
               gyy(i,j,k) = g3(2,2)
               gyz(i,j,k) = g3(2,3)
               gzz(i,j,k) = g3(3,3)

C     Calculate x^A,ij. Do this by hand, and loop over first index 
C     with an editor (hint for proofreading).

               s2d(1,1,1) = (slicex(i+1,j,k) + slicex(i-1,j,k) 
     $              - 2.d0 * slicex(i,j,k)) / dx**2 
               s2d(1,2,2) = (slicex(i,j+1,k) + slicex(i,j-1,k) 
     $              - 2.d0 * slicex(i,j,k)) / dy**2 
               s2d(1,3,3) = (slicex(i,j,k+1) + slicex(i,j,k-1) 
     $              - 2.d0 * slicex(i,j,k)) / dz**2 
               s2d(1,1,2) = (slicex(i+1,j+1,k) - slicex(i-1,j+1,k)
     $              - slicex(i+1,j-1,k) + slicex(i-1,j-1,k)) / (4.*dx*dy)
               s2d(1,1,3) = (slicex(i+1,j,k+1) - slicex(i-1,j,k+1)
     $              - slicex(i+1,j,k-1) + slicex(i-1,j,k-1)) / (4.*dy*dz)
               s2d(1,2,3) = (slicex(i,j+1,k+1) - slicex(i,j-1,k+1)
     $              - slicex(i,j+1,k-1) + slicex(i,j-1,k-1)) / (4.*dx*dz)
               s2d(1,2,1) = s2d(1,1,2)
               s2d(1,3,2) = s2d(1,2,3)
               s2d(1,3,1) = s2d(1,1,3)

               s2d(2,1,1) = (slicey(i+1,j,k) + slicey(i-1,j,k) 
     $              - 2.d0 * slicey(i,j,k)) / dx**2 
               s2d(2,2,2) = (slicey(i,j+1,k) + slicey(i,j-1,k) 
     $              - 2.d0 * slicey(i,j,k)) / dy**2 
               s2d(2,3,3) = (slicey(i,j,k+1) + slicey(i,j,k-1) 
     $              - 2.d0 * slicey(i,j,k)) / dz**2 
               s2d(2,1,2) = (slicey(i+1,j+1,k) - slicey(i-1,j+1,k)
     $              - slicey(i+1,j-1,k) + slicey(i-1,j-1,k)) / (4.*dx*dy)
               s2d(2,1,3) = (slicey(i+1,j,k+1) - slicey(i-1,j,k+1)
     $              - slicey(i+1,j,k-1) + slicey(i-1,j,k-1)) / (4.*dy*dz)
               s2d(2,2,3) = (slicey(i,j+1,k+1) - slicey(i,j-1,k+1)
     $              - slicey(i,j+1,k-1) + slicey(i,j-1,k-1)) / (4.*dx*dz)
               s2d(2,2,1) = s2d(2,1,2)
               s2d(2,3,2) = s2d(2,2,3)
               s2d(2,3,1) = s2d(2,1,3)

               s2d(3,1,1) = (slicez(i+1,j,k) + slicez(i-1,j,k) 
     $              - 2.d0 * slicez(i,j,k)) / dx**2 
               s2d(3,2,2) = (slicez(i,j+1,k) + slicez(i,j-1,k) 
     $              - 2.d0 * slicez(i,j,k)) / dy**2 
               s2d(3,3,3) = (slicez(i,j,k+1) + slicez(i,j,k-1) 
     $              - 2.d0 * slicez(i,j,k)) / dz**2 
               s2d(3,1,2) = (slicez(i+1,j+1,k) - slicez(i-1,j+1,k)
     $              - slicez(i+1,j-1,k) + slicez(i-1,j-1,k)) / (4.*dx*dy)
               s2d(3,1,3) = (slicez(i+1,j,k+1) - slicez(i-1,j,k+1)
     $              - slicez(i+1,j,k-1) + slicez(i-1,j,k-1)) / (4.*dy*dz)
               s2d(3,2,3) = (slicez(i,j+1,k+1) - slicez(i,j-1,k+1)
     $              - slicez(i,j+1,k-1) + slicez(i,j-1,k-1)) / (4.*dx*dz)
               s2d(3,2,1) = s2d(3,1,2)
               s2d(3,3,2) = s2d(3,2,3)
               s2d(3,3,1) = s2d(3,1,3)

               s2d(4,1,1) = (slicet(i+1,j,k) + slicet(i-1,j,k) 
     $              - 2.d0 * slicet(i,j,k)) / dx**2 
               s2d(4,2,2) = (slicet(i,j+1,k) + slicet(i,j-1,k) 
     $              - 2.d0 * slicet(i,j,k)) / dy**2 
               s2d(4,3,3) = (slicet(i,j,k+1) + slicet(i,j,k-1) 
     $              - 2.d0 * slicet(i,j,k)) / dz**2 
               s2d(4,1,2) = (slicet(i+1,j+1,k) - slicet(i-1,j+1,k)
     $              - slicet(i+1,j-1,k) + slicet(i-1,j-1,k)) / (4.*dx*dy)
               s2d(4,1,3) = (slicet(i+1,j,k+1) - slicet(i-1,j,k+1)
     $              - slicet(i+1,j,k-1) + slicet(i-1,j,k-1)) / (4.*dy*dz)
               s2d(4,2,3) = (slicet(i,j+1,k+1) - slicet(i,j-1,k+1)
     $              - slicet(i,j+1,k-1) + slicet(i,j-1,k-1)) / (4.*dx*dz)
               s2d(4,2,1) = s2d(4,1,2)
               s2d(4,3,2) = s2d(4,2,3)
               s2d(4,3,1) = s2d(4,1,3)


C     Calculate g_AB,C. Need to sum explicitly over C. Do this with 
C     the editor.

C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k)+ex_eps, slicey(i,j,k), slicez(i,j,k), 
     $              slicet(i,j,k),
     $              gd_p(4,4), gd_p(1,4), gd_p(2,4), gd_p(3,4),
     $              gd_p(1,1), gd_p(2,2), gd_p(3,3), 
     $              gd_p(1,2), gd_p(2,3), gd_p(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)

C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k)-ex_eps, slicey(i,j,k), slicez(i,j,k), 
     $              slicet(i,j,k),
     $              gd_m(4,4), gd_m(1,4), gd_m(2,4), gd_m(3,4),
     $              gd_m(1,1), gd_m(2,2), gd_m(3,3), 
     $              gd_m(1,2), gd_m(2,3), gd_m(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)
               do m=1,4
                  do n=m,4
                     gd1d(m,n,1) = (gd_p(m,n) - gd_m(m,n)) / (2.*ex_eps)
                  end do
               end do

C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k), slicey(i,j,k)+ex_eps, slicez(i,j,k), 
     $              slicet(i,j,k),
     $              gd_p(4,4), gd_p(1,4), gd_p(2,4), gd_p(3,4),
     $              gd_p(1,1), gd_p(2,2), gd_p(3,3), 
     $              gd_p(1,2), gd_p(2,3), gd_p(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)
               
C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k), slicey(i,j,k)-ex_eps, slicez(i,j,k), 
     $              slicet(i,j,k),
     $              gd_m(4,4), gd_m(1,4), gd_m(2,4), gd_m(3,4),
     $              gd_m(1,1), gd_m(2,2), gd_m(3,3), 
     $              gd_m(1,2), gd_m(2,3), gd_m(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)
               do m=1,4
                  do n=m,4
                     gd1d(m,n,2) = (gd_p(m,n) - gd_m(m,n)) / (2.*ex_eps)
                  end do
               end do

               
C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k), slicey(i,j,k), slicez(i,j,k)+ex_eps, 
     $              slicet(i,j,k),
     $              gd_p(4,4), gd_p(1,4), gd_p(2,4), gd_p(3,4),
     $              gd_p(1,1), gd_p(2,2), gd_p(3,3), 
     $              gd_p(1,2), gd_p(2,3), gd_p(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)
               
C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k), slicey(i,j,k), slicez(i,j,k)-ex_eps, 
     $              slicet(i,j,k),
     $              gd_m(4,4), gd_m(1,4), gd_m(2,4), gd_m(3,4),
     $              gd_m(1,1), gd_m(2,2), gd_m(3,3), 
     $              gd_m(1,2), gd_m(2,3), gd_m(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)
               do m=1,4
                  do n=m,4
                     gd1d(m,n,3) = (gd_p(m,n) - gd_m(m,n)) / (2.*ex_eps)
                  end do
               end do

               
C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k), slicey(i,j,k), slicez(i,j,k), 
     $              slicet(i,j,k)+ex_eps,
     $              gd_p(4,4), gd_p(1,4), gd_p(2,4), gd_p(3,4),
     $              gd_p(1,1), gd_p(2,2), gd_p(3,3), 
     $              gd_p(1,2), gd_p(2,3), gd_p(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)
               
C     Preset the conformal factor
               if (conformal_state .ne. 0) then
                 exact_psi=1.0d0
               else
                 exact_psi=0.0d0
               end if
               call Exact__metric(
     $              decoded_exact_model,
     $              slicex(i,j,k), slicey(i,j,k), slicez(i,j,k), 
     $              slicet(i,j,k)-ex_eps,
     $              gd_m(4,4), gd_m(1,4), gd_m(2,4), gd_m(3,4),
     $              gd_m(1,1), gd_m(2,2), gd_m(3,3), 
     $              gd_m(1,2), gd_m(2,3), gd_m(1,3),
     $              gu(4,4), gu(1,4), gu(2,4), gu(3,4),
     $              gu(1,1), gu(2,2), gu(3,3), 
     $              gu(1,2), gu(2,3), gu(1,3), exact_psi)
               do m=1,4
                  do n=m,4
                     gd1d(m,n,4) = (gd_p(m,n) - gd_m(m,n)) / (2.*ex_eps)
                  end do
               end do

C     Fill in remaining components of metric derivative.

               do l=1,4
                  do m=1,4
                     do n=1,m-1
                        gd1d(m,n,l) = gd1d(n,m,l)
                     end do
                  end do
               end do

C     Calculate K_ij.

               k3 = 0.d0
               do p=1,3
                  do q=p,3
                     do l=1,4
                        do m=1,4
                           k3(p,q) = k3(p,q) 
     $                          + s2d(l,p,q) * nu(m) * gd(l,m)
                           do n=1,4
                              k3(p,q) = k3(p,q) + 0.5d0 * (
     $                             s1d(l,p) * s1d(n,q) * nu(m)
     $                             + s1d(n,p) * s1d(m,q) * nu(l)
     $                             - s1d(l,p) * s1d(m,q) * nu(n) )
     $                             * gd1d(l,m,n)
                           end do
                        end do
                     end do
                  end do
               end do

               kxx(i,j,k) = - k3(1,1)
               kxy(i,j,k) = - k3(1,2)
               kxz(i,j,k) = - k3(1,3)
               kyy(i,j,k) = - k3(2,2)
               kyz(i,j,k) = - k3(2,3)
               kzz(i,j,k) = - k3(3,3)

            end do
         end do
      end do

C     Synchronize and bound slicetmp2, which contains dx^A/dt.

      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2x)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2y)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2z)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,slicetmp2t)
 
      call CCTK_SyncGroup(ierr,cctkGH,"Exact::Exact_slicetemp2")

C     Bound and synchronize the 3-metric and extrinsic curvature.

      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,gxx)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,gxy)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,gxz)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,gyy)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,gyz)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,gzz)

      call CCTK_SyncGroup(ierr,cctkGH,"admbase::metric")

      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,kxx)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,kxy)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,kxz)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,kyy)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,kyz)
      call Exact__linear_extrap_one_bndry(CCTK_ARGUMENTS,kzz)

      call CCTK_SyncGroup(ierr,cctkGH,"admbase::curv")
#endif

      return
      end

```

blended_boundary.F:
```
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

      subroutine Exact__blended_boundary(CCTK_ARGUMENTS)

      implicit none

      DECLARE_CCTK_ARGUMENTS
      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

      logical doKij, doGij, doLapse, doShift

      integer i,j,k
      integer nx,ny,nz

      CCTK_REAL router, rinner, frac, onemfrac
      CCTK_REAL gxxe, gyye, gzze, gxye, gyze, gxze
      CCTK_REAL kxxe, kyye, kzze, kxye, kyze, kxze
      CCTK_REAL dxgxxe, dxgyye, dxgzze, dxgxye, dxgyze, dxgxze
      CCTK_REAL dygxxe, dygyye, dygzze, dygxye, dygyze, dygxze
      CCTK_REAL dzgxxe, dzgyye, dzgzze, dzgxye, dzgyze, dzgxze

      CCTK_REAL
     $     exact_psi,
     $     exact_psix, exact_psiy, exact_psiz,
     $     exact_psixx, exact_psiyy, exact_psizz,
     $     exact_psixy, exact_psiyz, exact_psixz

      CCTK_REAL alpe, dtalpe, axe, aye, aze
      CCTK_REAL betaxe,betaye,betaze, dtbetaxe,dtbetaye,dtbetaze
      CCTK_REAL bxxe,bxye,bxze,byxe,byye,byze,bzxe,bzye,bzze

      CCTK_REAL det, uxx, uxy, uxz, uyy, uyz, uzz

      CCTK_REAL dx,dy,dz,time
      CCTK_REAL xmx,xmn,ymx,ymn,zmx,zmn,rmx
      integer ierr

C     Grid parameters.

      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

      dx = cctk_delta_space(1)
      dy = cctk_delta_space(2)
      dz = cctk_delta_space(3)

      time = cctk_time

C     Other parameters.

      doKij = (exblend_Ks.eq.1)
      doGij = (exblend_gs.eq.1)

      doLapse  = ((exblend_gauge.eq.1).and.
     $            (CCTK_Equals(lapse_evolution_method,"exact").ne.0))
      doShift  = ((exblend_gauge.eq.1).and.
     $            (CCTK_Equals(shift_evolution_method,"exact").ne.0))

      call CCTK_CoordRange(ierr,cctkGH,xmn,xmx,-1,"x","cart3d")
      call CCTK_CoordRange(ierr,cctkGH,ymn,ymx,-1,"y","cart3d")
      call CCTK_CoordRange(ierr,cctkGH,zmn,zmx,-1,"z","cart3d")

      rmx = min(xmx,ymx,zmx)

      if (exblend_rout.lt.0) then 
         router = rmx - 2.0d0*dx
      else
         router = exblend_rout
      endif

      if (exblend_width.lt.0) then 
         rinner = router + exblend_width*dx
      else
         rinner = router - exblend_width
      endif

      do k=1,nz
         do j=1,ny
            do i=1,nx

c     We only do anything if r >= rinner so only evaluate exact data 
c     there.

               if (r(i,j,k) .ge. rinner) then

C     Initialize the psi of exact
C     (also to tell the models about the conformal_state)
                  if (conformal_state .ne. 0) then
                    exact_psi = 1.0D0
                  else
                    exact_psi = 0.0D0
                  end if
                  exact_psix = 0.0D0
                  exact_psiy = 0.0D0
                  exact_psiz = 0.0D0
                  exact_psixx = 0.0D0
                  exact_psiyy = 0.0D0
                  exact_psizz = 0.0D0
                  exact_psixy = 0.0D0
                  exact_psiyz = 0.0D0
                  exact_psixz = 0.0D0

                  call Exact__Bona_Masso_data(
     $                 decoded_exact_model,
     $                 x(i,j,k), y(i,j,k), z(i,j,k), time,
     $                 gxxe, gyye, gzze, gxye, gyze, gxze,
     $                 kxxe, kyye, kzze, kxye, kyze, kxze,
     $                 exact_psi,
     $                 exact_psix, exact_psiy, exact_psiz,
     $                 exact_psixx, exact_psiyy, exact_psizz,
     $                 exact_psixy, exact_psiyz, exact_psixz,
     $                 dxgxxe, dxgyye, dxgzze, dxgxye, dxgyze, dxgxze,
     $                 dygxxe, dygyye, dygzze, dygxye, dygyze, dygxze,
     $                 dzgxxe, dzgyye, dzgzze, dzgxye, dzgyze, dzgxze,
     $                 alpe, dtalpe, axe, aye, aze,
     $                 betaxe, betaye, betaze, dtbetaxe, dtbetaye, dtbetaze,
     $                 bxxe, bxye, bxze, byxe, 
     $                 byye, byze, bzxe, bzye, bzze)

c     This sucks, but we want the exact vs so we can blend them also.

                  det = -(gxze**2*gyye) 
     &                 + 2.d0*gxye*gxze*gyze 
     &                 - gxxe*gyze**2 
     &                 - gxye**2*gzze 
     &                 + gxxe*gyye*gzze
    
                  uxx=(-gyze**2 + gyye*gzze)/det
                  uxy=(gxze*gyze - gxye*gzze)/det
                  uyy=(-gxze**2 + gxxe*gzze)/det
                  uxz=(-gxze*gyye + gxye*gyze)/det
                  uyz=(gxye*gxze - gxxe*gyze)/det
                  uzz=(-gxye**2 + gxxe*gyye)/det

c     Outside of router we want to place exact data on our grid

                  if (r(i,j,k) .gt. router) then

c     This is one of those things I will invariably screw up if I type
c     it in so let the computer do it

#define exassign(q) q(i,j,k) = q e
#define exassign_grp(p) \
        exassign(p xx) &&\
        exassign(p xy) &&\
        exassign(p xz) &&\
        exassign(p yy) &&\
        exassign(p yz) &&\
        exassign(p zz)

c     Note this plays on the nasty trick that fortran doesnt give a
c     damn about spaces so gxx e is the same as gxxe for the parser...
c     Grody but effective!

                    if (doGij) then 
                       exassign_grp(g)
                    endif
                    if (doKij) then 
                       exassign_grp(k)
                    endif

                    if (doLapse) then 
                       exassign(alp)
                    endif
                    
                    if (doShift.and.(shift_state.ne.0)) then 
                       exassign(betax)
                       exassign(betay)
                       exassign(betaz)
                    endif

c     OK so we dont want to blend so use a goto to jump.
                 else

c     Evaluate the linear weighting fraction. Obvious...

                    frac = (r(i,j,k) - rinner) / (router - rinner)
                    onemfrac = 1.0D0 - frac

c     Once again some c-preprocessor tricks based on the whole fortran
c     space thing...

#define INTPOINT(f,v) f(i,j,k) = frac * v + onemfrac * f(i,j,k)
#define intone(f) INTPOINT(f, f e)
#define int_grp(p) \
        intone(p xx) &&\
        intone(p xy) &&\
        intone(p xz) &&\
        intone(p yy) &&\
        intone(p yz) &&\
        intone(p zz)

                    if (doGij) then 
                       int_grp(g)
                    endif
                    if (doKij) then
                       int_grp(k)
                    endif

                    if (doLapse) then 
                       intone(alp)
                    endif

                    if (doShift.and.(shift_state.ne.0)) then 
                       intone(betax)
                       intone(betay)
                       intone(betaz)
                    endif

                 endif          ! r > router else
              endif             ! r > rinner

            enddo
         enddo
      enddo

      return
      end 

```

slice_initialize.F:
```
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"
#include "Exact.inc"

      subroutine Exact__slice_initialize(CCTK_ARGUMENTS)
      implicit none
      DECLARE_CCTK_ARGUMENTS

c #define-ing the symbol EXACT_NO_F90 will turn this subroutine into a no-op
#ifndef EXACT_NO_F90
      DECLARE_CCTK_PARAMETERS

C     Initialize position of slice in exact solution spacetime.
C     For now the spatial coordinates are identified with those of the 
C     exact solution, and the exact solution time is a Gaussian.

      slicex = x
      slicey = y
      slicez = z
      slicet = slice_gauss_ampl*exp(-(x**2 + y**2 + z**2) 
     $     /slice_gauss_width**2)

C     Calculate Cauchy data and dx^A/dt.

      call Exact__slice_data(CCTK_ARGUMENTS)

C     This tells the code that what we have set is the physical metric,
C     not a conformally rescaled one.

c     Commented out in einstein revamp, now Exact doesnot inherit anything
c     about the conformal factor
c      conformal_state = 0
c      psi = 1.0D0

#endif
      return
      end

```

Startup.c:
```
/* startup routine for Exact thorn */
/* $Header$ */

#include "cctk.h"
#include "Slicing.h"

/*
 * prototypes for scheduled routines
 */
int Exact__RegisterSlicing(void);

/******************************************************************************/

int Exact__RegisterSlicing(void) 
{
  int handle;
  handle=Einstein_RegisterSlicing("exact");
  if (handle<0) CCTK_WARN(1,"Cannot register exact slicing");
  return 0;
}

```

metrics/constant_density_star.F:
```
c     The metric given here corresponds to a constant
c     density star, also known as a "Schwarzschild" star.
c     There is corresponding code in
c        include/Scalar_CalcTmunu.inc
c     to set up the matter variables.
C
c     Author: Mitica Vulcanov 
C     see ../../README for copyright & licensing info
C
c $Header$

c
c     The metric is given as a conformally flat metric.
c     Turns out that in the original areal radius, the
c     metric variables have a kink at the surface of the
c     star, but they are smooth in the conformal form.
c
c     Thanks to Philippos Papadopoulos for suggesting
c     the use of this metric.

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__constant_density_star(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x, y, z
      CCTK_DECLARE(CCTK_REAL, t,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL mass,radius
      CCTK_REAL r,c,psi4

c constants
      CCTK_REAL zero,one,two
      parameter (zero=0.0d0, one=1.0d0, two=2.0d0)

c This model has matter
c ==> it sets the stress-energy tensor in the "CalcTmunu" code
      Tmunu_flag = .true.

c     Get parameters of the metric.

      mass   = constant_density_star__mass
      radius = constant_density_star__radius

c     Find r.

      r = sqrt(x**2 + y**2 + z**2)

c     Find conformal factor.

      if (r.le.radius) then

         c = mass/(two*radius)

         psi4 = (one + c)**6/(one + c*(r/radius)**2)**2

      else

         c = mass/(two*r)

         psi4 = (one + c)**4

      end if

c     Find metric components.

      gdtt = - psi4

      gdtx = zero
      gdty = zero
      gdtz = zero

      gdxx = psi4
      gdyy = psi4
      gdzz = psi4

      gdxy = zero
      gdyz = zero
      gdzx = zero

c     Find inverse metric.

      gutt = -one/psi4

      gutx = zero
      guty = zero
      gutz = zero

      guxx = one/psi4
      guyy = one/psi4
      guzz = one/psi4

      guxy = zero
      guyz = zero
      guzx = zero

      return
      end

```

metrics/Lemaitre.F:
```
C Lemaitre type universe - FRW with k =0, p=k rho and 
C cosmological constant
C
C Author : D. Vulcanov (Timisoara, Romania)
C see ../../README for copyright & licensing info
C
C $Header$


#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Functions.h"


      subroutine Exact__Lemaitre(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS      

c input arguments
      CCTK_REAL t
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag
      
c local variables
      CCTK_REAL ka, la, e0, r0
      CCTK_REAL unu, ra, ra2, Pii

c this model sets the stress-energy tensor in the "CalcTmunu" code
      Tmunu_flag = .true.

      ka = Lemaitre__kappa
      e0 = Lemaitre__epsilon0
      la = Lemaitre__Lambda 
      r0 = Lemaitre__R0

       Pii = acos(-1.0D0)

       unu = sqrt(3.0D0*la)*t*(ka+1.0D0)/(2.0D0)

       ra  = r0*(cosh(unu)+sqrt(1.0D0+8.0D0*Pii*e0/la)*sinh(unu))**
     &       (2.0D0/(3.0D0*ka+3.0D0)) 

       ra2 = ra*ra  
 
      gdtt = -1.0D0 
      gdtx = 0.0D0 
      gdty = 0.0D0
      gdtz = 0.0D0
      gdxx = ra2
      gdyy = ra2
      gdzz = ra2
      gdxy = 0.0D0
      gdyz = 0.0D0
      gdzx = 0.0D0

      gutt = -1.0D0
      gutx = 0.0D0
      guty = 0.0D0
      gutz = 0.0D0
      guxx = 1.0D0/ra2
      guyy = 1.0D0/ra2
      guzz = 1.0D0/ra2
      guxy = 0.0D0
      guyz = 0.0D0
      guzx = 0.0D0
 


      return
      end

```

metrics/Milne.F:
```
C Milne spacetime metric ?!?!?
C Suggested by Matteo Rossi and E. Onofri (Univ. di Parma, Italy)
C They inted to use thsi metric for simulating an Pre-Big-Bang
C Cosmology, as proposed by Veneziano some year ago 
C
C Author : D. Vulcanov (Timsoara, Romania)
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"

      subroutine Exact__Milne(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

c input arguments
      CCTK_REAL x, y, z, t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL coef, x2,y2,z2,t2

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

      x2= x*x
      y2= y*y
      z2= z*z
      t2= t*t
      coef= t2/(1.d0+ x2 +y2+ z2)

      gdtt = -1.d0 
      gdtx = 0.d0  
      gdty = 0.d0 
      gdtz = 0.d0 
      gdxx =  coef*(1.d0+y2+z2) 
      gdyy =  coef*(1.d0+x2+z2) 
      gdzz =  coef*(1.d0+x2+y2)
      gdxy = -coef*x*y 
      gdyz = -coef*y*z 
      gdzx = -coef*x*z

      gutt = -1.d0 
      gutx = 0.d0 
      guty = 0.d0 
      gutz = 0.d0 
      guxx = (1.d0+x2)/(t2)
      guyy = (1.d0+y2)/(t2)
      guzz = (1.d0+z2)/(t2)
      guxy = x*y/(t2)
      guyz = y*z/(t2) 
      guzx = x*z/(t2)


      return
      end

```

metrics/Schwarzschild_BL.F:
```
c Schwarzschild spacetime in Brill-Lindquist coordinates.
C
c $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Schwarzschild_BL(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x, y, z
      CCTK_DECLARE(CCTK_REAL, t,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL eps, m

c local variables
      CCTK_REAL r, psi4

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

C     Get parameters of the exact solution.

      eps = Schwarzschild_BL__epsilon
      m   = Schwarzschild_BL__mass

      r = ((x**2 + y**2 + z**2)**2 + eps**4) ** 0.25d0
      psi4 = (1 + m / (2 * r)) ** 4

      gdtt = -1
      gdtx = 0
      gdty = 0
      gdtz = 0
      gdxx = psi4
      gdyy = psi4
      gdzz = psi4
      gdxy = 0
      gdyz = 0
      gdzx = 0

      gutt = -1
      gutx = 0
      guty = 0
      gutz = 0
      guxx = 1 / psi4
      guyy = 1 / psi4
      guzz = 1 / psi4
      guxy = 0
      guyz = 0
      guzx = 0

      return
      end

```

metrics/anti_de_Sitter_Lambda.F:
```
C Anti DeSitter metric spacetime with csomological constant
C
C Author : D. Vulcanov (Timisoara, Romania)
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__anti_de_Sitter_Lambda(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)
      CCTK_DECLARE(CCTK_REAL, t,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL arad
      CCTK_REAL am

C This model has a cosmological constant
      Tmunu_flag = .true.

      arad = anti_de_Sitter_Lambda__scale

      am=exp(2.0D0*sqrt(-arad/3.0D0)*x)   
       
      gdtt = -am 
      gdtx = 0.0D0 
      gdty = 0.0D0
      gdtz = 0.0D0
      gdxx = 1.0D0
      gdyy = am
      gdzz = am
      gdxy = 0.0D0
      gdyz = 0.0D0
      gdzx = 0.0D0

      gutt = -1.0D0/am
      gutx = 0.0D0
      guty = 0.0D0
      gutz = 0.0D0
      guxx = 1.0D0
      guyy = 1.0D0/am
      guzz = 1.0D0/am
      guxy = 0.0D0
      guyz = 0.0D0
      guzx = 0.0D0


      return
      end

```

metrics/Minkowski_shifted_gauge_wave.F:
```
C This subroutine sets up Minkowski spacetime with a gague wave.
C
c $Header$
C
C Author: unknown
C Copyright/License: unknown
C

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Functions.h"

#define Pi (4 * atan(1.d0))


      subroutine Exact__Minkowski_shifted_gauge_wave(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none
      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

c input arguments
      CCTK_REAL x, y, t
      CCTK_DECLARE(CCTK_REAL, z,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local parameter copies
      CCTK_REAL a, o, d, fs

c local variables
      CCTK_REAL H
      character*100 warn_buffer

c constants
      CCTK_REAL zero,half,one
      parameter (zero = 0.0d0, half=0.5d0, one=1.0d0)

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

C     Get parameters of the exact solution.
      a  = Minkowski_gauge_wave__amplitude
      o  = Minkowski_gauge_wave__omega
      d  = Minkowski_gauge_wave__lambda
      fs = Minkowski_gauge_wave__phase

C     How should the wave look like.
      if (CCTK_EQUALS(Minkowski_gauge_wave__what_fn,"sin")) then
         d = Minkowski_gauge_wave__lambda * half / Pi
         if (Minkowski_gauge_wave__diagonal.ne.0) then
            H = a * sin((x-y)/d - o*t/d - fs)
         else
            H = a * sin((x-o*t)/d - fs)
         end if
      else
        write (warn_buffer, '(a,a,a)')
     $        'Unknown Minkowski_gauge_wave__what_fn = "',
     $         Minkowski_gauge_wave__what_fn, '"'
C       silence compiler warning about unused variable
        H = one
        call CCTK_WARN(0, warn_buffer)
      end if

C     write metric.

      if (Minkowski_gauge_wave__diagonal.ne.0) then

        gdxx = half * H + one
        gdxy = - half * H
        gdyy = half * H + one

        guxx = - half * H + one
        guxy = half * H
        guyy = - half * H + one

      else

        gdxx = H + one
        gdxy = zero
        gdyy = one

        guxx = - H + one
        guxy = zero
        guyy = one

      end if
      
      gdtt = H - one
      gdtx = - H
      gdty = zero
      gdtz = zero

      gdzx = zero
      gdyz = zero
      gdzz = one

C     and upper metric.

      gutt = - H - one
      gutx = - H
      guty = zero
      gutz = zero

      guyz = zero
      guzx = zero
      guzz = one

      end

```

metrics/boost_rotation_symmetric.F:
```
c Boost-Rotation symmetric metric
c see Pravda and Pravdova [a-acute accent on last a], gr-qc/0003067
C
C Author: unknown
C Copyright/License: unknown
C
c $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__boost_rotation_symmetric(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x, y, z, t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz,
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz,
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c functions local to this file
      CCTK_REAL gfunc

c local variables
      CCTK_REAL h, d, numlim
      CCTK_REAL a, b, mu0, mu1, lam1, mu2, lam2,
     $    lam3, mu4, lam4, mu5, lam5, num, div, f,
     $    elam, emu0, delta, tmp

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

C     Get parameters of the exact solution.

      h      = boost_rotation_symmetric__scale
      d      = boost_rotation_symmetric__amp
      numlim = boost_rotation_symmetric__min_d

C     Intermediate quantities.

      a = x**2 + y**2
      b = z**2 - t**2

      num = (0.5d0 * (a + b) - h)**2 + 2.d0 * h * a

C     Make sure we are not sitting on one of the two source wordlines,
C     given by x = y = 0, z = +/- sqrt(h^2 + t^2)

      if (num / h**4 .le. numlim) then
      	 call CCTK_WARN (0, "too close to source wordline")
      end if

      div = 1.d0 / sqrt(num**3)
      f = d**2  * ((0.25d0 * (a + b)**2 - h**2)**2 
     $     - 0.5d0 * h**2 * a * b) / num**4

      mu0 = - d * div * (0.5d0 * a**2 + h * a)
      mu1 = - d * div * (0.5d0 * b + a - h)
      lam1 = d * div * (0.5d0 * b - h) - a * f
      mu2 = gfunc(b, mu1)
      lam2 =  gfunc(b, lam1)

      lam3 = d * div * (0.5d0 * b**2 - h * b)
      lam4 = - d * div * (0.5d0 * a + h) - b * f
      mu4 = - d * div * (0.5d0 * a + b + h) 
      mu5 = gfunc(a, - mu4)
      lam5 = gfunc(a, lam4)

      elam = exp(lam3 + a * lam4)
      emu0 = exp(mu0)
      delta = exp(lam3) * (mu5 - lam5)

C     All nonvanishing metric coefficients (downstairs).

      gdxx = elam + y**2 * Delta
      gdyy = elam + x**2 * Delta
      gdxy = - x * y * Delta
      gdzz = emu0 * (1.d0 + lam2 * z**2 - mu2 * t**2)
      gdtz = - emu0 * z * t * (lam2 - mu2)
      gdtt = - emu0 * (1.d0 + mu2 * z**2 - lam2 * t**2)

C     Others.

      gdzx = 0.d0
      gdyz = 0.d0
      gdtx = 0.d0
      gdty = 0.d0

C     It is clear that the 3-metric is always spacelike in the xy plane. So
C     we only need to check that gdzz is positive.

      if (gdzz .le. 0.d0) then
         write(*,*) 'WARNING 3-metric not spacelike in boostrot at'
         write(*,*) 't =', t, 'z =', z
         write(*,*) 'x =', x, 'y =', y
	 call CCTK_WARN (0, "aborting")
      end if

C     Calculate inverse metric. That is not too difficult as it is
c     in block-diagonal form.

      tmp = gdtt * gdzz - gdtz**2

      if (tmp .eq. 0.d0) then
	 call CCTK_WARN (0, "boostrot metric inverse failed in tz plane")
      end if

      gutt = gdzz / tmp
      guzz = gdtt / tmp
      gutz = - gdtz / tmp
      
      tmp = gdxx * gdyy - gdxy**2

      if (tmp .eq. 0.d0) then
         call CCTK_WARN (0, "boostrot metric inverse failed in xy plane")
      end if

      guxx = gdyy / tmp
      guyy = gdxx / tmp
      guxy = - gdxy / tmp

      guzx = 0.d0
      guyz = 0.d0
      gutx = 0.d0
      guty = 0.d0

      return
      end

ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

C     Calculates g = [exp (x f) - 1] / x as a power series for small x, 
C     so that the expression is regular at x = 0.

      CCTK_REAL function gfunc(x, f)
    
      implicit none

      integer n

      CCTK_REAL x, f
      CCTK_REAL sum, tmp

      if (abs(x*f) .ge. 1.d-6) then
         gfunc = (exp(x*f) - 1.d0) / x
      else
         sum = 0.d0
         tmp = f
         do n=1,10
            tmp = tmp / dble(n) 
            sum = sum + tmp
            tmp = tmp * x * f
         end do
         gfunc = sum
      end if

      return
      end

```

metrics/Kerr_KerrSchild.F:
```
C     Kerr-Schild form of boosted rotating black hole.
C     Program g_ab = eta_ab + H l_a l_b, g^ab = eta^ab - H l^a l^b.
C     Here eta_ab is Minkowski in Cartesian coordinates, H is a scalar,
C     and l is a null vector.
C
C Author: unknown
C Copyright/License: unknown
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Functions.h"

      subroutine Exact__Kerr_KerrSchild(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

c input arguments
      CCTK_REAL x, y, z, t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL boostv, eps, m, a
      integer   power

c local variables
      CCTK_REAL gamma, t0, z0, x0, y0, rho02, r02, r0, costheta0, 
     $     lt0, lx0, ly0, lz0, hh, lt, lx, ly, lz

cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

C     Get parameters of the exact solution,
C     and convert from parameter file spin parameter J/m^2
C     to the J/m definition used in the code here.

      boostv = Kerr_KerrSchild__boost_v
      eps    = Kerr_KerrSchild__epsilon
      power  = Kerr_KerrSchild__power
      m      = Kerr_KerrSchild__mass
      a      = m*Kerr_KerrSchild__spin

C     Boost factor.

      gamma = 1.d0 / sqrt(1.d0 - boostv**2)

C     Lorentz transform t,x,y,z -> t0,x0,y0,z0. 
C     t0 is never used, but is here for illustration, and we introduce
C     x0 and y0 also only for clarity.
C     Note that z0 = 0 means z = vt for the BH.

      t0 = gamma * ((t - Kerr_KerrSchild__t) - boostv * (z - Kerr_KerrSchild__z))
      z0 = gamma * ((z - Kerr_KerrSchild__z) - boostv * (t - Kerr_KerrSchild__t))
      x0 = x - Kerr_KerrSchild__x
      y0 = y - Kerr_KerrSchild__y

C     Coordinate distance to center of black hole. Note it moves!

      rho02 = x0**2 + y0**2 + z0**2

C     Spherical auxiliary coordinate r and angle theta in BH rest frame.

      r02 = 0.5d0 * (rho02 - a**2) 
     $     + sqrt(0.25d0 * (rho02 - a**2)**2 + a**2 * z0**2)
      r0 = sqrt(max(0.0d0,r02))
      if (Kerr_KerrSchild__parabolic .eq. 0) then
C        Use a power law to avoid the singularity
         r0 = (r0**power + eps**power)**(1.0d0/power)
      else
         if (r0 .lt. eps) then
            if (power .eq. 0) then
               r0 = eps
            else if (power .eq. 2) then
               r0 = eps/2 + r0**2 * 1/(2*eps)
            else if (power .eq. 4) then
               r0 = 3*eps/8 + r0**2 * (3/(4*eps) - r0**2 * 1/(8*eps**3))
            else if (power .eq. 6) then
               r0 = 5*eps/16 + r0**2 * (15/(16*eps) + r0**2 * (-5/(16*eps**3) + r0**2 * 1/(16*eps**5)))
            else if (power .eq. 8) then
               r0 = 35*eps/128 + r0**2 * (35/(32*eps) + r0**2 * (-35/(64*eps**3) + r0**2 * (7/(32*eps**5) - r0**2 * 5/(128*eps**7))))
            else
               call CCTK_WARN (CCTK_WARN_ABORT, "Unsupported value of parameter Kerr_KerrSchild__power")
            end if
         end if
      end if
C     Another idea:
C        r0 = r0 + eps * exp(-x/eps)

      costheta0 = z0 / r0
      
C     Coefficient H. Note this transforms as a scalar, so does not carry
C     the suffix 0.
      hh = m * r0 / (r0**2 + a**2 * costheta0**2)
      
C     Components of l_a in rest frame. Note indices down.
      lt0 = 1.d0
      lx0 = (r0 * x0 + a * y0) / (r0**2 + a**2)
      ly0 = (r0 * y0 - a * x0) / (r0**2 + a**2)
      lz0 = z0 / r0

C     Now boost it to coordinates x, y, z, t.
C     This is the reverse Lorentz transformation, but applied
C     to a one-form, so the sign of boostv is the same as the forward
C     Lorentz transformation applied to the coordinates.

      lt = gamma * (lt0 - boostv * lz0) 
      lz = gamma * (lz0 - boostv * lt0) 
      lx = lx0
      ly = ly0
      
C     Down metric. g_ab = flat_ab + H l_a l_b

      gdtt = - 1.d0 + 2.d0 * hh * lt * lt
      gdtx = 2.d0 * hh * lt * lx
      gdty = 2.d0 * hh * lt * ly
      gdtz = 2.d0 * hh * lt * lz
      gdxx = 1.d0 + 2.d0 * hh * lx * lx
      gdyy = 1.d0 + 2.d0 * hh * ly * ly
      gdzz = 1.d0 + 2.d0 * hh * lz * lz
      gdxy = 2.d0 * hh * lx * ly
      gdyz = 2.d0 * hh * ly * lz
      gdzx = 2.d0 * hh * lz * lx

C     Up metric. g^ab = flat^ab - H l^a l^b.
C     Notice that g^ab = g_ab and l^i = l_i and l^0 = - l_0 in flat spacetime.
      gutt = - 1.d0 - 2.d0 * hh * lt * lt 
      gutx = 2.d0 * hh * lt * lx
      guty = 2.d0 * hh * lt * ly
      gutz = 2.d0 * hh * lt * lz
      guxx = 1.d0 - 2.d0 * hh * lx * lx
      guyy = 1.d0 - 2.d0 * hh * ly * ly
      guzz = 1.d0 - 2.d0 * hh * lz * lz
      guxy = - 2.d0 * hh * lx * ly
      guyz = - 2.d0 * hh * ly * lz
      guzx = - 2.d0 * hh * lz * lx

      return
      end

```

metrics/de_Sitter_Lambda.F:
```
C DeSitter metric spacetime with cosmological constant
C
C Author : D. Vulcanov (Timisoara, Romania)
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__de_Sitter_Lambda(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)
      CCTK_REAL t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL arad
      CCTK_REAL am

C This model is non-vacuum
C ==> it sets the stress-energy tensor in the "CalcTmunu" code
      Tmunu_flag = .true.

      arad = de_Sitter_Lambda__scale

      am=exp(2.0D0*sqrt(arad/3.0d0)*t)   

      gdtt = -1.d0 
      gdtx = 0.d0 
      gdty = 0.d0
      gdtz = 0.d0
      gdxx = am
      gdyy = am
      gdzz = am
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

      gutt = -1.d0
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = 1.d0/am
      guyy = 1.d0/am
      guzz = 1.d0/am
      guxy = 0.d0
      guyz = 0.d0
      guzx = 0.d0


      return
      end

```

metrics/Gowdy_wave.F:
```
C @@
C  @file      Gowdy.F77
C  @date      December 2002
C  @author    Denis Pollney
C  @desc
C             Cosmological Gowdy metric for a polarized wave in an
C	      expanding universe. See
C	        "Stable 3-level leapfrog integration in numerical relativity"
C               New, K, Watt, K, Misner, C and Centrella, J, PRD 58, 064022.
C  @desc
C  @version   $Header$
C @@

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Gowdy_wave(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL z, t
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local static variables
      logical firstcall
      CCTK_REAL amp
      CCTK_REAL PI, twoPI
      CCTK_REAL Bessel_J0, Bessel_J1
      data firstcall /.true./
      save firstcall, amp, PI, twoPI, Bessel_J0, Bessel_J1
c$omp threadprivate (firstcall, amp, PI, twoPI, Bessel_J0, Bessel_J1)
 
c local variables
      CCTK_REAL Bessel_J0_t, Bessel_J1_t
      CCTK_REAL cosz, eP, lambda
      CCTK_REAL d1, d2, d3, d4, d5, d6

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

      if (firstcall) then
          amp = Gowdy_wave__amplitude
	  PI = acos(-1.d0)
	  twoPI = 2.d0*PI
	  call jy01a(twoPI, Bessel_J0, d1, Bessel_J1, d2, d3, d4, d5, d6)
          firstcall = .false.
      end if

      if (t.eq.0.d0) then
	call CCTK_WARN(0, "The Gowdy metric is singular for t=0. You may need to set cactus::cctk_initial_time > 0.")
      end if

      call jy01a(twoPI*t, Bessel_J0_t, d1, Bessel_J1_t, d2, d3, d4, d5, d6)
      
      cosz = cos(twoPI*z)
      eP = exp(Bessel_J0_t * cosz)

      lambda = amp * (-twoPI * t * Bessel_J0_t * Bessel_J1_t * cosz**2
     +  + twoPI * PI * t**2 * (Bessel_J0_t**2 + Bessel_J1_t**2)
     +  - 0.5d0 * (twoPI**2 * (Bessel_J0**2 + Bessel_J1**2)
     +             - twoPI * Bessel_J0 * Bessel_J1))
c
c     lower metric components.
c
      gdtt = -exp(0.5d0*lambda)/sqrt(t)
      gdtx = 0.d0 
      gdty = 0.d0
      gdtz = 0.d0
      gdxx = t * eP
      gdyy = t / eP
      gdzz = -gdtt
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

c
c     upper metric components.
c
      gutt = 1.d0 / gdtt
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = 1.d0 / gdxx
      guyy = 1.d0 / gdyy
      guzz = 1.d0 / gdzz
      guxy = 0.d0
      guyz = 0.d0
      guzx = 0.d0

      return
      end

C @@
C  @routine   Bessel.F77
C  @date      December 2002
C  @author    Denis Pollney
C  @desc
C             Compute bessel functions of 0th and 1st order.
C             This routine was downloaded from:
C               http://iris-lee3.ece.uiuc.edu/~jjin/routines/routines.html
C
C       =======================================================
C       Purpose: Compute Bessel functions J0(x), J1(x), Y0(x),
C                Y1(x), and their derivatives
C       Input :  x   --- Argument of Jn(x) & Yn(x) ( x ? 0 )
C       Output:  BJ0 --- J0(x)
C                DJ0 --- dJ0(x)
C                BJ1 --- J1(x)
C                DJ1 --- dJ1(x)
C                BY0 --- Y0(x)
C                DY0 --- dY0(x)
C                BY1 --- Y1(x)
C                DY1 --- dY1(x)
C       =======================================================
C
C  @desc
C  @version   $Header$
C @@

        SUBROUTINE JY01A(X,BJ0,DJ0,BJ1,DJ1,BY0,DY0,BY1,DY1)
        IMPLICIT DOUBLE PRECISION (A-H,O-Z)
        DIMENSION A(12),B(12),A1(12),B1(12)
        PI=3.141592653589793D0
        RP2=0.63661977236758D0
        X2=X*X
        IF (X.EQ.0.0D0) THEN
           BJ0=1.0D0
           BJ1=0.0D0
           DJ0=0.0D0
           DJ1=0.5D0
           BY0=-1.0D+300
           BY1=-1.0D+300
           DY0=1.0D+300
           DY1=1.0D+300
           RETURN
        ENDIF
        IF (X.LE.12.0D0) THEN
           BJ0=1.0D0
           R=1.0D0
           DO 5 K=1,30
              R=-0.25D0*R*X2/(K*K)
              BJ0=BJ0+R
              IF (DABS(R).LT.DABS(BJ0)*1.0D-15) GO TO 10
5          CONTINUE
10         BJ1=1.0D0
           R=1.0D0
           DO 15 K=1,30
              R=-0.25D0*R*X2/(K*(K+1.0D0))
              BJ1=BJ1+R
              IF (DABS(R).LT.DABS(BJ1)*1.0D-15) GO TO 20
15         CONTINUE
20         BJ1=0.5D0*X*BJ1
           EC=DLOG(X/2.0D0)+0.5772156649015329D0
           CS0=0.0D0
           W0=0.0D0
           R0=1.0D0
           DO 25 K=1,30
              W0=W0+1.0D0/K
              R0=-0.25D0*R0/(K*K)*X2
              R=R0*W0
              CS0=CS0+R
              IF (DABS(R).LT.DABS(CS0)*1.0D-15) GO TO 30
25         CONTINUE
30         BY0=RP2*(EC*BJ0-CS0)
           CS1=1.0D0
           W1=0.0D0
           R1=1.0D0
           DO 35 K=1,30
              W1=W1+1.0D0/K
              R1=-0.25D0*R1/(K*(K+1))*X2
              R=R1*(2.0D0*W1+1.0D0/(K+1.0D0))
              CS1=CS1+R
              IF (DABS(R).LT.DABS(CS1)*1.0D-15) GO TO 40
35         CONTINUE
40         BY1=RP2*(EC*BJ1-1.0D0/X-0.25D0*X*CS1)
        ELSE
           DATA A/-.7031250000000000D-01,.1121520996093750D+00,
     &            -.5725014209747314D+00,.6074042001273483D+01,
     &            -.1100171402692467D+03,.3038090510922384D+04,
     &            -.1188384262567832D+06,.6252951493434797D+07,
     &            -.4259392165047669D+09,.3646840080706556D+11,
     &            -.3833534661393944D+13,.4854014686852901D+15/
           DATA B/ .7324218750000000D-01,-.2271080017089844D+00,
     &             .1727727502584457D+01,-.2438052969955606D+02,
     &             .5513358961220206D+03,-.1825775547429318D+05,
     &             .8328593040162893D+06,-.5006958953198893D+08,
     &             .3836255180230433D+10,-.3649010818849833D+12,
     &             .4218971570284096D+14,-.5827244631566907D+16/
           DATA A1/.1171875000000000D+00,-.1441955566406250D+00,
     &             .6765925884246826D+00,-.6883914268109947D+01,
     &             .1215978918765359D+03,-.3302272294480852D+04,
     &             .1276412726461746D+06,-.6656367718817688D+07,
     &             .4502786003050393D+09,-.3833857520742790D+11,
     &             .4011838599133198D+13,-.5060568503314727D+15/
           DATA B1/-.1025390625000000D+00,.2775764465332031D+00,
     &             -.1993531733751297D+01,.2724882731126854D+02,
     &             -.6038440767050702D+03,.1971837591223663D+05,
     &             -.8902978767070678D+06,.5310411010968522D+08,
     &             -.4043620325107754D+10,.3827011346598605D+12,
     &             -.4406481417852278D+14,.6065091351222699D+16/
           K0=12
           IF (X.GE.35.0) K0=10
           IF (X.GE.50.0) K0=8
           T1=X-0.25D0*PI
           P0=1.0D0
           Q0=-0.125D0/X
           DO 45 K=1,K0
              P0=P0+A(K)*X**(-2*K)
45            Q0=Q0+B(K)*X**(-2*K-1)
           CU=DSQRT(RP2/X)
           BJ0=CU*(P0*DCOS(T1)-Q0*DSIN(T1))
           BY0=CU*(P0*DSIN(T1)+Q0*DCOS(T1))
           T2=X-0.75D0*PI
           P1=1.0D0
           Q1=0.375D0/X
           DO 50 K=1,K0
              P1=P1+A1(K)*X**(-2*K)
50            Q1=Q1+B1(K)*X**(-2*K-1)
           CU=DSQRT(RP2/X)
           BJ1=CU*(P1*DCOS(T2)-Q1*DSIN(T2))
           BY1=CU*(P1*DSIN(T2)+Q1*DCOS(T2))
        ENDIF
        DJ0=-BJ1
        DJ1=BJ0-BJ1/X
        DY0=-BY1
        DY1=BY0-BY1/X
        RETURN
        END

```

metrics/Kasner_generalized.F:
```
C Kasner generalized metric spacetime !!!!
C
C Author : D. Vulcanov
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Kasner_generalized(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL t
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL pp1,pp2,a1,a2,a3
 
C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .true.

      pp1= Kasner_generalized__p1
      pp2= Kasner_generalized__p2

      a1= t**(2.d0*pp1)
      a2= t**(2.d0*pp2)
      a3= t**(2.d0-2.d0*pp1-2.d0*pp2)    


      gdtt = -1.d0 
      gdtx = 0.d0 
      gdty = 0.d0
      gdtz = 0.d0
      gdxx = a1 
      gdyy = a2
      gdzz = a3
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

      gutt = -1.d0
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = 1.d0/a1
      guyy = 1.d0/a2
      guzz = 1.d0/a3
      guxy = 0.d0
      guyz = 0.d0
      guzx = 0.d0
 

      return
      end

```

metrics/Alvi.F:
```
C The Alvi metric. Full description of this metric is given
C in gr-qc/9912113 . 
C Author: Nina Jansen (jansen@aei-potsdam.mpg.de)
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Alvi(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x, y, z, t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_REAL psi
      LOGICAL   Tmunu_flag

c locals
      CCTK_REAL m1,m2,b
      CCTK_REAL rin1,rin2,rout,x1,x2, r1, r2, r3, results(10)

C this is a vacuum solution with no cosmological constant
C ==> it does not set the stress-energy tensor
      Tmunu_flag = .false.

      m1 = Alvi__mass1
      m2 = Alvi__mass2
      b  = Alvi__separation

      rin1 = dsqrt(m1*b)
      rin2 = dsqrt(m2*b)
      rout = b*dsqrt(b)/(2.0d0*dsqrt(m1+m2))

      x1 = b

      x2 = -b

      r1 = dsqrt((x-x1)**2.0D0 + y**2.0D0 + z**2.0D0)


      r2 = dsqrt((x-x2)**2.0D0 + y**2.0D0 + z**2.0D0)


      r3 = dsqrt(x**2.0D0 + y**2.0D0 + z**2.0D0)

      if (r1 .le. rin1) then

      call Alvireg1(x,y,z,m1,m2,b,results)
      
      gdtt = results(1)
      gdtx = results(2)
      gdty = results(3)
      gdtz = results(4)
      gdxx = results(5)
      gdyy = results(8)
      gdzz = results(10)
      gdxy = results(9)
      gdyz = results(9)
      gdzx = results(7)
      
      else if (r2 .le. rin2) then

         call Alvireg2(x,y,z,m1,m2,b,results)

         gdtt = results(1)
         gdtx = results(2)
         gdty = results(3)
         gdtz = results(4)
         gdxx = results(5)
         gdyy = results(8)
         gdzz = results(10)
         gdxy = results(9)
         gdyz = results(9)
         gdzx = results(7)
         
      else if ((r3 .le. rout) .and. (r2 .gt. rin2) .and. (r1 .gt. rin1)) then
         call Alvireg3(x,y,z,m1,m2,b,results)

         gdtt = results(1)
         gdtx = results(2)
         gdty = results(3)
         gdtz = results(4)
         gdxx = results(5)
         gdyy = results(8)
         gdzz = results(10)
         gdxy = results(9)
         gdyz = results(9)
         gdzx = results(7)
         
      else if (r3 .gt. rout) then
         call Alvireg4(x,y,z,m1,m2,b,results)

         gdtt = results(1)
         gdtx = results(2)
         gdty = results(3)
         gdtz = results(4)
         gdxx = results(5)
         gdyy = results(8)
         gdzz = results(10)
         gdxy = results(9)
         gdyz = results(9)
         gdzx = results(7)

      else 

         print *,'problem!'

      end if         
      
      gutt = 
     $ (gdzx**2*gdyy - 2*gdxy*gdzx*gdyz + gdxy**2*gdzz + gdxx*(gdyz**2
     $ - gdyy*gdzz))/ (gdtt*gdzx**2*gdyy + gdtz**2*(-gdxy**2 +
     $ gdxx*gdyy) - 2*gdtt*gdxy*gdzx*gdyz - gdtx**2*gdyz**2 +
     $ gdtt*gdxx*gdyz**2 + 2*gdtz*(gdty*gdxy*gdzx - gdtx*gdzx*gdyy -
     $ gdty*gdxx*gdyz + gdtx*gdxy*gdyz) + gdtt*gdxy**2*gdzz +
     $ gdtx**2*gdyy*gdzz - gdtt*gdxx*gdyy*gdzz + gdty**2*(-gdzx**2 +
     $ gdxx*gdzz) + 2*gdtx*gdty*(gdzx*gdyz - gdxy*gdzz))

      gutx = 
     $ (-(gdtz*gdzx*gdyy) + gdtz*gdxy*gdyz + gdty*gdzx*gdyz -
     $ gdtx*gdyz**2 - gdty*gdxy*gdzz + gdtx*gdyy*gdzz)/
     $ (gdtt*gdzx**2*gdyy + gdtz**2*(-gdxy**2 + gdxx*gdyy) -
     $ 2*gdtt*gdxy*gdzx*gdyz - gdtx**2*gdyz**2 + gdtt*gdxx*gdyz**2 +
     $ 2*gdtz*(gdty*gdxy*gdzx - gdtx*gdzx*gdyy - gdty*gdxx*gdyz +
     $ gdtx*gdxy*gdyz) + gdtt*gdxy**2*gdzz + gdtx**2*gdyy*gdzz -
     $ gdtt*gdxx*gdyy*gdzz + gdty**2*(-gdzx**2 + gdxx*gdzz) +
     $ 2*gdtx*gdty*(gdzx*gdyz - gdxy*gdzz))


      guty = 
     $ (-(gdtz*gdxy*gdzx) + gdty*gdzx**2 + gdtz*gdxx*gdyz -
     $ gdtx*gdzx*gdyz - gdty*gdxx*gdzz + gdtx*gdxy*gdzz)/
     $ (-(gdtt*gdzx**2*gdyy) + gdtz**2*(gdxy**2 - gdxx*gdyy) +
     $ 2*gdtt*gdxy*gdzx*gdyz + gdtx**2*gdyz**2 - gdtt*gdxx*gdyz**2 -
     $ 2*gdtz*(gdty*gdxy*gdzx - gdtx*gdzx*gdyy - gdty*gdxx*gdyz +
     $ gdtx*gdxy*gdyz) - gdtt*gdxy**2*gdzz - gdtx**2*gdyy*gdzz +
     $ gdtt*gdxx*gdyy*gdzz + gdty**2*(gdzx**2 - gdxx*gdzz) +
     $ gdty*(-2*gdtx*gdzx*gdyz + 2*gdtx*gdxy*gdzz))





      gutz = 
     $ (-(gdty*gdxy*gdzx) + gdtx*gdzx*gdyy + gdtz*(gdxy**2 - gdxx*gdyy)
     $ + gdty*gdxx*gdyz - gdtx*gdxy*gdyz)/ (-(gdtt*gdzx**2*gdyy) +
     $ gdtz**2*(gdxy**2 - gdxx*gdyy) + 2*gdtt*gdxy*gdzx*gdyz +
     $ gdtx**2*gdyz**2 - gdtt*gdxx*gdyz**2 - 2*gdtz*(gdty*gdxy*gdzx -
     $ gdtx*gdzx*gdyy - gdty*gdxx*gdyz + gdtx*gdxy*gdyz) -
     $ gdtt*gdxy**2*gdzz - gdtx**2*gdyy*gdzz + gdtt*gdxx*gdyy*gdzz +
     $ gdty**2*(gdzx**2 - gdxx*gdzz) + gdty*(-2*gdtx*gdzx*gdyz +
     $ 2*gdtx*gdxy*gdzz)) 
      guxx =
     $ (gdtz**2*gdyy - 2*gdty*gdtz*gdyz + gdty**2*gdzz + gdtt*(gdyz**2
     $ - gdyy*gdzz))/ (gdtt*gdzx**2*gdyy + gdtz**2*(-gdxy**2 +
     $ gdxx*gdyy) - 2*gdtt*gdxy*gdzx*gdyz - gdtx**2*gdyz**2 +
     $ gdtt*gdxx*gdyz**2 + 2*gdtz*(gdty*gdxy*gdzx - gdtx*gdzx*gdyy -
     $ gdty*gdxx*gdyz + gdtx*gdxy*gdyz) + gdtt*gdxy**2*gdzz +
     $ gdtx**2*gdyy*gdzz - gdtt*gdxx*gdyy*gdzz + gdty**2*(-gdzx**2 +
     $ gdxx*gdzz) + 2*gdtx*gdty*(gdzx*gdyz - gdxy*gdzz)) 
      guyy = 
     $ (gdtz**2*gdxx - 2*gdtx*gdtz*gdzx + gdtx**2*gdzz + gdtt*(gdzx**2
     $ - gdxx*gdzz))/ (gdtt*gdzx**2*gdyy + gdtz**2*(-gdxy**2 +
     $ gdxx*gdyy) - 2*gdtt*gdxy*gdzx*gdyz - gdtx**2*gdyz**2 +
     $ gdtt*gdxx*gdyz**2 + 2*gdtz*(gdty*gdxy*gdzx - gdtx*gdzx*gdyy -
     $ gdty*gdxx*gdyz + gdtx*gdxy*gdyz) + gdtt*gdxy**2*gdzz +
     $ gdtx**2*gdyy*gdzz - gdtt*gdxx*gdyy*gdzz + gdty**2*(-gdzx**2 +
     $ gdxx*gdzz) + 2*gdtx*gdty*(gdzx*gdyz - gdxy*gdzz)) 
      guzz = 
     $ (gdty**2*gdxx - 2*gdtx*gdty*gdxy + gdtx**2*gdyy + gdtt*(gdxy**2
     $ - gdxx*gdyy))/ (gdtt*gdzx**2*gdyy + gdtz**2*(-gdxy**2 +
     $ gdxx*gdyy) - 2*gdtt*gdxy*gdzx*gdyz - gdtx**2*gdyz**2 +
     $ gdtt*gdxx*gdyz**2 + 2*gdtz*(gdty*gdxy*gdzx - gdtx*gdzx*gdyy -
     $ gdty*gdxx*gdyz + gdtx*gdxy*gdyz) + gdtt*gdxy**2*gdzz +
     $ gdtx**2*gdyy*gdzz - gdtt*gdxx*gdyy*gdzz + gdty**2*(-gdzx**2 +
     $ gdxx*gdzz) + 2*gdtx*gdty*(gdzx*gdyz - gdxy*gdzz)) 
      guxy = 
     $ (gdtz**2*gdxy + gdtt*gdzx*gdyz - gdtz*(gdty*gdzx + gdtx*gdyz) +
     $ gdtx*gdty*gdzz - gdtt*gdxy*gdzz)/ (-(gdtt*gdzx**2*gdyy) +
     $ gdtz**2*(gdxy**2 - gdxx*gdyy) + 2*gdtt*gdxy*gdzx*gdyz +
     $ gdtx**2*gdyz**2 - gdtt*gdxx*gdyz**2 - 2*gdtz*(gdty*gdxy*gdzx -
     $ gdtx*gdzx*gdyy - gdty*gdxx*gdyz + gdtx*gdxy*gdyz) -
     $ gdtt*gdxy**2*gdzz - gdtx**2*gdyy*gdzz + gdtt*gdxx*gdyy*gdzz +
     $ gdty**2*(gdzx**2 - gdxx*gdzz) + gdty*(-2*gdtx*gdzx*gdyz +
     $ 2*gdtx*gdxy*gdzz)) 
      guyz = 
     $ (-(gdty*gdtz*gdxx) + gdtx*gdtz*gdxy + gdtx*gdty*gdzx -
     $ gdtt*gdxy*gdzx - gdtx**2*gdyz + gdtt*gdxx*gdyz)/
     $ (gdtt*gdzx**2*gdyy + gdtz**2*(-gdxy**2 + gdxx*gdyy) -
     $ 2*gdtt*gdxy*gdzx*gdyz - gdtx**2*gdyz**2 + gdtt*gdxx*gdyz**2 +
     $ 2*gdtz*(gdty*gdxy*gdzx - gdtx*gdzx*gdyy - gdty*gdxx*gdyz +
     $ gdtx*gdxy*gdyz) + gdtt*gdxy**2*gdzz + gdtx**2*gdyy*gdzz -
     $ gdtt*gdxx*gdyy*gdzz + gdty**2*(-gdzx**2 + gdxx*gdzz) +
     $ 2*gdtx*gdty*(gdzx*gdyz - gdxy*gdzz)) 
      guzx = 
     $ (gdty**2*gdzx + gdtx*gdtz*gdyy - gdtt*gdzx*gdyy + gdtt*gdxy*gdyz
     $ - gdty*(gdtz*gdxy + gdtx*gdyz))/ (-(gdtt*gdzx**2*gdyy) +
     $ gdtz**2*(gdxy**2 - gdxx*gdyy) + 2*gdtt*gdxy*gdzx*gdyz +
     $ gdtx**2*gdyz**2 - gdtt*gdxx*gdyz**2 - 2*gdtz*(gdty*gdxy*gdzx -
     $ gdtx*gdzx*gdyy - gdty*gdxx*gdyz + gdtx*gdxy*gdyz) -
     $ gdtt*gdxy**2*gdzz - gdtx**2*gdyy*gdzz + gdtt*gdxx*gdyy*gdzz +
     $ gdty**2*(gdzx**2 - gdxx*gdzz) + gdty*(-2*gdtx*gdzx*gdyz +
     $ 2*gdtx*gdxy*gdzz)) 
      
      return

      end
      
      
      
      

```

metrics/bowl.F:
```
c     The metric given here is not a solution of
c     Einsteins equations!  It is nevertheless
c     useful for tests since it has a particularly
c     nice geometry.  It is a static, spherically
c     symmetric metric with no shift.
c
c     In spherical coordinates, the metric has the
c     form:
c
c       2      2        2        2
c     ds  =  dr  +  R(r)  d Omega
c
c     Clearly, r measures radial proper distance, and R(r)
c     is the areal (Schwarzschild) radius.
c
c     I choose a form of R(r) such that:
c
c     R  -->   r     r<<1, r>>1
c
c     So close in, and far away we have a flat metric.
c     In the middle region, I take R to be smaller than
c     r, but still larger than zero.  This deficit in
c     areal radius produces the geometry of a "bag of gold".
c
c     The size of the deviation from a flat geometry
c     is controled by the parameter "bowl__strength".
c     If this parameter is 0, we are in flat space.
c     The width of the curved region is controled by
c     the paramter "bowl__sigma", and the place where the
c     curvature becomes significant (the center of the
c     deformation) is controled by "bowl__center".
c
c     The specific form of the function R(r) is:
c
c     R(r) = ( r - a f(r) )
c
c     and the form of thr function f(r) depends on the
c     parameter bowl__shape:
c                                            2   2    2
c     bowl__shape = "Gaussian"   f(r) = exp(-(r-c) / s )
c
c     bowl__shape = "Fermi"      f(r) = 1 / ( 1 + exp(-s(r-c)) )
c
c     There are three extra paramters
c     (bowl__x_scale,bowl__y_scale,bowl__z_scale) that set the
c     scales for the (x,y,z) axis respectively.  Their default
c     value are all 1.  These parameters are useful to hide the
c     spherical symmetry of the metric.
C
C Author: unknown
C Copyright/License: unknown
c
c $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Functions.h"

      subroutine Exact__bowl(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

c input arguments
      CCTK_REAL x, y, z, t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $          gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $          gutt, gutx, guty, gutz, 
     $          guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local static variables
      logical firstcall,evolve
      integer type
      CCTK_REAL a,c,s
      CCTK_REAL dx,dy,dz
      CCTK_REAL t0,st
      data firstcall /.true./
      save firstcall,evolve,type,a,c,s,dx,dy,dz,t0,st
c$omp threadprivate (firstcall,evolve,type,a,c,s,dx,dy,dz,t0,st)

c local variables
      character*100 warn_buffer

      CCTK_REAL r,r2,rr2
      CCTK_REAL xr,yr,zr,xr2,yr2,zr2
      CCTK_REAL fac,det
      CCTK_REAL tfac

c constants
      CCTK_REAL zero,one,two
      parameter (zero=0.0d0, one=1.0d0, two=2.0d0)

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

c     Get parameters of the metric.

      if (firstcall) then

         a = bowl__strength
         c = bowl__center
         s = bowl__sigma

         dx = bowl__x_scale
         dy = bowl__y_scale
         dz = bowl__z_scale

         if      (CCTK_Equals(bowl__shape,"Gaussian").ne.0) then
            type = 1
         else if (CCTK_Equals(bowl__shape,"Fermi").ne.0) then
            type = 2
         else
            write (warn_buffer, '(a,a,a)')
     $            'Unknown bowl__shape = "', bowl__shape, '"'
            call CCTK_WARN(0, warn_buffer)
         end if

         if (bowl__evolve.eq.1) then
            evolve = .true.
            t0 = bowl__t0
            st = bowl__sigma_t
         else
            evolve = .false.
         end if

         firstcall = .false.

      end if

c     Multiply the bowl strength "a" with a time evolution factor.
c     The time evolution factor is taken to be a Fermi step centered
c     in "t0" and with a width "st".  The size of this step is always
c     1 so that far in the past we will always have flat space, and
c     far in the future we will have the static bowl.

      if (evolve) then
         tfac = one/(one + exp(-st*(t-t0)))
      else
         tfac = one
      end if

      a = a*tfac

c     Find {r2,r}.

      r2 = (x/dx)**2 + (y/dy)**2 + (z/dz)**2
      r  = sqrt(r2)

c     Find the form function rr2
c
c                      2    2                 2
c     rr2  =  (r - a f)  / r  =  (1 - a f / r)

      if (type.eq.1) then

c        Gaussian bowl:
c                                2  2       2
c        rr2 = [ 1 - a exp(-(r-c) /s ) / r ]
c
c        Notice that this really does not go to 1 at the
c        origin.  To fix this, I multiply the gaussian
c        with the factor:
c
c        fac  =  1  -  sech(4r)
c
c        This goes smoothly to 0 at the origin, and climbs
c        fast to a limiting value of 1 (at r=1 it is already
c        equal to 0.96).

         fac = one - two/(exp(4.0d0*r) + exp(-4.0d0*r))
         rr2 = (one - a*fac*exp(-((r-c)/s)**2)/r)**2

      else if (type.eq.2) then

c        Fermi bowl:
c                                                  2
c        rr2 = [ 1 - 1 / ( 1 + exp(-s(r-c)) ) / r ]
c
c        Again, this doesnt really go to 1 at the origin, so
c        I use the same trick as above.

         fac = one - two/(exp(4.0d0*r) + exp(-4.0d0*r))
         rr2 = (one - a*fac/(one + exp(-s*(r-c)))/r)**2

      else
         write (warn_buffer, '(a,i8)')
     $         'Unknown type = ', type
c        silence compiler warning about uninitialized variable
         rr2 = one
         call CCTK_WARN(0, warn_buffer)

      end if

c     Give metric components.

      gdtt = - one
      gdtx = zero
      gdty = zero
      gdtz = zero

      if (r.ne.0) then

         xr = (x/dx)/r
         yr = (y/dy)/r
         zr = (z/dz)/r

         xr2 = xr**2
         yr2 = yr**2
         zr2 = zr**2

         gdxx = (xr2 + rr2*(yr2 + zr2))/dx**2
         gdyy = (yr2 + rr2*(xr2 + zr2))/dy**2
         gdzz = (zr2 + rr2*(xr2 + yr2))/dz**2

         gdxy = xr*yr*(one - rr2)/(dx*dy)
         gdyz = yr*zr*(one - rr2)/(dy*dz)
         gdzx = xr*zr*(one - rr2)/(dx*dz)

      else

         gdxx = one
         gdyy = one
         gdzz = one

         gdxy = zero
         gdyz = zero
         gdzx = zero

      end if

c     Find inverse metric.

      gutt = - one
      gutx = zero
      guty = zero
      gutz = zero

      det = gdxx*gdyy*gdzz + two*gdxy*gdzx*gdyz
     .    - gdxx*gdyz**2 - gdyy*gdzx**2 - gdzz*gdxy**2

      guxx = (gdyy*gdzz - gdyz**2)/det
      guyy = (gdxx*gdzz - gdzx**2)/det
      guzz = (gdxx*gdyy - gdxy**2)/det

      guxy = (gdzx*gdyz - gdzz*gdxy)/det
      guyz = (gdxy*gdzx - gdxx*gdyz)/det
      guzx = (gdxy*gdyz - gdyy*gdzx)/det

      return
      end

```

metrics/Minkowski.F:
```
C Minkowski spacetime
C $Header$

#include "cctk.h"

      subroutine Exact__Minkowski(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

c input arguments
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)
      CCTK_DECLARE(CCTK_REAL, t,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

      gdtt = -1.d0 
      gdtx = 0.d0 
      gdty = 0.d0 
      gdtz = 0.d0 
      gdxx = 1.d0 
      gdyy = 1.d0 
      gdzz = 1.d0 
      gdxy = 0.d0 
      gdyz = 0.d0 
      gdzx = 0.d0

      gutt = -1.d0 
      gutx = 0.d0 
      guty = 0.d0 
      gutz = 0.d0 
      guxx = 1.d0 
      guyy = 1.d0 
      guzz = 1.d0 
      guxy = 0.d0 
      guyz = 0.d0 
      guzx = 0.d0

      return
      end

```

metrics/Minkowski_gauge_wave.F:
```
C This subroutine sets up Minkowski spacetime with a gague wave.
C
c $Header$
C
C Author: unknown
C Copyright/License: unknown
C

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Functions.h"

#define Pi (4 * atan(1.d0))


      subroutine Exact__Minkowski_gauge_wave(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none
      DECLARE_CCTK_PARAMETERS
      DECLARE_CCTK_FUNCTIONS

c input arguments
      CCTK_REAL x, y, t
      CCTK_DECLARE(CCTK_REAL, z,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local parameter copies
      CCTK_REAL a, o, d, fs

c local variables
      CCTK_REAL H
      character*100 warn_buffer

c constants
      CCTK_REAL zero,half,one
      parameter (zero = 0.0d0, half=0.5d0, one=1.0d0)

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

C     Get parameters of the exact solution.
      a  = Minkowski_gauge_wave__amplitude
      o  = Minkowski_gauge_wave__omega
      d  = Minkowski_gauge_wave__lambda
      fs = Minkowski_gauge_wave__phase

C     How should the wave look like.
      if (CCTK_EQUALS(Minkowski_gauge_wave__what_fn,"sin")) then
        d = Minkowski_gauge_wave__lambda * half / Pi
        if (Minkowski_gauge_wave__diagonal.ne.0) then
          H = one - a * sin((x-y)/d - o*t/d - fs)
        else
          H = one - a * sin((x-o*t)/d - fs)
        end if
      elseif (CCTK_EQUALS(Minkowski_gauge_wave__what_fn,"expsin")) then
c$$$        d = Minkowski_gauge_wave__lambda * half / Pi
c$$$        H = exp(a*sin(x/d)*cos(t/d))
        d = Minkowski_gauge_wave__lambda * half / Pi
        if (Minkowski_gauge_wave__diagonal.ne.0) then
          H = exp(- a * sin((x-y)/d - o*t/d - fs))
        else
          H = exp(- a * sin((x-o*t)/d - fs))
        end if
      elseif (CCTK_EQUALS(Minkowski_gauge_wave__what_fn,"Gaussian")) then
        H = one - a*exp(-(x-t)**2/d**2)
      else
        write (warn_buffer, '(a,a,a)')
     $        'Unknown Minkowski_gauge_wave__what_fn = "',
     $         Minkowski_gauge_wave__what_fn, '"'
C       silence compiler warning about uninitialized H
        H = one
        call CCTK_WARN(0, warn_buffer)
      end if

C     write metric.

      if (Minkowski_gauge_wave__diagonal.ne.0) then

        gdxx =  half * H + half
        gdxy = -half * H + half
        gdyy =  half * H + half

        guxx =  half / H + half
        guxy = -half / H + half
        guyy =  half / H + half

      else

        gdxx = H
        gdxy = zero
        gdyy = one

        guxx = one/H
        guxy = zero
        guyy = one

      end if
      
      gdtt = -H
      gdtx = zero
      gdty = zero
      gdtz = zero

      gdzx = zero
      gdyz = zero
      gdzz = one

C     and upper metric.

      gutt = -one / H
      gutx = zero
      guty = zero
      gutz = zero

      guyz = zero
      guzx = zero
      guzz = one

      return
      end

```

metrics/Schwarzschild_Novikov.F:
```
c     The metric given here corresponds to the novikov solution
c     in isotropic coordinates, as presented first in Bruegman96 
c     then in correct form in Cactus paper 1. This code is the code
c     which was used for the comparisons in cactus paper 1, and is written
c     by PW with input from BB.
C
C Author: unknown
C Copyright/License: unknown
C
C $Header$


#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Schwarzschild_Novikov(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x, y, z, t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL eps, mass
      CCTK_REAL r,c,psi4

      CCTK_REAL nov_dr_drmax, nov_rmax, nov_r
      CCTK_REAL grr, gqq, detg

      CCTK_REAL psi4_o_r2

c constants
      CCTK_REAL zero,one,two
      parameter (zero=0.0d0, one=1.0d0, two=2.0d0)

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

C     Get parameters of the exact solution.

      eps = Schwarzschild_Novikov__epsilon
      mass= Schwarzschild_Novikov__mass

      r = max(sqrt(x**2 + y**2 + z**2), eps)

c     Find r.
      r = sqrt(x**2 + y**2 + z**2)

c     Find conformal factor.
      c = mass/(two*r)
      psi4 = (one + c)**4

c     Evaluate novikov stuff. Note abs(t) since the data is time
c     symmetric (the metric is, at least...)
      grr = nov_dr_drmax(abs(t),abs(r))
      gqq = nov_r(abs(t),abs(r))

      grr = grr **2
      gqq = gqq**2 / nov_rmax(abs(r))**2


c     Find metric components.
      psi4_o_r2 = psi4 / r**2

      gdtt = - 1.0D0

      gdtx = zero
      gdty = zero
      gdtz = zero

c     This is just straightforward spherical -> cartesian I hope... ;-)
c     Note at t=0 (grr = gqq = 1) this gives the expected result
c     (namely diagonal psi^4, since psi4_o_r2 = psi^4 / r^2)
      gdxx = (grr * x**2 + gqq * (y**2 + z**2)) * psi4_o_r2
      gdyy = (grr * y**2 + gqq * (x**2 + z**2)) * psi4_o_r2
      gdzz = (grr * z**2 + gqq * (x**2 + y**2)) * psi4_o_r2
 
      gdxy = (grr - gqq) * x * y * psi4_o_r2
      gdzx = (grr - gqq) * x * z * psi4_o_r2
      gdyz = (grr - gqq) * y * z * psi4_o_r2

c     Find inverse metric.
      gutt = one/gdtt
      gutx = zero
      guty = zero
      gutz = zero
      detg = gdtt*gdxx*gdyy*gdzz-gdtt*gdxx*gdyz**2/4.D0-gdtt*gdxy**2*gdz
     $z/4.D0+gdtt*gdxy*gdzx*gdyz/4.D0-gdtt*gdzx**2*gdyy/4.D0
      guxx = -gdtt*(-4.D0*gdyy*gdzz+gdyz**2)/(4.D0 * detg)
      guxy = -gdtt*(2.D0*gdxy*gdzz-gdzx*gdyz)/(4.D0 * detg)
      guzx = gdtt*(gdxy*gdyz-2.D0*gdzx*gdyy)/(4.D0 * detg)
      guyy = gdtt*(4.D0*gdxx*gdzz-gdzx**2)/(4.D0 * detg)
      guyz = -gdtt*(2.D0*gdxx*gdyz-gdxy*gdzx)/(4.D0 * detg)
      guzz = gdtt*(4.D0*gdxx*gdyy-gdxy**2)/(4.D0 * detg)

      guxx = one/psi4
      guyy = one/psi4
      guzz = one/psi4

      guxy = zero
      guyz = zero
      guzx = zero

      return
      end

c     These are functions which evaluate the novikov stuff.

c     dr/drmax
      CCTK_REAL function nov_dr_drmax(tauin,rbarin)

      implicit none

      CCTK_REAL rbarin, tauin
      CCTK_REAL rt, nov_r, rmaxt, nov_rmax

      rt = nov_r(tauin, rbarin)
      rmaxt = nov_rmax(rbarin)
      nov_dr_drmax = 1.5D0 - rt / (2.0D0 * rmaxt) + 
     $     1.5D0 * sqrt(rmaxt / rt - 1.0D0) *
     $     acos(sqrt(rt/rmaxt))

      return
      end



c
c     Bisection to invert the function below. This is pretty crappy
c     but it works.
c
      CCTK_REAL function nov_r(tauin, rbarin)
      implicit none
c     input
      CCTK_REAL tauin, rbarin

c     funtions
      CCTK_REAL nov_rmax, nov_tau

c     temps
      CCTK_REAL rg, drg, delt, ttmp, rmt
      CCTK_REAL eps
      integer nit
      nit = 0
      delt = 1000.0D0
      rmt = nov_rmax(rbarin)
      rg  = rmt
      drg = rg / 2.0D0
      eps = 1.d-6 * rmt
      do while (delt .gt. eps .and. nit .lt. 100)
         ttmp = nov_tau(rg, rmt)
         delt = abs(tauin - ttmp)
         if (delt .gt. eps) then 
            if (ttmp .gt. tauin .or. rg .lt. drg) then 
               rg = rg + drg
c     Enforce upper bound
               if (rg .gt. rmt) rg = rmt
               drg = drg / 2.0D0
            else
               rg = rg - drg
            endif
         endif
c         write (*,*) rg, ttmp, tauin
         nit = nit + 1
      enddo
      if (nit .ge. 100) then
         write (*,*) "Novikov: inversion did not converge"
      endif
      nov_r = rg
      return
      end

c     Evaluate tau as a function of r and rmax
      CCTK_REAL function nov_tau(r, rmax)
      implicit none
      CCTK_REAL r, rmax

      nov_tau=  rmax * sqrt(0.5D0 * r * (1.0D0 - r / rmax)) +
     $     2.0D0 * (rmax / 2)**(3.0/2.0) *
     $     acos (sqrt(r/rmax))

      return
      end

c     Evaluate rmax as a function of rbar
      CCTK_REAL function nov_rmax(rbar)
      implicit none
      CCTK_REAL rbar
      nov_rmax = (1.0D0 + 2.0D0*rbar)**2 / (4.0D0 * rbar)
      return
      end

```

metrics/Minkowski_funny.F:
```
c     The metric given here corresponds to that of flat spacetime
c     but with non-trivial spatial coordinates.  Basically, I take
c     the flat metric in spherical coordinates, define a new
c     radial coordinate such that:
c
c     r  =  r    ( 1  -  a f(r   ) )
c            new              new
c
c     where f(r) is a gaussian centered at r=0 with amplitude 1.
c     Finally, I transform back to cartesian coordinates.
c     For  0 <= a < 1, the transformation above is monotonic.
C
C Author: unknown
C Copyright/License: unknown
C
c $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Minkowski_funny(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)
      CCTK_DECLARE(CCTK_REAL, t,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $          gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $          gutt, gutx, guty, gutz, 
     $          guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL a,s
      CCTK_REAL r,r2,x2,y2,z2
      CCTK_REAL f,fp,g11,g22
      CCTK_REAL det

c constants
      CCTK_REAL zero, one, two
      parameter (zero=0.0d0, one=1.0d0, two=2.0d0)

c This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

c     Read parameters

      a = Minkowski_funny__amplitude
      s = Minkowski_funny__sigma

c     Find transformation function.

      x2 = x**2
      y2 = y**2
      z2 = z**2

      r2 = x2 + y2 + z2
      r  = sqrt(r2)

      f  = exp(-r2/s**2)
      fp = - two*r/s**2*f

c     Give metric components.

      g11 = (one - a*(f + r*fp))**2
      g22 = (one - a*f)**2

      gdtt = - one
      gdtx = zero
      gdty = zero
      gdtz = zero

      gdxx = (x2*g11 + (y2 + z2)*g22)/r2
      gdyy = (y2*g11 + (x2 + z2)*g22)/r2
      gdzz = (z2*g11 + (x2 + y2)*g22)/r2

      gdxy = x*y*(g11 - g22)/r2
      gdzx = x*z*(g11 - g22)/r2
      gdyz = y*z*(g11 - g22)/r2

c     Find inverse metric.

      gutt = - one
      gutx = zero
      guty = zero
      gutz = zero

      det = gdxx*gdyy*gdzz + two*gdxy*gdzx*gdyz
     .    - gdxx*gdyz**2 - gdyy*gdzx**2 - gdzz*gdxy**2

      guxx = (gdyy*gdzz - gdyz**2)/det
      guyy = (gdxx*gdzz - gdzx**2)/det
      guzz = (gdxx*gdyy - gdxy**2)/det

      guxy = (gdzx*gdyz - gdzz*gdxy)/det
      guyz = (gdxy*gdzx - gdxx*gdyz)/det
      guzx = (gdxy*gdyz - gdyy*gdzx)/det

      return
      end

```

metrics/Bianchi_I.F:
```
C Bianchi-I spacetime !!!! Fake one...
C It is not a real Bianchi I spacetime, it just emulates
C one, taking the two BianchiI functions as harmonic ones...
C
C Author : D. Vulcanov (Timisoara, Romania)
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Bianchi_I(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x, t
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)
     

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL arad
      CCTK_REAL bx, by

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

      arad = Bianchi_I__scale

      bx = arad*sin(x+t)
      by = arad*cos(x+t)
     
      gdtt = - 1.d0
      gdtx = 0.d0
      gdty = 0.d0
      gdtz = 0.d0
      gdxx = bx**2 
      gdyy = by**2 
      gdzz = by**2
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

      gutt = - 1.d0
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = bx**(-2)
      guyy = by**(-2)
      guzz = by**(-2)
      guxy = 0.d0
      guyz = 0.d0 
      guzx = 0.d0

      return
      end

```

metrics/de_Sitter.F:
```
C Einstein-DeSitter metric spacetime !!!!
C It emulates the Robertson-Walker universe
C near t=0, with zero pressure, and k=0
C See :J.N. Islam, An Introduction to 
C Mathematical Cosmology, Cambridge, 1992 and 
C S. Hawking, G.F.R. Ellis, The Large Scale
C Structure of space-time, Cambridge, 1973
C
C Author : D. Vulcanov (Timisoara, Romania)
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__de_Sitter(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)
      CCTK_REAL t

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL arad
      CCTK_REAL am

C This model has a cosmological constant
C ==> it sets the stress-energy tensor in the "CalcTmunu" code
      Tmunu_flag = .true.

      arad = de_Sitter__scale
 
      am=arad*t**(4.0D0/3.0D0)     

      gdtt = -1.0D0 
      gdtx = 0.0D0 
      gdty = 0.0D0
      gdtz = 0.0D0
      gdxx = am
      gdyy = am
      gdzz = am
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

      gutt = -1.d0
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = 1.d0/am
      guyy = 1.d0/am
      guzz = 1.d0/am
      guxy = 0.d0
      guyz = 0.d0
      guzx = 0.d0


      return
      end

```

metrics/Goedel.F:
```
C Goedel spacetime !!!!
C See: S. Hawking, G.F.R. Ellis, The Large
C Scale Structure of space-time, Cambridge, 1973
C
C Author : D. Vulcanov (Timsioara, Romania)
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Goedel(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)
      CCTK_DECLARE(CCTK_REAL, t,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL arad

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

      arad = Goedel__scale
     
      gdtt = -arad*arad
      gdtx = 0.d0
      gdty = 0.d0
      gdtz = 0.d0
      gdxx = (1/2)*arad*arad*exp(x)*exp(x)
      gdyy = -arad*arad
      gdzz =  arad*arad*exp(x)
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = arad*arad*exp(x)

      gutt = -1/(arad*arad)
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = -2/(arad*arad*exp(x)*exp(x))
      guyy = -1/(arad*arad)
      guzz = -1/(arad*arad*exp(x))
      guxy = 0.d0
      guyz = 0.d0 
      guzx = 2/(arad*arad*exp(x))

      return
      end

```

metrics/README:
```
Description of files in this directory
======================================

$Header$

This file contains (typically) one file for each model, containing
a Fortran-callable subroutine to compute the 4-metric $g_{ab}$ and
inverse 4-metric $g^{ab}$:
      subroutine Exact__model_name_coords(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)
      CCTK_REAL x, y, z, t
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_REAL psi
      LOGICAL   Tmunu_flag
	...
      RETURN
      END

 psi  is normally unused, but can be set by the subroutine to explicitly
specify the Cactus static conformal factor.  At present only the
"Minkowski_gauge_wave" model does this

The subroutine should set  Tmunu_flag  to .true. if this model needs
to set the stress-energy tensor (i.e. if it's non-vacuum and/or it has
a cosmological constant, or .false. if it doesn't (i.e. if it's vacuum
and has no cosmological constant).



FIXME: Wouldn't it be cleaner to just compute $g_{ab}$,
       and use a 4x4 matrix inversion to get the other one?

```

metrics/Kasner_like.F:
```
C Kasner-like metric spacetime !!!!
C See: L. Pimentel, Int. Journ. of Theor. Physics,
C, vol. 32, No. 6, 1993, p. 979 (and the references
C cited here), and S. Gotlober, et. al. Early Evolution
C of the Universe and Formation Structure, Akad. Verlag, 1990
C
C Author : D. Vulcanov
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Kasner_like(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL t
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL qq,a1,a3
 
c this model sets the stress-energy tensor in the "CalcTmunu" code
      Tmunu_flag = .true.

      qq = Kasner_like__q

      a1= t**(2.d0*qq)
      a3= t**(2.d0-4.d0*qq)    


      gdtt = -1.d0 
      gdtx = 0.d0 
      gdty = 0.d0
      gdtz = 0.d0
      gdxx = a1 
      gdyy = a1
      gdzz = a3
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

      gutt = -1.d0
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = 1.d0/a1
      guyy = 1.d0/a1
      guzz = 1.d0/a3
      guxy = 0.d0
      guyz = 0.d0
      guzx = 0.d0
 

      return
      end

```

metrics/Kasner_axisymmetric.F:
```
C Axisymmetric Kasner solution !
C
C Author : D. Vulcanov
C see ../../README for copyright & licensing info
C
C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Kasner_axisymmetric(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL t
      CCTK_DECLARE(CCTK_REAL, x,)
      CCTK_DECLARE(CCTK_REAL, y,)
      CCTK_DECLARE(CCTK_REAL, z,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

      gdtt = -t**(-0.5d0) 
      gdtx = 0.d0 
      gdty = 0.d0
      gdtz = 0.d0
      gdxx = t**(-0.5d0)
      gdyy = t
      gdzz = t
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

      gutt = -t**(0.5d0)
      gutx = 0.d0
      guty = 0.d0
      gutz = 0.d0
      guxx = t**(0.5d0)
      guyy = 1.d0/t
      guzz = 1.d0/t
      guxy = 0.d0
      guyz = 0.d0
      guzx = 0.d0
 


      return
      end

```

metrics/make.code.defn:
```
# Main make.code.defn file for thorn Exact
# $Header$

#
# Source files in this directory
# ... if adding new files, please keep this list in the same order as the
#     metrics in this thorn's param.ccl file
#
SRCS = Minkowski.F			\
       Minkowski_funny.F		\
       Minkowski_shift.F		\
       Minkowski_gauge_wave.F		\
       Minkowski_shifted_gauge_wave.F	\
       Minkowski_conf_wave.F		\
					\
       Schwarzschild_EF.F		\
       Schwarzschild_PG.F		\
       Schwarzschild_BL.F		\
       Schwarzschild_Novikov.F	\
       Kerr_BoyerLindquist.F		\
       Kerr_KerrSchild.F		\
       Kerr_KerrSchild_spherical.F	\
       Schwarzschild_Lemaitre.F	\
       multi_BH.F			\
       Thorne_fakebinary.F		\
					\
       Lemaitre.F			\
       de_Sitter.F			\
       de_Sitter_Lambda.F		\
       anti_de_Sitter_Lambda.F	\
       Bianchi_I.F			\
       Goedel.F			\
       Bertotti.F			\
       Kasner_like.F			\
       Kasner_axisymmetric.F		\
       Kasner_generalized.F		\
       Gowdy_wave.F			\
       Milne.F			\
					\
       boost_rotation_symmetric.F	\
       bowl.F				\
       constant_density_star.F

# not fully implemented yet -- see Nina Jansen for details
#      Alvi.F Alvidef.c

```

metrics/Schwarzschild_PG.F:
```
c Schwarzschild spacetime in Painleve [e-acute on last e]-Gullstrand
c coordinates.  These have a *flat* 3-metric, and are described in
c detail in Martel and Poisson, gr-qc/0001069
C
C Author: unknown
C Copyright/License: unknown
C
c $Header$

#include "cctk.h"
#include "cctk_Parameters.h"

      subroutine Exact__Schwarzschild_PG(
     $     x, y, z, t,
     $     gdtt, gdtx, gdty, gdtz, 
     $     gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $     gutt, gutx, guty, gutz, 
     $     guxx, guyy, guzz, guxy, guyz, guzx,
     $     psi, Tmunu_flag)

      implicit none

      DECLARE_CCTK_PARAMETERS

c input arguments
      CCTK_REAL x, y, z
      CCTK_DECLARE(CCTK_REAL, t,)

c output arguments
      CCTK_REAL gdtt, gdtx, gdty, gdtz, 
     $       gdxx, gdyy, gdzz, gdxy, gdyz, gdzx,
     $       gutt, gutx, guty, gutz, 
     $       guxx, guyy, guzz, guxy, guyz, guzx
      CCTK_DECLARE(CCTK_REAL, psi,)
      LOGICAL   Tmunu_flag

c local variables
      CCTK_REAL eps, m
      CCTK_REAL r, bx, by, bz, b2

C This is a vacuum spacetime with no cosmological constant
      Tmunu_flag = .false.

C     Get parameters of the exact solution.

      eps = Schwarzschild_PG__epsilon
      m   = Schwarzschild_PG__mass

      r = max(sqrt(x**2 + y**2 + z**2), eps)
      bx = sqrt(2.d0 * m / r) * x / r
      by = sqrt(2.d0 * m / r) * y / r
      bz = sqrt(2.d0 * m / r) * z / r
      b2 = 2.d0 * m / r

      gdtt = - 1.d0 + b2
      gdtx = bx
      gdty = by
      gdtz = bz
      gdxx = 1.d0 
      gdyy = 1.d0 
      gdzz = 1.d0 
      gdxy = 0.d0
      gdyz = 0.d0
      gdzx = 0.d0

      gutt = - 1.d0
      gutx = bx
      guty = by
      gutz = bz
      guxx = 1.d0 - bx**2
      guyy = 1.d0 - by**2
      guzz = 1.d0 - bz**2
      guxy = - bx * by
      guyz = - by * bz
      guzx = - bz * bx

      return
      end

```


combined_doc_context: ## README (README):
```
Cactus Code Thorn Exact
Authors    : Carsten Gundlach initially, plus many other authors.
Maintainer : Jonathan Thornburg <jthorn@aei.mpg.de>
CVS info   : $Header$
--------------------------------------------------------------------------

Purpose of the thorn
====================

The initial purpose of this thorn was the comparison of numerical
spacetimes against exact solutions.  One particular solution,
the boost-rotation-symmetric spacetimes, was the first application.

Later, the thorn developed as a reservoir for a variety of exact spacetimes,
some of them in different coordinate systems, and even some non-Einstein
spcetimes.  All of these exact spacetimes have been found useful for
testing different aspect of the code.  Since mamy different people have
contributed to this thorn by adding new exact solutions, you should expect
many different styles of coding here.

For more details see the comments in the param.ccl file, and the
documentation in the directory doc.  For instructions on how to add
a new model, see doc/how_to_add_a_new_model.

Note that the June 2002 revisions to this thorn included renaming
most of the parameters.  The perl script  par/convert-par.pl  will
convert old parameter files to use the new names, renaming the old
parameter files to ".par.bak" as backups.


Compilation
===========

On some systems (notably the AEI Xeons using the Intel compilers) this
thorn only compiles if you use the Cactus (perl) preprocessor, i.e. you
need to configure with
   gmake foo-config CPP='$${PERL} $${CCTK_HOME}/lib/sbin/cpp.pl'
(along with any other configuration options), or put the line
      CPP=$${PERL} $${CCTK_HOME}/lib/sbin/cpp.pl
in your ~/.cactus/config or other Cactus options file.

[Note by Erik Schnetter, 2005-05-15: The adivce above is outdated and
incorrect.  This issue is also treated in the Cactus FAQ.  Read it for
more information.]

This thorn is mostly written in Fortran 77, with a few files in C
and Fortran 90.  At present Fortran 90 is only used for the "arbitrary slice"
option (see the thorn guide for details).  If this option isn't needed,
then by changing a single line in  src/include/Exact.inc  (see the comments
there for details) you can #ifdef-out the Fortran 90 code, allowing the
rest of this thorn to be compiled on a system with no Fortran 90 compiler
available.


Copyright
=========

As noted above, this code has been hacked on by many different people,
so its' copyright and licensing status is somewhat unclear.

Here is a (incomplete) list of authors and their wishes:

----------------------------------------

Many of the individual metrics (you can find them by grepping in the
   header comments in the  src/metrics/  directory) are
   copyright (C) 2000-2003 by Dumitru "Mitica" Vulcanov <vulcan@aei.mpg.de>

This code is under the same "GPL with exceptions for other thorns"
license as the Cactus flesh; see the file CACTUS.COPYRIGHT in this
directory for details.

----------------------------------------

The new code added in the June 2002 revisions to this thorn
   is copyright (C) 2001-2002 by Jonathan Thornburg <jthorn@aei.mpg.de>
Minkowski_conf_wave and the conformal factor code added in January 2003
   is copyright (C) 2003 by Frank Loeffler <frank.loeffler@aei.mpg.de>
Option to boost any non-stress-energy-tensor model
   is copyright (C) 2003 by Jonathan Thornburg <jthorn@aei.mpg.de>

This code 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 2 of the License, or
(at your option) any later version.

This code 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 thorn (see the file COPYING in this directory);
if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA  02111-1307  USA

------------------------------------------

```

## Documentation (.tex files):
Files: documentation.tex, KTsol.tex, slice_evolver.tex

```tex
=== documentation.tex ===
% *======================================================================*
%  Cactus Thorn template for ThornGuide documentation
%  Author: Ian Kelley
%  Date: Sun Jun 02, 2002
%  $Header$
%
%  Thorn documentation in the latex file doc/documentation.tex 
%  will be included in ThornGuides built with the Cactus make system.
%  The scripts employed by the make system automatically include 
%  pages about variables, parameters and scheduling parsed from the 
%  relevent thorn CCL files.
%  
%  This template contains guidelines which help to assure that your     
%  documentation will be correctly added to ThornGuides. More 
%  information is available in the Cactus UsersGuide.
%                                                    
%  Guidelines:
%   - Do not change anything before the line
%       % BEGIN CACTUS THORNGUIDE",
%     except for filling in the title, author, date etc. fields.
%        - Each of these fields should only be on ONE line.
%        - Author names should be sparated with a \\ or a comma
%   - You can define your own macros are OK, but they must appear after
%     the BEGIN CACTUS THORNGUIDE line, and do not redefine standard 
%     latex commands.
%   - To avoid name clashes with other thorns, 'labels', 'citations', 
%     'references', and 'image' names should conform to the following 
%     convention:          
%       ARRANGEMENT_THORN_LABEL
%     For example, an image wave.eps in the arrangement CactusWave and 
%     thorn WaveToyC should be renamed to CactusWave_WaveToyC_wave.eps
%   - Graphics should only be included using the graphix package. 
%     More specifically, with the "includegraphics" command. Do
%     not specify any graphic file extensions in your .tex file. This 
%     will allow us (later) to create a PDF version of the ThornGuide
%     via pdflatex. |
%   - References should be included with the latex "bibitem" command. 
%   - use \begin{abstract}...\end{abstract} instead of \abstract{...}
%   - For the benefit of our Perl scripts, and for future extensions, 
%     please use simple latex.     
%
% *======================================================================* 
% 
% Example of including a graphic image:
%    \begin{figure}[ht]
% 	\begin{center}
%    	   \includegraphics[width=6cm]{MyArrangement_MyThorn_MyFigure}
% 	\end{center}
% 	\caption{Illustration of this and that}
% 	\label{MyArrangement_MyThorn_MyLabel}
%    \end{figure}
%
% Example of using a label:
%   \label{MyArrangement_MyThorn_MyLabel}
%
% Example of a citation:
%    \cite{MyArrangement_MyThorn_Author99}
%
% Example of including a reference
%   \bibitem{MyArrangement_MyThorn_Author99}
%   {J. Author, {\em The Title of the Book, Journal, or periodical}, 1 (1999), 
%   1--16. {\tt http://www.nowhere.com/}}
%
% *======================================================================* 

% If you are using CVS use this line to give version information
% $Header$

\documentclass{article}

% Use the Cactus ThornGuide style file
% (Automatically used from Cactus distribution, if you have a 
%  thorn without the Cactus Flesh download this from the Cactus
%  homepage at www.cactuscode.org)
\usepackage{../../../../doc/latex/cactus}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\author{Original code by Carsten Gundlach and Miguel Alcubierre, \\
        exact solutions added by many other people,	\\
	this documentation by Jonathan Thornburg,
        and by other people}

% The title of the document (not necessarily the name of the Thorn)
\title{Thorn Guide for the {\bf Exact} Thorn}

% the date your document was last changed, if your document is in CVS, 
% please us:
%    \date{$ $Date$ $}
\date{$ $Date$ $}

\maketitle

% Do not delete next line
% START CACTUS THORNGUIDE

% Add all definitions used in this documentation here 
%   \def\mydef etc

\def\thorn#1{{\bf #1}}
\def\defn#1{{\bf #1}}

% force a line break in a itemize/description/enumerate environment
\def\forcelinebreak{\mbox{}\\[-\baselineskip]}

\def\eg{e.g.\hbox{}}
\def\ie{i.e.\hbox{}}
\def\etal{{\it et~al.\/\hbox{}}}
\def\nb{n.b.\hbox{}}
\def\Nb{N.b.\hbox{}}

% math stuff
\def\dfrac#1#2{{\displaystyle\frac{#1}{#2}}}
\def\tfrac#1#2{{\textstyle   \frac{#1}{#2}}}
\def\diag{\text{diag}}
\def\Gaussian{{\sf G}}
\def\half{\tfrac{1}{2}}
\def\sech{\text{sech}}

% Add an abstract for this thorn's documentation
\begin{abstract}
This thorn sets up the $3+1$ ADM variables for any of a number
of exact spacetimes/coordinates, and even some non-Einstein
spcetimes/coordinates.  It's easy to add more spacetimes/coordinates:
all you have to supply is the 4-metric $g_{ab}$ and the inverse 4-metric
$g^{ab}$ (this thorn automagically calculates all the ADM variables
from these).  Optionally, any 4-metric can be Lorentz-boosted in any
direction.  As another option, the ADM variables can be calculated on an
arbitrary slice through the spacetime, using arbitrary coordinates on
the slice.  Given a lapse and shift, the slice can be evolved through
the exact solution, in order to check on an evolution code, or in
order to test gauge conditions without the need for an evolution code.
\end{abstract}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Introduction}

This thorn sets up the ADM variables for any of a number of
different spacetimes/coordinates (we call the combination of a
spacetime and a coordinate system a \defn{model}), as specified by the
\verb|Exact::exact_model| parameter.

By default, this thorn sets up the ADM variables on an initial
slice only.  However, setting\\
\verb|ADMBase::evolution_method = "exact"|
makes this thorn set up the ADM variables at \verb|CCTK_PRESTEP|
every time step of an evolution, so you get an exact {\em spacetime\/},
not just a single slice.

There is an option to Lorentz-boost any vacuum model
(more precisely any model which doesn't set the stress-energy tensor;
see table~\ref{AEIThorns/Exact/tab-all-models} and
section~\ref{AEIThorns/Exact/sect-Lorentz-boosting-a-spacetime}
for details) in any direction.

There is also a more general option to set up the ADM variables
on an arbitrary slice through the spacetime, using arbitrary
coordinates on the slice.  Given a lapse and shift computed by some
other thorn(s), the slice can be evolved through the exact solution,
in order to check on an evolution code, or in order to test gauge
conditions without the need for an evolution code.  This option is
documented in \verb|doc/slice_evolver.tex|.

This thorn is mainly written in a mixture of Fortran~77 and Fortran~90;
a few routines are written in C.  At present Fortran~90 is used only
for the ``arbitrary slice'' option (described in the previous paragraph).
If this option isn't needed, then the Fortran~90 code can all be
\verb|#ifdef|-ed out, allowing this thorn to be compiled on a system
having only Fortran~77 and C compilers (\ie{} no Fortran~90 compiler).
This can be done by changing a single line in \verb|src/include/Exact.inc|;
see the comments there for details.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Models Supported}

Table~\ref{AEIThorns/Exact/tab-all-models} shows the models supported
by thorn~\thorn{Exact}.%%%
\footnote{%%%
	 To add a new model, you have to modify a
	 number of files in this thorn.  See the file
	 {\tt how\_to\_add\_a\_new\_model} in the
	 {\tt doc/} directory for a detailed list of
	 what to do.  Please follow the naming conventions
	 given in the next subsection.
	 }%%%
{}  As a general policy, this thorn includes only cases where the full
4-metric $g_{ab}$ (and its inverse, although we could dispense with
that if needed) is known throughout the spacetime.  Cases where this
is only known on one specific slice, should live in separate initial
data thorns.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{table}[htbp]
\begin{center}
\hyphenpenalty=10000	% forbid hyphenation
\begin{tabular}{@{\qquad}lcp{80mm}}
Model Name
	& $T_{\mu\nu}$?
		& Description						\\
\hline %----------------------------------------------------------------
%
\multicolumn{3}{l}{\bf Minkowski spacetime}				\\
{\tt "Minkowski"}
	& --	& Minkowski spacetime					\\
{\tt "Minkowski/shift"}
	& --	& Minkowski spacetime with time-dependent shift vector	\\
{\tt "Minkowski/funny"}
	& --	& Minkowski spacetime in non-trivial spatial coordinates\\
{\tt "Minkowski/gauge wave"}
	& --	& Minkowski spacetime in gauge-wave coordinates		\\
{\tt "Minkowski/shifted gauge wave"}
	& --	& Minkowski spacetime in shifted gauge-wave coordinates	\\
{\tt "Minkowski/conf wave"}
	& --	& Minkowski spacetime with $\sin$ in conformal factor	\\[1ex]
%
\multicolumn{3}{l}{\bf Black hole spacetimes}				\\
{\tt "Schwarzschild/EF"}
	& --	& Schwarzschild spacetime
		  in Eddington-Finkelstein coordinates			\\
{\tt "Schwarzschild/PG"}
	& --	& Schwarzschild spacetime in Painlev\'{e}-Gullstrand
		  coordinates (these have a flat 3-metric)		\\
{\tt "Schwarzschild/BL"}
	& --	& Schwarzschild spacetime in Brill-Lindquist coordinates\\
{\tt "Schwarzschild/Novikov"}
	& --	& Schwarzschild spacetime in Novikov coordinates	\\
{\tt "Kerr/Boyer-Lindquist"}
	& --	& Kerr spacetime in Boyer-Lindquist coordinates		\\
{\tt "Kerr/Kerr-Schild"}
	& --	& Kerr spacetime in Kerr-Schild coordinates		\\
{\tt "Schwarzschild-Lemaitre"}
	& Yes	& Schwarzschild-Lemaitre spacetime (Schwarzschild
		  black hole with a cosmological constant)		\\
{\tt "multi-BH"}
	& --	& Majumdar-Papapetrou or Kastor-Traschen
		  maximally-charged (extreme Reissner-Nordstrom)
		  multi-BH solutions					\\
{\tt "Alvi"}
	& --	& Alvi post-Newtonian 2BH spacetime
		  (not fully implemented yet)				\\
{\tt "Thorne-fakebinary"}
	& --	& Thorne's ``fake binary'' spacetime (non-Einstein)	\\[1ex]
%
\multicolumn{3}{l}{\bf Cosmological spacetimes}				\\
{\tt "Lemaitre"}
	& Yes	& Lemaitre-type spacetime				\\
%%{\tt "Robertson-Walker"}
%%	& Yes	& Robertson-Walker spacetime				\\
{\tt "de Sitter"}
	& Yes	& de~Sitter spacetime					\\
{\tt "de Sitter+Lambda"}
	& Yes	& de~Sitter spacetime with cosmological constant	\\
{\tt "anti-de Sitter+Lambda"}
	& Yes	& anti-de~Sitter spacetime with cosmological constant	\\
{\tt "Bianchi I"}
	& --	& approximate Bianchi type~I spacetime			\\
{\tt "Goedel"}
	& --	& G\"{o}del spacetime					\\
{\tt "Bertotti"}
	& Yes	& Bertotti spacetime					\\
{\tt "Kasner"}
	& Yes	& Kasner-like spacetime					\\
{\tt "Kasner-axisymmetric"}
	& --	& axisymmetric Kasner spacetime				\\
{\tt "Kasner-generalized"}
	& Yes	& generalized Kasner spacetime				\\
{\tt "Gowdy-wave"}
	& --	& Gowdy metric (polarized wave in an expanding universe)\\
{\tt "Milne"}
	& --	& Milne spacetime for pre-big-bang cosmology		\\[1ex]
%
\multicolumn{3}{l}{\bf Miscellaneous spacetimes}			\\
{\tt "boost-rotation symmetric"}
	& --	& boost-rotation symmetric spacetime			\\
{\tt "bowl"}
	& --	& bowl (``bag of gold'') spacetime (non-Einstein)	\\
{\tt "constant density star"}
	& Yes	& constant density (Schwarzschild) star			%%%\\
\end{tabular}
\end{center}
\caption{
	This table shows all the models currently supported by
	thorn \thorn{Exact}.  The $T_{\mu\nu}$ column shows which
	models set the Cactus stress-energy tensor; as discussed in
	section~\ref{AEIThorns/Exact/cosmological-constant+stress-energy-tensor}
	this includes both all non-vacuum models and all models
	with a cosmological constant.
	}
\label{AEIThorns/Exact/tab-all-models}
\end{table}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Naming Conventions}

This thorn includes many different spacetimes and coordinate systems,
so we use the following naming conventions to help keep the different
models and parameters clear:
\begin{itemize}
\item	If we have multiple coordinate systems for a given spacetime,
	the models are named with the pattern
	\hbox{{\tt "}spacetime{\tt /}coordinates{\tt "}}.
	For example, the model \verb|"Schwarzschild/EF"| is Schwarzschild
	spacetime in Eddington-Finkelstein coordinates.%%%
\footnote{%%%
	 We abbreviate the coordinate names both for
	 convenience, and because the unabbreviated
	 names would make the variable names in the
	 code (which are the same as the parameter names)
	 too long -- C only guarantees 31~characters for
	 variable names, and the Fortran~95 standard
	 explicitly limits variable names to this same
	 maximum length.
	 }%%%
\item	If we have spacetimes which are identical or very similar,
	except that one has a cosmological constant and the other
	doesn't, we name the with-cosmological-constant one by appending
	\verb|+Lambda| to the without-cosmological-constant spacetime
	name.  For example, the cosmological-constant variant of
	anti-de Sitter spacetime is the model \verb|"anti-de Sitter+Lambda"|.
\item	All the parameters for individual models have names which begin
	with the model name (with any slash (\verb|/|) or hyphen (\verb|-|)
	characters converted to underscores (\verb|_|)), followed by
	a double underscore (\verb|__|).
\item	The description comment for each parameter in the \verb|param.ccl|
	file begins with the model name follwed by a colon (\verb|:|).
	For example,
\begin{verbatim}
REAL Schwarzschild_EF__mass "Schwarzschild/EF: BH mass"
{
*:* :: "any real number"
} 1.0
\end{verbatim}
\end{itemize}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{The Cosmological Constant and the Stress-Energy Tensor}
\label{AEIThorns/Exact/cosmological-constant+stress-energy-tensor}

A number of these models have a cosmological constant.  To use these
with the Cactus code (which generally is written for the case of no
cosmological constant), we use a simple trick: we transfer the term
with the cosmological constant to the right hand side of the Einstein
equations, introducing fictitious ``matter'' terms in the stress-energy 
tensor.

This thorn uses the standard Cactus ``\verb|CalcTmunu|'' interface
for introducing terms into the stress-energy tensor.  See Ian Hawke's
documentation for the \thorn{ADMCoupling} thorn for details.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Accuracy}

\begingroup
\bf\mathversion{bold}
This thorn has been found to set up its initial data less accurately
than you might think.  In particular, \dots

Denis Pollney has found that if this thorn is used to set up a
Schwarzschild or Kerr solution
(\verb|Schwarzschild/EF| or \verb|Kerr/Kerr-Schild| model),
there are low-level ($\sim 10^{-12}$) asymmetries between the
field variables in the supposedly-symmetric octants.

Jonathan Thornburg has found that for at least the \verb|Schwarzschild/EF|
and \verb|Kerr/Kerr-Schild| models (and quite likely for all models),
this thorn's values of the extrinsic curvature $K_{ij}$ have random
point-to-point errors of about $\sim {\textstyle\frac{1}{2}} \times 10^{-10}$
(in regions where the metric is $O(1)$.
\endgroup

We suspect that these problems may be due to this thorn's internally
first setting up the 4-metric, then computing the Bona-Masso variables
by numerically finite differencing the 4-metric%%%
\footnote{%%%
	 This seems to be done using centered
	 2nd~order finite differencing with a
	 hard-wired $10^{-6}$ grid spacing.
	 }%%%
, then computing the ADM variables from this.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Time Levels}

In the context of Cactus grid functions with (potentially) multiple
time levels,
\textbf{this thorn only sets the initial data on the current time level!}.
This is a bug. :(

If you're doing a time evolution using the standard Cactus \thorn{MoL}
thorn,
\begin{itemize}
\item	Variables that you're going to \emph{evolve}
	(for example the ADM 3-metric if you're evolving
	it directly) only need initial data to be set
	on the current time level.
\item	Other variables that are used by the evolution system,
	but aren't themselves evolved (for example the ADM 3-metric
	if you're evolving some other fields on a fixed background)
	must have initial data set on \emph{all} time levels.
	\thorn{MoL} calls these ``save-and-restore'' variables.
\end{itemize}

\thorn{MoL} offers a useful option to help work around problems
of this sort (only the current time level is set, when you need
all time levels):  If you set
\begin{verbatim}
MoL::initial_data_is_crap = true
\end{verbatim}
then \thorn{MoL} will copy the current time level to all other time
levels, for all grid functions that are registered as ``evolved'',
``save-and-restore'', and/or ``constrained'' variables.  This happens
in the \verb|POSTINITIAL| schedule bin.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Further Sources of Information}

This documentation is at best a secondary source of information about
this thorn -- the primary sources are the \verb|param.ccl| file and
the source code itself.  In particular, much of this documentation
was developed by reverse-engineering from these primary sources, so
it's quite possible (indeed even likely!) that there are errors or
omissions here.  Caveat Lector!

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Lorentz-Boosting a Spacetime}
\label{AEIThorns/Exact/sect-Lorentz-boosting-a-spacetime}

For any of the models which don't set the stress-energy tensor
(\ie{} which are vacuum and have no cosmological constant;
see section~\ref{AEIThorns/Exact/cosmological-constant+stress-energy-tensor}
and table~\ref{AEIThorns/Exact/tab-all-models} for details),%%%
\footnote{%%%
	 Only $g_{ab}$ and $g^{ab}$ are transformed, not the
	 stress-energy tensor, which is why this only works
	 for models which don't set the stress-energy tensor.
	 }%%%
{} you can optionally Lorentz-boost the model by a specified 3-velocity
$v^i$.  The parameters for this are \verb|boost_vx|, \verb|boost_vy|,
and \verb|boost_vz|.

We define the Cactus spacetime coordinates to be $(t,x^i)$,
while the model is at rest in coordinates $(T,X^i)$.  The model's
``origin'' $X^i = 0$ is located at the Cactus coordinates $x^i = v^i t$.  

The boost Lorentz transformation is defined by
\begin{equation}
\renewcommand{\arraystretch}{1.333}
\begin{array}{lcl}
T		& = &	\gamma (t - \eta_{ij} v^i x^j)		\\
X^i_\parallel	& = &	\gamma (x^i_\parallel - v^i t)		\\
X^i_\perp	& = &	x^i_\perp				%%%\\
\end{array}
\end{equation}
and the inverse transformation by
\begin{equation}
\renewcommand{\arraystretch}{1.333}
\begin{array}{lcl}
t		& = &	\gamma (T + \eta_{ij} v^i X^j)		\\
x^i_\parallel	& = &	\gamma (X^i_\parallel + v^i T)		\\
x^i_\perp	& = &	X^i_\perp				%%%\\
\end{array}
\end{equation}
where $\gamma \equiv (1 - v^2)^{-1/2}$ is the usual Lorentz factor,
$\eta_{ij}$ is the flat metric, and $\parallel$ and $\perp$ refer
to the (flat-space) components of $x^i$ parallel and perpendicular
to $v^i$, respectively.

In more detail, define the unit vector $n^i = v^i / \sqrt{\eta_{jk} v^j v^k}$
and the (flat-space) projection operators
\begin{equation}
\renewcommand{\arraystretch}{1.333}
\begin{array}{lclcl}
\parallel^i{}\!_j
		& = &	\eta_{jk} n^i n^k				\\
		& \equiv &
			n^i n_j
			\qquad
			\hbox{(using $\eta_{ij}$ to raise/lower indices)}
									\\
\perp^i{}\!_j	& = &	\delta^i{}_j - \parallel^i{}\!_j		%%%\\
\end{array}
\end{equation}
Then the Lorentz transformations are
\begin{equation}
\renewcommand{\arraystretch}{1.333}
\begin{array}{lcl}
T	& = &	\gamma (t - \eta_{ij} v^i x^j)				\\
X^i	& = &	\gamma (\parallel^i{}\!_j x^j - v^i t)
		+ \perp^i{}\!_j x^j					%%%\\
\end{array}
\end{equation}
and
\begin{equation}
\renewcommand{\arraystretch}{1.333}
\begin{array}{lcl}
t	& = &	\gamma (T + \eta_{ij} v^i X^j)				\\
x	& = &	\gamma (\parallel^i{}\!_j X^j + v^i T)
		+ \perp^i{}\!_j X^j					%%%\\
\end{array}
\end{equation}
so their coordinate partial derivatives for transforming $g_{ab}$
and $g^{ab}$ are
\begin{equation}
\renewcommand{\arraystretch}{2.5}
\begin{array}{lcl@{\qquad\qquad\qquad}lcl}
\dfrac{\partial T}{\partial t}		& = &	\gamma
	&
\dfrac{\partial T}{\partial x^j}	& = &	- \gamma v^j		\\
\dfrac{\partial X^i}{\partial t}	& = &	- \gamma v^i
	&
\dfrac{\partial X^i}{\partial x^j}	& = &	\gamma \parallel^i{}\!_j
						+ \perp^i{}\!_j		%%%\\
\end{array}
\end{equation}
and
\begin{equation}
\renewcommand{\arraystretch}{2.5}
\begin{array}{lcl@{\qquad\qquad\qquad}lcl}
\dfrac{\partial t}{\partial T}		& = &	\gamma
	&
\dfrac{\partial t}{\partial X^j}	& = &	\gamma v^j		\\
\dfrac{\partial x^i}{\partial T}	& = &	\gamma v^i
	&
\dfrac{\partial x^i}{\partial X^j}	& = &	\gamma \parallel^i{}\!_j
						+ \perp^i{}\!_j		%%%\\
\end{array}
\end{equation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Minkowski Spacetime}

This thorn can set up Minkowski spacetime using several different
types of coordinates:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Minkowski Spacetime}

\verb|Exact::exact_model = "Minkowski"| specifies Minkowski spacetime
in the usual Minkowski coordinates:
\begin{equation}
g_{ab} = \diag \left[
	 \begin{array}{cccc}
	 -1	& 1	& 1	& 1	%%%\\
	 \end{array}
	 \right]
\end{equation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Minkowski Spacetime in Non-Trivial Spatial coordinates}

\verb|Exact::exact_model = "Minkowski/funny"| specifies Minkowski spacetime
with the usual Minkowski time slicing, but using the nontrivial spatial
coordinates defined as follows:  First take the flat metric in polar
spherical coordinates, then define a new radial coordinate by
\begin{equation}
r = r_{\text{w}} \big(1 - a \Gaussian(r_{\text{w}})\big)
\end{equation}
where 
$\Gaussian(r) = \exp(-\half r^2/\sigma^2)$ is a Gaussian centered at $r=0$.

The parameters are the perturbation amplitude
$a = \verb|Exact::Minkowski_funny__amplitude|$
and the perturbation width $\sigma = \verb|Exact::Minkowski_funny__sigma|$.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Minkowski Spacetime in Non-Trivial Slices with Shift}

\verb|Exact::exact_model = "Minkowski/shift"| specifies Minkowski spacetime
with the nontrivial time slicing and spatial coordinates defined as
follows:  First take the flat 4-metric in polar spherical coordinates,
then define a new time coordinate by
\begin{equation}
t_{\text{w}} = t - a \Gaussian(r)
\end{equation}
$\Gaussian(r) = \exp(-\half r^2/\sigma^2)$ is a Gaussian centered at $r=0$.
Note this gives a time-indpendent 4-metric.

The parameters are the perturbation amplitude
$a = \verb|Exact::Minkowski_shift__amplitude|$
and the perturbation width $\sigma = \verb|Exact::Minkowski_shift__sigma|$.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Minkowski Spacetime in gauge-wave coordinates}

\verb|Exact::exact_model = "Minkowski/gauge wave"| specifies Minkowski
spacetime with the ``gauge-wave'' coordinates suggested by Carlos Bona:
The line element is
\begin{equation}
ds^2=-H dt^2 +Hdx^2+dy^2+dz^2,
\end{equation}
where $H=H(x-t)$, for instance $H=1-A\sin\left((x-t)/\Lambda\right)$.
This is a flat spacetime, but the slice is a planar wave travelling
along the x axis.

This thorn implements several possible choices for the $H$ function,
controlled by the \verb|Minkowski_gauge_wave__what_fn| parameter:
\begin{eqnarray}
H(x-t)	&=& 1 - A \sin \left(\frac{x-\omega t}{\Lambda} - \delta\right)	\\
H(x-t)	&=& \exp \left(- A \sin \left(\frac{x-\omega t}{\Lambda}
                                      - \delta\right)\right)		\\
H(x-t)	&=& 1 - A \exp(-x^2)						%%%\\
\end{eqnarray}
The parameters are
\begin{itemize}
\item	$A = \verb|Minkowski_gauge_wave__amplitude|$, the amplitude
\item	$\omega = \verb|Minkowski_gauge_wave__omega|$, the angular frequency
\item	$\lambda = \verb|Minkowski_gauge_wave__lambda|$, the wavelength
\item	$\delta = \verb|Minkowski_gauge_wave__phase|$, the phase shift
\end{itemize}
A plane wave has $\omega = \pm \lambda$ for a wave that travels in the
$x$ direction, and $\omega = \pm \lambda \sqrt{2}$ for a diagonal wave.

If the Boolean parameter \verb|Minkowski_gauge_wave__diagonal| is true,
then we make the gauge wave travel diagonally across the grid by the
coordinate transformation
\begin{eqnarray}
x &=& \frac{1}{\sqrt{2}}(x^\prime - y^\prime)				\\
y &=& \frac{1}{\sqrt{2}}(x^\prime + y^\prime)				%%%\\
\end{eqnarray}
For code testing, the idea is to test evolving this with periodic boundary
conditions, to see whether the code is able to cope with that.
The tricky part is to make the wave fit the grid exactly (otherwise the
periodic boundary wouldn't make sence), especially in the diagonal case.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Minkowski Spacetime in shifted gauge-wave coordinates}

\verb|Exact::exact_model = "Minkowski/shifted gauge wave"| specifies Minkowski
spacetime with the ``shifted gauge-wave'' coordinates suggested by
Jeff Winicour:
The line element is
\begin{equation}
ds^2 = (H-1)\, dt^2 + (H+1)\, dx^2 - 2H\, dt\, dx + dy^2 + dz^2
\end{equation}
where $H=H(x-t)$, for instance $H=A\sin\left((x-t)/\Lambda\right)$.
This is a flat spacetime, but the slice is a planar wave travelling
along the x axis.

This thorn implements one choice for the $H$ function, controlled by
the \verb|Minkowski_gauge_wave__what_fn| parameter:
\begin{eqnarray}
H(x-t)	&=& 1 - A \sin \left(\frac{x-\omega t}{\Lambda} - \delta\right)
\end{eqnarray}

The parameters are
\begin{itemize}
\item	$A = \verb|Minkowski_gauge_wave__amplitude|$, the amplitude
\item	$\omega = \verb|Minkowski_gauge_wave__omega|$, the angular frequency
\item	$\lambda = \verb|Minkowski_gauge_wave__lambda|$, the wavelength
\item	$\delta = \verb|Minkowski_gauge_wave__phase|$, the phase shift
\end{itemize}
A plane wave has $\omega = \pm \lambda$ for a wave that travels in the
$x$ direction, and $\omega = \pm \lambda \sqrt{2}$ for a diagonal
wave.

If the Boolean parameter \verb|Minkowski_gauge_wave__diagonal| is
true, then we make the gauge wave travel diagonally across the grid by
the coordinate transformation
\begin{eqnarray}
x &=& \frac{1}{\sqrt{2}}(x^\prime - y^\prime)				\\
y &=& \frac{1}{\sqrt{2}}(x^\prime + y^\prime)				%%%\\
\end{eqnarray}
For code testing, the idea is to test evolving this with periodic
boundary conditions, to see whether the code is able to cope with
that.  The tricky part is to make the wave fit the grid exactly
(otherwise the periodic boundary wouldn't make sence), especially in
the diagonal case.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Minkowski Spacetime with $\sin$ term in conformal factor}

\verb|Exact::exact_model = "Minkowski/conf wave"| specifies Minkowski
spacetime with a $\sin$~term in the Cactus static conformal factor.
You have three parameters:
\begin{itemize}
 \item Minkowski\_conf\_wave\_\_amplitude ($a$)
 \item Minkowski\_conf\_wave\_\_wavelength ($l$)
 \item Minkowski\_conf\_wave\_\_direction ($d$)
\end{itemize}
These control $\Psi$ in the following form:
\begin{equation}
 \Psi=a\sin\left(\frac{2\pi}{l}D\right)+1
\end{equation}
Here $D$ is x, y or z according to d of 0, 1 or 2.

Alas, the ``arbitrary slice evolver'' option
(documented in \verb|doc/slice_evolver.tex|)
doesn't work with this model.  There's no warning,
you'll just silently get wrong results.  Sigh\dots

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Black Hole Spacetimes}

This thorn can set up Schwarzschild and Kerr spacetimes in several
different types of coordinates, and also a couple of multiple-black-hole
spacetimes:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Schwarzschild Spacetime in Eddington-Finkelstein coordinates}

\verb|Exact::exact_model = "Schwarzschild/EF"| specifies Schwarzschild
spacetime in (ingoing) Eddington-Finkelstein coordinates, as described
in MTW box~31.2 and figure~32.1.  The only physics parameter is
the black hole mass $m = \verb|Schwarzschild_EF__mass|$.

There is also a numerical parameter \verb|Schwarzschild_EF__epsilon|
which is used to avoid division by zero if a grid point falls exactly
at the origin; the default setting should be ok for most purposes.

In the usual polar spherical $(t,r,\theta,\phi)$ coordinates, the 4-metric
and ADM variables are
\begin{eqnarray}
g_{ab}	& = &
	\left[
	 \begin{array}{cccc}
	 - \left( 1 - \frac{2m}{r} \right)
			& \frac{2m}{r}	& 0	& 0	\\
	 \frac{2m}{r}	& 1 + \frac{2m}{r}
					& 0	& 0	\\
	 0		& 0		& r^2	& 0	\\
	 0		& 0		& 0	& r^2 \sin^2 \theta
							%%%\\
	 \end{array}
	 \right]
									\\
g_{ij}	& = &
	\diag
	\left[
	\begin{array}{ccc}
	1 + \frac{2m}{r}	& r^2	& r^2 \sin^2 \theta	%%%\\
	\end{array}
	\right]
									\\
K_{ij}	& = &
	\diag
	\left[
	\begin{array}{ccc}
	- \frac{2m^2}{r^2} \frac {1 + \frac{m}{r}} {\sqrt{1 + \frac{2m}{r}}}
				& \frac{2m^2}{\sqrt{1 + \frac{2m}{r}}}
					& \frac{2m^2}{\sqrt{1 + \frac{2m}{r}}}
					  \sin^2 \theta		%%%\\
	\end{array}
	\right]
									\\
\alpha	& = &
	\frac{1}{\sqrt{1 + \frac{2m}{r}}}
									\\
\beta^i	& = &
	\left[
	\begin{array}{ccc}
	\frac{2m}{r} \frac{1}{\sqrt{1 + \frac{2m}{r}}}
				& 0	& 0			%%%\\
	\end{array}
	\right]
									%%%\\
\end{eqnarray}
(Various other $3+1$ variables for Schwarzschild spacetime in these
coordinates are tabulated in appendix~2 of Jonathan Thornburg's Ph.D
thesis, \verb|http://www.aei.mpg.de/~jthorn/phd/html/phd.html|.)

In the Cactus $(t,x,y,z)$ Cartesian-topology coordinates the 4-metric is
\begin{equation}
g_{ab} = \left[
	 \begin{array}{cccc}
	 - \left( 1 - \frac{2m}{r} \right)
			& \frac{2m}{r} \frac{x}{r}
				& \frac{2m}{r} \frac{y}{r}
					& \frac{2m}{r} \frac{z}{r}	\\
	 \frac{2m}{r} \frac{x}{r}
			& 1 + \frac{2m}{r} \frac{x^2}{r^2}
				& \frac{2m}{r} \frac{xy}{r^2}
					& \frac{2m}{r} \frac{xz}{r^2}	\\
	 \frac{2m}{r} \frac{y}{r}
			& \frac{2m}{r} \frac{xy}{r^2}
				& 1 + \frac{2m}{r} \frac{y^2}{r^2}
					& \frac{2m}{r} \frac{yz}{r^2}	\\
	 \frac{2m}{r} \frac{z}{r}
			& \frac{2m}{r} \frac{xz}{r^2}
				& \frac{2m}{r} \frac{yz}{r^2}
					& 1 + \frac{2m}{r} \frac{z^2}{r^2}
									%%%\\
	 \end{array}
	 \right]
\end{equation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Schwarzschild spacetime in Painlev\'{e}-Gullstrand coordinates}

\verb|Exact::exact_model = "Schwarzschild/PG"| specifies Schwarzschild
spacetime in Painlev\'{e}-Gullstrand coordinates, as described by
Martel and Poisson, gr-qc/0001069.  These coordinates have the
interesting property that the spatial metric is {\em flat\/}.
The only physics parameter is the black hole mass
$m = \verb|Schwarzschild_PG__mass|$.

There is also a numerical parameter \verb|Schwarzschild_PG__epsilon|
which is used to avoid division by zero if a grid point falls exactly
at the origin; the default setting should be ok for most purposes.

In the usual Cactus $(t,x,y,z)$ Cartesian-topology coordinates, the
4-metric is
\begin{equation}
g_{ab} = \left[
	 \begin{array}{cccc}
	 -1 + \frac{2m}{r}
		& \sqrt{\frac{2m}{r}} \frac{x}{r}
			& \sqrt{\frac{2m}{r}} \frac{y}{r}
				& \sqrt{\frac{2m}{r}} \frac{z}{r}
									\\
	 \sqrt{\frac{2m}{r}} \frac{x}{r}
		& 1	& 0	& 0					\\
	 \sqrt{\frac{2m}{r}} \frac{y}{r}
		& 0	& 1	& 0					\\
	 \sqrt{\frac{2m}{r}} \frac{z}{r}
		& 0	& 0	& 1					%%%\\
	 \end{array}
	 \right]
\end{equation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Schwarzschild spacetime in Brill--Lindquist coordinates}

\verb|Exact::exact_model = "Schwarzschild/BL"| specifies Schwarzschild
spacetime in Brill--Lindquist coordinates.  These coordinates have the
interesting property that the spatial metric is conformally flat and
time-symmetric for the initial data.  The only physics parameter is
the black hole mass $m = \verb|Schwarzschild_BL__mass|$.

There is also a numerical parameter \verb|Schwarzschild_BL__epsilon|
which is used to avoid division by zero if a grid point falls exactly
at the origin; the default setting should be ok for most purposes.

In the usual Cactus $(t,x,y,z)$ Cartesian-topology coordinates, the
4-metric is given by
\begin{eqnarray}
   \alpha & = & 1
\\
   \beta^i & = & 0
\\
   \gamma_{ij} & = & \Psi^4\, \delta_{ij}
\end{eqnarray}
with the conformal factor
\begin{eqnarray}
   \Psi & = & 1 + \frac{m}{2r}
\end{eqnarray}
where $r$ is the coordinate radius.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Schwarzschild Spacetime in Novikov coordinates}

\verb|Exact::exact_model = "Novikov"| specifies the unit-mass Schwarzschild
spacetime in Novikov coordinates, as described in gr-qc/9608050
(see also MTW section~31.4 and figure~31.2).
The only physics parameter is the black hole mass
$m = \verb|Schwarzschild_Novikov__mass|$.

There is also a numerical parameter \verb|Schwarzschild_Novikov__epsilon|
which is used to avoid division by zero if a grid point falls exactly
at the origin; the default setting should be ok for most purposes.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Kerr Spacetime in Boyer-Lindquist coordinates}

\verb|Exact::exact_model = "Kerr/Boyer-Lindquist"| specifies Kerr
spacetime in (cartesian) Boyer-Lindquist coordinates, as described
in MTW box~33.2 (the spin axis is the $z$~axis).  The physics parameters
are the black hole mass $m = \verb|Kerr_BoyerLindquist__mass|$, and the
dimensionless spin parameter $a = J/m^2 = \verb|Kerr_BoyerLindquist__spin|$.

Mitica Vulcanov says: this metric still need some work in order to
run properly. Major problems: the convergence and calibration of the
units for the parameters and variables.  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Kerr-Schild form of Boosted Rotating Black Hole}

\verb|Exact::exact_model = "Kerr/Kerr-Schild"| specifies Kerr spacetime
in Kerr-Schild coordinates, as described in MTW exercise~33.8 (the spin
axis is the $z$~axis), Lorentz boosted in the $z$ direction so the
black hole is centered at the position $z = vt$.  The physics parameters
are the black hole mass $m = \verb|Kerr_KerrSchild__mass|$, the
dimensionless spin parameter $a = J/m^2 = \verb|Kerr_KerrSchild__spin|$,
and the boost velocity $v = \verb|Kerr_KerrSchild__boost_v|$.

There is also a numerical parameter \verb|Kerr_KerrSchild__epsilon|
which is used to avoid division by zero if a grid point falls exactly
at the black hole center; the default setting should be ok for most
purposes.

Kerr-Schild coordinates use the same time slicing (\nb{} non-maximal!)
and $z$~spatial coordinate as Kerr coordinates $(x_K, y_K, z_K)$, but
define new spatial coordinates $x \equiv x_{KS}$ and~$y \equiv y_{KS}$
by
\begin{equation}
x_{KS} + iy_{KS} = (r + ia) e^{i\phi} \sin\theta
\end{equation}
so that
\begin{eqnarray}
x_{KS}	& = & x_K - a \sin\theta \sin\phi				\\
y_{KS}	& = & y_K + a \sin\theta \cos\phi				%%%\\
\end{eqnarray}

In Kerr-Schild coordinates the 4-metric can be written
\begin{equation}
g_{ab} = \eta_{ab} + 2 H k_a k_b
\end{equation}
where
\begin{equation}
H = \frac{mr}{r^2 + a^2z^2/r^2}
\end{equation}
and where
\begin{equation}
k^a = - \frac{r(x\,dx + y\,dy) - a(x\,dy - y\,dx)}{r^2 + a^2}
      - \frac{z\,dz}{r}
      - dt
\end{equation}
is a null vector.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Schwarzschild-Lemaitre spacetime
	    (Schwarzschild black hole with cosmological constant}

\verb|Exact::exact_model = "Schwarzschild/Lemaitre"|%%%
is a metric proposed by Lemaitre in 1932 as a version of the
Schwarzschild solution in a universe with cosmological constant.
For a history of this metric and a good review see the chapter of
Jean Eisenstaedt, ``Lemaitre and the Schwarzschild solution'' in the
book ``The attraction of Gravitation: New Studies in the History of
General Relativity'', by J.~Earman, et.al.  Birk\"{a}user, 1993.
The line element is 
\begin{equation}
ds^2 = - \left( 1-\frac{2m}{r} - \frac{\Lambda}{3}r^2\right) \, dt^2
       + \left( 1-\frac{2m}{r} -\frac{\Lambda}{3}r^2 \right)^{-1} \, dr^2
       + r^2 \, d\theta^2
       + r^2 \sin(\theta)^2 \, d\phi^2
\end{equation}
Notice that for $\Lambda = 0$ this reduces to Schwarzschild spacetime
in the usual Schwarzschild coordinates.

The physics parameters are the black hole mass
$m = \verb|Schwarzschild_Lemaitre__mass|$, and the
cosmological constant $\Lambda = \verb|Schwarzschild_Lemaitre__Lambda|$.

The fictitious ``matter'' stress-energy tensor representing $\Lambda$ is
\begin{equation}
T_{ij}= - \frac{\Lambda}{8 \pi} g_{ij}
      = \left(
	\begin{array}{cccc}
	-\frac{1}{24}\frac{\Lambda A}{r\pi} & 0 & 0 & 0\\
	0 & \frac{3}{8}\frac{r\Lambda}{8\pi A }& 0 & 0\\
	0 & 0 &-\frac{1}{8}\frac{\Lambda r^2}{\pi }&  0\\
	0 & 0 & 0 & -\frac{1}{8}\frac{\Lambda r^2 \sin(\theta)^2}{\pi}
	\end{array}
	\right)
\end{equation}
where $A = (-3r +6m+\Lambda r^3)$.

Alas, this metric doesn't seem to give proper finite difference
convergence for $\Lambda \ne 0$.  It works fine for $\Lambda = 0$.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Majumdar-Papapetrou or Kastor-Traschen
	    Maximally-Charged (extreme Reissner-Nordstrom) multi-BH Solutions}

\verb|Exact::exact_model = "multi-BH"| specifies the Majumdar-Papapetrou
or Kastor-Traschen solution.  The file \verb|KTsol.tex| in the
documentation directory of this thorn gives more details/references
about these solutions.

The Majumdar-Papapetrou solution is a multi-black-hole static solution
to Einstein's equation, containing $N$ maximally charged ($Q=M$, \ie{}
extreme Reissner-Nordstrom) black holes.  The balance between
gravitational attraction and electrostatic repulsion among the
black holes causes each to maintain its position relative to the
others eternally, so the spacetime is static.  (The Majumdar-Papapetrou
solution somewhat resembles Brill-Lindquist initial data, but with the
black holes being charged.)  The line element is
\begin{equation}
ds^2=-\frac{1}{\Omega^2} dt^2+ \Omega^2(dx^2+dy^2+dz^2)
\end{equation}
where
\begin{eqnarray}
\Omega	&=& 1+\sum_{i=1}^N \frac{M_i}{r_i}				\\
r_i	&=& \sqrt{(x-x_i)^2+(y-y_i)^2+(z-z_i)^2}				%%%\\
\end{eqnarray}
where $M_i$ and $(x_i, y_i, z_i) \in \Re^3$ are the masses and
locations of the individual black holes.

The Kastor-Traschen solution is a cosmological generalization of the
Majumdar-Papapetrou solution, where there is a cosmological constant
and the black holes participate in an overall De~Sitter expansion or
contraction.  For $\Lambda = 0$ the Kastor-Traschen solution reduces
to the Majumdar-Papapetrou solution.

The Kastor-Traschen line element is
\begin{equation}
ds^2=-\frac{1}{\Omega^2} dt^2+a(t)^2 \Omega^2(dx^2+dy^2+dz^2)
\end{equation}
where
\begin{eqnarray}
\Omega	&=& 1+\sum_{i=1}^N {\frac{M_i}{a r_i}}				\\
a	&=& e^{Ht}							\\
H	&=& \pm \sqrt{\frac{\Lambda}{3}}				\\
r_i	&=& \sqrt{(x-x_i)^2 + (y-y_i)^2 + (z-z_i)^2}			%%%\\
\end{eqnarray}
This solution represents ``incoming'' (``outgoing'') charged BHs
if $H < 0$ ($H > 0$).  We interpret $M_i$ as the mass of the
$i{\rm th}$ black hole, although we have neither an asymptotically
flat region nor event horizons available to convert this naive
interpretation into a rigorous one.

This thorn supports up to 4~black holes.  The physics parameters are
the number of black holes $N = \verb|multi_BH__nBH|$ and the Hubble constant
$H = \verb|multi_BH__Hubble|$, and then for each black hole $i = 1, \dots, N$,
the mass $m_i = \verb|multi_BH__mass|\,i$ and the $x$, $y$, and $z$ positions
$x_i = \verb|multi_BH__x|\,i$, $y_i = \verb|multi_BH__y|\,i$,
and $z_i = \verb|multi_BH__z|\,i$ respectively.

Note that this thorn does {\bf not} set $T_{\mu\nu}$.
{\bf FIXME: does treating this metric as vacuum still give a solution
to the Einstein equations?}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Alvi post-Newtonian 2BH spacetime (not fully implemented yet)}

\verb|Exact::exact_model = "Alvi"| specifies the Alvi post-Newtonian
binary black hole metric, as described in gr-qc/9912113.  This
uses different approxamintion methods to describe different regions
of a binary black hole system: Near the holes, one uses a distorted
Schwarzschild black hole metric, while in the region around them
(divided into a near zone and a wave zone) one uses a 1st~order
post-Newtonian approximation. There are discontinuities at the
boundaries between the zones. 

This model has physics parameters giving the masses of the two black
holes, $m_1 = \verb|Alvi__mass1|$ and $m_2 = \verb|Alvi__mass2|$, and
their spatial separation $b = \verb|Alvi__separation|$.

Unfortunately, this metric isn't fully implemented yet.
See Nina Jansen for details.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Thorne's ``Fake Binary'' Approximate Spacetime}

\verb|Exact::exact_model = "fakebinary"| specifies Thorne's ``fake binary''
approximate binary-black-hole spacetime, as described in gr-qc/9808024.
This is not an exact solution of the Einstein equations, but has
qualitative features designed to mimic those of an inspiralling
binary black hole spacetime.  The physics parameters are:
\begin{itemize}
\item	$m = \verb|Thorne_fakebinary__mass|$, the mass\\
	(FIXME: is this the mass of the whole spacetime,
	or of an individual BH?)
\item	$a_0 = \verb|Thorne_fakebinary__separation|$, the initial binary
	separation
\item	$\Omega_0 = \verb|Thorne_fakebinary__Omega0|$, the initial
	angular frequency of the binary orbit
\item	\verb|Thorne_fakebinary__retarded|, a Boolean parameter which
	controls whether or not to use a retarded time coordinate
\item	\verb|Thorne_fakebinary__atype|, a keyword parameter to
	select a constant (\verb|"constant"|)
	or quadrupole (\verb|"quadrupole"|) solution
\item	\verb|Thorne_fakebinary__smoothing|, a smoothing length for
	the Newtonian potential
\end{itemize}

There is also a numerical parameter \verb|Thorne_fakebinary__epsilon|
which is used to avoid division by zero if a grid point falls exactly
at either black hole's center; the default setting should be ok for
most purposes.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Cosmological Spacetimes}

The code for most of these models was written by
Mitica Vulcanov \verb|<vulcan@aei.mpg.de>|.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Lemaitre-type spacetime}

\verb|Exact::exact_model="Lemaitre"| specifies a Lemairre spacetime,
version of the Friedmann-Robertson-Walker model with flat space
(\ie{} $k=0$), possibly a cosmological constant, $\Lambda$, and a
linear dependence between the energy density $\epsilon$ and the
pressure, $p$, namely $p=\kappa \epsilon$. Thus the metric is the
Robertson-Walker metric
%%(see section~\ref{AEIThorns/Exact/sect-Robertson-Walker})
with $k =0$ and (see gr-qc/0110030, astro-ph/9910093 and references
cited here),
\begin{equation}
R(t) = R_0 \left[ \cosh \left(\frac{\sqrt{3\Lambda}}{2}(\kappa+1) t \right)
		  +
		  \sqrt{1+\frac{8\pi G\,\epsilon_{0}}{\Lambda}}
		  \sinh \left( \frac{\sqrt{3\Lambda}}{2}(\kappa+1) t \right)
		  \right]^{2/3(\kappa+1)}   
\end{equation}
where $R_0$ is the scale factor of the universe (``radius'') at $t=0$;
the density of energy reads
\begin{equation}\label{dens}
\epsilon(t)=\epsilon_0\,a(t)^{-3(\kappa+1)}\,.
\end{equation}
The stress-enegy tensor is one of a perfect fluid,
\begin{equation}
T_{\mu}^{\nu}=(\epsilon+p)u^{\nu}u_{\mu}-p \delta_{\mu}^{\nu}\,, 
\end{equation}
which depends on the covariant four-velocity  $u^{\mu}=dx^{\mu}/ds$
(remember $p=\kappa \epsilon$).

The physics parameters are
the equation of state parameter $\kappa = \verb|Lemaitre__kappa|$,
the cosmological constant $\Lambda = \verb|Lemaitre__Lambda|$,
the energy density of the universe at time $t = 0$,
$\epsilon_0 = \verb|Lemaitre__epsilon0|$,
and the scale factor (radius) of the universe at time $t = 0$,
$R_0 = \verb|Lemaitre__R0|$.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%%\subsection{Robertson-Walker spacetime}
%%\label{AEIThorns/Exact/sect-Robertson-Walker}
%%
%%\verb|Exact::exact_model = "Robertson-Walker"| specifies a 
%%Robertson-Walker spacetime  as described in Hawking and Ellis section~5.3
%%and MTW section~27.11 (see also gr-qc/0110031),
%%transformed to the usual Cactus $(t,x,y,z)$ Cartesian-topology coordinates.
%%The general Robertson-Walker line element in $(t,r,\theta,\phi)$ coordinates
%%is
%%\begin{equation}
%%ds^2 = -dt^2 + R(t)^2 \left[ \frac{dr^2}{1 - kr^2} + r^2 \, d\Omega^2 \right]
%%\end{equation}
%%
%%The physics parameters are
%%the scale factor $R(t)$ at time $t = 0$, $R_0 = \verb|Robertson_Walker__R0|$,
%%a parameter $\rho = \verb|Robertson_Walker__rho|$ which is related to
%%the actual value of the matter density in the Universe,
%%the geometry curvature parameter $k = \verb|Robertson_Walker__k|$,
%%which can take (only) the values $k=-1$, $0$, or $+1$, corresponding
%%to open, flat, or closed 3-geometries, and finally
%%the Boolean parameter \verb|Robertson_Walker__pressure| to select
%%whether or not to include pressure terms in the model.  If pressure
%%is included we have a radiation-dominated universe $p = \frac{1}{3} \rho$;
%%if pressure is not included we have a matter-dominated universe $p=0$.
%%
%%For a good simulation it is necessary to give good numerical values
%%for the above parameters (they are very strictly related, through the
%%Einstein equations).  See gr-qc/0110031 for some examples.
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{de~Sitter spacetime}

\verb|Exact::exact_model = "de Sitter"| specifies an Einstein-de~Sitter 
spacetime (a zero-pressure spatially-flat Robertson-Walker spacetime),
as described in Hawking and Ellis section~5.3 and MTW section~27.11
(see also gr-qc/0110031 for some tests of Cactus with this model).
The only physics parameter is the multiplicative scale
factor $a = \verb|de_Sitter__scale|$.

The Einstein-De~Sitter spacetime is the special case
$R(t) = \sqrt{a}\,t^{2/3}$, $k = 0$ of the more general Robertson-Walker
spacetime, so the line element in $(t,r,\theta,\phi)$ coordinates is
\begin{equation}
ds^2 = -dt^2 + a t^{4/3} \left[ dr^2 + r^2 \, d\Omega^2 \right]
\end{equation}
The only non-vanishing component of the stress-energy tensor is
\begin{equation}
T_{tt} = \frac{1}{6 \pi t^2}
\end{equation}
This is properly set up by this thorn. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{de~Sitter spacetime with cosmological constant}

\verb|Exact::exact_model="de Sitter+Lambda"| specifies an Einstein-de~Sitter
spacetime with a cosmological constant, with the line element
\begin{equation}
ds^2 = - dt^2 + e^{2/3\sqrt{3\Lambda}t} \left ( dx^2 + dy^2 + dz^2 \right) 
\end{equation}
where $\Lambda$ is the cosmological constant.
FIXME: how is $\Lambda$ determined?

The only physics parameter is the multiplicative scale
factor $a = \verb|de_Sitter_Lambda__scale|$.

The fictitious ``matter'' stress-energy tensor representing $\Lambda$ is
\begin{equation}
T_{ij}= - \frac{\Lambda}{8 \pi} g_{ij} = \left ( \begin{array}{cccc}
\frac{1}{8}\frac{\Lambda}{\pi} & 0 & 0 & 0\\
0 & -\frac{1}{8}\frac{\Lambda  e^{2/3 \sqrt{3\Lambda}t}}{\pi }& 0 & 0\\
0 & 0 &-\frac{1}{8}\frac{\Lambda e^{2/3 \sqrt{3\Lambda}t}}{\pi }&  0\\
0 & 0 & 0 & -\frac{1}{8}\frac{\Lambda  e^{2/3 
\sqrt{3\Lambda}t}}{\pi}\end{array}\right ) \, 
\end{equation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{anti-de~Sitter spacetime with cosmological constant}

\verb|Exact::exact_model="anti-de Sitter+Lambda"| specifies an
anti-de~Sitter spacetime with a cosmological constant, with the line
element
\begin{equation}
ds^2 =  dx^2 + e^{2/3\sqrt{-3\Lambda}t} \left ( -dt^2 + dy^2 + dz^2 \right)  
\end{equation}
FIXME: how is $\Lambda$ determined?

The only physics parameter is the multiplicative scale
factor $a = \verb|anti_de_Sitter_Lambda__scale|$.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Approximate Bianchi type~I spacetime}

\verb|Exact::exact_model = "Bianchi I"| specifies an approximation to
a Bianchi type~I spacetime, setting the spacetime metric components
as harmonic functions. Thus this is not a proper solution of Einstein
equations.  The only physics parameter is the multiplicative scale
factor $a = \verb|Bianchi_I__scale|$.

{\bf This solution doesn't work properly yet.  See Mitica Vulcanov for
further information.}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{G\"{o}del spacetime}

\verb|Exact::exact_model = "Goedel"| specifies a G\"{o}del spacetime,
as described in Hawking and Ellis section~5.7.  The only physics parameter
is the multiplicative scale factor $a = \verb|Goedel__scale|$.

At present this thorn doesn't set up the stress-energy tensor;
you have to do this ``by hand''.

{\bf This solution doesn't work properly yet.  See Mitica Vulcanov for
further information.}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Bertotti spacetime}

\verb|Exact::exact_model = "Bertotti"| specifies a Bertotti spacetime.
This a spacetime metric with cosmological constant (see Gravitation
and Geometry by Rindler and Trautman, Bibliopolis, Napoli, 1987,
page~309), with the line element
\begin{equation}
ds^2 = -e^{2\sqrt{-\Lambda}x}dt^2 +dx^2 +  e^{2\sqrt{-\Lambda}z}du^2 + dz^2
\end{equation}
The only physics parameter is the cosmological constant
$\Lambda = \verb|Bertotti__Lambda|$.

The fictitious ``matter'' stress-energy tensor representing $\Lambda$ is
\begin{equation}
T_{ij}= - \frac{\Lambda}{8 \pi} g_{ij} = \left ( \begin{array}{cccc}
\frac{1}{8}\frac{\Lambda e^{2\sqrt{-\Lambda} x}}{\pi} & 0 & 0 & 0\\
0 & -\frac{1}{8}\frac{\Lambda}{\pi }& 0 & 0\\
0 & 0 &-\frac{1}{8}\frac{\Lambda e^{2\sqrt{-\Lambda}z}}{\pi }&  0\\
0 & 0 & 0 & -\frac{1}{8}\frac{\Lambda}{\pi}\end{array}\right ) \, 
\end{equation}

Mitica Vulcanov says:
This metric is not working properly. We suspect that it is not a solution
of the vacuum Einstein equations with cosmological constant, thus
somebody else can try to calculate properly the above components
of the $T_{ij}$ - ask Mitica D.N. Vulcanov for more details.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Kasner-like spacetime}

\verb|Exact::exact_model="Kasner-like"| is the so-called
``Kasner-like'' metric, as described in L.~Pimentel,
Int.\ Journ.\ of Theor.\ Physics, {\bf 32},  No.~6, p.~979, (1993)
and the references cited here.  (See also MTW section~30.2,
gr-qc/0110031, and S.~Gotlober \etal{},
``Early Evolution of the Universe and Formation [of] Structure'',
Akad.\ Verlag, 1990.)
The Kasner-like line element is
\begin{equation}
ds^2 = -dt^2 + t^{2q} (dx^2 +dy^2) + t^{2 - 4q}dz^2
\end{equation}
Here we have a stress-energy tensor which has all off-diagonal components 
vanishing:
\begin{eqnarray}
T_{ij} = \left(
	 \begin{array}{cccc}
	 q\frac{(2-3 q)}{8 \pi t^2} & 0 & 0 & 0 \\
	 0 & q\frac{(2-3 q)t^{2q}}{8 \pi t^2} & 0 & 0\\
	 0 & 0 & q\frac{(2-3 q)t^{2q}}{8 \pi t^2} & 0\\
	 0 & 0 & 0 & q\frac{(2-3q)t^{2-4q}}{8 \pi t^2}%%%\\
	 \end{array}
	 \right)
\end{eqnarray}

There is one parameter $q = \verb|Kasner_like__q|$.

This metric forms a one parameter family of solutions of Einstein's
equations with a perfect stiff fluid. The parameter $q$ is related to
the energy density, as is obvious from the last equation. The
qualitative features of the expansion depend on $q$ in the following
way: for $q > 1/2$ the universe expands from a ``cigar'' singularity;
for $q = 1/2$, the universe expands purely transversally from an
initial ``barrel'' singularity; for $0 < q < 1/2$ the initial
singularity is ``point-like'' and if $q \leq 0$ we have a ``pancake''
singularity. The case $q=1/3$ corresponds to an isotropic universe
with a stiff fluid; the case $q=0$ is a region of Minkowski spacetime
in non-Cartesian coordinates. This family of metrics is ``Kasner-like''
in the sense that the sum of the exponents is equal to one, but the
sum of the squares is not equal to one except in the cases when $q=0$
or $q=2/3$, when we have the vacuum case.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{axisymmetric Kasner spacetime}

\verb|Exact::exact_model="Kasner-axisymmetric"| specifies an
axisymmetric Kasner spacetime, as described in
S.~D.~Hern, {\it Numerical Relativity and Inhomogeneous  Cosmologies\/},
PhD thesis, Cambridge (gr-qc/0004036), and 
S.~D.~Hern, J.~M.~Stewart, Class.\ Quantum Grav, {\bf 15}, 1581, (1998).
The line element is
\begin{equation}
ds^2 = -\frac{dt^2}{\sqrt{t}} + \frac{dx^2}{\sqrt{t}} + t dy^2
+ t dz^2
\end{equation}
This is an exact solution of the vacuum Einstein equations, explicitly
homogeneous, and features a cosmological singularity at $t=0$.

There are no parameters for this model.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{generalized Kasner spacetime}
\verb|Exact::exact_model="Kasner-generalized"| specifies a
generalized Kasner spacetime, as described in MTW section~30.2,
where the line element is
\begin{equation}
ds^2 = -dt^2 +t^{2p_1}dx^2 + t^{2p_2}dy^2 + t^{2p_3}dz^2
\end{equation}
The Kasner parameters $p_1$, $p_2$ and $p_3$ must satisfy the relations
$p_1+p_2+p_3 = 1$ and
$p_1^2+p_2^2+p_3^2 = 1$.
Restricting ourselves only to two parameters, $p_1$ and $p_2$,
we have the following stress-energy tensor:
\begin{equation}
T_{ij} = \left(
	 \begin{array}{cccc}
	 \frac{A}{8\pi t^2} & 0 & 0 & 0\\
	 0 & \frac{A t^{2p_1-2}}{8 \pi} & 0 & 0\\
	 0 & 0 & \frac{A t^{2p_2-2}}{8\pi} & 0 \\
	 0 & 0 & 0 & \frac{A t^{-2p_1-2p_2}}{8 \pi}%%%
	 \end{array}
	 \right)
\end{equation}
where $A = p_1 - p_1^2 +p_2 - p_2^2 - p_1 p_2$ (note the use of the above
first condition on the parameters, thus we have $p_3 = 1-p_1-p_2$).  

The parameters are $p_1 = \verb|Kasner_generalized__p1|$
and $p_2 = \verb|Kasner_generalized__p2|$.

Mitica Vulcanov has done several simulations with various Kasner
spacetimes, see gr-qc/0110031. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Gowdy-wave Spacetime}

\verb|Exact::exact_model = "Gowdy-wave"| specifies a Gowdy spacetime,
which gives a polarized wave in an expanding universe.  See
K.~New, K.~Watt, C.~W.~Misner, and J.~Centrella,
``Stable 3-level leapfrog integration in numerical relativity'',
PRD 58, 064022.

There is only a single parameter, the wave amplitude
\verb|Gowdy_wave__amplitude|.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Milne Spacetime for Pre-Big-Bang Cosmology}

\verb|Exact::exact_model = "Milne"| specifies a Milne spacetime,
as described by gr-qc/9802001 (see in particular reference~14, which
in turn points to Zeldovich and Novikov volume~2 section~2.4):
\begin{equation}
g_{ab} = \left[
	 \begin{array}{cccc}
	 -1	& 0		& 0		& 0		\\
	 0	& V(1+y^2+z^2)	& -Vxy		& -Vxz		\\
	 0	& -Vxy		& V(1+x^2+z^2)	& -Vyz		\\
	 0	& -Vxz		& -Vyz		& V(1+x^2+y^2)	%%%\\
	 \end{array}
	 \right]
\end{equation}
where
\begin{equation}
V = \frac{t^2}{1 + x^2 + y^2 + z^2}
\end{equation}

{\bf The $g_{ab}$ given here is indeed what the code computes, but
alas noone seems to know whether this is indeed a Milne  spacetime.}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Miscellaneous Spacetimes}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Boost Rotation Symmetric Spacetime}

\verb|Exact::exactmodel = "starSchwarz"| specifies a boost-rotation
symmetric spacetime, as described in Jiri Bicak and Bernd Schmidt,
"Asymptotically flat radiative space-times with boost-rotation symmetry",
Physical Review~D {\bf 40}, 1827 (1989).
Pravda and Pravdov\'{a}, gr-qc/0003067, give a
general review of boost-rotation symmetric spacetimes.  

FIXME: the parameters are \dots

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Schwarzschild (Constant Density) Star}

\verb|Exact::exact_model = "constant density star"| specifies a
constant-density ``Schwarzschild'' star, as described in MTW~Box 23.2.
The stress-energy tensor is also properly set up.

The parameters are the star's mass \verb|constant_density_star__mass|
and its radius \verb|constant_density_star__radius|.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Non-Einstein Bowl (``Bag of Gold'') Spacetime}

\verb|Exact::exact_model = "bowl"| specifies a ``bag of Gold'' metric,
as described in gr-qc/9809004.  This is useful for testing purposes,
but isn't a solution of the Einstein equations.
The line element in $(t,r,\theta,\phi)$ coordinates is
\begin{equation}
ds^2 = -dt^2 + dr^2 + R^2(r) \, d\Omega^2
\end{equation}

We choose $R(r)$ such that $\displaystyle \lim_{r \ll 1} R(r) = r$
and $\displaystyle \lim_{r \gg 1} R(r) = r$, so we have a flat 3-metric
(and hence 4-metric too) for very small~$r$ and for very large~$r$.
For intermediate values of~$r$, we take $0 < R(r) < r$; this deficit
in areal radius produces the ``bag of gold'' geometry.

The physics parameters are
\begin{itemize}
\item	$a = \verb|bowl__strength|$, the deformation strength
\item	$c = \verb|bowl__center|$, the deformation center
\item	\verb|bowl__shape| is a keyword parameter to specify
	the type of function to use to specify the bowl (see below)
\item	$\sigma = \verb|bowl__sigma|$, the deformation width
	(\Nb{} for \verb|bowl__shape = "Gaussian"| the function
	is actually $\exp \big( \!-(x-c)^2/\sigma^2 \big)$, not
	$\exp \big( -\half(x-c)^2/\sigma^2 \big)$.  Thus for
	this case $\sigma$ is actually $\sqrt{2}$ times the
	standard deviation of the Gaussian.)
\item	\verb|bowl__x_scale|, \verb|bowl__y_scale|, and \verb|bowl__z_scale|,
	which set the $x$, $y,$ and $z$ scales of the bowl
	(\ie{} all the computations actually use $x/\verb|bowl__x_scale|$,
	$y/\verb|bowl__y_scale|$, and $z/\verb|bowl__z_scale|$)
\item	\verb|bowl__evolve| is a Boolean parameter which controls
	whether the bowl should be time-dependent; the remaining
	parameters are only used if \verb|bowl__evolve| is true
\item	$t_0 = \verb|bowl__t0|$, the center of the Fermi step in time
\item	$\sigma_t = \verb|bowl__sigma_t|$, the width of the Fermi step in time
\end{itemize}

The size of the deviation from a flat geometry is controled by the
parameter $a = \verb|bowl__strength|$.  If $a = 0$, we are in flat spacetime.
The width of the curved region is controled by $\sigma = \verb|bowl__sigma|$,
and the place where the curvature becomes significant (the center of
the deformation) is controlled by $c = \verb|bowl__center|$.

In detail, we choose
\begin{equation}
R(r) = r - A f(r) g(r)
\end{equation}
Here $A = a$ if \verb|bowl_evolve = "false"|, but is multiplied by
a Fermi factor
\begin{equation}
A = \frac{a}{1 + \exp(-\sigma_t(t-t_0))}
\end{equation}
if \verb|bowl_evolve = "true"|.  For this latter case we have
flat spacetime far in the past, and a static bowl far in the future.
$f(r)$ is either a Gaussian or a Fermi function,
\begin{equation}
f(r) = \left\{
       \begin{array}{ll}
       \displaystyle
       \exp \big( (r-c)^2/\sigma^2 \big)
			& \hbox{if {\tt bowl\_type = "Gaussian"}}	\\[1ex]
       \displaystyle
       \frac{1}{1 + \exp(-\sigma(r-c))}
			& \hbox{if {\tt bowl\_type = "Fermi"}}		%%%\\
       \end{array}
       \right.
\end{equation}
$g(r) = 1 - \sech 4r$ is a fixup factor to ensure that
$\displaystyle \lim_{r \to 0} R(r) = r$.

The three paramters \verb|bowl__x_scale|, \verb|bowl__y_scale|, and
\verb|bowl__z_scale| scale the $(x,y,z)$ axes respectively.  Their
default values are all~1.  These parameters are useful to hide the
spherical symmetry of the metric.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Acknowledgments}

The original code, including the boost-rotation symmetric metric
and the slice evolver, was written by Carsten Gundlach and Miguel Alcubierre.
Many different people have contributed exact solutions.
The Schwarzschild/Lemaitre solution
and most (all?) of the cosmological solutions
were written by Mitica Vulcanov.
The Minkowski/gauge wave model was written by Michael Koppitz.
In May-June 2002 Jonathan Thornburg cleaned up a lot of the code,
systematized the spacetime/coordinate and parameter names, and
wrote most of this documentation (based on the comments in the code,
some reverse-engineering, and querying various people about how the
code works.)
The description of the Kastor-Traschen maximally charged multi-BH
model is adapted from the file \verb|KTsol.tex| in this same directory,
by Hisa-aki Shinkai.
The Gowdy model was written by Denis Pollney.
The \verb|ADMBase::evolution_method = "exact"| code was written
by Peter Diener.
The ``boost any vacuum solution'' code was written by Jonathan Thornburg.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Do not delete next line
% END CACTUS THORNGUIDE

\end{document}


=== KTsol.tex ===
% Hisaaki Shinkai shinkai@atlas.riken.go.jp <- PL use this address
%-----------------------------------------------------------------------
% KTsol.tex version 0.1  19980603
% Hisaaki Shinkai shinkai@wurel.wustl.edu
%-----------------------------------------------------------------------
%00000000111111111122222222223333333333444444444455555555556666666666777
%-----------------------------------------------------------------------
\documentstyle[11pt]{article}
% A4 tate -----------------------------
\topmargin      0.3in
\oddsidemargin  0.0cm
\evensidemargin 0.0cm
\textwidth     16.0cm
\textheight    23.0cm
\headsep        0.0in
%--- US letter size
\topmargin     -0.0in
\headsep        0.0in
\oddsidemargin   0.0in
\evensidemargin  0.0in
\textwidth       6.5in
\textheight      8.5in
%-----------------------------------------------------------------------
%------------------------- macro for begin-eqs
\def\non{\nonumber \\}
\def\nonn{\nonumber \\ &&}
\def\be{\begin{equation}}
\def\en{\end{equation}}
\def\bear{\begin{eqnarray}}
\def\enar{\end{eqnarray}}
\def\beas{\begin{eqnarray*}}
\def\enas{\end{eqnarray*}}
%--------------->>>>>>>>>>>> commands for number of eqs. (1.1a)(1.1b)...
% following definition is for book or report style
%\renewcommand{\theequation}{\thechapter.\theenumi\alph{equation}}
\def\bera{ \setcounter{enumi}{\value{equation}}
            \addtocounter{enumi}{1}
            \setcounter{equation}{0}
            \renewcommand{\theequation}{\theenumi\alph{equation}}
            \begin{eqnarray} }
\def\enra{ \end{eqnarray}
            \setcounter{equation}{\value{enumi}}
            \renewcommand{\theequation}{\arabic{equation}}  }
%-----------------------------------------------------------------------
\def\non{\nonumber \\}
\def\nonn{\nonumber \\ &&}
\def\dsp{\displaystyle}
\def\mova{\left( M \over a\right)}
%------------------------- macro for lists
\def\been{\begin{enumerate}}
\def\enen{\end{enumerate}}
\def\beit{\begin{itemize}}
\def\enit{\end{itemize}}

\def\pl{ \partial}
\def\half{{1 \over 2}}
%-----------------------------------------------------------------------
\begin{document}
\noindent
filename="KTsol.tex" HShinkai ({\tt shinkai@atlas.riken.go.jp})

\begin{center}

{\Large\bf Multi Black Hole solutions}

\end{center}
\begin{flushright}
version 0.1 ~~~
19980603 Hisaaki Shinkai
\end{flushright}

\section{Majumdar-Papapetrou solution}
Majumdar-Papapetrou (MP)
solutions\cite{MP} is a multi-black-hole solution to Einstein's
equation.
Each black holes are charged maximally, $Q=M$,  and
the balance between gravitational attraction and
electrostatic repulsion among the black holes causes each to maintain
its position relative to the others eternally.
The MP solutions are given by
\be
ds^2=-{1 \over \Omega^2} dt^2+ \Omega^2(dx^2+dy^2+dz^2),
\label{MPmetric}
\en
$$\mbox{where}~~
\Omega=1+\sum_{i=1}^N {M_i \over  r_i},~~ \mbox{and}~~
  r_i=\sqrt{(x-x_i)^2+(y-y_i)^2+(z-z_i)^2}.
$$
where $M_i$ and $(x_i, y_i, z_i) \in {\bf R}^3$ are masses and
locations of black holes.


\section{Kastor-Traschen solution}


The  Kastor-Traschen (KT) solutions \cite{KT} is the cosmological
version of MP solution.  This is a multi-black-hole solution
  to Einstein's
equation with cosmological constant,  contains arbitrary many
$Q=M$ black holes that participate in an overall de Sitter expansion
or contraction.  In the $\Lambda \rightarrow 0$
limit, the KT solutions reduce to the MP solution.
 
To write the KT
metric, we first choose $(x_i, y_i, z_i) \in {\bf R}^3$,
$i=1,2,\cdots,N$ for locations of black holes, then
\be
ds^2=-{1 \over \Omega^2} dt^2+a(t)^2 \Omega^2(dx^2+dy^2+dz^2),
\label{KTmetric}
\en
$$\mbox{where}~~
\Omega=1+\sum_{i=1}^N {M_i \over a r_i},~~ a=e^{Ht}, ~~~
H=\pm \sqrt{\Lambda \over 3}.$$
$$\mbox{and}~~ r_i=\sqrt{(x-x_i)^2+(y-y_i)^2+(z-z_i)^2}$$
where we interpret $M_i$
as the mass of the $i{\rm th}$ black hole, although we have
neither an asymptotically flat region nor event horizons available
to convert this naive interpretation into a rigorous one.

If $H<0$, then the solution represents ``incoming" charged BHs.
If $H>0$, then the solution represents ``outgoing" charged WHs.


The principal null directions of KT solutions are illustrated in
\cite{KTpnd}.
The horizon structure of KT solutions are discussed in \cite{KThorizon}.


%-----------------------------------------------------------------------
\newpage
\appendix
\section{Reissner-Nordstr{\o}m-de Sitter solution }
It will be interesting to see such a cosmological extention for
a single black hole case.
The global structure of this solution is discussed in
\cite{RNdShorizon}.

\subsection{Reissner-Nordstr{\o}m-de Sitter solution (static coord) }
\be
ds^s=-V(R)dT^2 + {1 \over V(R)} dR^2 + R^2 d\Omega^2
\en
$$\mbox{where}~~
V(R)=1-{2M\over R}+{Q^2 \over R^2}-{\Lambda \over 3} R^2. $$
\subsection{Reissner-Nordstr{\o}m-de Sitter solution (cosmological coord) }
By the transformation
$$
a(t) r =  R-M, ~~~
t= T+h(R), ~~~
{dh \over dR} = - {HR^2 \over (R-M)V(R)}
$$
and setting $Q=M$, we will get the cosmological coordinate version of
RNdS as
\be
ds^2=-{1\over F^2}dt^2 + {a^2(t) F^2} ( dr^2 +  r^2 d\Omega^2)
\en
$$\mbox{where}~~
F=1+{M\over ar}, ~~~  a=e^{Ht}, ~~~
H=\pm \sqrt{\Lambda \over 3}.$$.

The horizons appeare at
$$
r_\pm = {1\over 2 a(t) |H| } ( 1 - 2 M |H| \pm \sqrt{1 - 4 M |H|} )
$$
which are corresponds to de Sitter horizon ($r_+$) and
outer BH horizon  ($r_-$),  respectivly.




%%**********************************************************************
%23456789012345678901234567890123456789012345678901234567890123456789012

\baselineskip .15in
\begin{thebibliography}{99}

\bibitem{MP}
S. D. Majumdar, Phys. Rev. {\bf 72}, 930 (1947); A. Papapetrou,
Proc. R. Ir. Acad. Sect. {\bf A51}, 191 (1947);
J. B. Hartle and S. W. Hawking, Commun. Math. Phys. {\bf 26}, 87
(1972).


\bibitem{KT}
D. Kastor and J. Traschen,  Phys. Rev. {\bf D47}, 5370 (1993).

\bibitem{KTpnd}
L. Gunnarsen, H. Shinkai and K. Maeda, Class. Quantum Grav. {\bf 12},
133 (1995).

\bibitem{KThorizon}
K. Nakao, T. Shiromizu and S. A. Hayward,
Phys. Rev. {\bf D52}, 796 (1995).

\bibitem{RNdShorizon}
D. R. Brill and S. A. Hayward
Class. Quant. Grav. {\bf 11}, 359 (1994).
 
\end{thebibliography}

\end{document}


=== slice_evolver.tex ===
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\documentstyle[a4wide]{article}
\begin{document}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\title{Documentation for the slice evolver in Cactus thorn Exact}

\author{Carsten Gundlach\\ Faculty for Mathematical Studies\\
University of Southampton\\ Southampton SO17 1BJ, UK}

\date{6 June 02}

\maketitle

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Introduction}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

This text gives all the formulas that are used in the slice evolver of
Cactus thorn Exact. I wrote it originally for a joint paper with
Miguel Alcubierre and Paul Walker that we never finished. The two last
sections are the original code documentation I wrote.

Here are some ways of using exact solutions in numerical relativity:

1) Use preferred slices of exact solutions to obtain initial data,
lapse and shift. Evolve with this lapse and shift, and with exact
boundary data or some ad hoc BC.

2) Obtain initial data (solutions of the constraints) without
symmetries by using an arbitrary slice in an exact solution. 

3) Evolve these data with an arbitrary lapse and shift, and at the
same time evolve the slice with the same lapse and shift.

a) Test accuracy of the code.

b) Test stability and accuracy of inner boundary conditions.

c) Test effect of outer boundary conditions on introducing
``spurious'' waves.

4) Test gauge conditions on their own, without the need for stable BC
and a stable evolution scheme, by evolving the slice only, and faking
the evolution of the Cauchy data. See if these can smooth a highly
distorted slice of Kerr or Schwarzschild.

The main idea of thorn Exact is that each physically different
spacetime is stored only in one set of coordinates, namely those that
are the standard for it and which are adapted to its symmetries
(``preferred coordinates''). One can then obtain it in any other
coordinate system, in particular one that hides the symmetries, by a
numerical coordinate transformation. As we are interested in a 3+1
split of the metric, and in Cauchy data, the fundamental object is a
slice $X^A(x^i)$ embedded in the spacetime. The four coordinates $X^A$
are the preferred ones, and the three coordinates $x^i$ are the ones
intrinsic to the slice.  From $X^A(x^i)$ and the four-metric $g_{AB}$
in the preferred coordinates, we compute the three-metric and
extrinsic curvature on the slice. We can then either evolve the $g$
and $K$ with the usual methods, or, if we want to test only a gauge
condition, we can evolve the slice itself, and read off $g$ and $K$ in
its new position. 

Since Miguel and I wrote the original code, several physical
spacetimes have been implemented in a number of coordinate
systems. However, if you want an exact solution in completely generic
coordinates, or if you want to test a gauge condition, the slice
evolver is the way to go.

Alas, the \verb|"Minkowski/conf wave"| model doesn't work with the
arbitrary-slice evolver.  There's no warning, you'll just silently
get wrong results.  Sigh\dots

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Extracting Cauchy data on an arbitrary slice}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

An arbitrary slice in the exact solution, together with a coordinate
system $x^i$ on this slice is given through four scalar functions
$X^A$ by $x^A=X^A(x^i)$, where $x^A$ are the preferred coordinates of
the exact solution, and $(t,x^i)$ are the coordinates of the numerical
code.  The induced 3-metric on the slice is simply
\begin{equation}
\label{3-metric}
g_{ij} = {X^A}_{,i} {X^B}_{,j} g_{AB},
\end{equation}
where we use a comma to denote partial derivatives. The index or the
context  will always make
clear if these are partial derivatives in the $x^A$ or $(t,x^i)$
coordinates. Next we construct the unit normal vector to the slice
as
\begin{equation}
n^A = N \bar n^A, \qquad N = (\bar n^A \bar n^B g_{AB})^{-1/2}
\end{equation}
where a non-unit normal vector $\bar n^A$ is 
\begin{equation}
\bar n^A = g^{AB} \epsilon_{BCDE} {X^C}_{,1} {X^D}_{,2} {X^E}_{,3}.
\end{equation}
Here $\epsilon_{BCDE}$ is any totally antisymmetric tensor, for
example the one given by $\epsilon_{0123}=1$ in coordinates $X^A$. We
only have to make sure that $\bar n^A$ is future-pointing.

The extrinsic curvature $K_{ij}$ of $\Sigma$ is calculated easily if
we extend the coordinates $x^i$ on $\Sigma$ to geodesic coordinates
$(x^i,t)$ on a neighbourhood of $\Sigma$. In these coordinates,
\begin{equation}
\label{gdot}
K_{ij} = -{1\over 2}{\partial\over\partial t} g_{ij}  \hbox{ (for } 
\alpha=1 \hbox{ and } \beta^i = 0 \hbox{ only).}
\end{equation}
In the same coordinates we also have 
\begin{equation}
{\partial X^A \over \partial t} = n^A \hbox{ (for } 
\alpha=1 \hbox{ and } \beta^i = 0 \hbox{ only).}
\end{equation}
Substituting (\ref{3-metric}) into (\ref{gdot}), and using the trivial
commutation relation
\begin{equation}
\left[{\partial\over\partial t}, {\partial\over\partial
x^i}\right] = 0, 
\end{equation}
we obtain
\begin{equation}
\label{Kij1}
K_{ij} = -{1\over 2}\left({n^A}_{,i} {X^B}_{,j} + {X^A}_{,i} {n^B}_{,j}\right)
g_{AB}  -{1\over 2}{X^A}_{,i} {X^B}_{,j} n^C g_{AB,C}.
\end{equation}
Note that we are now back within a single slice $\Sigma$, and this
result is valid without reference to a particular coordinate system on
spacetime beyond the slice.  This gives us a practical algorithm for
calculating $g_{ij}$ and $K_{ij}$, given the four functions $X^A$ on a
numerical $x^i$ grid. We obtain the ${X^A}_{,i}$ by finite differencing on
the grid, calculate $g_{ij}$ and $n^A$ algebraically for each point on
the grid, finite difference again to obtain ${n^A}_{,i}$, and
calculate $K_{ij}$ again algebraically. The metric coefficients
$g_{AB}(x^C)$ are given in closed form, and are accessed in practice
through a function call. We can obtain the $g_{AB,C}$ in closed form,
but in order to save labor and the scope for error, we actually obtain
them by finite differencing. The error incurred is negligible, as we
are not bound to a numerical grid, but can use a tiny finite
differencing interval $\Delta x^C$.

The term ${n^A}_{,i}$ contains both second derivatives of $X^A$ and
first derivatives of $g_{AB}$. While the former must necessarily be
calculated by finite differencing on the grid, the latter can be
obtained to higher accuracy using the analytic expressions for
$g_{AB,C}$. (This is useful at least when $X^A_{,i}$ are small.)
Therefore we prefer to eliminate ${n^A}_{,i}$ in favor of
${X^A}_{,ij}$ for numerical purposes. We do this by taking the
derivative of the identity
\begin{equation}
n^A {X^B}_{,j} g_{AB} = 0,
\end{equation}
and obtain
\begin{equation}
\label{Kij2}
K_{ij} =  {X^A}_{,ij} n^B g_{AB}  + {1\over 2} \left(
{X^A}_{,i} {X^C}_{,j} n^B + {X^C}_{,i} {X^B}_{,j} n^A  
- {X^A}_{,i} {X^B}_{,j} n^C 
\right)g_{AB,C}.
\end{equation}

In the hyperbolic Bona-Mass\'o formulation of the Einstein equations,
the spatial derivatives of the metric form part of the initial
data. Again we split these up into derivatives of the slicing and
the exact metric:
\begin{equation}
g_{ij,k}= \left({X^A}_{,ik} {X^B}_{,j} 
+ {X^A}_{,jk} {X^B}_{,i} \right) g_{AB}+ 
{X^A}_{,i} {X^B}_{,j} {X^C}_{,k}  g_{AB,C}.
\end{equation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Evolving a slice in time}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

To advance a given slice in time, for a given lapse $\alpha(x^i)$ and shift
$\beta^i(x^j)$, we use the definition of the vector field
$\partial/\partial t$ to obtain
\begin{equation}
{\partial  X^A \over\partial t}= \alpha n^A + \beta^i {X^A}_{,i},
\end{equation}
with $n^A$ defined above in terms of $X^A$ and their first and second
derivatives.  This is a partial differential equation for the four
scalar functions $X^A$. In a numerical relativity situation, we want
to evolve this equation for an interval $\Delta t$ in which $\alpha$
and $\beta^i$ are considered as fixed functions of the coordinates
$x^i$. To compare this scheme with a second order convergent numerical
relativity code, the numerical error must be of $O(\Delta t^3)$. One
way of doing this is using a Runge-Kutta like approach. In this we
evolve forward in time by $(\Delta t)/2$, recompute ${X^A}_{,i}$ and
$n^A$, and leapfrog over this half step. 


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Using the preferred slicing}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Things simplify if we use the preferred slicing and spatial
coordinates 
\begin{equation}
X^0 = t, \qquad X^I = x^i.
\end{equation}
Then we  have $g_{ij}=g_{IJ}$, and the expression for the extrinsic
curvature simplifies to
\begin{equation}
\label{Kij3}
K_{ij} = {1\over 2\alpha} \left(-g_{IJ,0} + g_{IJ,K} \beta^K
+ {\beta^K}_{,I} g_{KJ} + {\beta^K}_{,J} g_{KI} \right).
\end{equation}
Here we have used the expressions for the lapse and shift in the
preferred slicing
\begin{equation}
\alpha=(-g^{00})^{-1/2}, \qquad \beta^I = -{g^{0I}\over g^{00}}.
\end{equation}
These expressions are useful in their own right, as we may want to use
the analytic value of the lapse and shift in the preferred slicing for
the numerical evolution.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Code documentation}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Rudimentary documentation for Cactus thorn exact.

CG 4.11.97, revised 28.1.98 (PW 28.1.98, 4.9.98 on blend BC PW 2.2.98 on Comp)

This thorn checks cactus against an exact solution.

1) An exact solution with a boost and a rotation Killing vector. The
solution comes out of Eqns. (2.1), (2.8) and (2.10) of J. Bicak,
C. Honselaers and B. G. Schmidt, Proc. Royal Soc. London A 390,
411-419 (1983).

2) Schwarzschild in Eddington-Finkelstein coordinates.

One can separately ask the thorn to provide initial data, the lapse
and shift, and boundary data, from the exact solution. This means that
cactus can be tested without the complications of, say, maximal
slicing, or implementing an outer boundary conditions. But one can
also test these, using the thorn only to obtain initial data.

Look at exact\_rfr.F. There are three decisions:

1) Set initial data (gij and Kij, and Vs and Ds of BM) and initial
lapse and shift from the exact solution? Yes, if model =
"exact". In this case, register exactinitialize with rfr as
CACTUS\_INITIAL.  Unless lapseinit = "exact" and shift = "exact"
are also set, there will be an error message, but other values will be
tolerated. IMPORTANT: The thorn then assumes that after it has been
called, something else will overwrite the lapse and shift.

2) Are lapse and shift to be set from the exact solution during
runtime? Yes, if slicing = "exact" and shift = "exact". If one
is set, the other must be, too. Register exactgauge with
rfr as	CACTUS\_PRESTEP. Other gauge choices, eg. minmax or geodesic,
are possible.

3) Are boundary data to be obtained from the exact solution. Yes, if
bound = "exact". Then register exactboundary with rfr as
CACTUS\_BOUND. Another choice could be "flat".

4) Blending boundary conditions are available. These will set the
values of g, K, v, and D to an exact solution outside some radius, the
evolved value inside some radius, and a linear blend in between. They
are controlled by various parameters starting with exblend. See
exactblendbound.F for more documentation and comment. To activate
blended boundary conditions use

bound = "exact blend"

This blending technique is the same as the GC; on a radius between r1 and   
r2 a linear combination of the numerical and exact solution is placed on  
the grid, scaled in r (so at r1 you get all numerical, at r2, all exact,  
and half way between 50/50). Above r2 the exact solution is simply 
injected onto the grid.        

You can also blend in a cartesian direction (eg, only boundary layers
within n * dx of the grid) using bound = "exact cartblend". Control n
with exblend\_width, with $< 0$ meaning width * dx, and $> 0$ meaning width
in coordinate space.

Generally, this thorn could be broken by other thorns overwriting what
it does when they should not, or by not overwriting the initial lapse
and shift if they should. Therefore CAREFUL with the order of calling.

Exact Cauchy data, lapse and shift, and BM variables are obtained from
a routine that provides the 4-metric and its inverse. Its output is
differentiated numerically where necessary. This poses no problem, as
we are numerically differentiating analytic expressions with a very
small epsilon (not on the grid!)

Additionally this routine will compute convergence coefficients and
differences between the exact solution in runtime, a functionality
previously in thorn\_Comparison.  To use this feature, you need to run
in convergence mode (convergence="yes") and then activate the
following parameters:

comparison = "yes"
comp\_fields = "gxx gyy" 

If you list the comp\_fields in the slice fields then differences
between the fields and the exact solutions will be output. The
comparison is done against the exactmodel.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Code structure}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Code structure for faking a GR time evolution by evolving a surface
embedded in an exact solution. 

model = "slice" extracts Cauchy data from an arbitrary embedded slice 
in an exact solution. The solution in question is selected by, eg.
exactmodel = "fakebinary". model="exact" is now in effect a subclass of
model = "slice", although implemented independently.

system = "slice" then fakes a time evolution, by evolving the slice in
the exact solution, for arbitrary given lapse and shift, and
extracting Cauchy data at each time step. model = "slice" is then
implied and redundant.

The use of this is to test BM and ADM against exact solutions, but
mainly to test new elliptic gauge conditions in a 3D setting without
having to evolve BH spacetimes. Note that the "exact solution" need
only be a 4-metric given in a subroutine, but it need not obey the
Einstein equations. Examples so far are Miguel's bowl metric and Kip's
fake binary metric (just coded up by Bernd in thorn\_exact.)

Notation: $x^A = X^A(x^i,t)$. A=1,4 corresponding to X,Y,Z,T. 

Grid functions: $x^A$ are stored in GFs slicex, slicey, slicez,
slicet.  Temporary storage slicetmpx, slicetmpy, slicetmpz,
slicetmpt. These two groups are referred to in the following as SLICE
and TMP.

{\obeylines

CACTUS\_INITIAL slice\_initialize: 
\quad	initialize $x^A$ in SLICE
\quad	call slice\_data
\quad	call boundaries

CACTUS\_EVOL slice\_evolve: 
\quad	Loop over all points:
\quad\quad		evolve from SLICE to TMP1 using time derivative in TMP2
\quad\quad\quad			(Lax step, or forward in time to mid point)
\quad	end do	
\quad	call linextraponebound on SLICE
\quad	Loop over interior points:
\quad\quad		calculate $x^A_{,i}$ from TMP1	
\quad\quad		include slice\_normal
\quad	end do	
\quad	call linextraponebound on TMP2
\quad	Loop over all points:
\quad\quad		update SLICE using TMP2
\quad\quad\quad			(leapfrog, or centered in time, using $dx^A/dt$ in temp)
\quad	end do
\quad	call linextraponebound on SLICE
\quad	call slice\_data	

slice\_data:
\quad	Loop over interior points
\quad\quad		calculate $x^A_{,i}$ from SLICE
\quad\quad		include slice\_normal
\quad\quad		calculate $g_ij$
\quad\quad		calculate $x^A_{,ij}$ from SLICE
\quad\quad		calculate $g_{AB,C}$
\quad\quad		calculate $K_ij$
\quad\quad		(if BM) calculate $D_{ijk}$, $V_i$
\quad	end do	
\quad	call linextraponebound on TMP2
			
slice\_normal: to be used inside a loop over interior points.
\quad		calculate $n_A$
\quad		call exactmetric
\quad		calculate $n^A$
\quad		calculate $dx^A/dt$ in TMP2

}
						


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{document}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

```



Reference solution:
src_code: C $Header$

#include "cctk.h"
#include "cctk_Parameters.h"
#include "cctk_Arguments.h"
#include "cctk_Functions.h"

      subroutine Exact__boundary(CCTK_ARGUMENTS)

      implicit none

      DECLARE_CCTK_ARGUMENTS

      integer i,j,k
      integer nx,ny,nz

      CCTK_REAL tplusone
      CCTK_REAL 
     $     dxgxxjunk, dxgyyjunk, dxgzzjunk, 
     $     dxgxyjunk, dxgyzjunk, dxgxzjunk,
     $     dygxxjunk, dygyyjunk, dygzzjunk, 
     $     dygxyjunk, dygyzjunk, dygxzjunk,
     $     dzgxxjunk, dzgyyjunk, dzgzzjunk, 
     $     dzgxyjunk, dzgyzjunk, dzgxzjunk,
     $     axjunk, ayjunk, azjunk, 
     $     bxxjunk, bxyjunk, bxzjunk, 
     $     byxjunk, byyjunk, byzjunk, 
     $     bzxjunk, bzyjunk, bzzjunk
      CCTK_REAL
     $     exact_psi,
     $     exact_psix, exact_psiy, exact_psiz,
     $     exact_psixx, exact_psiyy, exact_psizz,
     $     exact_psixy, exact_psiyz, exact_psixz

C     Grid parameters.

      nx = cctk_lsh(1)
      ny = cctk_lsh(2)
      nz = cctk_lsh(3)

C     Initialize the psi of exact
C     (also to tell the models about the conformal_state)
                  if (conformal_state .ne. 0) then
                    exact_psi = 1.0D0
                  else
                    exact_psi = 0.0D0
                  end if
                  exact_psix = 0.0D0
                  exact_psiy = 0.0D0
                  exact_psiz = 0.0D0
                  exact_psixx = 0.0D0
                  exact_psiyy = 0.0D0
                  exact_psizz = 0.0D0
                  exact_psixy = 0.0D0
                  exact_psiyz = 0.0D0
                  exact_psixz = 0.0D0

C     Set all initial data including dijk and vi on all points which 
C     are on the boundary of the domain if it really is the boundary
C     of the complete grid. Treat all six sides of the grid cube this way.

c     Set t = time + dt.  This is necessary here because by the time
c     we reach this point the geometry has been evolved one time step
c     but the variable `time' still hasn't been updated. 

      tplusone = cctk_time + cctk_delta_time

C     Note we also always set the lapse and shift at the boundaries at
C     time t+1. This is to provide boundary conditions for testing
C     elliptic gauge conditions. If they are not used, they will be
C     overwritten by Exact__gauge.

#define EXACTDATAPOINT                                                  \
               call Exact__Bona_Masso_data(                             \
                   decoded_exact_model,                                 \
                   x(i,j,k), y(i,j,k), z(i,j,k), tplusone,              \
                   gxx(i,j,k), gyy(i,j,k), gzz(i,j,k),                  \
                   gxy(i,j,k), gyz(i,j,k), gxz(i,j,k),                  \
                   kxx(i,j,k), kyy(i,j,k), kzz(i,j,k),                  \
                   kxy(i,j,k), kyz(i,j,k), kxz(i,j,k),                  \
                   exact_psi,                                           \
                   exact_psix, exact_psiy, exact_psiz,                  \
                   exact_psixx, exact_psiyy, exact_psizz,               \
                   exact_psixy, exact_psiyz, exact_psixz,               \
                   dxgxxjunk, dxgyyjunk, dxgzzjunk,                     \
                   dxgxyjunk, dxgyzjunk, dxgxzjunk,                     \
                   dygxxjunk, dygyyjunk, dygzzjunk,                     \
                   dygxyjunk, dygyzjunk, dygxzjunk,                     \
                   dzgxxjunk, dzgyyjunk, dzgzzjunk,                     \
                   dzgxyjunk, dzgyzjunk, dzgxzjunk,                     \
                   alp(i,j,k), dtalp(i,j,k),                            \
                   axjunk, ayjunk, azjunk,                              \
                   betax(i,j,k), betay(i,j,k), betaz(i,j,k),            \
                   dtbetax(i,j,k), dtbetay(i,j,k), dtbetaz(i,j,k),      \
                   bxxjunk, bxyjunk, bxzjunk,                           \
                   byxjunk, byyjunk, byzjunk,                           \
                   bzxjunk, bzyjunk, bzzjunk)

      if (cctk_bbox(1) .eq. 1) then 
         i=1
         do j=1,ny
            do k=1,nz
               EXACTDATAPOINT
            end do
         end do
      end if

      if (cctk_bbox(2) .eq. 1) then 
         i=nx
         do j=1,ny
            do k=1,nz
               EXACTDATAPOINT
            end do
         end do
      end if

      if (cctk_bbox(3) .eq. 1) then 
         j=1
         do i=1,nx
            do k=1,nz
               EXACTDATAPOINT
            end do
         end do
      end if

      if (cctk_bbox(4) .eq. 1) then 
         j=ny
         do i=1,nx
            do k=1,nz
               EXACTDATAPOINT
           end do
         end do
      end if

      if (cctk_bbox(5) .eq. 1) then 
         k=1
         do j=1,ny
            do i=1,nx
               EXACTDATAPOINT
            end do
         end do
      end if

      if (cctk_bbox(6) .eq. 1) then 
         k=nz
         do j=1,ny
            do i=1,nx
               EXACTDATAPOINT
            end do
         end do
      end if

      return
      end