charm_shc#

Module to work with spherical harmonic coefficients:

  • defines the charm_shc structure to store spherical harmonic coefficients,

  • allocates, initializes, copies and frees charm_shc,

  • reads/writes spherical harmonic coefficients from/to text and binary files,

  • performs arithmetics with charm_shc such as addition, etc.,

  • computes (difference) degree variances and degree amplitudes,

  • rescales spherical harmonic coefficients.

Note

This documentation is written for double precision version of CHarm.

Special values for functions to read spherical harmonic coefficients

The values are used with charm_shc_read_dov(), charm_shc_read_gfc(), charm_shc_read_tbl(), charm_shc_read_mtx() and charm_shc_read_dov().

CHARM_SHC_NMAX_MODEL (ULONG_MAX - 1UL)#

Special value of the nmax input parameter to all functions that read spherical harmonic coefficients. If nmax is CHARM_SHC_NMAX_MODEL and shcs is NULL, the functions return the maximum harmonic degree found inside the file and do not read the rest of the file (see the documentation to charm_shc_read_* functions). The value is platform-dependent.

CHARM_SHC_NMAX_ERROR (ULONG_MAX)#

Special value signalizing that a function to read spherical harmonic coefficients encountered an error. The value is platform-dependent.

Allocate, initialize, copy and free the charm_shc structure

These functions allocate, initialize and free the charm_shc structure, which is designed to store spherical harmonic coefficients and some associated data such as the maximum degree of the coefficients, scaling constant, etc.

charm_shc *charm_shc_malloc(unsigned long nmax, double mu, double r)#

Allocates spherical harmonic coefficients up to degree nmax. The charm_shc.mu, charm_shc.r and charm_shc.owner members are set to mu, r and 1, respectively. The spherical harmonic coefficients are uninitialized, so their values are undefined.

Note

r must be larger than zero.

Warning

The structure returned must be deallocated by calling charm_shc_free(). The free function will not deallocate the memory and will lead to memory leaks.

Returns:

On success, returned is a pointer to the charm_shc structure. On error, NULL is returned.

charm_shc *charm_shc_calloc(unsigned long nmax, double mu, double r)#

The same as charm_shc_malloc() but all spherical harmonic coefficients are initialized to zero.

charm_shc *charm_shc_init(unsigned long nmax, double mu, double r, double *c, double *s)#

Creates charm_shc by taking spherical harmonic coefficients up to degree nmax from the arrays pointed to by c and s (shallow copy). The charm_shc.mu, charm_shc.r and charm_shc.owner members are set to mu, r and 0, respectively.

The c and s pointers must have access to ((nmax + 2) * (nmax + 1)) / 2 array elements. The ordering of coefficients in c and s must follow the pattern:

\[\begin{split}&\bar{C}_{0,0}, \, \bar{C}_{1,0},\bar{C}_{2,0}, \, \cdots, \bar{C}_{\mathrm{nmax},0}, \bar{C}_{1,1},\, \bar{C}_{2,1}, \, \cdots,\\ &\bar{C}_{\mathrm{nmax},1}, \, \bar{C}_{2,2}, \bar{C}_{3,2},\, \cdots,\, \bar{C}_{\mathrm{nmax},\mathrm{nmax}},\end{split}\]

and

\[\begin{split}&\bar{S}_{0,0}, \, \bar{S}_{1,0},\bar{S}_{2,0}, \, \cdots, \bar{S}_{\mathrm{nmax},0}, \bar{S}_{1,1},\, \bar{S}_{2,1}, \, \cdots,\\ &\bar{S}_{\mathrm{nmax},1}, \, \bar{S}_{2,2}, \bar{S}_{3,2},\, \cdots,\, \bar{S}_{\mathrm{nmax},\mathrm{nmax}},\end{split}\]

respectively. Be careful here and always put the product (nmax + 2) * (nmax + 1) into brackets to ensure correct rounding when subsequently dividing by 2 as shown above.

The rationale behind this function is to provide a means to create the charm_shc structure from custom arrays of spherical harmonic coefficients without a deep copy of the data. The following code snippet illustrates this:

unsigned long nmax = 10;

size_t ncs = ((nmax + 2) * (nmax + 1)) / 2;

double *myc = (double *)malloc(ncs * sizeof(double));
double *mys = (double *)malloc(ncs * sizeof(double));

// Now fill "myc" and "mys" with your coefficients.
// [Here goes your code]

// Next, create the "charm_shc" structure from the "myc" and "mys"
// coefficients:
charm_shc *shcs = charm_shc_init(nmax, 1.0, 1.0, myc, mys);

// Do some cool things here with "shcs", but remember that
// "shcs->c" and "shcs->s" share the memory space with "myc" and
// "mys", respectively.
// [Here goes your code]

// At this point, we did everything we needed to do with "shcs", so
// let's release the memory associated with it.
charm_shc_free(shcs);
// The "shcs" structure is now properly released. But
// since "shcs" was created by "charm_shc_init", which does not
// perform a deep copy of the coefficients in "myc" and "mys", the
// memory associated with "myc" and "mys" was not freed.  At this
// point, you may therefore still use "myc" and "mys".
// [Here goes your code]

// Once you are done with "myc" and "mys", release the memory as
// usually with:
free(myc);
free(mys);

Note

r must be larger than zero.

Warning

The structure returned must be deallocated by calling charm_shc_free(). The free function will not deallocate the memory and will lead to memory leaks.

Warning

The spherical harmonic coefficients in the returned charm_shc structure share the memory space with the input c and s arrays. The function does not perform a deep copy of the data. Therefore, charm_shc_free() properly deallocates the charm_shc structure except for the spherical harmonic coefficients. The user allocated c and s outside the scope of CHarm, so the user decides when to deallocate.

Returns:

On success, returned is a pointer to the charm_shc structure. On error, NULL is returned.

charm_shc *charm_shc_copy(const charm_shc *shcs, unsigned long nmin, unsigned long nmax, unsigned long nmax_shcs_out)#

