/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk),
* Matthieu Schaller (schaller@strw.leidenuniv.nl).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
******************************************************************************/
/* Config parameters. */
#include
/* Some standard headers. */
#include
#include
#include
#include
#include
/* This object's header. */
#include "units.h"
/* Includes. */
#include "adiabatic_index.h"
#include "error.h"
#include "restart.h"
/**
* @brief Initialises the unit_system structure with CGS system
*
* @param us The unit_system to initialize
*/
void units_init_cgs(struct unit_system* us) {
us->UnitMass_in_cgs = 1.;
us->UnitLength_in_cgs = 1.;
us->UnitTime_in_cgs = 1.;
us->UnitCurrent_in_cgs = 1.;
us->UnitTemperature_in_cgs = 1.;
}
/**
* @brief Initialises the unit_system structure with SI system
*
* @param us The unit_system to initialize
*/
void units_init_si(struct unit_system* us) {
us->UnitMass_in_cgs = 1000.;
us->UnitLength_in_cgs = 100.;
us->UnitTime_in_cgs = 1.;
us->UnitCurrent_in_cgs = 1.;
us->UnitTemperature_in_cgs = 1.;
}
/**
* @brief Initialise the unit_system with values for the base units.
*
* @param us The #unit_system to initialise.
* @param U_M_in_cgs The mass unit in [g].
* @param U_L_in_cgs The length unit in [cm].
* @param U_t_in_cgs The time unit in [s].
* @param U_C_in_cgs The current unit in [A].
* @param U_T_in_cgs The temperature unit in [K].
*/
void units_init(struct unit_system* us, double U_M_in_cgs, double U_L_in_cgs,
double U_t_in_cgs, double U_C_in_cgs, double U_T_in_cgs) {
us->UnitMass_in_cgs = U_M_in_cgs;
us->UnitLength_in_cgs = U_L_in_cgs;
us->UnitTime_in_cgs = U_t_in_cgs;
us->UnitCurrent_in_cgs = U_C_in_cgs;
us->UnitTemperature_in_cgs = U_T_in_cgs;
}
/**
* @brief Initialises the unit_system structure with the constants given in
* the parameter file.
*
* @param us The unit_system to initialize.
* @param params The parsed parameter file.
* @param category The section of the parameter file to read from.
*/
void units_init_from_params(struct unit_system* us, struct swift_params* params,
const char* category) {
char buffer[200];
sprintf(buffer, "%s:UnitMass_in_cgs", category);
us->UnitMass_in_cgs = parser_get_param_double(params, buffer);
sprintf(buffer, "%s:UnitLength_in_cgs", category);
us->UnitLength_in_cgs = parser_get_param_double(params, buffer);
sprintf(buffer, "%s:UnitVelocity_in_cgs", category);
const double unitVelocity = parser_get_param_double(params, buffer);
us->UnitTime_in_cgs = us->UnitLength_in_cgs / unitVelocity;
sprintf(buffer, "%s:UnitCurrent_in_cgs", category);
us->UnitCurrent_in_cgs = parser_get_param_double(params, buffer);
sprintf(buffer, "%s:UnitTemp_in_cgs", category);
us->UnitTemperature_in_cgs = parser_get_param_double(params, buffer);
}
/**
* @brief Initialises the unit_system structure with the constants given in
* the parameter file. Uses a default if the values are not present in the file.
*
* @param us The unit_system to initialize.
* @param params The parsed parameter file.
* @param category The section of the parameter file to read from.
* @param def The default unit system to copy from if required.
*/
void units_init_default(struct unit_system* us, struct swift_params* params,
const char* category, const struct unit_system* def) {
if (!def) error("Default unit_system not allocated");
char buffer[200];
sprintf(buffer, "%s:UnitMass_in_cgs", category);
us->UnitMass_in_cgs =
parser_get_opt_param_double(params, buffer, def->UnitMass_in_cgs);
sprintf(buffer, "%s:UnitLength_in_cgs", category);
us->UnitLength_in_cgs =
parser_get_opt_param_double(params, buffer, def->UnitLength_in_cgs);
sprintf(buffer, "%s:UnitVelocity_in_cgs", category);
const double defaultVelocity = def->UnitLength_in_cgs / def->UnitTime_in_cgs;
const double unitVelocity =
parser_get_opt_param_double(params, buffer, defaultVelocity);
us->UnitTime_in_cgs = us->UnitLength_in_cgs / unitVelocity;
sprintf(buffer, "%s:UnitCurrent_in_cgs", category);
us->UnitCurrent_in_cgs =
parser_get_opt_param_double(params, buffer, def->UnitCurrent_in_cgs);
sprintf(buffer, "%s:UnitTemp_in_cgs", category);
us->UnitTemperature_in_cgs =
parser_get_opt_param_double(params, buffer, def->UnitTemperature_in_cgs);
}
/**
* @brief Copy the content of a #unit_system to another one.
*
* @param dest The destination of the copy.
* @param src The source of the copy.
*/
void units_copy(struct unit_system* dest, const struct unit_system* src) {
dest->UnitMass_in_cgs = src->UnitMass_in_cgs;
dest->UnitLength_in_cgs = src->UnitLength_in_cgs;
dest->UnitTime_in_cgs = src->UnitTime_in_cgs;
dest->UnitCurrent_in_cgs = src->UnitCurrent_in_cgs;
dest->UnitTemperature_in_cgs = src->UnitTemperature_in_cgs;
}
/**
* @brief Returns the base unit conversion factor for a given unit system
* @param us The unit_system used
* @param baseUnit The base unit
*/
double units_get_base_unit(const struct unit_system* us,
enum base_units baseUnit) {
switch (baseUnit) {
case UNIT_MASS:
return us->UnitMass_in_cgs;
case UNIT_LENGTH:
return us->UnitLength_in_cgs;
case UNIT_TIME:
return us->UnitTime_in_cgs;
case UNIT_CURRENT:
return us->UnitCurrent_in_cgs;
case UNIT_TEMPERATURE:
return us->UnitTemperature_in_cgs;
default:
error("Invalid base Unit");
}
return 0.0;
}
/**
* @brief Returns the base unit symbol used internally
* @param baseUnit The base unit
*/
const char* units_get_base_unit_internal_symbol(enum base_units baseUnit) {
switch (baseUnit) {
case UNIT_MASS:
return "U_M";
case UNIT_LENGTH:
return "U_L";
case UNIT_TIME:
return "U_t";
case UNIT_CURRENT:
return "U_I";
case UNIT_TEMPERATURE:
return "U_T";
default:
error("Invalid base Unit");
}
return "";
}
/**
* @brief Returns the base unit symbol in the cgs system
* @param baseUnit The base unit
*/
const char* units_get_base_unit_cgs_symbol(enum base_units baseUnit) {
switch (baseUnit) {
case UNIT_MASS:
return "g";
case UNIT_LENGTH:
return "cm";
case UNIT_TIME:
return "s";
case UNIT_CURRENT:
return "A";
case UNIT_TEMPERATURE:
return "K";
default:
error("Invalid base Unit");
}
return "";
}
/**
* @brief Return an array of exponents of the base units required to construct a
* given unit.
*
* @param baseUnitsExp (return) The array of base-unit exponents.
* @param unit The unit we want the exponents for.
*/
void units_get_base_unit_exponents_array(float baseUnitsExp[5],
enum unit_conversion_factor unit) {
/* Init everything */
for (int k = 0; k < 5; ++k) baseUnitsExp[k] = 0.f;
switch (unit) {
case UNIT_CONV_NO_UNITS:
break;
case UNIT_CONV_MASS:
baseUnitsExp[UNIT_MASS] = 1.f;
break;
case UNIT_CONV_LENGTH:
baseUnitsExp[UNIT_LENGTH] = 1.f;
break;
case UNIT_CONV_TIME:
baseUnitsExp[UNIT_TIME] = 1.f;
break;
case UNIT_CONV_FREQUENCY:
case UNIT_CONV_SSFR:
case UNIT_CONV_PHOTONS_PER_TIME:
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_FREQUENCY_SQUARED:
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_DENSITY:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = -3.f;
break;
case UNIT_CONV_SPEED:
case UNIT_CONV_VELOCITY:
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_ACCELERATION:
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_POTENTIAL:
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_MOMENTUM:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_ANGULAR_MOMENTUM:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_FORCE:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_TIDAL_TENSOR:
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_ENERGY:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_ENERGY_PER_UNIT_MASS:
case UNIT_CONV_VELOCITY_SQUARED:
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_ENERGY_VELOCITY:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 3.f;
baseUnitsExp[UNIT_TIME] = -3.f;
break;
case UNIT_CONV_ENTROPY:
baseUnitsExp[UNIT_MASS] = 2.f - hydro_gamma;
baseUnitsExp[UNIT_LENGTH] = 3.f * hydro_gamma - 1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_ENTROPY_PER_UNIT_MASS:
baseUnitsExp[UNIT_MASS] = 1.f - hydro_gamma;
baseUnitsExp[UNIT_LENGTH] = 3.f * hydro_gamma - 1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_PHYSICAL_ENTROPY_PER_UNIT_MASS:
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -2.f;
baseUnitsExp[UNIT_TEMPERATURE] = -1.f;
break;
case UNIT_CONV_POWER:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -3.f;
break;
case UNIT_CONV_PRESSURE:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = -1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_ELECTRIC_CHARGE:
baseUnitsExp[UNIT_TIME] = 1.f;
baseUnitsExp[UNIT_CURRENT] = 1.f;
break;
case UNIT_CONV_ELECTRIC_VOLTAGE:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -3.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_ELECTRIC_CAPACITANCE:
baseUnitsExp[UNIT_MASS] = -1.f;
baseUnitsExp[UNIT_LENGTH] = -2.f;
baseUnitsExp[UNIT_TIME] = 4;
baseUnitsExp[UNIT_CURRENT] = 2.f;
break;
case UNIT_CONV_ELECTRIC_RESISTANCE:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -3.f;
baseUnitsExp[UNIT_CURRENT] = -2.f;
break;
case UNIT_CONV_ELECTRIC_CONDUCTANCE:
baseUnitsExp[UNIT_MASS] = -1.f;
baseUnitsExp[UNIT_LENGTH] = -2.f;
baseUnitsExp[UNIT_TIME] = 3.f;
baseUnitsExp[UNIT_CURRENT] = 2.f;
break;
case UNIT_CONV_MAGNETIC_FLUX:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -2.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_MAGNETIC_FIELD:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_MAGNETIC_FIELD_VECTOR_POTENTIAL:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_MAGNETIC_FIELD_PER_TIME:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_TIME] = -3.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_MAGNETIC_FIELD_SQUARED:
baseUnitsExp[UNIT_MASS] = 2.f;
baseUnitsExp[UNIT_TIME] = -4.f;
baseUnitsExp[UNIT_CURRENT] = -2.f;
break;
case UNIT_CONV_MAGNETIC_CURL:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = -1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_MAGNETIC_DIVERGENCE:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = -1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_MAGNETIC_INDUCTANCE:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -2.f;
baseUnitsExp[UNIT_CURRENT] = -2.f;
break;
case UNIT_CONV_MAGNETIC_HELICITY:
baseUnitsExp[UNIT_MASS] = 2.f;
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -4.f;
baseUnitsExp[UNIT_CURRENT] = -2.f;
break;
case UNIT_CONV_MAGNETIC_CROSS_HELICITY:
baseUnitsExp[UNIT_MASS] = 2.f;
baseUnitsExp[UNIT_TIME] = -3.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_ELECTRIC_CHARGE_FIELD_STRENGTH:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -3.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_ELECTRIC_CHARGE_FIELD_STRENGTH_RATE:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = 1.f;
baseUnitsExp[UNIT_TIME] = -4.f;
baseUnitsExp[UNIT_CURRENT] = -1.f;
break;
case UNIT_CONV_TEMPERATURE:
baseUnitsExp[UNIT_TEMPERATURE] = 1.f;
break;
case UNIT_CONV_AREA:
baseUnitsExp[UNIT_LENGTH] = 2.f;
break;
case UNIT_CONV_VOLUME:
baseUnitsExp[UNIT_LENGTH] = 3.f;
break;
case UNIT_CONV_INV_VOLUME:
case UNIT_CONV_NUMBER_DENSITY:
baseUnitsExp[UNIT_LENGTH] = -3.f;
break;
case UNIT_CONV_SFR:
case UNIT_CONV_MASS_PER_UNIT_TIME:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_DIFF_RATE:
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_DIFF_COEFF:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = -1.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_RADIATION_FLUX:
case UNIT_CONV_ENERGY_FLUX_PER_UNIT_SURFACE:
case UNIT_CONV_ENERGY_FLUX_DENSITY:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_TIME] = -3.f;
break;
case UNIT_CONV_ENERGY_DENSITY:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = -1.f;
baseUnitsExp[UNIT_TIME] = -2.f;
break;
case UNIT_CONV_INV_TIME:
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_INV_AREA:
baseUnitsExp[UNIT_LENGTH] = -2.f;
break;
case UNIT_CONV_POWER_DENSITY:
baseUnitsExp[UNIT_MASS] = 1.f;
baseUnitsExp[UNIT_LENGTH] = -1.f;
baseUnitsExp[UNIT_TIME] = -3.f;
break;
case UNIT_CONV_GASOLINE_DIFF_RATE:
case UNIT_CONV_THERMAL_DIFFUSIVITY:
baseUnitsExp[UNIT_LENGTH] = 2.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_NUMBER_DENSITY_PER_TIME:
baseUnitsExp[UNIT_LENGTH] = -3.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
case UNIT_CONV_PHOTON_FLUX_PER_UNIT_SURFACE:
baseUnitsExp[UNIT_LENGTH] = -2.f;
baseUnitsExp[UNIT_TIME] = -1.f;
break;
default:
error("Invalid choice of pre-defined units");
break;
}
}
/**
* @brief Returns the conversion factor for a given unit in the chosen unit
* system
* @param us The system of units in use
* @param unit The unit to convert
*/
double units_cgs_conversion_factor(const struct unit_system* us,
enum unit_conversion_factor unit) {
float baseUnitsExp[5] = {0.f};
units_get_base_unit_exponents_array(baseUnitsExp, unit);
return units_general_cgs_conversion_factor(us, baseUnitsExp);
}
/**
* @brief Returns the h factor exponentiation for a given unit
* @param us The system of units in use
* @param unit The unit to convert
*/
float units_h_factor(const struct unit_system* us,
enum unit_conversion_factor unit) {
float baseUnitsExp[5] = {0.f};
units_get_base_unit_exponents_array(baseUnitsExp, unit);
return units_general_h_factor(us, baseUnitsExp);
}
/**
* @brief Returns a string containing the exponents of the base units making up
* the conversion factors
*/
void units_cgs_conversion_string(char* buffer, const struct unit_system* us,
enum unit_conversion_factor unit,
float scale_factor_exponent) {
float baseUnitsExp[5] = {0.f};
units_get_base_unit_exponents_array(baseUnitsExp, unit);
units_general_cgs_conversion_string(buffer, us, baseUnitsExp,
scale_factor_exponent);
}
/**
* @brief Returns the conversion factor for a given unit (expressed in terms of
* the 5 fundamental units) in the chosen unit system
* @param us The unit system used
* @param baseUnitsExponents The exponent of each base units required to form
* the desired quantity. See conversionFactor() for a working example
*/
double units_general_cgs_conversion_factor(const struct unit_system* us,
const float baseUnitsExponents[5]) {
double factor = 1.;
for (int i = 0; i < 5; ++i)
if (baseUnitsExponents[i] != 0)
factor *= pow(units_get_base_unit(us, (enum base_units)i),
baseUnitsExponents[i]);
return factor;
}
/**
* @brief Returns the h factor exponentiation for a given unit (expressed in
* terms of the 5 fundamental units)
* @param us The unit system used
* @param baseUnitsExponents The exponent of each base units required to form
* the desired quantity. See conversionFactor() for a working example
*/
float units_general_h_factor(const struct unit_system* us,
const float baseUnitsExponents[5]) {
float factor_exp = 0.f;
factor_exp += -baseUnitsExponents[UNIT_MASS];
factor_exp += -baseUnitsExponents[UNIT_LENGTH];
factor_exp += -baseUnitsExponents[UNIT_TIME];
return factor_exp;
}
/**
* @brief Returns a string containing the exponents of the base units making up
* the conversion factors (expressed in terms of the 5 fundamental units)
*
* Note that in accordance with the SWIFT philosphy, there are no h-factors
* in any units and hence in the string returned here.
*
* @param buffer The buffer in which to write (The buffer must be long enough,
* 140 chars at most)
* @param us The UnitsSystem in use.
* @param baseUnitsExponents The exponent of each base units required to form
* the desired quantity. See conversionFactor() for a working example.
* @param scale_factor_exponent The scale-factor exponent to use to convert this
* unit to physical units.
*/
void units_general_cgs_conversion_string(char* buffer,
const struct unit_system* us,
const float baseUnitsExponents[5],
float scale_factor_exponent) {
char temp[32] = {0};
const double a_exp = scale_factor_exponent;
const double h_exp = 0.; /* There are no h-factors in SWIFT outputs. */
/* Check whether we are unitless or not */
char isAllZero = 1;
for (int i = 0; i < 5; ++i)
if (baseUnitsExponents[i] != 0.) isAllZero = 0;
if (isAllZero) {
sprintf(buffer, "[ - ] ");
return;
}
/* Add a-factor */
if (a_exp == 0) {
/* Nothing to print */
} else if (a_exp == 1) {
sprintf(buffer, "a ");
} else if (remainder(a_exp, 1.) == 0) {
sprintf(buffer, "a^%d ", (int)a_exp);
} else {
sprintf(buffer, "a^%7.4f ", a_exp);
}
/* Add h-factor */
if (h_exp == 0) {
/* Nothing to print */
} else if (h_exp == 1) {
sprintf(temp, "h ");
strcat(buffer, temp);
} else if (remainder(h_exp, 1.) == 0) {
sprintf(temp, "h^%d ", (int)h_exp);
strcat(buffer, temp);
} else {
sprintf(temp, "h^%7.4f ", h_exp);
strcat(buffer, temp);
}
/* Add conversion units */
for (int i = 0; i < 5; ++i)
if (baseUnitsExponents[i] != 0) {
if (baseUnitsExponents[i] == 0.) {
sprintf(temp, " ");
} else if (baseUnitsExponents[i] == 1.) {
sprintf(temp, "%s ",
units_get_base_unit_internal_symbol((enum base_units)i));
} else if (remainder(baseUnitsExponents[i], 1.) == 0) {
sprintf(temp, "%s^%d ",
units_get_base_unit_internal_symbol((enum base_units)i),
(int)baseUnitsExponents[i]);
} else {
sprintf(temp, "%s^%7.4f ",
units_get_base_unit_internal_symbol((enum base_units)i),
baseUnitsExponents[i]);
}
strcat(buffer, temp);
}
/* Add CGS units */
strcat(buffer, " [ ");
for (int i = 0; i < 5; ++i) {
if (baseUnitsExponents[i] != 0) {
if (baseUnitsExponents[i] == 0.) {
continue;
} else if (baseUnitsExponents[i] == 1.) {
sprintf(temp, "%s ",
units_get_base_unit_cgs_symbol((enum base_units)i));
} else if (remainder(baseUnitsExponents[i], 1.) == 0) {
sprintf(temp, "%s^%d ",
units_get_base_unit_cgs_symbol((enum base_units)i),
(int)baseUnitsExponents[i]);
} else {
sprintf(temp, "%s^%7.4f ",
units_get_base_unit_cgs_symbol((enum base_units)i),
baseUnitsExponents[i]);
}
strcat(buffer, temp);
}
}
strcat(buffer, "]");
}
/**
* @brief Are the two unit systems equal ?
*
* @param a The First #unit_system
* @param b The second #unit_system
* @return 1 if the systems are the same, 0 otherwise
*/
int units_are_equal(const struct unit_system* a, const struct unit_system* b) {
if (a->UnitMass_in_cgs != b->UnitMass_in_cgs) return 0;
if (a->UnitLength_in_cgs != b->UnitLength_in_cgs) return 0;
if (a->UnitTime_in_cgs != b->UnitTime_in_cgs) return 0;
if (a->UnitCurrent_in_cgs != b->UnitCurrent_in_cgs) return 0;
if (a->UnitTemperature_in_cgs != b->UnitTemperature_in_cgs) return 0;
return 1;
}
/**
* @brief Return the unit conversion factor between two systems
*
* @param from The #unit_system we are converting from
* @param to The #unit_system we are converting to
* @param baseUnitsExponents The exponent of each base units required to form
* the desired quantity. See conversionFactor() for a working example
*/
double units_general_conversion_factor(const struct unit_system* from,
const struct unit_system* to,
const float baseUnitsExponents[5]) {
const double from_cgs =
units_general_cgs_conversion_factor(from, baseUnitsExponents);
const double to_cgs =
units_general_cgs_conversion_factor(to, baseUnitsExponents);
return from_cgs / to_cgs;
}
/**
* @brief Return the unit conversion factor between two systems
*
* @param from The #unit_system we are converting from
* @param to The #unit_system we are converting to
* @param unit The unit we are converting
*
* @return The conversion factor
*/
double units_conversion_factor(const struct unit_system* from,
const struct unit_system* to,
enum unit_conversion_factor unit) {
float baseUnitsExp[5] = {0.f};
units_get_base_unit_exponents_array(baseUnitsExp, unit);
return units_general_conversion_factor(from, to, baseUnitsExp);
}
/**
* @brief print a #unit_system
*
* @param us The #unit_system
*/
void units_print(const struct unit_system* us) {
message("Units:");
message("\tUnit Mass: %g", us->UnitMass_in_cgs);
message("\tUnit Length: %g", us->UnitLength_in_cgs);
message("\tUnit Time: %g", us->UnitTime_in_cgs);
message("\tUnit Current: %g", us->UnitCurrent_in_cgs);
message("\tUnit Temperature: %g", us->UnitTemperature_in_cgs);
}
/**
* @brief Write a units struct to the given FILE as a stream of bytes.
*
* @param us the units
* @param stream the file stream
*/
void units_struct_dump(const struct unit_system* us, FILE* stream) {
restart_write_blocks((void*)us, sizeof(struct unit_system), 1, stream,
"units", "units");
}
/**
* @brief Restore a units struct from the given FILE as a stream of bytes.
*
* @param us the units
* @param stream the file stream
*/
void units_struct_restore(const struct unit_system* us, FILE* stream) {
restart_read_blocks((void*)us, sizeof(struct unit_system), 1, stream, NULL,
"units");
}