// Functions::findArrayIndicesWithinBoundaries()
//
// PURPOSE:
//      This function returns an array containing the indices of the input array that correspond
//      to the elements contained within the input boundaries.
//
// INPUT:
//      array:       an Eigen array whose indices we want to find
//      lowerBound:  a double specifying the smallest value allowed in the search
//      upperBound:  a double specifying the largest value allowed in the search
//
// OUTPUT:
//      a vector<int> containing the indices of the input array that correspond to its elements
//      that fall within the input boundaries.
//
// REMARKS:
//      There is no requirement for the input array to have its element sorted in any order.
//      The finding of the indices is done correctly independently of the sorting of the input array elements.
//


// Functions::countArrayIndicesWithinBoundaries()
//
// PURPOSE:
//      This function counts the number of elements of an input array that
//      fall within the input boundaries.
//
// INPUT:
//      array:       an Eigen array whose indices we want to find
//      lowerBound:  a double specifying the smallest value allowed in the search
//      upperBound:  a double specifying the largest value allowed in the search
//
// OUTPUT:
//      an integer containing the indices of the input array that correspond to its elements
//      that fall within the input boundaries.
//
// REMARKS:
//      There is no requirement for the input array to have its element sorted in any order.
//      The finding of the indices is done correctly independently of the sorting of the input array elements.
//


// Functions::cubicSplineInterpolation()
//
// PURPOSE:
//      This function computes a cubic spline interpolation of one-dimensional input data,
//      given a grid of new values we want the input data to be interpolated. The algorithm adopted is adapted
//      from Press W. et all, Numerical Recipes: The Art of Scientific Computing, 3rd Ed., 2007.
//
// INPUT:
//      observedAbscissa:                   an Eigen array containing the input data covariates to be used for the interpolation
//      observedOrdinate:                   an Eigen array containing the corresponding dependent variables of the input abscissa
//      interpolatedAbscissaUntruncated:    an Eigen array containing the values of the covariates for which we need to compute the
//                                          interpolated dependent variables. These values has not necessarily to be within the
//                                          observed bounds
//
// OUTPUT:
//      An eigen array of doubles containing the newly computed ordinates (dependent variables) of the corresponding
//      input grid of covariates for which the interpolation was required.
//
// REMARKS:
//      It is required that all input abscissa arrays contain values sorted in ascending order.
//      No extrapolation can be done.
//


// Functions::factorial()
//
// PURPOSE:
//      This function computes the factorial of an integer number. If the integer number is larger than 50, it relies on the
//      evaluation of factorial through the Ramanujan approximation (Ramanujan 1988).
//
// INPUT:
//      number:                   a positive integer number for which the factorial has to be computed
//
// OUTPUT:
//      A long double containing the factorial of the input number.
//
//


// Likelihood::Likelihood()
//
// PURPOSE:
//      Abstract base class constructor.
//
// INPUT:
//      observations: array containing the dependent variable values
//      model: object specifying the model to be used.
//


// FractionalDistanceMetric::FractionalDistanceMetric()
//
// PURPOSE:
//      Class constructor.
//
// INPUT:
//      fraction:           The fraction (usually in the interval [0,1]) to compute the
//                          corresponding norm. The norm has the expression
//                          ( sum_i^d (x_i - y_i)^f )^(1/f), where f is the fraction term,
//                          and d is the number of dimensions of the dataset.
//                          See Aggarwal et al. "On the Surprising Behavior of Distance Metrics
//                          in High Dimensional Space" for more details.


// Clusterer:Clusterer()
//
// PURPOSE:
//      Abstract base class constructor.
//
// INPUT:
//      metric : the metric class to define a metric for the computation of distances between pair of points.
//      featureProjector: the class to evaluate a feature projection of the dataset to cluster, in order to
//                        reduce its dimensionality.
//      featureProjectionActivated: a boolean variable to decide whether or not performing the feature projection.
//


// ZeroSampler::ZeroSampler()
//
// PURPOSE:
//      Constructor. Sets initial information, logEvidence and type
//      of prior and likelihood distributions to be used.
//
// INPUT:
//      printOnTheScreen:       Boolean value specifying whether the results are to
//                              be printed on the screen or not.
//      initialNlivePoints:        Initial number of live points to start the nesting process
//      minNlivePoints:            Minimum number of live points allowed in the nesting process
//      ptrPriors:              Vector of pointers to Prior class objects
//      likelihood:             Likelihood class object used for likelihood sampling.
//      metric:                 Metric class object to contain the metric used in the problem.
//      clusterer:              Clusterer class object specifying the type of clustering algorithm to be used.
//


// ZeroSampler::drawWithConstraint()
//
// PURPOSE:
//      Empty function not to be used.
//
// INPUT:
//      totalSample:                Eigen Array matrix of size (Ndimensions, NlivePoints)
//                                  containing the total sample of active points at a given nesting iteration
//      Nclusters:                  Optimal number of clusters found by clustering algorithm
//      clusterIndices:             Indices of clusters for each point of the sample
//      clusterSizes:               A vector of integers containing the number of points belonging to each cluster
//      drawnPoint:                 Eigen Array matrix of size (Ndimensions,Ndraws) to contain the
//                                  coordinates of the drawn point to be used for the next nesting loop.
//                                  When used for the first time, the array contains the coordinates of the
//                                  worst nested object to be updated.
//      maxNdrawAttempts:           Maximum number of attempts allowed when drawing from a single ellipsoid.
//
//
// OUTPUT:
//      A boolean value that is true if a new point in the sampling process is found and false otherwise.
//


// LivePointsReducer::findIndicesOfLivePointsToRemove()
//
// PURPOSE:
//          Picks one live point randomly and save its index.
//          Repeats the process up to the total number of live points to be removed.
//
// INPUT:
//          engine:     a Marsenne-Twister engine containing the clock seed for
//                      generating random numbers
//
// OUTPUT:
//          A vector to contain the indices of the live points to be removed.
//


// GaussianMixtureFreeSigmaLikelihood::logValue()
//
// PURPOSE:
//      Compute the natural logarithm of the normal likelihood for
//      a given set of observations, uncertainties and predictions.
//
// INPUT:
//      modelParameters: a one-dimensional array containing the actual
//      values of the free parameters that describe the model.
//
// OUTPUT:
//      a double number containing the natural logarithm of the
//      normal likelihood
//


// ZeroPrior::logDensity()
//
// PURPOSE:
//      Returns a -Infinity logDensity for any input coordinate.
//
// INPUT:
//      x:                   Point in which the log(pdf) should be evaluated.
//      includeConstantTerm: If true : compute the exact log(density),
//                           If false: ignore the constant terms (with factors of pi, 2, etc.)
//
// OUTPUT:
//      Natural logarithm of the probability density evaluation in x.
//


// NormalPrior:NormalPrior()
//
// PURPOSE:
//      Derived class constructor.
//
// INPUT:
//      mean:               array containing mean values for setting
//                          centroids of the multi-dimensional normal prior.
//      standardDeviation:  array containing SDV values of the
//                          multi-dimensional normal prior.
//


// NormalPrior::logDensity()
//
// PURPOSE:
//      Compute the logarithm of the probability density distribution evaluated in 'x'.
//
// INPUT:
//      x:                   Point in which the log(pdf) should be evaluated.
//      includeConstantTerm: If true : compute the exact log(density),
//                           If false: ignore the constant terms (with factors of pi, 2, etc.)
//
// OUTPUT:
//      Natural logarithm of the probability density evaluation in x.
//


// NormalPrior::drawnPointIsAccepted()
//
// PURPOSE:
//      Checks wheter a new drawn point to be verified is accepted
//      according to the prior distribution.
//
// INPUT:
//      drawnPoint:     an Eigen array containing the coordinates
//                      of the new drawn point to be verified
//
// OUTPUT:
//      Returns true if the new point is accepted, false if not.
//


// NormalPrior::draw()
//
// PURPOSE:
//      Draw a sample of parameters values from a normal prior
//      distribution. The parameters are in number Ndimensions
//      and contain Npoints values each.
//
// INPUT:
//      drawnSample:    two-dimensional Eigen Array to contain
//                      the resulting parameters values.
//
// OUTPUT:
//      void
//


// NormalPrior::drawWithConstraint()
//
// PURPOSE:
//      Replace an old set of parameters values with a new one
//      having higher likelihood value.
//
// INPUT:
//      drawnPoint: one-dimensional array containing the set of parameters
//                  values to be updated. Initially it should contain the coordinates
//                  of the point with the worst likelihood.
//      likelihood: an object to compute the likelihood values.
//
// OUTPUT:
//      void


// NormalPrior::writeHyperParametersToFile()
//
// PURPOSE:
//      Store prior hyper parameters in an output ASCII file.
//
// INPUT:
//      fullPath:     a string containing the full filename for the output ASCII file
//
// OUTPUT:
//      void
//


// File::openInputFile()
//
// PURPOSE:
//      Opens a file to read from and check its sanity
//
// INPUT:
//      inputFile: clean input stream
//      inputFileName: full path of the input file.
//
// OUTPUT:
//      void
//


// File::openOutputFile()
//
// PURPOSE:
//      Opens a file to write and check its sanity
//
// INPUT:
//      outputFile: clean output stream
//      outputFileName: full path of the output file.
//
// OUTPUT:
//      void
//


// File::arrayXXdToFile()
//
// PURPOSE: writes an Eigen ArrayXXd to an ascii file
//
// INPUT:
//      outputFile: output stream, assumed to be already opened and checked for sanity.
//      array: array to write to a file
//      separator: column separator, e.g. "  "
//      terminator: line terminator, e.g. "\n"
//
// OUTPUT:
//      - file contents is changed
//
// REMARKS:
//      - the stream is not closed afterwards
//      - this function can equally well be used to append to an existing file
//