Creates charm_shc by coping spherical harmonic coefficients of shcs starting at degree nmin and ending at degree nmax. The output structure is allocated up to degree nmax_shcs_out and all coefficients outside the nmin to nmax range are set to zero. charm_shc.mu and charm_shc.r are set to shcs.mu and shcs.r, respectively. charm_shc.owner and charm_shc.distributed are set to 1 and 0, respectively.

A few restrictions apply:

  • nmin and nmax must both be smaller than or equal to shcs->nmax,

  • nmax cannot be smaller than nmin,

  • nmin_shcs_out cannot be smaller than nmax,

  • charm_shc.distributed must be 0.

If any of these conditions is violated, NULL is returned.

Returns:

On success, returned is a pointer to the charm_shc structure. On error, NULL is returned.

void charm_shc_free(charm_shc *shcs)#

Frees the memory associated with shcs. No operation is performed if shcs is NULL.

If shcs->owner is 1, the function releases all the memory that is associated with shcs, including the arrays of spherical harmonic coefficients. If shcs->owner is 0, the coefficients are not released from the memory, because they were not allocated by CHarm.

Read and write the charm_shc structure

These functions read/write the charm_shc structure from/to various text and binary data files.

unsigned long charm_shc_read_bin(const char *pathname, unsigned long nmax, charm_shc *shcs, charm_err *err)#

Reads the charm_shc structure to shcs from a binary file whose name is the string pointed to by pathname. The spherical harmonic coefficients are loaded up to degree nmax. The file is assumed to has been created by charm_shc_write_bin() on the same architecture. Error reported by the function (if any) is written to err.

The input file is a binary representation of the charm_shc structure in the following order:

\[\begin{split}&\mathrm{nmax\_file}, \, \mu, \, R, \bar{C}_{0,0}, \, \bar{C}_{1,0},\bar{C}_{2,0}, \, \cdots, \bar{C}_{\mathrm{nmax\_file},0}, \bar{C}_{1,1},\, \bar{C}_{2,1}, \, \cdots,\\ &\bar{C}_{\mathrm{nmax\_file},1}, \, \bar{C}_{2,2}, \bar{C}_{3,2},\, \cdots,\, \bar{C}_{\mathrm{nmax\_file},\mathrm{nmax\_file}},\, \bar{S}_{0,0},\, \bar{S}_{1,0},\, \bar{S}_{2,0},\, \cdots,\\ &\bar{S}_{\mathrm{nmax\_file},0},\, \bar{S}_{1,1},\, \bar{S}_{2,1},\, \cdots, \bar{S}_{\mathrm{nmax\_file},1},\,\bar{S}_{2,2},\, \bar{S}_{3,2},\, \cdots, \bar{S}_{\mathrm{nmax\_file},\mathrm{nmax\_file}},\end{split}\]

where nmax_file is the maximum harmonic degree stored in pathname, \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and, finally, \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= nmax_file and shcs->nmax >= nmax.

Tip

If nmax is CHARM_SHC_NMAX_MODEL and shcs is NULL, the function returns the maximum harmonic degree of pathname without reading the spherical harmonic coefficients.

The rationale behind this behaviour is as follows. Sometimes, the maximum degree nmax_file from pathname is not known when loading the file. In that case, the problem is that the input shcs structure needs to be initialized up to a maximum harmonic degree nmax_shcs >= nmax before loading the coefficients from pathname up to degree nmax <= nmax_file. With nmax = CHARM_SHC_NMAX_MODEL and shcs = NULL, the maximum degrees nmax_file and nmax can be determined before initializing shcs. The following code snippet illustrates this:

charm_err *err = charm_err_init();
if (err == NULL)
    exit(CHARM_FAILURE);

char pathname[] = "/some/path/to/your/model";
unsigned long nmax_file, nmax_shcs, nmax;

// Get the maximum degree stored in "pathname" without reading
// its coefficients, that is, without the need to initialize
// a "charm_shc" structure.
nmax_file = charm_shc_read_bin(pathname, CHARM_SHC_NMAX_MODEL, NULL, err);
charm_err_handler(err, 1);

// Now set "nmax_shcs" to some value equal to or higher
// than "nmax_file"
// [Here goes your code]

// Initialize the "charm_shc" structure to "nmax_shcs"
charm_shc *shcs = charm_shc_malloc(nmax_shcs, 1.0, 1.0);
if (shcs == NULL)
    exit(CHARM_FAILURE);

// Set "nmax" to some value value equal to or smaller than
// "nmax_file"
// [Here goes your code]

// Finally, read the coefficients from "pathname" up to degree
// "nmax" to the structure "shcs"
charm_shc_read_bin(pathname, nmax, shcs, err);
charm_err_handler(err, 1);

Note

The function modifies shcs->c, shcs->s, shcs->mu and shcs->r by the values from the input file, but it does not touch shcs->nmax, shcs->nc and shcs->ns. If shcs->nmax > nmax, the coefficients beyond nmax are set to zero.

Returns:

Upon successful return, the function returns the maximum harmonic degree from pathname. On error, CHARM_SHC_NMAX_ERROR is returned in addition to the error reporting through err.

unsigned long charm_shc_read_gfc(const char *pathname, unsigned long nmax, const char *epoch, charm_shc *shcs, charm_err *err)#

Reads the charm_shc structure to shcs from the ICGEM’s gfc file whose name is the string pointed to by pathname. The coefficients are loaded up to degree nmax. If the file represents a time variable gravity field model, the coefficients are optionally transformed from the model’s default epoch into epoch. Error reported by the function (if any) is written to err. gfc is a format for gravity field models defined by ICGEM at https://icgem.gfz-potsdam.de/docs/ICGEM-Format-2023.pdf.

