schiff

Estimate the radiative properties of soft particless
git clone git://git.meso-star.com/schiff.git
Log | Files | Refs | README | LICENSE

commit 90e3f632604097d50432ae0ed1d03ea212cdf9ba
parent 19c0d487c13b6bc3e504d0fed5776e30aee82d79
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  6 Nov 2015 13:53:03 +0100

Add the supershape distribution

Add the -u option that defines the lower/upper bounds of the super shape
parameters.

Diffstat:
Msrc/schiff_args.c | 136++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/schiff_geometry.c | 128++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/schiff_geometry.h | 17+++++++++++++++++
Msrc/schiff_mesh.h | 16+++++++++++++++-
4 files changed, 268 insertions(+), 29 deletions(-)

diff --git a/src/schiff_args.c b/src/schiff_args.c @@ -31,6 +31,7 @@ #include "schiff_args.h" #include "schiff_optical_properties.h" +#include <rsys/dynamic_array_char.h> #include <rsys/cstr.h> #include <rsys/stretchy_array.h> @@ -52,11 +53,11 @@ print_help(const char* binary) "Method for Short Wavelength or High Energy Scattering\" (L. Schiff, 1956).\n\n", binary); printf( -"FILE lists the per wavelength optical properties of the micro organisms.\n" -"Each line must be formatted as \"W Nr Kr Ne\" where \"W\" is the wavelength\n" -"in micron, \"Nr\" and \"Kr\" are the real and imaginary parts, respectively, of\n" -"the relative refractive index, and \"Ne\" the refractive index of the medium.\n" -"With no FILE, read optical properties from standard input.\n\n"); +"FILE lists the per wavelength optical properties of the micro organisms. Each\n" +"line must be formatted as \"W Nr Kr Ne\" where \"W\" is the wavelength in\n" +"vacuum expressed in micron, \"Nr\" and \"Kr\" are the real and imaginary parts,\n" +"respectively, of the relative refractive index, and \"Ne\" the refractive index\n" +"of the medium. With no FILE, read optical properties from standard input.\n\n"); printf( " -c R:S:A[:N] the micro organisms are cylindrical meshes discretized in N\n" " slices. By default N is %u. The radius `r' and the height `h'\n" @@ -90,7 +91,8 @@ print_help(const char* binary) " r = 1/(ln(S)*x*sqrt(2PI)) * exp(-(ln(x)-ln(R))^2 / (2*ln(S)^2))\n", SCHIFF_SPHERE_DEFAULT.nslices); printf( -" -w A[:B]... list of wavelengths (in micron) to integrate.\n"); +" -w A[:B]... list of wavelengths in vacuum (expressed in micron) to\n" +" integrate.\n"); } static res_T @@ -186,6 +188,125 @@ error: } static res_T +parse_super_shape(const char* str, double formulas[2][6]) +{ + struct darray_char tmp; + char* tk; + char* tk_ctx; + size_t len; + res_T res = RES_OK; + ASSERT(str && formulas); + + darray_char_init(&mem_default_allocator, &tmp); + + /* Locallly copy the input string */ + res = darray_char_resize(&tmp, strlen(str) + 1 /*NULL char*/); + if(res != RES_OK) goto error; + strcpy(darray_char_data_get(&tmp), str); + + tk = strtok_r(darray_char_data_get(&tmp), ",", &tk_ctx); + if(!tk) { + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_list_double(tk, formulas[0], &len, 6); + if(res != RES_OK) goto error; + if(len != 6) { + res = RES_BAD_ARG; + goto error; + } + + tk = strtok_r(NULL, ",", &tk_ctx); + if(!tk) { + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_list_double(tk, formulas[1], &len, 6); + if(res != RES_OK) goto error; + if(len != 6) { + res = RES_BAD_ARG; + goto error; + } + +exit: + darray_char_release(&tmp); + return res; +error: + goto exit; +} + +static res_T +parse_super_shape_distribution(const char* str, struct schiff_args* args) +{ + struct darray_char tmp; + struct schiff_super_shape* sshape; + char* tk; + char* tk_ctx; + size_t str_len; + int i; + res_T res = RES_OK; + + darray_char_init(&mem_default_allocator, &tmp); + + if(args->geom.type != SCHIFF_NONE && args->geom.type != SCHIFF_SUPER_SHAPE) { + res = RES_BAD_ARG; + goto error; + } + + /* Locallly copy the input string */ + str_len = strlen(str); + res = darray_char_resize(&tmp, str_len + 1 /*NULL char*/); + if(res != RES_OK) goto error; + strcpy(darray_char_data_get(&tmp), str); + + /* Parse "lower" super shape */ + tk = strtok_r(darray_char_data_get(&tmp), "#", &tk_ctx); + if(!tk) { + res = RES_BAD_ARG; + goto error; + } + res = parse_super_shape(tk, args->geom.data.super_shape.lower); + if(res != RES_OK) goto error; + + /* Parse "upper" super shape */ + tk = strtok_r(NULL, "#", &tk_ctx); + if(!tk) { + res = RES_BAD_ARG; + goto error; + } + res = parse_super_shape(tk, args->geom.data.super_shape.upper); + if(res != RES_OK) goto error; + + /* Parse the optionnal "nslices" attrib */ + tk = strtok_r(NULL, "#", &tk_ctx); + if(!tk) { + args->geom.data.super_shape.nslices = SCHIFF_SUPER_SHAPE_DEFAULT.nslices; + } else { + res = cstr_to_uint(tk, &args->geom.data.super_shape.nslices); + if(res != RES_OK) goto error; + } + + args->geom.type = SCHIFF_SUPER_SHAPE; + + sshape = &args->geom.data.super_shape; + FOR_EACH(i, 0, 6) { + if(sshape->lower[0][i] > sshape->upper[0][i] + || sshape->lower[1][i] > sshape->upper[1][i]) { + res = RES_BAD_ARG; + goto error; + } + } + +exit: + darray_char_release(&tmp); + return res; +error: + goto exit; +} + +static res_T parse_wavelengths(const char* str, struct schiff_args* args) { size_t len; @@ -232,7 +353,7 @@ schiff_args_init ASSERT(argc && argv && args); *args = SCHIFF_ARGS_NULL; - while((opt = getopt(argc, argv, "c:d:g:G:ho:s:w:")) != -1) { + while((opt = getopt(argc, argv, "c:d:g:G:ho:s:u:w:")) != -1) { res_T res = RES_OK; switch(opt) { case 'c': res = parse_cylinder_distribution(optarg, args); break; @@ -245,6 +366,7 @@ schiff_args_init return RES_OK; case 'o': args->output_filename = optarg; break; case 's': res = parse_sphere_distribution(optarg, args); break; + case 'u': res = parse_super_shape_distribution(optarg, args); break; case 'w': res = parse_wavelengths(optarg, args); break; default: res = RES_BAD_ARG; break; } diff --git a/src/schiff_geometry.c b/src/schiff_geometry.c @@ -46,9 +46,8 @@ struct cylinder_context { }; /* 3D Context of the super shape geometry */ -enum { A, B, M, N0, N1, N2 }; -struct supershape_context { - double super_formulas[2][6]; +struct super_shape_context { + double formulas[2][6]; }; /* Distribution context of a sphere geometry */ @@ -65,9 +64,9 @@ struct cylinder_distribution_context { }; /* Distribtion context of a super shape geometry */ -struct supershape_distribution_context { - double lower[2][6]; /* Lower bound of the super formula parameters */ - double upper[2][6]; /* Upper bound of the super formula parameters */ +struct super_shape_distribution_context { + double lower[2][6]; + double upper[2][6]; }; /* 3D context of a generic geometry */ @@ -77,7 +76,7 @@ struct geometry_context { union { struct cylinder_context cylinder; struct sphere_context sphere; - struct supershape_context supershape; + struct super_shape_context super_shape; } data; }; @@ -89,7 +88,7 @@ struct geometry_distribution_context { union { struct cylinder_distribution_context cylinder; struct sphere_distribution_context sphere; - struct supershape_distribution_context supershape; + struct super_shape_distribution_context super_shape; } data; }; @@ -136,6 +135,78 @@ sphere_get_position(const unsigned ivert, float vertex[3], void* ctx) vertex[2] *= geom->data.sphere.radius; } +static void +super_shape_get_position(const unsigned ivert, float vertex[3], void* ctx) +{ + struct geometry_context* geom = ctx; + float angles[2]; + double cos_angles[2]; + double sin_angles[2]; + double uv[2]; + int iform; + ASSERT(geom && geom->type == SCHIFF_SUPER_SHAPE); + + schiff_mesh_get_polar_position(geom->mesh, ivert, angles); + + FOR_EACH(iform, 0, 2) { + double m, k, g; + double* form = geom->data.super_shape.formulas[iform]; + + m = cos(form[M] * angles[iform] / 4.0); + m = fabs(m) / form[A]; + k = sin(form[M] * angles[iform] / 4.0); + k = fabs(k) / form[B]; + g = pow(m, form[N1]) + pow(k, form[N2]); + uv[iform] = pow(g, (-1.0/form[N0])); + + cos_angles[iform] = cos(angles[iform]); + sin_angles[iform] = sin(angles[iform]); + } + + vertex[0] = (float)(uv[0] * cos_angles[0] * uv[1] * cos_angles[1]); + vertex[1] = (float)(uv[0] * sin_angles[0] * uv[1] * cos_angles[1]); + vertex[2] = (float)(uv[1] * sin_angles[1]); + +} + +static res_T +geometry_sample_cylinder + (struct ssp_rng* rng, + struct sschiff_material* mtl, + struct s3d_shape* shape, + void* context) +{ + struct geometry_distribution_context* distrib = context; + struct geometry_context geom; + struct s3d_vertex_data attrib; + size_t nverts, nprims; + double y; + ASSERT(rng && mtl && shape && context); + ASSERT(distrib->type == SCHIFF_CYLINDER); + + y = ssp_ran_lognormal + (rng, distrib->data.cylinder.log_mean_radius, distrib->data.cylinder.log_sigma); + geom.type = SCHIFF_CYLINDER; + geom.mesh = distrib->mesh; + geom.data.cylinder.radius = + (float)(y / pow(3.0 / (2.0*distrib->data.cylinder.aspect_ratio), 1.0/3.0)); + geom.data.cylinder.height = + (float)(2.f * geom.data.cylinder.radius / distrib->data.cylinder.aspect_ratio); + + attrib.usage = S3D_POSITION; + attrib.type = S3D_FLOAT3; + attrib.get = cylinder_get_position; + + mtl->get_property = get_material_property; + mtl->material = distrib->properties; + + nverts = darray_float_size_get(&distrib->mesh->vertices) / 3/*#coords*/; + nprims = darray_uint_size_get(&distrib->mesh->indices) / 3/*#indices per prim*/; + + return s3d_mesh_setup_indexed_vertices(shape, (unsigned)nprims, + geometry_get_indices, (unsigned)nverts, &attrib, 1, &geom); +} + static res_T geometry_sample_sphere (struct ssp_rng* rng, @@ -170,7 +241,7 @@ geometry_sample_sphere } static res_T -geometry_sample_cylinder +geometry_sample_super_shape (struct ssp_rng* rng, struct sschiff_material* mtl, struct s3d_shape* shape, @@ -179,29 +250,32 @@ geometry_sample_cylinder struct geometry_distribution_context* distrib = context; struct geometry_context geom; struct s3d_vertex_data attrib; + const struct super_shape_distribution_context* sshape; size_t nverts, nprims; - double y; + int i; ASSERT(rng && mtl && shape && context); - ASSERT(distrib->type == SCHIFF_CYLINDER); + ASSERT(distrib->type == SCHIFF_SUPER_SHAPE); - y = ssp_ran_lognormal - (rng, distrib->data.cylinder.log_mean_radius, distrib->data.cylinder.log_sigma); - geom.type = SCHIFF_CYLINDER; + sshape = &distrib->data.super_shape; geom.mesh = distrib->mesh; - geom.data.cylinder.radius = - (float)(y / pow(3.0 / (2.0*distrib->data.cylinder.aspect_ratio), 1.0/3.0)); - geom.data.cylinder.height = - (float)(2.f * geom.data.cylinder.radius / distrib->data.cylinder.aspect_ratio); + geom.type = SCHIFF_SUPER_SHAPE; + + FOR_EACH(i, 0, 6) { + geom.data.super_shape.formulas[0][i] = (float) + ssp_rng_uniform_double(rng, sshape->lower[0][i], sshape->upper[0][i]); + geom.data.super_shape.formulas[1][i] = (float) + ssp_rng_uniform_double(rng, sshape->lower[1][i], sshape->upper[1][i]); + } attrib.usage = S3D_POSITION; attrib.type = S3D_FLOAT3; - attrib.get = cylinder_get_position; + attrib.get = super_shape_get_position; mtl->get_property = get_material_property; mtl->material = distrib->properties; - nverts = darray_float_size_get(&distrib->mesh->vertices) / 3/*#coords*/; - nprims = darray_uint_size_get(&distrib->mesh->indices) / 3/*#indices per prim*/; + nverts = darray_float_size_get(&distrib->mesh->vertices) / 2/*#theta/phi*/; + nprims = darray_uint_size_get(&distrib->mesh->indices) / 3/*#indices*/; return s3d_mesh_setup_indexed_vertices(shape, (unsigned)nprims, geometry_get_indices, (unsigned)nverts, &attrib, 1, &geom); @@ -217,6 +291,7 @@ schiff_geometry_distribution_init struct schiff_optical_properties* properties) { struct geometry_distribution_context* ctx = NULL; + int i; res_T res = RES_OK; ASSERT(distrib && geom); @@ -252,6 +327,17 @@ schiff_geometry_distribution_init ctx->data.sphere.log_sigma = log(geom->data.sphere.sigma); distrib->sample = geometry_sample_sphere; break; + case SCHIFF_SUPER_SHAPE: + res = schiff_mesh_init_sphere_polar + (&mem_default_allocator, ctx->mesh, geom->data.super_shape.nslices); + FOR_EACH(i, 0, 6) { + ctx->data.super_shape.lower[0][i] = geom->data.super_shape.lower[0][i]; + ctx->data.super_shape.lower[1][i] = geom->data.super_shape.lower[1][i]; + ctx->data.super_shape.upper[0][i] = geom->data.super_shape.upper[0][i]; + ctx->data.super_shape.upper[1][i] = geom->data.super_shape.upper[1][i]; + } + distrib->sample = geometry_sample_super_shape; + break; default: FATAL("Unreachable code.\n"); break; } if(res != RES_OK) { diff --git a/src/schiff_geometry.h b/src/schiff_geometry.h @@ -34,6 +34,7 @@ enum schiff_geometry_type { SCHIFF_CYLINDER, SCHIFF_SPHERE, + SCHIFF_SUPER_SHAPE, SCHIFF_NONE }; @@ -58,11 +59,27 @@ struct schiff_cylinder { static const struct schiff_cylinder SCHIFF_CYLINDER_DEFAULT = SCHIFF_CYLINDER_DEFAULT__; +enum schiff_super_formula { A, B, M, N0, N1, N2 }; +struct schiff_super_shape { + double lower[2][6]; /* Lower bound of the formula params */ + double upper[2][6]; /* Upper bound of the formula params */ + unsigned nslices; +}; + +#define SCHIFF_SUPER_SHAPE_DEFAULT__ { \ + {{ 1, 1, 2, 1, 1, 1 }, { 1, 1, 5, 1, 1, 3 }}, \ + {{ 1, 1, 7, 1, 1, 2 }, { 1, 1, 7, 1, 1, 7 }}, \ + 64 \ +} +static const struct schiff_super_shape SCHIFF_SUPER_SHAPE_DEFAULT = + SCHIFF_SUPER_SHAPE_DEFAULT__; + struct schiff_geometry { enum schiff_geometry_type type; union { struct schiff_cylinder cylinder; struct schiff_sphere sphere; + struct schiff_super_shape super_shape; } data; }; diff --git a/src/schiff_mesh.h b/src/schiff_mesh.h @@ -84,7 +84,7 @@ static INLINE void schiff_mesh_get_cartesian_position (struct schiff_mesh* mesh, const unsigned ivert, - float vertex[]) + float vertex[3]) { const size_t i = ivert * 3; ASSERT(mesh && vertex && mesh->coordinates == SCHIFF_CARTESIAN); @@ -95,5 +95,19 @@ schiff_mesh_get_cartesian_position vertex[2] = darray_float_data_get(&mesh->vertices)[i + 2]; } +static INLINE void +schiff_mesh_get_polar_position + (struct schiff_mesh* mesh, + const unsigned ivert, + float angles[2]) /* theta, phi */ +{ + const size_t i = ivert * 2; + ASSERT(mesh && angles && mesh->coordinates == SCHIFF_POLAR); + ASSERT(darray_float_size_get(&mesh->vertices) % 2 == 0); + ASSERT(ivert < darray_float_size_get(&mesh->vertices) / 2); + angles[0] = darray_float_data_get(&mesh->vertices)[i + 0]; + angles[1] = darray_float_data_get(&mesh->vertices)[i + 1]; +} + #endif /* SBOX_SCHIFF_MESH_H */