// File::twoArrayXdToFile()
//
// PURPOSE:
//      Writes two Eigen::ArrayXd arrays as columns to an ascii file
//
// INPUT:
//      outputFile: output stream, assumed to be already opened and checked for sanity.
//      array1: array which will appear as the first column in the file
//      array2: array which will appear as the first column in the file
//      separator: column separator, e.g. "  "
//      terminator: line terminator, e.g. "\n"
//
// OUTPUT:
//      - file contents is changed
//
// REMARKS:
//      - overloaded function
//      - the stream is not closed afterwards
//      - this function can equally well be used to append to an existing file
//


// File::arrayXdToFile()
//
// PURPOSE:
//      Writes onw Eigen::ArrayXd arrays as a column to an ascii file
//
// INPUT:
//      outputFile: output stream, assumed to be already opened and checked for sanity.
//      array: array which will appear as a column in the file
//      terminator: line terminator, e.g. "\n"
//
// OUTPUT:
//      - file contents is changed
//
// REMARKS:
//      - the stream is not closed afterwards
//      - this function can equally well be used to append to an existing file
//


// File::sniffFile()
//
// PURPOSE:
//      Checks a file and derives the number of rows and columns
//
// INPUT:
//      inputFile: input stream, assumed to be already opened and checked for sanity.
//      separator: column separator, e.g. "  "
//      Nrows: see output
//      Ncols: see output
//
// OUTPUT:
//      - Nrows will contain the number of rows
//      - Ncols will constina the number of columns
//
// REMARKS:
//      - the stream is not closed afterwards, but it is rewinded.
//


// ZeroClusterer::cluster()
//
// PURPOSE:
//      Empty function, not used when building a ZeroClusterer object
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      optimalClusterIndices(Npoints): for each point the index of the cluster it belongs to. This index
//                                      runs from 0 to Nclusters-1.
//      optimalClusterSizes(Nclusters): for each of the clusters, this vector contains the number of points
//
// OUTPUT:
//      An integer equal to zero.
//


// KmeansClusterer::KmeansClusterer()
//
// PURPOSE:
//      Constructor.
//
// INPUT:
//      metric: this class is used to compute the squared distance between two points
//      featureProjector: this class is used to compute a dimensionality reduction of the input sample of points
//      featureProjectionActivated: a boolean to activate or deactivate the dimensionality reduction through the featureProjector class
//      minNclusters: the minimum number of clusters that is to be fitted
//      maxNclusters: the maximum number of clusters that is to be fitted
//      Ntrials: as k-means is sensitive to the initial choice of the cluster centers,
//               repeat k-means with different trials of initial centers, and pick the best one.
//      relTolerance: fitting the clusters converged when S < relTolerance, where S is the relative
//                    change in total sum of distances of all points to their cluster center.
//


// KmeansClusterer::chooseInitialClusterCenters()
//
// PURPOSE:
//      Choose semi-randomly the initial centers of the clusters among the sample
//      of points given
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      center(Ndimensions, Nclusters): set of N-dimensional coordinates of the cluster centers
//
// OUTPUT:
//      void
//


// KmeansClusterer::updateClusterCentersUntilConverged()
//
// PURPOSE:
//      Evolve the cluster centers according to the k-means algorithm. Given a set of cluster
//      centers, gather for each center the sample points that are closest to it, and use
//      the barycenter of these gathered points as the updated cluster center. And so on.
//
// INPUT:
//      sample(Ndimensions, Npoints):   sample of N-dimensional points
//      center(Ndimensions, Nclusters): set of N-dimensional coordinates of the cluster centers
//      clusterSizes(Nclusters):        for each cluster, the number of points it contains
//      clusterIndices(Npoints):        for each point the index of the cluster it belongs to. This index
//                                      runs from 0 to Nclusters-1.
//      sumOfDistancesToClosestCenter:  the sum over all points of their distance to the closest
//                                      cluster center (i.e. the center of the cluster to which they
//                                      belong).
//      relTolerance:                   fitting the clusters converged when S < relTolerance, where S
//                                      is the relative change in total sum of distances of all points
//                                      to their cluster center.
//
// OUTPUT:
//      True if the convergence of k-means was successful, false otherwise. A convergence is
//      considered successful if the relTolerance-criterion is satisfied (see above), _and_ if
//      all clusters contain at least 2 points.


// KmeansClusterer::evaluateBICvalue()
//
// PURPOSE:
//      Given a cluster configuration, evaluate its Bayesian Information Criterion value
//      assuming that the clusters are a gaussian mixture of spherical Gaussians.
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      center(Ndimensions, Nclusters): set of N-dimensional coordinates of the cluster centers
//      clusterSizes(Nclusters): for each cluster, the number of points it contains
//      clusterIndices(Npoints): for each point the index of the cluster it belongs to. This index
//                               runs from 0 to Nclusters-1.
//
// OUTPUT:
//      BIC value: - 2 ln(L) + k ln(N) up to constant terms
//


// KmeansClusterer::cluster()
//
// PURPOSE:
//      Given a sample of N-dimensional points, use the k-means clustering algorithm + BIC
//      to determine the optimal number of clusters that can be fitted to the data.
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      optimalClusterIndices(Npoints): for each point the index of the cluster it belongs to. This index
//                                      runs from 0 to Nclusters-1.
//      optimalClusterSizes(Nclusters): for each of the clusters, this vector contains the number of points
//
// OUTPUT:
//      The optimal number of clusters
//


// Functions::preparePriorDistributions()
//
// PURPOSE:
//      This function builds up mixed prior distributions by reading the hyper parameters and prior types from
//      an input file. The file has to be in a five-columns format, where the first four are related to the prior
//      hyper parameters and the last one to the prior type.
//      The prior type is specified through a flag: 0 for Uniform, 1 for Gaussian, 2 for Super Gaussian,
//      3 for Grid Uniform. Each line of the file will refer to a different free parameter of the model and
//      it can be specified with its own prior type. The prior hyper parameters are defined in the order listed below.
//
//      Uniform prior:
//      Col 1: lower boundary, Col 2: upper boundary, Col 3: 0, Col 4: 0
//
//      Gaussian prior:
//      Col 1: mean value, Col 2: standard deviation, Col 3: 0, Col 4: 0
//
//      Super Gaussian prior:
//      Col 1: mean value, Col 2: standard deviation, Col 3: width of plateau
//
//      Grid Uniform prior:
//      Col 1: starting point of the grid, Col 2: ending point of the grid, Col 3: number of grid points, Col 4: tolerance (0-1)
//
// INPUT:
//      inputFileName:                   a string containing the name (with full path) for the file containing the prior
//                                       hyper parameters and types
//      outputPathPrefix:                a string containing the full path of the output file of the hyper parameters
//      Ndimensions:                     an empty integer variable to contain the number of free parameters identified
//      writePriorHyperParametersToFile: a boolean to specify whether or not the prior hyper parameters (and prior types)
//                                       must be stored in an output ASCII file
//
// OUTPUT:
//      A vector of pointers to prior class object that will contain the prior distributions
//
// REMARK:
//      The function operates also with a two-column format input file in the case of uniform prior distribution
//      for all the free parameters.
//


// Ellipsoid::Ellipsoid()
//
// PURPOSE:
//      Class constructor.
//
// INPUT:
//      sample:                 Eigen Array of size (Ndimensions, sampleSize),
//                              containing the coordinates of the points inside the ellipsoid.
//      enlargementFraction:    Initial enlargement fraction to compute the ellipsoids for the first time
//


// Ellipsoid::resetEnlargementFraction()
//
// PURPOSE:
//      Compute covariance matrix, center coordinates,
//      eigenvalues and eigenvectors matrix of the ellipsoid.
//      Eigenvalues are automatically enlarged according to the
//      enlargementFraction term.
//
// INPUT:
//      newEnlargementFraction:  a double to contain the new enlargement
//                               fraction to be used for the chosen ellipsoid.
//
// OUTPUT:
//      void


// Ellipsoid::overlapsWith()
//
// PURPOSE:
//      Determines whether this ellipsoid overlaps with the given ellipsoid.
//      The algorithm used is the one described by Alfano & Greer (2003;
//      Journal of Guidance, Control and Dynamics, 26, 1).
//
// INPUT:
//      ellipsoid:                                  Ellipsoid object
//      ellipsoidMatrixDecompositionIsSuccessful:   a boolean specifying if the decomposition of
//                                                  the ellipsoid matrix was successful
//
// OUTPUT:
//      A boolean value specifying whether the two ellipsoids overlap (true) or not (false)
//
// REMARKS:
//      The coordinate system used by the ellipsoid in the argument must be the same as the
//      one used by this ellipsoid. This is relevant to know which coordinate corresponds to
//      which column in the covariance matrices of the ellipsoids.
//


// Ellipsoid::containsPoint()
//
// PURPOSE:
//      Determines if this ellipsoid contains the given point
//
// INPUT:
//      pointCoordinates: coordinates of the point to verify.
//
// OUTPUT:
//      'true' if the point falls within the (possibly enlarged) boundaries
//      of this ellipsoid, 'false' otherwise.
//


// Ellipsoid::drawPoint()
//
// PURPOSE:
//      Draw a random point inside this ellipsoid. The algorithm used is the one
//      described by Shaw J. R. et al. (2007; MNRAS, 378, 1365). First a point is
//      drawn from the unit hypersphere, whose coordinates are then transformed
//      to land into the ellipsoid.
//
//
// INPUT:
//      drawnPoint: Eigen Array that will contain the N-dimensional coordinates of the
//                  newly drawn point.
//
// OUTPUT:
//      void
//