The date string in epoch must follow either the pattern yyyyMMdd (e.g., "20050217" for Feb 17, 2005) or yyyyMMdd.hhmm (e.g., "20050217.1359" for Feb 17, 2005, 13:59).

  • For static models, epoch is ignored and can be either NULL or a valid date string (which is still ignored though).

  • If the format of the file is icgem1.0 or if the format is not specified, epoch can be either a valid date string or it can be NULL. If epoch is NULL and the file represents a time variable gravity field model, the model’s default epoch is used. No specification of the format implies icgem1.0 as per definition.

  • If the format of the file is icgem2.0, epoch must be a valid date string.

In each leap year, the month of February has 29 days instead of 28 days. The date strings "20050217.2400", "20050218" and "20050218.0000" represent the same epoch. Similarly, "20050217.1360" and "20050217.1400" are equal epochs. Date strings having the format "yyyyMMdd.2460" are not allowed.

It must hold that nmax <= nmax_file, where nmax_file is taken from the max_degree keyword of the gfc file, and shcs->nmax >= nmax.

Tip

If nmax is CHARM_SHC_NMAX_MODEL and shcs is NULL, the function returns the maximum harmonic degree of pathname without reading the spherical harmonic coefficients.

For a use-case, see the tip from the documentation to charm_shc_read_bin(), but keep in mind that this function has one additional input parameter when compared with charm_shc_read_bin().

Note

The function modifies shcs->c, shcs->s, shcs->mu and shcs->r by the values from the input file, but it does not touch shcs->nmax, shcs->nc and shcs->ns. If shcs->nmax > nmax, the coefficients beyond nmax are set to zero.

Returns:

Upon successful return, the function returns the maximum harmonic degree from pathname. On error, CHARM_SHC_NMAX_ERROR is returned in addition to the error reporting through err.

unsigned long charm_shc_read_tbl(const char *pathname, unsigned long nmax, charm_shc *shcs, charm_err *err)#

Reads the charm_shc structure to shcs from a text file whose name is the string pointed to by pathname. The structure is loaded up to degree nmax. The file is assumed to has been created by charm_shc_write_tbl(). Error reported by the function (if any) is written to err.

The first line of the input file must specify the maximum harmonic degree nmax_file of the coefficients stored in the file, their scaling parameter mu and the radius of the reference sphere r. Then, starting at a new line, provided must be a harmonic degree, harmonic order and the respective pair of coefficients per each line of the file. The entire file structure can be summarized as:

\[\begin{split}\begin{matrix} \mathrm{nmax\_file} & \mu & R\\ 0 & 0 & \bar{C}_{0,0} & \bar{S}_{0,0}\\ 1 & 0 & \bar{C}_{1,0} & \bar{S}_{1,0}\\ 1 & 1 & \bar{C}_{1,1} & \bar{S}_{1,1}\\ 2 & 0 & \bar{C}_{2,0} & \bar{S}_{2,0}\\ 2 & 1 & \bar{C}_{2,1} & \bar{S}_{2,1}\\ 2 & 2 & \bar{C}_{2,2} & \bar{S}_{2,2}\\ \vdots & \vdots & \vdots & \vdots \\ \mathrm{nmax\_file} & \mathrm{nmax\_file} & \bar{C}_{\mathrm{nmax\_file},\mathrm{nmax\_file}} & \bar{S}_{\mathrm{nmax\_file},\mathrm{nmax\_file}}\\ \end{matrix}\end{split}\]

where \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= nmax_file and shcs->nmax >= nmax. Lines specifying spherical harmonic coefficients (all lines after the first one) can be sorted arbitrarily. The non-existing coefficients \(\bar{S}_{n,0}\) of order 0 do not need to be present in the file.

Tip

If nmax is CHARM_SHC_NMAX_MODEL and shcs is NULL, the function returns the maximum harmonic degree of pathname without reading the spherical harmonic coefficients.

For a use-case, see the tip from the documentation to charm_shc_read_bin().

Note

The function modifies shcs->c, shcs->s, shcs->mu and shcs->r by the values from the input file, but it does not touch shcs->nmax, shcs->nc and shcs->ns. If shcs->nmax > nmax, the coefficients beyond nmax are set to zero.

Returns:

Upon successful return, the function returns the maximum harmonic degree from pathname. On error, CHARM_SHC_NMAX_ERROR is returned in addition to the error reporting through err.

unsigned long charm_shc_read_dov(const char *pathname, unsigned long nmax, charm_shc *shcs, charm_err *err)#

Reads the charm_shc structure to shcs from a text file whose name is the string pointed to by pathname. The structure is loaded up to degree nmax. The file is assumed to has been created by charm_shc_write_dov(). Error reported by the function (if any) is written to err. dov is an abbreviation for the degree, order, value format.

The first line of the input file must specify the maximum harmonic degree nmax_file of the coefficients stored in the file, their scaling parameter mu and the radius of the reference sphere r. Then, starting at a new line, each line must specify a harmonic degree, signed harmonic order (positive for \(\bar{C}_{nm}\), negative for \(\bar{S}_{nm}\)) and the respective coefficient (either \(\bar{C}_{nm}\) or \(\bar{S}_{nm}\), depending on the sign of the order). The entire file structure can be summarized as:

\[\begin{split}\begin{matrix} \mathrm{nmax\_file} & \mu & R\\ 0 & 0 & \bar{C}_{0,0}\\ 1 & 0 & \bar{C}_{1,0}\\ 1 & 1 & \bar{C}_{1,1}\\ 1 & -1 & \bar{S}_{1,1}\\ 2 & 0 & \bar{C}_{2,0}\\ 2 & 1 & \bar{C}_{2,1}\\ 2 & -1 & \bar{S}_{2,1}\\ 2 & 2 & \bar{C}_{2,2}\\ 2 & -2 & \bar{S}_{2,2}\\ \vdots & \vdots & \vdots \\ \mathrm{nmax\_file} & -\mathrm{nmax\_file} & \bar{S}_{\mathrm{nmax\_file},\mathrm{nmax\_file}}\\ \end{matrix}\end{split}\]

