These are chat archives for Fortran-FOSS-Programmers/General-Discussion

9th
Sep 2016 Stefano Zaghi
@szaghi
Sep 09 2016 12:52

@tomedunn Hi Tom, the week-diet was good... FURY now support temperature like conversions (with an offset) that can be defined by the friendly builtin string parser of the FURY uom and even a totally generic conversion formula that however can be defined less friendly...
for example you can now do the followings

type(uom)       :: dBm            !< dBm unit.
type(uom)       :: mW             !< mW unit.
type(uom)       :: kelvin         !< Kelvin unit.
type(uom)       :: celsius        !< Celsius unit.
type(qreal)     :: q1             !< A quantity.
type(qreal)     :: q2             !< A quantity.
type(qreal)     :: q3             !< A quantity.
type(dBm_to_mW) :: dBm2mW         !< Converter from dBm to mW.

dBm = uom('dBm = @user mW')
mW = uom('mW')

call dBm%set_alias_conversion(reference_index=1, alias_index=2, convert=dBm2mW)

q1 = 10. * dBm
q2 = q1%to(unit=mW)
test_passed(1) = q2%stringify(format='(F4.1)')=='10.0 mW'
print "(A,L1)", '10.0 dBm = '//q2%stringify(format='(F4.1)')//', is correct? ', test_passed(1)

call q1%unset
call q2%unset
q1 = 10. * mW
q2 = q1%to(unit=dBm)
test_passed(2) = q2%stringify(format='(F4.1)')=='10.0 dBm'
print "(A,L1)", '10.0 mW = '//q2%stringify(format='(F4.1)')//', is correct? ', test_passed(2)

kelvin = uom('K')
celsius = uom('degC<=273.15 + K=celsius>')

call q1%unset
call q2%unset
q1 = 2 * kelvin
q2 = 1 * celsius
q3 = q1 - q2%to(kelvin)
test_passed(3) = q3%stringify(format='(F7.2)')=='-272.15 K'
print "(A,L1)", '2 K - 1 celsius = '//q3%stringify(format='(F7.2)')//', is correct? ', test_passed(3)

call q3%unset
q3 = q2 - q1%to(celsius)
test_passed(4) = q3%stringify(format='(F6.2)')=='272.15 degC'
print "(A,L1)", '1 celsius - 2 K = '//q3%stringify(format='(F6.2)')//', is correct? ', test_passed(4)

Note that while "celsius to kelvin" can be defined very easy by the builtin string parser, the conversion from dBm to mW does not because their conversions are not simply y= offset + factor * x, rather in this case they are

• dBm = 10 * log(mW)
• mW = 10**(dBm / 10)

So the user must define this generic conversion and attach to the pre-defined uom (where I have used a placeholder), see the statement

call dBm%set_alias_conversion(reference_index=1, alias_index=2, convert=dBm2mW)

The converter dBm2mW is simply a concrete extension of one (the only for now) abstract class provided by FURY, i.e.

module dBm_to_mW_converter
!< Define the converter (user-supplied) from dBm to mW.
use fury

implicit none
private
public :: dBm_to_mW

type, extends(converter) :: dBm_to_mW
!< Converter (user-supplied) from dBm to mW.
contains
procedure, nopass :: convert
endtype dBm_to_mW
contains
pure function convert(magnitude, inverse) result(converted)
!< User-supplied conversion from dBm to mW.
real(R_P), intent(in)           :: magnitude !< Magnitude (of the quantity) to be converted.
logical,   intent(in), optional :: inverse   !< Activate inverse conversion.
real(R_P)                       :: converted !< Converted magnitude.
logical                         :: inverse_   !< Activate inverse conversion, local variable.

inverse_ = .false. ; if (present(inverse)) inverse_ = inverse
if (inverse_) then
converted = 10._R_P * log10(magnitude)
else
converted = 10._R_P**(magnitude / 10._R_P)
endif
endfunction convert
endmodule dBm_to_mW_converter

The above snippet is taken from a FURY test. Unfortunately, I was not able to find a way to pass a generic function without bothering the user: the string parsing has been discarderd because it could be result inefficient at runtime: the multiplicative-like conveters are efficient becuase after the intial parsing they are standard Fortran function (the parsing simply set the value of offset and factor) whereas a runtime evaluation of string-function could be too much overheaded.

Let me know if such an implementation can be useful for you.

Cheers