// Prior::Prior()
//
// PURPOSE:
//      Abstract base class constructor. Sets the dimensions
//      of the parameter space.
//
// INPUT:
//      Ndimensions : integer containing the number of dimensions, i.e.
//                    the number of free parameters of the problem.
//


// PrincipalComponentProjector:PrincipalComponentProjector()
//
// PURPOSE:
//      Class constructor for the derived class PrincipalComponent of the Projector abstract based class.
//
// INPUT:
//      printNdimensions: a boolean specifying whether one wants the reduced number
//      of dimensions to be explicitly printed on the screen.
//      scalingFactor: a double specifying the value of the scaling of the average eigenvalue (according to the correction
//      applied by Jolliffe to the Kaiser-Guttman test. A value of 0.7 is set by default.
//


// PrincipalComponentProjector::projection()
//
// PURPOSE:
//      Given a sample of N-dimensional points, use the linear Principal Component Analysis
//      to identify the principal components (PCs) of the original dataset. Subsequently select
//      only those component that contain the largest amount of variance in the data through the
//      Kaiser-Guttman test, modified by Jolliffe (1972) to consider PCs having eigenvalues > 70% of the average eigenvalue.
//
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//
// OUTPUT:
//      The reduced k-dimensional sample, with k <= N, but having the same number of points.
//


// FerozReducer::FerozReducer()
//
// PURPOSE:
//      Derived class constructor.
//
// INPUT:
//      nestedSampler:  a NestedSampler class object used as the container of
//                      information to use when reducing the number of live points.
//      tolerance:      a double containing the tolerance on the evidence. The lower the factor
//                      the more live points are removed at each iteration.
//


// FerozReducer::updateNlivePoints()
//
// PURPOSE:
//      Updates the number of live points for the next iteration of the nesting process.
//      For this case, the equation adopted is that used by
//      Feroz F. et al. (2009), MNRAS, 398, 1601.
//
// OUTPUT:
//      An integer specifying the final number of live points to be adopted.
//
// REMARK:
//      The returned value of live points is ensured to be not below the minimum allowed.
//


// MeanNormalLikelihood::MeanNormalLikelihood()
//
// PURPOSE:
//      Derived class onstructor.
//
// INPUT:
//      observations: array containing the dependent variable values
//      uncertainties: array containing the uncertainties of the observations
//      model: object specifying the model to be used.
//


// MeanNormalLikelihood::logValue()
//
// PURPOSE:
//      Compute the natural logarithm of the mean normal likelihood for
//      a given set of observations, uncertainties and predictions.
//      The mean normal likelihood is a normal likelihood whose uncertainties
//      have been integrated away by means of a Jeffrey's prior.
//      For more details cf. Froehlich H.-E. et al. 2009, A&A, 506, 263.
//
// INPUT:
//      modelParameters: a one-dimensional array containing the actual
//      values of the free parameters that describe the model.
//
// OUTPUT:
//      a double number containing the natural logarithm of the
//      mean likelihood
//


// UniformPrior::UniformPrior()
//
// PURPOSE:
//      Derived class constructor.
//
// INPUT:
//      minima:     array containing minimum values for setting
//                  lower bounds of the free parameters.
//      maxima:     array containing maximum values for setting
//                  upper bounds of the free parameters.
//


// UniformPrior::logDensity()
//
// PURPOSE:
//      Compute the logarithm of the probability density distribution evaluated in 'x'.
//
// INPUT:
//      x:                   Point in which the log(pdf) should be evaluated.
//      includeConstantTerm: If true : compute the exact log(density),
//                           If false: ignore the constant terms (with factors of pi, 2, etc.)
//
// OUTPUT:
//      Natural logarithm of the probability density evaluation in x.
//


// UniformPrior::drawnPointIsAccepted()
//
// PURPOSE:
//      Checks whether a new drawn point to be verified is accepted
//      according to the prior distribution.
//
// INPUT:
//      drawnPoint:     an Eigen array containing the coordinates
//                      of the new drawn point to be verified
//
// OUTPUT:
//      Returns true if the new point is accepted, false if not.
//


// UniformPrior::draw()
//
// PURPOSE:
//      Draw a sample of parameters values from a uniform prior
//      distribution. The parameters are in number Ndimensions
//      and contain Npoints values each.
//
// INPUT:
//      drawnSample:    two-dimensional Eigen Array to contain
//                      the resulting parameters values.
//
// OUTPUT:
//      void
//


// UniformPrior::drawWithConstraint()
//
// PURPOSE:
//      Replace an old set of parameters values with a new one
//      having higher likelihood value.
//
// INPUT:
//      drawnPoint:     one-dimensional Eigen Array containing the set of
//                      parameters values to be updated.
//      likelihood:     an object to compute the corresponding likelihood value.
//
// OUTPUT:
//      void
//
// NOTE:
//      parameters refers to the worst object identified in the nested
//      sampling loop. Thus, the array contains Ndimensions elements.
//


// UniformPrior::writeHyperParametersToFile()
//
// PURPOSE:
//      Store prior hyper parameters in an output ASCII file.
//
// INPUT:
//      fullPath:     a string containing the full filename for the output ASCII file
//
// OUTPUT:
//      void
//


// GeneralizedNormalLikelihood::GeneralizedNormalLikelihood()
//
// PURPOSE:
//      Derived class onstructor.
//
// INPUT:
//      observations: array containing the dependent variable values
//      observationsUncertainties: array containing the uncertainties of the observations
//      model: object specifying the model to be used.
//


// GeneralizedNormalLikelihood::logValue()
//
// PURPOSE:
//      Compute the natural logarithm of the normal likelihood for
//      a given set of observations, uncertainties and predictions of a
//      multilinear model. In this case, also uncertainties depend upon
//      the free parameters of the model.
//
// INPUT:
//      modelParameters: a one-dimensional array containing the actual
//      values of the free parameters that describe the model.
//      For this version of the normal likelihood, it is required
//      that the last element of the modelParameters is the free parameter of the offset and
//      that the remainder of the elements are divided in two groups, the first one related to
//      the multi-linear part of the model, and the second one related to the polynomial part of the model.
//
// OUTPUT:
//      a double number containing the natural logarithm of the
//      normal likelihood
//


// ZeroLikelihood::logValue()
//
// PURPOSE:
//      Returns a zero value for the likelihood, which implies
//      a -infinity for its natural logarithm.
//
// INPUT:
//      modelParameters: a one-dimensional array containing the actual
//      values of the free parameters that describe the model.
//
// OUTPUT:
//      a double number containing the natural logarithm of zero.
//


// GaussianMixtureClusterer::GaussianMixtureClusterer()
//
// PURPOSE:
//      Constructor.
//
// INPUT:
//      metric: this class is used to compute the squared distance between two points
//      featureProjector: this class is used to compute a dimensionality reduction of the input sample of points
//      featureProjectionActivated: a boolean to activate or deactivate the dimensionality reduction through the featureProjector class
//      minNclusters: the minimum number of clusters that is to be fitted
//      maxNclusters: the maximum number of clusters that is to be fitted
//      Ntrials: as k-means is sensitive to the initial choice of the cluster centers,
//               repeat k-means with different trials of initial centers, and pick the best one.
//      relTolerance: fitting the clusters converged when dp < relTolerance, where dp is the relative
//                    change in the total likelihood of the Gaussian Mixture Model as a function of the iterations.
//


// GaussianMixtureClusterer::chooseInitialClusterCenters()
//
// PURPOSE:
//      Choose semi-randomly the initial centers of the clusters among the sample
//      of points given
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      center(Ndimensions, Nclusters): set of N-dimensional coordinates of the cluster centers
//      Nclusters: number of clusters considered
//
// OUTPUT:
//      void
//


// GaussianMixtureClusterer::chooseInitialClusterCovarianceMatrices()
//
// PURPOSE:
//      Choose the initial covariance matrices for each cluster by using the set of cluster
//      centers found previously.
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      center(Ndimensions, Nclusters): set of N-dimensional coordinates of the cluster centers
//      covarianceMatrices(Ndimensions,Nclusters*Ndimensions): set of Nclusters N-dimensional covariance matrices for the clusters
//      Nclusters: number of clusters considered
//
// OUTPUT:
//      void
//


// GaussianMixtureClusterer::computeGaussianMixtureModel()
//
// PURPOSE:
//      Choose the initial covariance matrices for each cluster by using the set of cluster
//      centers found previously. Assume amplitudes of individual Gaussians are defined from outside.
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      center(Ndimensions, Nclusters): set of N-dimensional coordinates of the cluster centers
//      covarianceMatrices(Ndimensions,Nclusters*Ndimensions): set of Nclusters N-dimensional covariance matrices for the clusters
//      Nclusters: number of clusters considered
//
// OUTPUT:
//      void
//