where \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= nmax_file and shcs->nmax >= nmax. Lines specifying spherical harmonic coefficients (all lines after the first one) can be sorted arbitrarily.

Tip

If nmax is CHARM_SHC_NMAX_MODEL and shcs is NULL, the function returns the maximum harmonic degree of pathname without reading the spherical harmonic coefficients.

For a use-case, see the tip from the documentation to charm_shc_read_bin().

Note

The function modifies shcs->c, shcs->s, shcs->mu and shcs->r by the values from the input file, but it does not touch shcs->nmax, shcs->nc and shcs->ns. If shcs->nmax > nmax, the coefficients beyond nmax are set to zero.

Returns:

Upon successful return, the function returns the maximum harmonic degree from pathname. On error, CHARM_SHC_NMAX_ERROR is returned in addition to the error reporting through err.

unsigned long charm_shc_read_mtx(const char *pathname, unsigned long nmax, charm_shc *shcs, charm_err *err)#

Reads the charm_shc structure to shcs from a text file whose name is the string pointed to by pathname. The structure is loaded up to degree nmax. The file is assumed to has been created by charm_shc_write_mtx(). Error reported by the function (if any) is written to err.

The first line of the input file must specify the maximum harmonic degree nmax_file of the coefficients stored in the file, their scaling parameter mu and the radius of the reference sphere r. Then, starting at a new line, a matrix with a predefined structured specifying the coefficients must follow. The entire file structure can be summarized as:

\[\begin{split}\begin{matrix} \mathrm{nmax\_file} & \mu & R\\ \bar{C}_{00} & \bar{S}_{11} & \bar{S}_{21} & \bar{S}_{31} & \cdots &\bar{S}_{\mathrm{nmax\_file},1}\\ \bar{C}_{10} & \bar{C}_{11} & \bar{S}_{22} & \bar{S}_{32} & \cdots & \bar{S}_{\mathrm{nmax\_file},2}\\ \bar{C}_{20} & \bar{C}_{21} & \bar{C}_{22} & \bar{S}_{33} & \cdots & \bar{S}_{\mathrm{nmax\_file},3}\\ \bar{C}_{30} & \bar{C}_{31} & \bar{C}_{32} & \bar{C}_{33} & \cdots & \bar{S}_{\mathrm{nmax\_file},4}\\ \vdots& \vdots& \vdots& \vdots& \ddots & \vdots \\ \bar{C}_{\mathrm{nmax\_file},0} & \bar{C}_{\mathrm{nmax\_file},1} & \bar{C}_{\mathrm{nmax\_file},2} & \bar{C}_{\mathrm{nmax\_file},3} & \cdots & \bar{C}_{\mathrm{nmax\_file},\mathrm{nmax\_file}} \end{matrix}\end{split}\]

where \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= nmax_file and shcs->nmax >= nmax.

Any empty line in the file (that is, containing only the new line character \n) is ignored.

Tip

If nmax is CHARM_SHC_NMAX_MODEL and shcs is NULL, the function returns the maximum harmonic degree of pathname without reading the spherical harmonic coefficients.

For a use-case, see the tip from the documentation to charm_shc_read_bin().

Note

The function modifies shcs->c, shcs->s, shcs->mu and shcs->r by the values from the input file, but it does not touch shcs->nmax, shcs->nc and shcs->ns. If shcs->nmax > nmax, the coefficients beyond nmax are set to zero.

Returns:

Upon successful return, the function returns the maximum harmonic degree from pathname. On error, CHARM_SHC_NMAX_ERROR is returned in addition to the error reporting through err.

void charm_shc_write_bin(const charm_shc *shcs, unsigned long nmax, const char *pathname, charm_err *err)#

Writes shcs up to degree nmax to a binary file whose name is the string pointed to by pathname. Error reported by the function (if any) is written to err.

The output file is a binary representation of shcs up to degree nmax in the following order:

\[\begin{split}&\mathrm{nmax}, \mu, \, R, \, \bar{C}_{0,0}, \, \bar{C}_{1,0}, \, \bar{C}_{2,0}, \, \cdots, \bar{C}_{\mathrm{nmax},0}, \bar{C}_{1,1},\, \bar{C}_{2,1}, \, \cdots,\\ &\bar{C}_{\mathrm{nmax},1}, \, \bar{C}_{2,2}, \bar{C}_{3,2},\, \cdots,\, \bar{C}_{\mathrm{nmax},\mathrm{nmax}},\, \bar{S}_{0,0},\, \bar{S}_{1,0},\, \bar{S}_{2,0},\, \cdots,\\ &\bar{S}_{\mathrm{nmax},0},\, \bar{S}_{1,1},\, \bar{S}_{2,1},\, \cdots, \bar{S}_{\mathrm{nmax},1},\,\bar{S}_{2,2},\, \bar{S}_{3,2},\, \cdots, \bar{S}_{\mathrm{nmax},\mathrm{nmax}},\end{split}\]

where \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= shcs->nmax.

The path to the output file in pathname must already exist.

Note

The output file is platform-dependent.

void charm_shc_write_tbl(const charm_shc *shcs, unsigned long nmax, const char *formatting, int ordering, const char *pathname, charm_err *err)#

Writes shcs up to degree nmax to a text file whose name is the string pointed to by pathname using the formatting specifier and the ordering scheme for ordering spherical harmonic coefficients. Error reported by the function (if any) is written to err.

The formatting specifier is used for all floating point data of shcs. No extra characters before or after the formatting specifier are expected, not even the space (no internal check). Examples of valid formatting specifiers in double precision are %0.16e, %24.16e or %0.16f. The formatting specifiers may vary with the precision of the library (single, double or quadruple).

If ordering is CHARM_SHC_WRITE_N, the output file has the following structure:

\[\begin{split}\begin{matrix} \mathrm{nmax} & \mu & R\\ 0 & 0 & \bar{C}_{0,0} & \bar{S}_{0,0}\\ 1 & 0 & \bar{C}_{1,0} & \bar{S}_{1,0}\\ \vdots & \vdots & \vdots & \vdots \\ \mathrm{nmax} & 0 & \bar{C}_{\mathrm{nmax},0} & \bar{S}_{\mathrm{nmax},0}\\ 1 & 1 & \bar{C}_{1,1} & \bar{S}_{1,1}\\ \vdots & \vdots & \vdots & \vdots \\ \mathrm{nmax} & 1 & \bar{C}_{\mathrm{nmax},1} & \bar{S}_{\mathrm{nmax},1}\\ 2 & 2 & \bar{C}_{2,2} & \bar{S}_{2,2}\\ \vdots & \vdots & \vdots & \vdots \\ \mathrm{nmax} & \mathrm{nmax} & \bar{C}_{\mathrm{nmax},\mathrm{nmax}} & \bar{S}_{\mathrm{nmax},\mathrm{nmax}}\\ \end{matrix}\end{split}\]

If ordering is CHARM_SHC_WRITE_M, the output file has the following structure:

\[\begin{split}\begin{matrix} \mathrm{nmax} & \mu & R\\ 0 & 0 & \bar{C}_{0,0} & \bar{S}_{0,0}\\ 1 & 0 & \bar{C}_{1,0} & \bar{S}_{1,0}\\ 1 & 1 & \bar{C}_{1,1} & \bar{S}_{1,1}\\ 2 & 0 & \bar{C}_{2,0} & \bar{S}_{2,0}\\ 2 & 1 & \bar{C}_{2,1} & \bar{S}_{2,1}\\ 2 & 2 & \bar{C}_{2,2} & \bar{S}_{2,2}\\ \vdots & \vdots & \vdots & \vdots \\ \mathrm{nmax} & \mathrm{nmax} & \bar{C}_{\mathrm{nmax},\mathrm{nmax}} & \bar{S}_{\mathrm{nmax},\mathrm{nmax}}\\ \end{matrix}\end{split}\]

In either case, \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= shcs->nmax.

The path to the output file in pathname must already exist.

Note

In the quadruple version of CHarm (charmq_shc_write_tbl()), add the Q letter to the formatting specifier. Examples of valid formatting specifiers in quadruple precision are %0.34Qe, %40.34Qe or %0.34Qf (see the documentation to libquadmath).

void charm_shc_write_dov(const charm_shc *shcs, unsigned long nmax, const char *formatting, int ordering, const char *pathname, charm_err *err)#

Writes shcs up to degree nmax to a text file whose name is the string pointed to by pathname using the formatting specifier. Error reported by the function (if any) is written to err. dov is an abbreviation for the degree, order, value formatting.

The formatting specifier is used for all floating point data of shcs. No extra characters before or after the formatting specifier are expected, not even the space (no internal check). Examples of valid formatting specifiers in double precision are %0.16e, %24.16e or %0.16f. The formatting specifiers may vary with the precision of the library (single, double or quadruple).

If ordering is CHARM_SHC_WRITE_N, the output file has the following structure:

\[\begin{split}\begin{matrix} \mathrm{nmax} & \mu & R\\ 0 & 0 & \bar{C}_{0,0}\\ 1 & 0 & \bar{C}_{1,0}\\ 2 & 0 & \bar{C}_{2,0}\\ \vdots & \vdots & \vdots \\ \mathrm{nmax} & 0 & \bar{C}_{\mathrm{nmax},0}\\ 1 & 1 & \bar{C}_{1,1}\\ 1 & -1 & \bar{S}_{1,1}\\ 2 & 1 & \bar{C}_{2,1}\\ 2 & -1 & \bar{S}_{2,1}\\ 3 & 1 & \bar{C}_{3,1}\\ 3 & -1 & \bar{S}_{3,1}\\ \vdots & \vdots & \vdots \\ \mathrm{nmax} & -1 & \bar{S}_{\mathrm{nmax},1}\\ 2 & 2 & \bar{C}_{2,2}\\ 2 & -2 & \bar{S}_{2,2}\\ \vdots & \vdots & \vdots \\ \mathrm{nmax} & -\mathrm{nmax} & \bar{S}_{\mathrm{nmax},\mathrm{nmax}}\\ \end{matrix}\end{split}\]

If ordering is CHARM_SHC_WRITE_M, the output file has the following structure:

\[\begin{split}\begin{matrix} \mathrm{nmax} & \mu & R\\ 0 & 0 & \bar{C}_{0,0}\\ 1 & 0 & \bar{C}_{1,0}\\ 1 & 1 & \bar{C}_{1,1}\\ 1 & -1 & \bar{S}_{1,1}\\ 2 & 0 & \bar{C}_{2,0}\\ 2 & 1 & \bar{C}_{2,1}\\ 2 & -1 & \bar{S}_{2,1}\\ 2 & 2 & \bar{C}_{2,2}\\ 2 & -2 & \bar{S}_{2,2}\\ \vdots & \vdots & \vdots \\ \mathrm{nmax} & -\mathrm{nmax} & \bar{S}_{\mathrm{nmax},\mathrm{nmax}}\\ \end{matrix}\end{split}\]

In either case, \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= shcs->nmax.

The path to the output file in pathname must already exist.

Note

In the quadruple version of CHarm (charmq_shc_write_dov()), add the Q letter to the formatting specifier. Examples of valid formatting specifiers in quadruple precision are %0.34Qe, %40.34Qe or %0.34Qf (see the documentation to libquadmath).

void charm_shc_write_mtx(const charm_shc *shcs, unsigned long nmax, const char *formatting, const char *pathname, charm_err *err)#

Writes shcs up to degree nmax to a text file whose name is the string pointed to by pathname using the formatting specifier. Error reported by the function (if any) is written to err.

