XPLASMA

Xplasma -- D. McCune Apr. 2000 -- PPPL -- dmccune@pppl.gov
Xplasma2 -- D. McCune Sept. 2006 -- PPPL -- dmccune@pppl.gov

This document describes xplasma -- a set of routines for numerical
representation of fusion plasma MHD equilibrium and plasma parameter
profiles.

Abstract (Sept 2006 updated version) --

  The xplasma software offers a representation standard for tokamak
  plasma MHD equilibria and plasma parameter profiles defined over a 
  variety of coordinates.  Each xplasma dataset defines a "dictionary",
  a single namespace, in which each name refers to a specific data item-- 
  typically, a list, a grid discretizing a coordinate, or a profile 
  defined over one, two, or three gridded coordinates.  Xplasma provides
  efficient methods for accessing the data associated with these items,
  or for adding any number of new items to the dictionary and collective
  dataset.  An xplasma dataset (dictionary and all item contents) can be 
  written to or restored from a NetCDF file by means of simple subroutine
  calls.

  The original implementation (xplasma 1.0) provided a single global 
  xplasma dataset that was accessible by a set of fortran-77 style calls.
  An executable program could only contains one xplasma dataset at a time.
  The full fortran-95 implementation (xplasma 2.0) allows multiple 
  instantiation of xplasma datasets in a single process, while preserving 
  the fortran-77 interface with an implied reference to a "golden" xplasma
  pointer set aside for this purpose.

  Layered over efficient spline interpolation software (pspline [1]), 
  xplasma has been used for several years to communicate data between
  integrated simulation codes (e.g. TRANSP, ONETWO) and NTCC modules
  (e.g. NUBEAM).  There are also widely used applications for accessing
  experimental data (TRANSP & EFIT MDSplus trees) that use xplasma for
  internal storage of data items.  It is planned to use xplasma for
  implementation of a plasma state component in the Fusion Simulation
  Project (SciDAC-2 SWIM project).

[1]   https://w3.pppl.gov/NTCC/PSPLINE/pspline.html 

Home Top


Organization_of_help_document

The main topics are:

  Introductory Information
  F95 Upgrade (changes from xplasma vsn 1 to xplasma vsn 2).
  F95 (vsn 2) xplasma basic concepts
  Using F95 xplasma data
    Here, methods for accessing existing xplasma data are described.
  Initializing F95 xplasma data
    Here, first steps for creating a new xplasma object from scratch.
  Modifying F95 xplasma data
    Here, methods for writing data into xplasma are introduced.
  Error Handling
  Time evolution of xplasma
    Here, a discussion of what can and what cannot be easily changed.
  Creation and update of named xplasma data items
    More information on writing data into xplasma
  Global Items
    A few bits of modifiable globally accessible xplasma data
  Saving to File

  -- the remainder of the document: the original xplasma 1 (f77 interface)
     documentation.

Home Top


Xplasma_Introductory_Information

Xplasma is currently being used to communicate numerical representations
of axisymmetric tokamak plasma timeslices between experimental databases
and simulation codes, and between components or processes of multi-
component or multi-process (distributed) simulation codes.

Xplasma defines a sorted dictionary of named data items.  It provides 
efficient mechanisms for looking up and accessing data.  And it allows new
data to be named and added in a straight-forward manner.  The details are
given in the subtopics.

The contents of each xplasma dataset is thought of as a snapshot of the
plasma state at a particular time in an experiment or simulation.

Home Top


Xplasma_Data_Item_Identification

Each xplasma data item has a dictionary entry with:

  a) a unique NAME[1]
  b) a unique integer ID code
  c) an AUTHOR name [1]
  d) a LABEL [2]
  e) a UNITS label [2]
  f) an integer data TYPE code

The xplasma public module defines:

  integer, parameter, public :: xplasma_listType = 1 ! LIST data type code
  integer, parameter, public :: xplasma_coordType= 2 ! COORDinate data type
  integer, parameter, public :: xplasma_gridType = 3 ! GRID data type code
  integer, parameter, public :: xplasma_profType = 4 ! PROFILE data type code
  integer, parameter, public :: xplasma_blkbxType= 5 ! BLACK BOX data type code

Notes:

[1] up to 32 characters long, uppercase converted alphanumeric characters
    and underscore ("_"); first character must not be a numeric digit.

[2] any ascii character string, or blank.  Although xplasma does not 
    restrict the length, these labels may be used by graphical display 
    codes which may impose their own length restrictions e.g. by truncation.
    Recommendations: labels <~ 50 characters, units <~ 16 characters.

Home Top


Xplasma_Data_Types

COORDINATES-- an abstract coordinate, discretized by zero or more grids.
  There are two types: periodic, and non-periodic.

  Periodic coordinates are discretized by grids spanning [-pi:pi] or
  [0:2*pi].  For purposes of interpolation, there are no bounds: shifts
  of 2*pi*N are applied to bring interpolation coordinate data into bounds.
  For very large values of |N|, accuracy of interpolation will be lost.

  Non-periodic coordinates have fixed minimum and maximum values.  Xplasma
  enforces prescribed limits for some coordinates; otherwise the minimum
  and maximum values are defined when the first grid discretizing the 
  coordinate is provided.

The xplasma public module defines (this is a partial list):

  integer, parameter, public :: xplasma_rho_coord = 1   ! radial flux coord.
  integer, parameter, public :: xplasma_theta_coord = 2 ! poloidal angle coord.
  integer, parameter, public :: xplasma_phi_coord = 3   ! toroidal angle coord.
  integer, parameter, public :: xplasma_R_coord =   4   ! R coord
  integer, parameter, public :: xplasma_Z_coord =   5   ! Z coord
 
Xplasma methods exist for finding the periodicity attribute, min and max
value (when defined), and number of GRIDs discretizing the coordinate.

GRIDS-- specific discretization of a coordinate.  A grid is a strictly
  ascending finite sequence of numbers, the first of which precisely matches 
  the minimum value of the corresponding coordinate (or -pi or 0 in the case
  of a periodic coordinate), and the last of which precisely matches the
  maximum value of the corresponding coordinate (or pi or 2*pi in the case
  of a periodic coordinate).

  In gridded calculations, the GRID in the xplasma sense of the word is 
  usually the set of boundaries of the finite zones of the calculation.
  The set of zone centers only constitutes a grid in the xplasma sense of
  the word, when it is augmented with the inner and outer boundaries of
  the gridded region.

Xplasma methods exist for finding the size of any grid and retrieving its
values.

PROFILES-- 1d, 2d, or 3d interpolating functions based on array data defined
  over xplasma GRIDs.  Interpolation method is defined when the profile is
  defined; there are at present 4 options:

    type:                   storage requirement:
                            1d       2d       3d
    NC step function        N-1      (N1-1)*  (N1-1)*(N2-1)*(N3-1)
                                     (N2-1)
    C0 piecewise linear     N        N1*N2    N1*N2*N3    f continuous
    C1 cubic Hermite        2*N      4*N1*N2  8*N1*N2*N3  df/dx continuous
    C2 cubic Spline         2*N      4*N1*N2  8*N1*N2*N3  d2f/dx2 continuous

  (N, N1, N2, N3 refer to the sizes of GRIDs discretizing known coordinates).

  When profile data is accessed by interpolation, it is only necessary to
  know the coordinates over which it is defined, not the specific grids.  On
  the other hand, if the original data is needed, it is straightforward to
  acquire the specific grid information and the original data upon which the
  profile interpolating function is based.

  Cubic interpolation is affected by boundary conditions.  For data defined
  over periodic coordinates, periodic boundary conditions are employed.  For
  data defined over non-periodic coordinates, the boundary conditions are set
  when the data is defined.

Xplasma methods exist for interpolating profiles as well as finding the
underlying coordinates and grids.  For multidimensional profiles, input
coordinate data are tagged by COORDINATE or GRID ids; it is not necessary
for the caller to know the order of storage of the data.

Xplasma methods also allow straightforward means of acquiring information
on the interpolation method and underlying grids.

LISTS-- a list, identified by a single name, can contain 1 or more elements;
each element consists of:

  -- a 32 character name (not part of the xplasma dictionary namespace).
  -- an integer value
  -- a (real*8) floating point value
  -- character data, any length, trailing blanks trimmed away.

List lengths, element names, and contents are readily acquired by available
xplasma methods.

BLACK BOXES-- a named BLACK BOX consists of:

  -- an integer type code.  The meaning is user defined meaning, but, it
     should be noted that xplasma itself uses black box type codes K,
     0 <= K <= 101, to aid internal calculations and methods.  User defined
     type codes should be outside this range.
  -- an integer 1d array of length specified by the user.
  -- a floating point (real*8) 1d array of length specified by the user.

Black box datasets are used by xplasma for various purposes.  Examples are:
data caches for flux surface integration, representation of quantities 
defined over non-rectilinear grids.

Home Top


Conventions

Xplasma was developed for communication of data on axisymmetric tokamaks.

Physics units:  MKS; KeV for temperatures and particle energies.

Flux coordinates: 

   Radial flux coordinate "rho" --
   rho = sqrt([enclosed-toroidal-flux]/[toroidal-flux-enclosed-by-boundary])

   Poloidal angle coordinate "theta" -- theta=0 on large major radius side
   of plasma; theta increases along flux surfaces in counter-clockwise 
   direction when plasma cross-section is viewed to the right of the axis
   of symmetry.  But: data access methods provide optional controls to 
   enable user data to be interpreted as 

     theta_rev = 2*pi - theta
     grad(theta_rev) = -grad(theta),

   i.e. a clockwise poloidal angle coordinate.

   Toroidal angle coordinate "phi" -- increasing phi draws a circle in a
   counter-clockwise direction about the axis of symmetry, when the machine
   is viewed from above.

-------------------
Note: adaptation of xplasma for non-tokamak applications may well be possible,
but has not been attempted as of September 2006.  A major effort would be
required, e.g. to support stellarators or other non-axisymmetric plasma
configurations.

Home Top


Setting_theta_orientation

Setting the orientation of the poloidal angle coordinate "theta" (aka "chi"
in the fortran-77 interface) can now ONLY be done on a call-by-call basis.

In the xplasma (vsn 2) fortran-95 interface, use the ccwflag[n] 
optional logical arguments.  I.e. if the 2nd coordinate of a 2d
profile evaluation call is a poloidal angle which is to be 
interpreted as having reversed orientation, set the optional
argument ccwflag2=.FALSE.; if these arguments are omitted the
normal orientation (.TRUE.) is assumed to apply.

In the fortran-77 interface, most routines affected by the poloidal
angle orientation include a vector size argument (ivec).  To signal
that the poloidal angle is to be considered reversed, set ivec to 
[the vector size] x (-1).  I.e. a negative value of ivec signals
poloidal coordinate interpretation is to be reversed.  This will
be verified in the documentation of the specific routines.

Home Top


Interpolation_Methods

xplasma supports several interpolation methods for data.  The 
interpolation method is defined when an interpolating function
is set up.  In the xplasma software documentation, the desired 
interpolation method is indicated by an argument "iorder" in the
setup routine.  (Sometimes also referred to as the "spline type").

Generally the following methods are available:

  iorder    name              comment

   -1       zonal data        step function
    0       piecewise linear  1st derivatives defined, not continuous
    1       Akima Hermite     1st derivatives continuous
    2       Cubic Spline      1st & 2nd derivatives continuous

Hermite is a piecewise cubic method that is C1 given 1st derivatives
at the grid points.  Akima Hermite uses a numerical method [1] for
computing these derivatives which minimizes "ringing" in the case
of noisy data.

Cubic splines are C2 and preferable for smooth data, but can yield
"ringing" artifacts in the case of noisy data.

[1] Hiroshi Akima, Communications of the ACM, Jan 1974, Vol. 17 No. 1

Home Top


Axisymmetric-core-plasma

The core plasma is represented on a user defined flux coordinate grid
(rho,theta), where "rho" is a flux surface label-- by convention,
rho=sqrt(normalized-toroidal-flux) in xplasma itself, although 
physics applications can use any coordinate as long as the mapping
to rho is known.

After completion of the setup sequence, xplasma's core plasma model
will contain

  * the flux surface geometry R(rho,theta), Z(rho,theta), in m.
  * equilibrium related magnetic profiles g(rho) (Tesla*m), and the 
    poloidal flux profile psi(rho) (Wb/rad).  Other magnetic profiles 
    such as q(rho) are optional but often present.
  * the field components BR(rho,theta),BZ(rho,theta), and 
    [mod(B)](rho,theta), all in Tesla.
  * any number of user defined 1d plasma parameter profiles
    f(rho)
  * any number of user defined 2d plasma parameter profiles
    g(rho,theta).

The flux surface geometry and field components are represented
as bicubic splines.  User defined plasma parameter profiles are
represented according to the user's specification, with splines,
Hermite, piecewise linear, and zonal step function representations 
being available.

For each profile there is an associated id number and name
string.  For reasons of efficiency, the id numbers are used
for profile identification in the interpolation routines.
Routines for fetching the id number from the name are provided
and are efficient to log(N) of the number of names, but still
should not be used in applications' innermost loops.

Home Top


Limiter-description

There are two options for the "limiter" or "vessel wall" specification:

  * a closed sequence of (R,Z) points outside the core plasma, and, 
  * a list of bounding circles and infinite lines enclosing a space 
    that contains the core plasma.

The "scrape off plasma" is considered to be in the space inside 
the limiters but outside the core plasma.

Generally, after the limiter is specified the user will want to
set up an (R,Z) rectilinear grid which covers a rectangular space
enclosing both the core plasma and the scrape-off-layer region
between the core plasma and the limiters or vessel wall as given.
Automatic generation of evenly spaced (R,Z) meshes is available
as an option.

Once this is done, xplasma will construct a piecewise bilinear 
function d(R,Z), where d gives (in R,Z units) the distance of
(R,Z) from the nearest limiter, and

  * a negative number denotes a position inside the limiter
  * a zero denotes a position on the limiter
  * a positive number denotes a position outside the limiter.

Home Top


Scrape-off-plasma-coverage

After limiters are defined, a rectilinear (R,Z) grid can be 
constructed which covers both the core plasma and the scrape-off
plasma.  An (R,Z) representation of equilibrium, fields, and plasma
profiles can then be built up as needed.

Home Top


Intended_applications

It is envisioned that xplasma might be used as follows:

  (1) a transport simulation code evolves a plasma MHD equilibrium
      and a set of plasma parameters.

  (2) "physics modules" are programmed to acquire data from the 
      xplasma module and write data back into it.

  (3) the transport simulation code uses routines that add data to
      xplasma, to specify the plasma equilibrium and necessary plasma 
      parameter profiles, and then it calls the physics module.

  (4) the physics modules reads its input data using the xplasma
      read routines, and then does its modeling calculations,
      developing a set of output profiles.

  (5) the physics module writes its results back into xplasma using
      more data definition routines, then exits.

  (6) the transport simulation code reads back the data created by
      the physics module.

This reading and writing through xplasma will handle interpolation
so that the main transport code and the physics module need not 
share COMMON blocks nor use the same numerical grids.

Home Top


Physical_units_conventions

Since the purpose of xplasma is to facilitate communication of data
between separately developed physics models, it is necessary to 
recommend a convention regarding physical units.  The convention
adopted is based on emerging consensus in the tokamak physics
modeling community:  MKS for all quantities, except for temperatures
and energies where KeV are used.

Thus:
          MKS/KeV          NOT cgs/eV  (sorry, TRANSP...)

  "g"     Tesla*m          NOT gauss*cm
 "psi"    Webers/rad       NOT gauss*cm**2/rad
 "R,Z"    m                NOT   cm
 "Te,Ti"  KeV              NOT   eV
 "ne"     m**-3            NOT   cm**-3

[note it is customary to give the poloidal flux function normalized
per unit toroidal angle; then Bpol = (1/R)*grad(psi), note (1/R) not
(1/(2*pi*R))].

Home Top


Performance_considerations

Considerable effort has gone into optimization of the performance of 
xplasma subroutines.  In particular, xplasma is layered over the pspline
library, which has been shown to work well on modern vector and super-
scalar computer architectures.

But, general purpose routines (e.g. for interpolation) necessarily have
a fair amount of control logic and error checking to support general purpose 
use.  This will inevitably result in performance somewhat less than what is
optimally achievable for a specific code.

Codes for which e.g. field or metric interpolation are critical performance
considerations likely already have optimized code for these purposes.  In
many cases it will be best simply to use xplasma as a way to load the input
data structures for these optimized routines at the start of the calculation,
and use the optimized routines (not xplasma calls) in the innermost loops
of the calculation.

Home Top


Non-axisymmetry

Although the xplasma interface is designed to allow eventual support
of non-axisymmetric field equilibria, the September 2006 version of the
software is limited to axisymmetric configurations only.

Home Top


F95_Upgrade

A project has been completed to upgrade xplasma for the Fusion Simulation 
Project.  The upgrade includes:

  -- simplified fortran-95 interface; simplified underlying data structures.

  -- object-oriented implementation, allowing multiple xplasma "instances"
     to co-exist independently in memory.  (This is fortran-95; the term
     "object-oriented" is used loosely).

  -- ability to update equilibrium without deleting entire object contents
     and rebuilding from the ground up.

The fortran-77 style original xplasma interface is maintained for the
most part, but a few routines have been dropped-- see subtopic.

The f77 routines all refer implicitly to a reserved xplasma object
pointer set aside for this purpose.  To use f77 routines to modify any
other xplasma object, it is necessary to reset the f77 object pointer:
see the subtopic

Home Top


Reset_F77_pointer

To reset the f77 xplasma pointer-- which defines the xplasma object to
which all legacy f77 xplasma calls refer-- use the following module and
its pair of contained routines 

  grab_f77_xplasma(swant,ierr)
  release_f77_xplasma(ierr)

--------------------------------------
details:

  use xplasma_obj_instance
    ...

  !  the following points to an xplasma object, to which future
  !  f77 xplasma calls should refer.  This pointer has been initialized
  !  elsewhere...!

  type (xplasma), pointer :: swant

  integer :: ierr  ! status code, 0=normal on exit

  !  reset the f77 xplasma pointer with this call:

  call grab_f77_xplasma(swant,ierr)
  if(ierr.ne.0) [handle-unlikely-error]

To later restore the f77 xplasma pointer to its prior state, use:

  call release_f77_xplasma(ierr)
  if(ierr.ne.0) [handle-unlikely-error]

Note that these calls should occur in pairs!  If (e.g. due to error
handling logic) the pairing is broken, there are two likely serious
consequences:

  (a) F77 xplasma calls interact unexpectedly with a different xplasma
      object, with unpredictable results;
  (b) eventual f77 xplasma pointer stack underflow or overflow error.

Home Top


Deprecated_F77_Routines

The "C" interface to fortran-77 xplasma will be frozen.

The "R4" interface to fortran-77 xplasma will be frozen.  All the
fortran-95 interfaces are in REAL*8 precision.

The following fortran-77 style routines will be dropped in the upgraded
version:

   eqm_flxbdy / eqm_rbdy  -- "move limiter to plasma boundary" / 
         "restore original limiter".

     dropped because: (a) no evidence of use; (b) error-prone; if
     "eqm_flxbdy" call is not followed by "eqm_rbdy", xplasma suffers
     a side effect; distance to limiter calculations, used e.g. for fast
     ion orbit loss calculations, are modified.

     advice: codes wishing to treat the plasma boundary as the limiter
     can use routines like "eq_dfast" to compute distance-to-boundary.
     Such routines return a positive number for locations beyond the
     plasma boundary, and a negative number for locations within the 
     plasma boundary.

   eqm_chi_cwdir_set, eqm_chi_cwdir_restore, 
   eqm_chi_cwdir, eq_get_chi_cwdir

     control clockwise/counter-clockwise orientation of poloidal angle
     variable.  Dropped due to being error prone-- side effect of a
     subroutine's reset of chi_cwdir seen by all subsequent calls to
     xplasma routines.

     advice: In the xplasma fortran-95 interface, optional arguments
     are provided to specify angle coordinate orientations.  In affected
     fortran-77 interface routines, the poloidal angle coordinate
     orientation can be reversed, separately on each call, by setting
     the argument vector length to a negative number.  Details are
     provided in the updated subroutine documentation, below.

   eqm_phi_cwdir_set, eqm_phi_cwdir_restore, 
   eqm_phi_cwdir, eq_get_phi_cwdir

     dropped: no evidence of use.  Optional arguments in fortran-95
     interface only.

   eqm_spordr_set, eqm_spordr_get

     dropped: xplasma feature to control spline storage mode
     (compact or non-compact) was found to be unnecessary and 
     has been removed.

   eqm_nfast

     dropped: control of resolution of a 2nd (R,Z)->(rho,theta)
     inverse map, no longer necessary.

Home Top


Nomenclature

The original fortran-77 xplasma API used "chi" to designate the 
poloidal angle coordinate in a 2d flux coordinate representation
of a tokamak plasma equilibrium.

The new fortran-95 interface uses "theta" to designate this coordinate.
However, since the fortran-77 and fortran-95 interfaces are both 
maintained, both names persist in the xplasma API.

Hopefully this will not cause much confusion.

Home Top


F95_Xplasma_Basics

In order to use the Fortran-95 Xplasma Interface in code, it is necessary
to be able to refer to xplasma objects.  A consequence of the design goal
of allowing multiple xplasma objects to co-exist, is that each subroutine
that accesses or manipulates xplasma data must include an argument which
specifies which instance of xplasma is to be affected or used.

This argument is a "pointer to an xplasma object".  A pointer is used,
because each xplasma object can be quite large, such that it is sometimes
advantageous to reuse existing xplasma code by means of resetting a pointer,
rather than having to explicitly copy the entire contents from one xplasma
object to another.

Advanced users may want for various reasons to invent additional fortran-95
modules which declare xplasma objects and pointers.  However, for starting
out it is recommended to use the public module provided with the software:

  use xplasma_obj_instance

This causes the following pointers to be defined, with suggested semantics:

  s -- pointer to currently active xplasma object
       F77 xplasma calls implicitly refer to this one.

  s1-- pointer to previous xplasma object (e.g. from a prior timestep 
       in a time-dependent simulation).

  s2-- spare.

The module xplasma_obj_instance also imports all public xplasma modules
and definitions.

INITIALIZATION-- xplasma_obj_instance defines SAVEd global data.  Because
fortran-95 does not yet allow pointers to be initialized at compile time
to point to any particular object, the pointers are initially NULL.  To
be activated, the pointers in this module must be initialized with by 
calling a public subroutine defined in the module:

  call xoi_init(ierr)

This call simply associates the pointers with specific xplasma objects
inside the module; no data initialization is performed.  It also sets
a flag inside the module indicating that initialization has been performed,
so that if the call is repeated, no action is taken.

The integer argument "ierr" returns a status code, 0=normal.  Almost all
xplasma subroutine calls return such a status code.

  (NOTE: spelling variant: some xplasma routines spell this "ier" in
  their argument lists).

Nearly all f95 xplasma calls take an xplasma object pointer as their first
argument.  In the documentation, the symbol "s" is used for this pointer.
In some applications of xplasma, the symbol can be taken as short hand for
"plasma state".  Almost all xplasma calls also have a status code "ierr" as
their final required argument.

Ordering of calling arguments in f95 xplasma calls:

Example:

  call xplasma_eval_prof(s,id,x,result,ierr,ideriv1=1,n_out_of_bounds=iout)

    1st argument -- s -- xplasma object pointer
    next set of arguments -- id,x -- required inputs
         (here, the profile id and the x values at which to evaluate it)
    next set of arguments -- result,ierr -- required outputs
         (here, the result of the evaluation, and an error status code)
         ("ierr" is almost always the last required output argument).
    next set of arguments -- ideriv1 -- optional inputs
         (here, requesting the 1st derivative of the profile w.r.t. x).
         (the documentation will indicate that the default is to return
         the profile value unless otherwise directed by optional arguments).
    final set of arguments -- n_out_of_bounds -- optional outputs
         (here, the number of x values that were out of bounds, with
         respect to the coordinate over which the profile identified 
         by "id" is defined).

Of course, not all xplasma subroutines contain arguments in every one of
these categories.  Nevertheless, the ordering of arguments is consistent
with this ordering for all f95 xplasma public interfaces.

Home Top


Xplasma_public_modules

  xplasma_obj_instance
    uses "xplasma_obj_instance_mod"
         (where xplasma objects, pointers and xoi_init are defined).
    uses "xplasma_definitions", which...
      uses "xplasma_profs" -- methods for creating certain profiles.
      uses "xplasma_mcgrid"-- methods for creating and accessing a type
                              of fast ion distribution function "black box"
                              and related items.
      uses "xplasma_rzgeo" -- methods for defining MHD equilibrium
                              geometry and related profiles.
      uses "xplasma_flxint"-- methods for computing flux surface integrals
                              and averages.
      uses "xplasma_sol"   -- methods for defining limiter and scrape-off
                              region.
      uses "xplasma_ctran" -- coordinate transformation methods and
                              evaluation of metric jacobian.

      uses "xplasma_obj"   -- the kernel -- dictionary and supported
                              data types; error handling support;
                              NetCDF i/o.
Home Top


Xplasma_public_constants

The following are public parameters that are defined in the public
xplasma modules, which may be helpful in user applications:

Data types known to the xplasma dictionary:

  integer, parameter, public :: xplasma_listType = 1 ! LIST data type code
  integer, parameter, public :: xplasma_coordType= 2 ! COORDinate data type
  integer, parameter, public :: xplasma_gridType = 3 ! GRID data type code
  integer, parameter, public :: xplasma_profType = 4 ! PROFILE data type code
  integer, parameter, public :: xplasma_blkbxType= 5 ! BLACK BOX data type code

Commonly used coordinates:

  integer, parameter, public :: xplasma_rho_coord = 1   ! radial flux coord.
  integer, parameter, public :: xplasma_theta_coord = 2 ! poloidal angle coord.
  integer, parameter, public :: xplasma_phi_coord = 3   ! toroidal angle coord.
  integer, parameter, public :: xplasma_R_coord =   4   ! R coord
  integer, parameter, public :: xplasma_Z_coord =   5   ! Z coord

Designation for coordinate subsets (usable as argument in a handful of
xplasma routines):

  integer, parameter, public :: xplasma_flux_coords = 1 ! generic flux coord.
  integer, parameter, public :: xplasma_cyl_coords = 2  ! generic cyl. coord.

Author name usable to designate quantities that should be deleted when the
plasma MHD equilibrium changes:

  character*32, parameter, public :: xplasma_xmhd = '__XPLASMA_MHDEQ_DERIVED'

The following arguments define algorithm choices for the 
[R,Z] -> [rho,theta] inverse map, in order from the slowest but most
accurate to the fastest but most approximate...

  integer, parameter, public :: xp_imap_newton = 1
  integer, parameter, public :: xp_imap_polar = 2
  integer, parameter, public :: xp_imap_rzlinear = 3

Home Top


Reserved_names

For reasons of compatibility with the original xplasma implementation
and existing uses of the software, certain item names related to the
plasma MHD equilibrium are reserved.  These are:

  name -- definition (all are profiles unless otherwise specified)
  
  G    -- g(rho) = R*B_phi
  PSI  -- psi(rho); (1/R)*grad(Psi) = B_pol
  P    -- P(rho), plasma pressure for MHD equilibrium
  Q    -- q(rho), rotational transform d[toroidal_flux]/d[poloidal_flux]
  R    -- R(rho,theta), (with Z) position of flux surfaces
  Z    -- Z(rho,theta), (with R) position of flux surfaces

  PSI_RZ -- Psi(R,Z)

  BR   -- BR(rho,theta), field component in R direction
  BZ   -- BZ(rho,theta), field component in Z direction
  BPHI -- Bphi(rho,theta), field component in phi direction
  BMOD -- mod(B)(rho,theta), total field magnitude

  BR_RZ   -- BR(R,Z), field component in R direction
  BZ_RZ   -- BZ(R,Z), field component in Z direction
  BPHI_RZ -- Bphi(R,Z), field component in phi direction
  BMOD_RZ -- mod(B)(R,Z), total field magnitude

  MAG_AXIS -- list, [R,Z] at magnetic axis
  BDY_RZ_MINMAX -- list,{Rmin,Rmax,Zmin,Zmax} of plasma boundary
                   (nominal last closed flux surface).

User applications should avoid using these names for storage of items in
xplasma.

Several additional named items created by XPLASMA start with "__", two 
consecutive underscores.  Users should avoid defining names that start 
with this prefix.

Home Top


User_defined_modules

Although the public module xplasma_obj_instance defines sevaral xplasma
instances and associated pointers, the user may want to define his own
xplasma instances at some point.  The existing modules

  old_xplasma/xplasma_obj_instance.f90
  old_xplasma/xplasma_obj_instance_mod.f90

can be used as examples for how to do this.

The user's code will need to see 

  use xplasma_definitions

in order to make use of xplasma calls.

Home Top


Using_F95_Xplasma_Data

In this section, the new Fortran-95 Xplasma interface is described,
with emphasis on methods for using data in an existing dataset.

The xplasma pointers (s,s1) defined in xplasma_obj_instance are presumed
to be available in the coding examples.

The argument "ierr" is always a return status code, 0=normal.

For simplicity of examples, error checking / error handling code is
usually omitted -- but real codes should check the error codes!

To access any xplasma call, the calling code must declare

  use xplasma_obj_instance

or else use a user-defined module that otherwise provides access to 
xplasma object and interface definitions.  In all f95 code examples it
is assumed that this has been done.

Home Top


Example_code

The xplasma module comes with a debug library, which supports SGlib/ElVis
graphical examination of xplasma datasets.

The library is called xplasma_debug.a; the main source code for this
library is xplasma_debug_module.f90-- this code has examples of pretty
much every kind of access to xplasma data.

Given an xplasma file path, or a URL pointing to a publicly accessible
xplasma file, the data can be plotted running "plot_xplasma", a command
line interactive fortran program, which uses the debug library.

The f77 interface to xplasma has been re-implemented by using the
f95 xplasma routines internally.  This interface resides in the
library old_xplasma.a; the source routines for this library, e.g. 
eqm_rhofun.f90, contain examples of use of xplasma f95 routines.  This
may be useful especially for anyone already familiar with the f77 
routines.

Home Top


Copy_and_read

  ! copy contents of "s" to "s1".  Prior contents of "s1" are removed; all
  ! associated memory is freed; "s" is not changed.

  call xplasma_copy(s,s1,ierr)

  ! read in new contents of "s" from a file.  Prior contents of "s", if any, 
  ! are removed, and associated memory is freed.  "s" and "s1" are not sharing
  ! any memory, so, the removal of the prior contents of "s" has no effect on
  ! "s1".

  call xplasma_read(s,filename,ierr)

  ! "filename" is a character string variable containing a file path to
  !  a read accessible xplasma NetCDF file.
  !--------------------------
  !  example:

  use xplasma_obj_instance
  use my_module ! defines "file_path" and "runid" character string variables.

  implicit NONE

  character*100 filename

  filename = trim(file_path)//trim(runid)//'_my_xplasma.cdf'
  call xplasma_read(s,filename,ierr)
  if(ierr.ne.0) then
     write(6,*) ' ? xplasma open or read failure: '//trim(filename)
     call xplasma_error(s,ierr,6)
     call bad_exit
  endif

Note: if the filename argument has the form of a URL (i.e. starts with
" http://"),  xplasma_read will attempt to spawn a /usr/bin/curl process
to download the indicated URL to a local disk file (in the process current
working directory), and will then attempt a read of the downloaded file.

Home Top


Global_information

Certain global information, such as a global label, the current simulation
or experiment time in seconds, sign or orientation of the toroidal field 
and toroidal plasma current, are stored in each xplasma.  The accuracy
of this information depends on the software that created the original
xplasma object or file.

To retrieve this information use the following routine.  Other than the
status code, all arguments are optional, allowing the user to select
which piece or pieces of information are desired.

    subroutine xplasma_global_info(s,ier, &
         initLabel,time,axisymm,scrapeoff,bphi_ccw,jphi_ccw,nitems, &
         prof_counter,eq_counter,bdytol,ajac_maxVaR,rzOrder,kmom)

      ! this routine returns global xplasma object information, according
      ! to which optional arguments are provided...

      type (xplasma), pointer :: s
      integer, intent(out) :: ier   ! error set iff s is uninitialized.

      ! this is the label passed in an xplasma_(re)Init call...
      character*(*), intent(out), optional :: initLabel

      ! can also use xplasma_time_get for this:
      real*8, intent(out), optional :: time

      logical, intent(out), optional :: axisymm   ! axisymmetry flag

      logical, intent(out), optional :: scrapeoff ! SOL flag

      integer, intent(out), optional :: bphi_ccw  ! Bphi counter-clockwise flag
      ! 0 means: never specified; 1: counter-clockwise (CCW); -1: CW

      integer, intent(out), optional :: jphi_ccw  ! Jphi counter-clockwise flag
      ! 0 means: never specified; 1: counter-clockwise (CCW); -1: CW

      integer, intent(out), optional :: nitems    ! number of items in xplasma
      ! dictionary at time of call.

      integer, intent(out), optional :: prof_counter  ! profile counter
      ! global counter incremented for each creation or update of each profile

      integer, intent(out), optional :: eq_counter  ! profile counter
      ! global counter incremented for each update of MHD equilibrium

      real*8, intent(out), optional :: bdytol   ! out-of-range error tolerance
      ! relative tolerance applied for interpolations over non-periodic 
      ! coordinates; for periodic coordinates shifts of 2*n*pi are applied
      ! as necessary to bring interpolations in range

      real*8, intent(out), optional :: ajac_maxVar   ! det[J] variation tol.
      ! relative tolerance for variations of det[J] within a flux surface;
      ! used to check for singular or near-singular metric tensor in 
      ! R(rho,theta),Z(rho,theta) flux surface definitions.

      integer, intent(out), optional :: rzOrder ! spline fit order for MHD
      ! equilibrium geometry R(rho,theta) z(rho,theta) data
      ! 1 for C1 Hermite; 2 (the default) for C2 Spline.

      integer, intent(out), optional :: kmom    ! #moments for Fourier
      ! representation of equilibrium

Also available:

    subroutine xplasma_time_get(s,ztime,ier)

      !  fetch the time (seconds) affiliated with xplasma object "s".

      type (xplasma), pointer :: s
      real*8, intent(out) :: ztime
      integer, intent(out) :: ier


Home Top


Equilibrium_derived_information

The plasma MHD equilibrium defines the transformation between magnetic
flux coordinates (rho,phi,theta) and cylindrical coordinates (R,phi,Z).
It also defines the magnetic field and flux surface geometry.

Xplasma provides a routine for transforming coordinate sets between 
cartesian, cylindrical, and flux coordinate spaces.  It also provides
for retrieval or calculation of extrema-- e.g. minimum and maximum 
R, Z, and mod(B) on any flux surface, and for finding the distance
to the nearest point on any flux surface.

These are described in the subtopics...

Home Top


Magnetic_axis

To get the magnetic axis postion (m) and field strength(T):

  real*8 :: R_axis, Z_axis, B_axis

Use this call:

  call xplasma_mag_axis(s,ierr, raxis=R_axis, zaxis=Z_axis, baxis=B_axis)

Note that the last 3 arguments are keyworded and optional-- any user 
selected subset of the information may also be had using the same 
subroutine.  The B field information is mod(B); to get the sign use
xplasma_global_info and fetch "bphi_ccw" (see preceding topic).  Note
that this is the actual field strength, not the "vacuum" field-- i.e.
g(0)/R_axis, not g(1)/R_axis, where g = R*B_phi, constant on each flux
surface-- xplasma profile name "G".

Home Top


Flux_surface_extrema

To find the minimum and maximum R and/or Z and/or |B| occuring on a 
plasma flux surface:

  real*8 :: R_min, R_max, Z_min, Z_max   ! spatial extrema, m
  real*8 :: B_min, B_max                 ! extrema in mod(B), T

For the plasma boundary surface:

    subroutine xplasma_RZminmax_plasma(s, rmin,rmax, zmin,zmax, ier, &
         ccw_theta,i2pi, thRmin,thRmax, thZmin,thZmax)

      !  return the plasma boundary R & Z min & max

      type(xplasma), pointer :: s

      real*8, intent(out) :: Rmin,Rmax
      real*8, intent(out) :: Zmin,Zmax

      integer, intent(out) :: ier

      !  optionally return the poloidal angle locations of the extrema

      logical, intent(in), optional :: ccw_theta ! Theta CCW in poloidal plane, default=T

      integer, intent(in), optional :: i2pi ! angle coord normalization options
      !  i2pi=1 (default) returned value in range [0,2pi]
      !  i2pi=2 returned value in range [-pi,pi]

      real*8, intent(out), optional :: thRmin,thRmax
      real*8, intent(out), optional :: thZmin,thZmax

The optional controls ccw_theta and i2pi only have an effect if theta
location of extrema are being returned.

For any plasma surface identified by "rho":

    subroutine xplasma_RZminmax(s,rho,ier, phi, &
         ccw_theta,i2pi, &
         rmin,rmax, zmin,zmax, &
         thRmin,thRmax, thZmin,thZmax)

      !  very accurately determine Rmin/max, Zmin/max of a flux surface.

      type (xplasma), pointer :: s
      real*8, intent(in) :: rho       ! required input: flux surface.
      integer, intent(out) :: ier     ! completion code

      real*8, intent(in), optional :: phi   ! toroidal angle location
        ! ignored for axisymmetric cases

      real*8, intent(out), optional :: rmin,rmax  ! Rmin & Rmax of surface
      real*8, intent(out), optional :: zmin,zmax  ! Zmin & Zmax of surface

      !  optionally return the poloidal angle locations of the extrema

      logical, intent(in), optional :: ccw_theta ! Theta CCW in poloidal plane, default=T

      integer, intent(in), optional :: i2pi ! angle coord normalization options
      !  i2pi=1 (default) returned value in range [0,2pi]
      !  i2pi=2 returned value in range [-pi,pi]

      real*8, intent(out), optional :: thRmin,thRmax
      real*8, intent(out), optional :: thZmin,thZmax

The optional controls ccw_theta and i2pi only have an effect if theta
location of extrema are being returned.

For the minimum and maximum mod(B) on any surface "rho":

    subroutine xplasma_Bminmax(s,rho,ier, phi, &
         ccw_theta,i2pi, bmin,bmax, thbmin,thbmax)

      use eqi_rzbox_module

      !  very accurately determine Bmin/max of a flux surface

      type (xplasma), pointer :: s
      real*8, intent(in) :: rho       ! required input: flux surface.
      integer, intent(out) :: ier     ! completion code

      real*8, intent(in), optional :: phi   ! toroidal angle location
        ! ignored for axisymmetric cases

      logical, intent(in), optional :: ccw_theta ! Theta CCW in poloidal plane, default=T

      integer, intent(in), optional :: i2pi ! angle coord normalization options
      !  i2pi=1 (default) returned value in range [0,2pi]
      !  i2pi=2 returned value in range [-pi,pi]

      real*8, intent(out), optional :: Bmin,Bmax  ! Bmin & Bmax of surface
      real*8, intent(out), optional :: thBmin,thBmax

The optional controls ccw_theta and i2pi only have an effect of thBmin and/or
thBmax are being returned.

Home Top


Computational_domain_extrema

For the computational domain (this generally encompasses a rectangle in
[R,Z] space that covers and extends beyond the plasma boundary; if there
is no [R,Z] rectangle defined, the plasma boundary extrema are returned:

    subroutine xplasma_RZminmax_extended(s, rmin,rmax, zmin,zmax, ier, &
         sol, id_Rgrid, id_Zgrid)

      !  return the R & Z min & max of the extended mapped region; if
      !  there is no such region return the R & Z min & max of the
      !  plasma

      type(xplasma), pointer :: s

      real*8, intent(out) :: Rmin,Rmax
      real*8, intent(out) :: Zmin,Zmax

      integer, intent(out) :: ier

Home Top


Coordinate_transform

A single interface "xplasma_ctrans" enables computation of any coordinate
transformation between cartesian, cylindric, and flux coordinates.

The interface xplasma_ctrans aliases two routines xplasma_ctran1 and 
xplasma_ctrann which accept scalar and vector arguments, respectively.

The transformations are defined as follows:

(R,phi,Z) --> (x,y,z)
  x = R*cos(phi)
  y = R*sin(phi)
  z = Z

(x,y,z) --> (R,phi,Z)

  R = sqrt(x**2+y**2)
  if R > 0, phi = atan2(y,x), otherwise phi = 0
  Z = z

(rho,theta) --> (R,Z)
  bicubic splines R(rho,theta), Z(rho,theta) are evaluated.

  An extrapolation of the system defines (rho,theta) --> (R,Z) for 
  rho > 1 -- it is continuous at the boundary rho=1 with the interior
  splines, but not continuously differentiable.

(R,Z) --> (rho,theta)
  various options for estimating the inverse map are provided.  

  The options control an accuracy/speed trade off.  If many evaluations are
  needed (e.g. for straight line tracking in flux coordinate space), the
  fastest option is to compute a bilinear profile interpolant pair rho(R,Z) 
  and theta(R,Z) on some grid.  The map is calculated accurately at the
  grid points; the interpolation of theta(R,Z) is handled carefully in 
  the vicinity of the theta branch cut (2*pi discontinuity).  This method
  is supported by the "maptype=xp_imap_rzlinear" option and is sufficient
  for many purposes.

  For greater cost in cpu time, the (R,Z) splines can be inverted using
  a Newton method with accuracy tolerances set down near machine precision
  if necessary: "maptype=xp_imap_newton", the default, combined with 
  "tol=<desired relative accuracy tolerance>"; code comments:

      real*8, intent(in), optional :: tol           ! map tolerance
      
      ! tol applies to Newton map (maptype = xp_imap_newton = default) ONLY

      ! (R_in,Z_in)->(rho_out,theta_out): 
      !         |R_in-R(rho_out,theta_out)| < tol*max(R_in,|Z_in|) 
      !         |Z_in-Z(rho_out,theta_out)| < tol*max(R_in,|Z_in|) 
      ! default: s%bdytol
      !          s%bdytol's own default value is 1.0d-10
      !             cf xplasma_bdytol_set; xplasma_global_info.


  An option of intermediate speed that is generally accurate to ~1.0d-4 
  and requires no pre-tabulation of map data, can be had by setting
  "maptype=xp_imap_polar".

Almost all arguments are optional-- the presence of arguments defines
what transformation is desired.

Examples:

  INTEGER, PARAMETER :: R8=SELECTED_REAL_KIND(12,100)
  real(R8) :: r,z,rho,theta  ! real*8 also works...
  real(R8) :: r2(2),z2(2),rho2(2),theta2(2)

  ! scalar (rho,theta) -> (R,Z)
  call xplasma_ctrans(s,ierr,rho_in=1.0_R8,theta_in=0.0_R8, &
                            r_out=r,z_out=z)

  ! scalar (R,Z) -> (rho,theta)
  call xplasma_ctrans(s,ierr,r_in=r,z_in=z,rho_out=rho,theta_out=theta)

  r2(1)=r
  r2(2)=r-0.01_R8

  z2(1:2)=z

  ! vector (R,Z) -> (rho,theta)
  call xplasma_ctrans(s,xp_use_coord_vecsize,ier, &
          r_in=r2, z_in=z2, rho_out=rho2, theta_out=theta2)

  "xp_use_coord_vecsize" is a logical parameter (value is .TRUE.) defined
  by the xplasma public module; it means the vector size is inferred
  from the arguments (all sizes must match).  The alternative is
  "xp_set_coord_vecsize" (.FALSE.) which allows a size less than or equal
  to the smallest passed vector size to be used.

Full interface:

  interface xplasma_ctrans

     module procedure xplasma_ctran1   ! scalar
     module procedure xplasma_ctrann   ! vector

  end interface

Scalar interface:

    subroutine xplasma_ctran1(s,ier, &
         x_in,y_in,z_in, r_in,phi_in, rho_in,theta_in, &
         tol, maptype, ccw_theta,ccw_phi, i2pi, &
         x_out,y_out,z_out, r_out,phi_out, rho_out,theta_out, &
         nregion,cosphi,sinphi)

Vector interface:

    subroutine xplasma_ctrann(s,vsize_flag,ier, &
         isize, &
         x_in,y_in,z_in, r_in,phi_in, rho_in,theta_in, &
         tol, maptype, ccw_theta,ccw_phi, i2pi, &
         x_out,y_out,z_out, r_out,phi_out, rho_out,theta_out, &
         nregion,cosphi,sinphi)

      !  VECTOR coordinate mapping interface

      type (xplasma), pointer :: s
      logical, intent(in) :: vsize_flag  ! vector size flag
      !  .TRUE. means size is to be inferred from passed vector sizes,
      !  all of which must match;
      !  .FALSE. means size is to be set by optional argument "isize";
      !  all vectors must size.ge.isize then.

      integer, intent(out) :: ier   ! completion code 0=OK

      !------------------------
      ! optional inputs...

      integer, intent(in), optional :: isize  ! vector size if(vsize_flag)

      real*8, intent(in), dimension(:), optional :: x_in,y_in,z_in  ! Cartesian Coords in
      real*8, intent(in), dimension(:), optional :: r_in,phi_in   ! Cylindric Coords (z also)
      real*8, intent(in), dimension(:), optional :: rho_in,theta_in ! Flux Coords (phi also)

      !------------------------------------------------------------
      ! the following applies to (R,Z) -> (rho,theta) "inverse" map:

      real*8, intent(in), optional :: tol           ! map tolerance
      
      ! tol applies to Newton map (maptype = xp_imap_newton = default) ONLY

      ! (R_in,Z_in)->(rho_out,theta_out): 
      !         |R_in-R(rho_out,theta_out)| < tol*max(R_in,|Z_in|) 
      !         |Z_in-Z(rho_out,theta_out)| < tol*max(R_in,|Z_in|) 
      ! default: s%bdytol; s%bdytol's own default value is 1.0d-10

      integer, intent(in), optional :: maptype

      !  = 1 = xp_imap_newton = default -- iterative Newton root finder
      !        with initial guess generator using polar map (slowest but 
      !        most accurate, accuracy can be controlled with tol.
      !  = 2 = xp_imap_polar -- polar map inversion method
      !        much faster, not as accurate as Newton map
      !  = 3 = xp_imap_rzlinear -- bilinear inverse map -- after 
      !        initialization (using polar map), the fastest, but less
      !        accurate still (depends on R,Z grid resolution).  This 
      !        method requires a user defined (R,Z) rectangle grid; if 
      !        none is available the polar map is used instead.

      !------------------------------------------------------------

      logical, intent(in), optional :: ccw_phi  ! Phi CCW view from above, default=T
      logical, intent(in), optional :: ccw_theta ! Theta CCW in poloidal plane, default=T

      integer, intent(in), optional :: i2pi ! angle coord normalization options
      !  i2pi=1 (default) returned value in range [0,2pi]
      !  i2pi=2 returned value in range [-pi,pi]

      !-------------------------
      ! optional outputs...

      real*8, intent(out), dimension(:), optional :: x_out,y_out,z_out  ! Cartesian Coords in
      real*8, intent(out), dimension(:), optional :: r_out,phi_out   ! Cyl. Coords (z also)
      real*8, intent(out), dimension(:), optional :: rho_out,theta_out ! Flux Coords (phi also)

      real*8, intent(out), dimension(:), optional :: cosphi,sinphi   ! phi sin & cos
      integer, intent(out), dimension(:), optional :: nregion        ! region code
      ! 0=not checked; 1=inside core plasma; 2=outside plasma but inside
      ! mapped region; 3=beyond mapped region.


Home Top


Metric_jacobian

The 2x2 form of the metric jacobian [J]

   [ dR/drho   dR/dtheta ]
   [ dZ/drho   dZ/dtheta ]

This is useful for various calculations.  For example,

   2*pi*R*det[J]*drho*dtheta is the differential volume element;

   grad(rho) and grad(theta) are readily derived from [J]; for
   f=f(rho,theta), grad(f) = (df/drho)*grad(rho) + (df/dtheta)*grad(theta).

There is a generic interface xplasma_rzjac that maps to two specific
routines: xplasma_rzjac1 for all scalar arguments; xplasma_rzjacn for
all vector arguments.

The metric jacobian array elements, or R, or Z, or det[J], or components
of grad(rho) or grad(theta), or any combination thereof, can be acquired
with xplasma_rzjac.  The full interface follows...

Full interface:

  interface xplasma_rzjac

     module procedure xplasma_rzjac1   ! scalar
     module procedure xplasma_rzjacn   ! vector

  end interface

Scalar interface:

    subroutine xplasma_rzjac1(s,rho_in,theta_in,ier, ccwflag1, &
         r1,z1,drdrho1,dzdrho1,drdtheta1,dzdtheta1, &
         rzdetj1,drhodr1,drhodz1,dthdr1,dthdz1)

Vector interface:

    subroutine xplasma_rzjacn(s,rho_in,theta_in,ier, &
         ccwflag, r,z,drdrho,dzdrho,drdtheta,dzdtheta, &
         rzdetj, drhodr,drhodz, dthdr,dthdz)

      ! evaluate terms associated with 2d Jacobean -- vector version
      !   [dR/drho dR/dtheta]
      !   [dZ/drho dZ/dtheta]

      ! *** all vectors must be of the same length ***

      type (xplasma), pointer :: s
      real*8, dimension(:) :: rho_in   ! vector of radial coordinate in
      real*8, dimension(:) :: theta_in ! vector of poloidal angle coordinate in
      !  (see ccwflag below)

      integer, intent(out) :: ier      ! completion code 0=OK

      !  Poloidal angle orientation: TRUE (default) if dZ/dtheta is
      !  positive on the large major radius size and negative on the
      !  small major radius side of each flux surface; FALSE for the
      !  reverse.

      logical, intent(in), optional :: ccwflag

      real*8, intent(out), dimension(:), optional :: r,z
      ! (R,Z) values if desired

      real*8, intent(out), dimension(:), optional :: drdrho,dzdrho
      ! rho derivatives if desired

      real*8, intent(out), dimension(:), optional :: drdtheta,dzdtheta
      ! theta derivatives if desired

      real*8, intent(out), dimension(:), optional :: rzdetj 
      ! determinant of 2x2 jacobian matrix

      real*8, intent(out), dimension(:), optional :: drhodr,drhodz
      ! grad(rho) components if desired

      real*8, intent(out), dimension(:), optional :: dthdr,dthdz
      ! grad(theta) components if desired

Home Top


Distance_to_flux_surface

For any point [R,Z] or a vector of points {R(1:n),Z(1:n)}, it is possible
to very accurately find the closest point of approach on a chosen plasma
flux surface.  

The public interface xplasma_bdfind aliases two routines, xplasma_bdfind1
with scalar input and output arguments, and xplasma_bdfindn with vector
input and output arguments, to compute these distances.

Three methods are available, which trade accuracy for speed-- as described
in the interface comments.

Distances returned are in meters; positive numbers denote points outside
the flux surface; negative numbers denote points inside.  The user can
optionally receive information on the location of the point on the flux
surface which is closest to the input point(s).
 
Both these routines are aliased to "xplasma_bdfind" in the module interface.

Full interface:

  interface xplasma_bdfind

     module procedure xplasma_bdfind1   ! scalar
     module procedure xplasma_bdfindn   ! vector

  end interface

Scalar arguments:

    subroutine xplasma_bdfind1(s,zR,zZ,ier, &
         maptype, phi_in, rho_in, ccw_theta, ccw_phi, i2pi, outside_only, &
         theta_out, phi_out, dist)

Vector arguments:

    subroutine xplasma_bdfindn(s,isize,zR,zZ,ier, &
         maptype, phi_in, rho_in, ccw_theta, ccw_phi, i2pi, outside_only, &
         theta_out, phi_out, dist)

      ! accurately find the distance of points (R,Z) from a flux surface
      ! and the closest point on the flux surface

      ! although phi arguments are supplied to support a possible future
      ! upgrade to 3d, these have no effect on axisymmetric calculations.

      use eqi_rzbox_module

      type (xplasma), pointer :: s
      integer, intent(in) :: isize   ! vector size
      !  all array arguments' sizes must be .ge.isize

      !  the target points whose distances from a surface are to be
      !  calculated:

      real*8, dimension(:), intent(in) :: zR   ! R values
      real*8, dimension(:), intent(in) :: zZ   ! Z values

      integer, intent(out) :: ier       ! completion code 0=OK

      !------------
      !  optional arguments

      integer, intent(in), optional :: maptype

      !  = 1 = xp_imap_newton = default -- iterative Newton root finder
      !        with initial guess by searching method, accurate w.r.t.
      !        spline fit of R & Z, to machine precision, but costly...

      !  = 2 = xp_imap_polar -- polar "circle-fit" distance estimate:
      !        The boundary is treated as a piecewise linear interpolation
      !        between circles fit to nearby points on the boundary
      !        much faster, not as accurate as Newton map

      !  = 3 = xp_imap_rzlinear -- bilinear inverse map -- after 
      !        initialization (using polar map), the fastest, but less
      !        accurate still (depends on R,Z grid resolution).  This 
      !        method requires a user defined (R,Z) rectangle grid; if 
      !        none is available the polar map is used instead.

      real*8, dimension(:), intent(in), optional :: phi_in  ! toroidal angle 
      !  (not needed for axisymmetric equilibria)

      real*8, intent(in), optional :: rho_in  ! **SCALAR** -- the surface from
      !  which to calculate distances.  DEFAULT is the boundary surface rho=1.0

      logical, intent(in), optional :: ccw_phi  ! Phi CCW view from above, default=T
      logical, intent(in), optional :: ccw_theta ! Theta CCW in poloidal plane, default=T

      integer, intent(in), optional :: i2pi ! angle coord normalization options
      !  i2pi=1 (default) returned value in range [0,2pi]
      !  i2pi=2 returned value in range [-pi,pi]

      logical, intent(in), optional :: outside_only ! flag that caller only
      !  expects to need data from beyond plasma boundary (default .FALSE.)
      !  (this switch only useful for optimization of maptype=3 calls).

      !-------------
      !  results-- optional but at least one should be present

      real*8, dimension(:), intent(out), optional :: theta_out  ! theta of
      !  nearest point on surface

      real*8, dimension(:), intent(out), optional :: phi_out    ! phi of
      !  nearest point on surface

      real*8, dimension(:), intent(out), optional :: dist       ! distance to
      !  surface.  If dist(j) > 0.0 then (zR(j),zZ(j)) is outside the test
      !  surface; if dist(j) < 0.0 then the point is inside the test surface;
      !  if dist(j) = 0.0 then the point is on the test flux surface.

A caveat:  when the fastest (bilinear) map is used: the distance information 
is good to within the resolution of the map, but... the location-on-surface 
(theta_out) data can be inaccurate in the vicinity of discontinuities in the
location of the nearest point.  These discontinuities occur when passing 
through a plane where two widely separate nearest points are equidistant.
The bilinear interpolation of the fast map data then yields a theta value 
somewhere between the two nearly equidistant points, which is not correct.
The solution, when the accuracy of the angle coordinate of the nearest
point on the surface is of concern, is to use the slower but more accurate
mapping options.

Home Top


Volume_and_Area

When xplasma is loaded with an equilibrium, two spline functions

  Volume(rho) -- volume, m**3, enclosed by rho surface, 0 <= rho <= 1.
  Area(rho)   -- area, m**2, of poloidal cross section enclosed by rho
                 surface, 0 <= rho <= 1.

These are splines defined on the rho grid of the equilibrium.  Two 
convenience routines are for evaluating these functions: xplasma_volume
and xplasma_area.  These are interface names that map to two actual 
routines, one which just returns the total plasma enclosed volume
(or area), the other accepting vector of rho values for which either
the volume (area) or its derivative w.r.t. rho may be returned.
This may best be illustrated by example:

  real*8, parameter :: rho_bdy = 1.0d0
  real*8 :: plasma_volume, plasma_area

  real*8 :: my_rho_grid(5) = (/ 0.0d0, 0.25d0, 0.5d0, 0.75d0, 1.0d0 /)
  real*8 :: my_vols(5),my_areas(5)

  call xplasma_volume(s,plasma_volume, ierr)

  call xplasma_volume(s,my_rho_grid,my_vols, ierr)


  call xplasma_area(s,plasma_area, ierr)

  call xplasma_area(s,my_rho_grid,my_areas, ierr)

The variant with vector arguments accepts an optional argument with which
the derivative of the volume are area may be retrieved:

  interface xplasma_volume
     module procedure xplasma_vol1
     module procedure xplasma_voln
  end interface
    
    subroutine xplasma_voln(s,xs,ans,ier, ideriv)

      !  ** public **

      !  return Volume(x) or dVol/dx -- calculate if needed.

      type (xplasma), pointer :: s
      real*8, dimension(:), intent(in) :: xs      ! evaluation vector
      real*8, dimension(:), intent(out) :: ans    ! result of evaluation
      integer, intent(out) :: ier                 ! completion code 0=OK

      integer, intent(in), optional :: ideriv     ! derivative option 0,1,2

(Here "x" is used for "rho" -- radial flux coordinate).

The accuracies of volumes and areas are to 64 bit machine precision for 
the given equilibrium representation (see next subtopic).

Home Top


Flux_surface_integration

There are many flux surface averaged metric and/or field quantities that
may be needed in a plasma simulation, beyond area and volume.

So, xplasma includes a highly efficient and accurate facility for computing
flux surface integrated or averaged metrics on any user specified grid.

To do this, a program using the xplasma library needs write access (see
subtopic).

The steps involved are:

  a) enable write access to xplasma (xplasma_author_set).

  b) define integration grid & have xplasma initialize data structures
     to support integration.

  c) have xplasma compute each desired integration, one at a time.  If
     integrand data caching is enabled, the efficiency is greatly 
     improved, when multiple integrals or averages need to be computed.

  d) clean up temporary data structures

  e) release write access (xplasma_author_clear).

Home Top


Algorithm_and_accuracy

The integration method used is a 10 point gauss-kronrod-patterson non-
adaptive method, segmented to evaluate a separate 10 point sum between each
pair of grid points on the equilibrium grid.  This means that that the 
segments, or, algebraic sums, products, and quotients of cubic spline
segments for the geometry and magnetic fields as interpolated over
the equilibrium grid.  For non-singular integrands, this yields accuracy
to 64 bit machine precision, as has been verified by comparing to higher-N
gauss-kronrod-patterson summations.  The code to carry this out is derived
from www.netlib.org quadpack/dqng.for.

Of the standard integrations, only the "neoclassical" flux surface
averages "<F(H)NCLASS>S" and "<F(H)NC_TSC>S" involve integrand 
singularities.  These are of the form sqrt(1-B/Bmax).  At present, for 
the sake of convenience and speed, these are evaluated using the same
non-adaptive method with a simple patch to the singularity, resulting
in accuracy of about 1 part in 10**4 compared to a slow, precise method.
This is thought to be sufficient for the purposes of these quantities.

User defined spline profiles f(rho,theta) can also be integrated or 
averaged, but the machine precision accuracy will only be obtained if
the user splines are defined over the equilibrium grid-- i.e. the same
grid as used by "R", R(rho,theta), "Z", Z(rho,theta), and the magnetic
field splines BMOD, BZ, etc.  The accuracies claimed are with respect to
these spline representations of the equilibrium geometry and fields.

Home Top


Write_access_to_xplasma

Using the flux surface integration facility requires writing working data 
to be written into xplasma-- so, it is necessary to introduce routines to 
enable this.

By default, xplasma is opened "write locked"-- dictionary items may not be
added.  To open xplasma to allow new items to be written, it is necessary
to call the following pair of routines:

  character*32 :: author_name = <name-of-my-program-in-quotes>

  call xplasma_author_set(s,author_name,ierr)

    [... execute code requiring write access to xplasma ...]

  call xplasma_author_clear(s,author_name,ierr)

The code actually maintains a stack of author names-- i.e. the code
executed could include subroutine calls to another library which writes
xplasma data under a different authorname, with its own pair of 
xplasma_author_set and xplasma_author_clear calls.

(If a routine fails to issue the trailing xplasma_author_clear call, the
next routine that does issue such a call will see an error, because the
author_name passed will not match the author_name at the top of the
author stack).

Home Top


Define_integration_grid

The user's integration grid spans a subspace of rho [0,1] containing
at least one grid zone.  The entire [0,1] space need not be covered.
The subdivided space is defined by passing the rho zone boundaries to
the setup routine:

  real*8 :: my_rho_grid(5) = (/ 0.0d0, 0.25d0, 0.5d0, 0.75d0, 1.0d0 /)
  integer :: id_integ   ! integrator object ID

  call xplasma_create_integ(s,'my_integrator',my_rho_grid,id_integ,ierr, &
       cache_enable = .TRUE.)

Subsequent integrations using this grid will refer to the integer ID
"id_integ" to reference the integrator.

The integrator defined is now ready to compute surface averages at each
of the grid points (my_rho_grid(1:5)), or, zonal averages covering the
grid zones my_rho_grid(1:2), my_rho_grid(2:3), etc.

For many applications, the 1d integrator is all that is needed.  However,
it is also possible to set up a 2d grid, with an additional subdivision
of space by the poloidal angle coordinate:

  integer ::id_integ_2d  ! 2d integrator object ID
  real*8 :: my_theta_grida(n)

  my_theta_grid(1) = 0.0d0

    ...

  my_theta_grid(n) = 2*pi   ! can also use [-pi,pi] 
  !  or perhaps not span the entire theta coordinate range.

  call xplasma_augment_integ(s,'my_2d_integrator',id_integ,my_theta_grid, &
       id_integ_2d,ierr)

Note that now two integrators are defined, with IDs:

  id_integ -- 1d integrator
  id_integ_2d -- 2d integrator.

Home Top


Execute integrations

The typical call to evaluate a flux surface average looks like this:

  real*8 :: answer(nn)    ! nn the grid size specified earlier to
  real*8 :: ans_zon(nn-1) ! "xplasma_creat_integ"...

  real*8 :: ans_2d(nth,nn)  ! nth the theta grid size specified earlier
  real*8 :: ans_2dzon(nth,nn-1)  ! to "xplasma_augment_integ"...

  ! get the differential volume averaged <1/R^2> on my flux surfaces...
  call xplasma_rho_zonint(s,id_integ,'<1/R^2>S',answer,ierr)

  ! one can also evaluate
  call xplasma_rho_zonint(s,id_integ,'<1/R^2>',ans_zon,ierr)
  ! BUT it is much slower and usually the differential average is enough
  ! for modeling applications...

  ! <1/R^2> = zonal integral[dVol*(1/R**2)]/integral[dVol] over entire zone
  ! <1/R^2>S = surface integral[dVol*(1/R**2)]/integral[dVol] 
  !          = surface integral[dVol*(1/R**2)]/(dVol/drho at surface)

  !   dVol = 2*pi*R*[(dl/dtheta)/grad(rho)]*dtheta*drho
  !          (available from the equilibrium metric tensor)

  ! integrations can also be done separately for each theta zone.  The
  ! 1st dimension of ans_2d or ans_2dzon must match the number of theta
  ! zones:

  ! get volume of each zone in a 2d partitioning of flux space:

  call xplasma_2d_zonint(s,id_integ_2d,'dVOL',ans_2dzon,ierr)

Note that the 3rd argument (character string) identifies the integration
to be computed.

The following integrals and averages are available.  The intregral name
passed argument must match one of these exactly, after uppercase conversion:

  surface-oriented     zone-oriented    remark

    "VOL"                               enclosed volume, m**3
                         "dVOL"         volume in each zone

    "AREA"                              enclosed cross sectional area, m**2
                         "dAREA"        area in each zone

    "DVDRHO"                            dVol/drho at each surface, m**3
    "LPOL"                              poloidal path length, m
    "SURF"                              area of flux surface, m**2

    "ITOR"                              enclosed toroidal current, A

    "<1/R^2>S"           "<1/R^2>"      m**-2
    "<1/R>S"             "<1/R>"        m**-1
    "<1/R^3>S"           "<1/R^3>"      m**-2
    "<R^2>S"             "<R^2>"        m**2
    "<R>S"               "<R>"          m

    "<1/B^2>S"           "<1/B^2>"      T**-2
    "<1/B>S"             "<1/B>"        T**-1
    "<B^2>S"             "<B^2>"        T**2
    "<B>S"               "<B>"          T
    "<BZ^2>S"            "<BZ^2>"       T**2

    "<grad(RHO)>S"       "<grad(RHO)>"    m**-1
    "<grad(RHO)^2>S"     "<grad(RHO)^2>"  m**-2
    "<grad(RHO)^2/R^2>S" "<grad(RHO)^2/R^2>"   m**-4
    "<grad(RHO)^2/R^3>S" "<grad(RHO)^2/R^3>"   m**-5
    "<R^2*grad(RHO)^2>S" "<R^2*grad(RHO)^2>"   dimensionless
    "<1/(R*grad(RHO))>S" "<1/(R*grad(RHO))>"   dimensionless
    "<grad(RHO)^2/B^2>S" "<grad(RHO)^2/B^2>"   m**-2*T**-2

the following have sqrt singularities; the result is less accurate than
with continuously differentiable integrands:

    "<F(H)NCLASS>S"                     <(1-sqrt(1-h))(1+h/2)/(h*h)>; h=B/Bmax
    "<F(H)NC_TSC>S"                     <(1/B**2)*sqrt(1-h)*(2+h)/3>; h=B/Bmax

if "USER_FUNC" is the name of a profile vs. (rho,theta) existing in the 
current xplasma:

    "<USER_FUNC>S"      "<USER_FUNC>"   surface or zone averaged USER_FUNC
    "I(USER_FUNC)S"     "I(USER_FUNC)"  surface or zone integral of USER_FUNC

Any profile of (rho,theta) can be integrated or averaged in this way.

Home Top


xplasma_rho_zonint

    subroutine xplasma_rho_zonint(s,idi,int_name,result,ier, &
         dvol_out,iwarn_dvol,dvdrho_out,iwarn_dvdrho)

      ! integrator -- over rho zones result of form f(rho) indexed by zone
      !                      1 result per zone (#zones)
      !               or rho surfaces, also result of form f(rho)
      !                      1 result persurface (#zones + 1)

      type (xplasma), pointer :: s
      integer, intent(in) :: idi ! integrator data structure ("black box") id
      character*(*),intent(in) :: int_name ! name of desired integration
      real*8, dimension(:), intent(out) :: result
      integer, intent(out) :: ier  ! status code 0=OK

      !  ** optional outputs **

      real*8, dimension(:), optional :: dvol_out   ! zone volumes
      integer, intent(out), optional :: iwarn_dvol ! =0 if zone volumes OK
      ! iwarn_dvol=1: zone volumes not available; =2: array dimension error.

      real*8, dimension(:), optional :: dvdrho_out ! dV/drho @ surfaces
      integer, intent(out), optional :: iwarn_dvdrho ! =0 if dV/drho OK
      ! iwarn_dvdrho=1: dV/drho not available; =2: array dimension error.

Home Top


xplasma_2d_zonint

    subroutine xplasma_2d_zonint(s,idi,int_name,result,ier, &
         dvol_out,iwarn_dvol,dvdrho_out,iwarn_dvdrho)

      ! integrator -- 2d domain; return integrations or averages
      !   over theta^rho zones or across theta zones at rho surfaces.

      type (xplasma), pointer :: s
      integer, intent(in) :: idi ! integrator data structure ("black box") id
      character*(*),intent(in) :: int_name ! name of desired integration
      real*8, dimension(:,:), intent(out) :: result
      integer, intent(out) :: ier  ! status code 0=OK

      ! result is dimension [#theta-zones,#rho-zones] or
      !        [#theta-zones,#rho-surfaces] according as the integrand
      !        specified is zone oriented or surface oriented.
      !          The #zones are defined when the integrator dataset (idi)
      !          is defined.

      !  ** optional outputs **

      real*8, dimension(:,:), optional :: dvol_out   ! zone volumes
      integer, intent(out), optional :: iwarn_dvol   ! =0 if zone volumes OK
      ! iwarn_dvol=1: zone volumes not available; =2: array dimension error.

      real*8, dimension(:,:), optional :: dvdrho_out ! dV/drho @ surfaces
      integer, intent(out), optional :: iwarn_dvdrho ! =0 if dV/drho OK
      ! iwarn_dvdrho=1: dV/drho not available; =2: array dimension error.

      ! Options for integrands is the same as for xplasma_rho_zonint;
      ! Surface oriented results e.g. LPOL are on rho surfaces at each theta 
      ! zone;
      ! Zone orented results e.g. dVol are on rho^theta zones.


Home Top


Cleanup

After completion of use of the integrator or integrators, it is a good idea
to clean up, i.e. free the memory and temporary data associated with the
integrators.

  call xplasma_remove_item(s,id_integ,ierr)    ! remove integrator (rho)

...and if integrations segmented in theta space were done:

  call xplasma_remove_item(s,id_integ_2d,ierr) ! remove integrator (rho,theta)

(In general, "xplasma_remove_item" will report an error in case of an 
attempt to remove a non-existent item, or an item not owned by the current
author).

Finally, as previously mentioned, it is important to close the "write"
connection to xplasma:

  call xplasma_author_clear(s,author_name,ierr)
    (author_name the same character string as used in a prior 
     xplasma_author_set call).

Home Top


Poloidal_flux_grid

For codes that use a grid based on poloidal flux, it can be useful to
get a mapping to rho=sqrt(toroidal_flux/toroidal_flux_at_bdy).  The
following xplasma subroutine provides a precise mapping:

    subroutine xplasma_rhopsi_find(s,psivals,rhovals,ierr, tol, iwarn)

      !  find rho values corresponding to a specified set of Psi values
      !    Psi -- Poloidal flux, Wb/rad
      !    rho -- sqrt(Tor_flux/Tor_flux_at_bdy)

      !  all input Psi values should be in the range [Psimin,Psimax] where
      !  Psimin corresponds to the magnetic axis and Psimax-Psimin
      !  corresponds to the (unsigned) poloidal flux, Wb/rad, enclosed 
      !  within the core plasma.  Usually Psimin=0 is set.

      type (xplasma), pointer :: s
      real*8, dimension(:), intent(in) :: Psivals  ! Psi values in any order
      real*8, dimension(:), intent(out) :: rhovals ! rho values output
      !  sizes of Psivals and rhovals must match

      integer, intent(out) :: ierr   ! status code, =0 on normal exit
      !  error occurs if xplasma is unitialized or contains no MHD equilibrium;
      !  Psi-out-of-range is handled (see iwarn, below).

      real*8, intent(in), optional :: tol     ! accuracy tolerance
      !  on output, rho values satisfy
      !     abs(Psi(rhovals(i))-Psivals(i)) <= tol*[Psi at bdy]
      !  (1:npsi) -- sqrt(toroidal_flux/toroidal_flux_at_bdy)
      !  0 on axis, 1 at the edge.

      integer, intent(out), optional :: iwarn  ! #of Psi values out of range

      !  if Psi <= Psimin, rho=0 is returned; if Psi >= Psimax rho=1 is
      !  returned.

Caution-- note that the input Psi values are in physical units, Wb/rad, 
not normalized to 1.000 at the boundary.  But the following conventions
are used:

   Psi=0 at the magnetic axis
   Psi is "unsigned", always non-negative; rho > 0 ==> Psi'(rho) > 0.

The range of currently known Psi values within the plasma can be had
with the following call:

   real*8 psimin,psimax
   call xplasma_psi_range(s,psimin,psimax)

The sign of the poloidal flux can be had by fetching jphi_ccw, as in:

   integer :: jphi_ccw
   call xplasma_global_info(s,ierr, jphi_ccw=jphi_ccw)

The convention is: jphi_ccw=1 means that toroidal current flows counter-
clockwise in the tokamak as viewed from above.

Home Top


Find_data_items

Acquiring xplasma data generally involves two steps:

  a) translate name to integer ID (look up in dictionary)
  b) access the data, using the ID.

This section describes step (a).

If data of a known type is expected to exist under a known name, the 
following calls are the easiest to use:

  character*32 :: name
  integer :: id

  name = <the-name-you-want>

  call xplasma_profId(s,name,id)   ! look up a PROFILE

    --or--

  call xplasma_gridId(s,name,id)   ! look up a GRID

    --or--

  call xplasma_coordId(s,name,id)  ! look up a PROFILE

    --or--

  call xplasma_listId(s,name,id)   ! look up a LIST

    --or--

  call xplasma_blkbxId(s,name,id)  ! look up a BLACK BOX

Note there is no "ierr" code.  If the item does not exist, or if it is
of the wrong type, or if there is some other error (e.g. "s" is a NULL 
pointer), id=0 is returned.

Home Top


Alternate_method:

  ! this returns the ID of an item, no matter what its type is.

  ! setting nf_noerr=.TRUE. causes non-existence of the item not to
  ! be considered an error; this is an optional argument.

  call xplasma_find_item(s,name,id,ierr,nf_noerr=.TRUE.)

  ! itype is an integer...
  
  call xplasma_get_item_info(s,id,ierr, itype=itype)

  if(itype.eq.xplasma_profType) then
     <it is a profile>

  else if(itype.eq.xplasma_gridType) then
     <it is a grid>

  ...etc...

Home Top


xplasma_common_ids

The following call is used mainly within xplasma to retrieve the IDs of
commonly used items; it is publicly accessible:

    subroutine xplasma_common_ids(s,ier, &
         id_g,id_psi,id_P,id_R,id_Z,id_Bmod,id_BR,id_BZ, &
         id_axis,id_RZminmax)

      !  return commonly requested profile IDs
      !  g(rho), psi(rho), R(rho,theta), Z(rho,theta)

      type (xplasma), pointer :: s
      integer, intent(out) :: ier

      integer, intent(out), optional :: id_g
      integer, intent(out), optional :: id_psi
      integer, intent(out), optional :: id_P
      integer, intent(out), optional :: id_R
      integer, intent(out), optional :: id_Z
      integer, intent(out), optional :: id_BR
      integer, intent(out), optional :: id_BZ
      integer, intent(out), optional :: id_BMOD

      integer, intent(out), optional :: id_axis
      integer, intent(out), optional :: id_RZminmax

Home Top


Information_on_items

Use "xplasma_get_item_info" to retrieve one or more of the following:

    character*32 :: name
    character*32 :: author
	
    character*(*) :: label 
    character*(*) :: units

    integer :: itype  ! type of item (list, profile, grid, etc.)

All the return arguments are OPTIONAL and keyworded outputs.  An optional
input argument nf_noerr can be set .TRUE. to ignore "invalid ID" errors,
i.e. not to create a message or set an error code in this case.

Example:

    character*32 :: my_name,my_author

    call xplasma_get_item_info(s,id,ierr, name=my_name, author=my_author)
    
Full interface:

    subroutine xplasma_get_item_info(s,id,ier, &
         nf_noerr, &
         name,label,units,itype,author)

      ! return info on item-- what info determined by presence of
      ! optional arguments

      type (xplasma), pointer :: s
      integer, intent(in) :: id    ! id of item for which info is requested
      integer, intent(out) :: ier  ! return status code  (0=OK)

      !  optional control:
      logical, intent(in), optional :: nf_noerr  ! .TRUE. to allow ivalid id

      !  here is what can be returned...

      character*(*), intent(out), optional :: name     ! name of item
      character*(*), intent(out), optional :: label    ! item label
      character*(*), intent(out), optional :: units    ! item units label
      integer, intent(out), optional :: itype          ! item type
      character*(*), intent(out), optional :: author   ! name of author

Home Top


Tables_of_contents

It is possible to retrieve an entire table of contents of any category
of xplasma data type.  Since the interface uses optional arguments, the
user's code decides what type of table of contents list is to be fetched.

In addition, there is special treatment of lists containing elements that
identify profiles (list element name and integer value match name and id of
profile).

The following routine fetches the lengths of the ID lists for tables of
contents:

    subroutine xplasma_num_items(s,ier, &
         author_only, &
         num_lists, num_plists, num_coords, num_grids, num_profs, num_blkbxs)

      !  return the total numbers of items of various types in xplasma 
      !  container object.

      type (xplasma), pointer :: s
      integer, intent(out) :: ier ! error code -- only set if s not initialized

      character*(*), intent(in), optional :: author_only
      !  set this to restrict the list to items owned by the specified author

      integer, intent(out), optional :: num_lists   ! no. of lists
      integer, intent(out), optional :: num_plists  ! no. lists refering
                                                    !     to profiles
      integer, intent(out), optional :: num_coords  ! no. of coordinates
      integer, intent(out), optional :: num_grids   ! no. of grids
      integer, intent(out), optional :: num_profs   ! no. of profiles
      integer, intent(out), optional :: num_blkbxs  ! no. of black boxes

The following routine fetches the actual lists of ids of the indicated type.
Note that ierr=60 is returned if a passed integer array meant to receive
the contents list is too small...

    subroutine xplasma_contents(s,ier, &
         author_only, &
         id_lists, id_plists, id_coords, id_grids, id_profs, id_blkbxs)

      !  return sorted list(s) of ids of objects of indicated type(s).
      !    lists of lists, lists of profiles, etc.

      type (xplasma), pointer :: s
      integer, intent(out) :: ier ! error code, 0=OK

      character*(*), intent(in), optional :: author_only
      !  set this to restrict the list to items owned by the specified author

      integer, dimension(:), intent(out), optional :: id_lists  ! lists
      integer, dimension(:), intent(out), optional :: id_plists ! lists that
                                                      ! refer to profiles
      integer, dimension(:), intent(out), optional :: id_coords ! coordinates
      integer, dimension(:), intent(out), optional :: id_grids  ! grids
      integer, dimension(:), intent(out), optional :: id_profs  ! profiles
      integer, dimension(:), intent(out), optional :: id_blkbxs ! black boxes

The returned contents lists are sorted in alphabetic order of the names
corresponding to each item ID.

Home Top


Lists

The LIST is one of the data types supported within xplasma.

Each list has a name, and contains a named set of elements.  Each element
in addition to its name can have an integer, a floating point value, and
a character string associated with it.  Element names must be unique within
the list but are not part of and do not conflict with the xplasma namespace--
indeed, one of the uses of lists is to gather the names and IDs of related 
xplasma data items.

Some example applications of lists:

  -- storage of commonly referenced data, such as the plasma magnetic axis
     location;

  -- storage of scalar data, such as plasma ion species lists with the 
     Z and A of each ion species specified.

  -- storage of lists of names and IDs of useful sets of xplasma profiles.

If a list name is known, use the following call to get its integer ID:

  call xplasma_listId(s,name,id)   ! look up a LIST

Methods for accessing list data are described in the subtopics.

Home Top


xplasma_list_info

This routine optionally returns the size of a list and labeling information
for the list (the list itself, not the member elements):

    subroutine xplasma_list_info(s,id,ier, &
         nelems,name,label,units,author)
      !
      !  get the size of an existing list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      integer, intent(out) :: ier         ! completion code

      integer, intent(out), optional :: nelems  ! no. of list elements in list

      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: label
      character*(*), intent(out), optional :: units
      character*(*), intent(out), optional :: author

Home Top


xplasma_getList_size

To just get the size of a list:

    subroutine xplasma_getList_size(s,id,nelems,ier)
      !
      !  get the size of an existing list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      integer, intent(out) :: nelems      ! no. of list elements in list
      integer, intent(out) :: ier         ! completion code

Home Top


xplasma_getList_names

To get the names of list elements, and, optionally, element data and/or
global labels for lists, this routine can be used:

    subroutine xplasma_getList_names(s,id,enames,ier, &
         name,label,units,author,ivals,r8vals,chvals)
      !
      !  get the element names from an existing list
      !   optional arguments allow additional data to be fetched as well.
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      character*(*), dimension(:), intent(out) :: enames ! the names...
      integer, intent(out) :: ier         ! completion code

      character*(*), intent(out), optional :: name   ! name (of whole list)
      character*(*), intent(out), optional :: label  ! label (for whole list)
      character*(*), intent(out), optional :: units  ! units label (whole list)
      character*(*), intent(out), optional :: author ! author

      integer, intent(out), dimension(:), optional :: ivals   ! integer values
      real*8, intent(out), dimension(:), optional :: r8vals   ! real*8 values
      character*(*), intent(out), dimension(:), optional :: chvals  ! str vals

Home Top


xplasma_getList_ivals

    subroutine xplasma_getList_ivals(s,id,ivals,ier)
      !
      !  get integer values in list (r4 precision)
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      integer, dimension(:), intent(out) :: ivals  ! the integer values
      integer, intent(out) :: ier         ! completion code
Home Top


xplasma_getList_r8vals

    subroutine xplasma_getList_r8vals(s,id,r8vals,ier)
      !
      !  get real*8 values in list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      real*8, dimension(:), intent(out) :: r8vals ! the real*8 values
      integer, intent(out) :: ier         ! completion code

 4 xplasma_getList_r4vals
    subroutine xplasma_getList_r4vals(s,id,r4vals,ier)
      !
      !  get floating point values in list (r4 precision)
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      real, dimension(:), intent(out) :: r4vals ! the floating point values
      integer, intent(out) :: ier         ! completion code

Home Top


xplasma_getList_chvals

    subroutine xplasma_getList_chvals(s,id,chvals,ier)
      !
      !  get character string values in list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      character*(*), dimension(:), intent(out) :: chvals 
                                          ! the character string values
      integer, intent(out) :: ier         ! completion code


Home Top


Coordinates

The COORDINATE is one of the data types supported within xplasma.  It
contains little actual data-- it exists mainly as a mechanism to define
the semantics of grids, with the following associations:

  (a) profiles are defined over grids;
  (b) grids are associated with coordinates.

Each specific grid is associated with a single coordinate.  Multiple grids
can be associated with the same coordinate.  Interpolation of profiles is
organized by means of coordinates.

Like all xplasma data items, coordinates have names, labels, physical units,
and authors.  Additional attributes of coordinates are:

  (a) whether or not a coordinate is periodic;
  (b) the minimum and maximum value (range) of a coordinate.

When an xplasma object is initialized, several coordinates are predefined;
their IDs are public parameters supplied by xplasma f90 modules:

  integer, parameter, public :: xplasma_rho_coord = 1   ! radial flux coord.
  integer, parameter, public :: xplasma_theta_coord = 2 ! poloidal angle coord.
  integer, parameter, public :: xplasma_phi_coord = 3   ! toroidal angle coord.
  integer, parameter, public :: xplasma_R_coord =   4   ! R coord
  integer, parameter, public :: xplasma_Z_coord =   5   ! Z coord
  integer, parameter, public :: xplasma_rhox_coord =6   ! "rho" extrapolation
  integer, parameter, public :: xplasma_thx_coord = 7   ! "theta" extrapolation
  integer, parameter, public :: xplasma_B_coord =   8   ! mod(B) grid
  integer, parameter, public :: xplasma_vpv_coord = 9   ! vpll/v coord.

These parameters are frequently used, e.g. to identify the coordinates
of input arguments in multivariate profile interpolation calls.

The above list is sufficient for some applications.  However, codes may 
define additional coordinates.  For example, in the NUBEAM fast ion Monte
Carlo model, a separate energy coordinate is defined for each fast ion 
species distribution function, because, the energy range desired for 
distribution functions varies from species to species, e.g. fusion 
product ion species vs. beam ion species.

Several routines exist for making inquiries about coordinates, as shown
in the subtopics.

Home Top


xplasma_coord_info

    subroutine xplasma_coord_info(s,id,ier, &
         ngrids,periodic,xmin,xmax,name,label,units,author)

      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! coordinate object id
      integer, intent(out) :: ier   ! completion code, 0=OK

      integer, intent(out), optional :: ngrids    ! # of grid discretizations
      logical, intent(out), optional :: periodic  ! periodicity flag
      real*8, intent(out), optional :: xmin       ! min value
      real*8, intent(out), optional :: xmax       ! max value

      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: label
      character*(*), intent(out), optional :: units
      character*(*), intent(out), optional :: author

Home Top


xplasma_coord_gridId

It is possible to retrieve the IDs of specific grids discretizing a
coordinate.  This is probably not how it will be done in applications,
which are more likely to find grids by starting from a profile ID.
Nevertheless, this public interface is supplied.  The value of the input
argument "indx" should be between 1 and "ngrids", the upper limit being
the number of grids known to discretize the coordinate (see the
xplasma_coord_info call).

    subroutine xplasma_coord_gridId(s,id,indx,idgrid,ier)

      !  get grid id from coordinate grid list index

      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! coordinate object id
      integer, intent(in) :: indx   ! which grid is desired
      integer, intent(out) :: idgrid  ! grid id of desired grid
      integer, intent(out) :: ier   ! completion code, 0=OK

Home Top


xplasma_coord_isPeriodic

This public interface is provided; the periodicity attribute can also
be obtained through an optional argument in the xplasma_coord_info call.

    subroutine xplasma_coord_isPeriodic(s,id,periodic,ier)

      !  get information whether coordinate object is a periodic angle coord.

      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! coordinate object id
      logical, intent(out) :: periodic ! T if this is a periodic coordinate
      integer, intent(out) :: ier   ! completion code, 0=OK
 
Home Top


Grids

The GRID is one of the data types supported within xplasma.

Each grid is a strict ascending sequence of numbers covering a specific
range, and is associated with and discretizes a specific COORDINATE.

Some coordinates have a prescribed range-- e.g. the normalized radial
flux coordinate xplasma_rho_coord always covers the range 0 (the magnetic
axis) to 1 (the plasma boundary).

Grids over periodic coordinates cover a range of either [0,2pi] or [-pi,pi].

Some coordinates have their ranges defined by the first discretizing grid--
e.g. xplasma_R_coord and xplasma_Z_coord-- the dimensions of the [R,Z] box
defining a computational region that will vary from tokamak to tokamak.

With the exception of periodic coordinates, all grids discretizing a
given coordinate must cover exactly the same range-- i.e. the first and
last elements of the sequence of numbers defining the grid are constrained
by the coordinate discretized by the grid.

If the name of a grid is known and its ID is needed, the following call
can be used:

  call xplasma_gridId(s,name,id)   ! look up a GRID

Home Top


xplasma_grid_size

Get the size of a grid...

    subroutine xplasma_grid_size(s,id,nx,ier)

      !  get grid size

      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! grid object id
      integer, intent(out) :: nx    ! grid size
      integer, intent(out) :: ier   ! completion code, 0=OK

Home Top


xplasma_grid

Get the grid itself.  The array "x" must precisely match the size of
the grid.

    subroutine xplasma_grid(s,id,x,ier, ccwflag)

      !  get grid

      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! grid id object
      real*8, intent(out) :: x(:)   ! the grid returned
      integer, intent(out) :: ier   ! completion code, 0=OK

      logical, intent(in), optional :: ccwflag  ! orientation flag 
      ! default value is .TRUE., signifying counter-clockwise orientation

If the grid is periodic, ccwflag=.FALSE. causes the grid to be returned
in reverse order, corresponding e.g. to a clockwise drawn angle coordinate.

The internal grid is always stored with clockwise orientation.  The
ccwflag=.FALSE. transform of a periodic grid theta(...) with ntheta 
points covering range [-pi:pi] is: 

     theta_reverse(j) = -pi + (pi - theta(ntheta+1-j))
     for j=1:ntheta

Home Top


xplasma_grid_info

This routine returns information on a grid and its associated coordinate.

Other than the xplasma object pointer, the ID, and return status code, all
arguments are optional, so, the caller can select the information desired.

    subroutine xplasma_grid_info(s,id,ier, &
         size,xmin,xmax,perio,coord,nrefs,name,label,units,author)

      !  get grid reference count (# of profile items using this grid)

      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! grid id object
      integer, intent(out) :: ier   ! completion code, 0=OK

      integer, intent(out), optional :: size  ! size of grid
      real*8, intent(out), optional :: xmin   ! minimum grid value
      real*8, intent(out), optional :: xmax   ! maximum grid value
      logical, intent(out), optional :: perio ! T for periodic grids
      integer, intent(out), optional :: coord ! coordinate associated w/grid
      integer, intent(out), optional :: nrefs ! no. of references to grid

      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: label
      character*(*), intent(out), optional :: units
      character*(*), intent(out), optional :: author

Home Top


Profiles

The PROFILE is one of the data types supported within xplasma.  Indeed,
xplasma was largely invented to support the storage, retrieval, and
interpolation of profiles used in plasma simulations.

Profiles are defined over grids (and hence over coordinates as well).

For purposes of interpolation, it is generally enough to know the
coordinates over which a profile is defined, but, it is of course
possible to retrieve the underlying grids, and the original un-
interpolated data, if desired.

Profiles can be 1d, 2d, or 3d-- i.e. defined over 1, 2, or 3 grids
(coordinates).

The interpolation method for a profile is defined by the creator of
the profile.  The possibilities are the methods supported by the
PSPLINE NTCC module-- piecewise linear (continuous), cubic Hermite
(continuous and continuously once differentiable), and cubic spline
(continuous and continuously twice differentiable along any coordinate).
In addition, XPLASMA allows zonal step function data to be defined.

For more information on interpolation, see the PSPLINE NTCC web page,
 https://w3.pppl.gov/NTCC/PSPLINE. 

There is a generic interface for profile interpolation: xplasma_eval_prof.
Using this interface, retrieval of profile information basically comes 
down to making an appropriate xplasma_eval_prof call.  This method will
be described in detail.

If the name of a profile is known, the following xplasma call retrieves
its ID:

  call xplasma_profId(s,name,id)   ! look up a PROFILE

Home Top


xplasma_prof_info

The following call allows access to detailed information on a given
profile, as identified by its ID.  Many of the arguments are self-
explanatory, but further information on those that might not be is
given below.

    subroutine xplasma_prof_info(s,id,ier, &
         rank,splineType,gridId1,gridId2,gridId3,profId1,gridType,counter, &
         name,label,units,author)

      !  base argauments in/out
      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! profile object id
      integer, intent(out) :: ier   ! completion code, 0=OK

      !---------------------------------------------------
      !  select desired information with optional arguments...

      integer, intent(out), optional :: rank  ! rank

      integer, intent(out), optional :: splineType  
      ! -1 for step function; 0 for piecewise linear,
      ! 1 for C1 Hermite, 2 for C2 cubic spline

      integer, intent(out), optional :: gridId1  ! id of 1st grid
      integer, intent(out), optional :: gridId2  ! id of 2nd grid (or zero)
      integer, intent(out), optional :: gridId3  ! id of 3rd grid (or zero)

      integer, intent(out), optional :: profId1  ! id of associated profile
      !  (sometimes f(R,Z) has an associated f(rho,theta) profile available,
      !  and vice versa).

      integer, intent(out), optional :: gridType ! generic grid type code
      ! 0=unknown or mixed
      ! 1=flux coords (rho) or (rho,theta) [phi someday]
      ! 2=cylindric coordinates (R,Z) [phi someday]

      integer, intent(out), optional :: counter  ! profile counter
      ! each new version of this profile gets a new counter value.

      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: label
      character*(*), intent(out), optional :: units
      character*(*), intent(out), optional :: author

Notes on argumentes:

  rank -- the dimensionality of the profile: 1 for 1d, 2 for 2d, 3 for 3d.

  profId1 -- ID for quantity defined over "alternate" grids.  For some
    profiles there are two versions-- one defined over flux coordinates
    and one defined over [R,Z] coordinates.  If for the input profile ID
    an alternate version exists, the alternate version ID can be returned
    with this argument.  When interpolations are performed, if the 
    coordinates supplied are not appropriate for a given profile ID, the
    profile's alternate ID, if available, will be tried before giving up.

  gridType -- this can be used to determine if the profile is defined over
    flux coordinates or cylindrical coordinates.  The following public
    parameters are available for reference:

  integer, parameter, public :: xplasma_flux_coords = 1 ! generic flux coord.
  integer, parameter, public :: xplasma_cyl_coords = 2  ! generic cyl. coord.

Home Top


xplasma_prof_gridInfo

An alternate method of acquiring a profile's grid information is shown 
here; xplasma_prof_info can also be used.

    subroutine xplasma_prof_gridInfo(s,id,icoord,idgrid,ierr, &
         id_actual)

      type (xplasma), pointer :: s
      integer, intent(in) :: id     ! id of profile about which info is sought
      integer, intent(in) :: icoord ! coordinate sought

      integer, intent(out) :: idgrid   ! grid over this coordinate, or zero
      !  zero means profile identified by "id" is not a function of the
      !  specified coordinate; this is not considered an error.

      integer, intent(out) :: ierr  ! error status code returned, 0=OK
      !  errors: profile id is invalid; coordinate id is invalid...

      integer, intent(out), optional :: id_actual  ! "actual" profile id
      !  explanation: for some quantities there are two representations,
      !  e.g. Bphi(R,Z) and Bphi(rho,theta).  The passed id can refer to
      !  either of these; the coordinate sought is found for the appropriate
      !  representation.  Thus, if id points to Bphi(R,Z) and info on a rho
      !  grid is sought, id_actual (if present) will be set to the id of 
      !  Bphi(rho,theta).


Home Top


xplasma_eval_prof

xplasma_eval_prof is a generic interface that can be used in any of the
following modes:

  (1) interpolate 1d, 2d, or 3d profiles to given target coordinates.
  (2) interpolate 1d, 2d, or 3d profiles using previously calculated
      lookup information.
  (3) retrieve the original profile data (no interpolation).

Each type of use is considered in the subtopics.

Home Top


standard_interpolation

Interpolations are supported on 1d, 2d, and 3d profiles, and, in a
single call it is possible to perform interpolations on 1 profile
or multiple profiles, at 1 target location or at a vector of target
locations.  Function values or derivatives can be returned.  Angle
coordinates may optionally be reversed with transformations
theta -> 2pi - theta.

When the rank of the profiles being evaluated exceeds one, the 
coordinate arguments can be given in any order, with grid or 
coordinate ID information given to indicate which is which.

Generally for non-periodic coordinates it is an error to provide
target coordinate data that is out of bounds; this behavior can be
overridden with an optional argument "force_bounds".  The number
of out of bounds target points can be returned in the optional
output argument "n_out_of_bounds".

The relative tolerance for out-of-bounds tests is "bdytol", available
with the call:

  call xplasma_global_info(s,ierr, bdytol=bdytol);

interpolation target coordinates that exceed the coordinate minimum xmin
or maximum xmax by more than bdytol*[xmax-xmin] are considered out of 
bounds.

The result "ans" returned is a scalar if there is a single profile id
and a scalar target point.  It is a vector if there is either a list
of profile ids or a vector of target points.  If there is both a list
of profile ids and a vector of target points, ans is a 2d array with
size(ans,1) matching the target vector dimension, and size(ans,2) 
matching the number of profile ids; ans(:,1) will be the results of
the evaluation of the 1st profile; ans(2,:) will be the results for
all profiles at the 2nd target coordinate location.

Here are some example calls:

  integer :: id1,id2(2)
  real*8 :: x,xvec(3),yvec(3)
  real*8 :: ans00,ans2(2),ans3(3),ans2d(3,2)

  ! 1 id, 1 target, eval 1st derivative
  call xplasma_eval_prof(s,id1,x,ans00,ier, ideriv1=1)

  ! 2 ids, 1 target, eval profile value
  call xplasma_eval_prof(s,id2,x,ans2,ier)

  ! 1 id, vector target, eval profile values
  call xplasma_eval_prof(s,id,xvec,ans3,ier)

  ! 2 ids, vector target, eval value of 1st profile, derivative of 2nd
  call xplasma_eval_prof(s,id2,xvec,ans32,ier, ideriv1s = (/0,1/))

  ! 2d profile evaluation (no derivatives; xvec is "rho"; yvec is "theta"):
  call xplasma_eval_prof(s,id2, &
        xplasma_rho_coord,xvec, xplasma_theta_coord,yvec, ans32, ier)

When the 2d or higher evaluation routine is called, it is possible for
some of the profiles evaluated to be 1d, provided that the coordinate
scalar or vector argument needed for evaluation of the 1d profile is 
present.

What follows is the full interface for the calls mapped to when multiple
ids and a vector target is provided to xplasma_eval_prof.

For 1d profile evaluation:

    subroutine xplasma_eval_1dprofsxs(s,ids,xs,ans,ier, &
         ideriv1,ideriv1s,ccwflag1,force_bounds,n_out_of_bounds)

      !  evaluate multiple profiles f(x) 1d at a vector of points

      type (xplasma), pointer :: s
      integer, dimension(:), intent(in) :: ids    ! profile ids
      real*8, dimension(:), intent(in) :: xs      ! evaluation vector
      real*8, dimension(:,:), intent(out) :: ans  ! result of evaluations
      integer, intent(out) :: ier                 ! completion code 0=OK

      !  ans(1:size(xs),1) -- result of eval of profile ids(1)
      !  ans(1:size(xs),2) -- result of eval of profile ids(2) ...etc...

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv1    ! derivative control
      !    1 for df/dx; 2 for d2f/dx2; 3 for d3f/dx3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv1s
      !  as ideriv1 but specified separately for each profile

      !  default: T -- CCW orientation, no CW->CCW transform
      logical, intent(in), optional :: ccwflag1

      !  default: F -- T to force all points in bounds with min & max
      logical, intent(in), optional :: force_bounds

      !  optional output: return no. of target points out of range
      integer, intent(out), optional :: n_out_of_bounds

      ..............

For 2d profile evaluation:

    subroutine xplasma_eval_2dprofsxs(s,ids,idx1,x1s,idx2,x2s,ans,ier, &
         ideriv1,ideriv1s,ideriv2,ideriv2s, &
         ccwflag1,ccwflag2,force_bounds,n_out_of_bounds)

      !  evaluate multiple profiles f(x1,x2) 2d at a vector of points

      type (xplasma), pointer :: s
      integer, dimension(:), intent(in) :: ids    ! profile ids
      integer :: idx1                             ! id of x1 grid or coord.
      real*8, dimension(:), intent(in) :: x1s     ! evaluation vector x1
      integer :: idx2                             ! id of x2 grid or coord.
      real*8, dimension(:), intent(in) :: x2s     ! evaluation vector x2
      real*8, dimension(:,:), intent(out) :: ans  ! result of evaluations
      integer, intent(out) :: ier                 ! completion code 0=OK

      !  size(x1s)=size(x2s)=size(ans,1) expected...

      !  ans(1:size(x1s),1) -- result of eval of profile ids(1)
      !  ans(1:size(x1s),2) -- result of eval of profile ids(2) ...etc...

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv1    ! derivative control
      !    1 for df/d[x1]; 2 for d2f/d[x1]2; 3 for d3f/d[x1]3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv1s
      !  as ideriv1, 1 per evaluation profile id

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv2    ! derivative control
      !    1 for df/d[x2]; 2 for d2f/d[x2]2; 3 for d3f/d[x2]3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv2s
      !  as ideriv2, 1 per evaluation profile id

      !  default: T -- CCW orientation, no CW->CCW transform
      logical, intent(in), optional :: ccwflag1  ! for x1
      logical, intent(in), optional :: ccwflag2  ! for x2
      !    (these are ignored except for theta and phi angle coordinates

      !  default: F -- T to force all points in bounds with min & max
      logical, intent(in), optional :: force_bounds

      !  optional output: return no. of target points out of range
      integer, intent(out), optional :: n_out_of_bounds

For 3d profile evaluation:

    subroutine xplasma_eval_3dprofsxs(s,ids,idx1,x1s,idx2,x2s,idx3,x3s, &
         ans,ier, &
         ideriv1,ideriv1s,ideriv2,ideriv2s,ideriv3,ideriv3s, &
         ccwflag1,ccwflag2,ccwflag3,force_bounds,n_out_of_bounds)

      !  evaluate multiple profiles f(x1,x2) 2d at a vector of points

      type (xplasma), pointer :: s
      integer, dimension(:), intent(in) :: ids    ! profile ids
      integer :: idx1                             ! id of x1 grid or coord.
      real*8, dimension(:), intent(in) :: x1s     ! evaluation vector x1
      integer :: idx2                             ! id of x2 grid or coord.
      real*8, dimension(:), intent(in) :: x2s     ! evaluation vector x2
      integer :: idx3                             ! id of x3 grid or coord.
      real*8, dimension(:), intent(in) :: x3s     ! evaluation vector x3
      real*8, dimension(:,:), intent(out) :: ans  ! result of evaluations
      integer, intent(out) :: ier                 ! completion code 0=OK

      !  size(x1s)=size(x2s)=size(x3s)=size(ans,1) expected...

      !  ans(1:size(x1s),1) -- result of eval of profile ids(1)
      !  ans(1:size(x1s),2) -- result of eval of profile ids(2) ...etc...

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv1    ! derivative control
      !    1 for df/d[x1]; 2 for d2f/d[x1]2; 3 for d3f/d[x1]3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv1s
      !  as ideriv1, but separately specified for each evaluation

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv2    ! derivative control
      !    1 for df/d[x2]; 2 for d2f/d[x2]2; 3 for d3f/d[x2]3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv2s
      !  as ideriv2, but separately specified for each evaluation

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv3    ! derivative control
      !    1 for df/d[x3]; 2 for d2f/d[x3]2; 3 for d3f/d[x3]3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv3s
      !  as ideriv3, but separately specified for each evaluation

      !  default: T -- CCW orientation, no CW->CCW transform
      logical, intent(in), optional :: ccwflag1  ! for x1
      logical, intent(in), optional :: ccwflag2  ! for x2
      logical, intent(in), optional :: ccwflag3  ! for x3
      !    (these are ignored except for theta and phi angle coordinates

      !  default: F -- T to force all points in bounds with min & max
      logical, intent(in), optional :: force_bounds

      !  optional output: return no. of target points out of range
      integer, intent(out), optional :: n_out_of_bounds

Home Top


interpolation_using_prior_lookup

Every interpolation involves two steps:  zone lookup, and evaluation.

Especially in the case of profiles defined over unevenly spaced grids,
the zone lookup is a significant portion of the computational cost of
the interpolation.

Sometimes it is possible, and worth the effort, to pre-evaluate zone
lookup and reuse this information through several interpolation calls.

Xplasma provides a way to do this.  In order for the user application
to take advantage of this capability, it needs to declare special data
structures, given public definitions in the xplasma modules, to store
the results of a zone lookup calculation in such a way that it can be
passed on to an xplasma interpolation routine built for this purpose.

Such a declaration will look something like this:

  type (xpeval) :: x1_intrp,x2_intrp,x3_intrp

Then, a generic interface xplasma_x_lookup can be used which will
accept evaluation of a lookup either for a single scalar value or
for a vector of values-- see the subtopic for information on the 
lookup pre-evaluation routines "xplasma_x_lookup".

Once the lookups have been evaluated, xplasma_eval_prof can be 
called, supplying this information, to perform actual interpolations.

Each xpeval item contains the lookup information either for a single
point on a single coordinate, or a vector of points on a single coordinate.
The evaluation routines expect to do a vector evaluation; at least one
of the xpeval items must contain a vector of n lookup results.  Those
with only scalar lookup data will be replicated n times on evaluation.

xplasma_eval_prof will make the following call for interpolation of
a 1d profile:

    subroutine xplasma_xpeval_1dprof(s,id,xinfo,ans,ier, ideriv)

      !  evaluate a single 1d profile function f(x) at a vector of
      !  target points for which lookup has already been executed
      !  and stored in "xinfo".

      !  the x axis grid id of the profile and of the xinfo must match
      !  the size of the output and the no. of points in the xinfo must
      !  match.  

      !  xinfo was set up by a prior xplasma_x_lookup call.

      type(xplasma), pointer :: s
      integer, intent(in) :: id      ! 1d function to evaluate
      type (xpeval) :: xinfo         ! prepared interpolation information

      real*8, dimension(:), intent(out) :: ans   ! interpolation result
      integer, intent(out) :: ier    ! status code, 0=OK

      integer, intent(in), optional :: ideriv  ! derivative selection
      
The following call is generated for interpolation of a 2d profile:

    subroutine xplasma_xpeval_2dprof(s,id,xinfo1,xinfo2,ans,ier, &
         ideriv1, ideriv2)

      type(xplasma), pointer :: s
      integer, intent(in) :: id      ! 2d function to evaluate
      type (xpeval) :: xinfo1,xinfo2 ! prepared interpolation information sets

      real*8, dimension(:), intent(out) :: ans   ! interpolation result
      integer, intent(out) :: ier    ! status code, 0=OK

      integer, intent(in), optional :: ideriv1  ! derivative selection, x1
      integer, intent(in), optional :: ideriv2  ! derivative selection, x2

And the following call is generated for interpolation of a 3d profile:

    subroutine xplasma_xpeval_3dprof(s,id,xinfo1,xinfo2,xinfo3,ans,ier, &
         ideriv1, ideriv2, ideriv3)

      type(xplasma), pointer :: s
      integer, intent(in) :: id      ! 3d function to evaluate
      type (xpeval) :: xinfo1,xinfo2,xinfo3 
                                     ! prepared interpolation information sets

      real*8, dimension(:), intent(out) :: ans   ! interpolation result
      integer, intent(out) :: ier    ! status code, 0=OK

      integer, intent(in), optional :: ideriv1  ! derivative selection, x1
      integer, intent(in), optional :: ideriv2  ! derivative selection, x2
      integer, intent(in), optional :: ideriv3  ! derivative selection, x3

In all of these calls, the optional arguments default to zero-- meaning,
interpolate the function value, not a derivative.

ideriv*=1 means to evaluate the 1st derivative along the indicated coordinate.
ideriv*=2 means to evaluate the 2nd derivative along the indicated coordinate.

With these methods one interpolates one profile at a time.

Home Top


lookup_routines

These routines must be called to load the xpeval structures BEFORE calling
one of the xplasma_xpeval routines (via xplasma_eval_prof):

When done it is important to FREE MEMORY associated with the xpeval
structure, called "xinfo" in the interfaces below.  Failure to free memory
after use will result in memory leaks (pointers are involved).

  !------------------------------------------------------
    subroutine xpeval_free(xinfo)

      type(xpeval) :: xinfo

      !  deallocate & clean up xinfo

  !------------------------------------------------------
  interface xplasma_x_lookup
     module procedure xplasma_x_lookup1
     module procedure xplasma_x_lookupn
  end interface

    subroutine xplasma_x_lookup1(s,idx,x,xinfo,ier, &
         ccwflag,force_bounds,n_out_of_bounds)

      !  do x lookup -- scalar x value

      type (xplasma), pointer :: s
      
      integer, intent(in) :: idx                  ! x grid (grid) id
      real*8, intent(in) :: x                     ! single scalar x value
      type (xpeval) :: xinfo                      ! *** lookup results
      integer, intent(out) :: ier                 ! status code, 0=OK

      !  default: T -- CCW orientation, no CW->CCW transform
      logical, intent(in), optional :: ccwflag

      !  default: F -- T to force all points in bounds with min & max
      logical, intent(in), optional :: force_bounds

      !  optional output: return no. of target points out of range
      integer, intent(out), optional :: n_out_of_bounds
      
      ...............

    subroutine xplasma_x_lookupn(s,idx,x,xinfo,ier, &
         ccwflag,force_bounds,n_out_of_bounds)

      !  do x lookup -- scalar x value

      type (xplasma), pointer :: s
      
      integer, intent(in) :: idx                  ! x grid (grid) id
      real*8, intent(in), dimension(:) :: x       ! vector of x values
      type (xpeval) :: xinfo                      ! *** lookup results
      integer, intent(out) :: ier                 ! status code, 0=OK

      !  default: T -- CCW orientation, no CW->CCW transform
      logical, intent(in), optional :: ccwflag

      !  default: F -- T to force all points in bounds with min & max
      logical, intent(in), optional :: force_bounds

      !  optional output: return no. of target points out of range
      integer, intent(out), optional :: n_out_of_bounds
      
      ...............

Some further notes on arguments:

idx -- this must be a grid ID, not a coordinate ID.
x -- if scalar, the generic interface maps to xplasma_x_lookup1;
     if vector, the generic interface maps to xplasma_x_lookupn.

xinfo -- dummy argument name for xpeval object, where the results
     of the interpolation lookup are stored.

optional arguments:

ccwflag -- if idx points to a grid over an angle coordinate, e.g.
     the poloidal angle flux coordinate, setting this flag to .FALSE.
     will cause the input data to be transformed by the formula

           theta -> 2pi - theta

     which would be appropriate if the caller's code wants to treat
     the poloidal angle coordinate as drawn clockwise around the 
     flux surface (inside xplasma, the internal representation is
     always drawn counterclockwise).

force_bounds -- force all input arguments to be in range using min
     and max function calls.  This has no effect on periodic coordinate
     arguments, which always brought in range with 2*n*pi shifts as 
     needed.

n_out_of_bounds (out) -- number of x values not in bounds.

Normally it is an error for out of bounds x values to be provided.

Home Top


data_retrieval

The original profile data can be retrieved using xplasma_eval_prof 
with the arguments shown for the following non-generic interfaces.

In all cases, the arrays receiving the data must EXACTLY match the 
dimensioning of the profile being retrieved.  The dimensioning can
be reconstructed (i.e. use xplasma_prof_info to retrieve rank and 
grid IDs; use xplasma_grid_size to get sizes of individual grids,
which are also the correct profile array dimensions).

Error codes will be set if there is a mismatch in array dimension
sizes or array rank; if the return code "ier" is set to a non-zero
value, use:

  call xplasma_error(s,ier,6)

to cause the error report to be printed on fortran unit 6 (stdout).

Optional arguments "ccwflag*" are used to specify orientation of 
periodic coordinates.  These have the same meaning as the corresponding
arguments used when the profile is created.  Setting ccwflag<n> to .FALSE.
will reverse the indexing order of the data along the <n>th dimension, if
that dimension corresponds to a periodic coordinate.  If the <n>th
coordinate is not periodic, ccwflag<n> is ignored.

---------------

Retrieve 1d profile (this method in the xplasma_eval_prof generic
interface):

    subroutine xplasma_getprof_1data(s,id,zdata,ier, &
         ccwflag1)
      
      !  return the original data associated with this profile

      type (xplasma), pointer :: s
      integer, intent(in) :: id                   ! profile id
      real*8, dimension(:), intent(out) :: zdata  ! data returned
      integer, intent(out) :: ier                 ! completion code 0=OK

      logical, intent(in), optional :: ccwflag1   ! CCW flag (default T)

Retrieve 2d profile (this method in the xplasma_eval_prof generic
interface):

    subroutine xplasma_getprof_2data(s,id,zdata,ier, &
         ccwflag1,ccwflag2)
      
      !  return the original data associated with this profile

      type (xplasma), pointer :: s
      integer, intent(in) :: id                     ! profile id
      real*8, dimension(:,:), intent(out) :: zdata  ! data returned
      integer, intent(out) :: ier                   ! completion code 0=OK

      logical, intent(in), optional :: ccwflag1   ! dim. 1 CCW flag (default T)
      logical, intent(in), optional :: ccwflag2   ! dim. 2 CCW flag (default T)
 
Retrieve 3d profile (this method in the xplasma_eval_prof generic
interface):

    subroutine xplasma_getprof_3data(s,id,zdata,ier, &
         ccwflag1,ccwflag2,ccwflag3)
      
      !  return the original data associated with this profile

      type (xplasma), pointer :: s
      integer, intent(in) :: id                       ! profile id
      real*8, dimension(:,:,:), intent(out) :: zdata  ! data returned
      integer, intent(out) :: ier                     ! completion code 0=OK

      logical, intent(in), optional :: ccwflag1   ! dim. 1 CCW flag (default T)
      logical, intent(in), optional :: ccwflag2   ! dim. 2 CCW flag (default T)
      logical, intent(in), optional :: ccwflag3   ! dim. 3 CCW flag (default T)

Home Top


xplasma_RZeval_2d

This is a specialized routine for evaluating R(rho,theta) and/or
Z(rho,theta), with automatic failover to extrapolated profiles of R and Z
for rho > 1, when these are available.

In general, if xplasma has scrap off layer information, i.e. limiter 
locations, it will, when updating the MHD equilibrium, create
extrapolated (rho,theta) -> (R,Z) map which however is not differentiable
across the rho=1 boundary.

This routine gives access to both the original and extrapolated R and Z
in the context of a single call.

    subroutine xplasma_RZeval_2d(s,ids,idx1,x1s,idx2,x2s,ans,ier, &
         ideriv1,ideriv1s,ideriv2,ideriv2s, &
         ccwflag1,ccwflag2,force_bounds,n_out_of_bounds)

      !  use xplasma_eval_2dprofsxs to
      !  evaluate multiple profiles f(x1,x2) 2d at a vector of points
      !    IF all the profiles are "R" and "Z",
      !    and IF there is a scrape-off region,
      !    split the evaluation so that points inside the plasma use
      !    the standard R & Z, and points outside use the extrapolated
      !    profiles.

      type (xplasma), pointer :: s
      integer, dimension(:), intent(in) :: ids    ! profile ids
      integer :: idx1                             ! id of x1 grid or coord.
      real*8, dimension(:), intent(in) :: x1s     ! evaluation vector x1
      integer :: idx2                             ! id of x2 grid or coord.
      real*8, dimension(:), intent(in) :: x2s     ! evaluation vector x2
      real*8, dimension(:,:), intent(out) :: ans  ! result of evaluations
      integer, intent(out) :: ier                 ! completion code 0=OK

      !  size(x1s)=size(x2s)=size(ans,1) expected...

      !  ans(1:size(x1s),1) -- result of eval of profile ids(1)
      !  ans(1:size(x1s),2) -- result of eval of profile ids(2) ...etc...

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv1    ! derivative control
      !    1 for df/d[x1]; 2 for d2f/d[x1]2; 3 for d3f/d[x1]3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv1s
      !  as ideriv1, 1 per evaluation profile id

      !  default: 0= fcn value
      integer, intent(in), optional :: ideriv2    ! derivative control
      !    1 for df/d[x2]; 2 for d2f/d[x2]2; 3 for d3f/d[x2]3
      !    2 & 3 available only for C2 spline fits
      integer, intent(in), dimension(:), optional :: ideriv2s
      !  as ideriv2, 1 per evaluation profile id

      !  default: T -- CCW orientation, no CW->CCW transform
      logical, intent(in), optional :: ccwflag1  ! for x1
      logical, intent(in), optional :: ccwflag2  ! for x2
      !    (these are ignored except for theta and phi angle coordinates

      !  default: F -- T to force all points in bounds with min & max
      logical, intent(in), optional :: force_bounds

      !  optional output: return no. of target points out of range
      integer, intent(out), optional :: n_out_of_bounds

Home Top


Generic_blackBoxes

The BLACK BOX is one of the data types supported within xplasma.

A black box is a storage mechanism for data not fitting into other types.
It consists of the following:

  a) a user defined integer "type" code;
  b) a user specified 1d array or buffer of any size, of integers;
  c) a user specified 1d array or buffer of any size, of 64 bit 
     (real*8) floating point numbers.

The black box is used within xplasma for a number of purposes-- caches for
flux surface integration, data to support rapid methods for evaluation of
coordinate transformations, "MCgrid" data, ...

Integer black box type codes in the range 0 to 101 are used by xplasma 
library software; it is recommended that user defined black boxes stay
away from using type codes in this range.

In order to avoid unnecesary and costly copying of large arrays, the
black box data access allows pointers to the black box integer and
floating point array data to be returned.  This means however that
the contents of black box datasets can be modified directly by 
assignment of (pointer) array elements, without going through an
interface call.  User caution is advised.

Home Top


xplasma_blackBox_info

The black box type code, buffer sizes, and generic xplasma item labeling
can be retrieved with this call.  Except for the status code, output
arguments are optional, allowing the caller to control what information
is to be returned.

    subroutine xplasma_blackBox_info(s,id,ier, &
         type,isize,r8size,name,label,units,author)
      !
      !  get the size of an existing list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of black box item
      integer, intent(out) :: ier         ! completion code

      integer, intent(out), optional :: type  ! "type" of black box
      ! generally, meaning of iitype is user defined...

      integer, intent(out), optional :: isize  ! number of integer words
      integer, intent(out), optional :: r8size ! number of floating pt words

      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: label
      character*(*), intent(out), optional :: units
      character*(*), intent(out), optional :: author

Home Top


xplasma_blackBox_retrieve

Black box data, or pointers to data, can be retrieved with this call.  As
usual, most output arguments are optional:

    subroutine xplasma_blackBox_retrieve(s,id,ier, &
         itype,iarray,r8array,ia_ptr,r8a_ptr,name,label,units,author)

      !  retrieve blackBox data
      !    optional arguments; user controls what data is wanted.

      type (xplasma), pointer :: s
      integer, intent(in) :: id          ! id of black box item
      integer, intent(out) :: ier        ! completion code, 0=OK

      integer, intent(out), optional :: itype  ! "type" of black box
      !  meaning is user defined.

      !  if copies of arrays are wanted:
      integer, dimension(:), intent(out), optional :: iarray
      real*8, dimension(:), intent(out), optional :: r8array

      !  if pointers to arrays are wanted:
      integer, dimension(:), pointer, optional :: ia_ptr
      real*8, dimension(:), pointer, optional :: r8a_ptr

      !  optional labeling info...
      character*(*), intent(out), optional :: name     ! item name
      character*(*), intent(out), optional :: label    ! item label
      character*(*), intent(out), optional :: units    ! item units label
      character*(*), intent(out), optional :: author   ! author

Home Top


Limiter_information

Xplasma supports the notion of an axisymmetric "limiter" or vessel wall.

The region between the limiter and the core plasma contains plasma and
neutral gas on open field lines and is referred to here as the scrape off
layer.

For reasons related to legacy code, xplasma supports two methods for
defining an axisymmetric limiter.  Therefore, the routine for retrieving
limiter information supports both representations.  However, the routines
"xplasma_bdycon" and "xplasma_limcon" support methods for returning the
plasma boundary and limiter represented as a closed contour (to good 
approximation), regardless of the internal representation.

The interface xplasma_lim_distance allows quick access to the distance
from any point in space to the nearest limiter point.

Specific call interfaces are in the subtopics.

Home Top


xplasma_lim_info

    subroutine xplasma_lim_info(s,ier, &
         itype, npts,rpts,zpts, &
         dist, &
         nlines, Rl, Zl, thl, &
         ncircs, Rc, Zc, rad)

      ! retrieve limiter information

      type(xplasma), pointer :: s
      integer, intent(out) :: ier

      integer, intent(out), optional :: itype
      !  itype=100 means piecewise linear closed contour (axisymmetric limiter)
      !  itype=101 means list of circles & infinite lines

      integer, intent(out), optional :: npts ! #pts in contour (itype=100 only)

      real*8, dimension(:), intent(out), optional :: rpts,zpts
      !  the closed contour; rpts(npts)=rpts(1) and zpts(npts)=zpts(1) (m).

      real*8, intent(out), optional :: dist  ! itype=101 limiters only...
      !  if .ge.0.0d0, the plasma boundary + dist is considered a limiter
      !  if .lt.0.0d0-- no plasma boundary based limiter.

      integer, intent(out), optional :: nlines  ! #lines in itype=101 limiter
      real*8, dimension(:), intent(out), optional :: Rl,Zl,thl
      !  point (m) through which line passes, and line orientation in DEGREES
      !  e.g. 45.0 means up and to the right...

      integer, intent(out), optional :: ncircs ! #circles in itype=101 limiter
      real*8, dimension(:), intent(out), optional :: Rc,Zc,rad
      !  center location and radius of each circle (m)

Home Top


xplasma_lim_RZminmax

    subroutine xplasma_lim_rzminmax(s,zRmin,zRmax,zZmin,zZmax,ier, &
         itype)

      !  get the Rmin,Rmax,Zmin,Zmax of the vacuum region
      !  enclosed by the mechanical limiter
      !    optional: get a limiter type code also.

      type (xplasma), pointer :: s

      real*8, intent(out) :: zRmin,zRmax,zZmin,zZmax  ! R & Z min & max (m)

      integer, intent(out) :: ier

      integer, intent(out), optional :: itype  ! limiter representation
      ! within xplasma: 100 for piecewise contour; 101 for "circles and
      ! lines" possibly augmented by a fixed distance from the plasma
      ! boundary.

Home Top


xplasma_limcon

    subroutine xplasma_limcon(s,rlim,zlim,inum_got,ier, &
         tol,maptype)

      !  return a closed contour of length size(rlim)=size(zlim) or less
      !  describing the limiter.

      !  if tol.le.0.0d0 -- the length of the description is size(rlim) exactly
      !  if tol.gt.0.0d0 -- length may be shortened to remove colinear points.
      !      also, if the limiter was originally given in contour form, and,
      !      size(rlim) is sufficient, the original specification will be
      !      returned.

      type (xplasma), pointer :: s

      real*8, dimension(:), intent(out) :: rlim,zlim  ! limiter contour
      !  the sizes of these vectors must be the same.
      !  unless the original specification is being returned, the code
      !  requires a minimum size of 30 points.

      integer, intent(out) :: inum_got     ! contour length returned
      !  if inum_got.lt.size(rlim), rlim(inum_got+1:size(rlim))=0 on exit.
      !  similarly for zlim.

      integer, intent(out) :: ier  ! status code, 0=OK

      real*8, intent(in), optional :: tol  ! tolerance specification
      !  if zero or negative, no shortening of the limiter description is
      !  attempted.  If .gt. 0.0, adjacent segments that are colinear to within
      !  tol*[Rmax] are replaced by a single segment.  DEFAULT: s%bdytol

      integer, intent(in), optional :: maptype  ! mapping option
      !  1=slowest but most exact; 2=intermediate; 3=bilinear interpolation
      !  2 or 3 recommended.  DEFAULT: 2

Home Top


xplasma_bdycon

Return a closed contour describing the plasma boundary; length of contour
taken from size of vector arguments provided:

    subroutine xplasma_bdycon(s,rbdy,zbdy,ier)

      !  return a closed contour around the plasma boundary, similar to
      !  xplasma_limcon...

      type (xplasma), pointer :: s

      real*8, dimension(:), intent(out) :: rbdy,zbdy  ! bdy contour
      !  the sizes of these vectors must be the same.

      integer, intent(out) :: ier

Home Top


xplasma_lim_distance

  interface xplasma_lim_distance
     module procedure xplasma_lim_dist1
     module procedure xplasma_lim_distn
  end interface

    subroutine xplasma_lim_dist1(s,r,z,d,ier, maptype, rlim1,zlim1)

      !  scalar version of xplasma_lim_distn -- axisymmetry assumed.

      type (xplasma), pointer :: s
      real*8, intent(in) :: R,Z      ! input location (m)
      real*8, intent(out) :: d       ! output distance from nearest point
      !                                on limiter or wall (m).

      integer, intent(out) :: ier

      integer, intent(in), optional :: maptype  ! see xplasma_lim_distn
      real*8, intent(out), optional :: rlim1,zlim1  ! nearest limiter point

    end subroutine xplasma_lim_dist1

    subroutine xplasma_lim_distn(s,rvec,zvec,dist,ier, &
         maptype,rlim,zlim)

      !  find distance from each element of a vector of (R,Z) pairs
      !  to the nearest point on a limiter.

      !  optionally return the location of that point on the limiter
      !  in (R,Z).

      !  the routine assumes axisymmetry.  Optional phi arguments may
      !  be added someday.

      type (xplasma), pointer :: s
      real*8, intent(in), dimension(:) :: rvec,zvec  ! (R,Z) input vector

      real*8, intent(out), dimension(:) :: dist      ! distance values returned
      integer, intent(out) :: ier

      integer, intent(in), optional :: maptype       ! distance map option
      ! if it is required to compute the distance from the (R,Z) point to 
      ! the plasma boundary, this specifies the option (for xplasma_bdfind).
      !   Default is the circle-fit option (2).  (1) is slower but more
      ! precise; (3) is less accurate but would be faster if a bilinear
      ! distance map has already been computed.

      real*8, intent(out), dimension(:), optional :: rlim,zlim  ! locations
      !                      of nearest contact points on limiter, for each
      !                      input location.

Home Top


MCgrid_Data

The MCgrid, or "Monte Carlo grid", is an irregular 2d spatial grid that
was developed originally for capture of 2d binned data in a Monte Carlo
calculation (NUBEAM).  It is used for fast ion distribution functions and
for certain spatially 2d profiles output by NUBEAM-- such as, beam halo
thermal neutral sources, beam-target and beam-beam fusion rates.

The grid is aligned with flux coordinates.  It is constructed of "zone
rows" that are equally spaced in rho=sqrt(Psi_tor/Psi_tor_at_bdy); each
zone row is subdivided into a different number of zones equispaced in
the equilibrium poloidal angle coordinate theta, with fewer subdivisions
for zone rows near the axis, and more for zone rows in the edge.  The
result is a set of zones all with roughly equal volume and cross sectional
area, as is desirable for consistency of Monte Carlo summation statistics.

The number of poloidal zones per zone row is linear in the zone row index:
typically, 4 in the 1st zone row adjacent to the magnetic axis, 4+4=8 in the 
next row out, 8+4=12 in the next row, etc.

There are two variants, according as the underlying MHD equilibrium is
updown symmetric, or updown asymmetric.  

As internally stored, the first row layout is this for the updown symmetric
variant:
   _____
  /  |  \
 / 2 | 1 \
 |___|___|

with theta=0 on the large major radius side; increasing to theta=pi on
the large major radius side covering the upper half of the plasma cross
section above the midplane.  The next row out would have 4 zones, the
next 8 zones, etc.

And this for the updown asymmetric variant:

   _____
  /  |  \
 / 4 | 3 \
 |___|___|
 |   |   |
 \ 1 | 2 /
  \__|__/

with theta=-pi on the lower branch on the small major radius side, theta=0
on the large major radius side, and theta=pi on the upper branch on the small
major radius side.  The next zone row contains 4+4=8 zones, the next 8+4=12 zones,
and so on.

Poloidal zones are stored contiguously, with the poloidal zone index
increasing with increasing theta coordinate, theta being oriented
counter-clockwise in the plasma cross section drawn to the right of
the machine axis of symmetry.

This is how the data is stored internally.

Note, however, that on retrieval of MCgrid data, there are options to
reverse the storage order to be consistent with a clockwise oriented 
poloidal angle coordinate (as preferred by some codes), and, for both 
updown symmetric and updown asymmetric data, the start point for theta 
zone indexing can be specified as either 0, -pi, or the default (which
is 0 for updown symmetric data and -pi for updown asymmetric data).
These choices are controlled by optional arguments in the MCgrid data
access routines.

The MCgrid itself is a named "black box" item in the xplasma dataset;
in principle there could be multiple MCgrids defined, but in practice
there is usually only one.

Each profiles defined over an MCgrid is itself a named "black box" item.

When a MCgrid is set up, the volume of each MCgrid zone is computed,
and this is itself stored as a profile over the MCgrid; the name is
the MCgrid name with the suffix "_DVOL" appended.

These integer parameters define the black box type codes used for MCgrids
and their associated profiles:

  integer, parameter, public :: xplasma_bbgtype=17  ! MC grid type
  integer, parameter, public :: xplasma_bbftype=18  ! MC profile type

Although information on these grids and profile could be obtained by
using generic black box data access calls, it is better to use the
calls specifically provided to support MCgrid items, which are described
in the subtopics.  Calls for access to MCgrid data are shown here; calls
to create MCgrid data are given under the section heading 
Modifying_F95_Xplasma_Data.

Home Top


Finding_MCgrid_ID

Usually there is only one MCgrid per dataset, so, the optional argument
id_mcgrid1 can be used in the public interface shown below.  If the MCgrid
is known to have been created by a named author, the search can be
constrained by that name: e.g "author_only='NUBEAM'".

    subroutine xplasma_mcgrid_find(s,ierr, author_only, &
         id_mcgrid1,num_mcgrids,id_mcgrids)

      !  find MCgrid grid definitions that are available in the current
      !  xplasma-- usually there will be only one we think.

      type(xplasma), pointer :: s
      integer, intent(out) :: ierr          ! status code returned (0=OK)

      character*(*), intent(in), optional :: author_only
      !  restrict search to MCgrid objects written by this author or code

      integer, intent(out), optional :: id_mcgrid1  ! MCgrid id returned, if...
      !  if exactly one exists.  If none exist, id_mcgrid1=0 is returned; if
      !  >1 exists,id_mcgrid1=-<the number of MCgrids> is returned.

      integer, intent(out), optional :: num_mcgrids ! number of MCgrids found.

      integer, dimension(:), optional :: id_mcgrids ! MCgrid ids returned.

Home Top


MCgrid_info

The following interface enables access to details on the MCgrid.  It should
be noted that for historical reasons the MCgrid supports an extension beyond
the plasma boundary, but, known applications of the MCgrid are restricted
to the plasma core at present.

Other than the error code, the return arguments are optional, so, the 
caller can select just the information that is needed.

    subroutine xplasma_mcgrid_info(s,id_mcgrid,ierr, &
         nzrow,nzrow_ext, nzons,nzons_ext, nth0,nphi, nths, udsym, &
         name,label)

      ! fetch information on xplasma_mcgrid grid

      type(xplasma), pointer :: s
      integer, intent(in) :: id_mcgrid  ! id of MCgrid object to be queried
      integer, intent(out):: ierr       ! status code 0=OK

      integer, intent(out), optional :: nzrow  ! # of zone rows in plasma
      integer, intent(out), optional :: nzrow_ext  ! # inside and outside

      integer, intent(out), optional :: nzons  ! # of zones in plasma
      integer, intent(out), optional :: nzons_ext  ! # inside and outside

      integer, intent(out), optional :: nth0   ! # of zones @axis cover [0:pi]
      integer, intent(out), optional :: nphi   ! # of phi zones (1:axisymmetry)

      integer, dimension(:), intent(out), optional :: nths
      ! number of theta zones in each zone row

      logical, intent(out), optional :: udsym

      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: label
      character*(*), intent(out), optional :: author

-----------
It is important to notice that nth0 gives only the number of zones in the
upper (or lower) halfplane of the first zone row, regardless of whether 
the underlying MCgrid is updown symmetric or updown asymmetric.  Thus,
an updown symmetric grid with 2 zones in the first row, and an updown
asymmtric grid with 4 zones in the first row, would both return a value
of 2 for nth0.

Home Top


MCgrid_zone_indexing_example

[A working example is in xplasma_debug_module.f90]

  integer :: id_mcgrid
  real*8 :: rho = 0.375d0   ! rho where index is wanted
  real*8 :: th = 0.2d0      ! theta angle where index is wanted
  real*8, parameter :: rhomax = 1.0d0 ! only looking at core plasma region...

  integer :: nrow,irow      ! zone rows
  integer, dimension(:), allocatable :: nths,nthsum
  logical :: udsym          ! updown symmetry flag

  integer :: indx

  call xplasma_find_mcgrid(s,ierr, id_mcgrid1=id_mcgrid)

  if(ierr.ne.0) [handle xplasma error]
  if(id_mcgrid.eq.0) [no MCgrid exists]
  if(id_mcgrid.lt.0) [multiple MCgrids exist]

  call xplasma_mcgrid_info(s,id_mcgrid,ierr, nzrow=nrow, udsym=udsym)

  allocate(nths(nrow),nthsum(0:nrow))

  call xplasma_mcgrid_info(s,id_mcgrid,ierr, nths=nths)

  nthsum(0)=0
  do irow=1,nrow
     nthsum(irow)=nthsum(irow-1)+nths(irow)
  enddo

  !  find row index using subroutine.  The indexing is counting from -pi,
  !  regardless of the symmetry flag-- there is an implicit assumption that
  !  MCgrid profile data is fetched with this option!!!

  call mcindx(rho,th,udsym,nrows,rhomax,nths,nthsum,indx)

  !-------------------------

      subroutine mcindx(rho,th,udsym,nrow,rhomax,nths,nthsum,indx)

        ! private

        ! this routine assumes that the theta indexing is oriented
        ! counterclockwise and that it starts at -pi for each row,
        ! *even* for updown symmetric data.

        real*8, intent(in) :: rho,th  ! flux coords in
        logical, intent(in) :: udsym  ! updown symmetry flag
        integer, intent(in) :: nrow   ! #rows
        real*8, intent(in) :: rhomax  ! max rho in range
        integer, intent(in) :: nths(nrow) ! # theta zones / row
        integer, intent(in) :: nthsum(0:nrow) ! # in prior rows

        integer, intent(out) :: indx

        !----------------------------------------
        integer :: irho,ith
        real*8 :: zth,zthlim

        real*8, parameter :: CPI = 3.1415926535897931D+00
        real*8, parameter :: ZERO = 0.0d0
        !----------------------------------------

        indx = 0

        if(udsym) then
           zth = -abs(th)
           zthlim = ZERO
        else
           zth = th
           zthlim = CPI
        endif

        irho = 1 + rho*nrow/rhomax
        if((irho.ge.1).and.(irho.le.nrow)) then

           ith = 1 + (zth+CPI)*nths(irho)/(zthlim+CPI)
           if((ith.ge.1).and.(ith.le.nths(irho))) then
              indx = nthsum(irho-1) + ith
           endif
        endif

      end subroutine mcindx

Home Top


MCgrid_zone_volumes

The following interface allows retrieval of the volumes of all the 
MCgrid individual zones:

    subroutine xplasma_mcgrid_volumes(s,id_mcgrid,vols,ierr, &
         lstart0_th,ccwflag_th)

      !  return the zone volumes associated with a MCgrid.  Compute them
      !  if necessary.

      type(xplasma), pointer :: s
      integer, intent(in) :: id_mcgrid   ! MC grid id
      real*8, dimension(:) :: vols       ! the array of volume elements
      integer, intent(out) :: ierr       ! status code (0=OK)

      ! theta indexing options
      logical, intent(in), optional :: lstart0_th ! default depends on symmetry
      logical, intent(in), optional :: ccwflag_th ! default: T

      ! lstart0_th=T means user's first theta zone lower bdy is 0; F means it
      ! is -pi.  If defaulted: updown symmetric data assumed to start at 0;
      ! updown asymmetric data assumed to start at -pi.

      ! ccwflag_th=T means zone index increases as one goes along a row of
      ! zones at fixed radial index in a counter-clockwise direction; F means
      ! the opposite.  T is the default.

Home Top


List_of_MCgrid_profiles

The following routine allows retrieval of a list of IDs of available profiles
defined over a MCgrid.  In typical usage, a first call might get the number
of such profiles, followed by allocation of an integer array to hold the
list of profile IDs, followed by a second call to actually fetch the IDs.

    subroutine xplasma_mcgrid_findProfs(s,id_mcgrid,ierr, &
         author_only, num_profs, id_profs)

      ! find profiles defined over given MCgrid

      type(xplasma), pointer :: s
      integer, intent(in) :: id_mcgrid      ! MC grid id
      integer, intent(out) :: ierr          ! status code returned (0=OK)

      character*(*), intent(in), optional :: author_only
      !  restrict search to MCgrid profiles written by this author or code

      integer, intent(out), optional :: num_profs ! number of profiles found.

      integer, dimension(:), optional :: id_profs ! profile ids returned.

Home Top


Information_on_MCgrid_profile

This routine returns information on an individual MCgrid profile.  Except
for the status code, all output arguments are optional, allowing the caller
to select the desired information:

    subroutine xplasma_mcgrid_profInfo(s,id_mcprof,ierr, &
         id_mcgrid,nzons,irank,idim1,idim2, &
         gridId1,gridId2,normcode, &
         name,label,units,author)

      ! fetch information on a single profile defined over an MCgrid...

      type (xplasma), pointer :: s
      integer, intent(in) :: id_mcprof   ! profile ID
      integer, intent(out) :: ierr       ! status code returned: 0=OK

      integer, intent(out), optional :: id_mcgrid   ! MCgrid ID
      integer, intent(out), optional :: nzons       ! #spatial zones
      integer, intent(out), optional :: irank       ! #non-spatial dimensions
      integer, intent(out), optional :: idim1,idim2 ! non-spatial dim. sizes

      !  grid IDs for non-spatial dimensions (if available)

      integer, intent(out), optional :: gridId1
      integer, intent(out), optional :: gridId2

      ! normalization code

      integer, intent(out), optional :: normcode

      !-------------

      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: label
      character*(*), intent(out), optional :: units
      character*(*), intent(out), optional :: author

For multidimensional profiles with velocity space coordinates (i.e.
distribution functions), the arguments gridId1 and gridId2 can be used
to retrieve the IDs of the velocity space coordinates used.

Home Top


Fetch_MCgrid_profile_data

This routine retrieves the actual profile data into a user provided
array.  An array with correct dimensioning must be supplied by the user.

The last dimension of the user supplied array is the spatial dimension,
matching the MCgrid size-- the value of the "nzons" argument returned by
xplasma_mcgrid_info(...), for profiles defined just over the core plasma
region.

    subroutine xplasma_mcgrid_getobj(s,id_p,ierr, &
         lstart0_th,ccwflag_th, &
         data_1d,data_2d,data_3d,label,units)

      !  retrieve previously stored MCgrid profile
      !  (see xplasma_mcgrid_putobj)

      type (xplasma), pointer :: s
      integer, intent(in) :: id_p  ! MCgrid profile ID
      integer, intent(out) :: ierr ! exit status code (0=OK)

      ! theta indexing options
      logical, intent(in), optional :: lstart0_th ! default depends on symmetry
      logical, intent(in), optional :: ccwflag_th ! default: T

      ! lstart0_th=T means user's first theta zone lower bdy is 0; F means it
      ! is -pi.  If defaulted: updown symmetric data assumed to start at 0;
      ! updown asymmetric data assumed to start at -pi.

      ! ccwflag_th=T means zone index increases as one goes along a row of
      ! zones at fixed radial index in a counter-clockwise direction; F means
      ! the opposite.

      !-----------------
      !  one of the optional arguments data_1d, data_2d, data_3d must
      !  be provided to receive the data.

      !  the provided data array sizes must match the stored data.

      real*8, dimension(:), intent(out), optional :: data_1d
      real*8, dimension(:,:), intent(out), optional :: data_2d
      real*8, dimension(:,:,:), intent(out), optional :: data_3d

      !-----------------
      character*(*), intent(out), optional :: name
      character*(*), intent(out), optional :: labels
      character*(*), intent(out), optional :: units
      character*(*), intent(out), optional :: author

Home Top


Initializing_F95_Xplasma_Data

The previous sections discussed methods for accessing data in an xplasma
object that was already created.  This and the following sections describe
how to build up an xplasma object from scratch, and how to evolve it in a
time dependent simulation.

The following pieces of an xplasma dataset normally do not evolve in time;
rather, they are initialized once at the start of the lifetime of an xplasma
object:

  (a) the flux coordinate grids "rho" and "theta" over which equilibrium 
      profiles are defined:
         flux surface label "rho" = sqrt(toroidal_flux/toroidal_flux_at_bdy)
         poloidal angle "theta" -- in the internal xplasma representation,
         moving in the direction of +theta at fixed rho traces out a
         flux surface in the counter-clockwise direction, when the flux
         surface cross section is drawn to the right of the tokamak axis
         of symmetry (R=0).

  (b) the location of an axisymmetric limiter or vacuum vessel wall, usually
      specified as a closed contour sequence of [R,Z] pairs.

  (c) the R and Z grids covering a rectangle in space that encloses the
      limiters and will enclose the core plasma at all times.

  (d) additional coordinates and grids as may be defined by the user, e.g.
      in velocity space; multiple grids may discretize the same coordinates.

The items that do evolve over the lifetime of an xplasma object are:

  (e) the equilibrium over flux coordinates
      R(theta,rho), Z(theta,rho) -- the geometry of flux surfaces (m).
      g(rho) = R*|B_phi|, a flux surface constant, m*T;
                 B_phi = bphi_ccw*(g/R);
                      bphi_ccw=+1 if toroidal field points counter-clockwise
                               -1 if clockwise, viewed from above
      Psi(rho) = poloidal flux function, Wb/rad, zero on axis,
                 dPsi/drho > 0, with relation to the poloidal field
                 Bpol = -jphi_ccw*(1/R)*grad(Psi);
                      jphi_ccw=+1 if toroidal current flows counter-clockwise
                               -1 if clockwise, viewed from above
      P(rho) = a profile representing the pressure used in the Grad-
                 Shafranov equation to produce the equilibrium

      The derived profile BR(theta,rho), BZ(theta,rho), BPHI(theta,rho),
      BMOD(theta,rho) give spline approximations to the field components.

  (f) the equilibrium over (R,Z) coordinates

      Psi(R,Z), Wb/rad, Bpol = -jphi_ccw*(1/R)*grad(Psi)
      BR_RZ(R,Z), BZ_RZ(R,Z), BPHI_RZ(R,Z), BMOD_RZ(R,Z) are provided as
      spline approximations to the field components over (R,Z) coordinates.

  (g) any collection of named data items--
        * profiles-- zonal data, piecewise linear data, or splines over 
                   up to 3 independent coordinates
        * lists -- each containing its own collection of named, labeled
                   elements with associated scalar integer and floating
                   point values.
        * black boxes -- generic storage of "unstructured" integer and
                   floating point data.

The INITIALIZATION of an xplasma object consists of the definition of
the elements that do not (normally) vary in time.

The most direct method of initialization is to start from an EFIT
G-eqdsk file containing a free boundary equilibrium reconstruction:

  use xplasma_obj_instance

  character*32 :: author_name = 'My_code'
  character*60 :: filename = <path to G-eqdsk file>

  call xoi_init(ier)  ! init xplasma pointers in module

  call xplasma_author_set(s,author_name,ier)

  call xplasma_fromgeqdsk(s,filename,ier, &
         nrho = <number of numerical flux surfaces including axis>, &
         ntheta = <number of poloidal grid points covering 0:2pi>)

  ! also a good idea:
  real*8 :: curtime

  curtime = <current time of simulation>
  call xplasma_time_set(s,curtime,ier)

  call xplasma_author_clear(s,author_name,ier)

The optional arguments specify the desired equilibrium flux coordinate
grid resolutions; if defaulted, the code uses nrho=51, ntheta=101.

Loading xplasma from a G-eqdsk file for the first time, items (a)-(c),
are defined, and initial values for items (e)-(f) are also provided.

The equilibrium can subsequently be modified with later
calls to xplasma_fromgeqdsk, reading modified G-eqdsk files, but then
the limiter and [R,Z] grids found must be the same as were given in
the first G-eqdsk file read; this is checked and an error will be 
reported if there is a mismatch.

Further initializations may involve the definition of additional 
coordinates and grids, e.g. in velocity space, which are application
dependent.

The xplasma public interfaces include the following routines likely to
be used in initialization:

  xplasma_create_coordinate    xplasma_create_grid

which will be described below.

Home Top


Alternate_initialization_method

The alternative to using a G-eqdsk file is to use a series of calls to
spell out each of the components of the equilibrium.  In this context,
initialization consists in the definition of the flux coordinate grids,
the limiters, and the [R,Z] grids.  Code to do this is sketched below.
Details on the interfaces used will be given below.

  !--------------------------
  ! on the FIRST call, the rho and theta grids need to be defined...

  character*32 :: author_name = 'My_code'

  call xplasma_author_set(s,author_name,ier)

  allocate(rho(inrho),th(inth))

  <fill in rho values; rho(1)=0.0; rho(inrho)=1.0>

  <fill in th values over range -pi:pi or 0:2pi>

  call xplasma_create_grid(s,'my_rho',xplasma_rho_coordinate,rho,id_rho,ier, &
       label='my rho grid for the equilibrium')

  call xplasma_create_grid(s,'my_theta',xplasma_theta_coordinate,th,id_th, &
       ier, label='my theta grid for the equilibrium')

  ! the field SIGNS also have to be set, once, at the beginning of the
  ! lifetime of the xplasma object:

  ! bphi_ccw=1 means the toroidal field points counter clockwise;
  ! jphi_ccw=-1 means the toroidal current flows clockwise
  !   these orientations as viewed from above the tokamak
  !     values of +/-1 are allowed for each of these arguments

  call xplasma_field_ccw_set(s,ier, bphi_ccw=1, jphi_ccw=-1) ! example
  
  ! also on the first call, a LIMITER should be defined...

  allocate(rpts(nlim),zpts(nlim))

  <fill in with sequence of (R,Z) pairs defining a closed contour>
  <rpts(1)=rpts(nlim) and zpts(1)=zpts(nlim) are expected>

  call xplasma_mklim_contour(s,rpts(1:nlim),zpts(1:nlim),iwarn,ier)

  ! and an [R,Z] rectangular space covering the plasma and limiter should be
  ! defined:

  allocate(rgrid(nrgrid),zgrid(nzgrid))

  <fill in desired R and Z grids which should at least span the limiter>
  <  i.e. rgrid(1) <= minval(rpts); rgrid(nrgrid) >= maxval(rpts) >
  <  i.e. zgrid(1) <= minval(zpts); zgrid(nzgrid) >= maxval(zpts) >

  call xplasma_create_rzgrid(s,rgrid(1:nrgrid),zgrid(1:nzgrid), &
	id_rgrid,id_zgrid,ier)  ! these arguments returned...

  ! done for now...

  call xplasma_author_clear(s,author_name,ier)

Home Top


Modifying_F95_Xplasma_Data

In this section, the new Fortran-95 Xplasma interface is described,
with emphasis on methods for adding data to an existing dataset, or,
creating one from scratch.

The xplasma pointers (s,s1) defined in xplasma_obj_instance are presumed
to be available in the coding examples.

The argument "ierr" is always a return status code, 0=normal.

For simplicity of examples, error checking / error handling code is
usually omitted -- don't try this at home!

Home Top


Code_authorship

Since xplasma is envisioned as a means of communication between disparate
code modules or even separately executing processes, it is useful to be
able to trace the origin of xplasma data items to specific codes or 
modules.

In practice, this means a code must "identify itself" to access xplasma.
A code that writes into xplasma must provide an "author id", which is any
alphanumeric name, not starting with a digit, up to 32 characters long.

Failure to do this will usually result in an "xplasma locked" error report.

Codes which write to xplasma should use the following pair of calls:

  character*32 author_name

  author_name = "my_code"  ! or whatever name you choose...

  call xplasma_author_set(s,author_name,ier)  ! push my name onto author stack

     <write stuff into xplasma>

  call xplasma_author_clear(s,author_name,ier) ! pop my name off the stack

An error could conceivably occur on the latter call, if an intervening
call (after xplasma_author_set) was made to another module, which issued
another xplasma_author_set but failed to issue a matching call to
xplasma_author_clear; the software would then detect that the passed name
does not match the name at the top of the author stack.

To prevent such errors, it is important to always pair these calls.

Home Top


Update_the_MHD_equilibrium

FREE BOUNDARY MHD equilibria are best read into xplasma from a G-eqdsk 
file: 

  call xplasma_author_set(s,author_name,ier)

  call xplasma_fromgeqdsk(s,filename,ier, [...optional arguments...])

  ! also a good idea:
  real*8 :: curtime

  curtime = <current time of simulation>
  call xplasma_time_set(s,curtime,ier)

  call xplasma_author_clear(s,author_name,ier)

The first time this is done, the resolution of the flux coordinate "rho"
and "theta" grids can be specified-- note that only evenly spaced grids
are allowed for equilibria built from G-eqdsk at present.  If the grid
size optional arguments "nrho" and "nth" are omitted, the default values
nrho=51 and nth=101 are used-- sufficient for many purposes.

On subsequent calls, the equilibrium flux coordinate grids are reused
from the prior state.

PRESCRIBED BOUNDARY MHD equilibria are updated through a sequence of
calls which redefine the equilibrium profiles-- as described in the
subtopic.

Home Top


xplasma_fromgeqdsk

The full xplasma_fromgeqdsk interface is copied below.

Except possibly for specifying "nrho" and "nth" on the first call, most
users should leave the optional arguments unspecified-- the default values
are well tested and reliable.

The argument "filename" can be either a unix file path to a read-accessible
G-eqdsk file in the standard GA-documented EFIT format, or, it can be a
path to an MDS+ tree (access to experimental database).

MDS+ path strings take the following form:

  MDS+[/<time-option>]:<server>[:<port>]:<tree>(<shot>;t=<time>)

items in square brackets [,] are optional (though sometimes a port number
is required to access a particular server); items in angle brackets <,> 
are to be replaced with their correct values; everything else is literal.

  <time-option> can be REDUCE (the default) or NOREDUCE.
    REDUCE means: select the nearest available time; read only that time
    from the MDS+ database.

    NOREDUCE means: read all available times from the database; interpolate
    linearly between available times to get to the <time> requested.

    In applications which loop over all times in an experiment, it is more
    efficient to use NOREDUCE (fewer network data accesses).

  <server> or <server>[:<port>] is the network address of the MDS+ server.

    Examples: alcdata.psfc.mit.edu (CMOD); europa.pppl.gov:8501 (NSTX).

  <tree> is the name of the tree containing time dependent EFIT G-eqdsk data.

    Typical examples:  EFIT01 (NSTX, DIII-D), ANALYSIS (CMOD).

  <shot> is the integer shot or pulse number of the experimental data.

  <time> is time in seconds in any decodable floating point format.

Example:  MDS+/REDUCE:EUROPA.PPPL.GOV:8501:EFIT06(116313;t=0.9)

----------------------
CAUTION:  MDS+ server access may be restricted, depending on the policy
of the experimental project that owns the server.
----------------------

    subroutine xplasma_fromgeqdsk(s,filename,ier, &
         new_device, nrho, nth, lhermite, &
         bdy0, cratio_min, rzspace, rhobrk_adj_axis, mom_rtol, &
         equal_arc, &
         gs_errmax)

      ! (re)build equilibrium inverse represenation from EFIT g-eqdsk data
      !    R(rho,theta), Z(rho,theta), g(rho),q(rho),P(rho).

      type (xplasma), pointer :: s

      character*(*), intent(in) :: filename  ! Geqdsk filename or MDS+ path
      !                  ...or...EFIT_INDEX:filename(t=<time>) specification
      !                  see comments in source/xplasma/eqm_fromgeqdsk.f90

      integer, intent(out) :: ier  ! integer status code (returned; 0=OK)

      !---------------
      !  optional...

      logical, intent(in), optional :: new_device ! flag, .TRUE. if reading
      !  equilibrium for a new device.  Default: .TRUE. when reading the
      !  first equilibrium in the history of the xplasma object; .FALSE.
      !  subsequently.  When this is not .TRUE., the limiter data is presumed
      !  already known to xplasma.

      integer, intent(in), optional :: nrho  ! no. of flux surfaces 
      !                                        covering rho = [0:1]
      !  rho = normalized(sqrt(Psi-tor/Psi-tor-at-bdy))
      !        for 20 zones specify nrho=21 -- count includes axis and plasma
      !        boundary-- evenly spaced in rho
      !  DEFAULT: nrho=51 if new_device is .TRUE.; otherwise the value from
      !  the old equilibrium is taken.

      integer, intent(in), optional :: nth   ! no. of theta points -- no. of 
      !        evenly spaced points spanning 0:2pi inclusive.
      !  DEFAULT: nth=101 if new_device is .TRUE.; otherwise the value from
      !  the old equilibrium is taken.

      logical, intent(in), optional :: lhermite ! flag, .TRUE. for Hermite
      !  interpolation of {R,Z}(rho,theta) -- by default, bicubic spline
      !  interpolation is used.

      real*8, intent(in), optional :: bdy0   ! initial Psi_bdy/Psi_sep
      !  (default 1.0d0) fraction of Psi to enclose in mapped region
      !  The issue here is that a separatrix surface generally cannot be
      !  used as a boundary in an inverse representation, due to q=infinity
      !  and the kink in the surface shape.  So instead one backs off from
      !  the Psi_sep flux, defining a boundary just inside the separatrix.
      !    Recommendation: the default.  "cratio_min" causes the code to
      !  iterate to find a suitable boundary surface.
      !  Accepted range: 0.95d0 to 1.00d0

      real*8, intent(in), optional :: cratio_min  ! minimum curvature ratio
      !  (default 0.080d0) minimum acceptable local curvature radius, 
      !  normalized to midplane half width.  A separatrix kink has a curvature
      !  radius of zero.  This is tested by fitting a circle through successive
      !  sequences of 3 points on the boundary grid [1:nth] and looking at this
      !  circle's radius compared to an estimate of the plasma midplane half-
      !  width.
      !    Recommendation: the default, based on experience.
      !  Accepted range: 0.01d0 to 0.15d0

      logical, intent(in), optional :: rzspace ! .TRUE. to save (R,Z)
      !  grids using the EFIT grids, and compute B(R,Z).  Default = .TRUE.
      !  Setting this .FALSE. may speed some applications.

      integer, intent(in), optional :: kmom    ! number of Fourier moments
      !  to use in Fourier Spline representation of equilibrium 
      !  (default: not set here; xplasma default is 16).

      real*8, intent(in), optional :: rhobrk_adj_axis ! delta(rho) for
      !  moments trimming operations, and, the maximum rho where flux
      !  surfaces can be touched, in order to assure that d/drho[R0,Z0] --> 0
      !  as rho--> 0, an attributed needed by codes (e.g. RF solvers) that
      !  use the inverted equilibrium.
      !    Default value: 0.15d0.  To disable this feature, set 
      !  rhobrk_adj_axis = -1.0d0 or any other negative number

      real*8, intent(in), optional :: mom_rtol ! moments trimming ratio
      !  (default 1.0d-6).  The EFIT Psi(R,Z) inversion involves a Fourier
      !  representation; this control specifies a method for trimming away
      !  higher order moments that are very small over wide regions of space.
      !  Accepted range: 0.0d0 to 1.0d-4

      logical, intent(in), optional :: equal_arc  ! .TRUE. to use an equal
      !  arc definition for the poloidal angle coordinate; .FALSE. (default)
      !  for VMEC/descur moments power spectrum minimization definition, the
      !  traditional definition for past usage.

      real*8, intent(out), optional :: gs_errmax  ! normalized measure of
      !  Grad Shafranof (GS) error in the EFIT equilibrium.

Home Top


xplasma_geqdsk_rewrite

Immediately after reading an xplasma file or MDS+ tree (i.e. after an
xplasma_fromgeqdsk call) it is possible to rewrite the G-eqdsk data into
a separately named standard EFIT G-eqdsk file.

This is used mainly to extract MDS+ tree data into files, so that legacy
codes which only know to read G-eqdsk as files, not as MDS+ records, can
work:

    subroutine xplasma_geqdsk_rewrite(filename,ier)

      !  rewrite g-eqdsk file e.g. under new filename, after reading
      !  (e.g. inside an eqi_fromgeqdsk call).

      !  WARNING: the information written is based on the most recent
      !  read of g-eqdsk information.  Information to reconstruct the
      !  g-eqdsk from the data as originally read is NOT saved with each
      !  xplasma object.  Hence: no s pointer argument.

      character*(*), intent(in) :: filename
      integer, intent(out) :: ier

NOTE that there is no xplasma object pointer-- this simply rewrites the
most recently read G-eqdsk data.

The xplasma library is using a subsidiary, non-object-oriented library
for EFIT G-eqdsk I/O.  So, this method should be used with care.

Home Top


xplasma_wr_geqdsk

After an equilibrium has been created within xplasma, by whatever means,
it can be written as a G-file.

The method here differs from xplasma_geqdsk_rewrite as follows:

  (a) the output [R,Z] domain and resolution can be redefined;
  (b) the equilibrium could have been created by means other than an
      "xplasma_fromgeqdsk" call.

    subroutine xplasma_wr_geqdsk(s,ierr, &
         lun_geqdsk, filename, label, Rmin, Rmax, Zmin, Zmax, &
         cur, id_qprof, id_pprof, &
         nh, nv, nbdy)

      use eqi_geq_mod

      !  Build and write a G-eqdsk file (disk file) from current xplasma
      !  contents.  This differs from "xplasma_geqdsk_rewrite" as the latter
      !  just echoes data read in from another G-eqdsk file or MDSplus data
      !  structure.  This actual constructs the information from current
      !  xplasma contents -- interpolation is involved.

      !  The xplasma object must contain a complete free boundary or 
      !  extrapolated equilibrium, so that Psi(R,Z) covering a rectangle
      !  enclosing the plasma is defined.

      !-----------------
      !  required:

      type (xplasma), pointer :: s  ! XPLASMA object containing equilibrium

      integer, intent(out) :: ierr  ! status code on exit: 0=OK

      !  optional:

      integer, intent(in), optional :: lun_geqdsk  
      ! FORTRAN LUN on which to write file.  If omitted, the LUN used for
      ! reading G-eqdsk files, in the geqdsk_mds library, is used.
      !   (call geq_getlun(ilun)) (geqdsk_mod default value: 77 as of 7/2006).

      character*(*), intent(in), optional :: filename
      ! default " "; if non-blank, it is the
      ! name of the file to write.  If blank or omitted, the code simply 
      ! writes to lun_geqdsk; it would be up to the caller to OPEN a file.

      character*(*), intent(in), optional :: label
      ! default " "; default means: use xplasma global label; 
      ! if non-blank, the 1st 48 characters are used as a label string in the
      ! G-eqdsk file being written.

      real*8, intent(in), optional :: Rmin,Rmax, Zmin,Zmax
      ! [R,Z] domain over which Psi(R,Z) is written in the G-eqdsk file.
      ! default: use the [R,Z] grid limits already stored in xplasma.  If
      ! explicit limits are provided, overriding the defaults, these must
      ! not extend beyond the grid limits.

      real*8, intent(in), optional :: cur
      ! total plasma current.  Default: use value implied by equilibrium data.

      integer, intent(in), optional :: id_qprof
      ! ID of profile f(rho) defining q(rho).  Default: use value derived from
      ! equilibrium-- calculated here, it will be named Q_EQDSK

      integer, intent(in), optional :: id_pprof
      ! ID of profile f(rho) defining equilibrium pressure.  Default: use value
      ! previously tagged as equilibrium pressure.  If this is not available,
      ! the code will attempt to compute a pressure using the surface averaged
      ! GS equation JxB=grad(P).  This could lead to a non-physical result if
      ! there are errors in the equilibrium data already provided, or if the
      ! assumption of a scalar P is inappropriate.  If a pressure profile is
      ! calculated, it will be named P_EQDSK-- done using an xplasma_gen_p
      ! call.

      integer, intent(in), optional :: nh,nv
      ! number of horizontal and vertical grid points, respectively.  If
      ! defaulted, the sizes of the [R,Z] grids are used.  NOTE that nh also
      ! controls the size of the 1d profiles f,ff',P,P',and q written in the
      ! G-eqdsk profiles.  These 1d profiles are written over an implied 
      ! evenly spaced Psi grid going from Psi(min) at the axis to Psi(max)
      ! at the boundary.
      
      integer, intent(in), optional :: nbdy
      ! number of points to use to described plasma boundary and limiter.
      ! default: 200.

Home Top


Prescribed_boundary_equilibrium_update

A working example is given in the xplasma test program xplasma_fsp_test.
Here a sketch of the code is provided.  Details on individual calls are
provided in other parts of this document.

Prescribed boundary codes like TRANSP use this method.

Many details must be specified-- one reason why using a G-eqdsk instead is
often more convenient...

  call xplasma_author_set(s,author_name,ier)

  !--------------------------
  ! on the FIRST call, the rho and theta grids need to be defined...
  ! this is presumed done already; the rho and theta grid IDs are
  ! presumed known and stored in integers "id_rho" and "id_th".

  integer :: id_rho, id_th   ! grid IDs
  integer :: inrho, inth     ! grid sizes

  ! can retrieve this grid IDs e.g. as follows:

  integer :: id_R
  call xplasma_common_ids(s,ier, id_R=id_R)  ! retrieve R(theta,rho) ID

  call xplasma_prof_info(s,id_R,ier, gridId1=id_th, gridId2=id_rho)

  ! can get grid sizes this way:

  call xplasma_grid_size(s,id_rho,inrho,ier)
  call xplasma_grid_size(s,id_th,inth,ier)

  ! can also fetch actual grids with "xplasma_grid" calls.

  !--------------------------
  ! on calls other than the FIRST call, the following call will DELETE
  ! the old equilibrium profiles:

  logical :: rzonly  ! TRUE to delete R,Z only; FALSE to delete {R,Z,g,p,Psi}

  <set rzonly to desired value>
  call xplasma_eqClear(s,rzonly,ier)
  !--------------------------

  allocate(R(inth,inrho),Z(inth,inrho))  ! dimensions match equilibrium
  ! flux coordinate grids

  <update R and Z data arrays to desired new geometry>

  ! define the geometry
  !   optional arguments allow specification of dR/drho and dZ/drho
  !   boundary conditions if desired.
  call xplasma_rzmag(s,id_th,id_rho,R,Z,id_R,id_Z,ier, [options...])

  allocate(g(inrho),psi(inrho),p(inrho),q(inrho))

  <update G, psi, P, q data arrays>

  call xplasma_create_prof(s,'G',id_rho,g,id_g,ier)
  call xplasma_create_prof(s,'Psi',id_rho,psi,id_psi,ier)
  call xplasma_create_prof(s,'Q',id_rho,q,id_q,ier)  ! or...
  call xplasma_create_prof(s,'P',id_rho,p,id_p,ier)

  ! (Q can also be computed by xplasma, once G and Psi have been provided)

  ispline=2
  call xplasma_gen_q(s,'Q',ispline,id_q,ier)

  ! enough information has now been specified to check the equilibrium and
  ! compute field component splines

  iforce=.TRUE.  ! do the computation unconditionally
  call xplasma_eqCheck(s,iforce,icount,ier)

  ! the error code should be checked!! if the (R,Z) geometry contains
  ! metric singularities, it will be detected.  Such errors cannot be
  ! ignored as these would otherwise cause a zoo of failures later on...

  ! finally, to create an environment similar to the one provided by
  ! a free boundary equilibrium, based however only on a rough extrapolation
  ! of the fields to a [R,Z] rectangle covering the core and scrapeoff plasma

  ! DO NOT USE this if a free boundary Psi(R,Z), defining a real external
  ! field, is available...

  call xplasma_brz_extrap(s,ier, [options...])

  ! also a good idea:
  real*8 :: curtime

  curtime = <current time of simulation>
  call xplasma_time_set(s,curtime,ier)

  call xplasma_author_clear(s,author_name,ier)

Home Top


Error_handling

Xplasma routines never write messages to files or to stdout-- all error
handling is by means of a status code.  Almost all xplasma subroutine 
calls return an integer status code "ierr".  If the value of ierr returned
is 0, there is no error, completion status is normal.

  (NOTE: spelling variant: some xplasma routines spell this "ier" in
  their argument lists).

Codes using xplasma need to check for and handle errors.  Xplasma "tries 
hard" to avoid errors; if it fails the error is generally not ignorable.

It is expected that the normal action after an xplasma error will be to
shut down the software as gracefully as possible with appropriate 
explanatory messages.

Messages associated with errors are created and stored within a small 
message buffer in the xplasma object.  It is up to the code using xplasma 
to control the disposition of these messages.

If an f95 xplasma routine returns a non-zero error code, the following 
call should be used:

    call xplasma_error(s,ierr,ilun)

with "s" the xplasma object pointer,
     (integer) ierr the status code, *input* to this routine, and
     (integer) ilun the fortran I/O unit on which to write messages
               associated with this error.

In addition, the user software should generally write some message
such as perhaps "unexpected xplasma error in subroutine XYZ, exiting...";
good messages of this type are a tremendous help in debugging large codes.

Generally, specific error codes are associated with specific errors.
For example, ierr=101 indicates that a NULL s pointer was passed.

Home Top


Time_evolving_xplasma

A major change to F95 xplasma compared to the original version, is the
ability to update the xplasma equilibrium on the fly, while preserving
other profiles.  (In the original F77 xplasma version, an equilibrium
change required reconstruction of the entire xplasma contents).

Some items are marked as "derived from the equilibrium"-- these are 
generally built internally within xplasma and have the following 
author ID:

  character*32, parameter, public :: xplasma_xmhd = '__XPLASMA_MHDEQ_DERIVED'

These items will be deleted and rebuilt, each time the equilibrium
changes.  Examples of such items are:

  -- list giving magnetic axis parameters R_axis, Z_axis, B_axis
  -- list giving R, Z, B extrema of boundary surface
  -- data related to flux surface averages
  -- data related to coordinate transformations

----------------------------------------------------------------
There are some structural limits on changes over time.

The contraints are as follows.  Although profiles, including those 
describing the equilibrium, can be updated or replaced at any time, 
underlying grids are not so easily changed.

In particular, the software does not allow a grid to be deleted or
replaced, if it detects that any existing profiles are using that grid.

If it were necessary for a time dependent code to regrid to a finer
mesh, all affected profiles would need to be reinterpolated accordingly.

This can be done, but there is no standard method at present.  Some code
would have to be written.

Because F95 xplasma supports multiple instantiation of xplasma objects, it
would not be too difficult.

A sketch of the code to carry this out would look like this:

  integer :: ier,ii,idg,inum_profs,inum_modify
  integer :: idg1,idg2,idg3,icoord
  integer, dimension(:), allocatable :: ids, ids_modify
  character*32 gname

  idg = [id of grid that will be changed]

  ! retrieve name and associated coordinate ID
  ! (in a real code these are probably known already)

  call xplasma_grid_info(s,idg,ier, name=gname, coord=icoord)

  ! make a copy of the xplasma object "s" to "s2"
  call xplasma_copy(s,s2,ier)

  ! get the full list of profiles
  call xplasma_num_items(s,ier, num_profs=inum_profs)

  allocate(ids(inum_profs),ids_modify(inum_profs))
  call xplasma_contents(s,ier, id_profs=ids)

  ! delete profiles which use "idg"; build list of deleted profiles

  inum_modify = 0
  do ii=1,inum_profs
    call xplasma_prof_info(s,ids(ii),ier, &
         gridId1=idg1,gridId2=idg2,gridId3=idg3)
    if((idg1.eq.idg).or.(idg2.eq.idg).or.(idg3.eq.idg)) then
      ! this profile uses the marked grid
      inum_modify = inum_modify + 1
      ids_modify(inum_modify) = ids(ii)
      call xplasma_remove_item(s,ids(ii),ier)
    endif
  enddo

  ! remove the old idg grid-- this should succeed now, since all the profiles
  ! using idg were removed from "s".

  call xplasma_remove_item(s,idg,ier); [check ier status]

  <form new grid data real*8 x(1:n)> -- same name, same id will result.

  call xplasma_create_grid(s,gname,icoord,s,idg,ier,label='...')

  do ii=1,inum_modify

    <using s2 copy of profile, form a local array copy reinterpolated to
     the new grid>
    <for multidimensional profiles this involves a loop over each
     of the other coordinates>

    call xplasma_create_prof(s,...)  ! Insert interpolated profile into "s".

  enddo

  call xplasma_free(s2,ier)  ! done with "s2"-- free the memory.

Home Top


Creation_and_update_of_named_items

Coordinates, grids, profiles, lists, and "black boxes" can be created or
replaced by the user, within the following constraints:

  (a) When a grid is created, the coordinate to which it belongs must be
      identified.  Conversely, coordinates cannot be removed or replaced
      if there are any grids currently associated with the coordinate.

  (b) When a profile is created, the grid or grids over which it is 
      defined must be specified.  Conversely, grids cannot be removed
      or redefined when they are "in use" by any profile.

Every item within xplasma has a unique name and integer ID.  Since the
name translation and lookup is somewhat expensive, most calls which refer
to an item requires its integer ID.  Full names are used when items are
created, and when their IDs are retrieved, per the following table:

item type         CREATE call                 LOOKUP call

coordinate        xplasma_create_coordinate   xplasma_coordId
grid              xplasma_create_grid         xplasma_gridId
profile           xplasma_create_prof         xplasma_profId
list              xplasma_create_list         xplasma_listId
black box         xplasma_create_blackBox     xplasma_blkbxId

The lookup calls all take the arguments (s,name,id) where s is the
xplasma object pointer, name is the item name, id is the integer id 
returned.

The interfaces for the CREATE routines are described in the subtopics.

Some specialized methods are available.  These are:

  xplasma_irhofun -- create a smoothed integrated profile
  xplasma_rzprof  -- create a profile f(R,Z), e.g. from f(rho).
  xplasma_rzprof_fun -- xplasma_rzprof with a user provided function call

  xplasma_mcgrid_define -- create an irregular "Monte Carlo" grid (MCgrid).
  xplasma_mcgrid_putobj -- create a profile over a MCgrid.

--------------

All blocks of code using the CREATE methods should be bracked by the
pair of calls requesting and releasing write authority:

   call xplasma_author_set(s,author_name,ier)

     [create stuff]

   call xplasma_author_clear(s,author_name,ier)

Home Top


xplasma_label_item

The label and physical units of an item are generally optional arguments
in the xplasma_create subroutines.  These can be provided later, by means
of this call:

  character*50 :: label = <very brief description of item>
  character*16 :: units = <physical units label, should be MKS>

  call xplasma_label_item(s,id,ier, label=label, units=units)

  !-------------------

    subroutine xplasma_label_item(s,id,ier, &
         label,units)

      !  label an existing item as identified by "id"...

      type (xplasma), pointer :: s
      integer, intent(in) :: id          ! id of existing item
      integer, intent(out) :: ier        ! status code returned

      character*(*), intent(in), optional :: label ! label for item
      character*(*), intent(in), optional :: units ! units label for item

Home Top


xplasma_create_coordinate

    subroutine xplasma_create_coord(s,coordname,periodic,id,ier, &
      label,units)
    
      !  create a coordinate with the specified name; return new coord id

      type (xplasma), pointer :: s
      character*(*), intent(in) :: coordname
      logical, intent(in) :: periodic  ! T if named coordinate is periodic
      integer, intent(out) :: id  ! id of coordinate object
      integer, intent(out) :: ier ! completion code

      character*(*), intent(in), optional :: label
      character*(*), intent(in), optional :: units

Home Top


xplasma_create_grid

    subroutine xplasma_create_grid(s,gridname,icoord,x,id,ier, &
         ccwflag,label)
    
      !  create a new grid with the specified name; return new grid id

      type (xplasma), pointer :: s
      character*(*), intent(in) :: gridname
      integer, intent(in) :: icoord  ! id of coordinate object to which the
                                     ! grid object belongs
      !  icoord can also be a grid id, in which case the coordinate associated
      !  with this new grid is the one associated with grid (icoord)

      real*8, intent(in) :: x(:)  ! the grid, x(j).lt.x(j+1) required.
      integer, intent(out) :: id  ! id of grid object
      integer, intent(out) :: ier ! completion code

      !  specify if toroidal or poloidal angle grid is drawn counterclockwise:
      logical, intent(in), OPTIONAL :: ccwflag
      !    theta: when viewing plasma cross section to right of machine
      !           centerline
      !    phi:   when viewing machine from above
      !    Default: .TRUE.

      character*(*), intent(in), optional :: label
      !  units label inherited from associated coordinate object

      !  NOTE: xplasma saves all angle grids with CCW orientation; a CW
      !  oriented grid will be redefined with its direction reversed:
      !     angle -> 2pi - angle

Home Top


xplasma_create_prof

Generally, the following arguments are required:

  xplasma object pointer
  profile name
  grid ID(s)
  profile data -- array dimensions must match gridsizes EXACTLY.
  profile ID returned
  error status returned

Optional arguments:
  ispline -- type of interpolation
    -1 -- zonal data (step function):
          this is the default if the data dimension sizes are 1 less
          than the corresponding grid sizes.
     0 -- piecewise linear (the default)
     1 -- C1 Akima Hermite
     2 -- C2 Cubic Spline

  Boundary conditions (for ispline=1 or ispline=2).  For rank N data, 
  each explicit boundary condition data array is of rank N-1; array 
  dimensions must match appropriate gridsizes EXACTLY.  But-- there 
  are many cases where explicit boundary conditions are not required;
  it depends on the application of the data.

  ccwflag arguments -- in effect these specify that the storage order
     of the data along a periodic grid dimension is reversed-- but, the
     end points must match the referenced grid.

  assoc_id -- pairs of profiles can be associated.  This is to support
     the idea that a physical quantity, e.g. a B field component, might
     have both a flux coordinate representation and an [R,Z] representation.
     When profiles are associated, the IDs for the flux coordinate versions
     and [R,Z] coordinate versions of the data can be used interchangeably,
     i.e. providing the flux coordinate profile ID to an [R,Z] interpolation
     call will not result in an error.

  label & units

Verbatim interfaces for 1d 2d and 3d profile create routines follow...

  interface xplasma_create_prof
    module procedure xplasma_create_1dprof
    module procedure xplasma_create_2dprof
    module procedure xplasma_create_3dprof
  end interface 

    subroutine xplasma_create_1dprof(s,profname,idx,data,idf,ier, &
         ispline,ibca,zbca,ibcb,zbcb,ccwflag,assoc_id,label,units)
    
      !  create a new profile with the specified name

      !--------
      !  standard INPUT arguments...

      type (xplasma), pointer :: s
      character*(*), intent(in) :: profname  ! name of profile
      integer, intent(in) :: idx         ! id of grid over which it is defined
      real*8, dimension(:), intent(in) :: data  ! the profile data
      !  (NOTE: size of data must match size of grid)

      !--------
      !  standard OUTPUT arguments...

      integer, intent(out) :: idf        ! id of profile now being (re)defined.
      integer, intent(out) :: ier        ! completion code (0=normal)

      !--------
      !  optional input arguments...
      !  defaults: pc linear; for splines: "not a knot" BC
      !            angle grid: normal CCW orientation.

      integer, intent(in), optional :: ispline  ! order of fit
      ! 0 -- pc linear; 1 -- Hermite; 2 -- cubic spline;

      integer, intent(in), optional :: ibca     ! BC control @ LHS of grid
      real*8, intent(in), optional :: zbca      ! BC data @ LHS of grid
      integer, intent(in), optional :: ibcb     ! BC control @ RHS of grid
      real*8, intent(in), optional :: zbcb      ! BC data @ RHS of grid

      ! ibca=ibcb=0 = default: "not a knot" for splines; Akima for Hermite
      ! for periodic functions BC args are ignored; periodic BC is used.

      ! ibc[*]=1 -- df/dx specified in zbc[*] (0 if absent)
      ! ibc[*]=2 -- d^2f/dx^2 specified in zbc[*] (0 if absent)

      logical, intent(in), optional :: ccwflag  ! T means data vs. CCW angle
      ! grid; F means CW.  Default=T.  ccwflag is ignored if the x grid of
      ! the profile is not an angle coordinate.

      integer, intent(in), optional :: assoc_id

      character*(*), intent(in), optional :: label
      character*(*), intent(in), optional :: units

      !------------------------------------------

    subroutine xplasma_create_2dprof(s,profname, &
         idx1,idx2,data,idf,ier, &
         ispline,ibcx1a,zbcx1a,ibcx1b,zbcx1b, &
         ibcx2a,zbcx2a,ibcx2b,zbcx2b, ccwflag1,ccwflag2, &
         assoc_id, label,units)
    
      !  create a new profile with the specified name

      !--------
      !  standard INPUT arguments...

      type (xplasma), pointer :: s
      character*(*), intent(in) :: profname  ! name of profile
      integer, intent(in) :: idx1    ! id of 1st grid over which it is defined
      integer, intent(in) :: idx2    ! id of 2nd grid over which it is defined
      real*8, dimension(:,:), intent(in) :: data  ! the profile data
      !  (NOTE: sizes of dimensions MUST match sizes of identified grids)

      !--------
      !  standard OUTPUT arguments...

      integer, intent(out) :: idf       ! id of container for this profile.
      integer, intent(out) :: ier       ! completion code (0=normal)

      !--------
      !  optional input arguments...
      !  defaults: pc linear; for splines: "not a knot" BC
      !            angle grid: normal CCW orientation.

      integer, intent(in), optional :: ispline  ! order of fit
      ! 0 -- pc linear; 1 -- Hermite; 2 -- cubic spline;

      integer, intent(in), optional :: ibcx1a     ! BC control @ LHS of grid x1
      real*8, intent(in), dimension(:), optional :: zbcx1a ! BC data @ LHS of grid x1
      integer, intent(in), optional :: ibcx1b     ! BC control @ RHS of grid x1
      real*8, intent(in), dimension(:), optional :: zbcx1b ! BC data @ RHS of grid x1

      integer, intent(in), optional :: ibcx2a     ! BC control @ LHS of grid x2
      real*8, intent(in), dimension(:), optional :: zbcx2a ! BC data @ LHS of grid x2
      integer, intent(in), optional :: ibcx2b     ! BC control @ RHS of grid x2
      real*8, intent(in), dimension(:), optional :: zbcx2b ! BC data @ RHS of grid x2

      ! ibc*a=ibc*b=0 = default: "not a knot" for splines; Akima for Hermite
      ! for periodic functions BC args are ignored; periodic BC is used.

      ! ibc[*]=1 -- df/dx specified in zbc[*] (0 if absent)
      ! ibc[*]=2 -- d^2f/dx^2 specified in zbc[*] (0 if absent)

      logical, intent(in), optional :: ccwflag1  ! T means data vs. CCW angle
      ! grid; F means CW.  Default=T.

      logical, intent(in), optional :: ccwflag2  ! T means data vs. CCW angle
      ! grid; F means CW.  Default=T.

      integer, intent(in), optional :: assoc_id  ! id of associated profile

      character*(*), intent(in), optional :: label
      character*(*), intent(in), optional :: units

      !------------------------------------------
 
    subroutine xplasma_create_3dprof(s,profname, &
         idx1,idx2,idx3,data,idf,ier, &
         ispline,ibcx1a,zbcx1a,ibcx1b,zbcx1b, &
         ibcx2a,zbcx2a,ibcx2b,zbcx2b, &
         ibcx3a,zbcx3a,ibcx3b,zbcx3b, &
         ccwflag1,ccwflag2,ccwflag3, assoc_id,label,units)
    
      !  create a new profile with the specified name

      !--------
      !  standard INPUT arguments...

      type (xplasma), pointer :: s
      character*(*), intent(in) :: profname  ! name of profile
      integer, intent(in) :: idx1    ! id of 1st grid over which it is defined
      integer, intent(in) :: idx2    ! id of 2nd grid over which it is defined
      integer, intent(in) :: idx3    ! id of 3rd grid over which it is defined
      real*8, dimension(:,:,:), intent(in) :: data  ! the profile data
      !  (NOTE: sizes of dimensions MUST match sizes of identified grids)

      !--------
      !  standard OUTPUT arguments...

      integer, intent(out) :: idf     ! id of newly created profile.
      integer, intent(out) :: ier     ! completion code (0=normal)

      !--------
      !  optional input arguments...
      !  defaults: pc linear; for splines: "not a knot" BC
      !            angle grid: normal CCW orientation.

      integer, intent(in), optional :: ispline  ! order of fit
      ! 0 -- pc linear; 1 -- Hermite; 2 -- cubic spline;

      integer, intent(in), optional :: ibcx1a     ! BC control @ LHS of grid x1
      real*8, intent(in), dimension(:,:), optional :: zbcx1a ! BC data @ LHS of grid x1
      integer, intent(in), optional :: ibcx1b     ! BC control @ RHS of grid x1
      real*8, intent(in), dimension(:,:), optional :: zbcx1b ! BC data @ RHS of grid x1

      integer, intent(in), optional :: ibcx2a     ! BC control @ LHS of grid x2
      real*8, intent(in), dimension(:,:), optional :: zbcx2a ! BC data @ LHS of grid x2
      integer, intent(in), optional :: ibcx2b     ! BC control @ RHS of grid x2
      real*8, intent(in), dimension(:,:), optional :: zbcx2b ! BC data @ RHS of grid x2

      integer, intent(in), optional :: ibcx3a     ! BC control @ LHS of grid x3
      real*8, intent(in), dimension(:,:), optional :: zbcx3a ! BC data @ LHS of grid x3
      integer, intent(in), optional :: ibcx3b     ! BC control @ RHS of grid x3
      real*8, intent(in), dimension(:,:), optional :: zbcx3b ! BC data @ RHS of grid x3

      ! ibc*a=ibc*b=0 = default: "not a knot" for splines; Akima for Hermite
      ! for periodic functions BC args are ignored; periodic BC is used.

      ! ibc[*]=1 -- df/dx specified in zbc[*] (0 if absent)
      ! ibc[*]=2 -- d^2f/dx^2 specified in zbc[*] (0 if absent)

      logical, intent(in), optional :: ccwflag1  ! T means data vs. CCW angle
      ! grid; F means CW.  Default=T.

      logical, intent(in), optional :: ccwflag2  ! T means data vs. CCW angle
      ! grid; F means CW.  Default=T.

      logical, intent(in), optional :: ccwflag3  ! T means data vs. CCW angle
      ! grid; F means CW.  Default=T.

      ! ccwflag1 applies to x1 if it is periodic; otherwise it is ignored.
      ! ccwflag2 applies to x2 if it is periodic; otherwise it is ignored.
      ! ccwflag3 applies to x3 if it is periodic; otherwise it is ignored.

      integer, intent(in), optional :: assoc_id  ! id of associated profile

      character*(*), intent(in), optional :: label
      character*(*), intent(in), optional :: units

Home Top


xplasma_prof_lintrans

A linear transformation f -> a*f + b can be applied to an existing profile:

    subroutine xplasma_prof_lintrans(s,id,ierr, factor, offset)

      type (xplasma), pointer :: s
      integer, intent(in) :: id    ! profile ID
      integer, intent(out) :: ierr ! status code returned 0 = normal

      real*8, intent(in), optional :: factor   ! multiplicative factor
      real*8, intent(in), optional :: offset   ! additive offset

where a is specified as "factor" and b is specified as "offset".  If
neither optional argument is specified, the subroutine returns without
doing anything, since the default value for "factor" is a=1 and the
default value for "offset" is b=0.

Note: the current author (enabled to write xplasma data) must own the
profile being transformed; i.e. use xplasma_author_set(...) and 
xplasma_author_clear(...) calls if necessary to modify and restore
access control settings.

Home Top


xplasma_create_list

When a list is created, its elements must all be named.  Corresponding
values can either be given at create time, or may be supplied later.

    subroutine xplasma_create_list(s,listname,enames,id,ier, &
         label, units, ivals, r8vals, chvals)
      !
      !  create list & define list elements
      !
      type (xplasma), pointer :: s
      character*(*), intent(in) :: listname        ! name of list being created
      character*(*), intent(in), dimension(:) :: enames ! names of elements
      integer, intent(out) :: id          ! id of list item
      integer, intent(out) :: ier         ! completion code

      character*(*), intent(in), optional :: label  ! label for entire list
      character*(*), intent(in), optional :: units  ! units label for list

      integer,intent(in), dimension(:), optional :: ivals   ! integer values
      real*8, intent(in), dimension(:), optional :: r8vals  ! real*8 values
      character*(*), intent(in), dimension(:), optional :: chvals  ! str values

Methods for setting the list element values are given in the subtopics.

Home Top


xplasma_setList_r8vals

    subroutine xplasma_setList_r8vals(s,id,r8vals,ier)
      !
      !  set real*8 values in list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      real*8, dimension(:), intent(in) :: r8vals  ! the real*8 values
      integer, intent(out) :: ier         ! completion code

Home Top


xplasma_setList_ivals

    subroutine xplasma_setList_ivals(s,id,ivals,ier)
      !
      !  set integer values in list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      integer, dimension(:), intent(in) :: ivals   ! the integer values
      integer, intent(out) :: ier         ! completion code

Home Top


xplasma_setList_chvals

    subroutine xplasma_setList_chvals(s,id,chvals,ier)
      !
      !  set character string values in list
      !
      type (xplasma), pointer :: s
      integer, intent(in) :: id           ! id of list item
      character*(*), dimension(:), intent(in) :: chvals 
                                          ! the character string values

      integer, intent(out) :: ier         ! completion code

Home Top


xplasma_create_blackBox

A black box is basically a pair of buffers (one for integers, one for
real*8 floating point) in which the data interpretation is completely
left to the user.

Xplasma internally makes use of black boxes for various purposes-- caches
for numerical integration, data to speed coordinate transformations, and
implementation of MCgrids.

Each black box has a type code "itype".  Types between 0 and 101 are used
by xplasma.  User defined types should select a type code outside this
range.  The item name should also be chosen to give a hint as to the
meaning of the data.

    subroutine xplasma_create_blackBox(s,iname,itype,id,ier, &
         iarray,r8array,iasize,r8asize,label,units, &
         ia_ptr,r8a_ptr)

      !  create a blackBox -- a structure which contains the following
      !    -- a scalar integer TYPE (user defined meaning)
      !    -- an integer array
      !    -- a real*8 array

      !  Xplasma provides a mechanism for storage and retrieval of
      !  Black boxes; they are included in Xplasma NetCDF state files.
      !  The only methods supported are:
      !    xplasma_create_blackBox -- create the item; store the data
      !    xplasma_blackBox_info   -- retrieve info on item (e.g. array sizes)
      !    xplasma_blackBox_retrieve -- retrieve black box item data

      !  Xplasma makes internal use of blackboxes, e.g. to define limiters
      !  or set up data for efficient numerical integration for flux surface
      !  averages.  But, there are no reserved TYPE codes-- the significance
      !  of the blackBox TYPE, like the data itself, is entirely up to the
      !  user.

      type (xplasma), pointer :: s
      character*(*), intent(in) :: iname  ! name of black box item
      integer, intent(in) ::  itype       ! Black Box type code (user defined).

      integer, intent(out) :: id          ! id of newly created black box item
      integer, intent(out) :: ier         ! completion code

      !  independently for the integer and floating point arrays,
      !  --either data must be provided, or, data sizes must be provided.

      integer, dimension(:), intent(in), optional :: iarray   ! integer data
      real*8, dimension(:), intent(in), optional :: r8array   ! real*8 data

      !  --but not both!
      integer, intent(in), optional :: iasize   ! size of integer data
      integer, intent(in), optional :: r8asize  ! size of real*8 data

      !  optional labels...
      character*(*), intent(in), optional :: label,units

      !  optional output: pointers to blackbox arrays (null if ierr.ne.0)

      integer, dimension(:), pointer, optional :: ia_ptr
      real*8, dimension(:), pointer, optional :: r8a_ptr

Home Top


xplasma_irhofun

This subroutine creates a lightly smoothed interpolating profile for
an "integrated profile" function defined over a grid of the caller's
choosing.

An example of such a function would be:

   P_NBI(x) = Integrated NBI power, watts, from the plasma magnetic
             axis to flux surface "x".

The input gives a grid identification, the data, i.e. the integrated value
to each point on the grid, and the name to be used for identifying the
function.  The output is an identifier for the interpolating function.

The control "iflag" is 1 for volume integrated density profiles; 2 for
area integrated density profiles such as current drive profiles.

NOTE-- smoothing can produce unexpected artifacts-- for example, regions of
very small negative power density in a heating profile.  But, the integrated
power will be faithful to the original within half a zone width...

    !------------------------------------------
    subroutine xplasma_irhofun(s,id_axis,zlbl,inprof,zprof,iflag,id,ierr)

      !  make XPLASMA profile -- integrated quantity; smooth by 1/2 zone width
      !  to insure smooth derivative from spline

      type (xplasma), pointer :: s

      integer, intent(in) :: id_axis    ! axis id -- must be rho or akin to rho

      character*(*), intent(in) :: zlbl ! name for profile function to create

      integer, intent(in) :: inprof     ! size of the integrated data profile

      real*8, intent(in) :: zprof(inprof) ! the integrated data provided
              ! if inprof = size(x_axis) zprof(1)=0 is expected
              ! if inprof = size(x_axis)-1 the axial data point
              !    is presumed to be omitted.

      integer, intent(in) :: iflag      ! =1 -- volume normalization;
              ! derivative evaluations -> W/m^3, #/sec/m^3, etc.
              ! =2 -- area normalization;
              ! derivative evaluations -> A/m^2 (current density).

      integer, intent(out) :: id        ! id of stored profile (if successful)
      integer, intent(out) :: ierr      ! completion code, 0=OK.

      !  if an error occurs and ierr is set, id=0 will be returned.
      !-----------------------------------------------------------------

Home Top


xplasma_rzprof

    subroutine xplasma_rzprof(s,fname,id_out,ier, &
         id_Rgrid,id_Zgrid, &
         ispline,sm_edge, &
         id_fun_in,lamda, &
         label,units,data)

      ! create a profile f(R,Z) from existing data with extrapolation,
      ! or with array data provided.

      ! either an existing function (id_fun_in) or input data (data) or
      ! both must be provided.

      ! modes of use:
      !   (id_fun_in omitted, data(:,:) provided) -- just use the data given
      !   (id_fun_in provided, data(:,:) omitted) -- use existing profile
      !       at id_fun_in to give variation inside plasma; use extrapolation
      !       based on distance map: f_outside = f_bdy*exp(-d/lamda) where
      !       d is the distance from the plasma
      !   (both id_fun_in and data(:,:) provided) -- use existing profile
      !       at id_fun_in to give variation inside plasma: use data to 
      !       specify the variation beyond the plasma.

      !   ispline -- 0 = Bilinear, 1 = C1 Hermite, 2 = C2 Spline

      !   sm_edge -- Meters -- gives smoothing in vicinity of boundary
      !       a hat function convolution of half width sm_edge is applied
      !       in the vicinity of the boundary

      type(xplasma), pointer :: s

      character*(*), intent(in) :: fname  ! name of profile to create...

      integer, intent(out) :: id_out   ! ID of function just created
      integer, intent(out) :: ier      ! completion code 0=OK

      !------

      integer, intent(in), optional :: id_Rgrid,id_Zgrid  ! R & Z grids to use
      !  (default: __RGRID & __ZGRID)

      integer, intent(in), optional :: ispline  ! interpolation order
      ! -1: zonal step function; 0: piecewise linear;
      !  1: C1 Hermite; 2: C2 Spline

      real*8, intent(in), optional :: sm_edge   ! edge smoothing control
      ! default: no smoothing

      integer,intent(in), optional :: id_fun_in ! f(rho) from which to 
      ! form f(R,Z) (default: 0, none)
      real*8, intent(in), optional :: lamda     ! scrape off distance
      ! default: huge, making for flat extrapolation

      character*(*), intent(in), optional :: label,units  ! labeling info

      real*8, intent(inout), dimension(:,:), optional :: data  ! f(R,Z) data
      ! default: NONE
      ! data must be defined in extrapolated region-- internal region
      ! will be filled in...

Home Top


xplasma_rzprof_fun

    !-------------------------------------------------------
    subroutine xplasma_rzprof_fun(s,fname,user_fcn,user_iarg,id_out,ier, &
         id_Rgrid,id_Zgrid,ispline,sm_edge,id_fun_in,no_extrap, &
         label,units)

      ! create a profile f(R,Z) from a user provided callable function
      ! possibly combined with existing data.

      ! the callable function covers the entire region inside the limiters
      ! if id_fun_in is omitted; it covers only the region outside the plasma
      ! and inside the limiters if id_fun_in is included.

      ! modes of use:
      !   (id_fun_in omitted) -- just use the given callable function.
      !   (id_fun_in provided)-- use existing profile
      !       at id_fun_in to give variation inside plasma; use the given
      !       function to define the variation beyond the plasma boundary.

      ! the region beyond the limiters is defined by a simple extrapolation.
      ! unless no_extrap is set, in which case the function is used even
      ! beyond the limiters.

      !   sm_edge -- Meters -- gives smoothing in vicinity of boundary
      !       a hat function convolution of half width sm_edge is applied
      !       in the vicinity of the boundary

      type(xplasma), pointer :: s

      character*(*), intent(in) :: fname  ! name of profile to create...

      real*8, external :: user_fcn        ! user provided function...
      integer, intent(in) :: user_iarg    ! argument for user_fcn:

      !  real*8 function user_fcn(user_iarg,R,Z,Phi,ier)

      integer, intent(out) :: id_out   ! ID of function just created
      integer, intent(out) :: ier      ! completion code 0=OK

      !------

      integer, intent(in), optional :: id_Rgrid,id_Zgrid  ! R & Z grids to use
      !  (default: __RGRID & __ZGRID)

      integer, intent(in), optional :: ispline  ! interpolation order
      ! -1: zonal step function; 0: piecewise linear;
      !  1: C1 Hermite; 2: C2 Spline

      real*8, intent(in), optional :: sm_edge   ! edge smoothing control
      ! default: no smoothing

      integer,intent(in), optional :: id_fun_in ! f(rho) from which to 
      ! form f(R,Z) (default: 0, none)

      logical, intent(in), optional :: no_extrap ! T to suppress extrapolation
      ! beyond limiter.  In this case user_fcn calls are used for (R,Z) even
      ! for points outside the limiter.

      character*(*), intent(in), optional :: label,units  ! labeling info

Home Top


xplasma_mcgrid_define

This routine is used to create an irregular "Monte Carlo grid" or MCgrid.
This is a grid used by the NUBEAM fast ion Monte Carlo code.

The description of the MCgrid won't be repeated here, it is well described
elsewhere in the document (look for "mcgrid"), including in the f77 section.

    subroutine xplasma_mcgrid_define(s,mcname,inth0,inrow,id,ierr, &
         nphi,udsym,label,nrow_ext_in,nrow_ext_out)

      type(xplasma), pointer :: s
      character*(*), intent(in) :: mcname   ! name of MC grid

      integer, intent(in) :: inth0          ! no. of zones covering [0,pi]
                                            ! in 1st row at axis

      integer, intent(in) :: inrow          ! no. of rows covering plasma

      integer, intent(out) :: id            ! MC grid id returned (0 if error)
      integer, intent(out) :: ierr          ! status code returned (0=OK)

      integer, intent(in), optional :: nphi ! number of Phi=const zones
      !  default:1 (axisymmetry)

      logical, intent(in), optional :: udsym   ! updown symmetry flag
      !  default:.FALSE. (do not assume updown symmetric MHD equilibrium).

      character*(*), intent(in), optional :: label  ! optional label for MCgrid

      integer, intent(in), optional :: nrow_ext_in   ! no. of external rows
      !  requested (default: 0, meaning: use internal calculation).  If non-
      !  zero value is given, inrow >= nrow_ext_in >= 3 will be enforced.

      integer, intent(out), optional :: nrow_ext_out ! actual no. of external
      !  zone rows created.

Home Top


xplasma_mcgrid_putobj

Use this method to create a profile over an MCgrid.  The sister routine
xplasma_mcgrid_getobj is used to retrieve the profile.

    subroutine xplasma_mcgrid_putobj(s,id_mcgrid,pname,id_p,ierr, &
         lstart0_th,ccwflag_th, &
         data_1d,data_2d,data_3d, &
         gridId1,gridId2,normcode, &
         label,units)

      ! define a profile "object" over a MCgrid.  This can define
      ! a single data value per grid zone (use data_1d), or a vector of
      ! of data values per grid zone (use data_2d) or a 2d array of values
      ! per grid zone (use data_3d).

      type(xplasma), pointer :: s
      integer, intent(in) :: id_mcgrid  ! MCgrid over which profile is defined.
      character*(*), intent(in) :: pname ! name of profile
      integer, intent(out) :: id_p      ! xplasma ID of profile returned
      integer, intent(out) :: ierr      ! status code (0=OK)

      ! theta indexing options
      logical, intent(in), optional :: lstart0_th ! default depends on symmetry
      logical, intent(in), optional :: ccwflag_th ! default: T

      ! lstart0_th=T means user's first theta zone lower bdy is 0; F means it
      ! is -pi.  If defaulted: updown symmetric data assumed to start at 0;
      ! updown asymmetric data assumed to start at -pi.

      ! ccwflag_th=T means zone index increases as one goes along a row of
      ! zones at fixed radial index in a counter-clockwise direction; F means
      ! the opposite.  T is the default.

      ! NOTE: similar options for phi mapping could be defined but that has
      ! not yet been done; may be an issue if/when we get beyond axisymmetry
      ! in XPLASMA...

      ! Although following arguments are optional, exactly one must be
      ! provided.  The last dimension of the array must match the size
      ! of the entire grid, or of the subset of the grid covering the
      ! plasma (either or)

      real*8, intent(in), dimension(:), optional :: data_1d
      real*8, intent(in), dimension(:,:), optional :: data_2d
      real*8, intent(in), dimension(:,:,:), optional :: data_3d

      !  if data_2d or data_3d is specified-- it is desirable to specify
      !  a grid which corresponds to the 1st dimension of the data (default
      !  0, meaning no grid was specified).

      integer, intent(in), optional :: gridId1

      !  if data_3d is specified-- it is desirable to specify a grid which
      !  corresponds to the 2nd dimension of the data 

      integer, intent(in), optional :: gridId2
      
      !  (the actual data_2d or data_3d array dimensions will be one less 
      !  than the corresponding grid sizes, for zone oriented "binned" data).

      !-------------------
      !  normalization code
      !     0 - none -- default -- no information
      !    -1 - divide by vol(...) to get a density
      !    +1 - multiply by vol(...) to integrate a density
      !    +2 -- multiply by vol(...)*d[grid1]*d[grid2]/2 (FBM normalization)
      
      integer, intent(in), optional :: normcode

      !-----------------
      character*(*), intent(in), optional :: label
      character*(*), intent(in), optional :: units

Home Top


Xplasma_global_items

The following interfaces allow various xplasma global attributes or data
items to be updated.  Generally the values are retrieved with a call to
xplasma_global_info using optional arguments

    subroutine xplasma_time_set(s,ztime,ier)

      !  set the time (seconds) affiliated with xplasma object "s".

      type (xplasma), pointer :: s
      real*8, intent(in) :: ztime
      integer, intent(out) :: ier

  retrieval:
    call xplasma_time_get(s,ztime,ier) ...or...
    call xplasma_global_info(s,ier, time=ztime)

-------------------------------------------------------------
    subroutine xplasma_bdytol_set(s,zbtol,ier)

      !  set the out-of-bounds tolerance for profile interpolations
      !  a maximum value of 1.0d-4 is allowed...

      type (xplasma), pointer :: s
      real*8, intent(in) :: zbtol
      integer, intent(out) :: ier

  retrieval:
    call xplasma_global_info(s,ier, bdytol=zbtol)

-------------------------------------------------------------
    subroutine xplasma_kmom_set(s,kmom,ier)

      !  set the # of Fourier moments for the optional Fourier representation
      !  of the current equilibrium.  Default value is 16 not counting the
      !  0'th moment.  Minimum value is 2, max is 64.

      type (xplasma), pointer :: s
      integer, intent(in) :: kmom
      integer, intent(out) :: ier

  retrieval:
    call xplasma_global_info(s,ier, kmom=kmom)

-------------------------------------------------------------
    subroutine xplasma_ajac_maxvar_set(s,zvar,ier)

      !  set the amount of variation of det[J] to be allowed on a flux
      !  surface-- numerical control for detection of singular equilibria

      !  det J is det  | dR/drho   dR/dtheta |
      !                | dZ/drho   dZ/dtehta |

      type (xplasma), pointer :: s
      real*8, intent(in) :: zvar
      integer, intent(out) :: ier

  retrieval:
    call xplasma_global_info(s,ier, ajac_maxVar=zvar)

-------------------------------------------------------------
    subroutine xplasma_field_ccw_set(s,ier, bphi_ccw,jphi_ccw)

      !  set the Bphi and/or Jphi orientations (for tokamak fields)
      !  CCW -- counter-clockwise
      !  1 means (B or J is pointed) CCW looking down on machine from above
      ! -1 means CW, clockwise orientation.

      type (xplasma), pointer :: s
      integer, intent(out) :: ier   ! status code, 0=OK

      !  for the toroidal magnetic field:
      integer, intent(in), optional :: bphi_ccw  ! CCW value for Bphi

      !  for the toroidal plasma current:
      integer, intent(in), optional :: jphi_ccw  ! CCW value for Jphi

  retrieval:
    call xplasma_global_info(s,ier, bphi_ccw=bphi_ccw, jphi_ccw=jphi_ccw)

-------------------------------------------------------------
    subroutine xplasma_rzOrder_set(s,irzOrder,ier)

      !  set the default fit order for R(rho,theta),Z(rho,theta)
      !  equilibrium specification
      !    min value:  1 -- C1 Hermite fit will be used
      !    max value:  2 -- C2 Spline fit will be used (default)

      type (xplasma), pointer :: s
      integer, intent(in) :: irzOrder
      integer, intent(out) :: ier

  retrieval:
    call xplasma_global_info(s,ier, rzOrder=irzOrder)

Home Top


Saving_xplasma_to_file

The entire contents of an xplasma object "s" can be written to a NetCDF file,
with the following call:

  character*(*) filename  ! i.e. unix path to file

  call xplasma_write(s,filename,ier)

Other codes can load "s" (replacing any prior contents), with:

  call xplasma_read(s,filename,ier)

Home Top


Precision_and_F77_R4_interface

(With this section, original xplasma1 (f77 xplasma) documentation resumes).

(old f77 xplasma 1 documentation)

Note: the R4 interface is available for the fortran-77 xplasma
routines only.  The fortran-90 interface uses strictly REAL*8 precision
throughout.  The REAL*8 precision is compatible with fortran-90 floating
point KINDs which map to this (8-byte 64 bit) precision which is available
on all modern hardware.  Advice: code with IMPLICIT NONE to avoid 
inadvertant creation of 4-byte reals; be careful with handling of hard
coded constants.

The xplasma software is written in REAL*8 precision.
Routines described in the sections "Setup_Routines" and 
"Data_Access_Routines" are coded for REAL*8 floating point
arguments.  To call a fortran-77 style XPLASMA routine <name> 
instead with REAL arguments, use R4_<name>.

For example, 

      real*8 rhoR8,zeffR8    ! rhoR8 input, zeffR8 output
      real rhoR4,zeffR4      ! rhoR4 input, zeffR4 output
      integer id_Zeff        ! Zeff profile id (input)

      integer ierr           ! completion code, 0=OK (output)

 !  pass REAL*8 argument, get REAL*8 result
      rhoR8=0.5d0
      call eq_rgetf(1,rhoR8,id_Zeff,0,zeffR8,ierr)

 !  pass REAL(*4) argument, get REAL(*4) result
      rhoR4=rhoR8
      call r4_eq_rgetf(1,rhoR4,id_Zeff,0,zeffR4,ierr)

 --or--

fortran-90 codes can 

      use xplasma_calls

which defines "eq_rgetf" as a generic subroutine name.  This means
that if it the compiler sees that the routine has REAL*8 arguments
it will call the usual eq_rget subroutine, but, if the compiler
sees REAL*4 arguments, r4_eq_rgetf gets called.  The compiler can
also check that all arguments are of the right type and all arrays
of the correct rank.

The xplasma_calls module and the R4_ interfaces are automatically
generated from the standard interfaces by means of a script which
makes use of the "ftoken" tools in the NTCC modules library.

CAUTION:  for routines which take an external subroutine or 
function as an argument, the passed routine MUST use a REAL*8 
precision interface.

Home Top


C_F77_interface

(old f77 xplasma 1 documentation)

FROZEN in xplasma Version 2-- C interface routines exist for most
of the Version 1 xplasma fortran-77 style interface, but the 
development has been discontinued, due to lack of evidence of use.

PLEASE: if you are interested in further development of the xplasma
C interface, please contact the authors (email dmccune@pppl.gov).

The following is an edited description of the original C interface
for Version 1 xplasma f77-style subroutine calls:

All arguments for f77 xplasma (v1) routines were INTEGER, REAL*8,
or CHARACTER*(*).  C routines can use int* and double* to access
the INTEGER and REAL*8 arguments.

Generally, routines which have character arguments should have
explicit C interface routines provided, as well.  These routines 
will have names generated from the standard names by prepending
"C_".

  fortran routine     C callable routine

  eq_save             F77NAME(c_eq_save)
  eqm_msgs            F77NAME(c_eqm_msgs)

(where F77NAME is a macro provided in NTCC module FPREPROC to
"decorate" the names as needed to meet the requirements of the
current system's ld or binary loader software).

Where the standard fortran routines accept fortran CHARACTER
data, the c routine will take a null terminated byte string
instead.

NTCC "Portlib" module routines are used for converting C-strings
to fortran-strings.  The C_ interfaces were generated automatically
from standard xplasma sources, using tools from the ftoken module
in the NTCC modules library.  (These tools are not extensible to
the fortran-90 interfaces of XPLASMA v2).

Home Top


F77_Setup_Routines

(old f77 xplasma 1 documentation)

[This is the original xplasma 1.0 documentation].

The xplasma setup routines are used to load the plasma field
equilibrium and plasma parameters into the xplasma module, with
generation of spline or Hermite coefficients as needed for later
use by the Data Access Routines

(Note the subsections describe only the standard routines, although
the R4_ and C_ interfaces are also available).

Home Top


Error_Message_Control

By default, xplasma error messages are written to stdout via
FORTRAN i/o unit number 6.

To override this:

 ! input
      integer ilun_msgs       ! FORTRAN i/o unit number for messages
      character*(*) msg_file  ! file to receive messages
 ! output
      integer ierr            ! completion code, returned, 0=OK

      call eqm_msgs(ilun_msgs,msg_file,ierr)

...subroutine eqm_msgs tries to open `msg_file' on unit ilun_msgs,
if the `msg_file' character string is non-blank.  If it is blank,
the error message i/o unit number is still changed to ilun_msgs.

If a file open is attempted and fails, ierr.ne.0 is returned.

Home Top


xplasma_calls

(old f77 xplasma 1 documentation)

This module defines the fortran-77 xplasma calls only.

Included with "xplasma" is an "interface" module for fortran-90
code, which can be accessed by inserting the line

      use xplasma_calls

at the top of each fortran-90 subroutine that makes xplasma
subroutine calls.  This module does the following:

(1) allows generic names (e.g. eq_rgetf and eqm_frhochi) to be 
used for both REAL*8 and REAL(*4) codes.  Without the module,
REAL(*4) codes must call the R4 interface routines (e.g.
r4_eq_rgetf, r4_eqm_frhochi) by their full names.

(2) allows the compiler to check all subroutine arguments at
compile time.

The use of this module is optional.  There are situations where
functionally correct calls to xplasma routines will not survive
the compiler's argument check.

Home Top


Initialization

To delete the contents of xplasma, e.g. as a first step to
storing plasma parameters and equilibrium at a new time:

 ! input
      character*(*) model_string   ! name of equilibrium model
      integer ilaxi                ! axisymmetry flag (1 for TRUE).

      call eqm_select(model_string,ilaxi)

`model_string' contains a short string which may identify something
about the current or intended contents of xplasma.  This string is
used only as a prologue for certain messages.

Caution:  as of May 2000, ilaxi=1 is required.  Non-axisymmetry
is not yet supported in xplasma.

As xplasma is meant to contain a timeslice representing the current
plasma equilibrium and profiles, the user may choose to associate a 
time with the current contents of xplasma, by means of the call:

      real*8 ztime   ! physical time of xplasma data

      call eqm_time(ztime)

Home Top


Customizations

(old f77 xplasma 1 documentation)

The call to `eqm_select' sets default values for certain 
user adjustable model characteristics:

  (a) fit order for equilibrium representation
      {R(rho,chi),Z(rho,chi)}.  Default is iorder=2 (splines).
      However iorder=1 (Akima Hermite) is also allowed.

  (b) underlying Fourier representation-- highest order
      retained Fourier moments.  Default is 8; for some
      applications it may be desirable to reduce this.

Details:

Axisymmetric "xplasma", based on pspline [1], can use either
2nd order (piecewise bicubic spline) or 1st order (piecewise 
bicubic Hermite) interpolation functions to represent flux 
surface geometry {R(rho,chi),Z(rho,chi)}.  The default is
to use splines (iorder=2).  This produces a smoother output
for smooth input data, but for input data that is not smooth
there is a potential for "ringing", an oscillatory propagation
of a sharp feature in the input data.  By using Hermite
(iorder=1), such ringing can be suppressed at a cost to
overall smoothness.

      integer iorder    ! 2 for R,Z splines (default)
                        ! 1 for R,Z bicubic Hermite representation

      call eqm_rzordr_set(iorder)

Later, use the following call to determine what setting was chosen

      call eq_rzordr_get(iorder)

** This routine should be called right after eqm_select is
called.

[1]   https://w3.pppl.gov/NTCC/PSPLINE/pspline.html 

When "xplasma" is built from a psi(R,Z) representation (e.g. a
G-EQdsk file), part of the process involves a Fourier analysis
and recomposition.  By default, 8 moments are retained, but this
number can be changed by the call:

      kmom=5  ! retain moments 0:5 only in Fourier composition
      call xmoments_kmom_set(kmom)

In systems with known well behaved boundaries, the higher order
moments may not be needed and can be a source of "noise".

The call to "xmoments_kmom_set" will effect the results of 
subsequent calls to "xmoments_kmom_get" and "eqmom_Rcos" and
similar routines, after the xplasma setup is complete, as described 
in the subsection "Fourier Spline Representation" under the 
description of Data Access Routines.

Home Top


customized_initialization_example

 !  fit order for (R,Z) and B(rho,chi) components
      integer, parameter :: iordr_rz = 2 ! 2 for spline 1 for Hermite

 !  axisymmetry flag (axisymmetry required, ilaxi=1 REQUIRED).
      integer, parameter :: ilaxi = 1

 !  maximum retained Fourier Moments specification
      integer, parameter :: kmom = 5

      ...

      call eqm_select('your_xplasma',ilaxi)

      call eqm_rzordr_set(iorder_rz)

      call xmoments_kmom_set(kmom)

Home Top


Free_up_memory

(old f77 xplasma 1 documentation)

To erase xplasma contents and free up the memory used in the
xplasma module:

      call eqm_free

Home Top


Packages

(old f77 xplasma 1 documentation)

The full setup of an xplasma MHD equilibrium representation is
fairly complicated, involving as it does the requirement to 
define a large number of data items.

Common sources for equilibrium data are:  TRANSP runs in files
or MDS+, and EFIT (G-EQDSK) data in files or MDS+.

Canned routines, encapsulating the appropriate sequence of
xplasma "eqm" calls, are provided for the construction of xplasma
representations from these standard data sources.

Home Top


trxplib_module

      call trx_connect(...)   ! connect to a TRANSP run

      call trx_time(...)      ! set time of interest

      call trx_init_xplasma(...)  ! xplasma initialization

      call trx_mhd(...)       ! build xplasma from TRANSP MHD data

      call trx_wall_rz(...)   ! acquire limiter locations (optional)

      call trx_scal(...)      ! acquire any TRANSP scalar data item

      call trx_prof(...)      ! acquire any TRANSP profile data item

Xplasma "vacuum field extrapolation" software allows an environment
to be created in which full field information is available in (R,Z)
space or in magnetic coordinates.

Details are given in the documentation of the NTCC module "trxplib".

Home Top


eqm_fromgeqdsk

(old f77 xplasma 1 documentation)

Use this routine to acquire all xplasma MHD data from an EFIT G-EQDSK
file.  The software finds closed contours of psi(R,Z), equally spaced
in sqrt(toroidal flux), from which to construct the magnetic-coordinate
based equilibrium representation, at the same time preserving the (R,Z)
information: psi(R,Z), all components of B vs. (R,Z) as bicubic Hermite
interpolating functions.

To use this routine:

 ! identifying information
      character*30 label         ! xplasma label
      character*150 zfile        ! G-EQDSK file path or MDS+ path
                                 ! or "index file" expression...

 ! resolution of mag. coordinates representation
      integer ns                 ! abs(ns) = number of flux surfaces
      integer nth                ! number of theta grid points

 ! specify ns.lt.0 for Hermite instead of Spline fits of
 ! R(rho,chi),Z(rho,chi),BR(rho,chi),BZ(rho,chi),[mod(B)](rho,chi).

 ! Adjustment factor for psi(bdy)
      real*8 fbdy                ! psi(bdy(mag)) = fbdy*psi(bdy(efit))

 ! Alternate bdy adjustment option:  minimum curvature parameter
      real*8 cbdy                ! require curv(bdy)/a .gt. cbdy

 ! (R,Z) extension flag
      integer irz                ! =1: extend xplasma representation to
                                 ! cover EFIT's (R,Z) box; define
                                 ! psi(R,Z) & B(R,Z) as xplasma objects.
                                 ! =0: do not extend (less work).

 ! error status code returned
      integer ierr               ! returns 0 = OK

 ... ...

      call eqm_fromgeqdsk(label,zfile,ns,nth,fbdy,cbdy,irz,ierr)

The factor "fbdy" is allowed to vary between 0.95 and 1.00.  This may
be needed because some G-EQDSK data may give a psi(bdy) value which
corresponds to an open field line or the exact last closed flux
surface which has a shape that is kinked through a separatrix.  For
codes requiring a smooth boundary, fbdy = ~ 0.99 may be needed.
BUT: read on.

The factor "cbdy" gives a semi-automatic way to select a boundary
contour that is suitable.  The software will reject a boundary
contour if any of the following conditions arise:

  -- contour reverses direction or escapes (R,Z) box (open field line)
  -- minimum curvature divided by midplane minor radius is less than
     "cbdy".

The result is effective in preventing a "kinked" contour just inside
a separatrix, which might cause numerical problems for inverted
coordinate systems or equilibrium representations downstream.

The maximum allowed value of cbdy is 0.2; we recommend:

  fbdy = 1.000
  cbdy = 0.080

Home Top


Call examples:

  fbdy = 1.000
  cbdy = 0.080
  ns = 51
  nth = 76

  !  read from file "geqdsk.dat"; create xplasma "G-EQDSK-file"
  call eqm_fromgeqdsk('G-EQDSK-file','geqdsk.dat',ns,nth,fbdy,cbdy, &
       ierr)
  if(ierr.ne.0) then  ... [ process error ]

  !  or, read from MDSplus

  zfile = 'MDS+:EUROPA.PPPL.GOV:8501:EFIT01(103875;t=.25)'
  call eqm_fromgeqdsk('G-EQDSK-MDSplus',zfile,ns,nth,fbdy,cbdy,ierr)
  if(ierr.ne.0) then  ... [ process error ]

The string specification "zfile" contains the following components:

  MDS+[/NOREDUCE]:<server-name[:port]>:<tree-name>(<shot-no>;t=<time>)

Generally, each experiment supports an MDSplus server for its MDSplus
data; in the case of the NSTX experiment at PPPL, the server to use
is EUROPA.PPPL.GOV (port 8501).  The data is taken from tree "EFIT01",
NSTX shot 103875, at time t=0.25.  Because the option "/REDUCE" is set
by default, the eqm_fromgeqdsk call only caches the single time point
of EFIT data closest to 0.25 seconds; with "/NOREDUCE", it would cache
the entire time variation of the EFIT tree in memory, making subsequent
calls to eqm_fromgeqdsk on the same shot but at different times much 
faster, since a networked data access operation would be avoided.

Generally, collaborators need to obtain permission to read data from
MDSplus servers maintained by tokamak experiments, and, the user should
consult with responsible scientists about the suitability of selected
data.

Note that if <server-name> is given as "LOCAL" or "CONNECTED", then,
the eqm_fromgeqdsk call does not attempt to connect to and later
disconnect from the MDSplus server.  This is desirable e.g. if the
calling code is taking care of MDSplus server connect/disconnect
operations.

Note that if <tree-name> is given as "OPENED", then, eqm_fromgeqdsk
does not attempt to open and later close the EFIT MDS+ tree.  This
is desirable if the calling code is taking care of the MDS+ tree 
open and close operations.

Home Top


More_MDSplus_access_info

eqm_fromgeqdsk can be used to access G-EQDSK data over the net
from an MDSplus server.  To do this, one simply uses an MDSplus
path instead of a file path in the subroutine's "zfile" argument.

Here are comments from the code on this subject:

c
c  zfile - a file path, e.g. /u/efit/nstx/g123456_6800.eqdsk
c               --or--
c          an MDSplus path:
c
c    MDS+[/reduce|/noreduce]:<server[:port]|LOCAL>:<tree>(<shot>;t=<time>)
c
c    where the initial MDS+ specifies MDSplus not a file;
c
c    /reduce means just read the specified timeslice (this is the default)
c    /noreduce means read and cache data from all available EFIT times
c
c    <server...> specifies the MDSplus server, can be "LOCAL"
c
c    <tree> specifies the MDSplus tree, e.g. "EFIT01" or "EFIT02"
c
c    <shot> specifies the MDSplus (or experiment) shot number
c    <time> is an ascii encoding of the currently desired time of interest
c
c       examples of valid MDSplus paths:
c
c       MDS+:LOCAL:EFIT01(104370;t=0.15)
c       MDS+/reduce:europa.pppl.gov:8501:EFIT01(104370;t=1.0e-1)
c       MDS+/noreduce:cmoda.psfc.mit.edu:EFIT09(123456789;t=2.3)
c

The /reduce option (default) is recommended for codes which are really
only going to look at one timepoint.

For a code that is going to loop over time, the /noreduce option allows
all the data to be read in and cached, obviating the need for repeated
connections to the remote MDSplus server.

Note: option names, server names and tree-names are case-insensitive.
Thus for example, "/reduce" and "/REDUCE" have the same effect.  Also,
the time keyword after the shot number can be "t", "T", "time" or "TIME"
or "TiMe" or any combination which when mapped to uppercase yields "T"
or "TIME".

Home Top


EFIT_INDEX_files

In order to support access to time dependent EFIT datasets without
having to use MDS+, an alternative file-based access scheme is 
supported: access indirectly via an "EFIT_INDEX" file.  This is a 
file that correlates G-eqdsk filenames with physical times in 
seconds.  For example:

[tshare@dhcp-dmccune scrunch2]$ cat 8500index.txt 
ntimes=4
path='/pub/outgoing/pshare'
time=0.15   filename=g008500.00150
time=0.20   filename=g008500.00200
time=0.25   filename=g008500.00250
time=0.294  filename=g008500.00294

G-eqdsk files can be referred to directly by filename, or, indirectly
via an index file.  Thus in the above example, the same result would
follow from an eqm_fromgeqdsk call with argument

  zfile = "g008500.00294"

or with

  zfile = "EFIT_INDEX:8500index.txt( 4)"

(blanks are allowed between the parentheses in which the time index is
given).  Note that the "path" field is ignored; the g-eqdsk files are
expected to be found in the same directory in which the index file itself
is found.

This provides a mechanism for correlating files in g-eqdsk file collections
with specific times, without having to parse time information out of the
filename, a procedure which tends to be different at each EFIT user site.

Home Top


eqm_wr_geqdsk

(old f77 xplasma 1 documentation)

If EFIT data is acquired via MDSplus, then there is an option to 
write a local G-EQDSK file from the MDSplus data:

      character*(*) file_out    ! name of file to write
      integer ier               ! completion code returned, 0=OK

      call eqm_wr_geqdsk(file_out,ier)

This provides a mechanism for generating G-EQDSK files from remote
MDSplus trees.  The data is as acquired from the MDSplus tree, i.e.
not modified by xplasma.

There is another routine eq_geqdsk, which can generate and write a 
G-EQDSK file from any XPLASMA equilibrium, howsoever obtained.  But
this method involves interpolation and so is less accurate than
using eqm_wr_geqdsk if the purpose at hand is to write an MDSplus
time slice to disk.

Home Top


Flux_Coordinate_Grids

(old f77 xplasma 1 documentation)

The radial flux coordinate is designated as "rho" in xplasma
documentation.

The poloidal angle flux coordinate is designated as "chi" in
xplasma documentation.

Before any spline, Hermite, or piecewise linear f(rho) can be defined,
rho itself must be given; before any bicubic spline, Hermite, or 
bilinear f(chi,rho) can be defined, both rho and chi must be given.

The "rho" coordinate grid is to be surface oriented, covering
the entire plasma from magnetic axis to numeric boundary near
the last closed flux surface.  

The "chi" coordinate is periodic with period 2pi, i.e. 
chi(nchi)-chi(1)=2pi.  Usually the coordinate as given spans
[0,2pi] or [-pi,pi].

All grids x must be strict ascending, i.e. x(j).gt.x(j-1).
Even spacing is not required.

Once the "basic" rho, chi grids are defined, alternate
rho, chi grids can also be given.  This gives a foundation
for support, within "xplasma", of objects with different 
radial and/or angular resolution.

Home Top


Radial_Flux_Coordinate(rho)

(old f77 xplasma 1 documentation)

The following call sets the grid for the radial flux coordinate.
It is recommended to use the following flux coordinate:

  normalized sqrt(toroidal flux), 
    range 0 to 1

The problem with using a flux coordinate psi directly, is that
grad(psi) -> 0 on axis, which means, for any f such that
grad(f) does NOT -> 0 on axis, df/dpsi -> +/-infinity on axis;
this singularity leads to numerical problems e.g. "ringing" in 
spline interpolation.

 ! input
      integer nsurf           ! no. of flux surfaces, including axis
      real*8 zrho(nsurf)      ! flux coordinate, strict ascending
      real*8 ztol             ! d(zrho) variance tolerance

 ! ztol -- if the deviation of actual rho grid spacing varies
 !         from the average spacing by less than ztol, then, the
 !         grid is deemed evenly spaced.
 !         ...average spacing is (zrho(nsurf)-zrho(1))/(nsurf-1)
 !         ...actual spacing is (zrho(j+1)-zrho(j)) 
 !            with j in {1,2,...,(nsurf-1)}

 ! output
      integer id_rho          ! xplasma id code for rho grid
      integer ierr            ! completion code, 0=OK

      ...

      call eqm_rho(zrho,nsurf,ztol,id_rho,ierr)

Home Top


Poloidal_Angle_Coordinate(chi)

(old f77 xplasma 1 documentation)

The following call sets up the grid for the poloidal angle
coordinate.  Note that the grid array is either input or output,
depending how the automatic generation switch is set.

The xplasma software makes no restriction about the type of 
poloidal angle coordinate-- "Hamada", "Boozer", "Vmec", all
are acceptable.  However, for a plasma poloidal cross section
to the right of the axis of symmetry, an increasing poloidal
angle parameter is expected to describe the flux surface going
around in a counterclockwise direction, and, chi=0.0 is by
convention associated with the large major radius side of the
plasma.  The first and last points in the chi grid must differ
by exactly 2pi.  Typically the given grid covers the range
[0,2pi] or [-pi,+pi].

 ! input
      integer inum_chi         ! no. of chi grid points
      integer iauto            ! =1 to generate automatic chi grid
      real*8 ztol              ! d(zchi) variance tolerance

 ! ztol -- if the deviation of actual chi grid spacing varies
 !         from the average spacing by less than ztol, then, the
 !         grid is deemed evenly spaced.  If iauto=1, ztol is
 !         ignored; the iauto=1 grid is always evenly spaced.

 ! input/output
      real*8 zchi(inum_chi)    ! chi grid, output if iauto=1

 ! output
      integer id_chi           ! xplasma id code for chi grid
      integer ierr             ! completion code, 0=OK

      ...

      call eqm_chi(zchi,iauto,inum_chi,ztol,id_chi,ierr)

Although the poloidal angle grid is always stored internally with the
counter-clockwise orientation, clockwise grids can be provided as input
using this call:

      call eqm_chi_setccw(-1,zchi,iauto,inum_chi,ztol,id_chi,ierr)

The grid orientation will then be reversed prior to storage.

Note however that XPLASMA does not "remember" that a clockwise oriented
grid was provided as input.  Subsequent calls involving objects defined
over a clockwise grid must indicate this explicitly each time.  In the
XPLASMA f77 interface this is done by specifying a negative value for
an array size, as documented on a routine-by-routine basis below.  In 
the f90 interface, this is indicated by setting a flag in an optional
argument.

Home Top


Alternate_grids

(old f77 xplasma 1 documentation)

Once the basic "rho" and "chi" coordinate grids have been established,
or indeed once any coordinate grid is established, the user can define
alternate grids for these same coordinates.  An alternate grid has the
following properties:

  * strict ascending sequence
  * spans exactly the same range as the original grid
  * need not contain the same number of grid points.

Thus, for example, if zrho(1:nsurf) is the real*8 array of values
used to define "rho" in a call to eqm_rho, zrho2(1:nsurf2) can be
a regridding of zrho(1:nsurf) if zrho2(j).lt.zrho(j+1) for j = 1
to nsurf2-1, and, zrho(1)=zrho2(1), and, zrho(nsurf)=zrho2(nsurf2).

To establish an alternate grid, use subroutine `eqm_uaxis':

 ! input:
      character*(*) aname    ! name for alt. grid, not "RHO" or "CHI"
      integer id_orig        ! id of original grid
                             ! for which new grid is an alternate,
                             ! or, zero if this is a new "user grid".

      integer iper           ! =1 if this is a periodic dimension,
                             !  0 if not periodic
                             ! -1 if periodic with clockwise orientation

      integer inum           ! #of points in alternate grid
      real*8 zaxis(inum)     ! the alternate grid points
      real*8 ztol            ! even spacing tolerance
 !
 ! output:
      integer id             ! xplasma id code for this new grid
      integer ierr           ! completion code, 0=OK
         ...
      call eqm_uaxis(aname,id_orig,iper,zaxis,inum,ztol,id,ierr)

 ! notes:
 !   * aname should be unique & specific, i.e. not "RHO" or "CHI" 
 !     or "R" or "Z".  NAMES ARE CASE INSENSITIVE.
 !   * iper=1 should be set for angle-type coordinate grids
 !   * id_orig should be the value returned from eqm_rho or eqm_chi
 !     or eqm_rzgrid.
 !   * inum.ge.4 is required.
 !   * zaxis must be strict ascending and its endpoints must match
 !     the endpoints of the "id_orig" axis.
 !   * ztol sets a tolerance for endpoint matching and also for 
 !     determining if this grid is evenly spaced:  if 
 !       dzavg = (zaxis(inum)-zaxis(1))/(inum-1), and, 
 !       maxval(abs(zaxis(2:inum)-zaxis(1:inum-1)-dzavg)).lt.ztol
 !     then the grid is declared evenly spaced, and the faster
 !     even spacing algorithm can be used for zone lookup during
 !     interpolation.
Home Top


Mod(B)_grid

(old f77 xplasma 1 documentation)

A grid of ascending mod(B) values can be defined.  This might be
used e.g. to gather data binned by field strength.  If this is
needed, use the following...

 ! input:
      integer inum              ! #of mod(B) grid points wanted
      integer iauto             ! =1 for automatic grid generation

 ! input or output:
      real*8 zbb(inum)          ! mod(B) grid, input if iauto=0
                                ! output if iauto=1

 ! input:
      real*8 ztol               ! even spacing tolerance

 ! output:
      integer id_Bgrid          ! xplasma axis id for mod(B) grid

 ! output:
      integer ierr              ! completion status code, 0=OK

         ...

      call eqm_bbin(zbb,iauto,inum,ztol,id_Bgrid,ierr)

 ! note:  if the variance of delta(zbb) = zbb(j+1)-zb(j) from
 !        <delta(zbb)> = (zbb(inum)-zbb(1))/(inum-1) is .lt. ztol,
 !        then the grid is considered evenly spaced, allowing use
 !        of a faster lookup algorithm

Home Top


User_grids

(old f77 xplasma 1 documentation)

The eqm_uaxis routine can also be used to establish an arbitrary
"user grid", i.e. an ascending sequence of numbers spanning some
specified range.  For example, an energy grid, pitch angle grid,
or mod(B) grid might be defined.

To establish a user grid, use eqm_uaxis (cf Alternate_grids section),
but set id_orig=0 to indicate a new grid type unrelated to grids
previously defined.

Data Access routines are provided for efficient binning into user
defined axis grids.

Home Top


Summary

(old f77 xplasma 1 documentation)

 ! set up rho grid
      subroutine eqm_rho(zrho,nsurf,ztol,id_rho,ierr)
      
 ! set up chi grid
      subroutine eqm_chi(zchi,iauto,inum_chi,ztol,id_chi,ierr)

 ! set up alternate grid (axis)
      subroutine eqm_uaxis('grid-name',id_orig,iper,zaxis,inum,ztol,
     >                     id,ierr)

Home Top


function_definitions

(old f77 xplasma 1 documentation)

The following item types can be defined:

  f(rho)     e.g. psi(rho),q(rho),Te(rho), ...

  f(rho,chi) e.g. R(rho,chi), Z(rho,chi)

  f(R,Z)     e.g. Te(R,Z):  Te(rho) mapped and extrapolated into the 
             scrape-off layer.

Generally, data for items can be "updated" by calling the function
set-up routine with    iorder=99    set.  However, R(rho,chi) and
Z(rho,chi) cannot be updated in this manner -- xplasma must be
re-initialized if the flux surface geometry is to change.

Caution:  xplasma generally cannot enforce consistency of data
items just because one is updated.  If "G" or "PSI" are updated,
then B(rho,chi) will be updated as well.  However, an update of
B(R,Z) would require a separate call by the user.

Although there are some situations where updates of profiles in
the context of a fixed geometry might be useful, such methods
should be used with care.  More typically, as plasma profiles
change the flux surface geometry also changes; in this case, 
xplasma must be re-initialized and reconstructed from scratch
for each new timeslice.

Home Top


_1d_Profiles_f(rho)_etc

(old f77 xplasma 1 documentation)

Home Top


eqm_rhofun

(old f77 xplasma 1 documentation)

A special routine is provided for setting up a profile function f(rho).
This profile can be a piecewise cubic spline, piecewise cubic Hermite,
or piecewise linear.  Thus:

 ! input:
      integer iorder         ! "order" of interpolating function
      integer id_rho         ! rho coordinate grid id (orig. or alt.)
      character*(*) fname    ! unique name of profile function
      real*8 zdata(*)        ! the function data (#pts: id_rho axis)
      integer ibc1           ! boundary condition code, at rho(1)
      real*8 zbc1            ! boundary condition data, at rho(1)
      integer ibc2           ! boundary condition code, at rho(nrho)
      real*8 zbc2            ! boundary condition data, at rho(nrho)
 ! output:
      integer id_rhofun      ! unique xplasma id for this function
      integer ierr           ! completion code, 0=OK
         ...
      call eqm_rhofun(iorder,id_rho,fname,zdata,
     >                ibc1,zbc1,
     >                ibc2,zbc2,
     >                id_rhofun,ierr)
      if(ierr.ne.0) then
         [...handle error...]
      endif

 ! notes:
 ! * the amount of data expected in zdata(...) depends on the selected
 !   axis (id_rho) and the interpolation order (iorder).  Let nrho=
 !   the number of data points in the "id_rho" grid.  Then,
 !
 !   => iorder =  0 ... piecewise linear function, zdata(1:nrho)
 !                      must be defined;
 !   => iorder =  1 ... piecewise cubic Hermite fcn, zdata(1:nrho)
 !                      must be defined, Akima Hermite is used;
 !   => iorder =  2 ... piecewise spline function, zdata(1:nrho)
 !                      must be defined;
 !   for iorder.ge.0, the interpolating function f(rho) will satisfy 
 !   f(rho(i))=zdata(i) for i=1:nrho.
 !
 !   note:  set iorder = 99 to update data for an already defined
 !     item.  The original interpolation method is retained and
 !     the axis id must match.
 !
 ! * the name 'fname' must uniquely identify the function.  The
 !   names "R","Z","RHO,"CHI","G","PSI", "BR", "BZ", "BPHI" and
 !   "BMOD"  are reserved to xplasma.  NAMES ARE CASE INSENSITIVE.
 !
 ! * boundary conditions -- ignored if iorder.le.0
 !   ibc1,zbc1 -- controls at rho(1), i.e. the "magnetic axis"
 !   ibc2,zbc2 -- controls at rho(nrho), i.e. the "plasma bdy".
 !   options:
 !     ibc1|2 = 0 -- "not a knot" or default at axis | bdy
 !     ibc1|2 = 1 -- zbc1|2 contains df/drho at the axis | bdy
 !     ibc1|2 = 2 -- splines only -- zbc1|2 contains d2f/drho2 at
 !                   the axis | bdy.
 !
 ! * id_rhofun -- on normal exit (ierr.eq.0), id_rhofun contains the
 !   xplasma index to the interpolating function.  This may be worth 
 !   saving for efficient access to the interpolating function.

Home Top


eqm_irhofun

(old f77 xplasma 1 documentation)

This subroutine creates a lightly smoothed interpolating profile for
an "integrated profile" function defined over a grid of the caller's
choosing.

An example of such a function would be:

   P_NBI(x) = Integrated NBI power, watts, from the plasma magnetic
             axis to flux surface "x".

The input gives a grid identification, the data, i.e. the integrated value
to each point on the grid, and the name to be used for identifying the
function.  The output is an identifier for the interpolating function.

The control "iflag" is 1 for volume integrated density profiles; 2 for
area integrated density profiles such as current drive profiles.

subroutine eqm_irhofun(id_axis,zlbl,inprof,zprof,iflag,id,ierr)

  !  make XPLASMA profile -- integrated quantity; smooth by 1/2 zone width
  !  to insure smooth derivative from spline

  implicit NONE
  integer, intent(in) :: id_axis    ! axis id -- must be rho or akin to rho
  character*(*), intent(in) :: zlbl ! name for profile function to be created
  integer, intent(in) :: inprof     ! size of the integrated data profile
  real*8, intent(in) :: zprof(inprof) ! the integrated data provided
                         ! if inprof = size(x_axis) zprof(1)=0 is expected
                         ! if inprof = size(x_axis)-1 the axial data point
                         !    is presumed to be omitted.
  integer, intent(in) :: iflag      ! =1 -- volume normalization;
                         ! derivative evaluations -> W/m^3, #/sec/m^3, etc.
                                    ! =2 -- area normalization;
                         ! derivative evaluations -> A/m^2 (current density).

  integer, intent(out) :: id        ! id of stored profile (if successful)
  integer, intent(out) :: ierr      ! completion code, 0=OK.

  !  if an error occurs and ierr is set, id=0 will be returned.


Home Top


Required_1d_Magnetic_Profiles

(old f77 xplasma 1 documentation)

In order for (axisymmetric) xplasma to form a complete 
specification of the magnetic field, two 2d profile functions
must be provided:

    g -- name must be "g" or "G" -- g(rho) is the toroidal field 
         in the form R*Btor.  MKS units would be Tesla*m.  Units
         given must be consistent with other data given to xplasma.

   psi-- name must be "psi" or "PSI" -- poloidal flux function
         psi(rho) -- 1/(2*pi) * area integral of poloidal field
         through flux zones.  MKS units would be Webers/radian.
         Units given must be consistent with other data given to
         xplasma.

The field specification will be completed by giving the flux surface
geometry R(chi,rho) and Z(chi,rho).  Then,

  Btor(chi,rho) = g(rho)/R(chi,rho)
  Bpol(chi,rho) = grad(psi(rho))/R(chi,rho)
                = [d(psi)/d(rho)]*grad(rho)/R(chi,rho)

-------------
use eqm_rhofun to set up the g and psi profiles in xplasma.

Home Top


eqm_mark_pmhd

(old f77 xplasma 1 documentation)

Another profile associated with MHD equilibrium is the plasma pressure.
There are some variations as to how this may be defined, and the name
for the pressure profile within xplasma is not standardized.  However,
a specific profile can be "tagged" as "the" MHD equilibrium pressure 
profile by calling this routine:

  integer :: id_p   ! MHD pressure profile id (1d profile f(rho)) (input)
  integer :: ier    ! status code returned (0=normal) (output)

  call eqm_mark_pmhd(id_p,ier)

Home Top


eqm_f1d

(old f77 xplasma 1 documentation)

This routine is provided for setting up a general 1d profile function f(x);
x is a user defined axis with a presumption of no particular relationship
to magnetic or cylindric coordinates.  This profile can be a piecewise 
cubic spline, piecewise cubic Hermite, or piecewise linear.  Thus:

 ! input:
      integer iorder         ! "order" of interpolating function
      integer id_axis        ! user specified x axis
      character*(*) fname    ! unique name of profile function
      real*8 zdata(*)        ! the function data (#pts: id_rho axis)
      integer ibc1           ! boundary condition code, at rho(1)
      real*8 zbc1            ! boundary condition data, at rho(1)
      integer ibc2           ! boundary condition code, at rho(nrho)
      real*8 zbc2            ! boundary condition data, at rho(nrho)
 ! output:
      integer id_f1d         ! unique xplasma id for this function
      integer ierr           ! completion code, 0=OK
         ...
      call eqm_f1d(iorder,id_axis,fname,zdata,
     >                ibc1,zbc1,
     >                ibc2,zbc2,
     >                id_f1d,ierr)
      if(ierr.ne.0) then
         [...handle error...]
      endif

These arguments are a 1-to-1 analog to the arguments of eqm_rhofun.
The notes to the description of arguments for that routine apply here
as well.

Home Top


Summary

(old f77 xplasma 1 documentation)

To set up a profile f(rho)...

      call eqm_rhofun(iorder,id_rho,'f-name',zdata,
     >                ibc1,zbc1,ibc2,zbc2,
     >                id_rhofun,ierr)
      if(ierr.ne.0) then
         [...handle the error...]
      endif

The "G" and "PSI" profiles are required, if xplasma is to generate
a continuous differentiable field representation.

To set up a profile f(x), for a user defined x axis...

      call eqm_f1d(iorder,id_axis,'f-name',zdata,
     >                ibc1,zbc1,ibc2,zbc2,
     >                id_f1d,ierr)
      if(ierr.ne.0) then
         [...handle the error...]
      endif

Home Top


_2d_Profiles_f(chi,rho)

(old f77 xplasma 1 documentation)

This section discusses methods for defining 2d profile functions
f(chi,rho).  To have an (axisymmetric) equilibrium, at least
R(chi,rho) and Z(chi,rho) must be defined.

R(chi,rho) and Z(chi,rho) must be defined before any other 
f(chi,rho), and one of the special purpose routines (eqm_rzmag,
eqm_rzmagb, eqm_rzmag2) must be used for this.

Once R and Z are defined, additional functions f(chi,rho) can
be defined using eqm_frhochi.
Home Top


eqm_rzmag

(old f77 xplasma 1 documentation)

 !
 !  establish R(chi,rho) and Z(chi,rho) bicubic splines.
 !  periodic in chi, not-a-knot BC @ rho bdys
 !    (for more control of rho BCs use eqm_rzmagb)
 !
 !  ***note the R & Z arrays must be defined on the same grids as
 !     were specified by earlier eqm_rho and eqm_chi calls.
 !
 !  input arguments:
 !
   integer id1,id2        ! R,Z array dimensions
   real*8 Rarr(id1,id2)   ! R array - (1:nchi)x(1:nrho) points used
   real*8 Zarr(id1,id2)   ! Z array - (1:nchi)x(1:nrho) points used
 !
   integer idrho          ! =1:  id1 is "rho" dimension; =2: id2 is.
 !
 !  if idrho.eq.1, id1.ge.nrho & id2.ge.nchi 
 !                 R(1:nrho,1:nchi) & Z(1:nrho,1:nchi) are used
 !  if idrho.eq.2, id1.ge.nchi & id2.ge.nrho
 !                 R(1:nchi,1:nrho) & Z(1:nchi,1:nrho) are used
 !
 !  output arguments:
 !
   integer id_R           ! xplasma id for "R" bicubic spline (returned)
   integer id_Z           ! xplasma id for "Z" bicubic spline (returned)
 !
   integer ierr           ! completion code (0 = OK)
 !

    ....

   call eqm_rzmag(Rarr,Zarr,id1,id2,idrho, id_R,id_Z,ierr)

Home Top


eqm_rzmagb

(old f77 xplasma 1 documentation)

 !
 !  establish R(chi,rho) and Z(chi,rho) bicubic splines.
 !  periodic in chi, not-a-knot BC @ rho bdys
 !    use the BC controls to specify the boundary conditions at
 !    rho(1) (mag. axis) and rho(nrho) (plasma boundary); there
 !    are separate BC controls for R and for Z.
 !
 !  ***note the R & Z arrays must be defined on the same grids as
 !     were specified by earlier eqm_rho and eqm_chi calls.
 !
 !  input arguments:
 !
   integer id1,id2        ! R,Z array dimensions
   real*8 Rarr(id1,id2)   ! R array - (1:nchi)x(1:nrho) points used
   real*8 Zarr(id1,id2)   ! Z array - (1:nchi)x(1:nrho) points used
 !
   integer idrho          ! =1:  id1 is "rho" dimension; =2: id2 is.
 !
 !  if idrho.eq.1, id1.ge.nrho & id2.ge.nchi 
 !                 R(1:nrho,1:nchi) & Z(1:nrho,1:nchi) are used
 !  if idrho.eq.2, id1.ge.nchi & id2.ge.nrho
 !                 R(1:nchi,1:nrho) & Z(1:nchi,1:nrho) are used
 !
 !  ** boundary conditions **
 !
 !  BC controls are as in "pspline": 0 -- default, 1 -- fix df/drho
 !                                   2 -- fix d2f/drho2  ...f is R or Z
 !
 !  for BC types 1 & 2, data must be supplied:  nchi 1st or 2nd 
 !  derivative values, repsectively;  for other types the "zbc" 
 !  arrays are ignored.
 !
  integer ibcR0           ! R BC type @ rho(1)
  real*8 zbcR0(*)         ! R BC data @ rho(1) (if needed)
  integer ibcR1           ! R BC type @ rho(nrho)
  real*8 zbcR1(*)         ! R BC data @ rho(nrho) (if needed)
 !
  integer ibcZ0           ! Z BC type @ rho(1)
  real*8 zbcZ0(*)         ! Z BC data @ rho(1) (if needed)
  integer ibcZ1           ! Z BC type @ rho(nrho)
  real*8 zbcZ1(*)         ! Z BC data @ rho(nrho) (if needed)
 !
 !  output arguments:
 !
   integer id_R           ! xplasma id for "R" bicubic spline (returned)
   integer id_Z           ! xplasma id for "Z" bicubic spline (returned)
 !
   integer ierr           ! completion code (0 = OK)
 !

    ....

   call eqm_rzmagb(Rarr,Zarr,id1,id2,idrho,  &
  &               ibcR0,zbcR0,ibcR1,zbcR1,  &
  &               ibcZ0,zbcZ0,ibcZ1,zbcZ1,  &
  &               id_R,id_Z,ierr)

Home Top


eqm_rzmag2

(old f77 xplasma 1 documentation)

This routine sets up R(chi,rho) and Z(chi,rho) from a user supplied
mapping subroutine rzmapper:(rho,chi) -> (R,Z).  R and Z are defined
as bicubic splines.  `rzmapper' is the name of the mapping subroutine
as given in the documentation and source code comments, but of course
the actual programmer can choose any name.

In detail:

The user will supply a subroutine with the following interface:

      subroutine rzmapper(rho,chi,R,Z,ierr)
      real*8 rho,chi               ! magnetic coordinates (in)
      real*8 R,Z                   ! cylindric coordinates (out)
      integer ierr                 ! completion code, 0=OK
         ...
         [compute (R,Z) from (rho,chi)...]
         ...
      end

And then call eqm_rzmag2 to create the bicubic splines (with "not
a knot" rho boundary conditions) for R,Z:

 ! input:
      external rzmapper            ! mapping routine

 ! output:
      integer id_R                 ! xplasma index to R spline
      integer id_Z                 ! xplasma index to Z spline
      integer ierr                 ! completion code, 0=OK

          ...

      call eqm_rzmag2(rzmapper,id_R,id_Z,ierr)

          ...

Note that the rho and chi grids used to drive rzmapper have to
have already been defined by prior calls to eqm_rho and eqm_chi.
These axes determine the size of the bicubic spline "objects"
created.

Home Top


technical_note

(old f77 xplasma 1 documentation)

The eqm_rzmag* routines test the orientation of the chi parameter.
The xplasma internal representation is standardized on a "counter-
clockwise" increasing poloidal angle parameter.  If the R and Z
data imply the reverse orientation, the data is "reversed" so that
a counter-clockwise internal representation is used.

To reference data with respect to the original, clockwise oriented
poloidal angle coordinate, use appropriate "ccwflag" optional logical
arguments (fortran-90 interface) or set vector lengths to negative
values (fortran-77 interface).

Xplasma does not "remember" the orientation of the original R & Z
flux surface data.

Home Top


eqm_frhochi

(old f77 xplasma 1 documentation)

A special routine is provided for setting up a 2d profile function 
f(chi,rho).  This profile can be a piecewise bicubic spline, 
piecewise bicubic Hermite (Akima), or piecewise bilinear.  Thus:

 ! input:
      integer iorder         ! "order" of interpolating function
      integer id_axis1       ! rho or chi coordinate grid id
      integer id_axis2       ! chi or rho coordinate grid id
 !       these axes determine the size and layout requirements for 
 !       zdata(:,:)
      character*(*) fname    ! unique name of profile function
 !
      integer idim1          ! size of 1st dimension of zdata
      real*8 zdata(idim1,*)  ! the function data
 !
      integer ibcrho0        ! boundary condition code, at rho(1)
      real*8 zbcrho0(*)      ! boundary condition data, at rho(1)
      integer ibcrho1        ! boundary condition code, at rho(nrho)
      real*8 zbcrho1(*)      ! boundary condition data, at rho(nrho)

 ! output:
      integer id_fun         ! unique xplasma id for this new function
      integer ierr           ! completion code, 0=OK
         ...
      call eqm_frhochi(iorder,id_axis1,id_axis2,fname,
     >                 zdata,idim1,
     >                 ibc1,zbc1,
     >                 ibc2,zbc2,
     >                 id_fun,ierr)
      if(ierr.ne.0) then
         [...handle error...]
      endif

 ! notes:
 ! * the amount and ordering of data expected in zdata(...) depends 
 !   on the selected axes (id_axis1, id_axis2), and the interpolation 
 !   order (iorder).  Let nrho = the number of data points in the 
 !   "id_rho" grid; let nchi = the number of data points in the chi
 !   grid.  Let's suppose id_axis1.eq.id_rho & id_axis2.eq.id_chi.
 !   then:
 !
 !   => iorder =  0 ... piecewise bilinear interpolating function;
 !                      zdata(1:nrho,1:nchi) or zdata(1:nchi,1:nrho)
 !                      according as id_axis1 and id_axis2 are set.
 !   => iorder =  1 ... piecewise bicubic Akima Hermite function; 
 !                      zdata(1:nrho,1:nchi) or zdata(1:nchi,1:nrho)
 !                      according as id_axis1 and id_axis2 are set.
 !   => iorder =  2 ... piecewise bicubic spline function vs. chi,rho.
 !                      zdata(1:nrho,1:nchi) or zdata(1:nchi,1:nrho)
 !                      according as id_axis1 and id_axis2 are set.
 !
 !   for iorder.ge.0, the interpolating function f(rho) will satisfy 
 !   f(rho(i),chi(j))=zdata(i,j) for i=1:nrho, j=1:nchi.
 !
 !   note:  set iorder = 99 to update data for an already defined
 !     item.  The original interpolation method is retained and
 !     the axis ids must match.  ** "R" and "Z" cannot be updated
 !     by this method.
 !
 ! * the name 'fname' must uniquely identify the function.  The
 !   names "R","Z","RHO,"CHI","G","PSI", "BR", "BZ", "BPHI" and
 !   "BMOD"  are reserved to xplasma.  NAMES ARE CASE INSENSITIVE.
 !
 ! * the double data array zdata(idim1,*) has a first dimension idim1;
 !   idim1 must be .ge.nrho, or, .ge.nchi, depending on how
 !   id_axis1 and id_axis2 are set.
 !
 ! * boundary conditions -- ignored if iorder.le.0
 !   ibc1,zbc1(*) -- controls at rho(1), i.e. the "magnetic axis"
 !   ibc2,zbc2(*) -- controls at rho(nrho), i.e. the "plasma bdy".
 !   options:
 !     ibc1|2 = 0 -- "not a knot" or default at axis | bdy; zbc1|2 
 !                   ignored.
 !     ibc1|2 = 1 -- zbc1|2 contains df/drho vs. chi at the axis|bdy
 !     ibc1|2 = 2 -- splines only -- zbc1|2 contains d2f/drho2 vs. chi
 !                   at the axis|bdy.
 !
 ! * id_fun -- on normal exit (ierr.eq.0), id_fun contains the
 !   xplasma index to the interpolating function.  This may be worth 
 !   saving for efficient access to the interpolating function.
 !
 ! * after the subroutine returns, the value of ierr should be
 !   examined and appropriate action taken if an error is
 !   indicated.

Home Top


poloidal_angle_orientation

(old f77 xplasma 1 documentation)

Input profiles to eqm_frhochi are assumed to be defined w.r.t. a
standard counter-clockwise oriented poloidal angle coordinate.  If
this is not the case, there is an alternate call that may be used
to indicate a profile defined over a clockwise oriented poloidal
angle coordinate:

      iccw=0

      call eqm_frhochi_ccw(iccw,
     >                 iorder,id_axis1,id_axis2,fname,
     >                 zdata,idim1,
     >                 ibc1,zbc1,
     >                 ibc2,zbc2,
     >                 id_fun,ierr)
      if(ierr.ne.0) then
         [...handle error...]
      endif

Except for "iccw" the arguments are the same as for eqm_frhochi above.

Home Top


summary

(old f77 xplasma 1 documentation)

The profiles R(chi,rho) and Z(chi,rho) must be provided in order
to give the flux surface geometry.

Use one of the special purpose routines eqm_rzmag, eqm_rzmagb, or
eqm_rzmag2 to define R and Z.  Then, use eqm_frhochi to define
additional functions f(chi,rho).

The general purpose routine eqm_frhochi for constructing f(chi,rho) 
2d profiles may be used, or, the special purpose routine eqm_rzmag2
might be used as a more convenient alternative.

To set up R(chi,rho) and Z(chi,rho) from user supplied data arrays
using default "not a knot" spline boundary conditions:

To set up R(chi,rho) and Z(chi,rho) from user supplied data arrays
with full control of boundary conditions at the rho extrema:

To set up R(chi,rho) and Z(chi,rho) splines from a user supplied
subroutine:

      subroutine eqm_rzmag2(rzmapper,id_R,id_Z,ierr)
      !                     in       out  out  out

      ...where rzmapper stands for a user supplied routine with
      the interface

      subroutine rzmapper(rho,chi,R,Z,ierr)
      real*8 rho,chi          ! magnetic coordinates (in)
      real*8 R,Z              ! cylindric coordinates (out)
      integer ierr            ! completion code (out) 0=OK

To set up any function f(chi,rho):

      subroutine eqm_frhochi(iorder,id_axis1,id_axis2,'fname',
     >                       zdata,idim_1,
     >                       ibcrho0,zbcrho0,ibcrho1,zbcrho1,
     >                       id_fun,ierr)

where the first dimension of zdata(idim_1,*) is rho or chi (as 
specified by id_axis1), and the 2nd dimension is chi or rho (as 
specified by id_axis2).  The fit order is controlled by "iorder" 
but is forced to be a bicubic spline if the data is named "R" or 
"Z".  Boundary condition controls specify treatment of the data
at rho(1) and rho(nrho).  After the interpolating function is
successfully set up, the xplasma identifer is returned as id_fun.

Home Top


B(chi,rho)

(old f77 xplasma 1 documentation)

(for axisymmetric tokamak equilibria...)

To compute the magnetic field in the region mapped by magnetic
coordinates, the following quantities need to be defined:

 -> 1d profiles:  g(rho), psi(rho)  (...see _1d_Profiles_f(rho)...)
 -> 2d profiles:  R(chi,rho), Z(chi,rho)  (...see _2d_profiles...)
 -> sign factors:  given

      integer isnccwb,isnccwi

 !    isnccwb = +1 if Bphi is counterclockwise (CCW) looking down
 !                 on the torus
 !            = -1 if Bphi is clockwise (CW) looking down on the
 !                 torus.
 !
 !    isnccwi = +1 if Ip (plasma current) is CCW looking down on
 !                 the torus
 !              -1 if Ip is CW looking down on the torus.

      call eqm_bset(isnccwb,isnccwi)

 !    use eqm_bset to inform xplasma of the sign orientation of
 !    the toroidal field and plasma current (hence poloidal field).

Subsequently, one may use

      call eq_bchk_sign(isnccwb,isnccwi)

to retrieve the sign factors as previously set; if the field has not
been initialized then this routine will return zeroes.

When all of the above information is known to xplasma, it will 
go ahead and compute

      BR(chi,rho) -- R component of B field -- bicubic spline
      BZ(chi,rho) -- Z component of B field -- bicubic spline
      BMOD(chi,rho) -- mod(B) -- bicubic spline

(note Bphi(chi,rho) = isnccwb*g(rho)/R(chi,rho) is known implicitly).

(note also that the signs of g(rho) and d(psi)/d(rho) will not
be used to compute B.  Instead, "G" as stored by xplasma as a
positive definite function, and "PSI" is standardized such that
psi(rho(1))=0.0d0 and psi(rho) is strictly increasing.  The call
to eqm_bset is required to set the signs of the field vector
components.)

A sketched example of code that would supply enough information for 
xplasma to evaluate the B field vs. magnetic coordinates:

      call eqm_rho(...)     ! set up rho grid
      call eqm_chi(...)     ! set up chi grid

      call eqm_rhofun(...,'g',...)   ! set up g(rho)
      call eqm_rhofun(...,'psi',...) ! set up psi(rho)

      call eqm_frhochi(...,'R',...)  ! set up R(chi,rho)
      call eqm_frhochi(...,'Z',...)  ! set up Z(chi,rho)

      call eqm_bset(isnccwb,isnccwi) ! specify sign conventions

Home Top


Limiters_and_RZ_grid

In xplasma the "limiter" refers to traditional limiters, vacuum
vessel walls, divertor throats-- any mechanical bounding surface
that faces the plasma or the vacuum region surrounding the plasma.

Generally, the (R,Z) cartesian grid is set up at the same time as
the limiter, because the limiter location determines the range of
(R,Z) rectangular grid required to cover both the core plasma and
the scrape off plasma between the core and the limiters.

xplasma supports 3 types of limiter specifications:

 * fixed distance "dlim" from plasma boundary, but constrained by
   a box [Rmin,Rmax]x[Zmin,Zmax].  dlim.ge.zero, and the box contains
   (and does not cut into) the core plasma.  If dlim=0, the limiter
   and the plasma boundary are the same.

   => use eqm_dbdy_grid or eqm_rzgrid followed by eqm_dbdy

 * a list of infinite lines and circles.  Each line j divides space
   into two half-planes one of which contains the plasma, call this
   half plane Hj.  Each circle k divides space into the region inside
   the circle and the region outside, one of which contains the 
   plasma; call this region Ck.  The intersection I of all Hj and Ck
   then defines a space containing the plasma.  The boundary of I,
   which consists of segments of the given lines and arcs of the 
   given circles, defines the limiter.  It is an error if one of 
   the limiter lines or circles cuts into the plasma.

   => use eqm_tbdy_grid or eqm_tbdy followed by eqm_rzgrid

 * a contour defined by a closed sequence of points {(R(i),Y(i))},
   i=1:nc, R(1)=R(nc),Y(1)=Y(nc), and the contour does not cross
   itself, and the contour does not cut into the plasma.

   => use eqm_cbdy_grid or eqm_cbdy followed by eqm_rzgrid

Home Top


eqm_dbdy_methods

(old f77 xplasma 1 documentation)

If evenly spaced (R,Z) grids are OK, use eqm_dbdy_grid, as
follows:

To define the limiter (input to eqm_dbdy_grid or eqm_dbdy)
      real*8 dlim            ! fixed distance out from plasma bdy
      real*8 rmin,rmax       ! Rmin and Rmax of constraining box
      real*8 zmin,zmax       ! Zmin and Zmax of constraining box

To define the (R,Z) grids (input to eqm_dbdy_grid or eqm_rzgrid)

      integer inumR          ! no. of R grid points
      integer inumZ          ! no. of Z grid points

Information returned (from eqm_dbdy_grid or eqm_rzgrid)

      integer id_R           ! xplasma R grid id code
      integer id_Z           ! xplasma Z grid id code

      integer ierr           ! completion code 0 = OK

         ...

      call eqm_dbdy_grid(dlim,rmin,rmax,zmin,zmax,
     >                   inumR,inumZ,
     >                   id_R,id_Z,ierr)

-----------------------------------------------------
Or...
To explicitly control the (R,Z) grids...
Add the declarations...

      real*8 Rgrid(inumR)    ! user's desired R grid for eqm_rzgrid
      real*8 Zgrid(inumZ)    ! user's desired Z grid for eqm_rzgrid

 ! *** Rgrid and Zgrid must be strict ascending, and, 
 !     [Rgrid(1),Rgrid(inumR)]x[Zgrid(1),Zgrid(inumZ)] must
 !     cover the plasma 

      integer iauto          ! if iauto.le.0 user supplies grid
                             ! if iauto.eq.0 the grid is padded with
                             !    two "gaurd rows" on each edge
                             ! if iauto.eq.-1 the grid is not padded.

      real*8 ztol            ! (R,Z) grid even-spacing tolerance
                             ! recommend about 1.0d-6*Rmax
         ...

 ! set up grid FIRST

      call eqm_rzgrid(Rgrid,Zgrid,iauto,iauto,inumR,inumZ,ztol,
     >                id_R,id_Z,ierr)
      
 ! THEN set up limiter.

      call eqm_dbdy(dlim,Rgrid(1),Rgrid(inumR),Zgrid(1),Zgrid(inumZ),
                    ierr)

         -- or --

      call eqm_dbdy(dlim,Rmin,Rmax,Zmin,Zmax,
                    ierr)

 ! but note:
 !         if Rmin.lt.Rgrid(1), Rgrid(1) is used,
 !         if Rmax.gt.Rgrid(inumR), Rgrid(inumR) is used,
 !         if Zmin.lt.Zgrid(1), Zgrid(1) is used,
 !         if Zmax.gt.Zgrid(inumZ), Zgrid(inumZ) is used,

Home Top


eqm_tbdy_methods

(old f77 xplasma 1 documentation)

If evenly spaced (R,Z) grids are OK, use eqm_tbdy_grid, as
follows:

To define the line limiters (input to eqm_tbdy_grid or eqm_tbdy):

      integer ilines         ! number of infinite line "limiters"
      real*8 Rl(ilines),Zl(ilines) ! 1 point given on each line
      real*8 thl(ilines)     ! orientation angle in DEGREES

 ! thl(j) = 0 or 180 or -180 -- line j is horizontal
 ! thl(j) = +/- 90 -- line j is vertical
 ! thl(j) = 45 -- line runs in (+1,+1) or (-1,-1) direction 
   along the line in (R,Z) space
 ! thl(j) = -45 -- line runs in (-1,+1) or (+1,-1) direction
   along the line in (R,Z) space

To define the circle limiters (input to eqm_tbdy_grid or eqm_tbdy):

      integer icircs         ! number of circle "limiters"
      real*8 Rc(icircs),Zc(icircs) ! (R,Z) centers of circles
      real*8 rad(icircs)     ! radii of circles

To define the (R,Z) grids (input to eqm_tbdy_grid or eqm_rzgrid)

      integer inumR          ! no. of R grid points
      integer inumZ          ! no. of Z grid points

Information returned (from eqm_tbdy_grid or eqm_rzgrid)

      integer id_R           ! xplasma R grid id code
      integer id_Z           ! xplasma Z grid id code

      integer ierr           ! completion code 0 = OK

         ...

      call eqm_tbdy_grid(ilines,Rl,Zl,thl,
     >                   icircs,Rc,Zc,rad,
     >                   inumR,inumZ,
     >                   id_R,id_Z,ierr)

-----------------------------------------------------
Or...
To explicitly control the (R,Z) grids...
Add the declarations...

 ! for eqm_rzgrid:

      real*8 Rgrid(inumR)    ! desired R grid
      real*8 Zgrid(inumZ)    ! desired Z grid

 !     if Rgrid and Zgrid are not generated, then, 
 ! *** Rgrid and Zgrid must be strict ascending, and, 
 !     [Rgrid(1),Rgrid(inumR)]x[Zgrid(1),Zgrid(inumZ)] must
 !     cover the plasma AND scrapeoff layer

      integer iautoR = 0     ! user supplies Rgrid if iautoR=0
      integer iautoZ = 0     ! user supplies Zgrid if iautoZ=0

      real*8 ztol            ! (R,Z) grid even-spacing tolerance
                             ! recommend about 1.0d-6*Rmax
         ...

      integer itype          ! limiter type code from eq_bdlims
      real*8 zRmin,zRmax     ! limiter Rmin & Rmax from eq_bdlims
      real*8 zZmin,zZmax     ! limiter Zmin & Zmax from eq_bdlims

 ! set up limiter FIRST

      call eqm_tbdy(ilines,Rl,Zl,thl,
     >              icircs,Rc,Zc,rad, ierr)
      if(ierr.ne.0) then 
         [...handle error...]
      endif

 ! find Rmin,Rmax, Zmin,Zmax of limiters (use eq_bdlims subroutine)

      call eq_bdlims(itype,zRmin,zRmax,zZmin,zZmax,ierr)

 ! generate a grid which covers the necessary range + some margin
 ! **for example** code to generate an evenly spaced (R,Z) grid:

      zRmid=0.5d0*(zRmin+zRmax)
      zZmid=0.5d0*(zZmin+zZmax)

      zdelR=(inumR-1)*0.5d0*(zRmax-zRmin)/(inumR-4) ! 1.5 zone margin
      zdelZ=(inumZ-1)*0.5d0*(zZmax-zZmin)/(inumZ-4) ! 1.5 zone margin

      do i=1,inumR
         zRgrid(i)=zRmid-zdelR + (i-1)*2.0d0*zdelR/(inumR-1)
      enddo

      do i=1,inumZ
         zZgrid(i)=zZmid-zdelZ + (i-1)*2.0d0*zdelZ/(inumZ-1)
      enddo

 ! but note an evenly spaced grid is not required.

 ! finally, call eqm_rzgrid to set up the (R,Z) grid

      call eqm_rzgrid(Rgrid,Zgrid,iautoR,iautoZ,inumR,inumZ,ztol,
     >                id_R,id_Z,ierr)

Home Top


eqm_cbdy_methods

(old f77 xplasma 1 documentation)

If evenly spaced (R,Z) grids are OK, use eqm_cbdy_grid, as
follows:

To define the limiter contour, an ordered, closed sequence of
(R,Z) points, for eqm_cbdy_grid or eqm_cbdy:

      integer ipts           ! number of points in piecewise linear
                             ! limiter contour
      real*8 Rlim(ipts),Zlim(ipts) ! count (R,Z) point data

 ! Rlim(1)=Rlim(ipts) and Zlim(1)=Zlim(ipts) is required, and, 
 ! the arrays must describe a simple closed contour that does not
 ! cross itself, and which does not cut into the core plasma.

To define the (R,Z) grids (input to eqm_cbdy_grid or eqm_rzgrid)

      integer inumR          ! no. of R grid points
      integer inumZ          ! no. of Z grid points

Information returned (from eqm_cbdy_grid or eqm_rzgrid)

      integer id_R           ! xplasma R grid id code
      integer id_Z           ! xplasma Z grid id code

      integer ierr           ! completion code 0 = OK

         ...

      call eqm_cbdy_grid(ipts,Rlim,Zlim,
     >                   inumR,inumZ,
     >                   id_R,id_Z,ierr)

-----------------------------------------------------
Or...
To explicitly control the (R,Z) grids...
Add the declarations...

 ! for eqm_rzgrid:

      real*8 Rgrid(inumR)    ! desired R grid
      real*8 Zgrid(inumZ)    ! desired Z grid

 !     if Rgrid and Zgrid are not generated, then, 
 ! *** Rgrid and Zgrid must be strict ascending, and, 
 !     [Rgrid(1),Rgrid(inumR)]x[Zgrid(1),Zgrid(inumZ)] must
 !     cover the plasma AND scrapeoff layer

      integer iautoR = 0     ! user supplies Rgrid if iautoR=0
      integer iautoZ = 0     ! user supplies Zgrid if iautoZ=0

      real*8 ztol            ! (R,Z) grid even-spacing tolerance
                             ! recommend about 1.0d-6*Rmax
         ...

      integer itype          ! limiter type code from eq_bdlims
      real*8 zRmin,zRmax     ! limiter Rmin & Rmax from eq_bdlims
      real*8 zZmin,zZmax     ! limiter Zmin & Zmax from eq_bdlims

 ! set up limiter FIRST

      call eqm_cbdy(ipts,Rlim,Zlim, ierr)
      if(ierr.ne.0) then 
         [...handle error...]
      endif

 ! find Rmin,Rmax, Zmin,Zmax of limiters (use eq_bdlims subroutine)

      call eq_bdlims(itype,zRmin,zRmax,zZmin,zZmax,ierr)

 ! generate a grid which covers the necessary range + some margin
 ! **for example** code to generate an evenly spaced (R,Z) grid:

      zRmid=0.5d0*(zRmin+zRmax)
      zZmid=0.5d0*(zZmin+zZmax)

      zdelR=(inumR-1)*0.5d0*(zRmax-zRmin)/(inumR-4) ! 1.5 zone margin
      zdelZ=(inumZ-1)*0.5d0*(zZmax-zZmin)/(inumZ-4) ! 1.5 zone margin

      do i=1,inumR
         zRgrid(i)=zRmid-zdelR + (i-1)*2.0d0*zdelR/(inumR-1)
      enddo

      do i=1,inumZ
         zZgrid(i)=zZmid-zdelZ + (i-1)*2.0d0*zdelZ/(inumZ-1)
      enddo

 ! but note an evenly spaced grid is **not** required.

 ! finally, call eqm_rzgrid to set up the user (R,Z) grid

      call eqm_rzgrid(Rgrid,Zgrid,iautoR,iautoZ,inumR,inumZ,ztol,
     >                id_R,id_Z,ierr)

Home Top


_2d_Profiles_f(R,Z)

(old f77 xplasma 1 documentation)

After the limiter and (R,Z) grids have been established, the user
can define profiles over the (R,Z) grid.  These functions will
cover both the core plasma and the scrape-off plasma.  For (R,Z)
points which are behind the limiter, a smooth automatic extrap-
olation is provided.

Interpolating profile functions f(R,Z) are characterized by
an "order" which corresponds to fitting method:

  order   description

   0      bilinear interpolation, continuous
   1      Akima Hermite interpolation, continuous & differentiable
   2      Spline interpolation, continuous & twice differentiable

However, bicubic splines should be used with care, as noise in
the data can cause "ringing" artifacts.  If this is in the
plasma edge region, a smoothing option is available.

Three subroutines are available for defining functions f(R,Z):

  eqm_rzfun -- from an existing flux surface function f(rho),
               define f(R,Z) using f(rho) in the core region
               and f(rho(bdy))*exp(-d/lamda) in the scrape
               off region, where d = distance beyond plasma
               boundary.  The parameter "lamda", the scrape-
               off length, is a subroutine argument.

  eqm_rzfunf-- from an existing flux surface function f(rho),
               define f(R,Z) using f(rho) in the core region
               and using a user supplied function (passed as
               a subroutine argument) for the scrape-off layer.
               The user supplied function is only called for
               (R,Z) values which are outside the plasma but
               inside the limiter.

  eqm_rzfun2-- load f(R,Z) from a user supplied function
               which is passed as a subroutine argument.
               The user supplied function is called for
               all (R,Z) values which are inside the
               limiter, including inside the core
               plasma.

  eqm_rzfunda- load f(R,Z) from a user supplied data array.

As with f(rho) & f(rho,chi) routines, an existing item can
receive a "data update" by calling the appropriate routine with
iorder=99 specified.  However, it is up to the programmer to
enforce consistency of profiles in the context of updates.

Home Top


eqm_rzfun

(old f77 xplasma 1 documentation)

Use this subroutine to define a profile f(R,Z) from an existing
flux surface function profile f(rho), using a "scrape-off length"
parameter to specify the variation outside the core plasma
boundary.

Input arguments:

      integer id_fun     ! xplasma id for existing function f(rho)

 ! if necessary:  call eq_gfnum('TE',id_fun) to fetch a function
 ! id given the function name; here 'TE' might be the label for
 ! "electron temperature".

      real*8 lamda       ! scrape-off length

 ! outside the plasma boundary, f(R,Z)=f(rho(bdy))*exp(-d/lamda),
 ! where f(rho(bdy)) is the value of f(rho) at the plasma boundary,
 ! and d(R,Z) gives the distance from the plasma boundary.

      integer iorder     ! interpolation method, 0=bilinear,
                         ! 1=Hermite, 2=Spline

      real*8 delta       ! smoothing parameter (0.0d0 for none)

Output argument:

      integer ierr       ! completion code, 0=OK

         ...

      call eqm_rzfun(id_fun,lamda,iorder,delta,ierr)
      if(ierr.ne.0) then  [...handle error...]

After a successful call to eqm_rzfun, the interpolation object
indexed by "id_fun" is a "compound object" containing both
representations f(rho) and f(R,Z), which are designed to co-exist.

Home Top


eqm_rzfunf

(old f77 xplasma 1 documentation)

Use this subroutine to define a profile f(R,Z) from an existing
flux surface function profile f(rho), using a user supplied
function "userfcn" to specify the profile variation outside the
core plasma but inside the limiter.  "userfcn" is the name used
for the function dummy argument and in this documentation, but
in practice for any particular call to eqm_rzfunf the user 
chooses an appropriate specific name for this function.  The 
"userfcn" routine must have the following interface:

      real*8 function "userfcn"(iarg,R,Z,phi,ierr)

with inputs:

      integer iarg       ! integer argument, pass through eqm_rzfunf
      real*8 R,Z,phi     ! cylindric coordinates (for axisymmetric
                         ! cases phi will not be used).  Points passed
                         ! to userfcn will be outside the core plasma
                         ! but inside the limiter

and outputs:

      (function value)   ! the value of the function "f" at (R,Z,phi)
      integer ierr       ! completion code, 0=OK, else an error.

Assuming "userfcn" exists, then, the arguments to eqm_rzfunf are
as follows.

Input arguments:

      character*(*) zname  ! name of new function, must be unique.

 ! if necessary:  call eq_gfnum('TE',id_fun) to fetch a function
 ! id given the function name; here 'TE' might be the label for
 ! "electron temperature".

      external <your-userfcn>   ! the name of your "userfcn" routine

      integer iarg       ! pass-through argument for "userfcn"

      integer iorder     ! interpolation method, 0=bilinear,
                         ! 1=Hermite, 2=Spline

      real*8 delta       ! smoothing parameter (0.0d0 for none)

Output arguments:

      integer id_fun     ! xplasma id for new function (returned).
      integer ierr       ! completion code, 0=OK

         ...

      call eqm_rzfunf(id_fun,<your-userfcn>,iarg,iorder,delta,ierr)
      if(ierr.ne.0) then  [...handle error...]

Home Top


eqm_rzfun2

(old f77 xplasma 1 documentation)

Use this subroutine to define a new profile function f(R,Z),
using a user supplied function "userfcn" to specify the profile 
variation both inside the core plasma and also outside the
core plasma but inside the limiter.  "userfcn" is the name used
for the function dummy argument and in this documentation, but
in practice for any particular call to eqm_rzfun2 the user chooses
an appropriate specific name for this function.  The "userfcn" must
have the following interface:

      real*8 function "userfcn"(iarg,R,Z,phi,ierr)

with inputs:

      integer iarg       ! integer argument, pass through eqm_rzfun2
      real*8 R,Z,phi     ! cylindric coordinates (for axisymmetric
                         ! cases phi will not be used).  Points passed
                         ! to userfcn will be inside the limiter

and outputs:

      (function value)   ! the value of the function "f" at (R,Z,phi)
      integer ierr       ! completion code, 0=OK, else an error.

Assuming "userfcn" exists, then, the arguments to eqm_rzfun2 are
as follows.

Input arguments:

      character*(*) zname  ! name of function

      external <your-userfcn>   ! the name of your "userfcn" routine

      integer iarg       ! pass-through argument for "userfcn"

      integer iorder     ! interpolation method, 0=bilinear,
                         ! 1=Hermite, 2=Spline

      real*8 delta       ! smoothing parameter (0.0d0 for none)

Output arguments:

      integer id_fun     ! xplasma id for function
      integer ierr       ! completion code, 0=OK

         ...

      call eqm_rzfun2(zname,id_fun,<your-userfcn>,iarg,iorder,delta,
     >                ierr)
      if(ierr.ne.0) then  [...handle error...]

After a successful call to eqm_rzfun, the interpolation object
indexed by "id_fun" is a "compound object" containing both
representations f(rho) and f(R,Z), which are designed to co-exist.

Home Top


eqm_rzfunda

(old f77 xplasma 1 documentation)

Use this subroutine to define a new profile function f(R,Z),
using array data supplied by the user.  The data must be dimensioned
f(nR,nZ) where nR and nZ are the R and Z grids, respectively.  The
function covers the entire R-Z box, including points beyond the 
limiters.

Input arguments:

      character*(*) zname  ! name of function

      integer inR,inZ      ! array dimensions -- must match R, Z grids

      real*8 zdata(inR,inZ)  ! data array-- R,Z grid dimensions.

      integer iorder     ! interpolation method, 0=bilinear,
                         ! 1=Hermite, 2=Spline

      real*8 delta       ! smoothing parameter (0.0d0 for none)

Output arguments:

      integer id_fun     ! xplasma id for function
      integer ierr       ! completion code, 0=OK

         ...

      call eqm_rzfunda(zname,id_fun,zdata,inR,inZ,iorder,delta,ierr)
      if(ierr.ne.0) then  [...handle error...]

After a successful call to eqm_rzfun, the interpolation object
indexed by "id_fun" is a "compound object" containing both
representations f(rho) and f(R,Z), which are designed to co-exist.

Home Top


Smoothing

(old f77 xplasma 1 documentation)

Often noise occurs in the vicinity of the plasma boundary;
to ameliorate this there is a smoothing parameter "delta" given
in units of (R,Z).  Data at points (Rd,Zd) within distance 
0.5*delta of the plasma boundary are smoothed by a weighted
convolution over data in the region

   [Rd-delta,Rd+delta]x[Zd-delta,Zd+delta]

with the weighting a pyramid shaped function favoring the points
close to the original (Rd,Zd).  For points in the bands from
0.5*delta to 1.5*delta away from the boundary, reduced smoothing
is done, the less smoothing the further away, until at 1.5*delta
remove no smoothing is done at all.

The smoothing parameter "delta" is a calling argument in 
the subroutines eqm_rzfun* used for defining profile functions
f(R,Z).  To disable smoothing, specify delta = 0.0D0 ...

Home Top


B(R,Z)

(old f77 xplasma 1 documentation)

The xplasma package permits formation of a representation of the
magnetic field vector over the (R,Z) grid, and therefore covering
the scrape-off region as well as the core plasma.

To load this representation, the user calls subroutine "eqm_brz"
which itself takes a field specification subroutine as an argument.
For this field specification subroutine, the user must either

  (a) provide a user written subroutine "userbvec", with the
      required interface, which specifies he field everywhere, or,

  (b) if B(chi,rho) is available in the core region but there is
      no data for B in the scrape-off region, use the xplasma
      supplied extrapolator for B(R,Z):

         eqm_brz_adhoc  -- ad hoc extrapolation, fast and smooth.

         (the old method eqm_brzx -- div(B)=curl(B)=0 extrapolation
          has been continued; eqm_brzx and eqm_brz_adhoc now both
          yield the same result).

      (more details below).

  (c) if data specifying psi(R,Z) is available, enter this into
      xplasma using e.g. eqm_rzfun with iorder=1 or iorder=2,
      then use "eqm_bpsi", which will use grad(phi) x grad(psi)
      for BR and BZ, and g/R for Bphi.

Option (b) should only be used in cases where an independent data
source for reconstruction of B(R,Z) outside the core plasma is
unavailable.  For example, if reading data from a source such as
a TRANSP run, which lacks outside-the-plasma data, option (b) may
have to be used.  But, if reading from a source such as an EFIT
G EQDSK file which gives psi(R,Z), options (a) or (c) should be
used.

The call to eqm_brz takes the following form:

input arguments:
      external <your-userbvec | eqm_brz_adhoc | eqm_bpsi >
                     ! your B(R,Z) extrapolation data subroutine

      real*8 delta   ! edge smoothing parameter

output argument:

      integer ierr   ! completion code, 0=OK

         ...

      call eqm_brz(<your B(R,Z) extrapolation data subroutine>,
     >             delta, ierr)
      if(ierr.ne.0) then  [... handle error ...]

A successful call to eqm_brz results in the creation of functions
BR(R,Z), BZ(R,Z) and BPHI(R,Z), interpolations on which are usually
done by one of the eq_get* data access subroutines.  If
"eqm_brz_adhoc" is used, the poloidal flux function psi(R,Z) is 
also formed and associated with psi(rho) from inside the plasma.

Note:  at present this system is only valid for axisymmetric plasma 
field configurations.  Non-axisymmetry will require significant
new options.

Home Top


your-userbvec

(old f77 xplasma 1 documentation)

If you write your own routine for specifying the field, it must
have the following interface:

      subroutine <your-userbvec>(
     >                           ivec,R,Z,phi,
     >                           init,
     >                           BR,BZ,BPHI,
     >                           Psi,ipsi,
     >                           ierr)

 ! input arguments:
      integer ivec                     ! vector dimensioning
      real*8 R(ivec),Z(ivec),phi(ivec) ! coordinates at which
 !                                     !   to evaluate BR,BZ,Bphi
      integer init                     ! call flag
 !                init=1 -- initialization call (or just set ipsi)
 !                init=2 -- cleanup call (or do nothing)
 !                init=0 -- standard call
 !
 !    the purpose of init is to allow the subroutine to perform
 !    initializations before it is first used, and to perform
 !    cleanup operations after the last time it is used.  Of 
 !    course some <your-userbvec> routines might not require
 !    initialization or cleanup.
 !
 !    within an eqm_brz routine, the first call to <your-userbvec>
 !      has init=1, subsequent calls have init=0, and then there is
 !      a final call with init=2.

 ! output arguments:
 !   if init=1, only ipsi need be output
 !   if init=2, no output is required
 !   if init=0, all output is required
 !
      real*8 BR(ivec),BZ(ivec),BPHI(ivec)  ! the field components
 !                                         ! at the given coordinates
 !
 ! optional output:
      real*8 Psi(ivec)                     ! the poloidal flux 
      integer ipsi                         ! =1 if poloidal flux is
 !                                         !    output
 !
 ! status code
 !
      integer ierr                         ! exit code, 0=OK

 ! notes:
 !  * the phi(ivec) argument is provided for compatibility, in case
 !    the software is extended for non-axisymmetry in the future.
 !    For an axisymmetric code it can be ignored.
 !  * ipsi must be set =1 if the routine returns psi(R,Z) in addition
 !    to the field components.  Otherwise set ipsi=0.
 !  * the routine is expected to return BR(j),BZ(j),BPHI(j) and
 !    possibly psi(j), i.e. the field, at R(j),Z(j),phi(j), 
 !    for j = 1 to ivec.  If the field cannot be evaluated at
 !    any one or more of these points, the status code ierr
 !    should be set to a non-zero number.
 !
 ! it may be helpful to look at the source code for eqm_brz_adhoc
 ! and eqm_bpsi -- two routines which satisfy these interface
 ! requirements.
      
Home Top


eqm_brzx_OR_eqm_brz_adhoc

(old f77 xplasma 1 documentation)

CORRECTION: eqm_brzx has been remapped to point to eqm_brz_adhoc.  For
stability/robustness reasons, the original eqm_brzx described here has
been discontinued.

Xplasma supplies 2 B(R,Z) extrapolator routines.  Either

      subroutine eqm_brz_adhoc(ivec,zR,zZ,zphi,init,BR,BZ,BPHI,zpsi,
     >   ipsi,ierr)

or

      subroutine eqm_brzx(ivec,zR,zZ,zphi,init,BR,BZ,BPHI,zpsi,
     >   ipsi,ierr)

...can be passed to eqm_brz as the external subroutine argument.

Eqm_brz_adhoc uses a fast, approximate ad hoc method for extrapolating
B(R,Z), described in detail below.  In summary, the external toroidal
field is taken as g(rho_bdy)/R, while the external poloidal field is
assumed to allign with an ad hoc numerical extrapolation of the
(rho,chi) flux coordinate system.  The poloidal variation of the
poloidal field occurring at the boundary is preserved, but the
magnitude is scaled down by the ratio of the poloidal path length
at the extrapolated rho surface to the poloidal path length of the
boundary surface (at rho_bdy).  An extrapolation of the poloidal
flux function psi is also provided and is roughly consistent with
the extrapolated poloidal field.

The original Eqm_brzx used a block-tridiagonal finite difference 
solver to extrapolate the core field, assuming axisymmetry and 
div(B)=0, and, initially, curl(B)=0.  As the extrapolation advances, 
instabilities are detected and repaired by introducing current
(curl(b).ne.0).  Physically, this can be thought of as "guessing"
where the coils are that hold the field in place in the actual
experiment.  This stabilized extrapolation will result in a
field estimate whose deviation from the actual experimental
field will increase, the further one moves from the core plasma
region where the field is known.  However, the field should have
roughly the right behaviour close to the core plasma.  On the
other hand, the stabilization method is purely ad hoc.

The purpose of eqm_brz_adhoc and eqm_brzx is to provide an (R,Z) 
extrapolation when the original field data is unavailable outside 
the core plasma.  If the original field data is available, it should
be used in preference to these routines.

A sketch of the actual eqm_brz_adhoc algorithm executed by xplasma:

  1.  compute an ad hoc extrapolation of the (chi,rho) magnetic
      coordinate system.  This extrapolation produces a set of
      nested surfaces but not flux surfaces; outside the core
      plasma, psi is a function of (chi,rho), not just (rho).

  2.  for rho>rho_bdy compute
          Lpol(rho) = poloidal path length around rho "flux" surface.
      and then take
          mod(Bpol(rho,chi)) = mod(Bpol(rho_bdy,chi)) * L_ratio
             where L_ratio = Lpol(rho_bdy)/Lpol(rho) < 1.

      while the direction of Bpol is tangent to the rho surface
      with sign consistent with the interior Bpol field.

      also take
	   Bphi(rho,chi) = nsnccwb*g(rho_bdy)/R(rho,chi)

      i.e. use the "1/R" vacuum toroidal field beyond the plasma
      boundary.

  3.  form a poloidal variation spline
          fRB(chi)) = (R*Bpol(rho_bdy,chi))/(Rmax*Bpol(rho_bdy,Rmax))
      (Bpol(rho_bdy,Rmax) is found by finding chi_Rmax = the poloidal
      angle at which the max R on the rho surface occurs, then
      Bpol(rho_bdy,Rmax)=Bpol(rho_bdy,chi_Rmax) is used).

  4.  Along the contour (rho,chi_Rmax(rho)) compute the extrapolated
      poloidal field and poloidal flux function differential

         d(psi) = Rmax(rho)*d(Rmax)*Bpol(rho,chi_Rmax(rho))

      and integrate this to form psi(rho,chi_Rmax(rho))

  5.  Take psi(rho,chi) = fRB(chi)*psi(rho,chi_Rmax(rho))

The result is quickly calculated, numerically well behaved, gives
reasonable results near the boundary, but, it does not precisely
satisfy physics constraints (del.B=0, curl.B=0, Bpol=grad(psi)/R
are NOT satisfied accurately).

A sketch of the original eqm_brzx algorithm:

  *** NO LONGER AVAILABLE ***

  1.  compute an ad hoc extrapolation of the (chi,rho) magnetic
      coordinate system.  This extrapolation produces a set of
      nested surfaces but not flux surfaces; outside the core
      plasma, psi is a function of (chi,rho), not just (rho).

  2.  on this ad hoc coordinate system, advance from rho(j-1)
      to rho(j), for all chi, using a block tridiagonal solver
      for BR(1:nchi,j), BZ(1:nchi,j), with the triagonal system
      derived by finite differences from div(B)=0, curl(B)=0.

  3.  detect and repair fluctuations in Bchi, by adding current
      (in the form curl(B)) where needed to keep Bchi smooth.
      (this is an entirely ad hoc method).

  4.  move on to the next surface-- keep going until the (R,Z)
      grid rectangle is entirely covered.

The main computations are done on the init=1 call to eqm_brzx.
The init=0 calls return the resulting field components to 
eqm_brz, and the init=2 call is used to clean up memory
management related to the calculation.

Bottom line:  eqm_brz_adhoc is faster and more stable.  Both
extrapolators have "arbitrary" ad hoc features.  If a calculation
requires accurate B(R,Z) beyond the plasma boundary, there is no
substitute for providing the actual data based on coil positions,
coil currents, and a free boundary equilibrium reconstruction (e.g.
EFIT) that actually covers the vacuum region.  An EFIT-based or
equivalent psi(R,Z) profile can also be used (see the eqm_bpsi 
B(R,Z) data extrapolation routine).

Since many datasets (e.g. TRANSP results) do not retain the 
necessary vacuum field data, the extrapolation tools are provided
as a convenience.

Home Top


eqm_bpsi

(old f77 xplasma 1 documentation)

      subroutine eqm_bpsi(ivec,zR,zZ,zphi,init,BR,BZ,BPHI,zpsi,ipsi,
     >   ierr)

...can be passed to eqm_brz as the external subroutine argument.

This routine can be used when psi(R,Z) has been defined as an
xplasma function (e.g. with eqm_rzfun).  The routine computes
Bphi from g(rho)/R, where rho=rho(R,Z) inside the core plasma,
and, rho=rhobdy at the edge and outside the core plasma.

The routine computes BR and BZ from grad(phi) x grad(psi)
which looks like

  BR(i) =  nsnccwi*(dpsi/dZ)/R
  BZ(i) = -nsnccwi*(dpsi/dR)/R

where nsnccwi (+/-1) specifies the direction of the toroidal plasma
current.

If core field data BR(chi,rho) and BZ(chi,rho) are available,
xplasma will use this in preference to grad(psi)/R.

If necessary, edge smoothing can be employed to improve the
blending of the core and external regions.
Home Top


Smoothing

Often noise occurs in the vicinity of the plasma boundary;
to ameliorate this there is a smoothing parameter "delta" given
in units of (R,Z).  Data at points (Rd,Zd) within distance 
0.5*delta of the plasma boundary are smoothed by a weighted
convolution over data in the region

   [Rd-delta,Rd+delta]x[Zd-delta,Zd+delta]

with the weighting a pyramid shaped function favoring the points
close to the original (Rd,Zd).  For points in the bands from
0.5*delta to 1.5*delta away from the boundary, reduced smoothing
is done, the less smoothing the further away, until at 1.5*delta
remove no smoothing is done at all.

The smoothing parameter "delta" is a calling argument in 
the subroutines eqm_rzfun* used for defining profile functions
f(R,Z).  To disable smoothing, specify delta = 0.0D0 ...

Home Top


lists

XPLASMA now supports a generic facility for creating and accessing lists.
Each list has a name (max 32 characters, one alphanumeric word, treated
as uppercase), a label (max 60 characters), and a size which specifies 
the number of elements in the list.

Each list element has a name (max 32 characters, one alphanumeric word,
treated as uppercase), and the following associated data:

  a character string (max 60 characters) in addition to the name
  a floating point number
  an integer.

Lists can be used to communicate such information as:

  -> a list of plasma spacies and the Z and A values of each species:

     name of example list: TR_THERMAL_SPECIES, size = 3
       (label: "list of thermal ion species")
          name       character data        floating data    integer data
           H          (blank)               1.000            1
           D          (blank)               2.000            1
           HE4        (blank)               4.000            2

     interpretation: floating data gives "A", integer gives "Z".

  -> a timestep

     name of example list: TR_TIMESTEP, size = 2
       (label: "timestep for TRANSP sources")
          name       character data        floating data    integer data
           TR_TS1     S                     1.010            0
           TR_TS2     S                     1.020            0

     interpretation: character data gives physical units, floating data
     gives actual time values.
     
  -> a collection of related profile data items

     name of example list: TR_EHEAT, size = 5
       (label: "integrated electron heating profiles")
          name       character data        floating data    integer data
           TR_PBE     W                     3.073e4          310
           TR_PFE     W                     0.000            311
           TR_PEICRF  W                     0.000            312
           TR_PEECRF  W                     0.000            313
           TR_PELH    W                     0.000            314

     interpretation: a list of heating profiles.  Character data gives
     physical units, floating data gives total amount (power, W, in this
     context), and the integer gives XPLASMA id of the interpolating
     function f(rho).

The methods for creation of lists are described here.  Methods for 
finding and accessing lists and list contents are described under 
"Data Access Routines".

Home Top


eqm_list_create

(old f77 xplasma 1 documentation)

  ! inputs:
  character*32 :: list_name   ! 1 word, treated as uppercase in XPLASMA
  character*60 :: list_label  ! any label string
  integer :: list_size        ! number of elements in list
  character*32 :: element_names(list_size)  ! names of elements (1 word each)

  ! outputs:
  integer :: list_id ! list id -- used to refer to list in subsequent calls.
  integer :: ierr    ! completion code, 0=OK

    ...

  call eqm_list_create(list_name,list_label,list_size,element_names, &
 &                     list_id,ierr)

Home Top


eqm_list_chval

(old f77 xplasma 1 documentation)

  ! inputs:
  integer :: list_id
  integer :: list_size   ! should match size in prior eqm_list_create call
  character*60 chvals(list_size)   ! character data

  ! output:
  integer :: ierr    ! completion code, 0=OK

  call eqm_list_chval(list_id,list_size,chvals,ierr)

Home Top


eqm_list_ival

(old f77 xplasma 1 documentation)

  ! inputs:
  integer :: list_id
  integer :: list_size   ! should match size in prior eqm_list_create call
  integer :: ivals(list_size)   ! integer data

  ! output:
  integer :: ierr    ! completion code, 0=OK

  call eqm_list_ival(list_id,list_size,ivals,ierr)

Home Top


eqm_list_r8val

(old f77 xplasma 1 documentation)

  ! inputs:
  integer :: list_id
  integer :: list_size   ! should match size in prior eqm_list_create call
  real*8 r8vals(list_size)   ! 8 byte floating point data

  ! output:
  integer :: ierr    ! completion code, 0=OK

  call eqm_list_r8val(list_id,list_size,r8vals,ierr)

Home Top


eqm_list_r4val

(old f77 xplasma 1 documentation)

  ! inputs:
  integer :: list_id
  integer :: list_size   ! should match size in prior eqm_list_create call
  real*4 r4vals(list_size)   ! 4 byte floating point data

  ! output:
  integer :: ierr    ! completion code, 0=OK

  call eqm_list_r4val(list_id,list_size,r4vals,ierr)

Home Top


list_name_rules:

(old f77 xplasma 1 documentation)

  -- max 32 characters.
  -- no imbedded blanks.
  -- alphanumeric characters + "$" + "_" only.
  -- all alphabetic characters treated as uppercase.
  -- first character should not be a numerical digit [0-9].

Home Top


additional_items

(old f77 xplasma 1 documentation)

A subroutine to numerically compute the q(rho) profile, using the 
formula

  q = d(Phi)/d(Psi) = [d(Phi)/d(rho)]/[d(Psi)/d(rho)]

is provided:

  character*10 qname -- desired XPLASMA name of q profile (input)

  id_q    -- id of XPLASMA profile created (output)
  ierr    -- completion code (0 = normal) (output)

  call eqm_gen_q(qname,id_q,ierr)

The profile is a piecewise cubic Hermite function.
[d(Psi)/d(rho)] > 0 near the axis is forced, but, the numerical 
value of q near axis can still jump, in cases with low axial 
current density.

Home Top


F77_Data_Access_Routines

(old f77 xplasma 1 documentation)

[This is the original xplasma 1.0 documentation].

After xplasma setup has been completed, the xplasma module contains
a list of items identifiable by unique names and integer id codes.
Data Access Routines can be used.  The following is a partial list 
of the types of routines that are provided:

  * coordinate transformations between cartesian, cylindric, and
    magnetic coordinate systems.

  * interpolation of plasma parameters and field vector, and their
    gradients, to target locations given in cartesian, cylindric
    or magnetic coordinates.

  * determination of location inside or outside the core plasma
    boundary and/or limiter, and by what distance, given target
    points in cartesian, cylindric or magnetic coordinates.

  * metric tensor information.

  * flux surface oriented statistics, such as Rmin, Rmax, Zmin, Zmax,
    Bmin and Bmax on a given flux surface.

Many routines are **vectorized**, i.e. they accept vector arguments
and return vector results.  Taking advantage of vector features is
good for code performance, on modern workstations as well as 
traditional vector supercomputers.

Home Top


identification

(old f77 xplasma 1 documentation)

Associated with each xplasma dataset is a (30 character) label,
an "axisymmetry" flag, and a "scrape-off layer" flag.  Optionally,
a timeslice time can also be associated with the dataset.

To retrieve the label and flags:

  character*30 xplasma_label
  integer axisymm_flag   ! axisymmetry flag, =1 means axisymmetric
  integer scrapeoff_flag ! scrapeoff layer flag, =1 means defined

  call eq_ident(xplasma_label,axisymm_flag,scrapeoff_flag)

Notes:
  Any meaning or interpretation of the label is up to the user (it
     was set by a prior eqm_select(...) xplasma initialization call);
     xplasma only uses the label for informational messages.
  As of April 2003-- axisymm_flag=1 always.
  The setting scrapeoff_flag=1 means that xplasma has a limiter or
     vacuum vessel wall description, and, an (R,Z) grid that extends
     beyond the plasma boundary is defined.

If a time has been associated with the current xplasma dataset, it
can be retrieved with the call:

  real*8 ztime  ! xplasma time, seconds.

  call eq_time(ztime)

The xplasma time is user information only-- it is not used internally
by the xplasma library code.

Home Top


name_translation

(old f77 xplasma 1 documentation)

There are two types of named "xplasma" entities:  "grids" and
"profiles".  Each of these entities carries a unique name and 
id number.  Most of the xplasma software requires the id number
to be supplied.  Applications should keep frequently used xplasma
id numbers on hand, for performance reasons, i.e. to minimize
time spent doing name lookup and translation.

Even so, the following name translation routines are available.

All names are case insensitive.

      character*(*) zname            ! name of entity
      integer id                     ! integer entity id code

      integer nlist                  ! length of list
      character*(*) znames(nlist)    ! list of names
      integer idlist(nlist)          ! list of entity id codes
      integer ierr                   ! completion code, 0=OK
         ...

 ! get a grid id

      call eq_ganum(zname,id)        ! e.g.:  call eq_ganum("rho",id)
                                     ! id=0 if translation fails

 ! get a profile function id

      call eq_gfnum(zname,id)        ! e.g.:  call eq_gfnum("psi",id)
                                     ! id=0 if translation fails

 ! get a list of profile function ids

      call eq_gflist(nlist,znames,idlist,ierr)

 ! ...ierr.ne.0 if any translation fails...

Reverse translations can also be done:  given the id return the
name string:

      call eq_get_aname(id,zname) ! get name of axis grid
      call eq_get_fname(id,zname) ! get name of profile function

Home Top


grid_information

(old f77 xplasma 1 documentation)

The xplasma module contains a set of grids, each identifiable

 !  size of a grid

      integer id_grid             ! xplasma grid id (in)
      integer isize               ! size (no. of points) in grid (out)

      call eq_ngrid(id_grid,isize)

 !  the grid itself

      integer imax                ! max size of grid (in)
      integer igot                ! actual size of grid (out)
      real*8 zdata(imax)          ! array for grid data (out)
      integer ierr                ! completion code, 0=OK (out)

      call eq_grid(id_grid,zdata,imax,igot,ierr)

 !  grid "zone centers" -- if grid contains N pts, this is a 
 !  sequence of N-1 values; the jth value is half way point j and
 !  point j+1 in the original (boundary oriented) grid.

      call eq_grid_zc(id_grid,zdata,imax,igot,ierr)

 !  sizes of "common grids"...

      integer inumrho             ! no. of flux surface pts
      integer inumchi             ! no. of poloidal angle pts
      integer inumphi             ! no. of toroidal angle pts

      integer inumR               ! no. of R grid pts
      integer inumZ               ! no. of Z grid pts

      call eq_ngrids(inumrho,inumchi,inumphi,inumR,inumZ)

 !  inumphi=1 is returned for axisymmetric cases.  Otherwise, if
 !  any grid is undefined, a zero size is returned.

Home Top


zone_lookup

(old f77 xplasma 1 documentation)

A vectorized zone lookup routines is provided:

  eq_nindx  -- for a vector of values along a given grid, return
               a vector of zone indices, with a warning flag set
               if any of the values are out of range.

eq_nindx is intended for "binning".  A returned index value of j
means that the corresponding input value is between grid
point j and grid point j+1.

eq_nindx returns j=0 for points that are out of range low, and 
j=N for points that are out of range high.

Note that, if an axis is periodic, then, no point will ever be out 
of range, as the software will apply 2*pi*n shifts as necessary to 
bring the target value into the selected grid's normal range.  
Periodicity is an attribute of the grid which is defined at setup 
time (cf eqm_rho, eqm_chi, eqm_bbin, or eqm_uaxis).

further details:  see the subtopic.
Home Top


eq_nindx

(old f77 xplasma 1 documentation)

Details on the "eq_nindx" subroutine call:

 ! input:
      integer id_grid                ! grid id code
      integer ivec                   ! vector size
      real*8 zvals(ivec)             ! vector of input values
 !
 !    the "zvals" are along the "id_grid" axis.
 !
 ! output:
      integer kindx(ivec)            ! corresponding zone indices
      integer iwarn                  ! warning flag, 0=normal

         ...
      call eq_nindx(id_grid,ivec,zvals,kindx,iwarn)

Note that iwarn=0 indicates normal completion, no warning.
iwarn=+M means M points were out of range relative to the
grid indicated by id_grid.

For each value zvals(i), j=kindx(i) specifies the zone in
which zvals(i) lies, i.e. x(j).le.zvals(i).le.x(j+1), where
x(...) is the grid indicated by id_grid.  If N is the size
of the grid, 1 <= j < N for all points zvals(i) that are 
in range.

If zvals(i) is out of range low, kindx(i)=0 is returned
and the warning flag is incremented.

If zvals(i) is out of range high, kindx(i)=N is returned
and the warning flag is incremented.

The caller should check the warning flag value.  However,
if "id_grid" is a "periodic" axis such as a poloidal or
toroidal angle coordinate, out-of-range errors will never
occur.

Home Top


coordinate_transformation

(old f77 xplasma 1 documentation)

The xplasma module supports 3 coordinate systems:

  cylindric:  (R,Z,phi)
  cartesian:  (x,y,z)

  magnetic:   (rho,chi,phi), 

               rho and chi as defined during setup
               (xplasma makes no assumption about any
               possible physical meaning of rho and chi).

A collection of coordinate transformation routines are 
supported.  The following is a summary:

(R,phi) -> (x,y)
  subroutine eq_xcyl(ivec,R,phi,x,y)
  subroutine eq_xcylcs(ivec,R,phi,x,y,cosphi,sinphi)
               x=R*cos(phi), y=R*sin(phi), (z=Z)

(x,y) -> (R,phi)
  subroutine eq_rcyl(ivec,x,y,R,phi) 
  subroutine eq_rcylcs(ivec,x,y,R,phi,cosphi,sinphi)
               R=sqrt(x**2+y**2), phi=atan2(y,x), (z=Z)

In the following:

To have "chi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

(rho,chi,phi) -> (R,Z,phi)
  subroutine eq_rzget(ivec,rho,chi,phi,R,Z,nregion,ierr)
               R=R(rho,chi,phi) & Z=Z(rho,chi,phi)
               by interpolation (phi ignored for axisymmetric
               cases).

(rho,chi,phi) -> (x,y,z)
  subroutine eq_xget(ivec,rho,chi,phi,x,y,z,nregion,ierr)
               (call eq_rzget then eq_xcyl)

(R,Z,phi) -> (rho,chi,phi)
  subroutine eq_inv(ivec,R,Z,phi,tol,rho,chi,nregion,ierr)
               Newton's method with "fast map" initial guess 
               generator and using d[R,Z,phi]/d[rho,chi,phi].

               Accuracy:  if one uses eq_rzget to compute
               (R',Z') from (rho,chi,phi), then, 
               max(|R-R'|,|Z-Z'|) <= tol*max(R,|Z|)

(x,y,z) -> (rho,chi,phi)
  subroutine eqx_inv(ivec,x,y,z,tol,rho,chi,phi,nregion,ierr)
               (call eq_rcyl, then eq_inv)

Home Top


subroutine_arguments

(old f77 xplasma 1 documentation)

All of the coordinate transformation routines have similar
arguments, drawn from the following set.  Which are input and
which are output depend on context, except where noted.

Note that except for ivec and ierr, all arguments are vectors.

      integer ivec         ! (always input) vector dimensioning

      real*8 R(ivec)       ! major radius (cylindrical coordinate)
      real*8 Z(ivec)       ! elevation (cylindrical coordinate
                           ! or cartesian coordinate) (z=Z).

      real*8 phi(ivec)     ! toroidal angle (cylindrical coordinate)
      real*8 cosphi(ivec)  ! cos(phi) (always output)
      real*8 sinphi(ivec)  ! sin(phi) (always output)

      real*8 x(ivec)       ! cartesian coordinate, x axis along phi=0
      real*8 y(ivec)       ! cartesian coordinate, perp to x & Z.

      real*8 rho(ivec)     ! radial flux coordinate
      real*8 chi(ivec)     ! poloidal angle coordinate

      integer nregion(ivec) ! region code (always output)
                           ! nregion(i)=1 means input position (i)
                           ! is in the space mapped by (rho,chi,phi)
                           ! nregion(i).gt.1 means it is outside the
                           ! region mapped by magnetic coordinates.

      integer ierr         ! (always output) completion code, 0=OK
                           ! ierr.ne.0 means a serious error.
                           ! A point (i) being outside the magnetic
                           ! coordinate mapped region does NOT cause
                           ! ierr to be set.

Home Top


min_max_info

(old f77 xplasma 1 documentation)

Several routines are available for finding useful minima and maxima:

(a) minimum and maximum "rho" coordinate

 ! output:
      real*8 rho_axis    ! "rho" at magnetic axis
      real*8 rho_bdy     ! "rho" at plasma boundary
         ...
      call eq_rholim(rho_axis,rho_bdy)

(b) minimum and maximum R and Z ocurring on a flux surface

 ! input:
      real*8 rho              ! "rho" where min/max info is wanted
 ! output:
      real*8 Rmin,Rmax        ! minimum and maximum R on "rho" surface
      real*8 Zmin,Zmax        ! minimum and maximum Z on "rho" surface

      integer ierr            ! completion code (0=OK)
         ...
      call eq_glimrz(rho,Rmin,Rmax,Zmin,Zmax,ierr)

(c) minimum and maximum B ocurring on a flux surface

 ! output:
      real*8 Bmin,Bmax        ! minimum and maximum mod(B)
         ...
      call eq_glimb(rho,Bmin,Bmax,ierr)

       ...or...

      real*8 phi  ! input; use e.g. phi=0 for axisymmetric case
      real*8 chi_Bmin,chi_Bmax  ! ouput: angles of min & max B

      call eq_glimb1(rho,phi,Bmin,chi_Bmin,Bmax,chi_Bmax,ierr)

(d) minimum and maximum R and Z of space enclosed by limiters
    (i.e. minimum and maximum R and Z of scrape-off plasma).

 ! output:
      integer itype           ! xplasma modules limiter type
                              !  =1:  same as plasma boundary
                              !  =2:  circles & lines
                              !  =3:  piecewise linear contour
                              !  =4:  in box, fixed distance from bdy

 ! (for more information on limiters, see section on limiters in
 ! the description of xplasma setup routines).
         ...
      call eq_bdlims(itype,Rmin,Rmax,Zmin,Zmax,ierr)

(e) minimum and maximum R and Z of (R,Z) grids defined in xplasma
    module.

      call eq_rzlims(Rmin,Rmax,Zmin,Zmax,ierr)

    This gives the space over which B(R,Z), psi(R,Z), f(R,Z), etc.
    are defined.

(f) elongation,triangularity,indentation,midplane intercepts for a 
    set of flux surfaces

   The midplane intercepts are defined as the major radiaus at the height of the
   centroid of the flux surface.

   The rho value will be forced to be larger then  1.e-5*(rho_bdy-rho_axis).

   Date: Wed, 22 Sep 1999 11:59:40 -0400
   From: Glenn Bateman <bateman@fusion.physics.lehigh.edu>
         Consider a toroidal magnetic surface (also called a flux surface).
   Use the following variables

   R_out   = major radius to the outboard edge of the flux surface
             that is, the largest value of major radius anywhere on the surface
   R_in    = major radius to the inboard edge (ie, smallest value of major
   radius)
   R_top   = major radius to the top edge of the flux surface
             that is, to the highest point on the flux surface cross section
   R_bottom = major radius to the lowest point on the flux surface
   height  = distance between the elevations of the highest point
             and the lowest point
   R_dent_in  = major radius to the most indented inboard part of the surface
             in cases where the flux surface is bean shaped
             with a dent on the inboard edge
             Note: R_dent_in = R_in whenever the flux surface is not indented
   R_dent_out = major radius to the most indented outboard part of the surface

   r_minor = half width = (R_out - R_in ) / 2     (usually called minor radius)
   r_major = ( R_out + R_in ) / 2                 (usually called major radius)

   elongation:	kappa = height / ( R_out - R_in )

   tiangularity:	delta = ( r_major - min ( R_top, R_bottom ) ) / r_minor

   indentation:	indent = max ( ( R_dent_in - R_in ) / rminor ,
                             ( R_dent_out - R_out ) / rminor )

   Note: 
     For normal convex surfaces, indent = 0.0
     For bean-shaped surfaces with indentation on the inboard edge, indent > 0
     For bean-shaped surfaces with indentation on the outboard edge, indent < 0

     For surfaces with the point of the triangle facing outward,
     delta > 0.0, while if the triangle points inward, delta < 0.0

     For vertically elongated surfaces, kappa > 1.0
     For horizontally elongated surfaces, kappa < 1.0.

  ! input:
  integer, intent(in) :: ivec            ! number of surfaces
  real*8,  intent(in) :: rho(ivec)       ! radial coordinate of flux surface
  real*8,  intent(in) :: phi(ivec)       ! toroidal coordinate of flux surface
  integer, intent(in) :: ntheta          ! number of poloidal points to use around 
                                         ! the flux surface or 0 for the default of 400

  ! output:
  real*8,  intent(out) :: elong(ivec)    ! surface elongation
  real*8,  intent(out) :: triang(ivec)   ! triangularity
  real*8,  intent(out) :: indent(ivec)   ! indentation

  real*8,  intent(out) :: zmidp (ivec)   ! height of flux surface centroid
  real*8,  intent(out) :: rmnmidp(ivec)  ! inner midplane intercept at centroid height
  real*8,  intent(out) :: rmjmidp(ivec)  ! outer midplane intercept at centroid height

  real*8,  intent(out) :: limits(9,ivec) ! surface limits used for elong,triang,indent
                                         ! 1  -> R_in
                                         ! 2  -> R_out
                                         ! 3  -> R_top
                                         ! 4  -> Z_top
                                         ! 5  -> R_bottom
                                         ! 6  -> Z_bottom
                                         ! 7  -> R_dent_in
                                         ! 8  -> R_dent_out
                                         ! 9  -> R_centroid

  integer, intent(out) :: ier            ! nonzero on error

     ...
  call eq_surfgeo(ivec, rho, phi, ntheta, &
                  elong, triang, indent, zmidp, rmnmidp, rmjmidp, limits, ier)

Home Top


volume_and_area

(old f77 xplasma 1 documentation)

When an xplasma geometry is defined, splines are set up containing
estimates of enclosed plasma volume and enclosed cross-sectional area
as a function of flux surface.  These estimates are accurate to machine
precision at the rho grid points, and well behaved inbetween.

Method: Gauss's theorem is exploited to derive accurate expressions
for enclosed volume (area) as 1d integrals at each flux surface rather
than using 2d integrals convering the volume (area).

To access the results of these fits (Volume, d[Volume]/drho, 
d2[Volume]/drho2, Area, d[Area]/drho, d2[Area]/drho2):

 ! input:
      integer ivec            ! input data vector dimension
      real*8 x(ivec)          ! vector of "x" values
      integer iwant           ! 0: value, 1: df/drho, 2: d2f/drho2

 ! output:
      real*8 zval(ivec)       ! interpolation results, returned
      integer ierr            ! completion code, 0=OK
         ...

      call eq_volume(ivec,rho,iwant,zval,ierr)   ! Volume info. (m**3)

      call eq_area(ivec,rho,iwant,zval,ierr)     ! Xsect. Area info. (m**2)

Home Top


function_information

(old f77 xplasma 1 documentation)

(for information on translating an integer id code into a name, or
vice-versa, see "name_translation")

Given a function id integer code, the "eq_fun" call can be used to get
a description of the available fundation data:  fits to magnetic
coordinates and dimenstionality; fits to cylindric coordinates and
dimensionality, as follows.

 ! input:
      integer id_fun          ! function id code

 ! output:
      integer magdim          ! dimensionality vs. mag. coordinates
      integer magfit          ! type of fit
      integer cyldim          ! dimensionality vs. cyl. coordinates
      integer cylfit          ! type of fit

      integer iwarn           ! 0=OK, set if function is "internal".
      integer ierr            ! 0=OK, set if invalid id code is passed

      ...
      call eq_fun(id_fun,magdim,magfit,cyldim,cylfit,iwarn,ierr)

the output arguments should be interpreted as follows:

  magdim=0 => no fit to magnetic coordinates
  magdim=1 => f(rho) fit available -- flux function
  magdim=2 => f(rho,chi) fit available -- f(flux & pol. angle)
  magdim=3 => f(rho,chi,phi) fit available.

  magfit=0 => piecewise linear fit, f continuous
  magfit=1 => piecewise cubic Hermite, f' continuous
  magfit=2 => piecewise cubic spline, f'' continuous

  cyldim=0 => no fit to cylindric coordinates
  cyldim=2 => f(R,Z) fit available
  cyldim=3 => f(R,Z,phi) fit available

  cylfit=0 => piecewise linear fit, f continuous
  cylfit=1 => piecewise cubic Hermite, f' continuous
  cylfit=2 => piecewise cubic spline, f'' continuous

Home Top


function_grid_information

(old f77 xplasma 1 documentation)

Given an appropriate function id, these routines return the
indicated independent coordinate grid (axis) id.  In all cases,
if the function does not exist or does not have the type of
independent coordinate grid requested, 0 is returned.

  input:
      integer id_fun          ! function id code

  output: 
      integer id_grid         ! indep. coord. grid id, or zero (0)
                              ! 0 returned if no such grid or function

  call eq_fun_rhogrid(id_fun,id_grid)  ! rho grid id
  ! OK for f(rho), f(rho,chi), f(rho,chi,phi)

  call eq_fun_chigrid(id_fun,id_grid)  ! chi grid id
  ! OK for f(rho,chi), f(rho,chi,phi)

  call eq_fun_Rgrid(id_fun,id_grid)  ! R grid id
  ! OK for f(R,Z), f(R,Z,phi)

  call eq_fun_Zgrid(id_fun,id_grid)  ! Z grid id
  ! OK for f(R,Z), f(R,Z,phi)

if xplasma is extended for non-axisymmetric applications
some day, then:

  call eq_fun_phigrid(id_fun,id_grid)  ! phi grid id
  ! OK for f(R,Z,phi), f(rho,chi,phi)

Home Top


_1d_interpolation

(old f77 xplasma 1 documentation)

The following simplified routines may be useful for interpolation
of profile functions of "rho" only:

(a) for interpolation on a single profile f(rho) prepared previously
by an eqm_rhofun call:
 ! input:
      integer ivec            ! input data vector dimension
      real*8 rho(ivec)        ! vector of "rho" values
      integer id_fun          ! xplasma id of profile function f(rho)
      integer iwant           ! 0: value, 1: df/drho, 2: d2f/drho2

 ! output:
      real*8 zval(ivec)       ! interpolation results, returned
      integer ierr            ! completion code, 0=OK
         ...
      call eq_rgetf(ivec,rho,id_fun,iwant,zval,ierr)

The error code will be set if either an invalid function id is
passed or if some of the "rho" values are out of range.

Note: iwant=2 is valid only if f(rho) is a cubic spline.

(b) for interpolation on a multiple profiles f(rho).  arguments are as
    above, except:

 ! input:
      integer nlist           ! length of list of xplasma ids
      integer id_funs(nlist)  ! list of xplasma function ids
      integer ivecd           ! output vector dimension

 ! output:
      real*8 zvals(ivecd,nlist)   ! interpolation results, all fcns
         ...
      call eq_rgetff(ivec,rho,nlist,id_funs,iwant,ivecd,
     >              zvals,ierr)

(c) for interpolation on a single profile f(x) prepared previously
by an eqm_f1d call:

 ! input:
      integer ivec            ! input data vector dimension
      real*8 x(ivec)          ! vector of "x" values
      integer id_fun          ! xplasma id of profile function f(x)
      integer iwant           ! 0: value, 1: df/dx, 2: d2f/dx2

 ! output:
      real*8 zval(ivec)       ! interpolation results, returned
      integer ierr            ! completion code, 0=OK
         ...
      call eq_xgetf(ivec,rho,id_fun,iwant,zval,ierr)

The error code will be set if either an invalid function id is
passed or if some of the "x" values are out of range.

Note: iwant=2 is valid only if f(x) is a cubic spline.
 
Home Top


_1d_interpolation_with_smoothing

(old f77 xplasma 1 documentation)

Two combined interpolation/smooth routines are provided, one for 
ordinary profiles, and one for integrated profiles (such as are output
by several NTCC physics modules).

For ordinary profiles: eq_rget_sm

For integrated profiles: eq_rget_binsm

Home Top


eq_rget_sm

subroutine eq_rget_sm(inrho,zrho,id,zdelta,zval,ierr)
  !
  !  return a profile interpolated and then smoothed.
  !  caution: not recommended for volume- or area-integrated profiles; see
  !    eq_rget_bin(...) or eq_rget_binsm(...)
  !
  implicit NONE

  integer, intent(in) :: inrho           ! target gridsize, must be .gt.1
  real*8, intent(in) :: zrho(inrho)      ! target grid-- strict ascending order

  integer, intent(in) :: id              ! function id of f(rho) profile

  real*8, intent(in) :: zdelta           ! smoothing parameter

  !  zdelta defines the base half-width of a triangular weighting function
  !  used for smoothing.  The smoothed output profile at each rho is
  !  weighted average of the original function over the range
  !    (rho-zdelta,rho+zdelta) with weight 1/zdelta at rho linearly
  !  declining to weight 0 at the end points.  (area of weighting 
  !  triangle is unity).

  real*8, intent(out) :: zval(inrho)     ! results of smoothed interpolation

  !  zval(rho) is a weighted average of the original profile over the
  !            range [rho-zdelta,rho+zdelta] with a triangular weighting
  !            function whose weight goes to 0 at the interval enpoints.

  integer ierr  ! completion code 0=OK

Home Top


eq_rget_bin

subroutine eq_rget_bin(inrho,zrho,id,iint,zval,ierr)
  !
  !  given an integrated profile function id,
  !  return an integrated profile on the user's grid.
  !
  !  if the interpolation order is >1, just do an interpolation.
  !  if the interpolation order is =1 (piecewise linear), do an integration
  !  of the step function of the inferred density
  !
  implicit NONE

  integer, intent(in) :: inrho           ! target gridsize, must be .gt.1
  real*8, intent(in) :: zrho(inrho)      ! target grid-- strict ascending order

  integer, intent(in) :: id              ! function id of f(rho) profile

  integer, intent(in) :: iint            ! data type id
  !  iint=1 -- area integral profile being smoothed -- 
  !            Examples: current density profiles
  !  iint=2 -- volume integral profile being smoothed -- 
  !            Examples: density, energy density, ptcl/power/momentum source
  !                      functions, ...
  !
  real*8, intent(out) :: zval(inrho)     ! results of interpolation/integration

  integer ierr  ! completion code 0=OK

Home Top


eq_rget_binsm

subroutine eq_rget_binsm(inrho,zrho,id,zdelta,iint,zval,ierr)
  !
  !  given an integrated profile function id,
  !
  !  return an integrated profile, smoothed onto the user's grid
  !  from the step-function defined by binning the density on the function's
  !  original grid.
  !
  implicit NONE

  integer, intent(in) :: inrho           ! target gridsize, must be .gt.1
  real*8, intent(in) :: zrho(inrho)      ! target grid-- strict ascending order

  integer, intent(in) :: id              ! function id of f(rho) profile

  real*8, intent(in) :: zdelta           ! smoothing parameter
                                         ! if <0, zdelta=delta(rho) assumed.

  integer, intent(in) :: iint            ! data type id
  !  iint=1 -- area integral profile being smoothed -- 
  !            Examples: current density profiles
  !  iint=2 -- volume integral profile being smoothed -- 
  !            Examples: density, energy density, ptcl/power/momentum source
  !                      functions, ...
  !
  !    for iint > 0, the data is binned on the original grid, but smoothed
  !    on the user grid.  The unsmoothed unintegrated profile (e.g. density 
  !    profile) becomes a step function with step widths matching the original
  !    grid of the data.  It is smoothed using a triangular weighting function
  !    whose base half-width (smoothing parameter) is  zdelta.
  !
  !    If the smoothing parameter is too small, the step-
  !    function-like behavior of the binned density profile will remain 
  !    evident in the result
  !
  !      zdelta =~ delta(rho)
  !
  !    is recommended, where delta(rho) is the stepsize of the function's
  !    underlying rho grid.  The recommended value is used if the passed
  !    value for zdelta is < 0.  If zdelta=0, no smoothing occurs.
  !    if zdelta > 0, smoothing occurs using the user specified zdelta.
  !
  !    note that the result is independent of the interpolating function
  !    xplasma has for the (integrated) profile function #id.
  !
  !  NOTE: smoothing integrated profiles directly, e.g. with eq_rget_sm,
  !    is hazardous, because, if d/dV of the smoothed result is evaluated
  !    near the axis it will generally have a pole singularity there.

  real*8, intent(out) :: zval(inrho)     ! results of smoothed interpolation

  !  zval(rho) is a weighted average of the original profile over the
  !            range [rho-zdelta,rho+zdelta] with a triangular weighting
  !            function whose weight goes to 0 at the interval endpoints.

  integer ierr  ! completion code 0=OK

Home Top


_2d_f(rho,chi)_interpolation

(old f77 xplasma 1 documentation)

When a given function or set of functions is known to be represented 
in f(rho,chi) form, the fastest interpolation routines are:

   eq_frhochi -- for a given set of (rho,chi) target points, 
             return the values of all functions on the function 
             list.

   eq_grhochi -- for a given set of (rho,chi) target points, return
             the df/drho and df/dchi of all functions on the 
             function list.

   eq_hrhochi -- for a given set of (rho,chi) target points, return
             a user specified combination of values and derivatives
             (up to 2nd order derivatives).  The user specifies what
             is wanted via the "ictwant" integer array.

 ! input:
      integer ivec            ! vector dimension (vector of coordinates)
      real*8 zrho(ivec)       ! rho of target points
      real*8 zchi(ivec)       ! chi of target points
      integer nlist           ! number of functions in function list
      integer ifcns(nlist)    ! function ids of functions wanted
 !
      integer ivecd           ! 1st (vector) dimension of output buffer

 ! eq_frhochi output:

      real*8 fans(ivecd,nlist) ! function values returned
                               !  fans(j,k) = value of k'th function
                               !              at zrho(j),zchi(j)

 ! eq_grhochi output:

      real*8 gans(ivecd,2,nlist) ! df/drho, df/dchi values returned
                               !  gans(j,1,k) = df/drho of k'th function
                               !              at zrho(j),zchi(j)
                               !  gans(j,2,k) = df/dchi of k'th function
                               !              at zrho(j),zchi(j)

 ! output (for both):
      integer ierr             ! completion code, 0=OK


   ... ...

      call eq_frhochi(ivec,zrho,zchi,nlist,ifcns,ivecd,fans,ierr)

   ... ...

      call eq_grhochi(ivec,zrho,zchi,nlist,ifcns,ivecd,gans,ierr)

To have "zchi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

Home Top


eq_hrhochi

(old f77 xplasma 1 documentation)

This routine has the same arguments as "eq_frhochi" and "eq_grhochi"
except this input array:

      integer ictwant(6)    ! selector array

 !
 !  each element of ictwant(1:6) should be 0 or 1
 !  use 1 to indicate a desired item; use 0 otherwise:
 !
 !   ictwant(1) -- function values        
 !   ictwant(2) -- functions' df/drho values
 !   ictwant(3) -- functions' df/dchi values
 !   ictwant(4) -- functions' d2f/drho2 values
 !   ictwant(5) -- functions' d2f/dchi2 values
 !   ictwant(6) -- functions' d2f/drhodchi values

and the output array is interpreted differently:

      REAL*8 zans(ivecd,nlist*max(1,sum(ictwant))) ! results
 !
 !  ** let ictnum = # of non-zero elements of ictwant.  
 !         (ictnum=sum(ictwant)).  Then...
 !  zans(1:ivec,1)   = value or derivative for function id iflist(1)
 !                     indicated by first non-zero value of ictwant(...)
 !  zans(1:ivec,2)   = value or derivative for function id iflist(1)
 !                     indicated by second non-zero value of ictwant(...)
 !    ...
 !  zans(1:ivec,ictnum)   = value or derivative for function id iflist(1)
 !                     indicated by last non-zero value of ictwant(...)
 !
 !  or generally, 
 !      for 1 .le. j .le. nlist
 !      for 1 .le. k .le. ictnum, 
 !    ...
 !  zans(1:ivec,(j-1)*ictnum+k) = value or derivative for function
 !                                id iflist(j), corresponding to k'th
 !                                non-zero element of ictwant(...)
 !
   ... ...

      call eq_hrhochi(ivec,zrho,zchi,nlist,ifcns,                    &
     &                ictwant,ivecd,gans,ierr)


To have "zchi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

Home Top


_2d_f(R,Z)_interpolation

(old f77 xplasma 1 documentation)

When a given function or set of functions is known to be represented 
in f(R,Z) form, the fastest interpolation routines are:

   eq_fRZ -- for a given set of (R,Z) target points, return the
             values of all functions on the function list.

   eq_gRZ -- for a given set of (R,Z) target points, return
             the df/dR and df/dZ of all functions on the function
             list.

   eq_hRZ -- for a given set of (R,Z) target points, return
             a user specified set of values and derivatives up
             to 2nd order.

 ! input:
      integer ivec            ! vector dimension (vector of coordinates)
      real*8 zR(ivec)         ! R of target points
      real*8 zZ(ivec)         ! Z of target points
      integer nlist           ! number of functions in function list
      integer ifcns(nlist)    ! function ids of functions wanted
 !
      integer ivecd           ! 1st (vector) dimension of output buffer

 ! eq_fRZ output:

      real*8 fans(ivecd,nlist) ! function values returned
                               !  fans(j,k) = value of k'th function
                               !              at zR(j),zZ(j)

 ! eq_gRZ output:

      real*8 gans(ivecd,2,nlist) ! function df/dR, df/dZ values returned
                               !  gans(j,1,k) = df/dR of k'th function
                               !              at zR(j),zZ(j)
                               !  gans(j,2,k) = df/dZ of k'th function
                               !              at zR(j),zZ(j)

 ! output (for both):
      integer ierr             ! completion code, 0=OK


   ... ...

      call eq_fRZ(ivec,zR,zZ,nlist,ifcns,ivecd,fans,ierr)

   ... ...

      call eq_gRZ(ivec,zR,zZ,nlist,ifcns,ivecd,gans,ierr)

Home Top


eq_hRZ

(old f77 xplasma 1 documentation)

This routine has the same arguments as "eq_fRZ" and "eq_gRZ"
except this input array:

      integer ictwant(6)    ! selector array

 !
 !  each element of ictwant(1:6) should be 0 or 1
 !  use 1 to indicate a desired item; use 0 otherwise:
 !
 !   ictwant(1) -- function values        
 !   ictwant(2) -- functions' df/dR values
 !   ictwant(3) -- functions' df/dZ values
 !   ictwant(4) -- functions' d2f/dR2 values
 !   ictwant(5) -- functions' d2f/dZ2 values
 !   ictwant(6) -- functions' d2f/dRdZ values

and the output array is interpreted differently:

      REAL*8 zans(ivecd,nlist*max(1,sum(ictwant))) ! results
 !
 !  ** let ictnum = # of non-zero elements of ictwant.  
 !         (ictnum=sum(ictwant)).  Then...
 !  zans(1:ivec,1)   = value or derivative for function id iflist(1)
 !                     indicated by first non-zero value of ictwant(...)
 !  zans(1:ivec,2)   = value or derivative for function id iflist(1)
 !                     indicated by second non-zero value of ictwant(...)
 !    ...
 !  zans(1:ivec,ictnum)   = value or derivative for function id iflist(1)
 !                     indicated by last non-zero value of ictwant(...)
 !
 !  or generally, 
 !      for 1 .le. j .le. nlist
 !      for 1 .le. k .le. ictnum, 
 !    ...
 !  zans(1:ivec,(j-1)*ictnum+k) = value or derivative for function
 !                                id iflist(j), corresponding to k'th
 !                                non-zero element of ictwant(...)
 !
   ... ...

      call eq_hRZ(ivec,zR,zZ,nlist,ifcns,                    &
     &                ictwant,ivecd,zans,ierr)

Home Top


general_interpolation

(old f77 xplasma 1 documentation)

A set of routines exists to find values and gradients of a
set of functions, whose representation might be known a priori
to the caller.

There are 3 series of functions:

 eqxyz_*get -- given vectors of (x,y,z) coordinates, return
               function values, gradients (d/dx,d/dy,d/dz),
               Bfield vector, and Bfield gradient tensor.
               (rho,chi,phi) vectors can also be obtained.

 eqrz_*get  -- given vectors of (R,Z,phi) coordinates, return
               function values, gradients (d/dR,d/dZ,1/R*d/dphi),
               Bfield vector, and Bfield gradient tensor.
               (rho,chi,phi) vectors can also be obtained.

 eq_*get    -- given vectors of (rho,chi,phi), return function
               values, gradients, Bfield vector, and Bfield
               gradient tensor.  (R,Z,phi) vectors can also
               be obtained.  The gradients and field can be
               returned in cylindric- or flux-surface aligned
               coordinates:

c     if irzmode=1:  (df/dR,df/dZ,(1/R)*df/dphi) @ (rho,chi,phi)
c     if irzmode=0:  (df/dsperp,df/dschi,(1/R)*df/dphi) @ (rho,chi,phi)

               where sperp denotes ds in a flux durface normal
               direction, and dschi denotes ds tangential to the 
               surface in the poloidal plane.  Similarly, the
               the field will be returned with irzmode=1 as
               (BR,BZ,Bphi), or (0,Bchi,Bphi) for irzmode=0.

Home Top


performance_considerations

(old f77 xplasma 1 documentation)

(1)  it is faster to use eq_frz or eq_frhochi, if the function
representation is known a priori, then to use eq*get*.  However,
eq*get* have the "smarts" to define the field and gradients in
various coordinate systems, whereas eq_frz and eq_frhochi just
return function values and derivatives.

(2)  vectorization and function grouping...

Performance is improved both by using vectors of target points
rather than individual target points, and, by evaluating groups
of functions together, rather than each function individually.

On cache oriented workstations, for a fixed total number of
evaluations, we have seen factors of 25 (!) performance difference
by evaluating individual functions one target point at a time, vs.
evaluating groups of 10 functions in a single calls with target
vectors of length 100.  (This of course gives a 1000:1 difference
in the amount of data returned by a single interpolation call).
We think we are seeing the power of workstation data and 
instruction caches in these performace figures.

Tests were done on an Alpha 500au running DEC UNIX / compaq
fortran, and on an Intel P-II 400MHz Linux running fujitsu
fortran -- with similar scaling results.

(DEC alpha 500au results):
jupiter.pppl.gov 7 Jun 2000:

  500,000 function evaluations (10 functions x 50,000 target pts):
  cpu time, seconds

            function evaluations per cal
  vector    Nfcn=1     Nfcn=10
   size

    1        15.24       2.52

    10        4.88        .77

    100       4.07        .61


Home Top


eqxyz_*get

(old f77 xplasma 1 documentation)

generic interface (f90):

For routines involving flux coordinates:

To have "zchi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

      use xplasma_get
      ...
      call eqxyz_get(...)

specific interfaces (f77/f90):

arguments used by this series of routines:

 ! input:
      integer ivec            ! vector dimension (vector of coordinates)
      real*8 xx(ivec)         ! x coordinate, each vector element
      real*8 yy(ivec)         ! y coordinate, each vector element
      real*8 zz(ivec)         ! z coordinate, each vector element

 ! output:
      real*8 zrho(ivec)       ! rho coordinate, each vector element
      real*8 zchi(ivec)       ! chi coordinate, each vector element
      real*8 zphi(ivec)       ! phi coordinate, each vector element

 ! input:

      real*8 ztol             ! rel. tolerance for coord. mapping
                              !   (rho,chi,phi) maps to (x',y',z')
                              !   with max(|x-x'|,|y-y'|,|z-z'|)
                              !        .le. tol*[R of mag. axis].
 ! output:

      real*8 bvec(3,ivec)     ! field vector at each target point
      real*8 gbtensr(3,3,ivec) ! gbtensr(1:3,j,k)=grad(bvec(j,k))

 ! input:

      integer ifcn            ! a single fcn id, or...

      integer nlist           ! no. of fcns to evaluate
      integer ifcns(nlist)    ! list of fcn ids
      integer ivecd           ! vector dimension for output arrays

 ! output:

      real*8 fval(ivec)       ! function values, (single function)
      real*8 fgrad(3,ivec)    ! function gradient (single function)

      ! ..or..

      real*8 fvals(ivecd,nlist)    ! function values returned
      real*8 fgrads(3,ivecd,nlist) ! function gradients returned.

      integer nregion(ivec)   ! region code for each target point
                              !   for target point j:
                              !     nregion(j)=1:  core plasma
                              !     nregion(j)=2:  scrape off layer
                              !     nregion(j)=3:  outside limiter
                              !     nregion(j)=4:  beyond (R,Z) grid

      integer ierr            ! completion code, 0=OK
                              ! ierr.ne.0 means a "serious error".

 ! note:  B field is [Bx,By,Bz].
 ! all gradients are:  [d/dx,d/dy,d/dz].

 --->(return values of a single function)
 (f only)
      CALL eqxyz_fget(ivec,xx,yy,zz,ztol,ifcn,fval,nregion,ierr)

 (f, grad(f))
      CALL eqxyz_fgrad(ivec,xx,yy,zz,ztol,ifcn,
     >   fval,fgrad,nregion,ierr)

 (f, (rho,chi,phi))
      CALL eqxyzmap_fget(ivec,xx,yy,zz,zrho,zchi,zphi,ztol,
     >   ifcn,fval,nregion,ierr)

 (f, grad(f), (rho,chi,phi))
      CALL eqxyzmap_fgrad(ivec,xx,yy,zz,zrho,zchi,zphi,ztol,
     >   ifcn,fval,fgrad,nregion,ierr)

 -->(return values of multiple functions)
 (f only)
      CALL eqxyz_ffget(ivec,xx,yy,zz,ztol,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f))
      CALL eqxyz_ffgrad(ivec,xx,yy,zz,ztol,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 (f, (rho,chi,phi))
      CALL eqxyzmap_ffget(ivec,xx,yy,zz,zrho,zchi,zphi,
     >   ztol,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), (rho,chi,phi))
      CALL eqxyzmap_ffgrad(ivec,xx,yy,zz,zrho,zchi,zphi,
     >   ztol,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 -->(return values of B field only)
 (B only)
      CALL eqxyz_bget(ivec,xx,yy,zz,ztol,bvec,nregion,ierr)

 (B, grad(B))
      CALL eqxyz_bgrad(ivec,xx,yy,zz,ztol,bvec,gbtensr,nregion,
     >   ierr)

 (B, (rho,chi,phi))
      CALL eqxyzmap_bget(ivec,xx,yy,zz,zrho,zchi,zphi,ztol,
     >   bvec,nregion,ierr)

 (B, grad(B), (rho,chi,phi))
      CALL eqxyzmap_bgrad(ivec,xx,yy,zz,zrho,zchi,zphi,ztol,
     >   bvec,gbtensr,nregion,ierr)

 -->(return values of B field & multiple functions)
 (f, B only)
      CALL eqxyz_bffget(ivec,xx,yy,zz,ztol,bvec,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), B, grad(B))
      CALL eqxyz_bffgrad(ivec,xx,yy,zz,ztol,bvec,gbtensr,
     >   nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 (f, B, (rho,chi,phi))
      CALL eqxyzmap_bffget(ivec,xx,yy,zz,zrho,zchi,zphi,
     >   ztol,bvec,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), B, grad(B), (rho,chi,phi))
      CALL eqxyzmap_bffgrad(ivec,xx,yy,zz,zrho,zchi,zphi,
     >   ztol,bvec,gbtensr,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

Home Top


eqrz_*get

(old f77 xplasma 1 documentation)

generic interface (f90):

      use xplasma_get
      ...
      call eqrz_get(...)

For routines using flux coordinate:
To have "zchi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

specific interfaces (f77/f90):

arguments used by this series of routines:

 ! input:
      integer ivec            ! vector dimension (vector of coordinates)
      real*8 zR(ivec)         ! R coordinate, each vector element
      real*8 zZ(ivec)         ! Z coordinate, each vector element
      real*8 zphi(ivec)       ! phi coordinate, each vector element

 ! output:
      real*8 zrho(ivec)       ! rho coordinate, each vector element
      real*8 zchi(ivec)       ! chi coordinate, each vector element

 ! input:

      real*8 ztol             ! rel. tolerance for coord. mapping
                              !   (rho,chi,phi) maps to (x',y',z')
                              !   with max(|x-x'|,|y-y'|,|z-z'|)
                              !        .le. tol*[R of mag. axis].
 ! output:

      real*8 bvec(3,ivec)     ! field vector at each target point
      real*8 gbtensr(3,3,ivec) ! gbtensr(1:3,j,k)=grad(bvec(j,k))

 ! input:

      integer ifcn            ! a single fcn id, or...

      integer nlist           ! no. of fcns to evaluate
      integer ifcns(nlist)    ! list of fcn ids
      integer ivecd           ! vector dimension for output arrays

 ! output:

      real*8 fval(ivec)       ! function values, (single function)
      real*8 fgrad(3,ivec)    ! function gradient (single function)

      ! ..or..

      real*8 fvals(ivecd,nlist)    ! function values returned
      real*8 fgrads(3,ivecd,nlist) ! function gradients returned.

      integer nregion(ivec)   ! region code for each target point
                              !   for target point j:
                              !     nregion(j)=1:  core plasma
                              !     nregion(j)=2:  scrape off layer
                              !     nregion(j)=3:  outside limiter
                              !     nregion(j)=4:  beyond (R,Z) grid

      integer ierr            ! completion code, 0=OK
                              ! ierr.ne.0 means a "serious error".

 ! note:  B field is [BR,BZ,Bphi].
 ! all gradients are:  [d/dR,d/dZ,(1/R)d/dphi].

 --->(return values of a single function)
 (f only)
      CALL eqrz_fget(ivec,zR,zZ,zphi,ztol,ifcn,fval,nregion,ierr)

 (f, grad(f))
      CALL eqrz_fgrad(ivec,zR,zZ,zphi,ztol,ifcn,
     >   fval,fgrad,nregion,ierr)

 (f, (rho,chi))
      CALL eqrzmap_fget(ivec,zR,zZ,zphi,zrho,zchi,ztol,
     >   ifcn,fval,nregion,ierr)

 (f, grad(f), (rho,chi))
      CALL eqrzmap_fgrad(ivec,zR,zZ,zphi,zrho,zchi,ztol,
     >   ifcn,fval,fgrad,nregion,ierr)

 -->(return values of multiple functions)
 (f only)
      CALL eqrz_ffget(ivec,zR,zZ,zphi,ztol,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f))
      CALL eqrz_ffgrad(ivec,zR,zZ,zphi,ztol,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 (f, (rho,chi))
      CALL eqrzmap_ffget(ivec,zR,zZ,zphi,zrho,zchi,
     >   ztol,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), (rho,chi))
      CALL eqrzmap_ffgrad(ivec,zR,zZ,zphi,zrho,zchi,
     >   ztol,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 -->(return values of B field only)
 (B only)
      CALL eqrz_bget(ivec,zR,zZ,zphi,ztol,bvec,nregion,ierr)

 (B, grad(B))
      CALL eqrz_bgrad(ivec,zR,zZ,zphi,ztol,bvec,gbtensr,nregion,
     >   ierr)

 (B, (rho,chi))
      CALL eqrzmap_bget(ivec,zR,zZ,zphi,zrho,zchi,ztol,
     >   bvec,nregion,ierr)

 (B, grad(B), (rho,chi))
      CALL eqrzmap_bgrad(ivec,zR,zZ,zphi,zrho,zchi,ztol,
     >   bvec,gbtensr,nregion,ierr)

 -->(return values of B field & multiple functions)
 (f, B only)
      CALL eqrz_bffget(ivec,zR,zZ,zphi,ztol,bvec,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), B, grad(B))
      CALL eqrz_bffgrad(ivec,zR,zZ,zphi,ztol,bvec,gbtensr,
     >   nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 (f, B, (rho,chi))
      CALL eqrzmap_bffget(ivec,zR,zZ,zphi,zrho,zchi,
     >   ztol,bvec,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), B, grad(B), (rho,chi))
      CALL eqrzmap_bffgrad(ivec,zR,zZ,zphi,zrho,zchi,
     >   ztol,bvec,gbtensr,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

Home Top


eq_*get

(old f77 xplasma 1 documentation)

generic interface (f90):

      use xplasma_get
      ...
      call eq_get(...)

To have "zchi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

specific interfaces (f77/f90):

arguments used by this series of routines:

 ! input:
      integer ivec            ! vector dimension (vector of coordinates)
      real*8 zrho(ivec)       ! rho coordinate, each vector element
      real*8 zchi(ivec)       ! chi coordinate, each vector element
      real*8 zphi(ivec)       ! phi coordinate, each vector element

 ! output:
      real*8 zR(ivec)         ! R coordinate, each vector element
      real*8 zZ(ivec)         ! Z coordinate, each vector element

 ! input:

      integer irzmode         ! =1:  output B & grads in (R,Z,phi)
                              ! =0:  output B & grads in (sperp,chi,phi)

 ! output:

      real*8 bvec(3,ivec)     ! field vector at each target point
      real*8 gbtensr(3,3,ivec) ! gbtensr(1:3,j,k)=grad(bvec(j,k))

 ! input:

      integer ifcn            ! a single fcn id, or...

      integer nlist           ! no. of fcns to evaluate
      integer ifcns(nlist)    ! list of fcn ids
      integer ivecd           ! vector dimension for output arrays

 ! output:

      real*8 fval(ivec)       ! function values, (single function)
      real*8 fgrad(3,ivec)    ! function gradient (single function)

      ! ..or..

      real*8 fvals(ivecd,nlist)    ! function values returned
      real*8 fgrads(3,ivecd,nlist) ! function gradients returned.

      integer nregion(ivec)   ! region code for each target point
                              !   for target point j:
                              !     nregion(j)=1:  core plasma
                              !     nregion(j)=2:  scrape off layer
                              !     nregion(j)=3:  outside limiter
                              !     nregion(j)=4:  beyond (R,Z) grid

      integer ierr            ! completion code, 0=OK
                              ! ierr.ne.0 means a "serious error".

 ! note:  if irzmode.eq.1:
 !          B field is [BR,BZ,Bphi].
 !          all gradients are:  [d/dR,d/dZ,(1/R)d/dphi].
 !        if irzmode.eq.0:
 !          B field is [0,Bchi,Bphi]
 !          all gradients are:  [d/dsperp,d/dschi,(1/R)d/dphi]
 !             where dsperp is ds in the direction normal to the
 !                      flux surface, and, 
 !                   dschi is ds in the direction tangential to
 !                      the flux surface in the poloidal plane.

 --->(return values of a single function)
 (f only)
      CALL eq_fget(ivec,zrho,zchi,zphi,irzmode,ifcn,fval,nregion,
     >   ierr)

 (f, grad(f))
      CALL eq_fgrad(ivec,zrho,zchi,zphi,irzmode,ifcn,
     >   fval,fgrad,nregion,ierr)

 (f, (R,Z))
      CALL eqmap_fget(ivec,zrho,zchi,zphi,zR,zZ,irzmode,
     >   ifcn,fval,nregion,ierr)

 (f, grad(f), (R,Z))
      CALL eqmap_fgrad(ivec,zrho,zchi,zphi,zR,zZ,irzmode,
     >   ifcn,fval,fgrad,nregion,ierr)

 -->(return values of multiple functions)
 (f only)
      CALL eq_ffget(ivec,zrho,zchi,zphi,irzmode,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f))
      CALL eq_ffgrad(ivec,zrho,zchi,zphi,irzmode,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 (f, (R,Z))
      CALL eqmap_ffget(ivec,zrho,zchi,zphi,zR,zZ,
     >   irzmode,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, (R,Z))
      CALL eqmap_ffgrad(ivec,zrho,zchi,zphi,zR,zZ,
     >   irzmode,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 -->(return values of B field only)
 (B only)
      CALL eq_bget(ivec,zrho,zchi,zphi,irzmode,bvec,nregion,ierr)

 (B, grad(B))
      CALL eq_bgrad(ivec,zrho,zchi,zphi,irzmode,bvec,gbtensr,nregion,
     >   ierr)

 (B, (R,Z))
      CALL eqmap_bget(ivec,zrho,zchi,zphi,zR,zZ,irzmode,
     >   bvec,nregion,ierr)

 (B, grad(B), (R,Z))
      CALL eqmap_bgrad(ivec,zrho,zchi,zphi,zR,zZ,irzmode,
     >   bvec,gbtensr,nregion,ierr)

 -->(return values of B field & multiple functions)
 (f, B only)
      CALL eq_bffget(ivec,zrho,zchi,zphi,irzmode,bvec,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), B, grad(B))
      CALL eq_bffgrad(ivec,zrho,zchi,zphi,irzmode,bvec,gbtensr,
     >   nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

 (f, B, (R,Z))
      CALL eqmap_bffget(ivec,zrho,zchi,zphi,zR,zZ,
     >   irzmode,bvec,nlist,ifcns,
     >   ivecd,fvals,nregion,ierr)

 (f, grad(f), B, grad(B), (R,Z))
      CALL eqmap_bffgrad(ivec,zrho,zchi,zphi,zR,zZ,
     >   irzmode,bvec,gbtensr,nlist,ifcns,
     >   ivecd,fvals,fgrads,nregion,ierr)

Home Top


xplasma_get

(old f77 xplasma 1 documentation)

The fortran-90 module

      use xplasma_get

can be employed to allow the generic names

      call eq_get(...)
      call eqrz_get(...)
      call eqxyz_get(...)

for all of the interpolation routines described in the neighbouring
sections, and, the R4_ versions of the routines as well.

The xplasma_get module contains a description of all the specific
calls.  The compiler decides which one to call by analyzing the
calling arguments.

Caution#1:  "xplasma_get" and "xplasma_calls" cannot both be used
in the same routine;

Caution#2:  there exist functionally correct calls to the software
for which the fortran-90 compiler will fail to match up the proper
routine, giving a compile-time error instead.

The use of this module is optional.  In its absence, full 
subroutine names must be used.


Home Top


lists

(old f77 xplasma 1 documentation)

XPLASMA now supports a generic facility for creating and accessing lists.
Each list has a name (max 32 characters, one alphanumeric word, treated
as uppercase), a label (max 60 characters), and a size which specifies 
the number of elements in the list.

Each list element has a name (max 32 characters, one alphanumeric word,
treated as uppercase), and the following associated data:

  a character string (max 60 characters) in addition to the name
  a floating point number
  an integer.

Lists can be used to communicate such information as:

  -> a list of plasma spacies and the Z and A values of each species:

     name of example list: TR_THERMAL_SPECIES, size = 3
       (label: "list of thermal ion species")
          name       character data        floating data    integer data
           H          (blank)               1.000            1
           D          (blank)               2.000            1
           HE4        (blank)               4.000            2

     interpretation: floating data gives "A", integer gives "Z".

  -> a timestep

     name of example list: TR_TIMESTEP, size = 2
       (label: "timestep for TRANSP sources")
          name       character data        floating data    integer data
           TR_TS1     S                     1.010            0
           TR_TS2     S                     1.020            0

     interpretation: character data gives physical units, floating data
     gives actual time values.
     
  -> a collection of related profile data items

     name of example list: TR_EHEAT, size = 5
       (label: "integrated electron heating profiles")
          name       character data        floating data    integer data
           TR_PBE     W                     3.073e4          310
           TR_PFE     W                     0.000            311
           TR_PEICRF  W                     0.000            312
           TR_PEECRF  W                     0.000            313
           TR_PELH    W                     0.000            314

     interpretation: a list of heating profiles.  Character data gives
     physical units, floating data gives total amount (power, W, in this
     context), and the integer gives XPLASMA id of the interpolating
     function f(rho).

The methods for finding and accessing lists are described here.  Methods
for creating lists and list contents are described under "Setup Routines".

Home Top


eq_nlist

(old f77 xplasma 1 documentation)

To get the number of lists currently known to XPLASMA:

  integer :: num_lists   ! value returned by subroutine call

  call eq_nlist(num_lists)

Home Top


eq_lists

(old f77 xplasma 1 documentation)

To get the names and ids of *all* lists currently known to XPLASMA:

  ! input:
  integer :: num_lists   ! should match value returned by eq_nlists

  ! output:
  character*32 :: list_names(num_lists)   ! names of lists
  integer :: list_ids(num_lists)          ! list id codes
  integer :: ierr    ! completion code (0=OK)

  call eq_lists(num_lists,list_names,list_ids,ierr)

The list of names is retunred in alphabetic order.
To refer to a specific list, its id code is needed.

Home Top


eq_nlist_p

(old f77 xplasma 1 documentation)

To get the number of lists currently known to XPLASMA which contain
XPLASMA profile data:

  integer :: num_lists   ! value returned by subroutine call

  call eq_nlists(num_lists)

Home Top


eq_lists_p

(old f77 xplasma 1 documentation)

To get the names and ids of *all* lists containing XPLASMA profile data:

  ! input:
  integer :: num_lists   ! should match value returned by eq_nlists

  ! output:
  character*32 :: list_names(num_lists)   ! names of lists
  integer :: list_ids(num_lists)          ! list id codes
  integer :: ierr    ! completion code (0=OK)

  call eq_lists(num_lists,list_names,list_ids,ierr)

The list of names is retunred in alphabetic order.
To refer to a specific list, its id code is needed.

Home Top


eq_glistnum

(old f77 xplasma 1 documentation)

To find the list_id associated with a specific list name:

  ! input:
  character*32 :: list_name     ! name of a specific list

  ! output:
  integer :: list_id            ! corresponding id code

  call eq_glistnum(list_name,list_id)

If there is no such list in the current XPLASMA, list_id = 0 is returned.

Home Top


eq_list_size

(old f77 xplasma 1 documentation)

To find the size (number of elements) of a specific list:

  ! input:
  integer :: list_id            ! id of an existing list

  ! output:
  integer :: isize              ! list size (no. of elements)

  call eq_list_size(list_id,list_size)

If the id is invalid, list_size = 0 is returned.

Home Top


eq_list_maxsize

(old f77 xplasma 1 documentation)

To find them maximum number of elements (isze) of any list:

  ! output:
  integer :: max_size

  call eq_list_maxSize(max_size)

If there are no lists, max_size = 0 is returned.

Home Top


eq_list_label

(old f77 xplasma 1 documentation)

To fetch the label for a list:

  ! input:
  integer :: list_id            ! id of an existing list

  ! output:
  character*60 alabel           ! list label (arb. string) returned

  call eq_list_label(list_id,alabel)

Home Top


eq_list_enames

(old f77 xplasma 1 documentation)

To get list element names:

  ! input:
  integer :: list_id         ! id of an existing list
  integer :: list_size       ! size of list (should match eq_list_size value)

  ! output:
  character*32 :: enames(list_size)   ! list element names returned.
  integer :: ierr            ! completion code, 0=OK

  call eq_list_enames(list_id,list_size,enames,ierr)

ierr is set, and enames = " " returned, if the list id is invalid or if the
list_size value is less than the actual size of the list.

Home Top


eq_list_ivals

(old f77 xplasma 1 documentation)

To get integer data associated with each list element:

  ! input:
  integer :: list_id         ! id of an existing list
  integer :: list_size       ! size of list (should match eq_list_size value)

  ! output:
  integer :: ivals(list_size)   ! integer list data
  integer :: ierr            ! completion code, 0=OK

  call eq_list_ivals(list_id,list_size,ivals,ierr)

ierr is set, and ivals = 0 returned, if the list id is invalid or if the
list_size value is less than the actual size of the list.

Home Top


eq_list_chvals

(old f77 xplasma 1 documentation)

To get character data associated with each list element:

  ! input:
  integer :: list_id         ! id of an existing list
  integer :: list_size       ! size of list (should match eq_list_size value)

  ! output:
  character*60 :: chvals(list_size)   ! character data with each list element
  integer :: ierr            ! completion code, 0=OK

  call eq_list_chvals(list_id,list_size,chvals,ierr)

ierr is set, and chvals = " " returned, if the list id is invalid or if the
list_size value is less than the actual size of the list.

Home Top


eq_list_r8vals

(old f77 xplasma 1 documentation)

To get floating point data associated with each list element:

  ! input:
  integer :: list_id         ! id of an existing list
  integer :: list_size       ! size of list (should match eq_list_size value)

  ! output:
  real*8 :: r8vals(list_size)   ! floating point list data
  integer :: ierr            ! completion code, 0=OK

  call eq_list_r8vals(list_id,list_size,r8vals,ierr)

ierr is set, and r8vals = 0 returned, if the list id is invalid or if the
list_size value is less than the actual size of the list.

Home Top


eq_list_r4vals

(old f77 xplasma 1 documentation)

To get floating point data associated with each list element:

  ! input:
  integer :: list_id         ! id of an existing list
  integer :: list_size       ! size of list (should match eq_list_size value)

  ! output:
  real :: r4vals(list_size)     ! floating point list data
  integer :: ierr            ! completion code, 0=OK

  call eq_list_r4vals(list_id,list_size,r4vals,ierr)

ierr is set, and r4vals = 0 returned, if the list id is invalid or if the
list_size value is less than the actual size of the list.

Home Top


jacobian_matrix

(old f77 xplasma 1 documentation)

for irzmode=0:
  This routine finds the jacobian matrix d[x,y,z]/d[rho,chi,phi]
  for each point from a set of (rho,chi,phi) vectors.
for irzmode=1:
  this routine returns the jacobian matrix
  d[R,Z,Lphi]/d[rho,chi,phi]; 
            Lphi=(spatial displacement in phi direction -- R*phi)
  in axisymmetric case:  [(dR/drho) (dR/dchi)  0 ]
                         [(dZ/drho) (dZ/dchi)  0 ]
                         [   0         0       R ]
                  and det(J)= 
                       -R*((dR/drho)*(dZ/dchi)-(dR/dchi)*(dZ/drho))
                        (-sign as (R,Z,phi) is left-handed)

 ! input:
      integer ivec            ! vector dimension (vector of coordinates)
      real*8 rho(ivec)        ! rho coordinate, each vector element
      real*8 chi(ivec)        ! chi coordinate, each vector element
      real*8 phi(ivec)        ! phi coordinate, each vector element

 ! output:
      real*8 jtens(3,3,ivec)  ! Jacobian
      real*8 detj(ivec)       ! det(jtens), determinant
 !                         **** det(jtens) not dependent on irzmode
 !
      integer ierr            ! completion code, 0=OK

 ! notes for (irzmode=0):
 !  jtens(1:3,1,1:ivec) = (dx/drho,dx/dchi,dx/dphi), all elements
 !  jtens(1:3,2,1:ivec) = (dy/drho,dy/dchi,dy/dphi), all elements
 !  jtens(1:3,3,1:ivec) = (dz/drho,dz/dchi,dz/dphi), all elements
 !
 ! notes for (irzmode=1):
 !  jtens(1:3,1,1:ivec) = (dR/drho,dR/dchi,dR/dphi), all elements
 !  jtens(1:3,2,1:ivec) = (dZ/drho,dZ/dchi,dZ/dphi), all elements
 !  jtens(1:3,3,1:ivec) = R*(dphi/drho,dphi/dchi,1), all elements
 !
         ...
         ...

      call eq_getjac(ivec,rho,chi,phi,irzmode,jtens,detj,ierr)

To have "chi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

Home Top


determinant_of_jacobian

(old f77 xplasma 1 documentation)

  This routine returns the determinant of the jacobian matrix
  d[R,Z,Lphi]/d[rho,chi,phi]; 
            Lphi=(spatial displacement in phi direction -- R*phi)
  in axisymmetric case:  [(dR/drho) (dR/dchi)  0 ]
                         [(dZ/drho) (dZ/dchi)  0 ]
                         [   0         0       R ]

                  and det(J)= 
                       -R*((dR/drho)*(dZ/dchi)-(dR/dchi)*(dZ/drho))
                        (-sign as (R,Z,phi) is left-handed)

 ! input:
      integer ivec            ! vector dimension (vector of coordinates)
      real*8 rho(ivec)        ! rho coordinate, each vector element
      real*8 chi(ivec)        ! chi coordinate, each vector element
      real*8 phi(ivec)        ! phi coordinate, each vector element

      real*8 zscale           ! scale factor to apply to result (e.g. 1.0)

 ! output:
      real*8 detj(ivec)       ! det(jtens), determinant
 !
      integer ierr            ! completion code, 0=OK

      call eq_getdetj(ivec,rho,chi,phi,zscale,detj,ierr)

To have "chi" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

Home Top


distance_to_plasma

(old f77 xplasma 1 documentation)

The following routines can be used to determine the distance from
any point in space to a specified surface on the plasma (usually
the plasma boundary).  These routines have the convention that if
the returned distance is positive, the point is outside the surface
by the given amount; if the distance is negative, the point is inside
by the given amount.

(a) distance of cartesian coordinate point(s) (x,y,z) to plasma 
    boundary --fast, approximate solution

    subroutine eqx_dfast(ivec,x,y,z,dist,ierr)

(b) distance of cylindrical coordinate point(s) (R,Z,phi) to plasma
    boundary --fast, approximate solution

    subroutine eq_dfast(ivec,R,Z,phi,dist,ierr)

To have "chi_out" interpreted as lying on a reversed (clockwise oriented)
poloidal angle grid, substitute a negative number -ivec for ivec in the
calling argument list.

(c) distance of cartesian coordinate point(s) (x,y,z) to any "rho"
    surface in plasma --slow, precise solution

    subroutine eqx_bdfind(ivec,x,y,z,rho_in,chi_out,phi_out,dist,ierr)

(d) distance of cylindrical coordinate point(s) (R,Z,phi) to any "rho"
    surface in plasma --slow, precise solution

    subroutine eq_bdfind(ivec,R,Z,phi,rho_in,chi_out,phi_out,dist,ierr)

The fast routines function by using a bilinear lookup on a table of
precomputed exact solutions; the precise routines solve the distance
minimization problem to high accuracy with a root finder, and also
give the (chi,phi) of the nearest point on the requested rho surface.

Note:  the data for the fast evaluations are only available after the
limiters and (R,Z) grid have been set up.  If this setup is not done,
the code reverts to the accurate but slow method.

The routines share many arguments:

 ! input:
      integer ivec             ! vector dimension, no. of pts to solve
      real*8 x(ivec),y(ivec),z(ivec)   ! cartesian coordinate points
 ! or...
      real*8 R(ivec),Z(ivec),phi(ivec) ! cylindrical coordinate points
 !
 ! extra input, bdfind routines:
 !
      real*8 rho_in            ! "rho" of desired surface
 !
 ! output:
      real*8 dist(ivec)        ! distance to bdy or selected surface
                               ! .gt.0 -- outside, .lt.0 -- inside
                               ! .eq.0 -- the point is on the surface.

      integer ierr             ! completion code, 0=OK
 !
 ! extra output, bdfind routines:
 !
      real*8 chi_out(ivec)  ! "chi" of nearest point on target surface
      real*8 phi_out(ivec)  ! "phi" of nearest point on target surface

Home Top


distance_to_limiter

(old f77 xplasma 1 documentation)

The following routines compute the distance from given points to the
nearest limiter.  If the distance is positive, the point is behind the
limiter by the given amount; if the distance is negative, the point is
on the plasma side of the limiter by the given amount.

(a) distance of cartesian coordinate point(s) (x,y,z) to limiter

    subroutine eqx_dist(ivec,x,y,z,dist,ilopt,Rlim,Zlim,philim,ierr)

(b) distance of cylindrical coordinate point(s) (R,Z,phi) to limiter

    subroutine eq_rzdist(ivec,R,Z,phi,dist,ilopt,Rlim,Zlim,philim,ierr)

For both of these routines, if the control flag "iopt" is set, then,
the cylindrical coordinates of nearest limiter point are also returned.

The arguments are:

 ! input:
      integer ivec             ! vector dimension, no. of pts to solve
      real*8 x(ivec),y(ivec),z(ivec)   ! cartesian coordinate points
 ! or...
      real*8 R(ivec),Z(ivec),phi(ivec) ! cylindrical coordinate points

 ! output:
      real*8 dist(ivec)        ! distance to limiter
                               ! .gt.0 -- outside, .lt.0 -- inside
                               ! .eq.0 -- the point is on the limiter.

 ! input:
      integer ilopt            ! if ilopt=1, compute Rlim,Zlim,philimm

 ! output, only if ilopt.eq.1 ...

      real*8 Rlim(ivec)        ! R of nearest limiter point
      real*8 Zlim(ivec)        ! Z of nearest limiter point
      real*8 philim(ivec)      ! phi of nearest limiter point

 ! general output:
      integer ierr             ! completion code, 0=OK

Home Top


segment_bdy_locator

(old f77 xplasma 1 documentation)

It sometimes happens that one has a line segment AB, such that
A is outside and B is inside a boundary (either the limiter
boundary or the core plasma boundary), and the need is to find
the point on AB which intersects the boundary in question.

The vectorized routine eq_fxcep can be used to find such segment
boundary intersections:

 ! input:
      integer ivec             ! vector dimension (# of segments)
      integer itype            ! =1: want plasma bdy; =2: limiter
      integer idinit           ! =1: endpoint distances are known

 ! more input:
      real*8 ra(ivec),za(ivec) ! "A" endpoints of segments
      real*8 phia(ivec)        ! "A" endpoints phi locations

 ! input (if idinit.eq.1) or output (if idinit.ne.1):
      real*8 da(ivec)          ! distance, "A" to chosen bdy

 ! more input:
      real*8 rb(ivec),zb(ivec) ! "B" endpoints of segments
      real*8 phib(ivec)        ! "B" endpoints phi locations

 ! input (if idinit.eq.1) or output (if idinit.ne.1):
      real*8 db(ivec)          ! distance, "B" to chosen bdy

 ! input:
      real*8 tol               ! accuracy tolerance

 ! approximate accuracy of intercept positions:
 !    tol*[system size], system size = ~midplane half width
 !                                      of plasma (approx).

 ! output:
      real*8 rx(ivec),zx(ivec) ! segment bdy intercept pts returned
      real*8 phix(ivec)        ! segment bdy intercept phi values
 !
      integer istat(ivec)      ! segment status code (see below)
 !
      integer ierr             ! completion code, 0=OK


 ! ierr is only set for "serious" errors.
 ! segment status codes:  on output,
 !
 ! istat(j)=2 -- both endpoints outside bdy
 ! istat(j)=1 -- 1st endpoint outside, 2nd endpoint inside
 ! istat(j)=-1 -- 1st endpoint inside, 2nd endpoint outside
 ! istat(j)=-2 -- both endpoints inside bdy
 !   (rx(j),zx(j)) contains bdy intercept only if abs(istat(j))=1.

          ... ...

      call eq_fxcep(ivec,itype,idinit,
     >              ra,za,phia,da, rb,zb,phib,db,
     >              tol,
     >              rx,zx,phix, istat, ierr)

 ! the routine can be used to define a start point for RF rays
 ! or neutral atom tracks or diagnostic sightline - plasma
 ! intersections.  

Home Top


mag_axis_finder

(old f77 xplasma 1 documentation)

The following routine returns R, Z, and mod(B) at the magnetic
axis, for given phi value.  (For axisymmetric equilibria, the
phi value has no effect; one can use ivec=1 and phi(1)=0.0d0).

 ! input:
      integer ivec         ! vector dimension
      real*8 phi(ivec)     ! toroidal angle coordinate

 ! output:
      real*8 B_axis(ivec)  ! mod(B) on axis
      real*8 R_axis(ivec)  ! R of magnetic axis
      real*8 Z_axis(ivec)  ! Z of magnetic axis

         ...

      call eq_gaxis(ivec,phi,B_axis,R_axis,Z_axis)

--> simplified routine for axisymmetric case:

      call eq_sgaxis(b_axis,r_axis,z_axis)

 returns the single axial values for B, R, and Z; the arguments can
 be real*8 scalars.

Home Top


Fourier_Spline_Representation

(old f77 xplasma 1 documentation)

The (R,Z) MHD equilibrium may be retrieved in Fourier Spline form,
i.e. the coeffcient profiles Rc[i](x), Rs[i](x), Zc[i](x), Zs[i](x)
satisfying

  R(x,theta) = Rc[0](x) + sum(Rc[i](x)*cos(i*theta)+Rs[i](x)*sin(i*theta))
  Z(x,theta) = Zc[0](x) + sum(Zc[i](x)*cos(i*theta)+Zs[i](x)*sin(i*theta))
             ! generally x is normalized sqrt(toroidal_flux), aka "rho".

where the sum is from i=1 to kmom, where kmom is the maximum Fourier
coefficient retained.

To get kmom:

  integer :: kmom
  call xmoments_kmom_get(kmom)

The moments profile retrieval routines can return either the moments
coefficients themselves, or, a scaled representation

  Rcx[i] = Rc[i]/x**j, j=min(i,kmaxe)

which has been constructed in a way such that the behavior as x->0 is
kept smooth, i.e. Rc[i] is proportional to x**i in the limit as x->0.

(kmaxe can be fetched by an undocumented xplasma routine-- work in
progress-- for now users should just get the unnormalized coefficient).

Each moment coefficient is fetched by a separate call, using one of
the following four subroutines:

  eqmom_Rcos(...)  for Rc[i]
  eqmom_Rsin(...)  for Rs[i]

  eqmom_Zcos(...)  for Zc[i]
  eqmom_Zsin(...)  for Zs[i]

All of the above routines have the following arguments:

for input:

  integer nx       ! number of x points at which the coefficient is desired.
  real*8 x(nx)     ! the actual x points (x = sqrt(phi/philim) = "rho").

  integer inorm    ! =0 to get the coefficient, =1 to get coeff with 
                   !    normalization-- context dependent, do not use...

  integer i        ! the moment index of the desired coefficient

for output:

  real*8 momarr(nx)  ! the coefficients (or coeff/x**i) returned.
  integer iwarn    ! =0: OK; =-1: "i" not in range 0 to kmom.

if the warning flag is set, momarr=0.0 is returned.  The form of the
call is then:

  call eqmom_Rcos(x,nx,inorm,i,momarr,iwarn)  ! inorm=0 recommended

and a sample fragment showing the use of these routines follows:

  integer kmom
  real*8, dimension(:,:), allocatable :: rc,rs,zc,zs

  ! x(1:nx) contains the user's grid.

  call xmoments_kmom_get(kmom)

  allocate(rc(0:kmom,nx),rs(0:kmom,nx))
  allocate(zc(0:kmom,nx),zs(0:kmom,nx))

  do i=0,kmom
    call eqmom_Rcos(x,nx,0,i,rc(i,1:nx),iwarn) ! get the coeffs.
    call eqmom_Rsin(x,nx,0,i,rs(i,1:nx),iwarn)
    call eqmom_Zcos(x,nx,0,i,zc(i,1:nx),iwarn)
    call eqmom_Zsin(x,nx,0,i,zs(i,1:nx),iwarn)
  enddo

The Fourier Representation is available after xplasma has been 
initialized from any data source.

Home Top


NCLASS Poloidal Moments

(old f77 xplasma 1 documentation)

The poloidal moments of a geometric factor used to compute the Pfirsch-Schluter
contribution of the viscosity for NCLASS as described in 

  Houlberg,Shaing,Hirshman,Zarnstorff, "Bootstrap current and neoclassical 
  transport in tokamaks of arbitray collisionality and aspect ratio",
  Phys. Plasmas 4 (9), September 1997, pg 3230-3242 

are returned by the eq_psmom function.  The Fm moments from this paper are
returned in the PSMOM argument.  For rho<RHOMIN, axis values are returned.
The relative error returned by 
  ZERROR =|sum(Fm) - <(n.grad(B))**2>/<B**2>| / max(<(n.grad(B))**2>/<B**2>)
should go to zero for increasing number of moments.

  ! input
  integer :: ivec       ! number of surfaces
  real*8  :: rho(ivec)  ! radial coordinate
  real*8  :: rhomin     ! rho values below this are considered on axis
  integer :: nmom       ! number of moments to compute
  real*8  :: phi1       ! toroidal coordinate, same one used for all surfaces
  integer :: idmom      ! dimension of the psmom array

  !
  real*8  :: psmom(idmom,ivec)  ! PS moments
  real*8  :: gamma(ivec)        ! wayne's gamma = 2*pi/integral_0_2pi[Bmod/B.grad(theta)]_dtheta
  real*8  :: ngrdb2(ivec)       ! <(n.grad(B))**2>
  real*8  :: b2(ivec)           ! <B**2>
  real*8  :: zerror(ivec)       !|sum(Fm)-<(n.grad(B))**2>/<B**2>|/max(<(n.grad(B))**2>/<B**2>)
  integer :: ier                ! nonzero on error
  
  call eq_psmom(ivec, rho, rhomin, nmom, phi1, idmom, psmom, gamma, ngrdb2, b2, zerror, ier)

Home Top


Numerical_Integration

(old f77 xplasma 1 documentation)

(dmc:  20 Sept 2000.  Although these interfaces are written with 
eventual extension to 3d non-axisymmetric in mind, currently only
axisymmetric geometry is supported).

Home Top


Introduction

(old f77 xplasma 1 documentation)

Once the magnetic coordinates (rho,chi) are established, the
spline functions g(rho), psi(rho), R(rho,chi), Z(rho,chi), 
and the vector B(rho,chi) have been constructed, it becomes 
possible to evaluate metric and field flux surface / flux zone 
averages and integrals.

Generally the integrands are algebraic combinations of spline
functions, optionally weighted by the determinant of the Jacobian, 
which is also an algebraic combination of splines.

Integrals are evalaluated numerically using an 11-point Gauss
Legendre method within each spline grid zone, and summing
across multiple zones.  For typical integrands the (bi)cubic 
pieces within spline-grid zones are C-infinity, which means that 
components of the sum forming the integral are estimated to an
accuracy within REAL*8 machine precision, as is readily verified
by comparison to higher order Gauss Legendre formulae.

Integrations are performed on a set of flux surfaces-- not
necessarily the same set of surfaces as given by the rho
spline grid -- or over flux zones between successive flux 
surfaces.  Integrations are performed over entire surfaces
or zones (poloidal angle chi varying from 0 to 2pi), or, 
over a user defined discreet set of chi subzones, again not
necessarily the same zones as defined by the chi spline
grid.

Six types numerical integrations are available.

In these expressions:
   "f" is the user selected integrand function
   "det(J)" is the absolute value of the determinant of the 
    Jacobian (i.e. R*[(dR/drho)*(dZ/dchi)-(dZ/drho)*(dR/dchi)]
    in axisymmetric geometry).

When det(J) is used, the software verifies that sign(det(J)) 
does not change; an error will be reported if it does.

a) surface integral:

  Integral[phi = 0 to 2pi] dphi * 
    Integral[chi = 0 to 2pi] dchi * f

      = 2pi * Integral[chi = 0 to 2pi] dchi * f
        (in axisymmetric geometry)

  --computed at each of N rho surface (see setup routines)
  --also available split into chi subzones

b) volume weighted surface integral:

  Integral[phi = 0 to 2pi] dphi * 
    Integral[chi = 0 to 2pi] dchi * f * det(J)

      = 2pi * Integral[chi = 0 to 2pi] dchi * f * det(J)
        (in axisymmetric geometry)

  --computed at each of N rho surface (see setup routines)
  --also available split into chi subzones

c) volume weighted surface average:

  A type(b) integral, normalized by 

  Integral[phi = 0 to 2pi] dphi * 
    Integral[chi = 0 to 2pi] dchi * det(J)

  --computed at each of N rho surface (see setup routines)
  --also available split into chi subzones

d) zone integral:

  Integral[phi = 0 to 2pi] dphi * 
    Integral[chi = 0 to 2pi] dchi *
      Integral[rho = rho(j) to rho(j+1)] drho * f

      = 2pi * Integral[chi = 0 to 2pi] dchi *
        Integral[rho = rho(j) to rho(j+1)] drho * f
        (in axisymmetric geometry)

  --computed in the N-1 zones between the N rho surfaces
  --also available split into chi subzones

e) volume weighted zone integral

  Integral[phi = 0 to 2pi] dphi * 
    Integral[chi = 0 to 2pi] dchi *
      Integral[rho = rho(j) to rho(j+1)] drho * f * det(J)

      = 2pi * Integral[chi = 0 to 2pi] dchi *
        Integral[rho = rho(j) to rho(j+1)] drho * f * det(J)
        (in axisymmetric geometry)

  --computed in the N-1 zones between the N rho surfaces
  --also available split into chi subzones

  Note that if f=1 the integral result is the zone volume,
  which (for chi = 0 to 2pi) we'll call delta_volume(j).

f) volume weighted zone average

  a type (e) integral, normalized in each zone j by dividing
  by delta_volume(j).

  --computed in the N-1 zones between the N rho surfaces
  --also available split into chi subzones

Home Top


setup

(old f77 xplasma 1 documentation)

A rho grid for integrations needs to be defined.  This can be but
need not necessarily be the same rho grid as was used for setting 
up the g, psi, R, Z, and B field splines.

The rho grid identifies an ascending sequence of rho surfaces, 
at which / between which numerical integrations are to be performed.

Optionally, a chi grid can also be defined, to allow breaking up
an integration into zones [rho(j),rho(j+1)]x[chi(k),chi(k+1)], or
surface intervals [chi(k),chi(k+1)] at each surface rho(j), for
surface integrals.

The integration rho grid (chi grid) can be redefined any number of 
times, so that, for a given xplasma geometry and field, the call 
sequence

  setup rho-grid-A
  (optionally set up chi-grid-A)
  evaluate metric integrals on rho-grid-A (chi-grid-A)

  setup rho-grid-B
  (optionally set up chi-grid-B)
  evaluate metric integrals on rho-grid-B (chi-grid-B)

is readily done.

Home Top


basic_setup

(old f77 xplasma 1 documentation)

The basic setup call defines the integration rho grid:

    integer iauto   ! =1 for automatic generation of rho sequence
                    ! =0 for user supplied rho sequence

    integer inumrhos ! number of rho points (each identifies a surface)

    real*8 zrho(inumrhos)  ! the actual rho values
                    ! if iauto=1, evenly spaced values from rho(axis) 
                    ! to rho(bdy), inclusive, are output.
                    ! if iauto=0, user supplied values must lie within
                    ! the range defined by the splines.

    real*8 zrhomin  ! minimum safe rho (approach to axial singularity)
                    ! det(J) --> 0 as rho --> rho(axis).
                    ! a typical safe choice:
                    !     rho(axis)+1.0d-7*(rho(bdy)-rho(axix))
 !
 ! output:

    integer ierr    ! completion code, 0=OK


       ........


    call eq_flxint_init(iauto,inumrhos,zrho,zrhomin,ierr)


The setup evaluates the zone volumes between successive rho surfaces;
it uses this integration as a test to set "ineed".

An example of the use of eq_flxint_init can be found in xplasma in
the source code:  eqdbg_flxint.for

Home Top


optional_chi_grid

(old f77 xplasma 1 documentation)

This optional further setup call defines the integration chi grid:

    integer iauto   ! =1 for automatic generation of chi sequence
                    ! =0 for user supplied chi sequence
    integer inumchis ! number of chi points
                    ! each identifies a chi interval boundary.

    real*8 zchi(inumchis)  ! the actual chi values
                    ! if iauto=1, evenly spaced values from chi(min)
                    ! to chi(max), inclusive, are output; the extrema
                    ! are taken from the chi spline grid.
                    ! if iauto=0, user supplied values must be given
                    ! in increasing order, and must lie within one
                    ! period of the periodic chi grid.
 !
 ! output:
 !
    integer ierr    ! completion code, 0=OK


       ........


    call eq_flxint_chinit(iauto,inumchis,zchi,ierr)


Note that this call must come *after* an eq_flxint_init call.

Note also, in related documentation of the integration routines, 
the quantity "inumchi" refers to the number of chi intervals, which 
is (inumchis - 1).

Home Top


Predefined_Integrations

(old f77 xplasma 1 documentation)

Certain "canned" integrations are available by calling "eq_flxint"...

Home Top


eq_flxint subroutine

(old f77 xplasma 1 documentation)

 ! eq_flxint input:

    character*20 iname      ! name-of-desired-integral

    integer noption         ! accuracy control (noption=1 recommended)

 !
 !   noption=0 -- evaluate quadrature to near machine precision accuracy;
 !                a message is generated recommending a non-zero
 !                noption value that would be sufficiently accurate.
 !   noption=1 -- use 11-point Gauss-Legendre integration on each segment
 !          =2 -- use 21-point Gauss-Legendre integration on each segment
 !          =3 -- use 43-point Gauss-Legendre integration on each segment
 !     (each segment is a continuous segment btw spline grid pts)
 !
 !   **(generally noption=1 is sufficient real*8 machine precision, 
 !     and it is the fastest by far)
 !

    inteter inumchi          ! chi dimension of results array
                             ! --if inumchi=1, do whole flux surface
                             ! integrals.
                             ! --if inumchi.ge.(# of chi intervals
                             ! specified via a prior eq_flxint_chinit
                             ! call), break up the integral into the
                             ! chi intervals and store the partial
                             ! results
                             ! --if inumchi.gt.1 but less than the
                             ! no. of intervals:  this is an error.

    integer inumrho          ! rho dimension of results array
                             ! --must be .ge. the number of zones or
                             ! number of surfaces, depending on the
                             ! type of integral.

 ! eq_flxint output:

    real*8 result(inumchi,inumrho) ! integration results

    integer ierr             ! completion code, 0=OK

     ....

    call eq_flxint(name,noption,result,inumchi,inumrho,ierr)

Examples:

    call eq_flxint('DVOL',1,result,30,20,ierr)
    --valid if no. of rho surfaces is .le.21
    --valid if chi intervals are defined and there are at least
      30 of them (i.e. 31 chi interval boundaries).

    result(j,k) = the volume in the region
                  [chi(j),chi(j+1)]x[rho(k),rho(k+1)]
                  j = 1 to (#of chi intervals)
                  k = 1 to (#of rho zones)

    call eq_flxint('<1/R^2>',1,result,1,20,ierr)
    --valid if no. of rho surfaces is .le.21

    result(k)  = volume weighted average of 1/R**2, integrating
                 chi = 0 to 2pi, between surfaces at rho(k) and
                 rho(k+1).
                 k = 1 to (#of rho zones)

More realistic code examples of the use of eq_flxint can be found 
in xplasma in the source code:  eqdbg_flxint.for

The minimum required inum, inumchi was determined by preceding
initialization calls (eq_flxint_init, eq_flxint_chinit); the values
can be retrieved as follows:

    call fluxav_nzones_get(inumchi,inumrho) ! inumrho = #of rho zones
      --or--
    call fluxav_nsurfs_get(inumchi,inumrho) ! inumrho = #of rho surfaces 
                                            !      = (#of rho zones) + 1
    ! inumchi = #of chi intervals 
    !   (defined by prior eq_flxint_chinit call)
    !   ( =1 if no prior eq_flxint_chinit call)

Home Top


Integration names

(old f77 xplasma 1 documentation)

These are the character string names passed to "eq_flxint".  All 
names are case-insensitive.

Basic metrics:

  inumrho = #of rho zones
  inumchi = 1 --or-- #of rho zones * #of chi zones

    DVOL  -- zone volumes   (units of R,Z)^3  
    DAREA -- cross sectional area btw successive rho surfaces
            (units of R,Z)^2

  inumrho = #of rho surfaces
  inumchi = 1 --or-- #of rho surfaces  * #of chi zones

    SURF -- surface area of each rho surface   (units of R,Z)^2
    LPOL -- poloidal path length around each rho surface
            (units of R,Z)

    DVDRHO -- dV/drho at each rho surface   (units of R,Z)^3

Zonal volume averages
  --integrands are volume integrated; then zone volume is divided out

  inumrho = #of rho zones
  inumchi = 1 --or-- #of chi zones

  moments of R:
    <R^2>   <R>   <1/R>   <1/R^2>  <1/R^3>

  moments of |grad(rho)|

    <grad(rho)>   <grad(rho)^2>

  moments involving |grad(rho)| and R

    <grad(rho)^2/R^2>  <grad(rho)^2/R^3>  <R^2*grad(rho)^2>
    <1/(R*grad(rho))>  

  moment involving |grad(rho)| and mod(B)

    <grad(rho)^2/B^2>

  moments of B (mod(B)) or vertical component of B, BZ

    <B^2>  <B>  <1/B>  <1/B^2>      <BZ^2>

Volume weighted surface averages

  inumrho = #of rho surfaces
  inumchi = 1 --or-- #of chi zones

  --names as above, but with "S" appended, e.g.

     <R^2>S    or    <grad(rho)^2/R^2>S

  These quantities are are the flux surface integrals normalized
  by DVDRHO.  Since at the axis DVDRHO=0.0, the averages there are
  just the local values of the integrand.

(note: dmc 21 Sept 2000: several additional metric averages will
be added soon, to complete the set needed by NCLASS.  Also, 
suggestions for additional canned integrations are welcome, send
to dmccune@pppl.gov).

Home Top


user_defined_integrations

(old f77 xplasma 1 documentation)

Any quantity that can be represented as a bicubic spline can
be integrated, with the following routines.  The procedure is
as follows:

  1.  construct an array f(nchi,nrho) containing the integrand
      function values f(j,k) = f(chi(j),rho(k)), where the
      {chi(j)} and {rho(k)} values are from the *original* grid
      used to set up the R and Z splines, *not* the integration
      zone grids.

  2.  call the integrator routine, which will

      a)  construct a temporary (bicubic) spline from f
      b)  perform the requested integral
      c)  discard the temporary spline

Four types of integrations are available:

c  *** iwant *** specifies the type of integration desired:
c    here "f" denotes the interpolating function generated from the
c    passed array data.
c
c    iwant=1:  surface integral:
c      inumchi=1:
c        int[phi=0 to 2pi] dphi * {
c            int[chi=0 to 2pi] dchi * f }
c
c        result(1:inumrho) computed; inumrho = #of surfaces
c        result(1,j) -- integrated at rho(j)
c
c      inumchi=(# of chi intervals)
c        result(1:inumchi,1:inumrho) computed;
c        result(i,j) -- integrated from chi(i) to chi(i+1) at rho(j).
c
c    iwant=5:  volume weighted surface integral:
c      inumchi=1:
c        int[phi=0 to 2pi] dphi * {
c            int[chi=0 to 2pi] dchi * f * det(Jacobian) }
c
c        result(1:inumrho) computed; inumrho = #of surfaces
c        result(1,j) -- integrated at rho(j)
c
c      inumchi=(# of chi intervals)
c        result(1:inumchi,1:inumrho) computed;
c        result(i,j) -- integrated from chi(i) to chi(i+1) at rho(j).
c
c      **caution** if rho(1) corresponds to the mag. axis, a
c        det(Jacobian)=0 and a value of 0.0 is always returned!
c
c    iwant=6:  volume weighted surface average:
c      inumchi=1:
c
c        int[phi=0 to 2pi] dphi * {
c            int[chi=0 to 2pi] dchi * f * det(Jacobian)}
c        -----------------------------------------------
c        int[phi=0 to 2pi] dphi * {
c            int[chi=0 to 2pi] dchi * det(Jacobian)}
c
c        result(1:inumrho) computed; inumrho = #of surfaces
c        result(1,j) -- integrated at rho(j)
c
c      inumchi=(# of chi intervals)
c        result(1:inumchi,1:inumrho) computed;
c        result(i,j) -- integrated from chi(i) to chi(i+1) at rho(j).
c
c      **caution** if rho(1) corresponds to the mag. axis,
c        the value "f" evaluated at the axis is returned there.
c
c  zonal integrals:  result(1:inumchi,1:inumrho) are computed
c
c    iwant=2:  integrate f*drho*dchi*dphi:
c      inumchi=1:
c        int[rho=rho(j) to rho(j+1)] drho * {
c           int[phi=0 to 2pi] dphi * {
c              int[chi=0 to 2pi] dchi * f } }
c
c        result(1:inumrho) computed; inumrho = #of surfaces - 1
c        result(1,j) -- integrated from rho(j) to rho(j+1).
c
c      inumchi=(# of chi intervals)
c        result(1:inumchi,1:inumrho) computed;
c        result(i,j) -- doubly integrated from chi(i) to chi(i+1),
c                       rho(j) to rho(j+1)
c
c    iwant=3:  integrate f*dV (use det(Jacobian))
c
c       int[rho=rho(j) to rho(j+1)] drho * {
c          int[phi=0 to 2pi] dphi * {
c               int[chi=0 to 2pi] dchi * f * det(Jacobian) } }
c
c        result(1:inumrho) computed; inumrho = #of surfaces - 1
c        result(1,j) -- integrated from rho(j) to rho(j+1).
c
c      inumchi=(# of chi intervals)
c        result(1:inumchi,1:inumrho) computed;
c        result(i,j) -- doubly integrated from chi(i) to chi(i+1),
c                       rho(j) to rho(j+1)
c
c    iwant=4:  compute <f> = (integrated f*dV)/dVol
c              where dVol is the volume btw rho(j) and rho(j+1)
c
c        result(1:inumrho) computed; inumrho = #of surfaces - 1
c        result(1,j) -- integrated from rho(j) to rho(j+1).
c
c      inumchi=(# of chi intervals)
c        result(1:inumchi,1:inumrho) computed;
c        result(i,j) -- doubly integrated from chi(i) to chi(i+1),
c                       rho(j) to rho(j+1)
c
c  **caution** in axisymmetric case there is no variation with phi,
c  but a factor of 2pi still arises from the phi integration...
c

To control the boundary conditions on the temporary spline, use

  "eq_flxint_arr2s"

For default boundary conditions (not-a-knot) use

  "eq_flxint_arr2".

Home Top


eq_flxint_arr2s

(old f77 xplasma 1 documentation)

input:
    real*8 zdata(nchi,nrho)        ! the integrand function data

    integer ibcrho0                ! rho(1) BC option
    real*8 zbcrho0(*)              ! rho(1) BC data
    integer ibcrho1                ! rho(nrho) BC option
    real*8 zbcrho1(*)              ! rho(nrho) BC data
c
c  BC type values:  for ibcrho0:
c     =0 -- use "not a knot", zbcrho0(...) ignored
c     =1 -- match slope, given at x(1),chi(ichi) by zbcrho0(ichi)
c     =2 -- match 2nd deriv., given at x(1),chi(ichi) by zbcrho0(ichi)
c     =3 -- boundary condition is slope=0 (df/dx=0) at x(1), all chi(j)
c           (zbcrho0(...) ignored).
c  and similarly for (ibcrho1,zbcrho1(...)).
c
c  if zbcrho0,zbcrho1 are used, nchi points must be defined.

    integer iwant                  ! type of integration
            ! =1 -- surface integral of f*dchi*dphi
            ! =5 -- surface integral of f*det(Jacobian)*dchi*dphi
            ! =6 -- surface average:
            !       int(f*det(Jacobian)*dchi*dphi)/
            !       int(det(Jacobian)*dchi*dphi)
            ! =2 -- zone integral of f*dchi*dphi*drho
            ! =3 -- volume integeral, f*det(Jacobian)*dchi*dphi*drho
            ! =4 -- volume average:  vol. integral / delta_volume

 ! ** caution:  dphi integration -> factor of 2pi

    integer inumchi,inumrho        ! results dimensions
                                   ! *** see eq_flxint ***

output:
    real*8 result(inumrho,inumchi) ! integration results
    integer ierr                   ! completion code, 0=OK

     ....

      call eq_flxint_arr2s(zdata,
     >   ibcrho0,zbcrho0,ibcrho1,zbcrho1,
     >   iwant,result,inumchi,inumrho,ierr)

Home Top


eq_flxint_arr2

(old f77 xplasma 1 documentation)

input:
    real*8 zdata(nchi,nrho)        ! the integrand function data

    integer iwant                  ! type of integration
            ! =1 -- surface integral of f*dchi*dphi
            ! =5 -- surface integral of f*det(Jacobian)*dchi*dphi
            ! =6 -- surface average:
            !       int(f*det(Jacobian)*dchi*dphi)/
            !       int(det(Jacobian)*dchi*dphi)
            ! =2 -- zone integral of f*dchi*dphi*drho
            ! =3 -- volume integeral, f*det(Jacobian)*dchi*dphi*drho
            ! =4 -- volume average:  vol. integral / delta_volume

! ** caution:  dphi integration -> factor of 2pi

    integer inumchi,inumrho        ! results dimensions
                                   ! *** see eq_flxint ***

output:
    real*8 result(*)               ! integration results
    integer ierr                   ! completion code, 0=OK

     ....

      call eq_flxint_arr2(zdata,
     >   iwant,result,inumchi,inumrho,ierr)


Home Top


Example

(old f77 xplasma 1 documentation)

(real codes should check the return status code ierr).

! set up rho integration zones
     call eq_flxint_init(0,nsurfs,rho_surfs,rho_min,ierr)

! (optional) set up chi integration zones
     call eq_flxint_chinit(0,nchbdys,chi_bdys,ierr)

!
! (re)fetch flux integration zone grid sizes
!
     call fluxav_nzones_get(nchi_zones,nrho_zones)

! compute standard metric integrals -- chi = 0 to 2pi

     ichizons=1
     allocate(result(ichizons,nrho_zones))

     iaccuracy=1
     call eq_flxint('DVOL',iaccuracy,result,ichizons,nrho_zones,ierr)
        ...
     call eq_flxint('<1/R^2>',iaccuracy,result,ichizons,nrho_zones,ierr)
        ...
     call eq_flxint('<grad(rho)^2/R^2>',iaccuracy,  &
	  result,ichizons,nrho_zones,ierr)

! compute standard metric integrals -- discrete chi zones

     ichizons=nchi_zones
     allocate(result(ichizons,nrho_zones))

     call eq_flxint('DVOL',iaccuracy,result,ichizons,nrho_zones,ierr)

! given an array f(1:nchi,1:nrho) on the (R,Z) original spline grid
! (NOT the integration grid)... compute various integrals

     iwant=1                    ! surface integrals f*dphi*dchi
     nrho_surfs = nrho_zones+1
     allocate(result(ichizons,nrho_surfs))

     call eq_flxint_arr2(f,iwant,result,ichizons,nrho_surfs,ierr)

     iwant=2                    ! zone integrals f*drho*dphi*dchi
     allocate(result(ichizons,nrho_zones))

     call eq_flxint_arr2(f,iwant,result,ichizons,nrho_zones,ierr)

     iwant=3                    ! volume integrals f*det(J)*drho*dphi*dchi
     allocate(result(ichizons,nrho_zones))

     call eq_flxint_arr2(f,iwant,result,ichizons,nrho_zones,ierr)

     iwant=4                    ! volume avgs (as iwant=3, div. by dVol)
                                ! dVol = integral det(J)*drho*dphi*dchi
     allocate(result(ichizons,nrho_zones))

     call eq_flxint_arr2(f,iwant,result,ichizons,nrho_zones,ierr)

! these calls create temporary spline fits.  to control boundary
! conditions use eq_flxint_arr2s.

Home Top


Summary

(old f77 xplasma 1 documentation)

     eq_flxint_init, eq_flxint_chinit -- initialization 

     eq_flxint -- canned integrations

     eq_flxint_arr2, eq_flxint_arr2s -- user defined integrations

Home Top


Miscellaneous


Home Top


limiter_contour_sequence

(old f77 xplasma 1 documentation)

(eq_limcon)

(Axisymmetric geometry only...)

Regardless of the method chosen to represent the limiter, the
routine "eq_limcon" can be used to return a piecewise linear 
contour representation of the limiter:

 ! input:
      integer imax         ! max no. of points in contour returned

 ! output:
      integer inum         ! actual no. of points in contour
      real*8 rlim(inum),zlim(inum)  ! the contour itself

 ! input:
      real*8 dtol          ! colinearity tolerance (R,Z units)

 ! output:
      integer ierr         ! completion status code, 0=OK

       ...

      call eq_limcon(imax,inum,rlim,zlim,dtol,ierr)

The contour returned is a closed finite sequence of (R,Z)
points.  Closed means rlim(1)=rlim(inum) & zlim(1)=zlim(inum).

The colinearity tolerance "dtol" controls the deletion of 
extraneous contour points:  If 3 consecutive points A,B,C
are colinear to tolerance dtol, i.e. B is .le.dtol away
from the segment AC, then, B is eliminated, reducing the
size of the contour returned.

Sample use of eq_limcon:  create a limiter contour sequence
suitable for writing into a G EQDSK file.

Home Top


psi_rho_grid_mapping

(old f77 xplasma 1 documentation)

(eq_rhopsi, eq_rhopsin) -- these routines can be used to generate
the sequence of "rho" values corresponding to a specified sequence
of psi-poloidal values.  "eq_rhopsin" will generate the sequence of
rho values corresponding to an equispaced psi grid going from the
magnetic axis to the plasma boundary; "eq_rhopsi" will find the
sequence of rho values {rho[j]} satisfying

   psi(rho[j]) = psi[j]  (j = 1 to npsi)

for any given sequence of psi values {psi[j]}.

To use these eq_rhopsin:

      integer npsi          ! no. of pts in psi sequence (input)
      real*8 rhovals(npsi)  ! corresponding rho values (output)
      integer ierr          ! completion code, 0=OK (output)

         ...

      call eq_rhopsin(npsi,rhovals,ierr)

             ! rhovals(1:npsi) is the set of rho values which map
             ! to an equispaced psi grid ranging from the plasma
             ! magnetic axis to the plasma boundary

             ! the accuracy tolerance is 
             !   10*[machine epsilon]*[rho(bdy)]

To use eq_rhopsi:  npsi, rhovals, ierr as above, and...

      real*8 psivals(npsi)  ! psi values for which rho values
                            ! are sought...

      real*8 ztol           ! accuracy tolerance (in rho)
                            ! for the root finder


         ...

      call eq_rhopsi(npsi,psivals,rhovals,ztol,ierr)

Home Top


F77_MCgrid_Routines

(old f77 xplasma 1 documentation)

XPLASMA supports a legacy 2d spatial grid mechanism that derives 
from TRANSP and NUBEAM: the "Monte Carlo" grid, or MCgrid.

This is the spatial grid used for NUBEAM spatially 2d outputs, including
the fast ion distribution function, fusion rate profiles, etc.

This grid consists of radial zone rows each of which are partitioned
into evenly spaced poloidal zones-- with the number of zones proportional
to radius, i.e. fewer poloidal partitions at the center, more at the
edge.  This yields a grid where each zone has roughly equivalent volume
and cross-sectional area, which is well suited to Monte Carlo uses, i.e.
there are no "tiny" zones near the axis as would be the case with a
regularly structured polar mesh.  Such tiny zones would be hard to find
by Monte Carlo parameter summation methods, leading to high statistical
variance or noise in output.  Using MCgrid avoids this.

A typical MCgrid has 10 radial zone rows inside the plasma.  For historical
reasons, MCgrids also support a set of extrapolated zone rows mapping a
region somewhat beyond the plasma boundary.  A MCgrid supports the notion
of updown symmetry, allowing a smaller grid to be used in the case of
symmetric equilibrium.

Although the interface has been coded to allow eventual generalization to
3d, actual use has been limited to axisymmetric geometries so far.

The main parameters defining the grid are:

  iudsym -- =1 for updown symmetry  =2 for updown asymmetry
  inznbmri -- no. of zone rows inside the plasma (typical value: 10)
  inth0 -- no. of theta zones in first (centermost) zone row
           spanning the range poloidal angle range [0,pi]
           (typical value: 2).

The number of zones in the n'th zone rows is n*iudsym*inth0.

The following chart illustrates the zone counts in the "typical"
MCgrid -- this is the grid historically used for most NUBEAM
calculations in TRANSP over the years.

                   no. of poloidal zones per zone row
            updown symmetric            updown asymmetric
               [0,pi]                      [-pi,pi]
zone row
  1              2                            4
  2              4                            8
  3              6                           12
  4              8                           16
  5             10                           20
  6             12                           24
  7             14                           28
  8             16                           32
  9             18                           36
 10             20                           40
----------------------------------------------------------plasma bdy
 11             22                           44
 12             24                           48
 13             26                           52

zones
inside
plasma:        110                          220

total
zones:         182                          364

The radial zone rows are evenly spaced in the XPLASMA radial coordinate
"rho".

Home Top


Definition

(old f77 xplasma 1 documentation)

Input variables (traditional/suggested values in parentheses):

  integer :: inphi   ! no. of phi zones -- toroidal variation (1)
  integer :: iudsym  ! updown symmetry 1=yes 2=no  (1 or 2)
  integer :: inth0   ! no. of poloidal zones subtending [0,pi] at axis (2)
  integer :: inznri  ! no. of radial zone rows inside plasma (10)

Output variables 

  integer :: inznrx  ! no. of radial zones including extrapolated region
  integer :: id_mcgrid  ! XPLASMA id for MC grid just defined.

  call mcgrid_define(inphi,iudsym,inth0,inznri,   &
               inznrx, id_mcgrid)

If there is an error, id_mcgrid = 0 will be returned, and messages will
be written on the i/o unit open for XPLASMA messages.

Home Top


Retrieve_basic_grid_info

(old f77 xplasma 1 documentation)

Each of these routines retrieves information from the definition.  In
each case, the XPLASMA id "id_mcgrid" is input, and the grid description
parameters are output.  All arguments are integers.

  ! get symmetry information:
  call mcgrid_getsym(id_mcgrid,iudsym)
  !           iudsym=1 means updown symmetric; 2 means updown asymmetric.

  ! get number of zone rows:
  call mcgrid_getnumr(id_mcgrid,inznrx,inznri)
  !     inznrx -- *total* number of zone rows inside and outside plasma
  !     inznri -- number of zone rows inside plasma
  !       ** note order: inznrx then inznri **

  ! get number of zone rows:
  call mcgrid_getnumz(id_mcgrid,inzonx,inzoni)
  !     inzonx -- *total* number of zones inside and outside plasma
  !     inzoni -- number of zones inside plasma
  !       ** note order: inzonx then inzoni **

  ! get number of zones covering [0,pi] on axis; get no. of phi zones.
  call mcgrid_getnuma(id_mcgrid,inth0,inphi)
  !     inth0 -- no. of poloidal zones covering [0,pi] on axis
  !     inphi -- no. of phi zones (1 means axisymmetry).

  ! get array of numbers of poloidal zones per zone row

  integer, dimension(:), allocatable :: inthzns
  allocate inthzns(inznrx)

  call mcgrid_getnumzns(id_mcgrid,inthzns)

  ! for this it is also possible to use the simple formula 
  !    inthzns(k)=iudsym*inth0*k

Home Top


Define_Data_over_MCgrid

(old f77 xplasma 1 documentation)

These routines are used to create data objects defined over an existing
MCgrid.  For a scalar function use "mcgrid_putobj" (REAL*8 precision) or
"mcgrid_putobj_r4" (REAL precision).

There is also a call (used for specifying the beam distribution function)
which allows a 2d array of data to be associated with each MCgrid zone.
This is "mcgrid_putarr2" (REAL*8 precision) or "mcgrid_putarr2_r4" (REAL
precision).

The data is stored in XPLASMA in REAL*8 precision, regardless of which
call is used.

Specific functions are defined by names.  Each defined MCgrid supports
its own "name space".

Example of use:  the NUBEAM NTCC module uses these routines, to make
fast ion distribution functions, and other 2d profiles, such as neutron
emission rates, available externally.

The REAL*8 routine is shown; the REAL interface is identical except
for the floating point precision of zmks and zdata arguments.

input:
  integer :: id_mcgrid    ! MCgrid id
  character*(*) :: zname  ! (unique) name to use for this function
  integer :: ist_th       ! theta grid start point indicator:
                          !  =0: grid starts at theta=0;
                          !  =-1: grid starts at -pi
  integer :: ist_ph       ! phi grid start point indicator (for
                          !  axisymmetric case choose either value):
                          !  =0: grid starts at theta=0;
                          !  =-1: grid starts at -pi
  integer :: iextend      ! flag if data is defined beyond plasma boundary
  integer :: idim         ! zdata array dimension

  real*8 :: zmks          ! multiply data by this to put it in MKS units

  real*8 :: zdata(idim)   ! the data to be stored in XPLASMA.

output:
  integer :: ierr         ! status code 0=normal

  call mcgrid_putobj(id_mcgrid, zname, ist_th, ist_ph, iextend, &
                     zmks, zdata, idim,  ierr)


For the distribution function definition, the above arguments are
extended to define the 3 array dimensions of the input data-- size of
array, and the subset of numbers actually used:

  integer :: idim1,idim2,idim3  ! array dimensions
                          ! zdata(idim1,idim2,idim3)
  integer :: in1,in2      ! data used: zdata(1:in1,1:in2,:)

  call mcgrid_putarr2(id_mcgrid, zname, ist_th, ist_ph, iextend, &
                      zmks, zdata, in1, in2, idim1, idim2, idim3, &
                      ierr)

Home Top


Fetch_Data_over_MCgrid

(old f77 xplasma 1 documentation)

These routines are used to fetch data objects that have been defined 
over an existing MCgrid.  For a scalar function use "mcrid_getobj" 
(REAL*8 precision) or "mcgrid_getobj_r4" (REAL precision).  The
precision is that desired by the caller; XPLASMA internal storage is
always REAL*8.

There is also a call (used for fetching the beam distribution function)
which allows a 2d array of data to be associated with each MCgrid zone.
This is "mcgrid_getarr2" (REAL*8 precision) or "mcgrid_getarr2_r4" (REAL
precision).  Again, the precision is that desired by the caller.

Specific functions are defined by names.  Each defined MCgrid supports
its own "name space".

Example of use:  the TRANSP code retrieves spatially 2d NUBEAM module
outputs, including fast ion distribution function data, using these
calls.

The REAL*8 routine is shown; the REAL interface is identical except
for the floating point precision of zmks and zdata arguments.

input:
  integer :: id_mcgrid    ! MCgrid id
  character*(*) :: zname  ! (unique) name to use for this function
  integer :: ist_th       ! caller's theta grid start point indicator:
                          !  =0: grid starts at theta=0;
                          !  =-1: grid starts at -pi
  integer :: ist_ph       ! caller's phi grid start point indicator (for
                          !  axisymmetric case choose either value):
                          !  =0: grid starts at theta=0;
                          !  =-1: grid starts at -pi
  integer :: idim         ! zdata array dimension

  real*8 :: zconv         ! multiply data by this to put it into the
                          ! physical units desired by caller.  The data
                          ! as stored is in MKS/KeV in XPLASMA.

output:
  real*8 :: zdata(idim)   ! the data to be returned XPLASMA.

  integer :: ierr         ! status code 0=normal

  call mcgrid_getobj([-]id_mcgrid, zname, ist_th, ist_ph, &
                     zconv, zdata, idim,  ierr)


For the distribution function definition, the above arguments are
extended to define the 3 array dimensions of the input data-- size of
array, and the subset of numbers actually used:

  integer :: idim1,idim2,idim3  ! array dimensions
                          ! zdata(idim1,idim2,idim3)

input/output:

  subset of dimensioned array space actually in use.  If in1>0 on 
  input, the actual space used must match this value.  If in1<= 0,
  the actual space usage will be returned; similarly for in2.

  integer :: in1,in2      ! data used: zdata(1:in1,1:in2,:)

  call mcgrid_getarr2([-]id_mcgrid, zname, ist_th, ist_ph, iextend, &
                      zmks, zdata, idim1, idim2, idim3, in1, in2, &
                      ierr)

Notes:

  1.  if the MCgrid is updown symmetric, only data covering the range
      [0,pi] or [-pi,0] are copied, depending on the setting of ist_th.
      I.e. the order of the poloidal indexing is reversed, within each
      zone row.

  2.  if the non-existance of a function should not be treated as an
      error, and the output data should be set to zero in this case,
      pass -id_mcgrid instead of id_mcgrid as the first argument.

  3.  errors are flagged in case of argument values out of range, or
      if array dimensions are too small to hold the available data.
      Messages are written to the XPLASMA messages i/o unit.

Home Top


Zone_Volumes

(old f77 xplasma 1 documentation)

When an MCgrid is defined, a scalar function "ZONE_VOLUME" is 
automatically defined along with it, giving the volume of each zone
in m**3.

This data can be fetched by the call

  call mcgrid_getobj([-]id_mcgrid, 'ZONE_VOLUME', ist_th, ist_ph, &
                     zconv, zdata, idim,  ierr)

where the arguments are as described in the preceding section.

Home Top


More_on_indexing

(old f77 xplasma 1 documentation)

The mapping [(rho,theta) -> zone index] will depend on whether or
not the geometry is updown symmetric, and, e.g. in the case of
updown asymmetry, on whether the user's poloidal angle grid spans 
[-pi,pi] or [0,2pi].  It will also depend on whether the user's code
makes use of the extrapolated zone rows or not.  Here is some sample 
code which could be adapted or optimized for a particular situation.

 integer function izmap(id_mcgrid,rho,theta)

    ! MCgrid zone map, with assumptions:
    !   1. axisymmetry
    !   2. ignore zones outside plasma
    !   3. updown symmetric theta range: [0,pi]
    !   4. updown asymmetric theta range: [-pi,pi]

    integer, intent(in) :: id_mcgrid  ! grid id (axisymmetry assumed)
    real*8, intent(in) :: rho,theta   ! (rho,theta in)

    !------------------------------------
    !  info on zone rows

    logical, save :: init = .FALSE.
    integer, dimension(:), allocatable, save :: izns,iztot
    integer, save :: inznr,inznri,iudsym,inth0
    integer, save :: id_mcgrid_int = 0

    !------------------------------------
    integer i,izr,inth,ith,idum
    real*8 ztheta
    real*8, parameter :: cpi = 3.1415926535897931D+00
    real*8, parameter :: c2pi = 6.2831853071795862D+00

    !  check if id matches the one stored; if not, re-initialize...

    if(id_mcgrid.ne.id_mcgrid_int) init = .FALSE.

    if(.not.init) then
       ! ** initialize **
       ! get no. of zones per row; add up cumulative number

       call mcgrid_getnumr(id_mcgrid,inznr,inznri)
       if(inznr.eq.0) then
          izmap=0   ! invalid MCgrid, evidently.
          return
       endif
       call mcgrid_getsym(id_mcgrid,iudsym)
       allocate(izns(inznr),iztot(0:inznr))
       call mcgrid_getnumzns(id_mcgrid,izns)
       iztot(0)=0
       do i=1,inznr
          iztot(i)=iztot(i-1)+izns(i)
       enddo
       init = .TRUE.
    endif

    izr = 1 + rho*inznri           ! zone row index -- inznri are inside bdy
    izr = max(1,min(inznri,izr))   ! forced inside plasma

    inth = izns(izr)               ! no. of poloidal zones, this row

    ztheta = theta                 ! force theta in range [-pi,pi
    do while ( ztheta < -cpi )
       ztheta = ztheta + c2pi
    enddo
    do while ( ztheta > cpi )
       ztheta = ztheta - c2pi
    enddo

    if(iudsym.eq.1) then
       ztheta = abs(ztheta)  ! updown symmetry: map to upper half-plane
       ith=1 + ztheta*inth/cpi
       ith = max(1,min(inth,ith))
    else
       ith=1 + (ztheta+cpi)*inth/c2pi
       ith = max(1,min(inth,ith))
    endif

    izmap = iztot(izr-1)+ith

 end function izmap

This sort of routine could also be generalized for piecewise linear
interpolation of functions defined over an MCgrid, but, higher-order
interpolation methods probably require mapping to a regular polar
mesh, and, care would have to be taken at the axis, boundary, and
poloidal angle branch cut.

Home Top


Support_Routines_&_Programs


Home Top


Visualization_Routine

The current contents of the xplasma module can be visualized via the
command line / menu driven interactive fortran subroutine:

(fortran-95):  call xplasma_debug_access(s)
                 type (xplasma), pointer :: s

(fortran-77):
               call eqdbg_plot

which use the NTCC modules SGLIB, UREADSUB, and TRGRAF.

Home Top


Save_and_Restore_Routines

The current contents of the xplasma module can be written to a netcdf
file:

      character*(*) filename    ! name of file to write
      integer ierr              ! completion code, 0=OK

      [the filename must be set...]

(fortran-95):
               call xplasma_write(s,filename,ierr)
                 type (xplasma), pointer :: s

(fortran-77):
               call eq_save(filename,ierr)    ! ierr should be checked

A file previously written by `eq_save' can be read back in using

      character*(*) filename    ! name of file to write
      integer ierr              ! completion code, 0=OK

      [the filename must be set...]

(fortran-95):
               call xplasma_read(s,filename,ierr)
                 type (xplasma), pointer :: s

(fortran-77):
               call eq_restore(filename,ierr) ! ierr should be checked

these routines use the NTCC module EZCDF.

Home Top


miscellaneous_f77


Home Top


LUN_for_messages

(old f77 xplasma 1 documentation)

The f77 xplasma interface writes messages to a fortran i/o unit
(logical unit number or LUN).

To fetch the fortran logical unit number currently used for messages:

      integer ilun   ! l.u.n. (Returned)

      call eq_get_lunerr(ilun)

Home Top


Spline_fit_order_RZ

(old f77 xplasma 1 documentation)

To fetch the order of R(rho,chi), Z(rho,chi) and component B(rho,chi)
spline fits, use

      integer iorder ! fit order

      call eq_rzordr_get(iorder)

where the value returned is 1 for Hermite, 2 for spline.

Home Top


eq_GEQDSK

(old f77 xplasma 1 documentation)

This routine will write a GEQDSK (EFIT-style) ascii file, with 
format as per the notes of Lang Lao (General Atomic), Februrary 2000.

Psi(R,Z) and B(R,Z) must be defined.  "q" and "P" profiles must also
be provided.

The calling routine is responsible for naming and opening the file 
and providing a logical unit number on which the file may be written.

Input arguments:

      integer lun_geqdsk       ! logical unit number of open file
      character*48 geqdsk_lbl  ! label string, written into file.

The following define the limits of evenly spaced (R,Z) grids over
which psi(R,Z) will be written.  These limits must cover the core
plasma but not exceed the extent of the (R,Z) grids defined in the
xplasma module.

      real*8 Rmin,Rmax         ! R extrema
      real*8 Zmin,Zmax         ! Z extrema

The total toroidal plasma current (amps) must be specified

      real*8 zcur              ! plasma current, amps

Xplasma id codes for the pressure and q profiles:

      integer id_p             ! xplasma id:  Pressure profile
      integer id_q             ! xplasma id:  q profile

The following integers specify the resolution of the grids

      integer nh               ! no. of horizontal (R) grid points.
                               ! also the no. of flux grid points.

      integer nv               ! no. of vertical (Z) grid points.

      integer nb               ! no. of points in plasma bdy contour
                               ! also, upper limit on limiter contour.

Output:
      integer ierr             ! completion code, 0=OK

            ...

      call eq_geqdsk(lun_geqdsk,geqdsk_lbl,
     >               Rmin,Rmax, Zmin,Zmax, zcur,
     >               id_p, id_q, nh, nv, nb, 
     >               ierr)

The GEQDSK file will contain:

Psi(R,Z) on evenly spaced (R,Z) grid covering [Rmin,Rmax]x[Zmin,Zmax]

and on an evenly spaced psi grid mapping from the plasma mag. axis out
the plasma boundary,

f(psi) = R*Bt   f*f'   P(psi)   P'   q

where the "'" denotes d/dpsi.

  .....

The caller should check the error code; if it is non-zero, the 
open file on lun_geqdsk should be deleted 
(i.e. close(lun_geqdsk,status='delete')).

Home Top


plot_xplasma

Given a file written by a prior call to eq_save (see the neighbouring
topic Save_and_Restore_Routines), this program can be used to examine
and visualize the contents.  The program employs a simple command line
menu driven interface and vector graphics, using the NTCC modules
SGLIB, UREADSUB, and TRGRAF.

The program can be run in an xterm emulator window (must be a real 
xterm, some clones like aixterm will not work).  The environment
variable TERMINAL_TYPE must be set to XTERM.  The environment variable
PLOT should usually be undefined.

To run the program, simply type its name and give the name of the 
netcdf file previously written by the xplasma eq_save subroutine.

This program works with F95 xplasma as well.

Home Top


test_xplasma

This is a test program for the xplasma NTCC module.  It's data source
is an ascii file derived from TRANSP data.  (A general tool for building
an xplasma from TRANSP MDS+ or file data is available in the NTCC module
"trxplib").  The test_xplasma program comes with a controlling script,
script.ind so that

  > test_xplasma @script

will produce a canned sequence of plots.  This is the same set of
plots as are stored in "script_output.ps", which comes with the
xplasma distribution.

Details on building the software and running test_xplasma are in the 
module's README file.

This program has been upgraded to F95 xplasma.

Home Top


geqxpl

this is a 2nd test program for the xplasma NTCC module.  This program
demonstrates construction of an xplasma from EFIT output, a G-EQDSK 
file.  The program comes with a controlling script, nstx_geqxpl.ind,
so that

  > geqxpl @nstx_geqdsk

will produce a canned sequence of plots.  This is the same set of
plots as are stored in "geqxpl_output.ps", which comes with the
xplasma distribution.

Details on building the software and running test_xplasma are in the 
module's README file.

This program works with F95 xplasma.

Home Top


About this document

This Document was created by hlptohtml

  • Written By:
  • Manish Vachharajani(mvachhar@pppl.gov)