// GaussianMixtureClusterer::updateClustersUntilConverged()
//
// PURPOSE:
//      Evolve the cluster centers and covariance matrices according to the Gaussian Mixture Model.
//      Given a set of cluster centers and covariance matrices, compute the corresponding GMM.
//      Then perform a weighted sum of the differences (between each point and the cluster centers) for each cluster,
//      so that the cluster center and covariance matrix can be updated.
//      The weights are in this case the assignment probabilities for each point to belong
//      to a given cluster, according to the definition of the GMM.
//
// INPUT:
//      sample(Ndimensions, Npoints):   sample of N-dimensional points
//      center(Ndimensions, Nclusters): set of N-dimensional coordinates of the cluster centers
//      clusterSizes(Nclusters):        for each cluster, the number of points it contains
//      clusterIndices(Npoints):        for each point the index of the cluster it belongs to. This index
//                                      runs from 0 to Nclusters-1.
//      relTolerance:                   fitting the clusters converged when S < relTolerance, where S
//                                      is the relative increment in total logarithm of GMM probability
//
// OUTPUT:
//      True if the convergence of k-means was successful, false otherwise. A convergence is
//      considered successful if the relTolerance-criterion is satisfied (see above), _and_ if
//      all clusters contain at least 2 points.


// GaussianMixtureClusterer::searchForEmptyClusters()
//
// PURPOSE:
//      Use the optimal solution from the Gaussian Mixture Model clustering algorithm
// based on Expectation Maximization to determine whether a cluster exist without points inside.
//
// OUTPUT:
//      void
//


// GaussianMixtureClusterer::obtainClusterMembership()
//
// PURPOSE:
//      Given a sample of N-dimensional points, use the optimal solution from the Gaussian Mixture Model clustering algorithm
// based on Expectation Maximization to determine the cluster membership of each sample point, as well as
// the number of points contained in each cluster.
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      optimalClusterIndices(Npoints): for each point the index of the cluster it belongs to. This index
//                                      runs from 0 to Nclusters-1.
//      optimalClusterSizes(Nclusters): for each of the clusters, this vector contains the number of points
//      optimalAssignmentProbabilities(Npoints, Nclusters): assignment probabilities for each sample point according to each cluster
//
// OUTPUT:
//      void
//


// GaussianMixtureClusterer::cluster()
//
// PURPOSE:
//      Given a sample of N-dimensional points, use the Gaussian Mixture Model clustering algorithm based on
//      Expectation Maximization to determine the optimal number of clusters that can be fitted to the data.
//
// INPUT:
//      sample(Ndimensions, Npoints): sample of N-dimensional points
//      optimalClusterIndices(Npoints): for each point the index of the cluster it belongs to. This index
//                                      runs from 0 to Nclusters-1.
//      optimalClusterSizes(Nclusters): for each of the clusters, this vector contains the number of points
//
// OUTPUT:
//      The optimal number of clusters
//


// PowerlawReducer::PowerlawReducer()
//
// PURPOSE:
//      Derived class constructor.
//
// INPUT:
//      nestedSampler:      a NestedSampler class object used as the container of
//                          information to use when reducing the number of live points.
//      exponent:           a double specifying the rate of the reduction process. For this
//                          specific case, this number either enhances or smoothes the effect
//                          of the power law reduction. It is a number >= 0.
//                          Default is 1 meaning that a standard linear reduction occurs.
//                          If > 1 the reduction is suoer-linear, hence faster, and if
//                          < 1 the reduction is sub-linear, hence slower.
//      terminationFactor:  the fraction of remainder evidence to gained evidence used to terminate
//                          the nested iteration loop. This value is also used as a tolerance on the final
//                          evidence to update the number of live points in the nesting process.
//


// PowerlawReducer::updateNlivePoints()
//
// PURPOSE:
//      Updates the number of live points for the upcoming iteration of the nesting process.
//      For this case, the exponential expression adopted allows to start reducing live points
//      after the tolerance on the ratio of the live to the cumulated evidence has been reached.
//
// OUTPUT:
//      An integer specifying the final number of live points to be adopted.
//
// REMARK:
//      The returned value of live points is ensured to be not below the minimum allowed.
//


// SuperGaussianModel::predict()
//
// PURPOSE:
//      Builds the predictions from a model incorporating a super Gaussian function with free parameters
//      mean, half width of the plataeu region, standard deviation of the tails, and amplitude.
//
// INPUT:
//      predictions:        one-dimensional array to contain the predictions
//                          from the model
//      modelParameters:    one-dimensional array where each element
//                          contains the value of a free parameter of the model
//
// OUTPUT:
//      void
//


/*---------------------------------------------------------------------------*/
// Purely dynamical differential equations (see AG2012, s2 & GALB2013, s2)


/*---------------------------------------------------------------------------*/
//Dynamical Dimensionless Parameter Equations (see AG2012, s2 & GALB2013, s2,3)


/*---------------------------------------------------------------------------*/
//Extra required parameter equations (see AG2012, s2 & AGLB2013, s2,3)


/*---------------------------------------------------------------------------*/
// Purely SE differential equations (AGLB2013, s?)


/*---------------------------------------------------------------------------*/
//Dynamical SE Parameter Equations (AGLB2013, s?)


/*Contains 'fixed' data for the simulation, ie, the optimised parameters that
    are used by EMACSS to mimic the evolution of a star cluster. These are
    designed to be user-adjustable, but are set here as a reference, and to
    represent optimal values recovered in AG2012, GALB2013 and AGLB2014.*/


/*Readme and help files these are not essential for program operation, but
 contain a guide for use, version information, and sufficient documentation
 for basic usage. For full instruction, see Alexander and Gieles 2012 and
 Alexander, Gieles and Lamers 2013.*/


// TODO: replace with Grackle's existing err machinery


/// closes the current file descriptor associated with fd and then opens a new
/// file descriptor (reusing the same integer) that points to a temporary file.
/// The temporary file will be deleted once all file descriptors to it are
/// closed.
///
/// @returns
/// true and false indicates success and failure


// if we want to avoid heap-allocations, we could use std::optional


// since the class is primary intended to capture stderr, we eagerly abort if
// things go wrong (why even go on if testing is crippled?)


// allocates the grackle_field_data struct


// check that all elements in ref and actual that correspond to ghost cells
// are identical.


/// return randomly drawn double-precision value drawn from the uniform
/// distribution over the interval [0.0, 1.0).


/// try to parse a string that holds a file where each line has the format
/// "<member_name>, <member_type>" and create a MemberTypeNameMap
///
/// @note
/// although std::regex is known to be **VERY** slow, it is convenient


/// Reads the previously generated xml-file (produced by the build-system with
/// the castxml tool) to determine the data-members of a struct. Returns a
/// std::map that maps the names of data-members to their type. The result of
/// this function is used for checking the correctness of functionallity that
/// effectively implements "manual reflection" of the struct's members.
///
/// @returns a non-empty error-message to denote **any** errors
///
/// In more detail, this function has 2 phases:
/// 1. we check if a valid file was written by build-system
/// 2. a python script is invoked to extract relevant information from the xml
///    file (it uses python's builtin xml-parsing library)
/// 3. we read in the extracted information and put it into the output format
///
/// @note
/// In the future, we'll be able to replace this with a simplified alternative:
/// - For example, we could use 1 of the following lightweight librarie to
///   directly infer members of aggregates (this includes C structs,
///   https://en.cppreference.com/w/cpp/language/aggregate_initialization) at
///   compile-time (using compiler-extensions)
///   - https://github.com/boostorg/pfr  (this doesn't need the rest of boost)
///   - https://github.com/stephenberry/glaze
/// - Alteratively, C++26 is on track to make "reflection" of fields a standard
///   C++ feature.


/// an empty string indicates that the mappings are consistent


/* set levels and masses */


/* function to check ODE solver-related function return values */


/**********************************************
/* orbital element/vector conversion routines *
 **********************************************/


// ----- interpolate over t at specific theta index ----- //


// weighted average models


/* ==================================== */
/* Abort - Print error message and exit */
/* ==================================== */


/* ============================== */
/* Calculate Legendre Polynomials */
/* ============================== */


/* ============================================= */
/* Calculate Derivatives of Legendre Polynomials */
/* ============================================= */


/* ------------------------------------------------------ */
/* Check file OutRep and decode level number and truncation */
/* ------------------------------------------------------ */


//compute mean of an array


//compute mean day length per month


//Compute mean day length per month in units of 12 hours


////Calculate Hamon PET


//Update interception and melt rates based on canopy


//Water balance calculation
// [[Rcpp::export]]


/*!
    @brief checks whether the container is empty.

    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).

    @return The return value depends on the different types and is
            defined as follows:
            Value type  | return value
            ----------- | -------------
            null        | `true`
            boolean     | `false`
            string      | `false`
            number      | `false`
            binary      | `false`
            object      | result of function `object_t::empty()`
            array       | result of function `array_t::empty()`

    @liveexample{The following code uses `empty()` to check if a JSON
    object contains any elements.,empty}

    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
    the Container concept; that is, their `empty()` functions have constant
    complexity.

    @iterators No changes.

    @exceptionsafety No-throw guarantee: this function never throws exceptions.

    @note This function does not return whether a string stored as JSON value
    is empty - it returns whether the JSON container itself is empty which is
    false in the case of a string.

    @requirement This function helps `basic_json` satisfying the
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
    requirements:
    - The complexity is constant.
    - Has the semantics of `begin() == end()`.

    @sa see @ref size() -- returns the number of elements

    @since version 1.0.0
    */


/**
 * return the distance between point0 and point1
 */


/**
 * Find the nearest neigbors of all the points (specified with
 * x, y and z).
 *
 * Fills the n1, n2 and n3 arrays with the closest, second clostest
 * and third closests points.
 *
 **/


// Compute a single Eulerian gravity step


/* This routine computes mass loss */
/* age is given in units of MS time */