The formatting specifier is used for all floating point data of shcs. No extra characters before or after the formatting specifier are expected, not even the space (no internal check). Examples of valid formatting specifiers in double precision are %0.16e, %24.16e or %0.16f. The formatting specifiers may vary with the precision of the library (single, double or quadruple).

The output file has the following structure:

\[\begin{split}\begin{matrix} \mathrm{nmax} & \mu & R\\ \bar{C}_{00} & \bar{S}_{11} & \bar{S}_{21} & \bar{S}_{31} & \cdots &\bar{S}_{\mathrm{nmax},1}\\ \bar{C}_{10} & \bar{C}_{11} & \bar{S}_{22} & \bar{S}_{32} & \cdots & \bar{S}_{\mathrm{nmax},2}\\ \bar{C}_{20} & \bar{C}_{21} & \bar{C}_{22} & \bar{S}_{33} & \cdots & \bar{S}_{\mathrm{nmax},3}\\ \bar{C}_{30} & \bar{C}_{31} & \bar{C}_{32} & \bar{C}_{33} & \cdots & \bar{S}_{\mathrm{nmax},4}\\ \vdots&\vdots &\vdots & \vdots& \ddots & \vdots \\ \bar{C}_{\mathrm{nmax},0} & \bar{C}_{\mathrm{nmax},1} & \bar{C}_{\mathrm{nmax},2} & \bar{C}_{\mathrm{nmax},3} & \cdots & \bar{C}_{\mathrm{nmax},\mathrm{nmax}} \end{matrix}\end{split}\]

where \(\mu\) and \(R\) are the scaling parameter of the coefficients and the associated radius of the reference sphere and \(\bar{C}_{n,m}\) and \(\bar{S}_{n,m}\) are spherical harmonic coefficients of degree n and order m. It must hold that nmax <= shcs->nmax.

The path to the output file in pathname must already exist.

Note

In the quadruple version of CHarm (charmq_shc_write_mtx()), add the Q letter to the formatting specifier. Examples of valid formatting specifiers in quadruple precision are %0.34Qe, %40.34Qe or %0.34Qf (see the documentation to libquadmath).

Arithmetics with the charm_shc structure

These functions perform basic arithmetics with the charm_shc structure such as adding two charm_shc structures, etc.

void charm_shc_add(charm_shc *rop, charm_shc *op1, charm_shc *op2, unsigned long nmin, unsigned long nmax, charm_err *err)#

Adds spherical harmonic coefficients of matching degrees and orders from op1 and op2 and writes the output to rop. The addition starts at degree nmin and ends at nmax.

A few rules and restrictions apply.

  • The mu and r members of rop, op1 and op2 must be equal.

  • nmin cannot be larger than nmax.

  • Neither nmin nor nmax can be larger than rop->nmax.

  • If any degree from nmin to nmax reaches beyond op1->nmax and/or op2->nmax, then the coefficients of that degree(s) are assumed to be zero for op1 and/or op2 (zero padding).

  • rop is never modified outside the nmin to nmax degree range. Keep this in mind when performing an in-place addition.

  • All coefficients in rop in the nmin to nmax degree range are always modified. Due to the zero padding, this is true even if op1->nmax and/or op2->nmax are smaller than nmax.

Note

The function works in-place, that is, rop can be equal to op1 or op2 and op1 can be equal to op2. For instance, charm_shc_add(op1, op1, op1, nmin, nmax, err) adds the coefficients of op1 and op1 from degrees nmin to nmax and writes the result back to op1.

Parameters:
  • rop[out] Result of the operation.

  • op1[inout] First operand.

  • op2[inout] Second operand.

  • err[out] Error reported by the function (if any).

void charm_shc_sub(charm_shc *rop, charm_shc *op1, charm_shc *op2, unsigned long nmin, unsigned long nmax, charm_err *err)#

The same as charm_shc_add() but the coefficients of op2 are subtracted from the coefficients of op1.

void charm_shc_mul(charm_shc *rop, charm_shc *op1, charm_shc *op2, unsigned long nmin, unsigned long nmax, charm_err *err)#

The same as charm_shc_add() but the coefficients of op1 are multiplied by the coefficients of op2.

Note

Multiplying coefficients of matching degrees and orders from op1 and op2 in the spectral domain is not equivalent to the multiplication the functions given by op1 and op2 in the spatial domain.

void charm_shc_mul_degree_wise(charm_shc *shcs, const double *a, unsigned long nmin, unsigned long nmax, charm_err *err)#

Multiplies coefficients of shcs by degree-dependent factors pointed to by a starting at degree nmin and ending at nmax.

All spherical harmonic coefficients of degree nmin are multiplied by a[0], all coefficients of degree nmin + 1 are multiplied by a[1] and so on.

Parameters:
  • shcs[inout] Spherical harmonic coefficients.

  • a[in] Array of the degree-dependent factors. The pointer a must have an access to nmax - nmin + 1 array elements. The a[0] element represents the multiplier for all coefficients of degree nmin, a[1] holds the multiplier for all coefficients of degree nmin + 1, etc.

  • nmin[in] Starting degree to apply the degree-dependent factor.

  • nmax[in] Ending degree to apply the degree-dependent factor.

  • err[out] Error reported by the function (if any).

void charm_shc_mul_order_wise(charm_shc *shcs, const double *a, unsigned long nmin, unsigned long nmax, charm_err *err)#

Multiplies coefficients of shcs by order-dependent factors pointed to by a starting at degree nmin and ending at degree nmax.

Parameters:
  • shcs[inout] Spherical harmonic coefficients.

  • a[in] Array of the order-dependent factors. The pointer a must have an access to nmax + 1 array elements. The a[0] element represents the multiplier for all coefficients of order 0 within degrees from nmin to nmax, a[1] holds the multiplier for all coefficients of order 1 within degrees from nmin to nmax, etc., a[nmax] is the multiplier for coefficients of order nmax.

  • nmin[in] Starting degree to apply the order-dependent factor.

  • nmax[in] Ending degree to apply the order-dependent factor.

  • err[out] Error reported by the function (if any).

