commit ff3dd07b51cb4dece229359a0864ec9ef09adcad
parent ce93d40e2d2d0c5cc4a73acaa0d4500d30312e14
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 6 Dec 2022 12:53:00 +0100
htrdr-planeto : upd the definition of spectral integration
This commit removes the reference temperature from the option that
defines a Planck spectral integration. In shortwave, we now use the
temperature of the source as the reference temperature of the Planck
function. In longwave, the reference temperature is set to the maximum
ground temperature which should be the maximum temperature of the
system.
Diffstat:
7 files changed, 194 insertions(+), 86 deletions(-)
diff --git a/doc/htrdr-planeto.1.scd.in b/doc/htrdr-planeto.1.scd.in
@@ -254,24 +254,21 @@ launcher such as *mpirun*(1) to distribute the rendering on several computers.
*lw*=_wlen-min_,_wlen-max_
Perform continuous spectral sampling in the wavelength range [_wlen-min_, _wlen-max_]
(wavelengths must be provided in nanometers) according to the Planck
- function for a reference temperature (see *Tref* parameter). If _wlen-min_
- and _wlen-max_ are equal, the calculation is monochromatic. *lw* means
- longwaves but is here a code word that actually means "calculation of
+ function for a reference temperature which is the maximum ground
+ temperature, which is assumed to be the maximum scene temperature. If
+ _wlen-min_ and _wlen-max_ are equal, the calculation is monochromatic. *lw*
+ means longwaves but is here a code word that actually means "calculation of
radiance using the internal source of radiation": in other words, radiation
is emitted by the medium and its limits (ground and space).
*sw*=_wlen-min_,_wlen-max_
- Perform continuous spectral sampling in the wavelength range [_wlen-min_,
- _wlen-max_] (wavelengths must be provided in nanometers) according to the
- Planck function for a reference temperatura (see *Tref* parameter). If
+ Perform continuous spectral sampling in the wavelength range [_wlen-min_, _wlen-max_]
+ (wavelengths must be provided in nanometers) according to the Planck
+ function for a reference temperatura which is the source temperature. If
_wlen-min_ and _wlen-max_ are equal, the calculation is monochromatic. Here,
- *sw* means shortwaves, i.e. the radiation source is external to the medium.
+ *sw* means shortwaves, i.e. the radiation source is external to the medium
+ (option *-S*).
- *Tref*=_temperature_
- The reference temperature in Kelvin of the Planck function used to
- continuously sample the longwave/shortwave spectral range. This is a
- required parameter for the *lw* and *sw* parameters.
-
*-T* _optical-thickness_
Optical thickness used as a criterion to construct atmospheric acceleration
structures. Its default value is
@@ -308,25 +305,24 @@ standard error).
## Longwave image
-If the image is an infrared rendering (option
-*-s lw*=_wlen-min_,_wlen-max_:*Tref*=_temperature_), the first and second pixel
-values store the expected value and standard error of the estimated brightness
-temperature in Kelvin. The third and fourth values record the expected value and
-standard error of the estimated radiance, which is either integrated radiance in
-W/sr/m² or spectral radiance in W/sr/m²/nm depending on whether this radiance
-was calculated for a spectral range or at a single wavelength. The fifth and
-sixth values are not used and are therefore set to 0. Finally, the last 2
-components of the pixel record the expected value and the standard error in µs
-of the calculation time per radiative path.
+If the image is an infrared rendering (option *-s lw*=_wlen-min_,_wlen-max_),
+the first and second pixel values store the expected value and standard error of
+the estimated brightness temperature in Kelvin. The third and fourth values
+record the expected value and standard error of the estimated radiance, which is
+either integrated radiance in W/sr/m² or spectral radiance in W/sr/m²/nm
+depending on whether this radiance was calculated for a spectral range or at a
+single wavelength. The fifth and sixth values are not used and are therefore set
+to 0. Finally, the last 2 components of the pixel record the expected value and
+the standard error in µs of the calculation time per radiative path.
## Shortwave image
-For shortwave renderings (option
-*-s sw*=_wlen-min_,_wlen-max_:*Tref*=_temperature_), the image layout is the
-same as for infrared rendering, except for the first and second pixel values
-that are not used. That is, the third and fourth values record the estimated
-radiance per pixel and the seventh and eighth values store the estimate of the
-calculation time by radiative path. The other values are set to 0.
+For shortwave renderings (option *-s sw*=_wlen-min_,_wlen-max_), the image
+layout is the same as for infrared rendering, except for the first and second
+pixel values that are not used. That is, the third and fourth values record the
+estimated radiance per pixel and the seventh and eighth values store the
+estimate of the calculation time by radiative path. The other values are set to
+0.
# EXAMPLES
@@ -372,21 +368,20 @@ htrdr-planeto -v -N \
```
The next command line is the same as the previous one, except that it calculates
-an infrared image between _10,000_ nm and _20,000_ nm with a reference
-temperature of _300_ K (option *-s*). Note that the acceleration structure
-storage file is no longer the same (_storage_lw.bin_ rather than
-_storage_cie.bin_). Indeed, the previous one records the acceleration structures
-for the spectral range of the CIE XYZ color space, while one wants to
-store/reload the acceleration structures for a spectral range between 10 and 20
-µm (see *-O* option). In any case, if the previous storage, incompatible with
-the current spectral range, had been submitted, the command would have stopped
-with an error message, thus avoiding the use of the wrong accelerartion
-structures.
+an infrared image between _10,000_ nm and _20,000_ nm (option *-s*). Note that
+the acceleration structure storage file is no longer the same (_storage_lw.bin_
+rather than _storage_cie.bin_). Indeed, the previous one records the
+acceleration structures for the spectral range of the CIE XYZ color space, while
+one wants to store/reload the acceleration structures for a spectral range
+between 10 and 20 µm (see *-O* option). In any case, if the previous storage,
+incompatible with the current spectral range, had been submitted, the command
+would have stopped with an error message, thus avoiding the use of the wrong
+accelerartion structures.
```
htrdr-planeto -v -N \
-i def=800x600:spp=64 \
- -s lw=10000,20000:Tref=300 \
+ -s lw=10000,20000 \
-C pos=0,1.5e7,0:tgt=0,0,0:up=0,0,1:fov=70 \
-g mesh=gas.smsh:ck=gas.sck:temp=gas.rngt \
-a mesh=a1.smsh:radprop=a1.sars:phasefn=a1.rnsf:phaseids=a1.rnpfi:name=clouds \
diff --git a/src/planeto/htrdr_planeto.c b/src/planeto/htrdr_planeto.c
@@ -237,6 +237,7 @@ setup_spectral_domain
(struct htrdr_planeto* cmd,
const struct htrdr_planeto_args* args)
{
+ double ground_T_range[2];
size_t nintervals;
res_T res = RES_OK;
ASSERT(cmd && args);
@@ -245,23 +246,39 @@ setup_spectral_domain
/* Configure the spectral distribution */
nintervals = compute_nintervals_for_spectral_cdf(cmd);
- switch(cmd->spectral_domain.spectral_type) {
- /* Planck distribution */
+ switch(cmd->spectral_domain.type) {
+
case HTRDR_SPECTRAL_LW:
+ res = rngrd_get_temperature_range(cmd->ground, ground_T_range);
+ if(res != RES_OK) goto error;
+
+ /* Use as the reference temperature of the Planck distribution the
+ * maximum scene temperature which, in fact, should be the maximum ground
+ * temperature */
+ res = htrdr_ran_wlen_planck_create(cmd->htrdr,
+ cmd->spectral_domain.wlen_range, nintervals, ground_T_range[1],
+ &cmd->planck);
+ if(res != RES_OK) goto error;
+ break;
+
case HTRDR_SPECTRAL_SW:
+ /* Use the source temperature as the reference temperature of the Planck
+ * distribution */
res = htrdr_ran_wlen_planck_create(cmd->htrdr,
- cmd->spectral_domain.wlen_range, nintervals,
- cmd->spectral_domain.ref_temperature, &cmd->planck);
+ cmd->spectral_domain.wlen_range, nintervals, args->source.temperature,
+ &cmd->planck);
+ if(res != RES_OK) goto error;
break;
- /* CIE XYZ distribution */
+
case HTRDR_SPECTRAL_SW_CIE_XYZ:
+ /* CIE XYZ distribution */
res = htrdr_ran_wlen_cie_xyz_create(cmd->htrdr,
cmd->spectral_domain.wlen_range, nintervals, &cmd->cie);
+ if(res != RES_OK) goto error;
break;
default: FATAL("Unreachable code\n"); break;
}
- if(res != RES_OK) goto error;
exit:
return res;
@@ -563,7 +580,7 @@ planeto_get_pixel_format
ASSERT(cmd && fmt && cmd->output_type == HTRDR_PLANETO_ARGS_OUTPUT_IMAGE);
(void)cmd;
- switch(cmd->spectral_domain.spectral_type) {
+ switch(cmd->spectral_domain.type) {
case HTRDR_SPECTRAL_LW:
case HTRDR_SPECTRAL_SW:
fmt->size = sizeof(struct planeto_pixel_xwave);
diff --git a/src/planeto/htrdr_planeto_args.c b/src/planeto/htrdr_planeto_args.c
@@ -73,33 +73,29 @@ check_ground_args(const struct htrdr_planeto_ground_args* args)
}
static INLINE res_T
-check_spectral_args(const struct htrdr_args_spectral* spectral_domain)
+check_spectral_args(const struct htrdr_planeto_spectral_args* args)
{
- if(!spectral_domain) return RES_BAD_ARG;
+ if(!args) return RES_BAD_ARG;
- switch(spectral_domain->spectral_type) {
+ /* Invalid type */
+ switch(args->type) {
case HTRDR_SPECTRAL_LW:
case HTRDR_SPECTRAL_SW:
-
- /* Invalid reference temperature */
- if(spectral_domain->ref_temperature <= 0)
- return RES_BAD_ARG;
-
- /* Invalid spectral range */
- if(spectral_domain->wlen_range[0]
- > spectral_domain->wlen_range[1])
- return RES_BAD_ARG;
-
- break;
case HTRDR_SPECTRAL_SW_CIE_XYZ:
- /* Nothing to check since all parameters are implicitly defined */
+ /* Nothing to be done */
break;
- default: FATAL("Unreachable code\n"); break;
+ default:
+ return RES_BAD_ARG;
}
+ /* Invalid spectral range */
+ if(args->wlen_range[0] < 0
+ || args->wlen_range[1] < 0
+ || args->wlen_range[0] > args->wlen_range[1])
+ return RES_BAD_ARG;
+
return RES_OK;
}
-
static void
print_help(const char* cmd)
{
@@ -468,6 +464,98 @@ error:
goto exit;
}
+static INLINE res_T
+parse_spectral_range(const char* str, double wlen_range[2])
+{
+ double range[2];
+ size_t len;
+ res_T res = RES_OK;
+ ASSERT(wlen_range && str);
+
+ res = cstr_to_list_double(str, ',', range, &len, 2);
+ if(res == RES_OK && len != 2) res = RES_BAD_ARG;
+ if(res == RES_OK && range[0] > range[1]) res = RES_BAD_ARG;
+ if(res == RES_OK && (range[0] < 0 || range[1] < 0)) res = RES_BAD_ARG;
+ if(res != RES_OK) goto error;
+
+ wlen_range[0] = range[0];
+ wlen_range[1] = range[1];
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_spectral_parameters(const char* str, void* ptr)
+{
+ enum {CIE_XYZ, LW, SW} iparam;
+ char buf[BUFSIZ];
+ struct htrdr_planeto_args* args = ptr;
+ struct htrdr_planeto_spectral_args* spectral = NULL;
+ char* key;
+ char* val;
+ char* tk_ctx;
+ res_T res = RES_BAD_ARG;
+ ASSERT(str && ptr);
+
+ spectral = &args->spectral_domain;
+
+ if(strlen(str) >= sizeof(buf) -1/*NULL char*/) {
+ fprintf(stderr, "Could not duplicate the spectral parameter `%s'\n", str);
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ strncpy(buf, str, sizeof(buf));
+
+ key = strtok_r(buf, "=", &tk_ctx);
+ val = strtok_r(NULL, "", &tk_ctx);
+
+ if(!strcmp(key, "cie_xyz")) iparam = CIE_XYZ;
+ else if(!strcmp(key, "lw")) iparam = LW;
+ else if(!strcmp(key, "sw")) iparam = SW;
+ else {
+ fprintf(stderr, "Invalid spectral parameter `%s'\n", key);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if((iparam == LW || iparam == SW) && !val) {
+ fprintf(stderr,
+ "Invalid null value for the spectral parameter `%s'\n", key);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ switch(iparam) {
+ case CIE_XYZ:
+ spectral->type = HTRDR_SPECTRAL_SW_CIE_XYZ;
+ spectral->wlen_range[0] = HTRDR_RAN_WLEN_CIE_XYZ_RANGE_DEFAULT[0];
+ spectral->wlen_range[1] = HTRDR_RAN_WLEN_CIE_XYZ_RANGE_DEFAULT[1];
+ break;
+ case LW:
+ spectral->type = HTRDR_SPECTRAL_LW;
+ res = parse_spectral_range(val, spectral->wlen_range);
+ break;
+ case SW:
+ spectral->type = HTRDR_SPECTRAL_SW;
+ res = parse_spectral_range(val, spectral->wlen_range);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK) {
+ fprintf(stderr, "Unable to parse the spectral parameter `%s' -- %s\n",
+ str, res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -528,10 +616,7 @@ htrdr_planeto_args_init(struct htrdr_planeto_args* args, int argc, char** argv)
res = cstr_parse_list(optarg, ':', parse_source_parameters, args);
break;
case 's':
- res = htrdr_args_spectral_parse(&args->spectral_domain, optarg);
- if(res == RES_OK) {
- res = check_spectral_args(&args->spectral_domain);
- }
+ res = cstr_parse_list(optarg, ':', parse_spectral_parameters, args);
break;
case 'T':
res = cstr_to_double(optarg, &args->optical_thickness);
@@ -577,8 +662,8 @@ htrdr_planeto_args_init(struct htrdr_planeto_args* args, int argc, char** argv)
}
/* Check the source */
- if(args->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW
- || args->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW_CIE_XYZ) {
+ if(args->spectral_domain.type == HTRDR_SPECTRAL_SW
+ || args->spectral_domain.type == HTRDR_SPECTRAL_SW_CIE_XYZ) {
res = htrdr_planeto_source_args_check(&args->source);
if(res != RES_OK) {
fprintf(stderr, "Missing source definition -- option '-S'\n");
@@ -654,8 +739,8 @@ htrdr_planeto_args_check(const struct htrdr_planeto_args* args)
if(res != RES_OK) return res;
/* Check the source */
- if(args->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW
- || args->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW_CIE_XYZ) {
+ if(args->spectral_domain.type == HTRDR_SPECTRAL_SW
+ || args->spectral_domain.type == HTRDR_SPECTRAL_SW_CIE_XYZ) {
res = htrdr_planeto_source_args_check(&args->source);
if(res != RES_OK) return res;
}
diff --git a/src/planeto/htrdr_planeto_args.h.in b/src/planeto/htrdr_planeto_args.h.in
@@ -31,6 +31,17 @@ enum htrdr_planeto_args_output_type {
HTRDR_PLANETO_ARGS_OUTPUT_TYPES_COUNT__
};
+struct htrdr_planeto_spectral_args {
+ double wlen_range[2]; /* Spectral range in nm */
+ enum htrdr_spectral_type type;
+};
+#define HTRDR_PLANETO_SPECTRAL_ARGS_DEFAULT__ { \
+ HTRDR_RAN_WLEN_CIE_XYZ_RANGE_DEFAULT__, /* Spectral range */ \
+ HTRDR_SPECTRAL_SW_CIE_XYZ, /* Spectral type */ \
+}
+static const struct htrdr_planeto_spectral_args
+HTRDR_PLANETO_SPECTRAL_ARGS_DEFAULT = HTRDR_PLANETO_SPECTRAL_ARGS_DEFAULT__;
+
struct htrdr_planeto_source_args {
double longitude; /* In [-180, 180] degrees */
double latitude; /* In [-90, 90] degrees */
@@ -67,7 +78,7 @@ struct htrdr_planeto_args {
double optical_thickness; /* Threshold used during octree building */
char* output; /* File where the result is written */
- struct htrdr_args_spectral spectral_domain; /* Integration spectral domain */
+ struct htrdr_planeto_spectral_args spectral_domain; /* Integration spectral domain */
struct htrdr_planeto_source_args source;
struct htrdr_args_image image;
@@ -79,7 +90,7 @@ struct htrdr_planeto_args {
int precompute_normals; /* Pre-compute tetrahedron normals */
int force_output_overwrite; /* Replace output if it exists */
int verbose; /* Verbose level */
- int quit; /* Stop the command */
+ int quit; /* Stop the command */
};
#define HTRDR_PLANETO_ARGS_DEFAULT__ { \
RNATM_GAS_ARGS_NULL__, /* Gas */ \
@@ -93,7 +104,7 @@ struct htrdr_planeto_args {
@HTRDR_PLANETO_ARGS_DEFAULT_OPTICAL_THICKNESS_THRESHOLD@, \
\
NULL, /* Ouput file */ \
- HTRDR_ARGS_SPECTRAL_DEFAULT__, /* Spectral domain */ \
+ HTRDR_PLANETO_SPECTRAL_ARGS_DEFAULT__, /* Spectral domain */ \
HTRDR_PLANETO_SOURCE_ARGS_NULL__, /* Source */ \
HTRDR_ARGS_IMAGE_DEFAULT__, /* Image */ \
\
diff --git a/src/planeto/htrdr_planeto_c.h b/src/planeto/htrdr_planeto_c.h
@@ -82,7 +82,7 @@ struct htrdr_planeto {
struct rngrd* ground;
struct htrdr_planeto_source* source;
- struct htrdr_args_spectral spectral_domain;
+ struct htrdr_planeto_spectral_args spectral_domain;
struct htrdr_ran_wlen_cie_xyz* cie; /* HTRDR_SPECTRAL_SW_CIE_XYZ */
struct htrdr_ran_wlen_planck* planck; /* HTRDR_SPECTRAL_<LW|SW> */
diff --git a/src/planeto/htrdr_planeto_compute_radiance.c b/src/planeto/htrdr_planeto_compute_radiance.c
@@ -435,7 +435,7 @@ surface_bounce
if(mask & SSF_TRANSMISSION) reflectivity = 0;
/* No external source in longwave */
- if(cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_LW)
+ if(cmd->spectral_domain.type == HTRDR_SPECTRAL_LW)
goto exit;
/* Calculate direct contribution for specular reflection */
@@ -502,7 +502,7 @@ volume_scattering
pdf = htrdr_planeto_source_sample_direction(cmd->source, args->rng, sc_pos, wi);
/* In short wave, manage the contribution of the external source */
- switch(cmd->spectral_domain.spectral_type) {
+ switch(cmd->spectral_domain.type) {
case HTRDR_SPECTRAL_LW:
/* Nothing to be done */
break;
@@ -601,7 +601,7 @@ planeto_compute_radiance
d3_set(pos, args->path_org);
d3_set(dir, args->path_dir);
- longwave = cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_LW;
+ longwave = cmd->spectral_domain.type == HTRDR_SPECTRAL_LW;
if(!longwave && htrdr_planeto_source_is_targeted(cmd->source, pos, dir)) {
L = direct_contribution(cmd, args, pos, dir, NULL); /* In W/m²/sr/m */
diff --git a/src/planeto/htrdr_planeto_draw_map.c b/src/planeto/htrdr_planeto_draw_map.c
@@ -53,8 +53,8 @@ draw_pixel_xwave
cmd = args->context;
ASSERT(cmd);
- ASSERT(cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW
- || cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_LW);
+ ASSERT(cmd->spectral_domain.type == HTRDR_SPECTRAL_SW
+ || cmd->spectral_domain.type == HTRDR_SPECTRAL_LW);
ASSERT(cmd->output_type == HTRDR_PLANETO_ARGS_OUTPUT_IMAGE);
/* Reset accumulators */
@@ -132,7 +132,7 @@ draw_pixel_xwave
pixel->radiance = radiance;
pixel->time = time;
- if(cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW) {
+ if(cmd->spectral_domain.type == HTRDR_SPECTRAL_SW) {
pixel->radiance_temperature.E = 0;
pixel->radiance_temperature.SE = 0;
} else {
@@ -175,7 +175,7 @@ draw_pixel_image
cmd = args->context;
ASSERT(cmd);
- ASSERT(cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW_CIE_XYZ);
+ ASSERT(cmd->spectral_domain.type == HTRDR_SPECTRAL_SW_CIE_XYZ);
ASSERT(cmd->output_type == HTRDR_PLANETO_ARGS_OUTPUT_IMAGE);
/* Reset accumulators */
@@ -356,7 +356,7 @@ write_buffer
void* pix_raw = htrdr_buffer_at(buf, x, y);
ASSERT(IS_ALIGNED(pix_raw, pixfmt.alignment));
- switch(cmd->spectral_domain.spectral_type) {
+ switch(cmd->spectral_domain.type) {
case HTRDR_SPECTRAL_LW:
case HTRDR_SPECTRAL_SW:
write_pixel_xwave(pix_raw, radiance_acc, time_acc, stream);
@@ -387,7 +387,7 @@ planeto_draw_map(struct htrdr_planeto* cmd)
args.buffer_layout = cmd->buf_layout;
args.spp = cmd->spp;
args.context = cmd;
- switch(cmd->spectral_domain.spectral_type) {
+ switch(cmd->spectral_domain.type) {
case HTRDR_SPECTRAL_LW:
case HTRDR_SPECTRAL_SW:
args.draw_pixel = draw_pixel_xwave;
@@ -416,8 +416,8 @@ planeto_draw_map(struct htrdr_planeto* cmd)
path_time.E, path_time.SE);
/* Log measured radiance on the whole image */
- if(cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_LW
- || cmd->spectral_domain.spectral_type == HTRDR_SPECTRAL_SW) {
+ if(cmd->spectral_domain.type == HTRDR_SPECTRAL_LW
+ || cmd->spectral_domain.type == HTRDR_SPECTRAL_SW) {
struct htrdr_estimate L;
double omega; /* Solid angle of the camera */