//-----------------------------------------------------------------------------
//  pgetopt  --  each call to  pgetopt()  returns the next option encountered
//               on the command line, starting from the beginning. If the
//               option occurs in the  optstr  string as well, the option
//               itself is returned (as the int value of the character;
//               options are limited to one char). Otherwise, the character '?'
//               is returned. If the end of the string is reached, the value
//               -1 is returned.  If an option is followed by the character ':'
//               in  optstr , then a command line argument is expected,
//               separated by spaces. If such an argument if found, the pointer
//                poptarg  is pointed at that string, so that the calling
//               function can access the argument.  If such an argument is not
//               found, an error message is given.
//
//		 ..............................................................
//
//		 See above note for extension to this scheme, as of 8/99.
//		 Also added optional arguments, indicated by "." in optstr.
//
//		 Optional arguments *may not* start with "-", as that character
//		 is used to identify the start of the next option string...
//
//		 ..............................................................
//
//		 This function is quite unforgiving of errors in the format
//		 of the command line.  In typical use, there is no check in
//		 the calling program that poptarg (etc.) are properly set, or
//		 that the number of arguments is correct.  No default values
//		 are set, and errors generally cause the program to stop
//		  -- caveat emptor!
//
//               NOTE: The option "-version" or "--version" to any Starlab
//                     program is legal, and will result in the program
//                     printing the current Starlab and CVS versions on
//                     cout and terminating.
//
//----------------------------------------------------------------------------


/* this routine build a void stellar model */


// Setup and parameters.


// Setters and getters for individual particles.


// add_node: Insert node n into the tree before (i.e. as the older
//	     sister of) node m.  Set pointers only.  Don't adjust
//	     masses or dynamics.


// detach_node: Detach node n from the tree.  Do not check whether the
//		parent has more than two remaining daughters.  Set
//		pointers only.  Don't adjust dynamics, and don't
//		correct the parent mass.


// should also be bj->get_parent()


// Construct summary and state strings describing the system.


//----------------------------------------------------------------------
// Externally visible functions:


//----------------------------------------------------------------------------
//  keplerseq  --  solve Kepler's equation by iteration, for elliptic orbits
//		   litt: H. Goldstein (1980), Classical Mechanics, eq. (3-76);
//  			 S.W. McCuskey (1963), Introduction to Celestial
//					       Mechanics, Sec. 3-7.
//		   method: true_an follows from ecc_an, which is determined
//			   by inverting Kepler's equation:
//			   mean_an = ecc_an - ecc * sin(ecc_an)
//
//                 Note that ecc = 1 is OK (linear bound orbit).
//
//----------------------------------------------------------------------------
//


//----------------------------------------------------------------------------
//  keplershypeq  --  solves Kepler's equation by iteration: hyperbolic orbits
//		      litt: S.W. McCuskey (1963), Introduction to Celestial
//					          Mechanics, Sec. 3-10.
//		      method: true_an follows from ecc_an, which is determined
//			      by inverting the hyperbolic analog of
//			      Kepler's equation:
//			      mean_an = -ecc_an + ecc// sinh(ecc_an)
//
//                 Note that ecc = 1 is OK (linear unbound orbit).
//
//----------------------------------------------------------------------------


//----------------------------------------------------------------------------
//  keplerspareq  --  solves Kepler's equation for parabolic orbits
//		      litt: S.W. McCuskey (1963), Introduction to Celestial
//					          Mechanics, Sec. 3-9.
//		      method: true_an (f) is determined by inverting the
//                            parabolic analog of Kepler's equation:
//			      mean_an = tan(f/2)// (1 + tan(f/2)*tan(f/2) / 3)
//----------------------------------------------------------------------------


// Basic Kepler class member functions:
// -----------------------------------


//----------------------------------------------------------------------------
//  kepler::pred_true_to_mean_anomaly  --  sign conventions:
//                                    elliptic orbit:
//                                      mean anomaly will return with a value
//					in (-pi, pi), independent of the
//                                      initial sign of the true anomaly.
//                                    parabolic or hyperbolic orbit:
//                                      both true and mean anomaly will return
//                                      with the same sign as the initial true
//                                      anomaly.
//                                    linear orbit:
//                                      true_anomaly is not defined, so assume
//                                      that true_anomaly = eccentric_anomaly
//                                      on entry.
//
//----------------------------------------------------------------------------


//----------------------------------------------------------------------------
//  kepler::mean_anomaly_to_periastron_passage  --  sign conventions:
//                                    elliptic orbit:
//                                      the previous function
//                                      pred_true_to_mean_anomaly() will
//                                      guarantee that the mean anomaly is
//                                      already positive.
//                                      The time_of_periastron_passage is the
//                                      time of the previous periastron
//                                      passage.
//                                    hyperbolic orbit:
//                                      the previous function
//                                      pred_true_to_mean_anomaly() allows
//                                      either sign for the mean anomaly.
//                                      The time_of_periastron_passage is the
//                                      time of the one and only periastron
//                                      passage, which may be either in the
//                                      past or in the future with respect to
//                                      the present time `time'.
//----------------------------------------------------------------------------


// New kepler member functions (Steve, 6/01):


// Modified kepler member function (Steve, 6/01):


// Align_with_axes: initialize the right-handed triad (l, t, n) with the
//		    longitudinal unit vector l pointing along the specified
// 		    axis (note that x, y, z = 1, 2, 3, Piet).


// initialize_from_pos_and_vel: start with time, mass, position and velocity
//				and determine all other orbital properties.


// Convention: on input, specify semi-major axis > 0 and eccentricity.  If
//             eccentricity = 1, look at periastron to distinguish a parabola
//             from a linear orbit.  If the orbit is linear, use the sign of
//             the energy to distinguish a bound from an unbound orbit.


// initialize_from_integrals_and_separation:  start with time, mass, energy,
//				    angular momentum, and separation, and
//				    determine all other orbital properties.
//
// Does not set unit vectors, so those must be specified beforehand in order
// for rel_pos and rel_vel to be defined.


// make_standard_kepler: set standard properties for an existing
//			 kepler structure.   By default, the new
//			 orbit is in the x-y plane, with the major
//			 axis in the x direction.


// For small systems, probably OK just to search the list to find a
// particle with a given index.


// srandinter:  Accept a seed to start up randunit.
//              If seed = 0, then a positive number is chosen, which
//              is unique if no other call to srandinter is made within
//              2.0 seconds of the current call (the UNIX clock is used,
//              which returns the time in seconds).
//              The return value is the actual value of the seed (either
//              the specified non-zero value, or the clock time+PID).


// randinter:  Return a random real number within an interval [a,b]
//	       by invoking a standard random number generator.


//----------------------------------------------------------------------
//
// Check if a collision occurs before time t.


//----------------------------------------------------------------------
//
// Advance the components of a binary to the specified time.


// Take the next step.  Return the actual system time at the end of
// the step, after symmetrization if specified.  Starting time step is
// dt.


// cout << "correcting" << endl << flush;


// Complete the step.


//-----------------------------------------------------------------------------
//  write_diagnostics  --  writes diagnostics on the output stream cout:
//                         current time; total mass; number of
//                         integration steps so far; kinetic,
//                         potential, and total energy; absolute and
//                         relative energy errors since the start of
//                         the run.  If x_flag (x for eXtra data) is
//                         true, all internal data are dumped for each
//                         particle (mass, position, velocity,
//                         acceleration, and jerk).
//
//  Note: the kinetic energy is calculated here, while the potential
//  energy is calculated in the function get_acc_jerk_pot_coll().
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//  predict_step  --  take the first approximation of one Hermite integration
//                    step, advancing the positions and velocities through a
//                    Taylor series development up to the order of the jerks.
//                    Note that all pos and vel are overwritten.
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//  correct_step  --  take one iteration to improve the new values of
//                    position and velocities, constructing a higher-order
//                    Taylor series from the terms up to jerk at the
//                    beginning and the end of the time step.  This symmetric
//                      formulation is not the original one from Makino and
//                      Aarseth; it comes from ACS (Hut & Makino).
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//  evolve_step  --  take one integration step for an N-body system, using
//                   the Hermite algorithm.
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//  evolve_system -- integrate an N-body system to time t_end.
//                   Diagnostics are sent to cout every time interval dt_dia.
//
//  Note: the integration time step, shared by all particles at any given time,
//        is variable.  Before each integration step we use coll_time (short
//        for collision time, an estimate of the time scale for any significant
//        change in configuration to happen), multiplying it by dt_param (the
//        accuracy parameter governing the size of dt in units of coll_time),
//        to obtain the new time step size.
//
//  Before moving any particles, we start with an initial diagnostics output
//  and snapshot output if desired.  In order to write the diagnostics, we
//  first have to calculate the potential energy, with get_acc_jerk_pot_coll().
//  That function also calculates accelerations, jerks, and an estimate for the
//  collision time scale, all of which are needed before we can enter the main
//  integration loop below.
//
//  The main loop takes as many integration time steps as needed to
//  reach the next output time, does the output required, then
//  continues taking integration steps and invoking output in this way
//  until the final time is reached, which triggers a `break' out of
//  the infinite loop set up with `while(true)'.
//
//-----------------------------------------------------------------------------


//Initialise the code


// req: 26.5.1.4 Random number engine requirements, p.907 table 117, row 2
// Creates an engine that compares equal to x.


// req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 5


// req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 6
// s needs to be of return_type, which is uint32_t


//~int new_black_hole(int *particle_identifier, double mass,
//~double x, double y, double z, double vx, double vy, double vz, double radius) {
//~dynamics_state new_p;
//~
//~// Particle is stored in the buffer until (re)commit_particles is called
//~particle_id_counter++;
//~*particle_identifier = particle_id_counter;
//~new_p.mass = mass;
//~new_p.radius = radius;
//~new_p.x = x;
//~new_p.y = y;
//~new_p.z = z;
//~new_p.vx = vx;
//~new_p.vy = vy;
//~new_p.vz = vz;
//~black_hole_buffer.insert(pair<int, dynamics_state>(*particle_identifier, new_p));
//~return 0;
//~}