void charm_shc_div(charm_shc *rop, charm_shc *op1, charm_shc *op2, unsigned long nmin, unsigned long nmax, charm_err *err)#

The same as charm_shc_add() but the coefficients of op1 are divided by the coefficients of op2.

Note

Dividing coefficients of matching degrees and orders from op1 and op2 in the spectral domain is not equivalent to the division of the functions given by op1 and op2 in the spatial domain.

Note

The coefficients of op2 must not be zero within the nmin to nmax range to avoid division by zero. The only exceptions are the non-existing coefficients \(\bar{S}_{n,0}\).

void charm_shc_div_degree_wise(charm_shc *shcs, const double *a, unsigned long nmin, unsigned long nmax, charm_err *err)#

The same as charm_shc_mul_degree_wise(), but the coefficients are divided by the degree-dependent factor.

void charm_shc_div_order_wise(charm_shc *shcs, const double *a, unsigned long nmin, unsigned long nmax, charm_err *err)#

The same as charm_shc_mul_order_wise(), but the coefficients are divided by the order-dependent factor.

Spectrum from the charm_shc structure

These functions compute the spectrum from the charm_shc structure in the form of (difference) degree variances and (difference) degree amplitudes.

void charm_shc_dv(const charm_shc *shcs, unsigned long nmax, double *dv, charm_err *err)#

Computes degree variances (spectrum) dv up to degree nmax of a signal given by spherical harmonic coefficients in shcs. Each array index of dv, n = 0, 1, …, nmax, corresponds to the degree variance of the respective degree n. Error reported by the function (if any) is written to err.

The degree variances are given as

\[\mathrm{dv}_n = \sum_{m = 0}^{n}(\bar{C}_{nm}^2 + \bar{S}_{nm}^2) \,.\]

Note

The shcs->mu and shcs->r parameters are not used to evaluate the degree variances, since this appears to be the most common way in practice.

void charm_shc_da(const charm_shc *shcs, unsigned long nmax, double *da, charm_err *err)#

Computes degree amplitudes (square root of degree variances) da up to degree nmax of a signal given by spherical harmonic coefficients in shcs. Each array index of da, n = 0, 1, …, nmax, corresponds to the degree amplitude of the respective degree n. Error reported by the function (if any) is written to err.

The degree amplitudes are given as

\[\mathrm{da}_n = \sqrt{\sum_{m = 0}^{n}(\bar{C}_{nm}^2 + \bar{S}_{nm}^2)} \,.\]

Note

The shcs->mu and shcs->r parameters are not used to evaluate the degree amplitudes, since this appears to be the most common way in practice.

void charm_shc_ddv(const charm_shc *shcs1, const charm_shc *shcs2, unsigned long nmax, double *ddv, charm_err *err)#

Computes difference degree variances (difference spectrum) ddv up to degree nmax between a signal given by spherical harmonic coefficients in shcs1 and shcs2. Each array index of ddv, n = 0, 1, …, nmax, corresponds to the difference degree variance of the respective degree n. Error reported by the function (if any) is written to err.

The difference degree variances are given as

\[\mathrm{ddv}_n = \sum_{m = 0}^{n}\left(\left(\bar{C}_{nm}^{(1)} - \bar{C}_{nm}^{(2)}\right)^2 + \left(\bar{S}_{nm}^{(1)} - \bar{S}_{nm}^{(2)}\right)^2\right) \,.\]

Note

The shcs->mu and shcs->r parameters are not used to evaluate the differece degree variances, since this appears to be the most common way in practice. However, the values of mu and r in shcs1 and shcs2 must be equal (the function performs a check on this).

void charm_shc_dda(const charm_shc *shcs1, const charm_shc *shcs2, unsigned long nmax, double *da, charm_err *err)#

Computes difference degree amplitudes (square root of difference degree variances) dda up to degree nmax between a signal given by spherical harmonic coefficients in shcs1 and shcs2. Each array index of dda, n = 0, 1, …, nmax, corresponds to the difference degree amplitude of the respective degree n. Error reported by the function (if any) is written to err.

The difference degree amplitudes are given as

\[\mathrm{dda}_n = \sqrt{\sum_{m = 0}^{n}\left(\left(\bar{C}_{nm}^{(1)} - \bar{C}_{nm}^{(2)}\right)^2 + \left(\bar{S}_{nm}^{(1)} - \bar{S}_{nm}^{(2)}\right)^2\right)} \,.\]

Note

The shcs->mu and shcs->r parameters are not used to evaluate the difference degree amplitudes, since this appears to be the most common way in practice. However, the values of mu and r in shcs1 and shcs2 must be equal (the function performs a check on this).

Miscellaneous functions

void charm_shc_rescale(charm_shc *shcs, double munew, double rnew, charm_err *err)#

Rescales spherical harmonic coefficients in shcs to a new scaling parameter munew and a new radius of the reference sphere rnew:

\[ \begin{align}\begin{aligned}\begin{split}\bar{C}_{nm}^{\mathrm{new}} = \frac{\mu}{\mu_{\mathrm{new}}} \, \left( \frac{R}{R_{\mathrm{new}}} \right)^n \, \bar{C}_{nm}\,,\\\end{split}\\\bar{S}_{nm}^{\mathrm{new}} = \frac{\mu}{\mu_{\mathrm{new}}} \, \left( \frac{R}{R_{\mathrm{new}}} \right)^n \, \bar{S}_{nm}\,.\end{aligned}\end{align} \]

After the conversion, shcs->mu and shcs->r are updated to munew and rnew, respectively.

Error reported by the function (if any) is written to err.

Enums

Ordering scheme to write spherical harmonic coefficients with charm_shc_write_tbl() and charm_shc_write_dov().

Values:

enumerator CHARM_SHC_WRITE_N#

Harmonic degree varies fastest.

enumerator CHARM_SHC_WRITE_M#

Harmonic order varies fastest.

struct charm_shc#