//static int Ndestroy = 0;
//static int Ndestroy_loop = 0;


/////////////////////////////
///// forces from SMBH //////
/////////////////////////////


/*
Initialize the GPU library

SHOULD BE CALLED FIRST! AND ONLY ONCE!

*/


/*
Set time of the prediction

time = time to which particles are predicted
nj = amount of particles that are predicted

*/


/*

Do not execute prediction, but only copy the particles
into the predicted buffers.

*/


/*

Return the predicted values for a particle at an address

addr = address of the particle

pos = buffer to store predicted position
vel = buffer to store predicted velocity
acc = buffer to store predicted acceleration

*/


//int EX_FLAG = 0;


// functions with "_string" assign strings to mpreals, and without "_string" assign doubles to mpreals


////////////////////////////////////////////////////////
// Amuse interface functions
////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////
// Laguerre's method Solver
////////////////////////////////////////////////////////////////////////////


// Note on internal and external times:
//
//	begin_time	is the external time at which the simulation starts;
//			it should be set only at the start of the simulation,
//			through the interface function set_begin_time(), and
//			can't be changed by the internal integrator
//	jd.system_time	is the internal time used by the integrator; it
//			always starts at 0 and should be reset when a
//			synchronization occurs; the scheduler requires that
//			time steps be commensurate with system_time, so we
//			don't want it to become something that will force
//			very short steps
//	jd.sync_time	is the last time we forced system_time back to 0,
//			to preserve the scheduler
//
// Sync_time is measured relative to begin_time. System_time is measured
// relative to sync_time. Thus
//
//	sync_time + system_time is the total time since the simulation started
//	begin_time + sync_time + system_time is the absolute ("external") value
//					     of the current system time
//
// All time bookkeeping is handled in this file, in function sync_times().
// Sync_time exists in ph4 only for use by diagnostics that need to print
// the true system time (currently updated only in jdata.cc).


// The i-data temporarily mirror a subset of the j-data during a block
// time step.  Between idata::gather() and idata::scatter(), the
// following data are currently used:
//
//	j-data			i-data
//
//	id	     -->	iid
//	nn	    <--		inn
//	pot	    <-->	ipot
//	dnn	    <--		idnn
//	mass	     -->	imass
//	radius	     -->	iradius
//	time	    <-->	itime
//	timestep    <-->	itimestep
//	acc	     -->	old_acc
//		    <--		iacc
//	jerk	     -->	old_jerk
//		    <--		ijerk
//	pos	     -->	old_pos
//		    <--		ipos
//	vel	     -->	old_vel
//		    <--		ivel
//  no GPU:
//
//	pred_pos     -->	ipos
//	pred_vel     -->	ivel
//
// The j-data are predicted prior to gather if GPU is not used.
// Otherwise, the j-prediction is done on the GPU, but the i-data are
// predicted on the CPU.  Note that pred_pos and pred_vel are needed
// ONLY if the force calculation is done on the front end.  If a GPU
// is used, they are never used.


// Note the uncomfortable mix of arrays and vectors below.  The jdata
// functions all use arrays of ints/reals, while we use vectors
// internally for programming convenience.


// *** Multiple code under development. ***


//Function that mangles the filename into the correct format
//incase we use more than 1 process


//Version that writes the BD dump format


//Some old utility functions


//Copied from Makino code


//Uses one communication by storing data in one buffer
//nsample can be set to zero if this call is only used
//to get updated domain information
//This one is used when only updating the currentbox sizes


//Uses one communication by storing data in one buffer
//nsample can be set to zero if this call is only used
//to get updated domain information


//Sort function based on Makinos function
//Sorts (a part) of the coordinate array
//containing the sample particles
//Either sorts the x,y or z direction
//lo is the lower bound of the to sorted part
//up is the upper bound of the to sorted part
//cid is the index/axes to sort
//cid=0=x, cid=1=y and cid=2=z


//Calculates the dimension of the box
//np number of sample particles
//pos the sample particle positions
//cid the coordinate index, 0=x, 1=y, 2=z
//istart/iend the start and end position of the sorted array
//rmax the maximum coordinate
//xlow/xhigh the box coordinates


//Checks if the position falls within the specified box


//Send particles to the appropriate processors


//Function that uses the GPU to get a set of particles that have to be
//send to other processes


//Exchange particles with other processes


//Compacts an array of integers, the values in srcValid indicate if a
//value is valid (1 == valid anything else is UNvalid) returns the
//compacted values in the output array and the total
//number of valid items is stored in 'count'


//Splits an array of integers, the values in srcValid indicate if a
//value is valid (1 == valid anything else is UNvalid) returns the
//splitted values in the output array (first all valid
//number and then the invalid ones) and the total
//number of valid items is stored in 'count'


// If srcValues and buffer are different, then the original values
// are preserved, if they are the same srcValues will be overwritten


//Single precision version


// 1) construct tree
// 2) evaluate gravity
// 3) neighbour search (construct ngh_list_idx[])
// 4) calc acc from close particles
// set ngh_list_len_loc,
// set ngh_list_len_glb,
// set Nshort_loc,
// set Nshort_glb,
// set ngh_list_idx
// set adr_from_idx


////////////////////////////////////////////
/// evolve through the inner hamiltonian ///
////////////////////////////////////////////


///////////////////////////////////////////////////////
//                                                   //
//            SHORT RANGE FORCE CALCULATION          //
//                                                   //
///////////////////////////////////////////////////////


// NOTE: Order of calculations of predictors.
// Initailly, all Ni particles are predicted .
// During force loop on an i particle,
// if a j particle has been alreaddy predicted,
// this j particle must not predicted, because
// if this j particle is already integrated,
// acc and jrk of this particle have been new values in the future.
// Thus each particle must be predicted once.


// NOTE: Order of predictor calculation.
// Initailly, all Ni particles are predicted .
// During force loop on an i particle,
// if a j particle has been alreaddy predicted,
// this j particle must not be predicted, because
// if this j particle is already integrated,
// acc and jrk of this particle have been new values at t+dt.
// Thus each particle must be predicted once.


/////////////////////////////////////
//                                 //
//           KICK & DRIFT          //
//                                 //
/////////////////////////////////////


///////////////////////////////////////////////////////
//                                                   //
//            LONG RANGE FORCE CALCULATION           //
//                                                   //
///////////////////////////////////////////////////////


// probablly update of acc is not need


// if MPI is used,
// the particles in other node possibly is included in this box.
// fuction "pack_real_particles()" exclude these particles.
// these particles must be integrated in other node.


//////////////////////////////////////////
//
//       add particles or cells to LET
//
//////////////////////////////////////////


// void octree::set_context( bool disable_timing) {
//
//   devContext.create(disable_timing);
//   set_context2();
// }
//
//
// void octree::set_context(std::ofstream &log, bool disable_timing) {
//
//   devContext.create(log, disable_timing);
//   set_context2();
// }


// Reads the IC from a gadget HDF5 file


// During the reading of HDF5 input, the indices of vertices holding the sources will be stored in an array
// Now, use this array to find the sources and smear out their luminosities EQUALLY (should be more clever...) among
// their neighbours


// Constructor with the file name - if the file does not exist create it, else just open it...


// Constructor with the file name and mode - will do what the mode says...


// makes a dataset on atomic data


// makes a group with absolute pathname "name"


// makes a group with absolute pathname "name"   - WITH SIZE_HINT


// write_attr overload to write single string by refenrece


// write_attr overload to write single string by value


// read_attr overload to read single variable by refenrece


// returns a string holding the name of the datatype of the dataset


//
// read one variable from the HDF5 file and return it as a double array
// (used for generalizing data input...)
//


/*
  Dummy routines to reading different types of data...
*/


// Open with the file name and mode - will do what the mode says...


// Initialise octree with size tree_size


//delete the octree


//Insert vertex in the octree


//get the id's of vertices that are inside box


//! constructor for cooling_curve object


//! constructor for Simpl array


//! Constructor for Sites array


//! Constructor for Site_Update


// overloaded for floats


//calculate the determinant of a 4x4 matrix


//Calculate the coordinates of the circumcentre of a simplex


/***************************************************************/
/*               Romberg integration routines                  */
/***************************************************************/


//find the zero of function func


/**************************************************************************************************/
/*! This routine is a comparison kernel used in a sort routine to group
 *  vertices that are exported to the same processor.
 */


// cross-section for H from Verner et al. 1996


// hydrogen cross section from Verner et al. 1996 times black body curve


//collisional ionisation coefficient from Theuns et al. 1998


// Recombination coefficient HII for case B from Hui & Gnedin 1997


// Recombination coefficient HII for case A from Hui & Gnedin 1997


//Planck curve times H cross section times h*(nu-nu_0) and divided by h*nu
//Verner et al. 1996 cross section is used


// Recombination cooling coefficient HII for case B from Hui & Gnedin 1997


// Recombination cooling coefficient HII for case A from Hui & Gnedin 1997


// Collisional ionisation cooling coefficient from Theuns et al. 1998


// Collisional excitation cooling from Cen 1992


//free-free cooling coefficient with gaunt factor from Theuns et al. 1998


//initialise parameters that are usually read in from file


//add one vertex to the list of vertices that needs to be triangulated


//add a site to the sites list


//remove a site from the list


//convert the physical units to code units


//initialise the code:
// create boundary around domain
// do domain decomposition
// compute triangulation
// create the sites for RT
// compute the physical properties of the sites


//set up a simulation


//evolve the radiative transfer over time t_target


//store everything in the simulation and recompute triangulation and physics


//return properties of specified site


//set properties of specified site


/****  Initialize the simulation and compute the triangulation  ****/


/**** read in parameter file  ****/


/****  Read in vertices from hdf5 file  ****/


//compute the maximum id of the vertices


/**** Create homogenous boundary around simulation domain ****/
// Width of the boundary is variable borderBox
// Number of points in the boundary is variable borderSites


/****  Create octree of vertices  ****/
//size of octree is 4 * #subboxes, to ensure fast localisation of vertices
//in subbox and subbox boundaries


/****  Create the sites array  ****/
//create a list of sites from the list of simplices that was created
//during the triangulation stage
//since we count every site_index once. This is possible since duplicate
//sites outside the simulation domain point with their site_index to
//the site that is in the simulation domain


/****  Assign id's to sites  ****/


/****  Initiate which site use ballistic transport  ****/
//Determine which sites are to use ballistic transport
//and which direction conserving


/****  Shuffle the list of sites  ****/
//this is necessary since the sites list was created from the list of
//simplices and is thus ordered according to the simplices they belong to


/****  Compute the properties of the sites  ****/


/****  Compute the neighbours of every site ****/
// Generate the neighbour vectors for each vertex from the simplex vector
// Care should be taken so that no vertex is put twice in the neighbour list


/****  Compute site volumes  ****/
// Compute the volume of the voronoi cell around each vertex from the volumes
// of the simplices that the vertex is part of


/****  Calculate most straight forward neighbours  ****/
// Calculate the d most straight paths for every incoming direction,
// but exclude neighbours that deviate straightAngle degrees (input
// variable) from going straight


/****  determine the place of this in neighbour array of neighbour site  ****/


//create list of only local simplices


/****  Rotate the solid angles of the unit sphere  ****/


//calculate normal distributed random numbers using the Box-Muller transformation


/**** store the intensities in big array ****/
//big array can be send by MPI


/**** return the stored intensities to sites ****/


/****  Check which sites are ballistic and which not  ****/
//Only used in case of combined transport


/****  Store the relevant properties of the sites  ****/
// stored are:  vertex_id
//              site_id
//              numberDensity
//              ion_frac
//              localIntensity
//              flux
//              ballistic


/****  Create new list of vertices to be triangulated  ****/


/****  Send the domain decomposition to all procs  ****/


/****  Send all vertices to all processors  ****/


/****  Create list of sites that belong to other proc  ****/


/****  Send properties of the sites  ****/
//send the properties of sites that belong to this proc
//but also exist on another proc to other procs


/**** Send neighbour information  ****/
//send the properties of the neighbours of sites that belong to this proc
//but also exist on another proc to other procs


/****  Send the intensities among procs between sweeps  ****/


/****  Send the updates list of vertices to master  ****/
//vertices no longer exist only on master proc as when the grid
//was first created, so every proc has to send its own list to
//master


/****  Send the stored intensities to procs that need them  ****/
//During vertex movement sites might have been migrated to
//another proc, so the intensities of these sites have
//to be send


/****  Send the ballistic properties of the changed sites to other proc  ****/


// Send physical quantities to sites that have moved to another processor


//send the intensities from sites that changed process


//Initialize physical parameters


/****  Read metal line cooling data  ****/


/****  Assign the number densities and fluxes from read in to sites  ****/


/****  Return the physical params to the sites  ****/
//this function only works if site_properties contains all sites on this proc
//and no others


//calculate the bounds of the frequency bins


//calculate effective cross section and spectrum of black body source


//compute the total number of atoms on this proc, used for output


//compute the mean optical depth on this proc, used for output


//output relevant physical quantities to screen


//rate of energy loss inside cell


//rate of energy gain inside cell


//convert internal energy to temperature using ideal gas law


//convert temperature to internal energy using ideal gas law


//update the temperature state of the gas
// function returns the heating/cooling time


//generate output files


//Write hdf5 output. Difference for serial version is the proc dependence
//of the offset


//write position of the IFront to file


//clear all temporary arrays


/*
 * Interface code for the stripped-down version of HALOGEN for the AMUSE project
 */


// All advance/return functions should check the allowability of the
// command and return the appropriate status.  The kepler functions
// will produce warning messages and do something, but won't return an
// error indicator.


// Binary scattering in standard (Hut & Bahcall 1983) units.  Binary
// mass = 1, semimajor axis = 1, t = 0 at pericenter if appropriate.


// note that the dinner's mass is set to zero, but other parameters and the particle itself remain


//note that dinner is not altered by this routine!


//Does not work for binaries as memory is already refreshed in SeBa by SeBa


/* Calculate kinetic energy */


/* Calculate potential energy (using potential 'w' values from particles) */


/* Performs one integration step using leapfrog scheme. */


///extern int id_collision_1, id_collision_2;   // determined in BHTC/BHtree.C
///extern double r_collision_12;


/*! This function computes a Peano-Hilbert key for an integer triplet (x,y,z),
 *  with x,y,z in the range between 0 and 2^bits-1.
 */


/*
int initialize_grid(const int n, const int linear,
					const double *r_g, const double *r_h,
					const double *vphi_g, const double *vphi_h,
					const double *beta_g, const double *beta_h,
					const double *psiEff_g,
					const double *psiEff_h,
					const double *g_h) {

	disk->grd = gridInitKeplerian(n, r_g, r_h, vphi_g, vphi_h,
								  beta_g, beta_h,
								  psiEff_g, psiEff_h,
								  g_h, linear);

	return 0;
}
*/


// simulation property getters:


///build group size array


///build group size array for specific type


///build the Head array which points to the head of the group a particle belongs to


///build the Next array which points to the next particle in the group


///build the Len array which stores the length of the group a particle belongs to


///build the GroupTail array which stores the Tail of a group


///build a particle list subset using array of indices


///sort particles according to some quantity which is stored in particle type and build an array for a sorted particle list
///remember this reorders the particle array!


///reorder groups from largest to smallest
///\todo must alter so that after pfof is reorderd, so is numingroup array and pglist so that do not have to reconstruct this list
///after reordering if numgroups==newnumgroups (ie, list has not shrunk)


///similar to \ref ReorderGroupIDs but weight by value


///similar to \ref ReorderGroupIDsbyValue but also reorder associated group data


///similar to \ref ReorderGroupIDsbyValue but also reorder associated property data


///search if some region is in the local mpi domain


/// Determine if a particle needs to be exported to another mpi domain based on a physical search radius


///Saerch particles to see if they overlap other OpenMP domains


/// Once data is loaded using field names in HDF5 file, update the names
/// to be unique to the selection loaded by VR


///remove index string from output string if only single dimension


///because some extra fields only have one dimension, not useful to keep index_0
///for these extra fields, so remove this from the output string


///if running in MPI, it might be necessary to update the outnames associated
///with extra fields. Therefore, just send all output names from task 0 (which
///will always be a read task to all other tasks.


///\name Tree-Potential routines
//@{
///subroutine that generates node list for tree gravity calculation


///subroutine that marks a cell for a given particle in tree-walk


///remove particles deemed unbound


///correct cm for removal of all least bound particles


/// Update the potential if necessary for small groups


/// Update the potential if necessary for large groups


///loop over groups and get velocity frame


/// Calculates the gravitational potential using a kd-tree and monopole expansion
///\todo need ewald correction for periodic systems and also use more than monopole.


/// Calculate FOF mass looping over groups once substructure search and have calculated properties


///\name Routines to calculate specific property of a set of particles
//@{
///Get spatial morphology using iterative procedure


///calculate the phase-space dispersion tensor


///calculate concentration. Note that we limit concentration to 1000 or so which means VmaxVvir2<=36


///\name Routines for manipulation of property data
//@{
///copy mass information over


///reorder mass information stored in properties data


/*
   Calculate Halo properties only, assumes that information in particle PIDs is meaningless, useful when don't care about particle tracking
   and just want halo catalogs (like when analysing results from runs like PICOLA (or say 2LPT runs))
*/


///\name functions used to find root of concentration
//@{


//return cosmic time in years


///\name Radial Profile functions
//@{


///Calculate the average mass weighted value of a chemical and how it was produced
///based on gas particles of an object


///Calculate the average mass weighted value of a chemical and how it was produced
///based on star particles of an object


///Calculate the average mass weighted value of a chemical and how it was produced
///based on bh particles of an object


/// \ name Spherical Overdensity related function calls
//@{
//loop over radii to get overdensity working outwards from some small fraction of the mass or at least 1 particles + small fraction of min halo size


/*! Calculates the normalized deviations from the mean of the dominated population.
    \todo note that before had FOFSTPROB set density to probability, but here set to ell, the normalized logaritmic "distance" from predicted maxwellian velocity density)
    but could add routine that transforms these values to probablity if necessary.

*/


/// function that sends information between threads


/// @brief Generate a vector list of mpi ranks that need to communicate
/// @param send_info information containing number of items to be sent from one task to another
/// @return vector of pair of mpi process ranks


/// @brief Set which task is sending and receiving
/// @param task1 one of the tasks in the pair
/// @param task2 second task in the pair
/// @return


/// @brief Initialize the number of chunks and chunksize for a communication
/// @param nsend number of times to send
/// @param nrecv number of items to receive
/// @param maxchunksize max number to send in one go
/// @return tuple of number of send/receives, current send chunk size, current receive chunk size, send off access, receive offset access