Structure to store spherical harmonic coefficients and some associated data.

If CHarm is compiled with the MPI support, the data of the structure can be distributed across MPI processes. This is useful if your dataset is so large that it would not fit into the RAM of a single computing node. The members of the structure are therefore divided into two groups.

  • Members common to both non-distributed and distributed structures. These are always accessible.

  • Members specific to distributed structures only. These are accessible only when CHarm was compiled with the MPI support.

Members common to non-distributed and distributed structures

unsigned long nmax#

Maximum harmonic degree of the spherical harmonic coefficients.

double mu#

Scaling parameter \(\mu\) associated with the spherical harmonic coefficients, for instance, the geocentric gravitational constant. In case the coefficients are not associated with any scaling parameter (as it is, for instance, with planetary topographies), simply set this variable to 1.0 (not to 0.0!).

double r#

Radius of the reference sphere \(R\), to which the spherical harmonic coefficients refer (are scaled). The value must be larger than zero. To get the unit sphere, as needed, for instance, when working with planetary topographies, set this variable to 1.0.

size_t nc#

Total number of spherical harmonic coefficients \(\bar{C}_{nm}\). The value is always larger than zero.

size_t ns#

Total number of spherical harmonic coefficients \(\bar{S}_{nm}\). The value is always larger than zero.

double **c#

Spherical harmonic coefficients \(\bar{C}_{nm}\) stored as a 2D array. The first dimension is related to harmonic orders and the second one to harmonic degrees. Importantly, the number of columns varies for each row as follows:

Assuming the charm_shc structure was initialized up to some degree unsigned long nmax as

charm_shc *shcs = charm_shc_calloc(nmax, 1.0, 1.0);

harmonic coefficients of degree n <= nmax and order m <= n can be accessed as:

shcs->c[m][n - m];

The coefficients in charm_shc.c are stored in a contiguous block of memory. For fast sequential access, the loop over harmonic orders should always be the outer one, in which the degree-dependent loop is nested, such as:

charm_shc *shcs = charm_shc_calloc(nmax, 1.0, 1.0);
for (unsigned long m = 0; m <= nmax; m++)
    for (unsigned long n = m; n <= nmax; n++)
        shcs->c[m][n - m];

Warning

charm_shc.c is not a 2D rectangular array.

double **s#

Spherical harmonic coefficients \(\bar{S}_{nm}\). The same comments as for charm_shc.c apply to charm_shc.s, too.

_Bool owner#

_Bool distributed#

Note

If CHarm was compiled without the MPI support (default), charm_shc.distributed is always 0.

Members available to distributed structures only

Note

The members that follow are available only when CHarm is compiled with the MPI support (--enable-mpi, refer to charm_mpi for further details).

size_t local_nc#

Total number of spherical harmonic coefficients \(\bar{C}_{nm}\) locally accessible to an MPI process. If 0, no coefficients are stored locally.

size_t local_ns#

Total number of spherical harmonic coefficients \(\bar{S}_{nm}\) locally accessible to an MPI process. If 0, no coefficients are stored locally.

size_t local_nchunk#

Total number of chunks of spherical harmonic orders that are stored locally. If 0, no chunks are stored locally.

unsigned long *local_order#

Spherical harmonic orders specifying chunks of spherical harmonic coefficients that are locally available to an MPI process. The pointer is NULL if charm_shc.local_nchunk is 0.

Assume there is k = charm_shc.local_nchunk local chunks. The pointer charm_shc.local_order points to an array of 2 * k elements having the structure:

\[\underbrace{m_0, m_1}_{\textrm{chunk 0}} | \underbrace{m_2, m_3}_{\textrm{chunk 1}} | \underbrace{...}_{\textrm{chunks 2 to }k - 2} | \underbrace{m_{2k - 2}, m_{2k - 1}}_{\textrm{chunk }k - 1}{,}\]

where \(m_{2j}\) and \(m_{2j + 1}\), \(j = 0, 1, ..., k - 1\), denote the minimum and the maximum orders of the chunks, respectively. Spherical harmonic coefficients \(\bar{C}_{nm}\) and \(\bar{S}_{nm}\) of all degrees \(n = m, m + 1, ..., n_{\textrm{max}}\) and orders \(m = m_{2j}, ..., m_{2j + 1}\), \(j = 0, 1, ..., k - 1\), are accessible to an MPI process through charm_shc.c and charm_shc.s. The ordering of the coefficients in charm_shc.c is then as follows:

\[\underbrace{\bar{C}_{m_0, m_0}, \bar{C}_{m_0 + 1, m_0}, ..., \bar{C}_{\mathrm{nmax}, m_0}, \bar{C}_{m_0 + 1, m_0 + 1}, ... ,\bar{C}_{\mathrm{nmax}, m_0 + 1}, ..., \bar{C}_{\mathrm{nmax}, m_1}}_{\textrm{chunk 0}} | \underbrace{\bar{C}_{m_2, m_2}, ..., \bar{C}_{\mathrm{nmax}, m_3}}_{\textrm{chunk 1}} | \underbrace{...}_{\textrm{chunks 2 to }k - 2} | \underbrace{\bar{C}_{m_{2k - 2}, m_{2k - 2}}, ..., \bar{C}_{\mathrm{nmax}}, m_{2k - 1}}_{\textrm{chunk }k - 1}{.}\]

The total number of these coefficients is stored in charm_shc.local_nc. It can also be determined a priori by charm_mpi_shc_local_ncs(). The same ordering and the number of coefficients applies to \(\bar{S}_{nm}\) in charm_shc.s.

Note

Whenever creating charm_shc through the CHarm’s API, charm_shc.local_order is always a deep copy of the user’s original data local_order. Users can therefore safely free their original local_order array after creating charm_shc.

Note

Sounds complicated? It isn’t! Have a look at the charm_mpi module and the cookbook.

MPI_Comm comm#

MPI communicator defining the group of MPI processes to distribute the structure across.