/// @brief Initialize the number of chunks and chunksize for a communication
/// @param nsend number of times to send
/// @param nrecv number of items to receive
/// @param cursendchunksize current number of items sent
/// @param currecvchunksize current number of items received
/// @param sendoffset current send offset
/// @param recvoffset current receive offset


/// @brief Find load imbalance ((max-min)/expected average)
/// @param opt Options structure containing runtime arguments


/// @brief given a position and a mpi thread domain information, determine which mpi process a particle is assigned to
/// @param opt Options structure containing runtime arguments
/// @param x x position
/// @param y y position
/// @param z z position
/// @return mpi process rank in MPI_COMM_WORLD


/// @def Routines related to managing extra properties of baryon particles
//@{


/// @def Routines related to sending information between threads when reading in data.
//@{


/// @brief send between read threads of input particle data


/// @brief send between read threads of input particle data to vector of buffers


//adds a particle read from an input file to the appropriate buffers


///\todo clean up memory allocation in these functions, no need to keep allocating xsearch,xsearchp,numoverlap,etc
/// Determine if a particle needs to be exported to another mpi domain based on a physical search radius


/// \name Routines involved in reading input data
//@{
/// \brief Distribute the mpi processes that read the input files so as to spread the read threads evenly throughout the MPI_COMM_WORLD


/// \brief Set what tasks read what files


/// \name MPI file write related routines
//@{
/// @brief Initialize the write communicators


/// @brief Define the write communicators (what tasks below to what communicators)


/// @brief Free any communicators involved in writing data


/// \name Routines involved in moving particles between tasks
//@{


/// @brief Determine which particles have a spatial linking length
/// such that linking overlaps the domain of another processor
/// store the necessary information to send that data and then send that information


/// @brief Similar to @ref MPIBuildParticleExportList but uses mesh to determine when mpi's to search


/// @brief like @ref MPIGetExportNum but number based on NN search, useful for reducing mem at the expense of cpu cycles


/// @brief like @ref MPIBuildParticleExportList but each particle has a different distance stored in rdist, used to find nearest neighbours


/// @brief like @ref MPIBuildParticleNNExportList but use mesh to determine overlap


/// @brief Mirror to @ref MPIGetNNExportNum, use exported particles, run ball search
/// to find number of all local particles that need to be
/// imported back to exported particle's thread so that a proper NN search can be made.


/// @brief Mirror to @ref MPIBuildParticleNNExportList, use exported particles,
/// run ball search to find all local particles that need to be
/// imported back to exported particle's thread so that a proper NN search can be made.
/// Is also used for calculating spherical overdensity quantities, where iSOcalc = true


/// @brief similar @ref MPIGetExportNum but number based on halo properties to see if any


/// @brief similar @ref MPIGetHaloSearchExportNum but using mesh mpi decomposition


/// @brief like @ref MPIBuildParticleExportList but each particle has a different distance stored in rdist used to find nearest neighbours


/// @brief similar \ref MPIBuildHaloSearchExportList but for mesh mpi decomposition


/// @brief Mirror to @ref MPIGetHaloSearchExportNum, use exported positions,
/// run ball search to find number of all local particles that need to be
/// imported back to exported positions's thread so that a proper search can be made.


/// @brief Mirror to \ref MPIBuildHaloSearchExportList, use exported particles,
/// run ball search to find all local particles that need to be
/// imported back to exported particle's thread so that a proper NN search can be made.


/// @brief Similar to \ref MPIBuildParticleExportList, however this is for associated baryon search
/// where particles have been moved from original mpi domains and their group id accessed through
/// the id array and their stored id and length in numingroup


/// \name FOF related mpi routines
//@{
///Set fof task id of particle


///Offset pfof array based so that local group numbers do not overlap
///\todo alter to that this now ranks threads so that group ids are larger if thread has more particles. This ensures that mpi threads
///send particles to thread with the fewest particles when linking across mpi domains during a FOF search


/*! Particles that have been marked for export may have had their fof information updated so need to update this info
*/


/*! This routine searches the local particle list using the positions of the exported particles to see if any local particles
    met the linking criterion and any other FOF criteria of said exported particle. If that is the case, then the group id of the local particle
    and all other particles that belong to the same group are adjusted if the group id of the exported particle is smaller. This routine returns
    the number of links found between the local particles and all other exported particles from all other mpi domains.
    \todo need to update lengths if strucden flag used to limit particles for which real velocity density calculated
*/


///link particles belonging to the same group across mpi domains using comparison function


///link particles belonging to the same group across mpi domains given a type check function


/*!
    Group particles belong to a group to a particular mpi thread so that locally easy to determine
    the maximum group size and reoder the group ids according to descending group size.
    return the new local number of particles
*/


/*!
    The baryon equivalent of \ref MPIGroupExchange. Here assume baryons are searched afterwards
*/


///Determine which exported dm particle is closest in phase-space to a local baryon particle and assign that particle to the group of that dark matter particle if is closest particle


///This alters the group ids by an offset determined by the number of groups on all previous mpi threads so that the group
///has a unique group id. Prior to this, group ids are determined locally.


///Collect FOF from all


/// \name Routines related to distributing the grid cells used to calculate the coarse-grained mean field
//@{
/*! Collects all the grid data
*/


/// \name config updates for MPI
//@{
///Update config option for particle types present


/// \name comparison functions used to assign particles to a specific mpi thread
//@{
///comprasion function used to sort particles for export so that all particles being exported to the same processor are in a contiguous block and well ordered
///\todo, I should remove this and determine the ordering before hand.


///comprasion function used to sort particles for export so that all particles being exported to the same processor are in a contiguous block and well ordered


///comprasion function used to sort grouped particles so that easy to determine total number of groups locally, size of groups, etc.


///\name mesh MPI decomposition related functions
//@{


/*! The FoF linking terms are adjusted by determining the physical extent of the halo and Rvir, Vcirc(Rvir), Mvir, Renc where Menclosed is [20%, 50%, 80%] of mass \n
    Units should be V=100 km/s, L=kpc, M=2.32e9 Msun so that G=1 and rhoc=3*Ho^2/8piG which gives 1.19e-7.
    These quantites, such as average spacing and ciricular velocity at virial radius, are stored in \ref Options.ellxscale and \ref Options.ellvscale.
*/


//Merge any groups that overlap in phase-space


///Testing a merge of all substructures


///Remove spurious dynamical substructures that comprise most of host (this could happen in VERY rare cases of a multitude of radial shells)


///adjust to phase centre


///Pre-calcualtions for searching for substructure


/*!
    Check significance of group using significance parameter.  A group is considered significant if (ave/expected ave) (and possibly (max-min)/varexpected] is significant relative to Poisson noise.
    If a group is not start removing particle with lowest ell value.
*/


///Create array for each group listing all previously unlinked particles that should now be linked. Note that the triple pointer newIndex is a double pointer, extra pointer layer is to ensure that
///it is passed by reference so that the memory allocated in the function is associated with the newIndex pointer once the function as returned.


///Create array for each group listing all possibly intergroup links


///This routine links particle's stored in newIndex to a group. Routine assumes that each group's list of new particle's is independent.


/*! Calculates the local velocity density function for each particle using a kernel technique
    There are two approaches to getting this local quantity \n
    1) From a large set of nearest physical neighbours use a smaller subset of nearest velocity neighbours \n
    2) Or calculate phase space density and physical density and divide phase-space density by physical density. This is far more computationally expensive and may not enhance velocity clustering
    and is just present for testing purposes.
    \todo velocity density function is NOT mass weighted. Might want to alter this.
    \todo there is a seg fault memory error when searching for NN in large sims using \em SINGLEPRECISION flag. I don't know why.
*/


///Checks if file exits by attempting to get the file attributes
///If success file obviously exists.
///If failure may mean that we don't have permission to access the folder which contains this file or doesn't exist.
///If we need to do that level of checking, lookup return values of stat which will give you more details on why stat failed.


///Reads the header structure if its a tipsy file or get_nbodies if gadget


///Reads particle data
///To add a new interface simply alter this to include the appropriate user written call


//Adjust particle data to appropriate units


///Read local velocity density


///Writes local velocity density of each particle to a file


/*! Writes a tipsy formatted fof.grp array file that contains the number of particles first then for each particle the group id of that particle
    group zero is untagged particles. \n
*/


/*! Writes a particle group list array file that contains the total number of groups,
    local number of groups (if using MPI) and group id followed by number of particles
    in that group and particle ids in the group
    For MPI, each thread writes it its own file (ie: parallel write)
    \todo Must check if parallel output is not an issue since on shared memory machine, write would probably write
    to the same hard drive, whereas on a cluster, each system could in principle write to different drive.
*/


///if particles are separately searched (i.e. \ref Options.iBaryonSearch is set) then produce list of particle types


///\name Final outputs such as properties and output that can be used to construct merger trees and substructure hierarchy
//@{
///Writes the bulk properties of the substructures
///\todo need to add in 500crit mass and radial output in here and in \ref allvars.h


///Write subfind style format of properties, where selection of properties
///are written for FOF objects and a larger selection of properties are written
///for each object


/// \name Routines that can be used to output information of a halo subvolume decomposition
//@{
///Writes cell quantites


/// \name Read group ids which can be useful if {\em Halo} have already been found
//@{


//load binary group fof catalogue


///\name Write configuration/simulation info
//@{


///\name output simulation state
//@{


///routine to get arguments from command line
/// \todo alter interface as now need to be able to specify only smdata file (no grid, res, normalized res) and functionality to specify eps, background fof search, etc


///Outputs the usage to stdout