From db1c28a0d9f4a1614517fb451a1f033677904951 Mon Sep 17 00:00:00 2001 From: Diablo Date: Tue, 3 Feb 2026 16:47:42 +0100 Subject: [PATCH 01/11] Begin work on adding support for inhomogenous processes in union --- mcstas-comps/share/tinyexpr.c | 734 +++++++++++++++++++++++++++ mcstas-comps/share/tinyexpr.h | 87 ++++ mcstas-comps/share/union-lib.c | 2 + mcstas-comps/share/union-suffix.c | 10 + mcstas-comps/union/Union_master.comp | 16 + 5 files changed, 849 insertions(+) create mode 100644 mcstas-comps/share/tinyexpr.c create mode 100644 mcstas-comps/share/tinyexpr.h diff --git a/mcstas-comps/share/tinyexpr.c b/mcstas-comps/share/tinyexpr.c new file mode 100644 index 000000000..176e8d0ab --- /dev/null +++ b/mcstas-comps/share/tinyexpr.c @@ -0,0 +1,734 @@ +// SPDX-License-Identifier: Zlib +/* + * TINYEXPR - Tiny recursive descent parser and evaluation engine in C + * + * Copyright (c) 2015-2020 Lewis Van Winkle + * + * http://CodePlea.com + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/* COMPILE TIME OPTIONS */ + +/* Exponentiation associativity: +For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing. +For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/ +/* #define TE_POW_FROM_RIGHT */ + +/* Logarithms +For log = base 10 log do nothing +For log = natural log uncomment the next line. */ +/* #define TE_NAT_LOG */ + +#include "tinyexpr.h" +#include +#include +#include +#include +#include +#include + +#ifndef NAN +#define NAN (0.0/0.0) +#endif + +#ifndef INFINITY +#define INFINITY (1.0/0.0) +#endif + + +typedef double (*te_fun2)(double, double); + +enum { + TOK_NULL = TE_CLOSURE7+1, TOK_ERROR, TOK_END, TOK_SEP, + TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_VARIABLE, TOK_INFIX +}; + + +enum {TE_CONSTANT = 1}; + + +typedef struct state { + const char *start; + const char *next; + int type; + union {double value; const double *bound; const void *function;}; + void *context; + + const te_variable *lookup; + int lookup_len; +} state; + + +#define TYPE_MASK(TYPE) ((TYPE)&0x0000001F) + +#define IS_PURE(TYPE) (((TYPE) & TE_FLAG_PURE) != 0) +#define IS_FUNCTION(TYPE) (((TYPE) & TE_FUNCTION0) != 0) +#define IS_CLOSURE(TYPE) (((TYPE) & TE_CLOSURE0) != 0) +#define ARITY(TYPE) ( ((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) & 0x00000007) : 0 ) +#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__}) +#define CHECK_NULL(ptr, ...) if ((ptr) == NULL) { __VA_ARGS__; return NULL; } + +static te_expr *new_expr(const int type, const te_expr *parameters[]) { + const int arity = ARITY(type); + const int psize = sizeof(void*) * arity; + const int size = (sizeof(te_expr) - sizeof(void*)) + psize + (IS_CLOSURE(type) ? sizeof(void*) : 0); + te_expr *ret = malloc(size); + CHECK_NULL(ret); + + memset(ret, 0, size); + if (arity && parameters) { + memcpy(ret->parameters, parameters, psize); + } + ret->type = type; + ret->bound = 0; + return ret; +} + + +void te_free_parameters(te_expr *n) { + if (!n) return; + switch (TYPE_MASK(n->type)) { + case TE_FUNCTION7: case TE_CLOSURE7: te_free(n->parameters[6]); /* Falls through. */ + case TE_FUNCTION6: case TE_CLOSURE6: te_free(n->parameters[5]); /* Falls through. */ + case TE_FUNCTION5: case TE_CLOSURE5: te_free(n->parameters[4]); /* Falls through. */ + case TE_FUNCTION4: case TE_CLOSURE4: te_free(n->parameters[3]); /* Falls through. */ + case TE_FUNCTION3: case TE_CLOSURE3: te_free(n->parameters[2]); /* Falls through. */ + case TE_FUNCTION2: case TE_CLOSURE2: te_free(n->parameters[1]); /* Falls through. */ + case TE_FUNCTION1: case TE_CLOSURE1: te_free(n->parameters[0]); + } +} + + +void te_free(te_expr *n) { + if (!n) return; + te_free_parameters(n); + free(n); +} + + +static double pi(void) {return 3.14159265358979323846;} +static double e(void) {return 2.71828182845904523536;} +static double fac(double a) {/* simplest version of fac */ + if (a < 0.0) + return NAN; + if (a > UINT_MAX) + return INFINITY; + unsigned int ua = (unsigned int)(a); + unsigned long int result = 1, i; + for (i = 1; i <= ua; i++) { + if (i > ULONG_MAX / result) + return INFINITY; + result *= i; + } + return (double)result; +} +static double ncr(double n, double r) { + if (n < 0.0 || r < 0.0 || n < r) return NAN; + if (n > UINT_MAX || r > UINT_MAX) return INFINITY; + unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i; + unsigned long int result = 1; + if (ur > un / 2) ur = un - ur; + for (i = 1; i <= ur; i++) { + if (result > ULONG_MAX / (un - ur + i)) + return INFINITY; + result *= un - ur + i; + result /= i; + } + return result; +} +static double npr(double n, double r) {return ncr(n, r) * fac(r);} + +#ifdef _MSC_VER +#pragma function (ceil) +#pragma function (floor) +#endif + +static const te_variable functions[] = { + /* must be in alphabetical order */ + {"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE, 0}, + {"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"e", e, TE_FUNCTION0 | TE_FLAG_PURE, 0}, + {"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"fac", fac, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"ln", log, TE_FUNCTION1 | TE_FLAG_PURE, 0}, +#ifdef TE_NAT_LOG + {"log", log, TE_FUNCTION1 | TE_FLAG_PURE, 0}, +#else + {"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, +#endif + {"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, + {"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, + {"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0}, + {"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0}, + {"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {0, 0, 0, 0} +}; + +static const te_variable *find_builtin(const char *name, int len) { + int imin = 0; + int imax = sizeof(functions) / sizeof(te_variable) - 2; + + /*Binary search.*/ + while (imax >= imin) { + const int i = (imin + ((imax-imin)/2)); + int c = strncmp(name, functions[i].name, len); + if (!c) c = '\0' - functions[i].name[len]; + if (c == 0) { + return functions + i; + } else if (c > 0) { + imin = i + 1; + } else { + imax = i - 1; + } + } + + return 0; +} + +static const te_variable *find_lookup(const state *s, const char *name, int len) { + int iters; + const te_variable *var; + if (!s->lookup) return 0; + + for (var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) { + if (strncmp(name, var->name, len) == 0 && var->name[len] == '\0') { + return var; + } + } + return 0; +} + + + +static double add(double a, double b) {return a + b;} +static double sub(double a, double b) {return a - b;} +static double mul(double a, double b) {return a * b;} +static double divide(double a, double b) {return a / b;} +static double negate(double a) {return -a;} +static double comma(double a, double b) {(void)a; return b;} + + +void next_token(state *s) { + s->type = TOK_NULL; + + do { + + if (!*s->next){ + s->type = TOK_END; + return; + } + + /* Try reading a number. */ + if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') { + s->value = strtod(s->next, (char**)&s->next); + s->type = TOK_NUMBER; + } else { + /* Look for a variable or builtin function call. */ + if (isalpha(s->next[0])) { + const char *start; + start = s->next; + while (isalpha(s->next[0]) || isdigit(s->next[0]) || (s->next[0] == '_')) s->next++; + + const te_variable *var = find_lookup(s, start, s->next - start); + if (!var) var = find_builtin(start, s->next - start); + + if (!var) { + s->type = TOK_ERROR; + } else { + switch(TYPE_MASK(var->type)) + { + case TE_VARIABLE: + s->type = TOK_VARIABLE; + s->bound = var->address; + break; + + case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: /* Falls through. */ + case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: /* Falls through. */ + s->context = var->context; /* Falls through. */ + + case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3: /* Falls through. */ + case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7: /* Falls through. */ + s->type = var->type; + s->function = var->address; + break; + } + } + + } else { + /* Look for an operator or special character. */ + switch (s->next++[0]) { + case '+': s->type = TOK_INFIX; s->function = add; break; + case '-': s->type = TOK_INFIX; s->function = sub; break; + case '*': s->type = TOK_INFIX; s->function = mul; break; + case '/': s->type = TOK_INFIX; s->function = divide; break; + case '^': s->type = TOK_INFIX; s->function = pow; break; + case '%': s->type = TOK_INFIX; s->function = fmod; break; + case '(': s->type = TOK_OPEN; break; + case ')': s->type = TOK_CLOSE; break; + case ',': s->type = TOK_SEP; break; + case ' ': case '\t': case '\n': case '\r': break; + default: s->type = TOK_ERROR; break; + } + } + } + } while (s->type == TOK_NULL); +} + + +static te_expr *list(state *s); +static te_expr *expr(state *s); +static te_expr *power(state *s); + +static te_expr *base(state *s) { + /* = | | {"(" ")"} | | "(" {"," } ")" | "(" ")" */ + te_expr *ret; + int arity; + + switch (TYPE_MASK(s->type)) { + case TOK_NUMBER: + ret = new_expr(TE_CONSTANT, 0); + CHECK_NULL(ret); + + ret->value = s->value; + next_token(s); + break; + + case TOK_VARIABLE: + ret = new_expr(TE_VARIABLE, 0); + CHECK_NULL(ret); + + ret->bound = s->bound; + next_token(s); + break; + + case TE_FUNCTION0: + case TE_CLOSURE0: + ret = new_expr(s->type, 0); + CHECK_NULL(ret); + + ret->function = s->function; + if (IS_CLOSURE(s->type)) ret->parameters[0] = s->context; + next_token(s); + if (s->type == TOK_OPEN) { + next_token(s); + if (s->type != TOK_CLOSE) { + s->type = TOK_ERROR; + } else { + next_token(s); + } + } + break; + + case TE_FUNCTION1: + case TE_CLOSURE1: + ret = new_expr(s->type, 0); + CHECK_NULL(ret); + + ret->function = s->function; + if (IS_CLOSURE(s->type)) ret->parameters[1] = s->context; + next_token(s); + ret->parameters[0] = power(s); + CHECK_NULL(ret->parameters[0], te_free(ret)); + break; + + case TE_FUNCTION2: case TE_FUNCTION3: case TE_FUNCTION4: + case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7: + case TE_CLOSURE2: case TE_CLOSURE3: case TE_CLOSURE4: + case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: + arity = ARITY(s->type); + + ret = new_expr(s->type, 0); + CHECK_NULL(ret); + + ret->function = s->function; + if (IS_CLOSURE(s->type)) ret->parameters[arity] = s->context; + next_token(s); + + if (s->type != TOK_OPEN) { + s->type = TOK_ERROR; + } else { + int i; + for(i = 0; i < arity; i++) { + next_token(s); + ret->parameters[i] = expr(s); + CHECK_NULL(ret->parameters[i], te_free(ret)); + + if(s->type != TOK_SEP) { + break; + } + } + if(s->type != TOK_CLOSE || i != arity - 1) { + s->type = TOK_ERROR; + } else { + next_token(s); + } + } + + break; + + case TOK_OPEN: + next_token(s); + ret = list(s); + CHECK_NULL(ret); + + if (s->type != TOK_CLOSE) { + s->type = TOK_ERROR; + } else { + next_token(s); + } + break; + + default: + ret = new_expr(0, 0); + CHECK_NULL(ret); + + s->type = TOK_ERROR; + ret->value = NAN; + break; + } + + return ret; +} + + +static te_expr *power(state *s) { + /* = {("-" | "+")} */ + int sign = 1; + while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) { + if (s->function == sub) sign = -sign; + next_token(s); + } + + te_expr *ret; + + if (sign == 1) { + ret = base(s); + } else { + te_expr *b = base(s); + CHECK_NULL(b); + + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, b); + CHECK_NULL(ret, te_free(b)); + + ret->function = negate; + } + + return ret; +} + +#ifdef TE_POW_FROM_RIGHT +static te_expr *factor(state *s) { + /* = {"^" } */ + te_expr *ret = power(s); + CHECK_NULL(ret); + + int neg = 0; + + if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) { + te_expr *se = ret->parameters[0]; + free(ret); + ret = se; + neg = 1; + } + + te_expr *insertion = 0; + + while (s->type == TOK_INFIX && (s->function == pow)) { + te_fun2 t = s->function; + next_token(s); + + if (insertion) { + /* Make exponentiation go right-to-left. */ + te_expr *p = power(s); + CHECK_NULL(p, te_free(ret)); + + te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], p); + CHECK_NULL(insert, te_free(p), te_free(ret)); + + insert->function = t; + insertion->parameters[1] = insert; + insertion = insert; + } else { + te_expr *p = power(s); + CHECK_NULL(p, te_free(ret)); + + te_expr *prev = ret; + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, p); + CHECK_NULL(ret, te_free(p), te_free(prev)); + + ret->function = t; + insertion = ret; + } + } + + if (neg) { + te_expr *prev = ret; + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); + CHECK_NULL(ret, te_free(prev)); + + ret->function = negate; + } + + return ret; +} +#else +static te_expr *factor(state *s) { + /* = {"^" } */ + te_expr *ret = power(s); + CHECK_NULL(ret); + + while (s->type == TOK_INFIX && (s->function == pow)) { + te_fun2 t = s->function; + next_token(s); + te_expr *p = power(s); + CHECK_NULL(p, te_free(ret)); + + te_expr *prev = ret; + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, p); + CHECK_NULL(ret, te_free(p), te_free(prev)); + + ret->function = t; + } + + return ret; +} +#endif + + + +static te_expr *term(state *s) { + /* = {("*" | "/" | "%") } */ + te_expr *ret = factor(s); + CHECK_NULL(ret); + + while (s->type == TOK_INFIX && (s->function == mul || s->function == divide || s->function == fmod)) { + te_fun2 t = s->function; + next_token(s); + te_expr *f = factor(s); + CHECK_NULL(f, te_free(ret)); + + te_expr *prev = ret; + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, f); + CHECK_NULL(ret, te_free(f), te_free(prev)); + + ret->function = t; + } + + return ret; +} + + +static te_expr *expr(state *s) { + /* = {("+" | "-") } */ + te_expr *ret = term(s); + CHECK_NULL(ret); + + while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) { + te_fun2 t = s->function; + next_token(s); + te_expr *te = term(s); + CHECK_NULL(te, te_free(ret)); + + te_expr *prev = ret; + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, te); + CHECK_NULL(ret, te_free(te), te_free(prev)); + + ret->function = t; + } + + return ret; +} + + +static te_expr *list(state *s) { + /* = {"," } */ + te_expr *ret = expr(s); + CHECK_NULL(ret); + + while (s->type == TOK_SEP) { + next_token(s); + te_expr *e = expr(s); + CHECK_NULL(e, te_free(ret)); + + te_expr *prev = ret; + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, e); + CHECK_NULL(ret, te_free(e), te_free(prev)); + + ret->function = comma; + } + + return ret; +} + + +#define TE_FUN(...) ((double(*)(__VA_ARGS__))n->function) +#define M(e) te_eval(n->parameters[e]) + + +double te_eval(const te_expr *n) { + if (!n) return NAN; + + switch(TYPE_MASK(n->type)) { + case TE_CONSTANT: return n->value; + case TE_VARIABLE: return *n->bound; + + case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3: + case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7: + switch(ARITY(n->type)) { + case 0: return TE_FUN(void)(); + case 1: return TE_FUN(double)(M(0)); + case 2: return TE_FUN(double, double)(M(0), M(1)); + case 3: return TE_FUN(double, double, double)(M(0), M(1), M(2)); + case 4: return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3)); + case 5: return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4)); + case 6: return TE_FUN(double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5)); + case 7: return TE_FUN(double, double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5), M(6)); + default: return NAN; + } + + case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: + case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: + switch(ARITY(n->type)) { + case 0: return TE_FUN(void*)(n->parameters[0]); + case 1: return TE_FUN(void*, double)(n->parameters[1], M(0)); + case 2: return TE_FUN(void*, double, double)(n->parameters[2], M(0), M(1)); + case 3: return TE_FUN(void*, double, double, double)(n->parameters[3], M(0), M(1), M(2)); + case 4: return TE_FUN(void*, double, double, double, double)(n->parameters[4], M(0), M(1), M(2), M(3)); + case 5: return TE_FUN(void*, double, double, double, double, double)(n->parameters[5], M(0), M(1), M(2), M(3), M(4)); + case 6: return TE_FUN(void*, double, double, double, double, double, double)(n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5)); + case 7: return TE_FUN(void*, double, double, double, double, double, double, double)(n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6)); + default: return NAN; + } + + default: return NAN; + } + +} + +#undef TE_FUN +#undef M + +static void optimize(te_expr *n) { + /* Evaluates as much as possible. */ + if (n->type == TE_CONSTANT) return; + if (n->type == TE_VARIABLE) return; + + /* Only optimize out functions flagged as pure. */ + if (IS_PURE(n->type)) { + const int arity = ARITY(n->type); + int known = 1; + int i; + for (i = 0; i < arity; ++i) { + optimize(n->parameters[i]); + if (((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) { + known = 0; + } + } + if (known) { + const double value = te_eval(n); + te_free_parameters(n); + n->type = TE_CONSTANT; + n->value = value; + } + } +} + + +te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) { + state s; + s.start = s.next = expression; + s.lookup = variables; + s.lookup_len = var_count; + + next_token(&s); + te_expr *root = list(&s); + if (root == NULL) { + if (error) *error = -1; + return NULL; + } + + if (s.type != TOK_END) { + te_free(root); + if (error) { + *error = (s.next - s.start); + if (*error == 0) *error = 1; + } + return 0; + } else { + optimize(root); + if (error) *error = 0; + return root; + } +} + + +double te_interp(const char *expression, int *error) { + te_expr *n = te_compile(expression, 0, 0, error); + + double ret; + if (n) { + ret = te_eval(n); + te_free(n); + } else { + ret = NAN; + } + return ret; +} + +static void pn (const te_expr *n, int depth) { + int i, arity; + printf("%*s", depth, ""); + + switch(TYPE_MASK(n->type)) { + case TE_CONSTANT: printf("%f\n", n->value); break; + case TE_VARIABLE: printf("bound %p\n", n->bound); break; + + case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3: + case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7: + case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: + case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: + arity = ARITY(n->type); + printf("f%d", arity); + for(i = 0; i < arity; i++) { + printf(" %p", n->parameters[i]); + } + printf("\n"); + for(i = 0; i < arity; i++) { + pn(n->parameters[i], depth + 1); + } + break; + } +} + + +void te_print(const te_expr *n) { + pn(n, 0); +} diff --git a/mcstas-comps/share/tinyexpr.h b/mcstas-comps/share/tinyexpr.h new file mode 100644 index 000000000..c2cbe1a30 --- /dev/null +++ b/mcstas-comps/share/tinyexpr.h @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: Zlib +/* + * TINYEXPR - Tiny recursive descent parser and evaluation engine in C + * + * Copyright (c) 2015-2020 Lewis Van Winkle + * + * http://CodePlea.com + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef TINYEXPR_H +#define TINYEXPR_H + + +#ifdef __cplusplus +extern "C" { +#endif + + + +typedef struct te_expr { + int type; + union {double value; const double *bound; const void *function;}; + void *parameters[1]; +} te_expr; + + +enum { + TE_VARIABLE = 0, + + TE_FUNCTION0 = 8, TE_FUNCTION1, TE_FUNCTION2, TE_FUNCTION3, + TE_FUNCTION4, TE_FUNCTION5, TE_FUNCTION6, TE_FUNCTION7, + + TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3, + TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7, + + TE_FLAG_PURE = 32 +}; + +typedef struct te_variable { + const char *name; + const void *address; + int type; + void *context; +} te_variable; + + + +/* Parses the input expression, evaluates it, and frees it. */ +/* Returns NaN on error. */ +double te_interp(const char *expression, int *error); + +/* Parses the input expression and binds variables. */ +/* Returns NULL on error. */ +te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error); + +/* Evaluates the expression. */ +double te_eval(const te_expr *n); + +/* Prints debugging information on the syntax tree. */ +void te_print(const te_expr *n); + +/* Frees the expression. */ +/* This is safe to call on NULL pointers. */ +void te_free(te_expr *n); + + +#ifdef __cplusplus +} +#endif + +#endif /*TINYEXPR_H*/ diff --git a/mcstas-comps/share/union-lib.c b/mcstas-comps/share/union-lib.c index eac2f889a..3c8007312 100755 --- a/mcstas-comps/share/union-lib.c +++ b/mcstas-comps/share/union-lib.c @@ -25,6 +25,7 @@ enum shape { }; enum process { + Inhomogenous_incoherent, Incoherent, Powder, Single_crystal, @@ -479,6 +480,7 @@ double refraction_Qc; union data_transfer_union{ // List of pointers to storage structs for all supported physical processes + struct Inhomogenous_incoherent_struct *Inhomogenous_incoherent_struct; struct Incoherent_physics_storage_struct *pointer_to_a_Incoherent_physics_storage_struct; struct Powder_physics_storage_struct *pointer_to_a_Powder_physics_storage_struct; struct Single_crystal_physics_storage_struct *pointer_to_a_Single_crystal_physics_storage_struct; diff --git a/mcstas-comps/share/union-suffix.c b/mcstas-comps/share/union-suffix.c index 1f7d2db17..a1bdb00b1 100644 --- a/mcstas-comps/share/union-suffix.c +++ b/mcstas-comps/share/union-suffix.c @@ -11,6 +11,11 @@ int physics_my(enum process choice, double *my,double *k_initial, union data_tra int output = 0; // Error return value #ifdef PROCESS_DETECTOR switch(choice) { + #ifdef PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR + case Inhomogenous_incoherent: + output = Inhomogenous_incoherent_physics_my(my, k_initial, data_transfer, focus_data, _particle); + break; + #endif #ifdef PROCESS_INCOHERENT_DETECTOR case Incoherent: output = Incoherent_physics_my(my, k_initial, data_transfer, focus_data, _particle); @@ -75,6 +80,11 @@ int physics_scattering(enum process choice, double *k_final, double *k_initial, int output = 0; // Error return value #ifdef PROCESS_DETECTOR switch(choice) { + #ifdef PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR + case Inhomogenous_incoherent: + output = Inhomogenous_incoherent_physics_scattering(k_final, k_initial, weight, data_transfer, focus_data, _particle); + break; + #endif #ifdef PROCESS_INCOHERENT_DETECTOR case Incoherent: output = Incoherent_physics_scattering(k_final, k_initial, weight, data_transfer, focus_data, _particle); diff --git a/mcstas-comps/union/Union_master.comp b/mcstas-comps/union/Union_master.comp index 92a4679b7..e774bac5a 100755 --- a/mcstas-comps/union/Union_master.comp +++ b/mcstas-comps/union/Union_master.comp @@ -1536,6 +1536,22 @@ TRACE k_rotated[0] = k[0]; k_rotated[1] = k[1]; k_rotated[2] = k[2]; // focus_data RayAim already updated for non isotropic processes } + /* + Plan for adding in inhomogenous processes: + - The processes will have a flag, that checks if they require + numerical integration. + - If they do, then we use a numerical integration algorithm, + where we sample my from the process at different points. + We then assume that each mu has a distance around itself + that it is "correct" for, i.e the mu distribution is uniform + around the mu. + - Then each of these mu now have a smaller distance than length_to_boundary + and we must therefore weight each in my_sum with the normalized length they posses. + i.e if length_to_boundary is divided into 10, divide each mu by 10. + - For the sampling, we must then sample with the cumulative + probability function, which we calculate for each small bit of + the inhomogenous process. + */ // Call the probability for scattering function assighed to this specific procress (the process pointer is updated in the for loop) process = &Volumes[current_volume]->p_physics->p_scattering_array[p_index]; // GPU Allowed From bbb23acb0270010851f4834662709fc72046b436 Mon Sep 17 00:00:00 2001 From: Diablo Date: Tue, 3 Feb 2026 16:50:38 +0100 Subject: [PATCH 02/11] Add inhomogenous incoherent component --- .../Inhomogenous_incoherent_process.comp | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100755 mcstas-comps/union/Inhomogenous_incoherent_process.comp diff --git a/mcstas-comps/union/Inhomogenous_incoherent_process.comp b/mcstas-comps/union/Inhomogenous_incoherent_process.comp new file mode 100755 index 000000000..12fa7ef87 --- /dev/null +++ b/mcstas-comps/union/Inhomogenous_incoherent_process.comp @@ -0,0 +1,226 @@ +/******************************************************************************* +* +* McStas, neutron ray-tracing package +* Copyright(C) 2007 Risoe National Laboratory. +* +* %I +* Written by: Daniel Lomholt Christensen +* Date: 26/01/2026 +* Version: $Revision: 0.1 $ +* Origin: University of Copenhagen +* +* A sample component to separate geometry and phsysics +* +* %D +* +* This Union_process is based on the Incoherent_process.comp component +* originally written by Mads Bertelsen inspired by Kim Lefmann and +* Kristian Nielsen +* +* Part of the Union components, a set of components that work together and thus +* sperates geometry and physics within McStas. +* The use of this component requires other components to be used. +* +* 1) One specifies a number of processes using process components like this one +* 2) These are gathered into material definitions using Union_make_material +* 3) Geometries are placed using Union_box / Union_cylinder, assigned a material +* 4) A Union_master component placed after all of the above +* +* Only in step 4 will any simulation happen, and per default all geometries +* defined before the master, but after the previous will be simulated here. +* +* There is a dedicated manual available for the Union_components +* +* Algorithm: +* Described elsewhere +* +* %P +* INPUT PARAMETERS: +* inhomogenous_function [string]String containing your mathematical function. +* sigma: [barns] Incoherent scattering cross section +* f_QE: [1] Fraction of quasielastic scattering (rest is elastic) [1] +* gamma: [meV] Lorentzian width of quasielastic broadening (HWHM) [1] +* packing_factor: [1] How dense is the material compared to optimal 0-1 +* unit_cell_volume: [AA^3] Unit cell volume +* interact_fraction: [1] How large a part of the scattering events should use this process 0-1 (sum of all processes in material = 1) +* init: [string] name of Union_init component (typically "init", default) +* +* CALCULATED PARAMETERS: +* +* %L +* +* +* %E +******************************************************************************/ + +DEFINE COMPONENT Inhomogenous_incoherent_process + +SETTING PARAMETERS(string inhomogenous_function = "", sigma=5.08, f_QE=0, gamma=0, packing_factor=1, unit_cell_volume=13.8, interact_fraction=-1, string init="init") + + +/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */ + +SHARE +%{ +%include "tinyexpr.h" +%include "tinyexpr.c" +#ifndef Union +#error "The Union_init component must be included before this Incoherent_process component" +#endif + + +struct Inhomogenous_incoherent_struct{ + // Variables that needs to be transfered between any of the following places: + // The initialize in this component + // The function for calculating my + // The function for calculating scattering + double my_scattering; + double QE_sampling_frequency; + double lorentzian_width; + +}; + + + + +// Function for calculating my in Incoherent case +int Inhomogenous_incoherent_physics_my(double *my,double *k_initial, union data_transfer_union data_transfer, struct focus_data_struct *focus_data, _class_particle *_particle) { + *my = data_transfer.Inhomogenous_incoherent_struct->my_scattering; + return 1; +}; + +// Function for basic incoherent scattering event +int Inhomogenous_incoherent_physics_scattering(double *k_final, double *k_initial, double *weight, union data_transfer_union data_transfer, struct focus_data_struct *focus_data, _class_particle *_particle) { + + //New version of incoherent scattering + double k_length = sqrt(k_initial[0]*k_initial[0]+k_initial[1]*k_initial[1]+k_initial[2]*k_initial[2]); + + Coords k_out; + // Here is the focusing system in action, get a vector + double solid_angle; + focus_data->focusing_function(&k_out,&solid_angle,focus_data); + NORM(k_out.x,k_out.y,k_out.z); + *weight *= solid_angle*0.25/PI; + + double v_i,v_f,E_i,dE,E_f; + + if (rand01() < data_transfer.Inhomogenous_incoherent_struct->QE_sampling_frequency) { + v_i = k_length * K2V; + E_i = VS2E*v_i*v_i; + dE = data_transfer.Inhomogenous_incoherent_struct->lorentzian_width*tan(PI/2*randpm1()); + E_f = E_i + dE; + if (E_f <= 0) + return 0; + v_f = SE2V*sqrt(E_f); + k_length = v_f*V2K; + } + + k_final[0] = k_out.x*k_length; k_final[1] = k_out.y*k_length; k_final[2] = k_out.z*k_length; + return 1; +}; + +#ifndef PROCESS_DETECTOR + #define PROCESS_DETECTOR dummy +#endif + +#ifndef PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR + #define PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR dummy +#endif +%} + +DECLARE +%{ +// Needed for transport to the main component +struct global_process_element_struct global_process_element; +struct scattering_process_struct This_process; + +// Declare for this component, to do calculations on the input / store in the transported data +struct Inhomogenous_incoherent_struct Inhomogenous_storage; +double effective_my_scattering; + +%} + +INITIALIZE +%{ + if (!strcmp(inhomogenous_function, "")){ + fprintf(stderr, "\nERROR! No Inhomogenous function was set!\tEXITING!\n\n"); + exit(1); + } + double pos_x, pos_y, pos_z, vel_x, vel_y, vel_z, t; + /* Store variable names and pointers. */ + te_variable vars[] = {{"pos_x", &pos_x}, {"pos_y", &pos_y}, {"pos_z", &pos_z}, + {"vel_x", &vel_x}, {"vel_y", &vel_y}, {"vel_z", &vel_z}, + {"t", &t}}; + + int err; + /* Compile the expression with variables. */ + pos_x = 10; + // pos_y = 10; + // pos_z = 10; + // vel_x = 10; + // vel_y = 10; + // vel_z = 10; + // t = 10; + te_expr *expr = te_compile(inhomogenous_function, vars, 7, &err); + if (expr){ + double result = te_eval(expr); + printf("\nResult of inhomogenous_function is %g\n\n", result); + te_free(expr); + } else { + printf("Parse error at %d\n", err); + } + // Initialize done in the component + effective_my_scattering = ((packing_factor/unit_cell_volume) * 100 * sigma); + Inhomogenous_storage.my_scattering = effective_my_scattering; + + Inhomogenous_storage.QE_sampling_frequency = f_QE; + Inhomogenous_storage.lorentzian_width = gamma; + + //First initialise This_process with default values: + scattering_process_struct_init(&This_process); + + // Need to specify if this process is isotropic + This_process.non_isotropic_rot_index = -1; // Yes (powder) + //This_process.non_isotropic_rot_index = 1; // No (single crystal) + + // Need to specify if this process need to use focusing in calculation of inverse penetration depth (physics_my) + //This_process.needs_cross_section_focus = 1; // Yes + This_process.needs_cross_section_focus = -1; // No + + // The type of the process must be saved in the global enum process + This_process.eProcess = Inhomogenous_incoherent; + + // Packing the data into a structure that is transported to the main component + sprintf(This_process.name,"%s",NAME_CURRENT_COMP); + This_process.process_p_interact = interact_fraction; + This_process.data_transfer.Inhomogenous_incoherent_struct = &Inhomogenous_storage; + //This_process.data_transfer.pointer_to_a_Incoherent_physics_storage_struct->my_scattering = effective_my_scattering; + This_process.probability_for_scattering_function = &Inhomogenous_incoherent_physics_my; + This_process.scattering_function = &Inhomogenous_incoherent_physics_scattering; + + // This will be the same for all process's, and can thus be moved to an include. + sprintf(global_process_element.name,"%s",NAME_CURRENT_COMP); + global_process_element.component_index = INDEX_CURRENT_COMP; + global_process_element.p_scattering_process = &This_process; + + if (_getcomp_index(init) < 0) { + fprintf(stderr,"Incoherent_process:%s: Error identifying Union_init component, %s is not a known component name.\n", + NAME_CURRENT_COMP, init); + exit(-1); + } + + struct pointer_to_global_process_list *global_process_list = COMP_GETPAR3(Union_init, init, global_process_list); + add_element_to_process_list(global_process_list, global_process_element); + %} + +TRACE +%{ +%} + +FINALLY +%{ +// Since the process and it's storage is a static allocation, there is nothing to deallocate + +%} + +END From a07f0d0ade355c0d3b05488dd161d3631174371f Mon Sep 17 00:00:00 2001 From: Diablo Date: Wed, 4 Feb 2026 13:07:04 +0100 Subject: [PATCH 03/11] Add formatting to Union_master comp --- mcstas-comps/union/Union_master.comp | 4632 +++++++++++++------------- 1 file changed, 2320 insertions(+), 2312 deletions(-) diff --git a/mcstas-comps/union/Union_master.comp b/mcstas-comps/union/Union_master.comp index e774bac5a..242833aaf 100755 --- a/mcstas-comps/union/Union_master.comp +++ b/mcstas-comps/union/Union_master.comp @@ -73,2719 +73,2727 @@ NOACC SHARE %{ -#ifndef Union -#error "The Union_init component must be included before this Union_master component" -#endif -struct logger_with_data_struct loggers_with_data_array; -struct abs_logger_with_data_struct abs_loggers_with_data_array; + #ifndef Union + #error "The Union_init component must be included before this Union_master component" + #endif + + struct logger_with_data_struct loggers_with_data_array; + struct abs_logger_with_data_struct abs_loggers_with_data_array; + + #ifndef MASTER_DETECTOR + #define MASTER_DETECTOR dummy + #endif -#ifndef MASTER_DETECTOR - #define MASTER_DETECTOR dummy -#endif %} DECLARE %{ - // Declare global lists, will be retrieved in INITIALIZE - struct global_positions_to_transform_list_struct *global_positions_to_transform_list_master; - struct global_rotations_to_transform_list_struct *global_rotations_to_transform_list_master; - struct pointer_to_global_process_list *global_process_list_master; - struct pointer_to_global_material_list *global_material_list_master; - struct pointer_to_global_surface_list *global_surface_list_master; - struct pointer_to_global_geometry_list *global_geometry_list_master; - struct pointer_to_global_logger_list *global_all_volume_logger_list_master; - struct pointer_to_global_logger_list *global_specific_volumes_logger_list_master; - struct pointer_to_global_abs_logger_list *global_all_volume_abs_logger_list_master; - struct pointer_to_global_abs_logger_list *global_specific_volumes_abs_logger_list_master; - struct global_tagging_conditional_list_struct *global_tagging_conditional_list_master; - struct pointer_to_global_master_list *global_master_list_master; - - // New precompiler settings for verbal / tagging, remove // to include verbal in trace and/or tagging - //#define Union_trace_verbal_setting - //#define Union_enable_tagging_setting - - int starting_volume_warning; - - // Declare the global variables (not to be in output parameters) - struct global_master_element_struct global_master_element; - int this_global_master_index; - - // variables used for assigning global information to local variables - int previous_master_index; - int geometry_list_index; - - // The main structures used in this component - struct intersection_time_table_struct intersection_time_table; - struct Volume_struct **Volumes; - struct geometry_struct **Geometries; - struct Volume_struct **Volume_copies; - struct starting_lists_struct starting_lists; - - // garbage collection for volume_copies - struct pointer_to_1d_int_list Volume_copies_allocated; - - // Vectors in old format (still used by intersect function, will go to Coords in future) - double r[3]; - double r_start[3]; - double v[3]; - - // Error handling - int error_msg; - int component_error_msg; - - // For verbal output - char string_output[128]; - - // Variables for ray-tracing algorithm - int number_of_volumes; - int volume_index; - int process_index; - int iterator; - int solutions; - int max_number_of_processes; - int limit; - int solution; - int min_solution; - int ignore_closest; - int ignore_surface_index; - int min_volume; - int time_found; - double intersection_time; - double min_intersection_time; - - struct scattering_process_struct *process; - struct scattering_process_struct *process_start; - double *my_trace; - double *p_my_trace; - double *my_trace_fraction_control; - double k[3]; - double k_new[3]; - double k_old[3]; - double k_rotated[3]; - double v_length; - double my_sum; - double my_sum_plus_abs; - double culmative_probability; - double mc_prop; - double time_to_scattering; - double length_to_scattering; - double length_to_boundary; - double time_to_boundery; - int selected_process; - int scattering_event; - double time_propagated_without_scattering; - - int a_next_volume_found; - int next_volume; - double next_volume_priority; - - int done; - int current_volume; - int previous_volume; - int ray_sucseeded; - int *number_of_solutions; - int number_of_solutions_static; - int *check; - int *start; - int intersection_with_children; - int geometry_output; - - // For within_which_volume - int tree_next_volume; - int *pre_allocated1; - int *pre_allocated2; - int *pre_allocated3; - Coords ray_position; - - Coords ray_velocity; - Coords ray_velocity_rotated; - Coords ray_velocity_final; - Coords wavevector; - Coords wavevector_rotated; - int volume_0_found; - - int *scattered_flag; - int **scattered_flag_VP; - - // For coordinate transformations - Rotation master_transposed_rotation_matrix; - Rotation temp_rotation_matrix; - Rotation temp_transpose_rotation_matrix; - Coords non_rotated_position; - Coords rotated_position; - int non_isotropic_found; - - // For tagging - struct list_of_tagging_tree_node_pointers master_tagging_node_list; - struct tagging_tree_node_struct *current_tagging_node; - - int tagging_leaf_counter; - int stop_tagging_ray; - int stop_creating_nodes; - int number_of_scattering_events; - - // For geometry p interact - double real_transmission_probability; - double mc_transmission_probability; - - // Process p interact - int number_of_process_interacts_set; - int index_of_lacking_process; - double total_process_interact; - - // Volume nr -> component index - struct pointer_to_1d_int_list geometry_component_index_list; - - // Masks - struct pointer_to_1d_int_list mask_volume_index_list; - int number_of_masks; - int number_of_masked_volumes; - struct pointer_to_1d_int_list mask_status_list; - struct pointer_to_1d_int_list current_mask_intersect_list_status; - int mask_index_main; - int mask_iterator; - int *mask_start; - int *mask_check; - int need_to_run_within_which_volume; - - // Loggers - //struct logger_with_data_struct loggers_with_data_array; - int *number_of_processes_array; - double p_old; - int log_index; - int conditional_status; - struct logger_struct *this_logger; - struct abs_logger_struct *this_abs_logger; - // union detector_pointer_union detector_pointer; - - // Conditionals - struct conditional_list_struct *tagging_conditional_list; - int *logger_conditional_extend_array; - int *abs_logger_conditional_extend_array; - int max_conditional_extend_index; - int tagging_conditional_extend; - int free_tagging_conditioanl_list; - - // Reliability control - // Safty distance is needed to avoid having ray positions closer to a wall than the precision of intersection functions - double safety_distance; - double safety_distance2; - - // Focusing - struct focus_data_struct temporary_focus_data; - struct focus_data_struct *this_focus_data; - int focus_data_index; - - // Record absorption - double r_old[3]; - double initial_weight; - double abs_weight_factor; - double time_old; - int absorption_index; - int abs_weight_factor_set; - double my_abs; - struct abs_event absorption_event_data[1000]; - - // Absorption logger - Coords abs_position; - Coords transformed_abs_position; - double t_abs_propagation; - double abs_distance; - double abs_max_length; - - // Surfaces - int longest_surface_stack; - struct surface_stack_struct interface_stack; + + // Declare global lists, will be retrieved in INITIALIZE + struct global_positions_to_transform_list_struct *global_positions_to_transform_list_master; + struct global_rotations_to_transform_list_struct *global_rotations_to_transform_list_master; + struct pointer_to_global_process_list *global_process_list_master; + struct pointer_to_global_material_list *global_material_list_master; + struct pointer_to_global_surface_list *global_surface_list_master; + struct pointer_to_global_geometry_list *global_geometry_list_master; + struct pointer_to_global_logger_list *global_all_volume_logger_list_master; + struct pointer_to_global_logger_list *global_specific_volumes_logger_list_master; + struct pointer_to_global_abs_logger_list *global_all_volume_abs_logger_list_master; + struct pointer_to_global_abs_logger_list *global_specific_volumes_abs_logger_list_master; + struct global_tagging_conditional_list_struct *global_tagging_conditional_list_master; + struct pointer_to_global_master_list *global_master_list_master; + + // New precompiler settings for verbal / tagging, remove // to include verbal in trace and/or tagging + //#define Union_trace_verbal_setting + //#define Union_enable_tagging_setting + + int starting_volume_warning; + + // Declare the global variables (not to be in output parameters) + struct global_master_element_struct global_master_element; + int this_global_master_index; + + // variables used for assigning global information to local variables + int previous_master_index; + int geometry_list_index; + + // The main structures used in this component + struct intersection_time_table_struct intersection_time_table; + struct Volume_struct **Volumes; + struct geometry_struct **Geometries; + struct Volume_struct **Volume_copies; + struct starting_lists_struct starting_lists; + + // garbage collection for volume_copies + struct pointer_to_1d_int_list Volume_copies_allocated; + + // Vectors in old format (still used by intersect function, will go to Coords in future) + double r[3]; + double r_start[3]; + double v[3]; + + // Error handling + int error_msg; + int component_error_msg; + + // For verbal output + char string_output[128]; + + // Variables for ray-tracing algorithm + int number_of_volumes; + int volume_index; + int process_index; + int iterator; + int solutions; + int max_number_of_processes; + int limit; + int solution; + int min_solution; + int ignore_closest; + int ignore_surface_index; + int min_volume; + int time_found; + double intersection_time; + double min_intersection_time; + + struct scattering_process_struct *process; + struct scattering_process_struct *process_start; + double *my_trace; + double *p_my_trace; + double *my_trace_fraction_control; + double k[3]; + double k_new[3]; + double k_old[3]; + double k_rotated[3]; + double v_length; + double my_sum; + double my_sum_plus_abs; + double culmative_probability; + double mc_prop; + double time_to_scattering; + double length_to_scattering; + double length_to_boundary; + double time_to_boundery; + int selected_process; + int scattering_event; + double time_propagated_without_scattering; + + int a_next_volume_found; + int next_volume; + double next_volume_priority; + + int done; + int current_volume; + int previous_volume; + int ray_sucseeded; + int *number_of_solutions; + int number_of_solutions_static; + int *check; + int *start; + int intersection_with_children; + int geometry_output; + + // For within_which_volume + int tree_next_volume; + int *pre_allocated1; + int *pre_allocated2; + int *pre_allocated3; + Coords ray_position; + + Coords ray_velocity; + Coords ray_velocity_rotated; + Coords ray_velocity_final; + Coords wavevector; + Coords wavevector_rotated; + int volume_0_found; + + int *scattered_flag; + int **scattered_flag_VP; + + // For coordinate transformations + Rotation master_transposed_rotation_matrix; + Rotation temp_rotation_matrix; + Rotation temp_transpose_rotation_matrix; + Coords non_rotated_position; + Coords rotated_position; + int non_isotropic_found; + + // For tagging + struct list_of_tagging_tree_node_pointers master_tagging_node_list; + struct tagging_tree_node_struct *current_tagging_node; + + int tagging_leaf_counter; + int stop_tagging_ray; + int stop_creating_nodes; + int number_of_scattering_events; + + // For geometry p interact + double real_transmission_probability; + double mc_transmission_probability; + + // Process p interact + int number_of_process_interacts_set; + int index_of_lacking_process; + double total_process_interact; + + // Volume nr -> component index + struct pointer_to_1d_int_list geometry_component_index_list; + + // Masks + struct pointer_to_1d_int_list mask_volume_index_list; + int number_of_masks; + int number_of_masked_volumes; + struct pointer_to_1d_int_list mask_status_list; + struct pointer_to_1d_int_list current_mask_intersect_list_status; + int mask_index_main; + int mask_iterator; + int *mask_start; + int *mask_check; + int need_to_run_within_which_volume; + + // Loggers + //struct logger_with_data_struct loggers_with_data_array; + int *number_of_processes_array; + double p_old; + int log_index; + int conditional_status; + struct logger_struct *this_logger; + struct abs_logger_struct *this_abs_logger; + // union detector_pointer_union detector_pointer; + + // Conditionals + struct conditional_list_struct *tagging_conditional_list; + int *logger_conditional_extend_array; + int *abs_logger_conditional_extend_array; + int max_conditional_extend_index; + int tagging_conditional_extend; + int free_tagging_conditioanl_list; + + // Reliability control + // Safty distance is needed to avoid having ray positions closer to a wall than the precision of intersection functions + double safety_distance; + double safety_distance2; + + // Focusing + struct focus_data_struct temporary_focus_data; + struct focus_data_struct *this_focus_data; + int focus_data_index; + + // Record absorption + double r_old[3]; + double initial_weight; + double abs_weight_factor; + double time_old; + int absorption_index; + int abs_weight_factor_set; + double my_abs; + struct abs_event absorption_event_data[1000]; + + // Absorption logger + Coords abs_position; + Coords transformed_abs_position; + double t_abs_propagation; + double abs_distance; + double abs_max_length; + + // Surfaces + int longest_surface_stack; + struct surface_stack_struct interface_stack; + %} INITIALIZE %{ -if (_getcomp_index(init) < 0) { -fprintf(stderr,"Union_master:%s: Error identifying Union_init component, %s is not a known component name.\n", -NAME_CURRENT_COMP, init); -exit(-1); -} - // Unpack global lists - global_positions_to_transform_list_master = COMP_GETPAR3(Union_init, init, global_positions_to_transform_list); - global_rotations_to_transform_list_master = COMP_GETPAR3(Union_init, init, global_rotations_to_transform_list); - global_process_list_master = COMP_GETPAR3(Union_init, init, global_process_list); - global_material_list_master = COMP_GETPAR3(Union_init, init, global_material_list); - global_surface_list_master = COMP_GETPAR3(Union_init, init, global_surface_list); - global_geometry_list_master = COMP_GETPAR3(Union_init, init, global_geometry_list); - global_all_volume_logger_list_master = COMP_GETPAR3(Union_init, init, global_all_volume_logger_list); - global_specific_volumes_logger_list_master = COMP_GETPAR3(Union_init, init, global_specific_volumes_logger_list); - global_all_volume_abs_logger_list_master = COMP_GETPAR3(Union_init, init, global_all_volume_abs_logger_list); - global_specific_volumes_abs_logger_list_master = COMP_GETPAR3(Union_init, init, global_specific_volumes_abs_logger_list); - global_tagging_conditional_list_master = COMP_GETPAR3(Union_init, init, global_tagging_conditional_list); - global_master_list_master = COMP_GETPAR3(Union_init, init, global_master_list); - - // It is possible to surpress warnings on starting volume by setting this to 1 - starting_volume_warning = 0; - - // Start at 0 error messages, quit after 100. - component_error_msg = 0; - - // For within_which_volume - volume_0_found = 0; - - // For tagging - tagging_leaf_counter=0; - - // For masks - number_of_masks = 0; - number_of_masked_volumes = 0; - - // For surfaces - longest_surface_stack = 0; - - // Use sanitation - #ifndef ANY_GEOMETRY_DETECTOR_DECLARE - printf("\nERROR: Need to define at least one Volume using Union_cylinder or Union_box before using the Union_master component. \n"); - exit(1); - #endif - #ifdef ANY_GEOMETRY_DETECTOR_DECLARE - if (global_geometry_list_master->num_elements == 0) { - printf("\nERROR: Need to define at least one Volume using Union_cylinder or Union_box before using the Union_master component. \n"); - printf(" Union_master component named \"%s\" is before any Volumes in the instrument file. At least one Volume need to be defined before\n",NAME_CURRENT_COMP); + + if (_getcomp_index(init) < 0) { + fprintf(stderr,"Union_master:%s: Error identifying Union_init component, %s is not a known component name.\n", + NAME_CURRENT_COMP, init); + exit(-1); + } + // Unpack global lists + global_positions_to_transform_list_master = COMP_GETPAR3(Union_init, init, global_positions_to_transform_list); + global_rotations_to_transform_list_master = COMP_GETPAR3(Union_init, init, global_rotations_to_transform_list); + global_process_list_master = COMP_GETPAR3(Union_init, init, global_process_list); + global_material_list_master = COMP_GETPAR3(Union_init, init, global_material_list); + global_surface_list_master = COMP_GETPAR3(Union_init, init, global_surface_list); + global_geometry_list_master = COMP_GETPAR3(Union_init, init, global_geometry_list); + global_all_volume_logger_list_master = COMP_GETPAR3(Union_init, init, global_all_volume_logger_list); + global_specific_volumes_logger_list_master = COMP_GETPAR3(Union_init, init, global_specific_volumes_logger_list); + global_all_volume_abs_logger_list_master = COMP_GETPAR3(Union_init, init, global_all_volume_abs_logger_list); + global_specific_volumes_abs_logger_list_master = COMP_GETPAR3(Union_init, init, global_specific_volumes_abs_logger_list); + global_tagging_conditional_list_master = COMP_GETPAR3(Union_init, init, global_tagging_conditional_list); + global_master_list_master = COMP_GETPAR3(Union_init, init, global_master_list); + + // It is possible to surpress warnings on starting volume by setting this to 1 + starting_volume_warning = 0; + + // Start at 0 error messages, quit after 100. + component_error_msg = 0; + + // For within_which_volume + volume_0_found = 0; + + // For tagging + tagging_leaf_counter=0; + + // For masks + number_of_masks = 0; + number_of_masked_volumes = 0; + + // For surfaces + longest_surface_stack = 0; + + // Use sanitation + #ifndef ANY_GEOMETRY_DETECTOR_DECLARE + printf("\nERROR: Need to define at least one Volume using Union_cylinder or Union_box before using the Union_master component. \n"); + exit(1); + #endif + #ifdef ANY_GEOMETRY_DETECTOR_DECLARE + if (global_geometry_list_master->num_elements == 0) { + printf("\nERROR: Need to define at least one Volume using Union_cylinder or Union_box before using the Union_master component. \n"); + printf(" Union_master component named \"%s\" is before any Volumes in the instrument file. At least one Volume need to be defined before\n",NAME_CURRENT_COMP); - exit(1); + exit(1); + } + #endif + + // Parameters describing the safety distances close to surfaces, as scattering should not occur closer to a surface than the + // accuracy of the intersection calculation. + safety_distance = 1E-11; + safety_distance2 = safety_distance*2.0; + + // Write information to the global_master_list_master about the current Union_master + sprintf(global_master_element.name,"%s",NAME_CURRENT_COMP); + global_master_element.component_index = INDEX_CURRENT_COMP; + add_element_to_master_list(global_master_list_master, global_master_element); + if (inherit_number_of_scattering_events == 1 && global_master_list_master->num_elements == 1) { + printf("ERROR in Union_master with name %s. Inherit_number_of_scattering_events set to 1 for first Union_master component, but there is no preceeding Union_master component. Aborting.\n",NAME_CURRENT_COMP); + exit(1); + } + this_global_master_index = global_master_list_master->num_elements - 1; // Save the index for this master in global master list + + // Set the component index of the previous Union_master component if one exists + if (global_master_list_master->num_elements == 1) previous_master_index = 0; // no previous index + else previous_master_index = global_master_list_master->elements[global_master_list_master->num_elements-2].component_index; // -2 because of zero indexing and needing the previous index. + //printf("Assigned previous_master_index = %d \n",previous_master_index); + + // All volumes in the global_geometry_list_master is being check for activity using the number_of_activations input made for each geometry (default is 1) + // In addition it is counted how many volumes, mask volumes and masked volumes are active in this Union_master. + number_of_volumes = 1; // Starting with 1 as the surrounding vacuum is considered a volume + number_of_masks = 0; // Starting with 0 mask volumes + number_of_masked_volumes = 0; // Starting with 0 masked volumes + for (iterator=0;iteratornum_elements;iterator++) { + if (global_geometry_list_master->elements[iterator].component_index < INDEX_CURRENT_COMP && global_geometry_list_master->elements[iterator].activation_counter > 0) { + global_geometry_list_master->elements[iterator].active = 1; + global_geometry_list_master->elements[iterator].activation_counter--; + number_of_volumes++; + if (global_geometry_list_master->elements[iterator].Volume->geometry.is_mask_volume == 1) number_of_masks++; + if (global_geometry_list_master->elements[iterator].Volume->geometry.is_masked_volume == 1) number_of_masked_volumes++; + } else global_geometry_list_master->elements[iterator].active = 0; } - #endif - - // Parameters describing the safety distances close to surfaces, as scattering should not occur closer to a surface than the - // accuracy of the intersection calculation. - safety_distance = 1E-11; - safety_distance2 = safety_distance*2.0; - - // Write information to the global_master_list_master about the current Union_master - sprintf(global_master_element.name,"%s",NAME_CURRENT_COMP); - global_master_element.component_index = INDEX_CURRENT_COMP; - add_element_to_master_list(global_master_list_master, global_master_element); - if (inherit_number_of_scattering_events == 1 && global_master_list_master->num_elements == 1) { - printf("ERROR in Union_master with name %s. Inherit_number_of_scattering_events set to 1 for first Union_master component, but there is no preceeding Union_master component. Aborting.\n",NAME_CURRENT_COMP); - exit(1); - } - this_global_master_index = global_master_list_master->num_elements - 1; // Save the index for this master in global master list - - // Set the component index of the previous Union_master component if one exists - if (global_master_list_master->num_elements == 1) previous_master_index = 0; // no previous index - else previous_master_index = global_master_list_master->elements[global_master_list_master->num_elements-2].component_index; // -2 because of zero indexing and needing the previous index. - //printf("Assigned previous_master_index = %d \n",previous_master_index); - - // All volumes in the global_geometry_list_master is being check for activity using the number_of_activations input made for each geometry (default is 1) - // In addition it is counted how many volumes, mask volumes and masked volumes are active in this Union_master. - number_of_volumes = 1; // Starting with 1 as the surrounding vacuum is considered a volume - number_of_masks = 0; // Starting with 0 mask volumes - number_of_masked_volumes = 0; // Starting with 0 masked volumes - for (iterator=0;iteratornum_elements;iterator++) { - if (global_geometry_list_master->elements[iterator].component_index < INDEX_CURRENT_COMP && global_geometry_list_master->elements[iterator].activation_counter > 0) { - global_geometry_list_master->elements[iterator].active = 1; - global_geometry_list_master->elements[iterator].activation_counter--; - number_of_volumes++; - if (global_geometry_list_master->elements[iterator].Volume->geometry.is_mask_volume == 1) number_of_masks++; - if (global_geometry_list_master->elements[iterator].Volume->geometry.is_masked_volume == 1) number_of_masked_volumes++; - } else global_geometry_list_master->elements[iterator].active = 0; - } - // Allocation of global lists - geometry_component_index_list.num_elements = number_of_volumes; - geometry_component_index_list.elements = malloc( geometry_component_index_list.num_elements * sizeof(int)); - mask_volume_index_list.num_elements = number_of_masks; - if (number_of_masks >0) mask_volume_index_list.elements = malloc( number_of_masks * sizeof(int)); - mask_status_list.num_elements = number_of_masks; - if (number_of_masks >0) mask_status_list.elements = malloc( number_of_masks * sizeof(int)); - current_mask_intersect_list_status.num_elements = number_of_masked_volumes; - if (number_of_masked_volumes >0) current_mask_intersect_list_status.elements = malloc( number_of_masked_volumes * sizeof(int)); - - // Make a list of component index from each volume index - volume_index = 0; - for (iterator=0;iteratornum_elements;iterator++) { - if (global_geometry_list_master->elements[iterator].active == 1) - geometry_component_index_list.elements[++volume_index] = global_geometry_list_master->elements[iterator].component_index; + // Allocation of global lists + geometry_component_index_list.num_elements = number_of_volumes; + geometry_component_index_list.elements = malloc( geometry_component_index_list.num_elements * sizeof(int)); + mask_volume_index_list.num_elements = number_of_masks; + if (number_of_masks >0) mask_volume_index_list.elements = malloc( number_of_masks * sizeof(int)); + mask_status_list.num_elements = number_of_masks; + if (number_of_masks >0) mask_status_list.elements = malloc( number_of_masks * sizeof(int)); + current_mask_intersect_list_status.num_elements = number_of_masked_volumes; + if (number_of_masked_volumes >0) current_mask_intersect_list_status.elements = malloc( number_of_masked_volumes * sizeof(int)); + + // Make a list of component index from each volume index + volume_index = 0; + for (iterator=0;iteratornum_elements;iterator++) { + if (global_geometry_list_master->elements[iterator].active == 1) + geometry_component_index_list.elements[++volume_index] = global_geometry_list_master->elements[iterator].component_index; - } - geometry_component_index_list.elements[0] = 0; // Volume 0 is never set in the above code, but should never be used. - - // The input for this component is done through a series of input components - // All information needed is stored in global lists, some of which is printed here for an overview to the user. - MPI_MASTER( // MPI_MASTER ensures just one thread output this information to the user - if (verbal == 1) { - printf("---------------------------------------------------------------------\n"); - printf("global_process_list_master->num_elements: %d\n",global_process_list_master->num_elements); - for (iterator=0;iteratornum_elements;iterator++) { - printf("name of process [%d]: %s \n",iterator,global_process_list_master->elements[iterator].name); - printf("component index [%d]: %d \n",iterator,global_process_list_master->elements[iterator].component_index); - } + } + geometry_component_index_list.elements[0] = 0; // Volume 0 is never set in the above code, but should never be used. + + // The input for this component is done through a series of input components + // All information needed is stored in global lists, some of which is printed here for an overview to the user. + MPI_MASTER( // MPI_MASTER ensures just one thread output this information to the user + if (verbal == 1) { + printf("---------------------------------------------------------------------\n"); + printf("global_process_list_master->num_elements: %d\n",global_process_list_master->num_elements); + for (iterator=0;iteratornum_elements;iterator++) { + printf("name of process [%d]: %s \n",iterator,global_process_list_master->elements[iterator].name); + printf("component index [%d]: %d \n",iterator,global_process_list_master->elements[iterator].component_index); + } - printf("---------------------------------------------------------------------\n"); - printf("global_material_list_master->num_elements: %d\n",global_material_list_master->num_elements); - for (iterator=0;iteratornum_elements;iterator++) { - printf("name of material [%d]: %s \n",iterator,global_material_list_master->elements[iterator].name); - printf("component index [%d]: %d \n",iterator,global_material_list_master->elements[iterator].component_index); - printf("my_absoprtion [%d]: %f \n",iterator,global_material_list_master->elements[iterator].physics->my_a); - printf("number of processes [%d]: %d \n",iterator,global_material_list_master->elements[iterator].physics->number_of_processes); - } + printf("---------------------------------------------------------------------\n"); + printf("global_material_list_master->num_elements: %d\n",global_material_list_master->num_elements); + for (iterator=0;iteratornum_elements;iterator++) { + printf("name of material [%d]: %s \n",iterator,global_material_list_master->elements[iterator].name); + printf("component index [%d]: %d \n",iterator,global_material_list_master->elements[iterator].component_index); + printf("my_absoprtion [%d]: %f \n",iterator,global_material_list_master->elements[iterator].physics->my_a); + printf("number of processes [%d]: %d \n",iterator,global_material_list_master->elements[iterator].physics->number_of_processes); + } - printf("---------------------------------------------------------------------\n"); - printf("global_geometry_list_master->num_elements: %d\n",global_material_list_master->num_elements); - for (iterator=0;iteratornum_elements;iterator++) { - if (global_geometry_list_master->elements[iterator].active == 1) { - printf("\n"); - printf("name of geometry [%d]: %s \n",iterator,global_geometry_list_master->elements[iterator].name); - printf("component index [%d]: %d \n",iterator,global_geometry_list_master->elements[iterator].component_index); - printf("Volume.name [%d]: %s \n",iterator,global_geometry_list_master->elements[iterator].Volume->name); - if (global_geometry_list_master->elements[iterator].Volume->geometry.is_mask_volume == 0) { - printf("Volume.p_physics.is_vacuum [%d]: %d \n",iterator,global_geometry_list_master->elements[iterator].Volume->p_physics->is_vacuum); - printf("Volume.p_physics.my_absorption [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->p_physics->my_a); - printf("Volume.p_physics.number of processes [%d]: %d \n",iterator,global_geometry_list_master->elements[iterator].Volume->p_physics->number_of_processes); - } - printf("Volume.geometry.shape [%d]: %s \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.shape); - printf("Volume.geometry.center.x [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.center.x); - printf("Volume.geometry.center.y [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.center.y); - printf("Volume.geometry.center.z [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.center.z); - printf("Volume.geometry.rotation_matrix[0] [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[0][0],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[0][1],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[0][2]); - printf("Volume.geometry.rotation_matrix[1] [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[1][0],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[1][1],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[1][2]); - printf("Volume.geometry.rotation_matrix[2] [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[2][0],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[2][1],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[2][2]); - if (strcmp(global_geometry_list_master->elements[iterator].Volume->geometry.shape,"cylinder") == 0) { - printf("Volume.geometry.geometry_parameters.cyl_radius [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.geometry_parameters.p_cylinder_storage->cyl_radius); - printf("Volume.geometry.geometry_parameters.height [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.geometry_parameters.p_cylinder_storage->height); - } - printf("Volume.geometry.focus_data_array.elements[0].Aim [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.focus_data_array.elements[0].Aim.x,global_geometry_list_master->elements[iterator].Volume->geometry.focus_data_array.elements[0].Aim.y,global_geometry_list_master->elements[iterator].Volume->geometry.focus_data_array.elements[0].Aim.z); + printf("---------------------------------------------------------------------\n"); + printf("global_geometry_list_master->num_elements: %d\n",global_material_list_master->num_elements); + for (iterator=0;iteratornum_elements;iterator++) { + if (global_geometry_list_master->elements[iterator].active == 1) { + printf("\n"); + printf("name of geometry [%d]: %s \n",iterator,global_geometry_list_master->elements[iterator].name); + printf("component index [%d]: %d \n",iterator,global_geometry_list_master->elements[iterator].component_index); + printf("Volume.name [%d]: %s \n",iterator,global_geometry_list_master->elements[iterator].Volume->name); + if (global_geometry_list_master->elements[iterator].Volume->geometry.is_mask_volume == 0) { + printf("Volume.p_physics.is_vacuum [%d]: %d \n",iterator,global_geometry_list_master->elements[iterator].Volume->p_physics->is_vacuum); + printf("Volume.p_physics.my_absorption [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->p_physics->my_a); + printf("Volume.p_physics.number of processes [%d]: %d \n",iterator,global_geometry_list_master->elements[iterator].Volume->p_physics->number_of_processes); + } + printf("Volume.geometry.shape [%d]: %s \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.shape); + printf("Volume.geometry.center.x [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.center.x); + printf("Volume.geometry.center.y [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.center.y); + printf("Volume.geometry.center.z [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.center.z); + printf("Volume.geometry.rotation_matrix[0] [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[0][0],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[0][1],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[0][2]); + printf("Volume.geometry.rotation_matrix[1] [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[1][0],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[1][1],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[1][2]); + printf("Volume.geometry.rotation_matrix[2] [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[2][0],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[2][1],global_geometry_list_master->elements[iterator].Volume->geometry.rotation_matrix[2][2]); + if (strcmp(global_geometry_list_master->elements[iterator].Volume->geometry.shape,"cylinder") == 0) { + printf("Volume.geometry.geometry_parameters.cyl_radius [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.geometry_parameters.p_cylinder_storage->cyl_radius); + printf("Volume.geometry.geometry_parameters.height [%d]: %f \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.geometry_parameters.p_cylinder_storage->height); + } + printf("Volume.geometry.focus_data_array.elements[0].Aim [%d]: [%f %f %f] \n",iterator,global_geometry_list_master->elements[iterator].Volume->geometry.focus_data_array.elements[0].Aim.x,global_geometry_list_master->elements[iterator].Volume->geometry.focus_data_array.elements[0].Aim.y,global_geometry_list_master->elements[iterator].Volume->geometry.focus_data_array.elements[0].Aim.z); + } + } + printf("---------------------------------------------------------------------\n"); + printf("number_of_volumes = %d\n",number_of_volumes); + printf("number_of_masks = %d\n",number_of_masks); + printf("number_of_masked_volumes = %d\n",number_of_masked_volumes); } - } - printf("---------------------------------------------------------------------\n"); - printf("number_of_volumes = %d\n",number_of_volumes); - printf("number_of_masks = %d\n",number_of_masks); - printf("number_of_masked_volumes = %d\n",number_of_masked_volumes); - } - ); // End MPI_MASTER + ); // End MPI_MASTER - // --- Initialization tasks independent of volume stucture ----------------------- + // --- Initialization tasks independent of volume stucture ----------------------- - // Store a pointer to the conditional list and update the current index in that structure - // If no tagging_conditionals were defined between this and the previous master, a dummy is allocated instead - if (global_tagging_conditional_list_master->num_elements == global_tagging_conditional_list_master->current_index + 1) { - tagging_conditional_list = &global_tagging_conditional_list_master->elements[global_tagging_conditional_list_master->current_index++].conditional_list; - free_tagging_conditioanl_list = 0; - } else { - tagging_conditional_list = malloc(sizeof(struct conditional_list_struct)); - tagging_conditional_list->num_elements = 0; - free_tagging_conditioanl_list = 1; - } + // Store a pointer to the conditional list and update the current index in that structure + // If no tagging_conditionals were defined between this and the previous master, a dummy is allocated instead + if (global_tagging_conditional_list_master->num_elements == global_tagging_conditional_list_master->current_index + 1) { + tagging_conditional_list = &global_tagging_conditional_list_master->elements[global_tagging_conditional_list_master->current_index++].conditional_list; + free_tagging_conditioanl_list = 0; + } else { + tagging_conditional_list = malloc(sizeof(struct conditional_list_struct)); + tagging_conditional_list->num_elements = 0; + free_tagging_conditioanl_list = 1; + } - // Find the maximum logger extend index so that the correct memory allocation can be performed later - // Here the loggers applied to all volumes are searched, later this result is compared to volume specific loggers and updated - max_conditional_extend_index = -1; - for (iterator=0;iteratornum_elements;iterator++) { - if (global_all_volume_logger_list_master->elements[iterator].logger->logger_extend_index > max_conditional_extend_index) { - max_conditional_extend_index = global_all_volume_logger_list_master->elements[iterator].logger->logger_extend_index; + // Find the maximum logger extend index so that the correct memory allocation can be performed later + // Here the loggers applied to all volumes are searched, later this result is compared to volume specific loggers and updated + max_conditional_extend_index = -1; + for (iterator=0;iteratornum_elements;iterator++) { + if (global_all_volume_logger_list_master->elements[iterator].logger->logger_extend_index > max_conditional_extend_index) { + max_conditional_extend_index = global_all_volume_logger_list_master->elements[iterator].logger->logger_extend_index; + } } - } - // The absolute rotation of this component is saved for use in initialization - rot_transpose(ROT_A_CURRENT_COMP,master_transposed_rotation_matrix); - - // Preceeding componnets can add coordinates and rotations to global_positions_to_transform and global_rotations_to_transform - // in order to have these transformed into the coordinate system of the next master compoent in the instrument file. - // Here these transformations are performed, and the lists are cleared so no transformed information is further altered by - // next master components. - - // Position transformation - for (iterator=0;iteratornum_elements;iterator++) { - non_rotated_position = coords_sub(*(global_positions_to_transform_list_master->positions[iterator]),POS_A_CURRENT_COMP); - *(global_positions_to_transform_list_master->positions[iterator]) = rot_apply(ROT_A_CURRENT_COMP,non_rotated_position); - } - if (global_positions_to_transform_list_master->num_elements > 0) { - global_positions_to_transform_list_master->num_elements = 0; - free(global_positions_to_transform_list_master->positions); - } - // Rotation transformation - for (iterator=0;iteratornum_elements;iterator++) { - //print_rotation(*(global_rotations_to_transform_list_master->rotations[iterator]),"rotation matrix to be updated"); - rot_mul(master_transposed_rotation_matrix,*(global_rotations_to_transform_list_master->rotations[iterator]),temp_rotation_matrix); - rot_copy(*(global_rotations_to_transform_list_master->rotations[iterator]),temp_rotation_matrix); - } - if (global_rotations_to_transform_list_master->num_elements > 0) { - global_rotations_to_transform_list_master->num_elements = 0; - free(global_rotations_to_transform_list_master->rotations); - } + // The absolute rotation of this component is saved for use in initialization + rot_transpose(ROT_A_CURRENT_COMP,master_transposed_rotation_matrix); + + // Preceeding componnets can add coordinates and rotations to global_positions_to_transform and global_rotations_to_transform + // in order to have these transformed into the coordinate system of the next master compoent in the instrument file. + // Here these transformations are performed, and the lists are cleared so no transformed information is further altered by + // next master components. + + // Position transformation + for (iterator=0;iteratornum_elements;iterator++) { + non_rotated_position = coords_sub(*(global_positions_to_transform_list_master->positions[iterator]),POS_A_CURRENT_COMP); + *(global_positions_to_transform_list_master->positions[iterator]) = rot_apply(ROT_A_CURRENT_COMP,non_rotated_position); + } + if (global_positions_to_transform_list_master->num_elements > 0) { + global_positions_to_transform_list_master->num_elements = 0; + free(global_positions_to_transform_list_master->positions); + } + // Rotation transformation + for (iterator=0;iteratornum_elements;iterator++) { + //print_rotation(*(global_rotations_to_transform_list_master->rotations[iterator]),"rotation matrix to be updated"); + rot_mul(master_transposed_rotation_matrix,*(global_rotations_to_transform_list_master->rotations[iterator]),temp_rotation_matrix); + rot_copy(*(global_rotations_to_transform_list_master->rotations[iterator]),temp_rotation_matrix); + } + if (global_rotations_to_transform_list_master->num_elements > 0) { + global_rotations_to_transform_list_master->num_elements = 0; + free(global_rotations_to_transform_list_master->rotations); + } - // --- Definition of volumes and loading of appropriate data ----------------------- - - // The information stored in global lists is to be stored in one array of structures that is allocated here - Volumes = malloc(number_of_volumes * sizeof(struct Volume_struct*)); - scattered_flag = malloc(number_of_volumes*sizeof(int)); - scattered_flag_VP = (int**) malloc(number_of_volumes * sizeof(int*)); - number_of_processes_array = malloc(number_of_volumes*sizeof(int)); - - // The mcdisplay functions need access to the other geomtries, but can not use the Volumes struct because of order of definition. - // A separate list of pointers to the geometry structures is thus allocated - Geometries = malloc(number_of_volumes * sizeof(struct geometry_struct *)); - - // When activation counter is used to have several copies of one volume, it can become necessary to have soft copies of volumes - // Not all of these will necessarily be allocated or used. - Volume_copies = malloc(number_of_volumes * sizeof(struct Volume_struct *)); - Volume_copies_allocated.num_elements = 0; - - // The central structure is called a "Volume", it describes a region in space with certain scattering processes and absorption cross section - - // --- Volume 0 ------------------------------------------------------------------------------------------------ - // Volume 0 is the vacuum surrounding the experiment (infinite, everywhere) and its properties are hardcoded here - Volumes[0] = malloc(sizeof(struct Volume_struct)); - strcpy(Volumes[0]->name,"Surrounding vacuum"); - // Assign geometry - - // This information is meaningless for volume 0, and is never be acsessed in the logic. - Volumes[0]->geometry.priority_value = 0.0; - Volumes[0]->geometry.center.x = 0; - Volumes[0]->geometry.center.y = 0; - Volumes[0]->geometry.center.z = 0; - strcpy(Volumes[0]->geometry.shape,"vacuum"); - Volumes[0]->geometry.eShape = surroundings; - Volumes[0]->geometry.within_function = &r_within_surroundings; // Always returns 1 - // No physics struct allocated - Volumes[0]->p_physics = NULL; - number_of_processes_array[volume_index] = 0; - - // These are never used for volume 0, but by setting the length to 0 it is automatically skipped in many forloops without the need for an if statement - Volumes[0]->geometry.children.num_elements=0; - Volumes[0]->geometry.direct_children.num_elements=0; - Volumes[0]->geometry.destinations_list.num_elements=0; - Volumes[0]->geometry.reduced_destinations_list.num_elements=0; - - Volumes[0]->geometry.is_exit_volume = 0; - Volumes[0]->geometry.masked_by_list.num_elements = 0; - Volumes[0]->geometry.mask_list.num_elements = 0; - Volumes[0]->geometry.masked_by_mask_index_list.num_elements = 0; - Volumes[0]->geometry.mask_mode=0; - Volumes[0]->geometry.is_mask_volume=0; - Volumes[0]->geometry.is_masked_volume=0; - - // A pointer to the geometry structure - Geometries[0] = &Volumes[0]->geometry; - - // Logging initialization - Volumes[0]->loggers.num_elements = 0; - Volumes[0]->abs_loggers.num_elements = 0; - - - // --- Loop over user defined volumes ------------------------------------------------------------------------ - // Here the user defined volumes are loaded into the volume structure that is used in the ray-tracing - // algorithm. Not all user defined volumes are used, some could be used by a previous master, some - // could be used by the previous master, this one, and perhaps more. This is controlled by the - // activation counter input for geometries, and is here condensed to the active variable. - // Volumes that were used before - - max_number_of_processes = 0; // The maximum number of processes in a volume is assumed 0 and updated during the following loop - - volume_index = 0; - mask_index_main = 0; - for (geometry_list_index=0;geometry_list_indexnum_elements;geometry_list_index++) { - if (global_geometry_list_master->elements[geometry_list_index].active == 1) { // Only include the volume if it is active - volume_index++; - // Connect a volume for each of the geometry.comp instances in the McStas instrument files - if (global_geometry_list_master->elements[geometry_list_index].activation_counter == 0) { - // This is the last time this volume is used, use the hard copy from the geometry component - Volumes[volume_index] = global_geometry_list_master->elements[geometry_list_index].Volume; - } else { - // Since this volume is still needed more than this once, we need to make a shallow copy and use instead + // --- Definition of volumes and loading of appropriate data ----------------------- + + // The information stored in global lists is to be stored in one array of structures that is allocated here + Volumes = malloc(number_of_volumes * sizeof(struct Volume_struct*)); + scattered_flag = malloc(number_of_volumes*sizeof(int)); + scattered_flag_VP = (int**) malloc(number_of_volumes * sizeof(int*)); + number_of_processes_array = malloc(number_of_volumes*sizeof(int)); + + // The mcdisplay functions need access to the other geomtries, but can not use the Volumes struct because of order of definition. + // A separate list of pointers to the geometry structures is thus allocated + Geometries = malloc(number_of_volumes * sizeof(struct geometry_struct *)); + + // When activation counter is used to have several copies of one volume, it can become necessary to have soft copies of volumes + // Not all of these will necessarily be allocated or used. + Volume_copies = malloc(number_of_volumes * sizeof(struct Volume_struct *)); + Volume_copies_allocated.num_elements = 0; + + // The central structure is called a "Volume", it describes a region in space with certain scattering processes and absorption cross section + + // --- Volume 0 ------------------------------------------------------------------------------------------------ + // Volume 0 is the vacuum surrounding the experiment (infinite, everywhere) and its properties are hardcoded here + Volumes[0] = malloc(sizeof(struct Volume_struct)); + strcpy(Volumes[0]->name,"Surrounding vacuum"); + // Assign geometry + + // This information is meaningless for volume 0, and is never be acsessed in the logic. + Volumes[0]->geometry.priority_value = 0.0; + Volumes[0]->geometry.center.x = 0; + Volumes[0]->geometry.center.y = 0; + Volumes[0]->geometry.center.z = 0; + strcpy(Volumes[0]->geometry.shape,"vacuum"); + Volumes[0]->geometry.eShape = surroundings; + Volumes[0]->geometry.within_function = &r_within_surroundings; // Always returns 1 + // No physics struct allocated + Volumes[0]->p_physics = NULL; + number_of_processes_array[volume_index] = 0; + + // These are never used for volume 0, but by setting the length to 0 it is automatically skipped in many forloops without the need for an if statement + Volumes[0]->geometry.children.num_elements=0; + Volumes[0]->geometry.direct_children.num_elements=0; + Volumes[0]->geometry.destinations_list.num_elements=0; + Volumes[0]->geometry.reduced_destinations_list.num_elements=0; + + Volumes[0]->geometry.is_exit_volume = 0; + Volumes[0]->geometry.masked_by_list.num_elements = 0; + Volumes[0]->geometry.mask_list.num_elements = 0; + Volumes[0]->geometry.masked_by_mask_index_list.num_elements = 0; + Volumes[0]->geometry.mask_mode=0; + Volumes[0]->geometry.is_mask_volume=0; + Volumes[0]->geometry.is_masked_volume=0; + + // A pointer to the geometry structure + Geometries[0] = &Volumes[0]->geometry; + + // Logging initialization + Volumes[0]->loggers.num_elements = 0; + Volumes[0]->abs_loggers.num_elements = 0; + + + // --- Loop over user defined volumes ------------------------------------------------------------------------ + // Here the user defined volumes are loaded into the volume structure that is used in the ray-tracing + // algorithm. Not all user defined volumes are used, some could be used by a previous master, some + // could be used by the previous master, this one, and perhaps more. This is controlled by the + // activation counter input for geometries, and is here condensed to the active variable. + // Volumes that were used before + + max_number_of_processes = 0; // The maximum number of processes in a volume is assumed 0 and updated during the following loop + + volume_index = 0; + mask_index_main = 0; + for (geometry_list_index=0;geometry_list_indexnum_elements;geometry_list_index++) { + if (global_geometry_list_master->elements[geometry_list_index].active == 1) { // Only include the volume if it is active + volume_index++; + // Connect a volume for each of the geometry.comp instances in the McStas instrument files + if (global_geometry_list_master->elements[geometry_list_index].activation_counter == 0) { + // This is the last time this volume is used, use the hard copy from the geometry component + Volumes[volume_index] = global_geometry_list_master->elements[geometry_list_index].Volume; + } else { + // Since this volume is still needed more than this once, we need to make a shallow copy and use instead - Volume_copies[volume_index] = malloc(sizeof(struct Volume_struct)); - *(Volume_copies[volume_index]) = *global_geometry_list_master->elements[geometry_list_index].Volume; // Makes shallow copy - Volumes[volume_index] = Volume_copies[volume_index]; - add_element_to_int_list(&Volume_copies_allocated,volume_index); // Keep track of dynamically allocated volumes in order to free them in FINALLY. + Volume_copies[volume_index] = malloc(sizeof(struct Volume_struct)); + *(Volume_copies[volume_index]) = *global_geometry_list_master->elements[geometry_list_index].Volume; // Makes shallow copy + Volumes[volume_index] = Volume_copies[volume_index]; + add_element_to_int_list(&Volume_copies_allocated,volume_index); // Keep track of dynamically allocated volumes in order to free them in FINALLY. - // The geometry storage needs a shallow copy as well (hard copy not necessary for any current geometries), may need changes in future - // A simple copy_geometry_parameters function is added to the geometry in each geometry component - Volumes[volume_index]->geometry.geometry_parameters = Volumes[volume_index]->geometry.copy_geometry_parameters(&global_geometry_list_master->elements[geometry_list_index].Volume->geometry.geometry_parameters); + // The geometry storage needs a shallow copy as well (hard copy not necessary for any current geometries), may need changes in future + // A simple copy_geometry_parameters function is added to the geometry in each geometry component + Volumes[volume_index]->geometry.geometry_parameters = Volumes[volume_index]->geometry.copy_geometry_parameters(&global_geometry_list_master->elements[geometry_list_index].Volume->geometry.geometry_parameters); - // Copy focusing data too, it will be modified based on this master components rotation, so should not be reused - copy_focus_data_array(&global_geometry_list_master->elements[geometry_list_index].Volume->geometry.focus_data_array, - &Volumes[volume_index]->geometry.focus_data_array); + // Copy focusing data too, it will be modified based on this master components rotation, so should not be reused + copy_focus_data_array(&global_geometry_list_master->elements[geometry_list_index].Volume->geometry.focus_data_array, + &Volumes[volume_index]->geometry.focus_data_array); - } + } - // This section identifies the different non isotropic processes in the current volume and give them appropriate transformation matrices - // Identify the number of non isotropic processes in a material (this code can be safely executed for the same material many times) - // A setting of -1 means no transformation necessary, other settings are assigned a unique identifier instead - non_isotropic_found = 0; - for (iterator=0;iteratorp_physics->number_of_processes;iterator++) { - if (Volumes[volume_index]->p_physics->p_scattering_array[iterator].non_isotropic_rot_index != -1) { - Volumes[volume_index]->p_physics->p_scattering_array[iterator].non_isotropic_rot_index = non_isotropic_found; - non_isotropic_found++; - } - } + // This section identifies the different non isotropic processes in the current volume and give them appropriate transformation matrices + // Identify the number of non isotropic processes in a material (this code can be safely executed for the same material many times) + // A setting of -1 means no transformation necessary, other settings are assigned a unique identifier instead + non_isotropic_found = 0; + for (iterator=0;iteratorp_physics->number_of_processes;iterator++) { + if (Volumes[volume_index]->p_physics->p_scattering_array[iterator].non_isotropic_rot_index != -1) { + Volumes[volume_index]->p_physics->p_scattering_array[iterator].non_isotropic_rot_index = non_isotropic_found; + non_isotropic_found++; + } + } - // Update focusing absolute_rotation before running through processes, then this will be the baseline for nonisotropic processes - //rot_copy(Volumes[volume_index]->geometry.focus_data_array.elements[0].absolute_rotation, ROT_A_CURRENT_COMP); + // Update focusing absolute_rotation before running through processes, then this will be the baseline for nonisotropic processes + //rot_copy(Volumes[volume_index]->geometry.focus_data_array.elements[0].absolute_rotation, ROT_A_CURRENT_COMP); - Volumes[volume_index]->geometry.focus_array_indices.num_elements=0; - // For the non_isotropic volumes found, rotation matrices need to be allocated and calculated - if (non_isotropic_found > 0) { - // Allocation of rotation and transpose rotation matrices - if (Volumes[volume_index]->geometry.process_rot_allocated == 0) { - Volumes[volume_index]->geometry.process_rot_matrix_array = malloc(non_isotropic_found * sizeof(Rotation)); - Volumes[volume_index]->geometry.transpose_process_rot_matrix_array = malloc(non_isotropic_found * sizeof(Rotation)); - Volumes[volume_index]->geometry.process_rot_allocated = 1; - } + Volumes[volume_index]->geometry.focus_array_indices.num_elements=0; + // For the non_isotropic volumes found, rotation matrices need to be allocated and calculated + if (non_isotropic_found > 0) { + // Allocation of rotation and transpose rotation matrices + if (Volumes[volume_index]->geometry.process_rot_allocated == 0) { + Volumes[volume_index]->geometry.process_rot_matrix_array = malloc(non_isotropic_found * sizeof(Rotation)); + Volumes[volume_index]->geometry.transpose_process_rot_matrix_array = malloc(non_isotropic_found * sizeof(Rotation)); + Volumes[volume_index]->geometry.process_rot_allocated = 1; + } - // Calculation of the appropriate rotation matrices for transformation between Union_master and the process in a given volume. - non_isotropic_found = 0; - for (iterator=0;iteratorp_physics->number_of_processes;iterator++) { - if (Volumes[volume_index]->p_physics->p_scattering_array[iterator].non_isotropic_rot_index != -1) { - // Transformation for each process / geometry combination + // Calculation of the appropriate rotation matrices for transformation between Union_master and the process in a given volume. + non_isotropic_found = 0; + for (iterator=0;iteratorp_physics->number_of_processes;iterator++) { + if (Volumes[volume_index]->p_physics->p_scattering_array[iterator].non_isotropic_rot_index != -1) { + // Transformation for each process / geometry combination - // The focus vector is given in relation to the geometry and needs to be transformed to the process - // Work on temporary_focus_data_element which is added to the focus_data_array_at the end - temporary_focus_data = Volumes[volume_index]->geometry.focus_data_array.elements[0]; + // The focus vector is given in relation to the geometry and needs to be transformed to the process + // Work on temporary_focus_data_element which is added to the focus_data_array_at the end + temporary_focus_data = Volumes[volume_index]->geometry.focus_data_array.elements[0]; - // Correct for process rotation - // Aim - temporary_focus_data.Aim = rot_apply(Volumes[volume_index]->p_physics->p_scattering_array[iterator].rotation_matrix,temporary_focus_data.Aim); + // Correct for process rotation + // Aim + temporary_focus_data.Aim = rot_apply(Volumes[volume_index]->p_physics->p_scattering_array[iterator].rotation_matrix,temporary_focus_data.Aim); - // Absolute rotation of focus_data needs to updated using the rotation matrix from this process (before it is combined with the rotation matrix of the geometry) - rot_mul(Volumes[volume_index]->p_physics->p_scattering_array[iterator].rotation_matrix, temporary_focus_data.absolute_rotation, temp_rotation_matrix); - rot_copy(temporary_focus_data.absolute_rotation, temp_rotation_matrix); + // Absolute rotation of focus_data needs to updated using the rotation matrix from this process (before it is combined with the rotation matrix of the geometry) + rot_mul(Volumes[volume_index]->p_physics->p_scattering_array[iterator].rotation_matrix, temporary_focus_data.absolute_rotation, temp_rotation_matrix); + rot_copy(temporary_focus_data.absolute_rotation, temp_rotation_matrix); - // Add element to focus_array_indices - // focus_array_indices refers to the correct element in focus_data_array for this volume/process combination - // focus_data_array[0] is the isotropic version in all cases, so the first non_isotropic goes to focus_data_array[1] - // and so forth. When a process is isotropic, this array is appended with a zero. - // The focus_array_indices maps process numbers to the correct focus_data_array index. - add_element_to_int_list(&Volumes[volume_index]->geometry.focus_array_indices, non_isotropic_found+1); + // Add element to focus_array_indices + // focus_array_indices refers to the correct element in focus_data_array for this volume/process combination + // focus_data_array[0] is the isotropic version in all cases, so the first non_isotropic goes to focus_data_array[1] + // and so forth. When a process is isotropic, this array is appended with a zero. + // The focus_array_indices maps process numbers to the correct focus_data_array index. + add_element_to_int_list(&Volumes[volume_index]->geometry.focus_array_indices, non_isotropic_found+1); - // Add the new focus_data element to this volumes focus_data_array. - add_element_to_focus_data_array(&Volumes[volume_index]->geometry.focus_data_array, temporary_focus_data); + // Add the new focus_data element to this volumes focus_data_array. + add_element_to_focus_data_array(&Volumes[volume_index]->geometry.focus_data_array, temporary_focus_data); - // Quick error check to see the length is correct which indirectly confirms the indices are correct - if (Volumes[volume_index]->geometry.focus_data_array.num_elements != non_isotropic_found + 2) { - printf("ERROR, focus_data_array length for volume %s inconsistent with number of non isotropic processes found!\n",Volumes[volume_index]->name); - exit(1); - } + // Quick error check to see the length is correct which indirectly confirms the indices are correct + if (Volumes[volume_index]->geometry.focus_data_array.num_elements != non_isotropic_found + 2) { + printf("ERROR, focus_data_array length for volume %s inconsistent with number of non isotropic processes found!\n",Volumes[volume_index]->name); + exit(1); + } - // Create rotation matrix for this specific volume / process combination to transform from master coordinate system to the non-isotropics process coordinate system - // This is done by multipling the transpose master component roration matrix, the volume rotation, and then the process rotation matrix onto the velocity / wavevector - rot_mul(Volumes[volume_index]->geometry.rotation_matrix,master_transposed_rotation_matrix,temp_rotation_matrix); - rot_mul(Volumes[volume_index]->p_physics->p_scattering_array[iterator].rotation_matrix,temp_rotation_matrix,Volumes[volume_index]->geometry.process_rot_matrix_array[non_isotropic_found]); + // Create rotation matrix for this specific volume / process combination to transform from master coordinate system to the non-isotropics process coordinate system + // This is done by multipling the transpose master component roration matrix, the volume rotation, and then the process rotation matrix onto the velocity / wavevector + rot_mul(Volumes[volume_index]->geometry.rotation_matrix,master_transposed_rotation_matrix,temp_rotation_matrix); + rot_mul(Volumes[volume_index]->p_physics->p_scattering_array[iterator].rotation_matrix,temp_rotation_matrix,Volumes[volume_index]->geometry.process_rot_matrix_array[non_isotropic_found]); - // Need to transpose as well to transform back to the master coordinate system - rot_transpose(Volumes[volume_index]->geometry.process_rot_matrix_array[non_isotropic_found],Volumes[volume_index]->geometry.transpose_process_rot_matrix_array[non_isotropic_found]); + // Need to transpose as well to transform back to the master coordinate system + rot_transpose(Volumes[volume_index]->geometry.process_rot_matrix_array[non_isotropic_found],Volumes[volume_index]->geometry.transpose_process_rot_matrix_array[non_isotropic_found]); - // Debug print - //print_rotation(Volumes[volume_index]->geometry.process_rot_matrix_array[non_isotropic_found],"Process rotation matrix"); - //print_rotation(Volumes[volume_index]->geometry.transpose_process_rot_matrix_array[non_isotropic_found],"Transpose process rotation matrix"); + // Debug print + //print_rotation(Volumes[volume_index]->geometry.process_rot_matrix_array[non_isotropic_found],"Process rotation matrix"); + //print_rotation(Volumes[volume_index]->geometry.transpose_process_rot_matrix_array[non_isotropic_found],"Transpose process rotation matrix"); - non_isotropic_found++; - } else { - // This process can use the standard isotropic focus_data_array which is indexed zero. - add_element_to_int_list(&Volumes[volume_index]->geometry.focus_array_indices,0); - } - } - } else { - // No non isotropic volumes found, focus_array_indices should just be a list of 0's of same length as the number of processes. - // In this way all processes use the isotropic focus_data structure - Volumes[volume_index]->geometry.focus_array_indices.elements = malloc(Volumes[volume_index]->p_physics->number_of_processes * sizeof(int)); - for (iterator=0;iteratorp_physics->number_of_processes;iterator++) - Volumes[volume_index]->geometry.focus_array_indices.elements[iterator] = 0; + non_isotropic_found++; + } else { + // This process can use the standard isotropic focus_data_array which is indexed zero. + add_element_to_int_list(&Volumes[volume_index]->geometry.focus_array_indices,0); + } + } + } else { + // No non isotropic volumes found, focus_array_indices should just be a list of 0's of same length as the number of processes. + // In this way all processes use the isotropic focus_data structure + Volumes[volume_index]->geometry.focus_array_indices.elements = malloc(Volumes[volume_index]->p_physics->number_of_processes * sizeof(int)); + for (iterator=0;iteratorp_physics->number_of_processes;iterator++) + Volumes[volume_index]->geometry.focus_array_indices.elements[iterator] = 0; - } + } - rot_copy(Volumes[volume_index]->geometry.focus_data_array.elements[0].absolute_rotation, ROT_A_CURRENT_COMP); + rot_copy(Volumes[volume_index]->geometry.focus_data_array.elements[0].absolute_rotation, ROT_A_CURRENT_COMP); - // This component works in its local coordinate system, and thus all information from the input components should be transformed to its coordinate system. - // All the input components saved their absolute rotation/position into their Volume structure, and the absolute rotation of the current component is known. - // The next section finds the relative rotation and translation of all the volumes and the master component. + // This component works in its local coordinate system, and thus all information from the input components should be transformed to its coordinate system. + // All the input components saved their absolute rotation/position into their Volume structure, and the absolute rotation of the current component is known. + // The next section finds the relative rotation and translation of all the volumes and the master component. - // Transform the rotation matrices for each volume - rot_mul(ROT_A_CURRENT_COMP,Volumes[volume_index]->geometry.transpose_rotation_matrix,temp_rotation_matrix); - // Copy the result back to the volumes structure - rot_copy(Volumes[volume_index]->geometry.rotation_matrix,temp_rotation_matrix); - // Now update the transpose as well - rot_transpose(Volumes[volume_index]->geometry.rotation_matrix,temp_rotation_matrix); - rot_copy(Volumes[volume_index]->geometry.transpose_rotation_matrix,temp_rotation_matrix); + // Transform the rotation matrices for each volume + rot_mul(ROT_A_CURRENT_COMP,Volumes[volume_index]->geometry.transpose_rotation_matrix,temp_rotation_matrix); + // Copy the result back to the volumes structure + rot_copy(Volumes[volume_index]->geometry.rotation_matrix,temp_rotation_matrix); + // Now update the transpose as well + rot_transpose(Volumes[volume_index]->geometry.rotation_matrix,temp_rotation_matrix); + rot_copy(Volumes[volume_index]->geometry.transpose_rotation_matrix,temp_rotation_matrix); - // Transform the position for each volume - non_rotated_position.x = Volumes[volume_index]->geometry.center.x - POS_A_CURRENT_COMP.x; - non_rotated_position.y = Volumes[volume_index]->geometry.center.y - POS_A_CURRENT_COMP.y; - non_rotated_position.z = Volumes[volume_index]->geometry.center.z - POS_A_CURRENT_COMP.z; + // Transform the position for each volume + non_rotated_position.x = Volumes[volume_index]->geometry.center.x - POS_A_CURRENT_COMP.x; + non_rotated_position.y = Volumes[volume_index]->geometry.center.y - POS_A_CURRENT_COMP.y; + non_rotated_position.z = Volumes[volume_index]->geometry.center.z - POS_A_CURRENT_COMP.z; - rot_transpose(ROT_A_CURRENT_COMP,temp_rotation_matrix); // REVIEW LINE - rotated_position = rot_apply(ROT_A_CURRENT_COMP, non_rotated_position); + rot_transpose(ROT_A_CURRENT_COMP,temp_rotation_matrix); // REVIEW LINE + rotated_position = rot_apply(ROT_A_CURRENT_COMP, non_rotated_position); - Volumes[volume_index]->geometry.center.x = rotated_position.x; - Volumes[volume_index]->geometry.center.y = rotated_position.y; - Volumes[volume_index]->geometry.center.z = rotated_position.z; + Volumes[volume_index]->geometry.center.x = rotated_position.x; + Volumes[volume_index]->geometry.center.y = rotated_position.y; + Volumes[volume_index]->geometry.center.z = rotated_position.z; - // Use same rotation on the aim vector of the isotropic focus_data element - Volumes[volume_index]->geometry.focus_data_array.elements[0].Aim = rot_apply(Volumes[volume_index]->geometry.rotation_matrix, Volumes[volume_index]->geometry.focus_data_array.elements[0].Aim); + // Use same rotation on the aim vector of the isotropic focus_data element + Volumes[volume_index]->geometry.focus_data_array.elements[0].Aim = rot_apply(Volumes[volume_index]->geometry.rotation_matrix, Volumes[volume_index]->geometry.focus_data_array.elements[0].Aim); - // To allocate enough memory to hold information on all processes, the maximum of these is updated if this volume has more - if (Volumes[volume_index]->p_physics->number_of_processes > max_number_of_processes) - max_number_of_processes = Volumes[volume_index]->p_physics->number_of_processes; + // To allocate enough memory to hold information on all processes, the maximum of these is updated if this volume has more + if (Volumes[volume_index]->p_physics->number_of_processes > max_number_of_processes) + max_number_of_processes = Volumes[volume_index]->p_physics->number_of_processes; - // Allocate memory to scattered_flag_VP (holds statistics for scatterings in each process of the volume) - scattered_flag_VP[volume_index] = malloc(Volumes[volume_index]->p_physics->number_of_processes * sizeof(int)); - number_of_processes_array[volume_index] = Volumes[volume_index]->p_physics->number_of_processes; + // Allocate memory to scattered_flag_VP (holds statistics for scatterings in each process of the volume) + scattered_flag_VP[volume_index] = malloc(Volumes[volume_index]->p_physics->number_of_processes * sizeof(int)); + number_of_processes_array[volume_index] = Volumes[volume_index]->p_physics->number_of_processes; - // Normalizing and error checking process interact fraction - number_of_process_interacts_set = 0; total_process_interact=0; - for (process_index=0;process_indexp_physics->number_of_processes;process_index++) { - if (Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact != -1) { - number_of_process_interacts_set++; - total_process_interact += Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact; - } else { - index_of_lacking_process = process_index; - } - } + // Normalizing and error checking process interact fraction + number_of_process_interacts_set = 0; total_process_interact=0; + for (process_index=0;process_indexp_physics->number_of_processes;process_index++) { + if (Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact != -1) { + number_of_process_interacts_set++; + total_process_interact += Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact; + } else { + index_of_lacking_process = process_index; + } + } - if (number_of_process_interacts_set == 0) Volumes[volume_index]->p_physics->interact_control = 0; - else Volumes[volume_index]->p_physics->interact_control = 1; + if (number_of_process_interacts_set == 0) Volumes[volume_index]->p_physics->interact_control = 0; + else Volumes[volume_index]->p_physics->interact_control = 1; - // If all are set, check if they need renormalization so that the sum is one. - if (number_of_process_interacts_set == Volumes[volume_index]->p_physics->number_of_processes) { - if (total_process_interact > 1.001 || total_process_interact < 0.999) { - for (process_index=0;process_indexp_physics->number_of_processes;process_index++) { - Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact = Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact/total_process_interact; - } - } - } else if ( number_of_process_interacts_set != 0) { - if (number_of_process_interacts_set == Volumes[volume_index]->p_physics->number_of_processes - 1) {// If all but one is set, it is an easy fix - Volumes[volume_index]->p_physics->p_scattering_array[index_of_lacking_process].process_p_interact = 1 - total_process_interact; - if (total_process_interact >= 1) { - printf("ERROR, material %s has a total interact_fraction above 1 and a process without an interact_fraction. Either set all so they can be renormalized, or have a sum below 1, so that the last can have 1 - sum.\n",Volumes[volume_index]->p_physics->name); - exit(1); - } - } else { - printf("ERROR, material %s needs to have all, all minus one or none of its processes with an interact_fraction \n",Volumes[volume_index]->p_physics->name); - exit(1); - } - } + // If all are set, check if they need renormalization so that the sum is one. + if (number_of_process_interacts_set == Volumes[volume_index]->p_physics->number_of_processes) { + if (total_process_interact > 1.001 || total_process_interact < 0.999) { + for (process_index=0;process_indexp_physics->number_of_processes;process_index++) { + Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact = Volumes[volume_index]->p_physics->p_scattering_array[process_index].process_p_interact/total_process_interact; + } + } + } else if ( number_of_process_interacts_set != 0) { + if (number_of_process_interacts_set == Volumes[volume_index]->p_physics->number_of_processes - 1) {// If all but one is set, it is an easy fix + Volumes[volume_index]->p_physics->p_scattering_array[index_of_lacking_process].process_p_interact = 1 - total_process_interact; + if (total_process_interact >= 1) { + printf("ERROR, material %s has a total interact_fraction above 1 and a process without an interact_fraction. Either set all so they can be renormalized, or have a sum below 1, so that the last can have 1 - sum.\n",Volumes[volume_index]->p_physics->name); + exit(1); + } + } else { + printf("ERROR, material %s needs to have all, all minus one or none of its processes with an interact_fraction \n",Volumes[volume_index]->p_physics->name); + exit(1); + } + } - // Some initialization can only happen after the rotation matrix relative to the master is known - // Such initialization is placed in the geometry component, and executed here through a function pointer - Volumes[volume_index]->geometry.initialize_from_main_function(&Volumes[volume_index]->geometry); + // Some initialization can only happen after the rotation matrix relative to the master is known + // Such initialization is placed in the geometry component, and executed here through a function pointer + Volumes[volume_index]->geometry.initialize_from_main_function(&Volumes[volume_index]->geometry); - // Add pointer to geometry to Geometries - Geometries[volume_index] = &Volumes[volume_index]->geometry; + // Add pointer to geometry to Geometries + Geometries[volume_index] = &Volumes[volume_index]->geometry; - // Initialize mask intersect list - Volumes[volume_index]->geometry.mask_intersect_list.num_elements = 0; + // Initialize mask intersect list + Volumes[volume_index]->geometry.mask_intersect_list.num_elements = 0; - // Here the mask_list and masked_by_list for the volume is updated from component index values to volume indexes - for (iterator=0;iteratorgeometry.mask_list.num_elements;iterator++) - Volumes[volume_index]->geometry.mask_list.elements[iterator] = find_on_int_list(geometry_component_index_list,Volumes[volume_index]->geometry.mask_list.elements[iterator]); + // Here the mask_list and masked_by_list for the volume is updated from component index values to volume indexes + for (iterator=0;iteratorgeometry.mask_list.num_elements;iterator++) + Volumes[volume_index]->geometry.mask_list.elements[iterator] = find_on_int_list(geometry_component_index_list,Volumes[volume_index]->geometry.mask_list.elements[iterator]); - for (iterator=0;iteratorgeometry.masked_by_list.num_elements;iterator++) - Volumes[volume_index]->geometry.masked_by_list.elements[iterator] = find_on_int_list(geometry_component_index_list,Volumes[volume_index]->geometry.masked_by_list.elements[iterator]); + for (iterator=0;iteratorgeometry.masked_by_list.num_elements;iterator++) + Volumes[volume_index]->geometry.masked_by_list.elements[iterator] = find_on_int_list(geometry_component_index_list,Volumes[volume_index]->geometry.masked_by_list.elements[iterator]); - // If the volume is a mask, its volume number is added to the mask_volume_index list so volume index can be converted to mask_index. - if (Volumes[volume_index]->geometry.is_mask_volume == 1) Volumes[volume_index]->geometry.mask_index = mask_index_main; - if (Volumes[volume_index]->geometry.is_mask_volume == 1) mask_volume_index_list.elements[mask_index_main++] = volume_index; + // If the volume is a mask, its volume number is added to the mask_volume_index list so volume index can be converted to mask_index. + if (Volumes[volume_index]->geometry.is_mask_volume == 1) Volumes[volume_index]->geometry.mask_index = mask_index_main; + if (Volumes[volume_index]->geometry.is_mask_volume == 1) mask_volume_index_list.elements[mask_index_main++] = volume_index; - // Check all loggers assosiated with this volume and update the max_conditional_extend_index if necessary - for (iterator=0;iteratorloggers.num_elements;iterator++) { - for (process_index=0;process_indexloggers.p_logger_volume[iterator].num_elements;process_index++) { - if (Volumes[volume_index]->loggers.p_logger_volume[iterator].p_logger_process[process_index] != NULL) { - if (Volumes[volume_index]->loggers.p_logger_volume[iterator].p_logger_process[process_index]->logger_extend_index > max_conditional_extend_index) - max_conditional_extend_index = Volumes[volume_index]->loggers.p_logger_volume[iterator].p_logger_process[process_index]->logger_extend_index; - } - } - } + // Check all loggers assosiated with this volume and update the max_conditional_extend_index if necessary + for (iterator=0;iteratorloggers.num_elements;iterator++) { + for (process_index=0;process_indexloggers.p_logger_volume[iterator].num_elements;process_index++) { + if (Volumes[volume_index]->loggers.p_logger_volume[iterator].p_logger_process[process_index] != NULL) { + if (Volumes[volume_index]->loggers.p_logger_volume[iterator].p_logger_process[process_index]->logger_extend_index > max_conditional_extend_index) + max_conditional_extend_index = Volumes[volume_index]->loggers.p_logger_volume[iterator].p_logger_process[process_index]->logger_extend_index; + } + } + } - // Find longest surface length - int surfaces_in_this_stack; - for (iterator=0;iteratorgeometry.number_of_faces;iterator++) { - surfaces_in_this_stack = Volumes[volume_index]->geometry.surface_stack_for_each_face[iterator]->number_of_surfaces; - if (surfaces_in_this_stack > longest_surface_stack) { - longest_surface_stack = surfaces_in_this_stack; - } - } + // Find longest surface length + int surfaces_in_this_stack; + for (iterator=0;iteratorgeometry.number_of_faces;iterator++) { + surfaces_in_this_stack = Volumes[volume_index]->geometry.surface_stack_for_each_face[iterator]->number_of_surfaces; + if (surfaces_in_this_stack > longest_surface_stack) { + longest_surface_stack = surfaces_in_this_stack; + } + } - } - } // Initialization for each volume done + } + } // Initialization for each volume done - // ------- Initialization of ray-tracing algorithm ------------------------------------ + // ------- Initialization of ray-tracing algorithm ------------------------------------ - my_trace = malloc(max_number_of_processes*sizeof(double)); - my_trace_fraction_control = malloc(max_number_of_processes*sizeof(double)); + my_trace = malloc(max_number_of_processes*sizeof(double)); + my_trace_fraction_control = malloc(max_number_of_processes*sizeof(double)); - // All geometries can have 2 intersections currently, when this changes the maximum number of solutions need to be reported to the Union_master. - number_of_solutions = &number_of_solutions_static; - component_error_msg = 0; + // All geometries can have 2 intersections currently, when this changes the maximum number of solutions need to be reported to the Union_master. + number_of_solutions = &number_of_solutions_static; + component_error_msg = 0; - // Pre allocated memory for destination list search - pre_allocated1 = malloc(number_of_volumes * sizeof(int)); - pre_allocated2 = malloc(number_of_volumes * sizeof(int)); - pre_allocated3 = malloc(number_of_volumes * sizeof(int)); + // Pre allocated memory for destination list search + pre_allocated1 = malloc(number_of_volumes * sizeof(int)); + pre_allocated2 = malloc(number_of_volumes * sizeof(int)); + pre_allocated3 = malloc(number_of_volumes * sizeof(int)); - // Pre allocated memory to fit all surfaces in an interface - interface_stack.number_of_surfaces = 2*longest_surface_stack; - interface_stack.p_surface_array = malloc(interface_stack.number_of_surfaces*sizeof(struct surface_process_struct*)); + // Pre allocated memory to fit all surfaces in an interface + interface_stack.number_of_surfaces = 2*longest_surface_stack; + interface_stack.p_surface_array = malloc(interface_stack.number_of_surfaces*sizeof(struct surface_process_struct*)); - // Allocate memory for logger_conditional_extend_array used in the extend section of the master component, if it is needed. - if (max_conditional_extend_index > -1) { - logger_conditional_extend_array = malloc((max_conditional_extend_index + 1)*sizeof(int)); - } + // Allocate memory for logger_conditional_extend_array used in the extend section of the master component, if it is needed. + if (max_conditional_extend_index > -1) { + logger_conditional_extend_array = malloc((max_conditional_extend_index + 1)*sizeof(int)); + } - // In this function different lists of volume indecies are generated. They are the key to the speed of the component and central for the logic. - // They use simple set algebra to generate these lists for each volume: - // Children list for volume n: Indicies of volumes that are entirely within the set described by volume n - // Overlap list for volume n: Indicies of volume that contains some of the set described by volume n (excluding volume n) - // Intersect check list for volume n: Indicies of volumes to check for intersection if a ray originates from volume n (is generated from the children and overlap lists) - // Parents list for volume n: Indicies of volumes that contain the entire set of volume n - // Grandparents lists for volume n: Indicies of volumes that contain the entire set of at least one parent of volume n - // Destination list for volume n: Indicies of volumes that could be the destination volume when a ray leaves volume n - // The overlap, parents and grandparents lists are local variables in the function, and not in the main scope. - - generate_lists(Volumes, &starting_lists, number_of_volumes, list_verbal); - - // Generate "safe starting list", which contains all volumes that the ray may enter from other components - // These are all volumes without scattering or absorption - - // Updating mask lists from volume index to global_mask_indices - // Filling out the masked_by list that uses mask indices - for (volume_index=0;volume_indexgeometry.masked_by_mask_index_list.num_elements = Volumes[volume_index]->geometry.masked_by_list.num_elements; - Volumes[volume_index]->geometry.masked_by_mask_index_list.elements = malloc(Volumes[volume_index]->geometry.masked_by_mask_index_list.num_elements * sizeof(int)); - for (iterator=0;iteratorgeometry.masked_by_list.num_elements;iterator++) - Volumes[volume_index]->geometry.masked_by_mask_index_list.elements[iterator] = find_on_int_list(mask_volume_index_list,Volumes[volume_index]->geometry.masked_by_list.elements[iterator]); - } + // In this function different lists of volume indecies are generated. They are the key to the speed of the component and central for the logic. + // They use simple set algebra to generate these lists for each volume: + // Children list for volume n: Indicies of volumes that are entirely within the set described by volume n + // Overlap list for volume n: Indicies of volume that contains some of the set described by volume n (excluding volume n) + // Intersect check list for volume n: Indicies of volumes to check for intersection if a ray originates from volume n (is generated from the children and overlap lists) + // Parents list for volume n: Indicies of volumes that contain the entire set of volume n + // Grandparents lists for volume n: Indicies of volumes that contain the entire set of at least one parent of volume n + // Destination list for volume n: Indicies of volumes that could be the destination volume when a ray leaves volume n + // The overlap, parents and grandparents lists are local variables in the function, and not in the main scope. + + generate_lists(Volumes, &starting_lists, number_of_volumes, list_verbal); + + // Generate "safe starting list", which contains all volumes that the ray may enter from other components + // These are all volumes without scattering or absorption + + // Updating mask lists from volume index to global_mask_indices + // Filling out the masked_by list that uses mask indices + for (volume_index=0;volume_indexgeometry.masked_by_mask_index_list.num_elements = Volumes[volume_index]->geometry.masked_by_list.num_elements; + Volumes[volume_index]->geometry.masked_by_mask_index_list.elements = malloc(Volumes[volume_index]->geometry.masked_by_mask_index_list.num_elements * sizeof(int)); + for (iterator=0;iteratorgeometry.masked_by_list.num_elements;iterator++) + Volumes[volume_index]->geometry.masked_by_mask_index_list.elements[iterator] = find_on_int_list(mask_volume_index_list,Volumes[volume_index]->geometry.masked_by_list.elements[iterator]); + } - int volume_index_main; + int volume_index_main; - // Checking for equal priorities in order to alert the user to a potential input error - for (volume_index_main=0;volume_index_maingeometry.priority_value == Volumes[volume_index]->geometry.priority_value && volume_index_main != volume_index) { + // Checking for equal priorities in order to alert the user to a potential input error + for (volume_index_main=0;volume_index_maingeometry.priority_value == Volumes[volume_index]->geometry.priority_value && volume_index_main != volume_index) { if (Volumes[volume_index_main]->geometry.is_mask_volume == 0 && Volumes[volume_index]->geometry.is_mask_volume == 0) { - // Priority of masks do not matter - printf("ERROR in Union_master with name %s. The volumes named %s and %s have the same priority. Change the priorities so the one present in case of overlap has highest priority.\n",NAME_CURRENT_COMP,Volumes[volume_index_main]->name,Volumes[volume_index]->name); - exit(1); + // Priority of masks do not matter + printf("ERROR in Union_master with name %s. The volumes named %s and %s have the same priority. Change the priorities so the one present in case of overlap has highest priority.\n",NAME_CURRENT_COMP,Volumes[volume_index_main]->name,Volumes[volume_index]->name); + exit(1); } } - } + } - // Printing the generated lists for all volumes. - MPI_MASTER( - if (verbal) printf("\n ---- Overview of the lists generated for each volume ---- \n"); + // Printing the generated lists for all volumes. + MPI_MASTER( + if (verbal) printf("\n ---- Overview of the lists generated for each volume ---- \n"); - if (verbal) printf("List overview for surrounding vacuum\n"); - for (volume_index_main=0;volume_index_maingeometry.is_mask_volume == 0 || - Volumes[volume_index_main]->geometry.is_masked_volume == 0 || - Volumes[volume_index_main]->geometry.is_exit_volume == 0) { - printf("List overview for %s with %s shape made of %s\n", - Volumes[volume_index_main]->name, - Volumes[volume_index_main]->geometry.shape, - Volumes[volume_index_main]->p_physics->name); - } else { - printf("List overview for %s with shape %s\n", - Volumes[volume_index_main]->name, - Volumes[volume_index_main]->geometry.shape); - } - } - } + if (verbal) { + if (volume_index_main != 0) { + if (Volumes[volume_index_main]->geometry.is_mask_volume == 0 || + Volumes[volume_index_main]->geometry.is_masked_volume == 0 || + Volumes[volume_index_main]->geometry.is_exit_volume == 0) { + printf("List overview for %s with %s shape made of %s\n", + Volumes[volume_index_main]->name, + Volumes[volume_index_main]->geometry.shape, + Volumes[volume_index_main]->p_physics->name); + } else { + printf("List overview for %s with shape %s\n", + Volumes[volume_index_main]->name, + Volumes[volume_index_main]->geometry.shape); + } + } + } - if (verbal) sprintf(string_output,"Children for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.children,string_output); + if (verbal) sprintf(string_output,"Children for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.children,string_output); - if (verbal) sprintf(string_output,"Direct_children for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.direct_children,string_output); + if (verbal) sprintf(string_output,"Direct_children for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.direct_children,string_output); - if (verbal) sprintf(string_output,"Intersect_check_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.intersect_check_list,string_output); + if (verbal) sprintf(string_output,"Intersect_check_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.intersect_check_list,string_output); - if (verbal) sprintf(string_output,"Mask_intersect_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_intersect_list,string_output); + if (verbal) sprintf(string_output,"Mask_intersect_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_intersect_list,string_output); - if (verbal) sprintf(string_output,"Destinations_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.destinations_list,string_output); + if (verbal) sprintf(string_output,"Destinations_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.destinations_list,string_output); - //if (verbal) sprintf(string_output,"Destinations_logic_list for Volume %d",volume_index_main); - //if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.destinations_logic_list,string_output); + //if (verbal) sprintf(string_output,"Destinations_logic_list for Volume %d",volume_index_main); + //if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.destinations_logic_list,string_output); - if (verbal) sprintf(string_output,"Reduced_destinations_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.reduced_destinations_list,string_output); + if (verbal) sprintf(string_output,"Reduced_destinations_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.reduced_destinations_list,string_output); - if (verbal) sprintf(string_output,"Next_volume_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.next_volume_list,string_output); + if (verbal) sprintf(string_output,"Next_volume_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.next_volume_list,string_output); - if (verbal) { - if (volume_index_main != 0) - printf(" Is_vacuum for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->p_physics->is_vacuum); - } - if (verbal) { - if (volume_index_main != 0) - printf(" is_mask_volume for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.is_mask_volume); - } - if (verbal) { - if (volume_index_main != 0) - printf(" is_masked_volume for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.is_masked_volume); - } - if (verbal) { - if (volume_index_main != 0) - printf(" is_exit_volume for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.is_exit_volume); - } + if (verbal) { + if (volume_index_main != 0) + printf(" Is_vacuum for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->p_physics->is_vacuum); + } + if (verbal) { + if (volume_index_main != 0) + printf(" is_mask_volume for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.is_mask_volume); + } + if (verbal) { + if (volume_index_main != 0) + printf(" is_masked_volume for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.is_masked_volume); + } + if (verbal) { + if (volume_index_main != 0) + printf(" is_exit_volume for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.is_exit_volume); + } - if (verbal) sprintf(string_output,"mask_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_list,string_output); + if (verbal) sprintf(string_output,"mask_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_list,string_output); - if (verbal) sprintf(string_output,"masked_by_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_list,string_output); + if (verbal) sprintf(string_output,"masked_by_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_list,string_output); - if (verbal) sprintf(string_output,"masked_by_mask_index_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_mask_index_list,string_output); + if (verbal) sprintf(string_output,"masked_by_mask_index_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_mask_index_list,string_output); - if (verbal) printf(" mask_mode for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.mask_mode); - if (verbal) printf("\n"); - } - ) // End of MPI_MASTER - - - // Initializing intersection_time_table - // The intersection time table contains all information on intersection times for the current position/direction, and is cleared everytime a ray changes direction. - // Not all entries needs to be calculated, so there is a variable that keeps track of which intersection times have been calculated in order to avoid redoing that. - // When the intersections times are calculated for a volume, all future intersections are kept in the time table. - // Thus the memory allocation have to take into account how many intersections there can be with each volume, but it is currently set to 2, but can easily be changed. This may need to be reported by individual geometry components in the future. - - intersection_time_table.num_volumes = number_of_volumes; - - intersection_time_table.n_elements = (int*) malloc(intersection_time_table.num_volumes * sizeof(int)); - intersection_time_table.calculated = (int*) malloc(intersection_time_table.num_volumes * sizeof(int)); - intersection_time_table.intersection_times = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); - intersection_time_table.normal_vector_x = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); - intersection_time_table.normal_vector_y = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); - intersection_time_table.normal_vector_z = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); - intersection_time_table.surface_index = (int**) malloc(intersection_time_table.num_volumes * sizeof(int*)); - - for (iterator = 0;iterator < intersection_time_table.num_volumes;iterator++){ - if (strcmp(Volumes[iterator]->geometry.shape, "mesh") == 0) { - intersection_time_table.n_elements[iterator] = (int) 100; // Meshes can have any number of intersections, here we allocate room for 100 - } else { - intersection_time_table.n_elements[iterator] = (int) 2; // number of intersection for all other geometries - } - if (iterator == 0) intersection_time_table.n_elements[iterator] = (int) 0; // number of intersection solutions - intersection_time_table.calculated[iterator] = (int) 0; // Initializing calculated logic + if (verbal) printf(" mask_mode for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.mask_mode); + if (verbal) printf("\n"); + } + ) // End of MPI_MASTER + + + // Initializing intersection_time_table + // The intersection time table contains all information on intersection times for the current position/direction, and is cleared everytime a ray changes direction. + // Not all entries needs to be calculated, so there is a variable that keeps track of which intersection times have been calculated in order to avoid redoing that. + // When the intersections times are calculated for a volume, all future intersections are kept in the time table. + // Thus the memory allocation have to take into account how many intersections there can be with each volume, but it is currently set to 2, but can easily be changed. This may need to be reported by individual geometry components in the future. + + intersection_time_table.num_volumes = number_of_volumes; + + intersection_time_table.n_elements = (int*) malloc(intersection_time_table.num_volumes * sizeof(int)); + intersection_time_table.calculated = (int*) malloc(intersection_time_table.num_volumes * sizeof(int)); + intersection_time_table.intersection_times = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); + intersection_time_table.normal_vector_x = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); + intersection_time_table.normal_vector_y = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); + intersection_time_table.normal_vector_z = (double**) malloc(intersection_time_table.num_volumes * sizeof(double*)); + intersection_time_table.surface_index = (int**) malloc(intersection_time_table.num_volumes * sizeof(int*)); + + for (iterator = 0;iterator < intersection_time_table.num_volumes;iterator++){ + if (strcmp(Volumes[iterator]->geometry.shape, "mesh") == 0) { + intersection_time_table.n_elements[iterator] = (int) 100; // Meshes can have any number of intersections, here we allocate room for 100 + } else { + intersection_time_table.n_elements[iterator] = (int) 2; // number of intersection for all other geometries + } + if (iterator == 0) intersection_time_table.n_elements[iterator] = (int) 0; // number of intersection solutions + intersection_time_table.calculated[iterator] = (int) 0; // Initializing calculated logic - if (iterator == 0) { - intersection_time_table.intersection_times[0] = NULL; - } - else { - //printf("allocating memory for volume %d \n", iterator); - intersection_time_table.intersection_times[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); - intersection_time_table.normal_vector_x[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); - intersection_time_table.normal_vector_y[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); - intersection_time_table.normal_vector_z[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); - intersection_time_table.surface_index[iterator] = (int*) malloc(intersection_time_table.n_elements[iterator]*sizeof(int)); + if (iterator == 0) { + intersection_time_table.intersection_times[0] = NULL; + } + else { + //printf("allocating memory for volume %d \n", iterator); + intersection_time_table.intersection_times[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); + intersection_time_table.normal_vector_x[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); + intersection_time_table.normal_vector_y[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); + intersection_time_table.normal_vector_z[iterator] = (double*) malloc(intersection_time_table.n_elements[iterator]*sizeof(double)); + intersection_time_table.surface_index[iterator] = (int*) malloc(intersection_time_table.n_elements[iterator]*sizeof(int)); - for (solutions = 0;solutions < intersection_time_table.n_elements[iterator];solutions++) { - intersection_time_table.intersection_times[iterator][solutions] = -1.0; - intersection_time_table.normal_vector_x[iterator][solutions] = -1.0; - intersection_time_table.normal_vector_y[iterator][solutions] = -1.0; - intersection_time_table.normal_vector_z[iterator][solutions] = -1.0; - intersection_time_table.surface_index[iterator][solutions] = -1; + for (solutions = 0;solutions < intersection_time_table.n_elements[iterator];solutions++) { + intersection_time_table.intersection_times[iterator][solutions] = -1.0; + intersection_time_table.normal_vector_x[iterator][solutions] = -1.0; + intersection_time_table.normal_vector_y[iterator][solutions] = -1.0; + intersection_time_table.normal_vector_z[iterator][solutions] = -1.0; + intersection_time_table.surface_index[iterator][solutions] = -1; + } } - } - } + } - // If enabled, the tagging system tracks all different histories sampled by the program. + // If enabled, the tagging system tracks all different histories sampled by the program. - // Initialize the tagging tree - // Allocate a list of host nodes with the same length as the number of volumes + // Initialize the tagging tree + // Allocate a list of host nodes with the same length as the number of volumes - stop_creating_nodes = 0; stop_tagging_ray = 0; tagging_leaf_counter = 0; - if (enable_tagging) { - master_tagging_node_list.num_elements = number_of_volumes; - master_tagging_node_list.elements = malloc(master_tagging_node_list.num_elements * sizeof(struct tagging_tree_node_struct*)); + stop_creating_nodes = 0; stop_tagging_ray = 0; tagging_leaf_counter = 0; + if (enable_tagging) { + master_tagging_node_list.num_elements = number_of_volumes; + master_tagging_node_list.elements = malloc(master_tagging_node_list.num_elements * sizeof(struct tagging_tree_node_struct*)); - // Initialize - for (volume_index=0;volume_indexelements[this_global_master_index-1].stored_number_of_scattering_events; + if (inherit_number_of_scattering_events==1) // Continue number of scattering from previous Union_master + number_of_scattering_events = global_master_list_master->elements[this_global_master_index-1].stored_number_of_scattering_events; - // Zero scattered_flag_VP data - for (volume_index = 1;volume_indexelements[0].component_index == INDEX_CURRENT_COMP) { - // If this is the first Union master, clean up logger data for rays that did not make it through Union components - for (log_index=loggers_with_data_array.used_elements-1;log_index>-1;log_index--) { - loggers_with_data_array.logger_pointers[log_index]->function_pointers.clear_temp(&loggers_with_data_array.logger_pointers[log_index]->data_union); + // If first Union_master in instrument, reset loggers_with_data_array and clean unused data. + // Unused data happens when logging data is passed to the next Union_master, but the ray is absorbed on the way. + // Could be improved by using the precompiler instead as ncount times the number of Union_masters could be avoided. + if (global_master_list_master->elements[0].component_index == INDEX_CURRENT_COMP) { + // If this is the first Union master, clean up logger data for rays that did not make it through Union components + for (log_index=loggers_with_data_array.used_elements-1;log_index>-1;log_index--) { + loggers_with_data_array.logger_pointers[log_index]->function_pointers.clear_temp(&loggers_with_data_array.logger_pointers[log_index]->data_union); + } + loggers_with_data_array.used_elements = 0; + for (log_index=abs_loggers_with_data_array.used_elements-1;log_index>-1;log_index--) { + abs_loggers_with_data_array.abs_logger_pointers[log_index]->function_pointers.clear_temp(&abs_loggers_with_data_array.abs_logger_pointers[log_index]->data_union); + } + abs_loggers_with_data_array.used_elements = 0; } - loggers_with_data_array.used_elements = 0; - for (log_index=abs_loggers_with_data_array.used_elements-1;log_index>-1;log_index--) { - abs_loggers_with_data_array.abs_logger_pointers[log_index]->function_pointers.clear_temp(&abs_loggers_with_data_array.abs_logger_pointers[log_index]->data_union); + tagging_conditional_extend = 0; + for (iterator=0;iteratorgeometry.within_function(ray_position,&Volumes[mask_volume_index_list.elements[iterator]]->geometry) == 1) { - // GPU - if (r_within_function(ray_position, &Volumes[mask_volume_index_list.elements[iterator]]->geometry) == 1) { - mask_status_list.elements[iterator] = 1; - } else { - mask_status_list.elements[iterator] = 0; + // Need to clean up the double notation for position and velocity. // REVIEW_LINE + r_start[0] = x; r_start[1] = y; r_start[2] = z; + r[0]=x;r[1]=y;r[2]=z;v[0]=vx;v[1]=vy;v[2]=vz; // REVIEW_LINE r and v are bad names + k[0] = V2K*vx; k[1] = V2K*vy; k[2] = V2K*vz; + + ray_position = coords_set(x,y,z); + ray_velocity = coords_set(vx,vy,vz); + + // Mask update: need to check the mask status for the initial position + // mask status for a mask is 1 if the ray position is inside, 0 if it is outside + for (iterator=0;iteratorgeometry.within_function(ray_position,&Volumes[mask_volume_index_list.elements[iterator]]->geometry) == 1) { + // GPU + if (r_within_function(ray_position, &Volumes[mask_volume_index_list.elements[iterator]]->geometry) == 1) { + mask_status_list.elements[iterator] = 1; + } else { + mask_status_list.elements[iterator] = 0; + } } - } - #ifdef Union_trace_verbal_setting - print_1d_int_list(mask_status_list,"Initial mask status list"); - #endif + #ifdef Union_trace_verbal_setting + print_1d_int_list(mask_status_list,"Initial mask status list"); + #endif - // Now the initial current_volume can be found, which requires the up to date mask_status_list - current_volume = within_which_volume_GPU(ray_position, starting_lists.reduced_start_list, starting_lists.starting_destinations_list, Volumes, &mask_status_list, number_of_volumes, pre_allocated1, pre_allocated2, pre_allocated3); + // Now the initial current_volume can be found, which requires the up to date mask_status_list + current_volume = within_which_volume_GPU(ray_position, starting_lists.reduced_start_list, starting_lists.starting_destinations_list, Volumes, &mask_status_list, number_of_volumes, pre_allocated1, pre_allocated2, pre_allocated3); - // For excluding closest intersection in search after refraction/reflection - ignore_closest = -1; + // For excluding closest intersection in search after refraction/reflection + ignore_closest = -1; - // Using the mask_status_list and the current volume, the current_mask_intersect_list_status can be made - // it contains the effective mask status of all volumes on the current volumes mask intersect list, which needs to be calculated, - // but only when the current volume or mask status changes, not under for example scattering inside the current volume - update_current_mask_intersect_status(¤t_mask_intersect_list_status, &mask_status_list, Volumes, ¤t_volume); + // Using the mask_status_list and the current volume, the current_mask_intersect_list_status can be made + // it contains the effective mask status of all volumes on the current volumes mask intersect list, which needs to be calculated, + // but only when the current volume or mask status changes, not under for example scattering inside the current volume + update_current_mask_intersect_status(¤t_mask_intersect_list_status, &mask_status_list, Volumes, ¤t_volume); - #ifdef Union_trace_verbal_setting - printf("Starting current_volume = %d\n",current_volume); - #endif + #ifdef Union_trace_verbal_setting + printf("Starting current_volume = %d\n",current_volume); + #endif - // Check if the ray appeared in an allowed starting volume, unless this check is disabled by the user for advanced cases - if (allow_inside_start == 0 && starting_lists.allowed_starting_volume_logic_list.elements[current_volume] == 0) { - printf("ERROR, ray ''teleported'' into Union component %s, if intentional, set allow_inside_start=1\n", NAME_CURRENT_COMP); - // NEED ERROR FLAG: Need to set an error flag that is read in finally to warn user of problem. - exit(1); - } - // Warn the user that rays have appeared inside a volume instead of outside as expected - if (starting_volume_warning == 0 && current_volume != 0) { + // Check if the ray appeared in an allowed starting volume, unless this check is disabled by the user for advanced cases + if (allow_inside_start == 0 && starting_lists.allowed_starting_volume_logic_list.elements[current_volume] == 0) { + printf("ERROR, ray ''teleported'' into Union component %s, if intentional, set allow_inside_start=1\n", NAME_CURRENT_COMP); + // NEED ERROR FLAG: Need to set an error flag that is read in finally to warn user of problem. + exit(1); + } + // Warn the user that rays have appeared inside a volume instead of outside as expected + if (starting_volume_warning == 0 && current_volume != 0) { printf("WARNING: Ray started in volume ''%s'' rather than the surrounding vacuum in component %s. This warning is only shown once.\n",Volumes[current_volume]->name,NAME_CURRENT_COMP); starting_volume_warning = 1; - } + } - // Placing the new ray at the start of the tagging tree corresponding to current volume - // A history limit can be imposed so that no new nodes are created after this limit (may be necessary to fit in memory) - // Rays can still follow the nodes created before even when no additional nodes are created, but if a situation that - // requires a new node is encountered, stop_tagging_ray is set to 1, stopping further tagging and preventing the data - // for that ray to be used further. - if (enable_tagging) { - current_tagging_node = master_tagging_node_list.elements[current_volume]; - stop_tagging_ray = 0; // Allow this ray to be tracked - if (tagging_leaf_counter > history_limit) stop_creating_nodes = 1; - } + // Placing the new ray at the start of the tagging tree corresponding to current volume + // A history limit can be imposed so that no new nodes are created after this limit (may be necessary to fit in memory) + // Rays can still follow the nodes created before even when no additional nodes are created, but if a situation that + // requires a new node is encountered, stop_tagging_ray is set to 1, stopping further tagging and preventing the data + // for that ray to be used further. + if (enable_tagging) { + current_tagging_node = master_tagging_node_list.elements[current_volume]; + stop_tagging_ray = 0; // Allow this ray to be tracked + if (tagging_leaf_counter > history_limit) stop_creating_nodes = 1; + } - #ifdef Union_trace_verbal_setting - if (enable_tagging) printf("current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging) printf("current_tagging_node->number_of_rays = %d \n",current_tagging_node->number_of_rays); - #endif - - // Propagation loop including scattering - // This while loop continues until the ray leaves the ensamble of user defined volumes either through volume 0 - // or a dedicated exit volume. The loop is cancelled after a large number of iterations as a failsafe for errors. - // A single run of the loop will either be a propagation to the next volume along the path of the ray, or a - // scattering event at some point along the path of the ray in the current volume. - limit = 100000; - while (done == 0) { - limit--; - #ifdef Union_trace_verbal_setting - printf("----------- START OF WHILE LOOP --------------------------------------\n"); - print_intersection_table(&intersection_time_table); - printf("current_volume = %d \n",current_volume); - #endif - - if (weight_ratio_limit && p < weight_limit) { - #ifdef Union_trace_verbal_setting - printf("Weight reduced more than ratio_limit p=%lf, p0=%lf, (p_limit=%lf, limit=%d)\n", p, start_weight, weight_limit, limit); - #endif - //printf("Weight reduced more than ratio_limit p=%30.28lf, p0=%15.13lf, (p_limit=%15.13lf, scatter=%d)\n", p, start_weight, weight_limit, 100000-limit); - ABSORB; - } - - // Calculating intersections with the necessary volumes. The relevant set of volumes depend on the current volume and the mask status array. - // First the volumes on the current volumes intersect list is checked, then its mask interset list. Before checking the volume itself, it is - // checked if any children of the current volume is intersected, in which case the intersection calculation with the current volume can be - // skipped. + if (enable_tagging) printf("current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + if (enable_tagging) printf("current_tagging_node->number_of_rays = %d \n",current_tagging_node->number_of_rays); + #endif + + // Propagation loop including scattering + // This while loop continues until the ray leaves the ensamble of user defined volumes either through volume 0 + // or a dedicated exit volume. The loop is cancelled after a large number of iterations as a failsafe for errors. + // A single run of the loop will either be a propagation to the next volume along the path of the ray, or a + // scattering event at some point along the path of the ray in the current volume. + limit = 100000; + while (done == 0) { + limit--; - // Checking intersections for all volumes in the intersect list. - for (start=check=Volumes[current_volume]->geometry.intersect_check_list.elements;check-startgeometry.intersect_check_list.num_elements;check++) { - // This will leave check as a pointer to the intergers in the intersect_check_list and iccrement nicely #ifdef Union_trace_verbal_setting - printf("Intersect_list = %d being checked \n",*check); + printf("----------- START OF WHILE LOOP --------------------------------------\n"); + print_intersection_table(&intersection_time_table); + printf("current_volume = %d \n",current_volume); #endif + + if (weight_ratio_limit && p < weight_limit) { + #ifdef Union_trace_verbal_setting + printf("Weight reduced more than ratio_limit p=%lf, p0=%lf, (p_limit=%lf, limit=%d)\n", p, start_weight, weight_limit, limit); + #endif + //printf("Weight reduced more than ratio_limit p=%30.28lf, p0=%15.13lf, (p_limit=%15.13lf, scatter=%d)\n", p, start_weight, weight_limit, 100000-limit); + ABSORB; + } + + // Calculating intersections with the necessary volumes. The relevant set of volumes depend on the current volume and the mask status array. + // First the volumes on the current volumes intersect list is checked, then its mask interset list. Before checking the volume itself, it is + // checked if any children of the current volume is intersected, in which case the intersection calculation with the current volume can be + // skipped. - if (intersection_time_table.calculated[*check] == 0) { - #ifdef Union_trace_verbal_setting - printf("running intersection for intersect_list with *check = %d \n",*check); - #endif - // Calculate intersections using intersect function imbedded in the relevant volume structure using parameters that are also imbedded in the structure. - #ifdef Union_trace_verbal_setting - printf("surface_index[*check][0] = %d, surface_index[*check][1] = %d\n", - intersection_time_table.surface_index[*check][0], - intersection_time_table.surface_index[*check][1]); - #endif - // GPU Flexible intersect_function call - geometry_output = intersect_function(intersection_time_table.intersection_times[*check], - intersection_time_table.normal_vector_x[*check], - intersection_time_table.normal_vector_y[*check], - intersection_time_table.normal_vector_z[*check], - intersection_time_table.surface_index[*check], - number_of_solutions, r_start, v, &Volumes[*check]->geometry); + // Checking intersections for all volumes in the intersect list. + for (start=check=Volumes[current_volume]->geometry.intersect_check_list.elements;check-startgeometry.intersect_check_list.num_elements;check++) { + // This will leave check as a pointer to the intergers in the intersect_check_list and iccrement nicely + #ifdef Union_trace_verbal_setting + printf("Intersect_list = %d being checked \n",*check); + #endif + + if (intersection_time_table.calculated[*check] == 0) { + #ifdef Union_trace_verbal_setting + printf("running intersection for intersect_list with *check = %d \n",*check); + #endif + // Calculate intersections using intersect function imbedded in the relevant volume structure using parameters that are also imbedded in the structure. + #ifdef Union_trace_verbal_setting + printf("surface_index[*check][0] = %d, surface_index[*check][1] = %d\n", + intersection_time_table.surface_index[*check][0], + intersection_time_table.surface_index[*check][1]); + #endif + // GPU Flexible intersect_function call + geometry_output = intersect_function(intersection_time_table.intersection_times[*check], + intersection_time_table.normal_vector_x[*check], + intersection_time_table.normal_vector_y[*check], + intersection_time_table.normal_vector_z[*check], + intersection_time_table.surface_index[*check], + number_of_solutions, r_start, v, &Volumes[*check]->geometry); - intersection_time_table.calculated[*check] = 1; - #ifdef Union_trace_verbal_setting - printf("finished running intersection for intersect_list with *check = %d \n",*check); - print_intersection_table(&intersection_time_table); - #endif + intersection_time_table.calculated[*check] = 1; + #ifdef Union_trace_verbal_setting + printf("finished running intersection for intersect_list with *check = %d \n",*check); + print_intersection_table(&intersection_time_table); + #endif + } } - } - // Mask update: add additional loop for checking intersections with masked volumes depending on mask statuses - for (mask_iterator=0;mask_iteratorgeometry.mask_intersect_list.num_elements;mask_iterator++) { - if (current_mask_intersect_list_status.elements[mask_iterator] == 1) { // Only check if the mask is active - #ifdef Union_trace_verbal_setting - printf("Mask Intersect_list = %d being checked \n",Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]); - #endif - if (intersection_time_table.calculated[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]] == 0) { - #ifdef Union_trace_verbal_setting - printf("running intersection for mask_intersect_list element = %d \n",Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]); - // printf("r = (%f,%f,%f) v = (%f,%f,%f) \n",r[0],r[1],r[2],v[0],v[1],v[2]); - #endif - // Calculate intersections using intersect function imbedded in the relevant volume structure using parameters - // that are also imbedded in the structure. - // CPU Only - //geometry_output = Volumes[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]]->geometry.intersect_function(intersection_time_table.intersection_times[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]],number_of_solutions,r_start,v,&Volumes[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]]->geometry); + // Mask update: add additional loop for checking intersections with masked volumes depending on mask statuses + for (mask_iterator=0;mask_iteratorgeometry.mask_intersect_list.num_elements;mask_iterator++) { + if (current_mask_intersect_list_status.elements[mask_iterator] == 1) { // Only check if the mask is active + #ifdef Union_trace_verbal_setting + printf("Mask Intersect_list = %d being checked \n",Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]); + #endif + if (intersection_time_table.calculated[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]] == 0) { + #ifdef Union_trace_verbal_setting + printf("running intersection for mask_intersect_list element = %d \n",Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]); + // printf("r = (%f,%f,%f) v = (%f,%f,%f) \n",r[0],r[1],r[2],v[0],v[1],v[2]); + #endif + // Calculate intersections using intersect function imbedded in the relevant volume structure using parameters + // that are also imbedded in the structure. + // CPU Only + //geometry_output = Volumes[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]]->geometry.intersect_function(intersection_time_table.intersection_times[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]],number_of_solutions,r_start,v,&Volumes[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]]->geometry); - // GPU allowed - int selected_index; - selected_index = Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]; - geometry_output = intersect_function(intersection_time_table.intersection_times[selected_index], - intersection_time_table.normal_vector_x[selected_index], - intersection_time_table.normal_vector_y[selected_index], - intersection_time_table.normal_vector_z[selected_index], - intersection_time_table.surface_index[selected_index], - number_of_solutions, r_start, v, &Volumes[selected_index]->geometry); + // GPU allowed + int selected_index; + selected_index = Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]; + geometry_output = intersect_function(intersection_time_table.intersection_times[selected_index], + intersection_time_table.normal_vector_x[selected_index], + intersection_time_table.normal_vector_y[selected_index], + intersection_time_table.normal_vector_z[selected_index], + intersection_time_table.surface_index[selected_index], + number_of_solutions, r_start, v, &Volumes[selected_index]->geometry); - intersection_time_table.calculated[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]] = 1; - // if printf("succesfully calculated intersection times for volume *check = %d \n",*check); + intersection_time_table.calculated[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]] = 1; + // if printf("succesfully calculated intersection times for volume *check = %d \n",*check); + } + } } - } - } - // Checking if there are intersections with children of current volume, which means there is an intersection before current_volume, and thus can be skipped. But only if they have not been overwritten. In case current_volume is 0, there is no need to do this regardless. - if (current_volume != 0 && intersection_time_table.calculated[current_volume] == 0 ) { - #ifdef Union_trace_verbal_setting - printf("Checking if children of current_volume = %d have intersections. \n",current_volume); - #endif - intersection_with_children = 0; - //for (start = check = Volumes[current_volume]->geometry.direct_children.elements;check - start < Volumes[current_volume]->geometry.children.num_elements;check++) { // REVIEW LINE. Caused bug with masks. - if (!Volumes[current_volume]->geometry.skip_hierarchy_optimization){ - for (start = check = Volumes[current_volume]->geometry.children.elements;check - start < Volumes[current_volume]->geometry.children.num_elements;check++) { - #ifdef Union_trace_verbal_setting - printf("Checking if child %d of current_volume = %d have intersections. \n",*check,current_volume); - #endif - // Only check the first of the two results in the intersection table, as they are ordered, and the second is of no interest - if (intersection_time_table.calculated[*check] == 1 && intersection_time_table.intersection_times[*check][0] > time_propagated_without_scattering) { - // If this child is masked, its mask status need to be 1 in order to be taken into account - if (Volumes[*check]->geometry.is_masked_volume == 0) { - #ifdef Union_trace_verbal_setting - printf("Found an child of current_volume with an intersection. Skips calculating for current_volume \n"); - #endif - intersection_with_children = 1; - break; // No need to check more, if there is just one it is not necessary to calculate intersection with current_volume yet - } else { - #ifdef Union_trace_verbal_setting - printf("Found an child of current_volume with an intersection, but it is masked. Check to see if it can skip calculating for current_volume \n"); - #endif - - if (Volumes[*check]->geometry.mask_mode == 2) { // ANY mask mode - tree_next_volume = 0; - for (mask_start=mask_check=Volumes[*check]->geometry.masked_by_mask_index_list.elements;mask_check-mask_startgeometry.masked_by_mask_index_list.num_elements;mask_check++) { - if (mask_status_list.elements[*mask_check] == 1) { + // Checking if there are intersections with children of current volume, which means there is an intersection before current_volume, and thus can be skipped. But only if they have not been overwritten. In case current_volume is 0, there is no need to do this regardless. + if (current_volume != 0 && intersection_time_table.calculated[current_volume] == 0 ) { + #ifdef Union_trace_verbal_setting + printf("Checking if children of current_volume = %d have intersections. \n",current_volume); + #endif + intersection_with_children = 0; + //for (start = check = Volumes[current_volume]->geometry.direct_children.elements;check - start < Volumes[current_volume]->geometry.children.num_elements;check++) { // REVIEW LINE. Caused bug with masks. + if (!Volumes[current_volume]->geometry.skip_hierarchy_optimization){ + for (start = check = Volumes[current_volume]->geometry.children.elements;check - start < Volumes[current_volume]->geometry.children.num_elements;check++) { + #ifdef Union_trace_verbal_setting + printf("Checking if child %d of current_volume = %d have intersections. \n",*check,current_volume); + #endif + // Only check the first of the two results in the intersection table, as they are ordered, and the second is of no interest + if (intersection_time_table.calculated[*check] == 1 && intersection_time_table.intersection_times[*check][0] > time_propagated_without_scattering) { + // If this child is masked, its mask status need to be 1 in order to be taken into account + if (Volumes[*check]->geometry.is_masked_volume == 0) { + #ifdef Union_trace_verbal_setting + printf("Found an child of current_volume with an intersection. Skips calculating for current_volume \n"); + #endif intersection_with_children = 1; - break; - } - } - } else { // ALL mask mode - intersection_with_children = 1; - for (mask_start=mask_check=Volumes[*check]->geometry.masked_by_mask_index_list.elements;mask_check-mask_startgeometry.masked_by_mask_index_list.num_elements;mask_check++) { - if (mask_status_list.elements[*mask_check] == 0) { - intersection_with_children = 0; - break; - } - } - } - #ifdef Union_trace_verbal_setting - printf("The mask status was 1, can actually skip intersection calculation for current volume \n"); - #endif - if (intersection_with_children == 1) break; - } - } - } + break; // No need to check more, if there is just one it is not necessary to calculate intersection with current_volume yet + } else { + #ifdef Union_trace_verbal_setting + printf("Found an child of current_volume with an intersection, but it is masked. Check to see if it can skip calculating for current_volume \n"); + #endif + + if (Volumes[*check]->geometry.mask_mode == 2) { // ANY mask mode + tree_next_volume = 0; + for (mask_start=mask_check=Volumes[*check]->geometry.masked_by_mask_index_list.elements;mask_check-mask_startgeometry.masked_by_mask_index_list.num_elements;mask_check++) { + if (mask_status_list.elements[*mask_check] == 1) { + intersection_with_children = 1; + break; + } + } + } else { // ALL mask mode + intersection_with_children = 1; + for (mask_start=mask_check=Volumes[*check]->geometry.masked_by_mask_index_list.elements;mask_check-mask_startgeometry.masked_by_mask_index_list.num_elements;mask_check++) { + if (mask_status_list.elements[*mask_check] == 0) { + intersection_with_children = 0; + break; + } + } + } + #ifdef Union_trace_verbal_setting + printf("The mask status was 1, can actually skip intersection calculation for current volume \n"); + #endif + if (intersection_with_children == 1) break; + } + } + } + } + #ifdef Union_trace_verbal_setting + printf("intersection_with_children = %d \n",intersection_with_children); + #endif + if (intersection_with_children == 0) { + // GPU Allowed + geometry_output = intersect_function(intersection_time_table.intersection_times[current_volume], + intersection_time_table.normal_vector_x[current_volume], + intersection_time_table.normal_vector_y[current_volume], + intersection_time_table.normal_vector_z[current_volume], + intersection_time_table.surface_index[current_volume], + number_of_solutions, r_start, v, &Volumes[current_volume]->geometry); + + intersection_time_table.calculated[current_volume] = 1; + } } + + // At this point, intersection_time_table is updated with intersection times of all possible intersections. #ifdef Union_trace_verbal_setting - printf("intersection_with_children = %d \n",intersection_with_children); + print_intersection_table(&intersection_time_table); #endif - if (intersection_with_children == 0) { - // GPU Allowed - geometry_output = intersect_function(intersection_time_table.intersection_times[current_volume], - intersection_time_table.normal_vector_x[current_volume], - intersection_time_table.normal_vector_y[current_volume], - intersection_time_table.normal_vector_z[current_volume], - intersection_time_table.surface_index[current_volume], - number_of_solutions, r_start, v, &Volumes[current_volume]->geometry); - - intersection_time_table.calculated[current_volume] = 1; - } - } - - // At this point, intersection_time_table is updated with intersection times of all possible intersections. - #ifdef Union_trace_verbal_setting - print_intersection_table(&intersection_time_table); - #endif - // For the closest intersection to volume with index ignore_closest, the scattering with the shortest absolute time should be ignored - if (ignore_closest > 0) { - min_intersection_time = 1E9; - min_solution = -1; - for (solution = 0; solution 0) { + min_intersection_time = 1E9; + min_solution = -1; + for (solution = 0; solutiongeometry.intersect_check_list.elements;check-startgeometry.intersect_check_list.num_elements;check++) { - for (solution = 0;solution time_propagated_without_scattering && intersection_time < min_intersection_time) { - min_intersection_time = intersection_time;min_solution = solution;min_volume = *check; - #ifdef Union_trace_verbal_setting - printf("found A at %i x %i\n",*check,solution); - #endif - } - } else { - if ((intersection_time = intersection_time_table.intersection_times[*check][solution]) > time_propagated_without_scattering) { - min_intersection_time = intersection_time;min_solution = solution;min_volume = *check; - time_found = 1; - #ifdef Union_trace_verbal_setting - printf("found B at %i x %i\n",*check,solution); - #endif + #ifdef Union_trace_verbal_setting + printf("Incoming value of MIN_intersection_time=%g\n",min_intersection_time); + #endif + min_intersection_time=0; + time_found = 0; + for (start=check=Volumes[current_volume]->geometry.intersect_check_list.elements;check-startgeometry.intersect_check_list.num_elements;check++) { + for (solution = 0;solution time_propagated_without_scattering && intersection_time < min_intersection_time) { + min_intersection_time = intersection_time;min_solution = solution;min_volume = *check; + #ifdef Union_trace_verbal_setting + printf("found A at %i x %i\n",*check,solution); + #endif + } + } else { + if ((intersection_time = intersection_time_table.intersection_times[*check][solution]) > time_propagated_without_scattering) { + min_intersection_time = intersection_time;min_solution = solution;min_volume = *check; + time_found = 1; + #ifdef Union_trace_verbal_setting + printf("found B at %i x %i\n",*check,solution); + #endif + } } } } - } - #ifdef Union_trace_verbal_setting - printf("min_intersection_time=%g min_solution=%i\n",min_intersection_time,min_solution); - #endif + #ifdef Union_trace_verbal_setting + printf("min_intersection_time=%g min_solution=%i\n",min_intersection_time,min_solution); + #endif - // Now check the masked_intersect_list, but only the ones that are currently active - for (mask_iterator=0;mask_iteratorgeometry.mask_intersect_list.num_elements;mask_iterator++) { - if (current_mask_intersect_list_status.elements[mask_iterator] == 1) { - for (solution = 0;solutiongeometry.mask_intersect_list.elements[mask_iterator]];solution++) { + // Now check the masked_intersect_list, but only the ones that are currently active + for (mask_iterator=0;mask_iteratorgeometry.mask_intersect_list.num_elements;mask_iterator++) { + if (current_mask_intersect_list_status.elements[mask_iterator] == 1) { + for (solution = 0;solutiongeometry.mask_intersect_list.elements[mask_iterator]];solution++) { + if (time_found) { + if ((intersection_time = intersection_time_table.intersection_times[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]][solution]) > time_propagated_without_scattering && intersection_time < min_intersection_time) { + min_intersection_time = intersection_time;min_solution = solution;min_volume = Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]; + } + } else { + if ((intersection_time = intersection_time_table.intersection_times[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]][solution]) > time_propagated_without_scattering) { + min_intersection_time = intersection_time;min_solution = solution;min_volume = Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]; + time_found = 1; + } + } + } + } + } + + // And check the current_volume + for (solution = 0;solutiongeometry.mask_intersect_list.elements[mask_iterator]][solution]) > time_propagated_without_scattering && intersection_time < min_intersection_time) { - min_intersection_time = intersection_time;min_solution = solution;min_volume = Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]; + if ((intersection_time = intersection_time_table.intersection_times[current_volume][solution]) > time_propagated_without_scattering && intersection_time < min_intersection_time) { + min_intersection_time = intersection_time;min_solution = solution;min_volume = current_volume; } } else { - if ((intersection_time = intersection_time_table.intersection_times[Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]][solution]) > time_propagated_without_scattering) { - min_intersection_time = intersection_time;min_solution = solution;min_volume = Volumes[current_volume]->geometry.mask_intersect_list.elements[mask_iterator]; + if ((intersection_time = intersection_time_table.intersection_times[current_volume][solution]) > time_propagated_without_scattering) { + min_intersection_time = intersection_time;min_solution = solution;min_volume = current_volume; time_found = 1; } } } - } - } - - // And check the current_volume - for (solution = 0;solution time_propagated_without_scattering && intersection_time < min_intersection_time) { - min_intersection_time = intersection_time;min_solution = solution;min_volume = current_volume; - } - } else { - if ((intersection_time = intersection_time_table.intersection_times[current_volume][solution]) > time_propagated_without_scattering) { - min_intersection_time = intersection_time;min_solution = solution;min_volume = current_volume; - time_found = 1; - } - } - } - // Reset ingore_closest after one intersection iteration - ignore_closest = -1; + // Reset ingore_closest after one intersection iteration + ignore_closest = -1; - #ifdef Union_trace_verbal_setting - printf("min_intersection_time = %f \n", min_intersection_time); - printf("min_solution = %d \n", min_solution); - printf("min_volume = %d \n", min_volume); - printf("time_found = %d \n", time_found); - #endif + #ifdef Union_trace_verbal_setting + printf("min_intersection_time = %f \n", min_intersection_time); + printf("min_solution = %d \n", min_solution); + printf("min_volume = %d \n", min_volume); + printf("time_found = %d \n", time_found); + #endif - abs_weight_factor = 1.0; - abs_weight_factor_set = 0; + abs_weight_factor = 1.0; + abs_weight_factor_set = 0; - // If a time is found, propagation continues, and it will be checked if a scattering occurs before the next intersection. - // If a time is not found, the ray must be leaving the ensamble of volumes and the loop will be concluded - if (time_found) { - time_to_boundery = min_intersection_time - time_propagated_without_scattering; // calculate the time remaining before the next intersection - scattering_event = 0; // Assume a scattering event will not occur + // If a time is found, propagation continues, and it will be checked if a scattering occurs before the next intersection. + // If a time is not found, the ray must be leaving the ensamble of volumes and the loop will be concluded + if (time_found) { + time_to_boundery = min_intersection_time - time_propagated_without_scattering; // calculate the time remaining before the next intersection + scattering_event = 0; // Assume a scattering event will not occur - // Check if a scattering event should occur - if (current_volume != 0) { // Volume 0 is always vacuum, and if this is the current volume, an event will not occur - if (Volumes[current_volume]->p_physics->number_of_processes == 0) { // If there are no processes, the volume could be vacuum or an absorber - if (Volumes[current_volume]->p_physics->is_vacuum == 0) { - // This volume does not have physical processes but does have an absorption cross section, so the ray weight is reduced accordingly + // Check if a scattering event should occur + if (current_volume != 0) { // Volume 0 is always vacuum, and if this is the current volume, an event will not occur + if (Volumes[current_volume]->p_physics->number_of_processes == 0) { // If there are no processes, the volume could be vacuum or an absorber + if (Volumes[current_volume]->p_physics->is_vacuum == 0) { + // This volume does not have physical processes but does have an absorption cross section, so the ray weight is reduced accordingly - my_sum_plus_abs = Volumes[current_volume]->p_physics->my_a*(2200/v_length); - length_to_boundary = time_to_boundery * v_length; + my_sum_plus_abs = Volumes[current_volume]->p_physics->my_a*(2200/v_length); + length_to_boundary = time_to_boundery * v_length; - abs_weight_factor = exp(-Volumes[current_volume]->p_physics->my_a*2200*time_to_boundery); - abs_weight_factor_set = 1; + abs_weight_factor = exp(-Volumes[current_volume]->p_physics->my_a*2200*time_to_boundery); + abs_weight_factor_set = 1; - #ifdef Union_trace_verbal_setting - printf("name of material: %s \n",Volumes[current_volume]->name); - printf("length to boundery = %f\n",length_to_boundary); - printf("absorption cross section = %f\n",Volumes[current_volume]->p_physics->my_a); - printf("chance to get through this length of absorber: %f %%\n", 100*exp(-Volumes[current_volume]->p_physics->my_a*length_to_boundary)); - #endif - } - } else { - // Since there is a non-zero number of processes in this material, all the scattering cross section for these are calculated - my_sum = 0; k[0] = V2K*vx; k[1] = V2K*vy; k[2] = V2K*vz; - p_my_trace = my_trace; wavevector = coords_set(k[0],k[1],k[2]); - length_to_boundary = time_to_boundery * v_length; + #ifdef Union_trace_verbal_setting + printf("name of material: %s \n",Volumes[current_volume]->name); + printf("length to boundery = %f\n",length_to_boundary); + printf("absorption cross section = %f\n",Volumes[current_volume]->p_physics->my_a); + printf("chance to get through this length of absorber: %f %%\n", 100*exp(-Volumes[current_volume]->p_physics->my_a*length_to_boundary)); + #endif + } + } else { + // Since there is a non-zero number of processes in this material, all the scattering cross section for these are calculated + my_sum = 0; k[0] = V2K*vx; k[1] = V2K*vy; k[2] = V2K*vz; + p_my_trace = my_trace; wavevector = coords_set(k[0],k[1],k[2]); + length_to_boundary = time_to_boundery * v_length; - double forced_length_to_scattering; - Coords ray_position_geometry; + double forced_length_to_scattering; + Coords ray_position_geometry; - // If any process in this material needs focusing, sample scattering position and update focus_data accordingly - if (Volumes[current_volume]->p_physics->any_process_needs_cross_section_focus == 1) { - // Sample length_to_scattering in linear manner - forced_length_to_scattering = safety_distance + rand01()*(length_to_boundary - safety_distance2); + // If any process in this material needs focusing, sample scattering position and update focus_data accordingly + if (Volumes[current_volume]->p_physics->any_process_needs_cross_section_focus == 1) { + // Sample length_to_scattering in linear manner + forced_length_to_scattering = safety_distance + rand01()*(length_to_boundary - safety_distance2); - ray_velocity = coords_set(vx,vy,vz); // Test for root cause - // Find location of scattering point in master coordinate system without changing main position / velocity variables - Coords direction = coords_scalar_mult(ray_velocity, 1.0/length_of_position_vector(ray_velocity)); - Coords scattering_displacement = coords_scalar_mult(direction, forced_length_to_scattering); - Coords forced_ray_scattering_point = coords_add(ray_position, scattering_displacement); - ray_position_geometry = coords_sub(forced_ray_scattering_point, Volumes[current_volume]->geometry.center); // ray_position relative to geometry center + ray_velocity = coords_set(vx,vy,vz); // Test for root cause + // Find location of scattering point in master coordinate system without changing main position / velocity variables + Coords direction = coords_scalar_mult(ray_velocity, 1.0/length_of_position_vector(ray_velocity)); + Coords scattering_displacement = coords_scalar_mult(direction, forced_length_to_scattering); + Coords forced_ray_scattering_point = coords_add(ray_position, scattering_displacement); + ray_position_geometry = coords_sub(forced_ray_scattering_point, Volumes[current_volume]->geometry.center); // ray_position relative to geometry center - // Calculate the aim for non isotropic processes - this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[0]; - this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray + // Calculate the aim for non isotropic processes + this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[0]; + this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray - #ifdef Union_trace_verbal_setting - printf("Prepared for focus in cross section calculation in volume: %s \n",Volumes[current_volume]->name); - printf("forced_length_to_scattering =%lf \n", forced_length_to_scattering); - print_position(ray_position, "ray_position"); - print_position(direction, "direction"); - print_position(scattering_displacement, "scattering_displacement"); - print_position(forced_ray_scattering_point, "forced_ray_scattering_point"); - print_position(ray_position_geometry, "ray_position_geometry"); - printf("for isotropic processes this RayAim is used \n"); - print_position(this_focus_data->RayAim, "this_focus_data->RayAim"); - #endif - - /* - // update focus data for this ray (could limit this to only update the necessary focus_data element, but there are typically very few) - int f_index; - for (f_index=0; f_index < Volumes[current_volume]->geometry.focus_data_array.num_elements; f_index++) { - this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[f_index]; - // Coords ray_position_geometry_rotated = rot_apply(this_focus_data.absolute_rotation, ray_position_geometry); - this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray - } - - printf("calculated forced_length_to_scattering = %lf, new RayAim \n", forced_length_to_scattering); - print_position(direction, "direction"); - print_position(scattering_displacement, "scattering_displacement"); - print_position(forced_ray_scattering_point, "forced_ray_scattering_point"); - print_position(ray_position_geometry, "ray_position_geometry"); - print_position(this_focus_data->RayAim, "this_focus_data->RayAim"); - */ + #ifdef Union_trace_verbal_setting + printf("Prepared for focus in cross section calculation in volume: %s \n",Volumes[current_volume]->name); + printf("forced_length_to_scattering =%lf \n", forced_length_to_scattering); + print_position(ray_position, "ray_position"); + print_position(direction, "direction"); + print_position(scattering_displacement, "scattering_displacement"); + print_position(forced_ray_scattering_point, "forced_ray_scattering_point"); + print_position(ray_position_geometry, "ray_position_geometry"); + printf("for isotropic processes this RayAim is used \n"); + print_position(this_focus_data->RayAim, "this_focus_data->RayAim"); + #endif + + /* + // update focus data for this ray (could limit this to only update the necessary focus_data element, but there are typically very few) + int f_index; + for (f_index=0; f_index < Volumes[current_volume]->geometry.focus_data_array.num_elements; f_index++) { + this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[f_index]; + // Coords ray_position_geometry_rotated = rot_apply(this_focus_data.absolute_rotation, ray_position_geometry); + this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray + } + + printf("calculated forced_length_to_scattering = %lf, new RayAim \n", forced_length_to_scattering); + print_position(direction, "direction"); + print_position(scattering_displacement, "scattering_displacement"); + print_position(forced_ray_scattering_point, "forced_ray_scattering_point"); + print_position(ray_position_geometry, "ray_position_geometry"); + print_position(this_focus_data->RayAim, "this_focus_data->RayAim"); + */ - } else { - forced_length_to_scattering = -1.0; // Signals that no forcing needed, could also if on the selected process struct - } + } else { + forced_length_to_scattering = -1.0; // Signals that no forcing needed, could also if on the selected process struct + } - int p_index; - for (p_index=0; p_index < Volumes[current_volume]->p_physics->number_of_processes; p_index++ ){ // GPU + int p_index; + for (p_index=0; p_index < Volumes[current_volume]->p_physics->number_of_processes; p_index++ ){ // GPU - // Find correct focus_data_array index for this volume/process - focus_data_index = Volumes[current_volume]->geometry.focus_array_indices.elements[p_index]; - this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[focus_data_index]; + // Find correct focus_data_array index for this volume/process + focus_data_index = Volumes[current_volume]->geometry.focus_array_indices.elements[p_index]; + this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[focus_data_index]; - if (Volumes[current_volume]->p_physics->p_scattering_array[p_index].non_isotropic_rot_index != -1) { - // If the process is not isotropic, the wavevector is transformed into the local coordinate system of the process - int non_isotropic_rot_index = Volumes[current_volume]->p_physics->p_scattering_array[p_index].non_isotropic_rot_index; - wavevector_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[non_isotropic_rot_index],wavevector); - coords_get(wavevector_rotated,&k_rotated[0],&k_rotated[1],&k_rotated[2]); + if (Volumes[current_volume]->p_physics->p_scattering_array[p_index].non_isotropic_rot_index != -1) { + // If the process is not isotropic, the wavevector is transformed into the local coordinate system of the process + int non_isotropic_rot_index = Volumes[current_volume]->p_physics->p_scattering_array[p_index].non_isotropic_rot_index; + wavevector_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[non_isotropic_rot_index],wavevector); + coords_get(wavevector_rotated,&k_rotated[0],&k_rotated[1],&k_rotated[2]); - if (Volumes[current_volume]->p_physics->p_scattering_array[p_index].needs_cross_section_focus == 1) { - // Prepare focus data using ray_position_geometry of forced scattering point which will be prepared if any process needs cross_section time focusing - Coords ray_position_geometry_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[non_isotropic_rot_index], ray_position_geometry); - this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry_rotated); // Aim vector for this ray - #ifdef Union_trace_verbal_setting - printf("Checking process number : %d, it was not isotropic, so RayAim updated \n",p_index); - print_position(ray_position_geometry, "ray_position_geometry"); - print_position(ray_position_geometry_rotated, "ray_position_geometry_rotated"); - print_position(this_focus_data->RayAim, "this_focus_data->RayAim"); - #endif + if (Volumes[current_volume]->p_physics->p_scattering_array[p_index].needs_cross_section_focus == 1) { + // Prepare focus data using ray_position_geometry of forced scattering point which will be prepared if any process needs cross_section time focusing + Coords ray_position_geometry_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[non_isotropic_rot_index], ray_position_geometry); + this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry_rotated); // Aim vector for this ray + #ifdef Union_trace_verbal_setting + printf("Checking process number : %d, it was not isotropic, so RayAim updated \n",p_index); + print_position(ray_position_geometry, "ray_position_geometry"); + print_position(ray_position_geometry_rotated, "ray_position_geometry_rotated"); + print_position(this_focus_data->RayAim, "this_focus_data->RayAim"); + #endif - } - - } else { - k_rotated[0] = k[0]; k_rotated[1] = k[1]; k_rotated[2] = k[2]; - // focus_data RayAim already updated for non isotropic processes - } - /* - Plan for adding in inhomogenous processes: - - The processes will have a flag, that checks if they require - numerical integration. - - If they do, then we use a numerical integration algorithm, - where we sample my from the process at different points. - We then assume that each mu has a distance around itself - that it is "correct" for, i.e the mu distribution is uniform - around the mu. - - Then each of these mu now have a smaller distance than length_to_boundary - and we must therefore weight each in my_sum with the normalized length they posses. - i.e if length_to_boundary is divided into 10, divide each mu by 10. - - For the sampling, we must then sample with the cumulative - probability function, which we calculate for each small bit of - the inhomogenous process. - */ + } + + } else { + k_rotated[0] = k[0]; k_rotated[1] = k[1]; k_rotated[2] = k[2]; + // focus_data RayAim already updated for non isotropic processes + } + /* + Plan for adding in inhomogenous processes: + - The processes will have a flag, that checks if they require + numerical integration. + - If they do, then we use a numerical integration algorithm, + where we sample my from the process at different points. + We then assume that each mu has a distance around itself + that it is "correct" for, i.e the mu distribution is uniform + around the mu. + - Then each of these mu now have a smaller distance than length_to_boundary + and we must therefore weight each in my_sum with the normalized length they posses. + i.e if length_to_boundary is divided into 10, divide each mu by 10. + - For the sampling, we must then sample with the cumulative + probability function, which we calculate for each small bit of + the inhomogenous process. + */ - // Call the probability for scattering function assighed to this specific procress (the process pointer is updated in the for loop) - process = &Volumes[current_volume]->p_physics->p_scattering_array[p_index]; // GPU Allowed + // Call the probability for scattering function assighed to this specific procress (the process pointer is updated in the for loop) + process = &Volumes[current_volume]->p_physics->p_scattering_array[p_index]; // GPU Allowed - int physics_output; - physics_output = physics_my(process->eProcess, p_my_trace, k_rotated, process->data_transfer, this_focus_data, _particle); + int physics_output; + physics_output = physics_my(process->eProcess, p_my_trace, k_rotated, process->data_transfer, this_focus_data, _particle); - my_sum += *p_my_trace; - #ifdef Union_trace_verbal_setting - printf("my_trace = %f, my_sum = %f\n",*p_my_trace,my_sum); - #endif - // increment the pointers so that it point to the next element (max number of process in any material is allocated) - p_my_trace++; - } + my_sum += *p_my_trace; + #ifdef Union_trace_verbal_setting + printf("my_trace = %f, my_sum = %f\n",*p_my_trace,my_sum); + #endif + // increment the pointers so that it point to the next element (max number of process in any material is allocated) + p_my_trace++; + } - #ifdef Union_trace_verbal_setting - printf("time_propagated_without_scattering = %f.\n",time_propagated_without_scattering); - printf("v_length = %f.\n",v_length); - printf("exp(- length_to_boundary*my_sum) = %f. length_to_boundary = %f. my_sum = %f.\n",exp(-length_to_boundary*my_sum),length_to_boundary,my_sum); - #endif + #ifdef Union_trace_verbal_setting + printf("time_propagated_without_scattering = %f.\n",time_propagated_without_scattering); + printf("v_length = %f.\n",v_length); + printf("exp(- length_to_boundary*my_sum) = %f. length_to_boundary = %f. my_sum = %f.\n",exp(-length_to_boundary*my_sum),length_to_boundary,my_sum); + #endif - my_sum_plus_abs = my_sum + Volumes[current_volume]->p_physics->my_a*(2200/v_length); + my_sum_plus_abs = my_sum + Volumes[current_volume]->p_physics->my_a*(2200/v_length); - // New flow:length_to_boundary + // New flow:length_to_boundary - // Calculate if scattering happens based on my_sub_plus_abs - if (my_sum < 1E-18) { - scattering_event = 0; - } else if (length_to_boundary < safety_distance2) { - scattering_event = 0; - } else { - real_transmission_probability = exp(-length_to_boundary*my_sum_plus_abs); - if (Volumes[current_volume]->geometry.geometry_p_interact != 0) { - mc_transmission_probability = (1.0 - Volumes[current_volume]->geometry.geometry_p_interact); - if ((scattering_event = (rand01() > mc_transmission_probability))) { - // Scattering event happens, this is the correction for the weight - p *= (1.0-real_transmission_probability)/(1.0-mc_transmission_probability); - } else { - // Scattering event does not happen, this is the appropriate correction - p *= real_transmission_probability/mc_transmission_probability; - } - } else { - // probability to scatter is the natural value - scattering_event = rand01() > real_transmission_probability; - } - } + // Calculate if scattering happens based on my_sub_plus_abs + if (my_sum < 1E-18) { + scattering_event = 0; + } else if (length_to_boundary < safety_distance2) { + scattering_event = 0; + } else { + real_transmission_probability = exp(-length_to_boundary*my_sum_plus_abs); + if (Volumes[current_volume]->geometry.geometry_p_interact != 0) { + mc_transmission_probability = (1.0 - Volumes[current_volume]->geometry.geometry_p_interact); + if ((scattering_event = (rand01() > mc_transmission_probability))) { + // Scattering event happens, this is the correction for the weight + p *= (1.0-real_transmission_probability)/(1.0-mc_transmission_probability); + } else { + // Scattering event does not happen, this is the appropriate correction + p *= real_transmission_probability/mc_transmission_probability; + } + } else { + // probability to scatter is the natural value + scattering_event = rand01() > real_transmission_probability; + } + } - // If scattering happens - if (scattering_event == 1) { - // Select scattering process + // If scattering happens + if (scattering_event == 1) { + // Select scattering process - // Adjust weight for absorption - abs_weight_factor *= my_sum/my_sum_plus_abs; - abs_weight_factor_set = 1; - // Safety feature, alert in case of nonsense my results / negative absorption - if (my_sum/my_sum_plus_abs > 1.0) printf("WARNING: Absorption weight factor above 1! Should not happen! \n"); - // Select process - if (Volumes[current_volume]->p_physics->number_of_processes == 1) { // trivial case - // Select the only available process, which will always have index 0 - selected_process = 0; - } else { - if (Volumes[current_volume]->p_physics->interact_control == 1) { - // Interact_fraction is used to influence the choice of process in this material - mc_prop = rand01();culmative_probability=0;total_process_interact=1.0; + // Adjust weight for absorption + abs_weight_factor *= my_sum/my_sum_plus_abs; + abs_weight_factor_set = 1; + // Safety feature, alert in case of nonsense my results / negative absorption + if (my_sum/my_sum_plus_abs > 1.0) printf("WARNING: Absorption weight factor above 1! Should not happen! \n"); + // Select process + if (Volumes[current_volume]->p_physics->number_of_processes == 1) { // trivial case + // Select the only available process, which will always have index 0 + selected_process = 0; + } else { + if (Volumes[current_volume]->p_physics->interact_control == 1) { + // Interact_fraction is used to influence the choice of process in this material + mc_prop = rand01();culmative_probability=0;total_process_interact=1.0; - // If any of the processes have probability 0, they are excluded from the selection - for (iterator = 0;iterator < Volumes[current_volume]->p_physics->number_of_processes;iterator++) { - if (my_trace[iterator] < 1E-18) { - // When this happens, the total force probability is corrected and the probability for this particular instance is set to 0 - total_process_interact -= Volumes[current_volume]->p_physics->p_scattering_array[iterator].process_p_interact; - my_trace_fraction_control[iterator] = 0; - // In cases where my_trace is not zero, the forced fraction is still used. - } else my_trace_fraction_control[iterator] = Volumes[current_volume]->p_physics->p_scattering_array[iterator].process_p_interact; - } - // Randomly select a process using the weights stored in my_trace_fraction_control divided by total_process_interact - for (iterator = 0;iterator < Volumes[current_volume]->p_physics->number_of_processes;iterator++) { - culmative_probability += my_trace_fraction_control[iterator]/total_process_interact; - if (culmative_probability > mc_prop) { - selected_process = iterator; - p *= (my_trace[iterator]/my_sum)*(total_process_interact/my_trace_fraction_control[iterator]); - break; - } - } + // If any of the processes have probability 0, they are excluded from the selection + for (iterator = 0;iterator < Volumes[current_volume]->p_physics->number_of_processes;iterator++) { + if (my_trace[iterator] < 1E-18) { + // When this happens, the total force probability is corrected and the probability for this particular instance is set to 0 + total_process_interact -= Volumes[current_volume]->p_physics->p_scattering_array[iterator].process_p_interact; + my_trace_fraction_control[iterator] = 0; + // In cases where my_trace is not zero, the forced fraction is still used. + } else my_trace_fraction_control[iterator] = Volumes[current_volume]->p_physics->p_scattering_array[iterator].process_p_interact; + } + // Randomly select a process using the weights stored in my_trace_fraction_control divided by total_process_interact + for (iterator = 0;iterator < Volumes[current_volume]->p_physics->number_of_processes;iterator++) { + culmative_probability += my_trace_fraction_control[iterator]/total_process_interact; + if (culmative_probability > mc_prop) { + selected_process = iterator; + p *= (my_trace[iterator]/my_sum)*(total_process_interact/my_trace_fraction_control[iterator]); + break; + } + } - } else { - // Select a process based on their relative attenuations factors - mc_prop = rand01();culmative_probability=0; - for (iterator = 0;iterator < Volumes[current_volume]->p_physics->number_of_processes;iterator++) { - culmative_probability += my_trace[iterator]/my_sum; - if (culmative_probability > mc_prop) { - selected_process = iterator; - break; - } - } - } - } + } else { + // Select a process based on their relative attenuations factors + mc_prop = rand01();culmative_probability=0; + for (iterator = 0;iterator < Volumes[current_volume]->p_physics->number_of_processes;iterator++) { + culmative_probability += my_trace[iterator]/my_sum; + if (culmative_probability > mc_prop) { + selected_process = iterator; + break; + } + } + } + } - // Select distance to scattering position - if (Volumes[current_volume]->p_physics->p_scattering_array[selected_process].needs_cross_section_focus == 1) { - // Respect forced length to scattering chosen by process - length_to_scattering = forced_length_to_scattering; - // Drawing between 0 and L from constant s = 1/L and should have been q = A*exp(-kz). - // Normalizing A*exp(-kz) over 0 to L: A = k/(1-exp(-k*L)) - // Weight correction is ratio between s and q, L*A*exp(-kz) = L*k*exp(-kz)/(1-exp(-Lk)) - p *= length_to_boundary*my_sum_plus_abs*exp(-length_to_scattering*my_sum_plus_abs)/(1.0 - exp(-length_to_boundary*my_sum_plus_abs)); - #ifdef Union_trace_verbal_setting - printf("Used forced length to scattering, %lf \n", length_to_scattering); - #endif + // Select distance to scattering position + if (Volumes[current_volume]->p_physics->p_scattering_array[selected_process].needs_cross_section_focus == 1) { + // Respect forced length to scattering chosen by process + length_to_scattering = forced_length_to_scattering; + // Drawing between 0 and L from constant s = 1/L and should have been q = A*exp(-kz). + // Normalizing A*exp(-kz) over 0 to L: A = k/(1-exp(-k*L)) + // Weight correction is ratio between s and q, L*A*exp(-kz) = L*k*exp(-kz)/(1-exp(-Lk)) + p *= length_to_boundary*my_sum_plus_abs*exp(-length_to_scattering*my_sum_plus_abs)/(1.0 - exp(-length_to_boundary*my_sum_plus_abs)); + #ifdef Union_trace_verbal_setting + printf("Used forced length to scattering, %lf \n", length_to_scattering); + #endif - } else { - // Decided the ray scatters, choose where on truncated exponential from safety_distance to length_to_boundary - safety_distance - length_to_scattering = safety_distance - log(1.0 - rand0max((1.0 - exp(-my_sum_plus_abs*(length_to_boundary-safety_distance2))))) / my_sum_plus_abs; - #ifdef Union_trace_verbal_setting - printf("Sampled length to scattering, %lf \n", length_to_scattering); - #endif - } + } else { + // Decided the ray scatters, choose where on truncated exponential from safety_distance to length_to_boundary - safety_distance + length_to_scattering = safety_distance - log(1.0 - rand0max((1.0 - exp(-my_sum_plus_abs*(length_to_boundary-safety_distance2))))) / my_sum_plus_abs; + #ifdef Union_trace_verbal_setting + printf("Sampled length to scattering, %lf \n", length_to_scattering); + #endif + } - } // Done handling scattering + } // Done handling scattering - } // Done handling situation where there are scattering processes in the material + } // Done handling situation where there are scattering processes in the material - } // Done checking for scttering event and in case of scattering selecting a process + } // Done checking for scttering event and in case of scattering selecting a process - // Record initial weight, absorption weight factor and initial position + // Record initial weight, absorption weight factor and initial position - initial_weight = p; - r_old[0] = r[0]; r_old[1] = r[1]; r_old[2] = r[2]; time_old = t; - // Apply absorption - p *= abs_weight_factor; + initial_weight = p; + r_old[0] = r[0]; r_old[1] = r[1]; r_old[2] = r[2]; time_old = t; + // Apply absorption + p *= abs_weight_factor; - // Create event for absorption loggers - // Need to use start position and length travelled to sample that trajectory for absorption event. Could do several, here just one. + // Create event for absorption loggers + // Need to use start position and length travelled to sample that trajectory for absorption event. Could do several, here just one. - // min length: 0, max length: length_to_scattering if scattering, else length to boundary + // min length: 0, max length: length_to_scattering if scattering, else length to boundary - // Avoid logging absorption when the ray is in vacuum. - if (current_volume != 0 && abs_weight_factor_set == 1) { // Volume 0 is always vacuum, and if this is the current volume, an event will not occur - if (Volumes[current_volume]->p_physics->is_vacuum == 0) { // No absorption in vacuum + // Avoid logging absorption when the ray is in vacuum. + if (current_volume != 0 && abs_weight_factor_set == 1) { // Volume 0 is always vacuum, and if this is the current volume, an event will not occur + if (Volumes[current_volume]->p_physics->is_vacuum == 0) { // No absorption in vacuum - if (scattering_event == 1) { - // When scattering events occur, place the absoprtion the same place (the total cross section is used to place it) - abs_distance = length_to_scattering; - } else { - // When the ray exits a volume, the absorption position should be exponentially distributed using the total cross section - my_abs = Volumes[current_volume]->p_physics->my_a*(2200/v_length); - abs_distance = -log(1.0 - rand0max(1.0 - exp(-my_sum_plus_abs*length_to_boundary)) ) / my_sum_plus_abs; - } + if (scattering_event == 1) { + // When scattering events occur, place the absoprtion the same place (the total cross section is used to place it) + abs_distance = length_to_scattering; + } else { + // When the ray exits a volume, the absorption position should be exponentially distributed using the total cross section + my_abs = Volumes[current_volume]->p_physics->my_a*(2200/v_length); + abs_distance = -log(1.0 - rand0max(1.0 - exp(-my_sum_plus_abs*length_to_boundary)) ) / my_sum_plus_abs; + } - t_abs_propagation = abs_distance/v_length; + t_abs_propagation = abs_distance/v_length; - abs_position = coords_set(x + t_abs_propagation*vx, y + t_abs_propagation*vy, z + t_abs_propagation*vz); + abs_position = coords_set(x + t_abs_propagation*vx, y + t_abs_propagation*vy, z + t_abs_propagation*vz); - // This info needs to be loaded into the absorption loggers + // This info needs to be loaded into the absorption loggers - // Need to run through relevant absorption loggers here - #ifdef Union_trace_verbal_setting - printf("Running abs_logger system for specific volumes \n"); - #endif + // Need to run through relevant absorption loggers here + #ifdef Union_trace_verbal_setting + printf("Running abs_logger system for specific volumes \n"); + #endif - // Logging for detector components assosiated with this volume - for (log_index=0;log_indexabs_loggers.num_elements;log_index++) { - // Make transformation according to the individual position of the abs_logger? This would require position / rotation for all abs_loggers - transformed_abs_position = coords_sub(abs_position, Volumes[current_volume]->abs_loggers.p_abs_logger[log_index]->position); - transformed_abs_position = rot_apply(Volumes[current_volume]->abs_loggers.p_abs_logger[log_index]->rotation, transformed_abs_position); + // Logging for detector components assosiated with this volume + for (log_index=0;log_indexabs_loggers.num_elements;log_index++) { + // Make transformation according to the individual position of the abs_logger? This would require position / rotation for all abs_loggers + transformed_abs_position = coords_sub(abs_position, Volumes[current_volume]->abs_loggers.p_abs_logger[log_index]->position); + transformed_abs_position = rot_apply(Volumes[current_volume]->abs_loggers.p_abs_logger[log_index]->rotation, transformed_abs_position); - // This function calls a logger function which in turn stores some data among the passed, and possibly performs some basic data analysis - Volumes[current_volume]->abs_loggers.p_abs_logger[log_index]->function_pointers.active_record_function(&transformed_abs_position, k_new, initial_weight*(1.0-abs_weight_factor), t + t_abs_propagation, scattered_flag[current_volume], number_of_scattering_events, Volumes[current_volume]->abs_loggers.p_abs_logger[log_index], &abs_loggers_with_data_array); - // If the logging component have a conditional attatched, the collected data will be written to a temporary place - // At the end of the rays life, it will be checked if the condition is met - // if it is met, the temporary data is transfered to permanent, and temp is cleared. - // if it is not met, the temporary data is cleared. - } + // This function calls a logger function which in turn stores some data among the passed, and possibly performs some basic data analysis + Volumes[current_volume]->abs_loggers.p_abs_logger[log_index]->function_pointers.active_record_function(&transformed_abs_position, k_new, initial_weight*(1.0-abs_weight_factor), t + t_abs_propagation, scattered_flag[current_volume], number_of_scattering_events, Volumes[current_volume]->abs_loggers.p_abs_logger[log_index], &abs_loggers_with_data_array); + // If the logging component have a conditional attatched, the collected data will be written to a temporary place + // At the end of the rays life, it will be checked if the condition is met + // if it is met, the temporary data is transfered to permanent, and temp is cleared. + // if it is not met, the temporary data is cleared. + } - #ifdef Union_trace_verbal_setting - printf("Running abs_logger system for all volumes \n"); - #endif - for (log_index=0;log_indexnum_elements;log_index++) { - // As above, but on a global scale, meaning scattering in all volumes are logged + #ifdef Union_trace_verbal_setting + printf("Running abs_logger system for all volumes \n"); + #endif + for (log_index=0;log_indexnum_elements;log_index++) { + // As above, but on a global scale, meaning scattering in all volumes are logged - // Problems with VN, PV, as there is no assosiated volume or process. The functions however need to have the same input to make the logger components general. - // Could be interesting to have a monitor that just globally measurres the second scattering event in any volume (must be two in the same). Weird but not meaningless. + // Problems with VN, PV, as there is no assosiated volume or process. The functions however need to have the same input to make the logger components general. + // Could be interesting to have a monitor that just globally measurres the second scattering event in any volume (must be two in the same). Weird but not meaningless. - // Make transformation according to the individual position of the abs_logger? This would require position / rotation for all abs_loggers - transformed_abs_position = coords_sub(abs_position, global_all_volume_abs_logger_list_master->elements[log_index].abs_logger->position); - transformed_abs_position = rot_apply(global_all_volume_abs_logger_list_master->elements[log_index].abs_logger->rotation, transformed_abs_position); + // Make transformation according to the individual position of the abs_logger? This would require position / rotation for all abs_loggers + transformed_abs_position = coords_sub(abs_position, global_all_volume_abs_logger_list_master->elements[log_index].abs_logger->position); + transformed_abs_position = rot_apply(global_all_volume_abs_logger_list_master->elements[log_index].abs_logger->rotation, transformed_abs_position); - // Above version includes scattered_flag_VP, but selected_process may be undefined at this point. - global_all_volume_abs_logger_list_master->elements[log_index].abs_logger->function_pointers.active_record_function(&transformed_abs_position, k_new, initial_weight*(1.0-abs_weight_factor), t+t_abs_propagation, scattered_flag[current_volume], number_of_scattering_events, global_all_volume_abs_logger_list_master->elements[log_index].abs_logger, &abs_loggers_with_data_array); + // Above version includes scattered_flag_VP, but selected_process may be undefined at this point. + global_all_volume_abs_logger_list_master->elements[log_index].abs_logger->function_pointers.active_record_function(&transformed_abs_position, k_new, initial_weight*(1.0-abs_weight_factor), t+t_abs_propagation, scattered_flag[current_volume], number_of_scattering_events, global_all_volume_abs_logger_list_master->elements[log_index].abs_logger, &abs_loggers_with_data_array); + } + } } - } - } - if (scattering_event == 1) { - #ifdef Union_trace_verbal_setting - printf("SCATTERING EVENT \n"); - printf("current_volume = %d \n", current_volume); - printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", r[0], r[1], r[2], v[0], v[1], v[2]); - #endif + if (scattering_event == 1) { + #ifdef Union_trace_verbal_setting + printf("SCATTERING EVENT \n"); + printf("current_volume = %d \n", current_volume); + printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", r[0], r[1], r[2], v[0], v[1], v[2]); + #endif - // Calculate the time to scattering - time_to_scattering = length_to_scattering/v_length; + // Calculate the time to scattering + time_to_scattering = length_to_scattering/v_length; - #ifdef Union_trace_verbal_setting - printf("time to scattering = %2.20f \n",time_to_scattering); - printf("length to boundery = %f, length to scattering = %f \n",length_to_boundary,length_to_scattering); - #endif + #ifdef Union_trace_verbal_setting + printf("time to scattering = %2.20f \n",time_to_scattering); + printf("length to boundery = %f, length to scattering = %f \n",length_to_boundary,length_to_scattering); + #endif - // May be replace by version without gravity - //PROP_DT(time_to_scattering); + // May be replace by version without gravity + //PROP_DT(time_to_scattering); - // Reduce the double book keeping done here - x += time_to_scattering*vx; y += time_to_scattering*vy; z += time_to_scattering*vz; t += time_to_scattering; - r_start[0] = x; r_start[1] = y; r_start[2] = z; - r[0] = x; r[1] = y; r[2] = z; - ray_position = coords_set(x,y,z); - ray_velocity = coords_set(vx,vy,vz); + // Reduce the double book keeping done here + x += time_to_scattering*vx; y += time_to_scattering*vy; z += time_to_scattering*vz; t += time_to_scattering; + r_start[0] = x; r_start[1] = y; r_start[2] = z; + r[0] = x; r[1] = y; r[2] = z; + ray_position = coords_set(x,y,z); + ray_velocity = coords_set(vx,vy,vz); - // Safe check that should be unecessary. Used to fine tune how close to the edge of a volume a scattering event is allowed to take place (1E-14 m away currently). - if (r_within_function(ray_position, &Volumes[current_volume]->geometry) == 0) { - printf("\nERROR, propagated out of current volume instead of to a point within!\n"); - printf("length_to_scattering_specified = %2.20f\n length propagated = %2.20f\n length_to_boundary = %2.20f \n current_position = (%lf,%lf,%lf) \n",length_to_scattering,sqrt(time_to_scattering*time_to_scattering*vx*vx+time_to_scattering*time_to_scattering*vy*vy+time_to_scattering*time_to_scattering*vz*vz),length_to_boundary,x,y,z); + // Safe check that should be unecessary. Used to fine tune how close to the edge of a volume a scattering event is allowed to take place (1E-14 m away currently). + if (r_within_function(ray_position, &Volumes[current_volume]->geometry) == 0) { + printf("\nERROR, propagated out of current volume instead of to a point within!\n"); + printf("length_to_scattering_specified = %2.20f\n length propagated = %2.20f\n length_to_boundary = %2.20f \n current_position = (%lf,%lf,%lf) \n",length_to_scattering,sqrt(time_to_scattering*time_to_scattering*vx*vx+time_to_scattering*time_to_scattering*vy*vy+time_to_scattering*time_to_scattering*vz*vz),length_to_boundary,x,y,z); - volume_index = within_which_volume_GPU(ray_position,starting_lists.reduced_start_list,starting_lists.starting_destinations_list,Volumes,&mask_status_list,number_of_volumes,pre_allocated1,pre_allocated2,pre_allocated3); + volume_index = within_which_volume_GPU(ray_position,starting_lists.reduced_start_list,starting_lists.starting_destinations_list,Volumes,&mask_status_list,number_of_volumes,pre_allocated1,pre_allocated2,pre_allocated3); - printf("Debug info: Volumes[current_volume]->name = %s, but now inside volume number %d named %s.\n",Volumes[current_volume]->name,volume_index,Volumes[volume_index]->name); - printf("Ray absorbed \n"); - ABSORB; - } + printf("Debug info: Volumes[current_volume]->name = %s, but now inside volume number %d named %s.\n",Volumes[current_volume]->name,volume_index,Volumes[volume_index]->name); + printf("Ray absorbed \n"); + ABSORB; + } - // Save information before scattering event needed in logging section - p_old = p; - k_old[0] = k[0];k_old[1] = k[1];k_old[2] = k[2]; + // Save information before scattering event needed in logging section + p_old = p; + k_old[0] = k[0];k_old[1] = k[1];k_old[2] = k[2]; - // Find correct focus_data_array index for this volume/process and correct for ray position - focus_data_index = Volumes[current_volume]->geometry.focus_array_indices.elements[selected_process]; - this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[focus_data_index]; + // Find correct focus_data_array index for this volume/process and correct for ray position + focus_data_index = Volumes[current_volume]->geometry.focus_array_indices.elements[selected_process]; + this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[focus_data_index]; - Coords ray_position_geometry = coords_sub(ray_position, Volumes[current_volume]->geometry.center); // ray_position relative to geometry center + Coords ray_position_geometry = coords_sub(ray_position, Volumes[current_volume]->geometry.center); // ray_position relative to geometry center - this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray + this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray - // Rotation to local process coordinate system (for non isotropic processes) - if (Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index != -1) { - ray_velocity_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index],ray_velocity); + // Rotation to local process coordinate system (for non isotropic processes) + if (Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index != -1) { + ray_velocity_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index],ray_velocity); - Coords ray_position_geometry_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index],ray_position_geometry); - this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry_rotated); // Aim vector for this ray - } else { - ray_velocity_rotated = ray_velocity; - this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray - } - #ifdef Union_trace_verbal_setting - printf("Kin: %g %g %g, selected_process: %i %i\n",k[0],k[1],k[2],selected_process,current_volume); - coords_print(Volumes[current_volume]->geometry.focus_data_array.elements[0].Aim); - #endif - // test_physics_scattering(double *k_final, double *k_initial, union data_transfer_union data_transfer) { - coords_get(coords_scalar_mult(ray_velocity_rotated,V2K), &k[0], &k[1], &k[2]); + Coords ray_position_geometry_rotated = rot_apply(Volumes[current_volume]->geometry.process_rot_matrix_array[Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index],ray_position_geometry); + this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry_rotated); // Aim vector for this ray + } else { + ray_velocity_rotated = ray_velocity; + this_focus_data->RayAim = coords_sub(this_focus_data->Aim, ray_position_geometry); // Aim vector for this ray + } + #ifdef Union_trace_verbal_setting + printf("Kin: %g %g %g, selected_process: %i %i\n",k[0],k[1],k[2],selected_process,current_volume); + coords_print(Volumes[current_volume]->geometry.focus_data_array.elements[0].Aim); + #endif + // test_physics_scattering(double *k_final, double *k_initial, union data_transfer_union data_transfer) { + coords_get(coords_scalar_mult(ray_velocity_rotated,V2K), &k[0], &k[1], &k[2]); - // I may replace a intial and final k with one instance that serves as both input and output - process = &Volumes[current_volume]->p_physics->p_scattering_array[selected_process]; // CPU Only - if (0 == physics_scattering(process->eProcess, k_new, k, &p, process->data_transfer, this_focus_data, _particle)) { - /* - // PowderN and Single_crystal requires the option of absorbing the neutron, which is weird. If there is a scattering probability, there should be a new direction. - // It can arise from need to simplify sampling process and end up in cases where weight factor is 0, and the ray should be absorbed in these cases - printf("ERROR: Union_master: %s.Absorbed ray because scattering function returned 0 (error/absorb)\n",NAME_CURRENT_COMP); - component_error_msg++; - if (component_error_msg > 100) { - printf("To many errors encountered, exiting. \n"); - exit(1); - } - */ - ABSORB; - } - #ifdef Union_trace_verbal_setting - printf("Kout: %g %g %g\n", k_new[0],k_new[1],k_new[2]); - #endif - // Update velocity using k - ray_velocity_rotated = coords_set(K2V*k_new[0],K2V*k_new[1],K2V*k_new[2]); + // I may replace a intial and final k with one instance that serves as both input and output + process = &Volumes[current_volume]->p_physics->p_scattering_array[selected_process]; // CPU Only + if (0 == physics_scattering(process->eProcess, k_new, k, &p, process->data_transfer, this_focus_data, _particle)) { + /* + // PowderN and Single_crystal requires the option of absorbing the neutron, which is weird. If there is a scattering probability, there should be a new direction. + // It can arise from need to simplify sampling process and end up in cases where weight factor is 0, and the ray should be absorbed in these cases + printf("ERROR: Union_master: %s.Absorbed ray because scattering function returned 0 (error/absorb)\n",NAME_CURRENT_COMP); + component_error_msg++; + if (component_error_msg > 100) { + printf("To many errors encountered, exiting. \n"); + exit(1); + } + */ + ABSORB; + } + #ifdef Union_trace_verbal_setting + printf("Kout: %g %g %g\n", k_new[0],k_new[1],k_new[2]); + #endif + // Update velocity using k + ray_velocity_rotated = coords_set(K2V*k_new[0],K2V*k_new[1],K2V*k_new[2]); - // Transformation back to main coordinate system (maybe one should only do this when multiple scattering in that volume was over, especially if there is only one non isotropic frame) - if (Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index != -1) { - ray_velocity_final = rot_apply(Volumes[current_volume]->geometry.transpose_process_rot_matrix_array[Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index],ray_velocity_rotated); - } else { - ray_velocity_final = ray_velocity_rotated; - } - #ifdef Union_trace_verbal_setting - printf("Final velocity vector "); coords_print(ray_velocity_final); - #endif - // Write velocity to global variable (temp, only really necessary at final) - coords_get(ray_velocity_final, &vx, &vy, &vz); + // Transformation back to main coordinate system (maybe one should only do this when multiple scattering in that volume was over, especially if there is only one non isotropic frame) + if (Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index != -1) { + ray_velocity_final = rot_apply(Volumes[current_volume]->geometry.transpose_process_rot_matrix_array[Volumes[current_volume]->p_physics->p_scattering_array[selected_process].non_isotropic_rot_index],ray_velocity_rotated); + } else { + ray_velocity_final = ray_velocity_rotated; + } + #ifdef Union_trace_verbal_setting + printf("Final velocity vector "); coords_print(ray_velocity_final); + #endif + // Write velocity to global variable (temp, only really necessary at final) + coords_get(ray_velocity_final, &vx, &vy, &vz); - // Write velocity in array format as it is still used by intersect functions (temp, they need to be updated to ray_position / ray_velocity) - v[0] = vx; v[1] = vy; v[2] = vz; - v_length = sqrt(vx*vx+vy*vy+vz*vz); - k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; - if (verbal) if (v_length < 1) printf("velocity set to less than 1\n"); - ray_velocity = coords_set(vx,vy,vz); + // Write velocity in array format as it is still used by intersect functions (temp, they need to be updated to ray_position / ray_velocity) + v[0] = vx; v[1] = vy; v[2] = vz; + v_length = sqrt(vx*vx+vy*vy+vz*vz); + k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; + if (verbal) if (v_length < 1) printf("velocity set to less than 1\n"); + ray_velocity = coords_set(vx,vy,vz); - #ifdef Union_trace_verbal_setting - printf("Running logger system for specific volumes \n"); - #endif - // Logging for detector components assosiated with this volume - for (log_index=0;log_indexloggers.num_elements;log_index++) { - if (Volumes[current_volume]->loggers.p_logger_volume[log_index].p_logger_process[selected_process] != NULL) { - // Technically the scattering function could edit k, the wavevector before the scattering, even though there would be little point to doing that. - // Could save a secure copy and pass that instead to be certain that no scattering process accidently tampers with the logging. + #ifdef Union_trace_verbal_setting + printf("Running logger system for specific volumes \n"); + #endif + // Logging for detector components assosiated with this volume + for (log_index=0;log_indexloggers.num_elements;log_index++) { + if (Volumes[current_volume]->loggers.p_logger_volume[log_index].p_logger_process[selected_process] != NULL) { + // Technically the scattering function could edit k, the wavevector before the scattering, even though there would be little point to doing that. + // Could save a secure copy and pass that instead to be certain that no scattering process accidently tampers with the logging. - // This function calls a logger function which in turn stores some data among the passed, and possibly performs some basic data analysis - Volumes[current_volume]->loggers.p_logger_volume[log_index].p_logger_process[selected_process]->function_pointers.active_record_function(&ray_position, k_new, k_old, p, p_old, t, scattered_flag[current_volume], scattered_flag_VP[current_volume][selected_process], number_of_scattering_events, Volumes[current_volume]->loggers.p_logger_volume[log_index].p_logger_process[selected_process], &loggers_with_data_array); - // If the logging component have a conditional attatched, the collected data will be written to a temporary place - // At the end of the rays life, it will be checked if the condition is met - // if it is met, the temporary data is transfered to permanent, and temp is cleared. - // if it is not met, the temporary data is cleared. - } - } + // This function calls a logger function which in turn stores some data among the passed, and possibly performs some basic data analysis + Volumes[current_volume]->loggers.p_logger_volume[log_index].p_logger_process[selected_process]->function_pointers.active_record_function(&ray_position, k_new, k_old, p, p_old, t, scattered_flag[current_volume], scattered_flag_VP[current_volume][selected_process], number_of_scattering_events, Volumes[current_volume]->loggers.p_logger_volume[log_index].p_logger_process[selected_process], &loggers_with_data_array); + // If the logging component have a conditional attatched, the collected data will be written to a temporary place + // At the end of the rays life, it will be checked if the condition is met + // if it is met, the temporary data is transfered to permanent, and temp is cleared. + // if it is not met, the temporary data is cleared. + } + } - #ifdef Union_trace_verbal_setting - printf("Running logger system for all volumes \n"); - #endif - for (log_index=0;log_indexnum_elements;log_index++) { - // As above, but on a global scale, meaning scattering in all volumes are logged + #ifdef Union_trace_verbal_setting + printf("Running logger system for all volumes \n"); + #endif + for (log_index=0;log_indexnum_elements;log_index++) { + // As above, but on a global scale, meaning scattering in all volumes are logged - // Problems with VN, PV, as there is no assosiated volume or process. The functions however need to have the same input to make the logger components general. - // Could be interesting to have a monitor that just globally measurres the second scattering event in any volume (must be two in the same). Weird but not meaningless. - global_all_volume_logger_list_master->elements[log_index].logger->function_pointers.active_record_function(&ray_position, k_new, k_old, p, p_old, t, scattered_flag[current_volume], scattered_flag_VP[current_volume][selected_process], number_of_scattering_events, global_all_volume_logger_list_master->elements[log_index].logger, &loggers_with_data_array); - } - #ifdef Union_trace_verbal_setting - printf("Outgoing event: %g %g %g // %g %g %g\n",x,y,z,vx,vy,vz); - #endif - SCATTER; - ++number_of_scattering_events; - ++scattered_flag[current_volume]; - ++scattered_flag_VP[current_volume][selected_process]; + // Problems with VN, PV, as there is no assosiated volume or process. The functions however need to have the same input to make the logger components general. + // Could be interesting to have a monitor that just globally measurres the second scattering event in any volume (must be two in the same). Weird but not meaningless. + global_all_volume_logger_list_master->elements[log_index].logger->function_pointers.active_record_function(&ray_position, k_new, k_old, p, p_old, t, scattered_flag[current_volume], scattered_flag_VP[current_volume][selected_process], number_of_scattering_events, global_all_volume_logger_list_master->elements[log_index].logger, &loggers_with_data_array); + } + #ifdef Union_trace_verbal_setting + printf("Outgoing event: %g %g %g // %g %g %g\n",x,y,z,vx,vy,vz); + #endif + SCATTER; + ++number_of_scattering_events; + ++scattered_flag[current_volume]; + ++scattered_flag_VP[current_volume][selected_process]; - // Clear intersection time lists as the direction of the ray has changed - clear_intersection_table(&intersection_time_table); - time_propagated_without_scattering = 0.0; - #ifdef Union_trace_verbal_setting - printf("SCATTERED SUCSSESFULLY \n"); - printf("r = (%f,%f,%f) v = (%f,%f,%f) \n",x,y,z,vx,vy,vz); + // Clear intersection time lists as the direction of the ray has changed + clear_intersection_table(&intersection_time_table); + time_propagated_without_scattering = 0.0; + #ifdef Union_trace_verbal_setting + printf("SCATTERED SUCSSESFULLY \n"); + printf("r = (%f,%f,%f) v = (%f,%f,%f) \n",x,y,z,vx,vy,vz); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new process node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("Before new process node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + if (enable_tagging && stop_tagging_ray == 0) printf("Before new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); + #endif - if (enable_tagging && stop_tagging_ray == 0) - current_tagging_node = goto_process_node(current_tagging_node, selected_process,Volumes[current_volume], &stop_tagging_ray,stop_creating_nodes); + if (enable_tagging && stop_tagging_ray == 0) + current_tagging_node = goto_process_node(current_tagging_node, selected_process,Volumes[current_volume], &stop_tagging_ray,stop_creating_nodes); - #ifdef Union_trace_verbal_setting + #ifdef Union_trace_verbal_setting - if (enable_tagging && stop_tagging_ray == 0) printf("After new process node: current_tagging_node->intensity = %f\n", current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("After new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("After new process node: current_tagging_node->intensity = %f\n", current_tagging_node->intensity); + if (enable_tagging && stop_tagging_ray == 0) printf("After new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); + #endif - } else { - previous_volume = current_volume; // Record the current volume as previous, as this will change in this branch of the code + } else { + previous_volume = current_volume; // Record the current volume as previous, as this will change in this branch of the code - #ifdef Union_trace_verbal_setting - printf("Propagate out of volume %d\n", current_volume); - printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); - #endif - // Propagate neutron to found minimum time - // PROP_DT(time_to_boundery); - x += time_to_boundery*vx; - y += time_to_boundery*vy; - z += time_to_boundery*vz; - t += time_to_boundery; - r[0] = x; r[1] = y; r[2] = z; - ray_position = coords_set(x,y,z); - ray_velocity = coords_set(vx,vy,vz); - - time_propagated_without_scattering = min_intersection_time; - SCATTER; // For debugging purposes - #ifdef Union_trace_verbal_setting - printf("r = (%f,%f,%f) v = (%f,%f,%f) \n",x,y,z,vx,vy,vz); - #endif - // Remove this entry from the intersection_time_table - intersection_time_table.intersection_times[min_volume][min_solution] = -1; + #ifdef Union_trace_verbal_setting + printf("Propagate out of volume %d\n", current_volume); + printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); + #endif + // Propagate neutron to found minimum time + // PROP_DT(time_to_boundery); + x += time_to_boundery*vx; + y += time_to_boundery*vy; + z += time_to_boundery*vz; + t += time_to_boundery; + r[0] = x; r[1] = y; r[2] = z; + ray_position = coords_set(x,y,z); + ray_velocity = coords_set(vx,vy,vz); - // Use destination list for corresponding intersection entry n,i) to find next volume - #ifdef Union_trace_verbal_setting - printf("PROPAGATION FROM VOLUME %d \n",current_volume); - #endif - if (min_volume == current_volume) { + time_propagated_without_scattering = min_intersection_time; + SCATTER; // For debugging purposes #ifdef Union_trace_verbal_setting - printf("min_volume == current_volume \n"); + printf("r = (%f,%f,%f) v = (%f,%f,%f) \n",x,y,z,vx,vy,vz); #endif - // List approach to finding the next volume. - // When the ray intersects the current volume, the next volume must be on the destination list of the current volume - // However, the reduced_destination_list can be investigated first, and depending on the results, the - // direct children of the volumes on the reduced destination list are investigated. - // In the worst case, all direct children are investigated, which is eqvivalent to the entire destination list. - // There is however a certain overhead in the logic needed to set up this tree, avoid duplicates of direct children, and so on. - // This method is only faster than just checking the destination list when there are direct children (nested structures), - // but in general the tree method scales better with complexity, and is only slightly slower in simple cases. - - if (Volumes[current_volume]->geometry.destinations_list.num_elements == 1) - tree_next_volume = Volumes[current_volume]->geometry.destinations_list.elements[0]; - else { - ray_position = coords_set(x,y,z); - ray_velocity = coords_set(vx,vy,vz); - tree_next_volume = within_which_volume_GPU(ray_position,Volumes[current_volume]->geometry.reduced_destinations_list,Volumes[current_volume]->geometry.destinations_list,Volumes,&mask_status_list,number_of_volumes,pre_allocated1,pre_allocated2,pre_allocated3); - } - + // Remove this entry from the intersection_time_table + intersection_time_table.intersection_times[min_volume][min_solution] = -1; + + // Use destination list for corresponding intersection entry n,i) to find next volume #ifdef Union_trace_verbal_setting - if (enable_tagging) printf("tree method moves from %d to %d\n",current_volume,tree_next_volume); - - if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + printf("PROPAGATION FROM VOLUME %d \n",current_volume); #endif + if (min_volume == current_volume) { + #ifdef Union_trace_verbal_setting + printf("min_volume == current_volume \n"); + #endif + // List approach to finding the next volume. + // When the ray intersects the current volume, the next volume must be on the destination list of the current volume + // However, the reduced_destination_list can be investigated first, and depending on the results, the + // direct children of the volumes on the reduced destination list are investigated. + // In the worst case, all direct children are investigated, which is eqvivalent to the entire destination list. + // There is however a certain overhead in the logic needed to set up this tree, avoid duplicates of direct children, and so on. + // This method is only faster than just checking the destination list when there are direct children (nested structures), + // but in general the tree method scales better with complexity, and is only slightly slower in simple cases. - if (enable_tagging && stop_tagging_ray == 0) - current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); + if (Volumes[current_volume]->geometry.destinations_list.num_elements == 1) + tree_next_volume = Volumes[current_volume]->geometry.destinations_list.elements[0]; + else { + ray_position = coords_set(x,y,z); + ray_velocity = coords_set(vx,vy,vz); + tree_next_volume = within_which_volume_GPU(ray_position,Volumes[current_volume]->geometry.reduced_destinations_list,Volumes[current_volume]->geometry.destinations_list,Volumes,&mask_status_list,number_of_volumes,pre_allocated1,pre_allocated2,pre_allocated3); + } + + #ifdef Union_trace_verbal_setting + if (enable_tagging) printf("tree method moves from %d to %d\n",current_volume,tree_next_volume); - #ifdef Union_trace_verbal_setting - if (enable_tagging && stop_tagging_ray == 0) printf("After new tree volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("After new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif - // Set next volume to the solution found in the tree method - current_volume = tree_next_volume; - update_current_mask_intersect_status(¤t_mask_intersect_list_status, &mask_status_list, Volumes, ¤t_volume); - #ifdef Union_trace_verbal_setting - print_1d_int_list(current_mask_intersect_list_status,"Updated current_mask_intersect_list_status"); - #endif + if (enable_tagging && stop_tagging_ray == 0) + current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); - } else { - #ifdef Union_trace_verbal_setting - if (enable_tagging && stop_tagging_ray == 0) printf("Before new intersection volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif + #ifdef Union_trace_verbal_setting + if (enable_tagging && stop_tagging_ray == 0) printf("After new tree volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + if (enable_tagging && stop_tagging_ray == 0) printf("After new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif - // Mask update: If the min_volume is not a mask, things are simple, current_volume = min_volume. - // however, if it is a mask, the mask status will switch. - // if the mask status becomes one, the masked volumes inside may be the next volume (unless they are children of the mask) - // if the mask status becomes zero (and the current volume is masked by min_volume), the destinations list of the mask is searched - // if the mask status becomes zero (and the current volume is NOT masked by min volume), the current volume doesn't change + // Set next volume to the solution found in the tree method + current_volume = tree_next_volume; + update_current_mask_intersect_status(¤t_mask_intersect_list_status, &mask_status_list, Volumes, ¤t_volume); + #ifdef Union_trace_verbal_setting + print_1d_int_list(current_mask_intersect_list_status,"Updated current_mask_intersect_list_status"); + #endif - if (Volumes[min_volume]->geometry.is_mask_volume == 0) { - #ifdef Union_trace_verbal_setting - printf("Min volume is not a mask, next volume = min volume\n"); - #endif - if (enable_tagging && stop_tagging_ray == 0) { - current_tagging_node = goto_volume_node(current_tagging_node, current_volume, min_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); - } - current_volume = min_volume; } else { - #ifdef Union_trace_verbal_setting - printf("Current volume is not a mask, complex decision tree\n"); - #endif - if (mask_status_list.elements[Volumes[min_volume]->geometry.mask_index] == 1) { - // We are leaving the mask, change the status #ifdef Union_trace_verbal_setting - printf("mask status changed from 1 to 0 as a mask is left\n"); - #endif - mask_status_list.elements[Volumes[min_volume]->geometry.mask_index] = 0; - // If the current volume is masked by this mask, run within_which_volume using the masks destination list, otherwise keep the current volume - if (on_int_list(Volumes[current_volume]->geometry.masked_by_list,min_volume) == 1) { - #ifdef Union_trace_verbal_setting - printf("The current volume was masked by this mask, and my need updating\n"); - #endif - // In case of ANY mode, need to see if another mask on the masked_by list of the current volume is active, and if so, nothing happens - need_to_run_within_which_volume = 1; - if (Volumes[current_volume]->geometry.mask_mode == 2) { - for (mask_start=mask_check=Volumes[current_volume]->geometry.masked_by_mask_index_list.elements; mask_check-mask_startgeometry.masked_by_mask_index_list.num_elements; mask_check++) { - if (mask_status_list.elements[*mask_check] == 1) { - // Nothing needs to be done, the effective mask status of the current volume is still 1 - need_to_run_within_which_volume = 0; - break; - } + if (enable_tagging && stop_tagging_ray == 0) printf("Before new intersection volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + if (enable_tagging && stop_tagging_ray == 0) printf("Before new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif + + // Mask update: If the min_volume is not a mask, things are simple, current_volume = min_volume. + // however, if it is a mask, the mask status will switch. + // if the mask status becomes one, the masked volumes inside may be the next volume (unless they are children of the mask) + // if the mask status becomes zero (and the current volume is masked by min_volume), the destinations list of the mask is searched + // if the mask status becomes zero (and the current volume is NOT masked by min volume), the current volume doesn't change + + if (Volumes[min_volume]->geometry.is_mask_volume == 0) { + #ifdef Union_trace_verbal_setting + printf("Min volume is not a mask, next volume = min volume\n"); + #endif + if (enable_tagging && stop_tagging_ray == 0) { + current_tagging_node = goto_volume_node(current_tagging_node, current_volume, min_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); } - } - if (need_to_run_within_which_volume == 1) { + current_volume = min_volume; + } else { #ifdef Union_trace_verbal_setting - printf("The current volume was masked by this mask, and does need updating\n"); + printf("Current volume is not a mask, complex decision tree\n"); #endif - if (Volumes[min_volume]->geometry.destinations_list.num_elements == 1) { - #ifdef Union_trace_verbal_setting - printf("Only one element in the destination tree of the mask\n"); - #endif - // If there is only one element on the destinations list (quite common) there is no reason to run within_which_volume - // Instead the mask status is calculated here - if (Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.is_masked_volume == 1) { + if (mask_status_list.elements[Volumes[min_volume]->geometry.mask_index] == 1) { + // We are leaving the mask, change the status #ifdef Union_trace_verbal_setting - printf("The one element is however masked, so the mask status need to be calculated\n"); + printf("mask status changed from 1 to 0 as a mask is left\n"); #endif - // figure out the effective mask status of this volume - if (Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.mask_mode == 2) { // ANY mask mode - tree_next_volume = 0; - for (mask_start=mask_check=Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.elements; mask_check-mask_startgeometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.num_elements; mask_check++) { - if (mask_status_list.elements[*mask_check] == 1) { - tree_next_volume = Volumes[min_volume]->geometry.destinations_list.elements[0]; - break; + mask_status_list.elements[Volumes[min_volume]->geometry.mask_index] = 0; + // If the current volume is masked by this mask, run within_which_volume using the masks destination list, otherwise keep the current volume + if (on_int_list(Volumes[current_volume]->geometry.masked_by_list,min_volume) == 1) { + #ifdef Union_trace_verbal_setting + printf("The current volume was masked by this mask, and my need updating\n"); + #endif + // In case of ANY mode, need to see if another mask on the masked_by list of the current volume is active, and if so, nothing happens + need_to_run_within_which_volume = 1; + if (Volumes[current_volume]->geometry.mask_mode == 2) { + for (mask_start=mask_check=Volumes[current_volume]->geometry.masked_by_mask_index_list.elements; mask_check-mask_startgeometry.masked_by_mask_index_list.num_elements; mask_check++) { + if (mask_status_list.elements[*mask_check] == 1) { + // Nothing needs to be done, the effective mask status of the current volume is still 1 + need_to_run_within_which_volume = 0; + break; + } + } } - } - } else { // ALL mask mode - tree_next_volume = Volumes[min_volume]->geometry.destinations_list.elements[0]; - for (mask_start=mask_check=Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.elements;mask_check-mask_startgeometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.num_elements;mask_check++) { - if (mask_status_list.elements[*mask_check] == 0) { - tree_next_volume = 0; - break; + if (need_to_run_within_which_volume == 1) { + #ifdef Union_trace_verbal_setting + printf("The current volume was masked by this mask, and does need updating\n"); + #endif + if (Volumes[min_volume]->geometry.destinations_list.num_elements == 1) { + #ifdef Union_trace_verbal_setting + printf("Only one element in the destination tree of the mask\n"); + #endif + // If there is only one element on the destinations list (quite common) there is no reason to run within_which_volume + // Instead the mask status is calculated here + if (Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.is_masked_volume == 1) { + #ifdef Union_trace_verbal_setting + printf("The one element is however masked, so the mask status need to be calculated\n"); + #endif + // figure out the effective mask status of this volume + if (Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.mask_mode == 2) { // ANY mask mode + tree_next_volume = 0; + for (mask_start=mask_check=Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.elements; mask_check-mask_startgeometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.num_elements; mask_check++) { + if (mask_status_list.elements[*mask_check] == 1) { + tree_next_volume = Volumes[min_volume]->geometry.destinations_list.elements[0]; + break; + } + } + } else { // ALL mask mode + tree_next_volume = Volumes[min_volume]->geometry.destinations_list.elements[0]; + for (mask_start=mask_check=Volumes[Volumes[min_volume]->geometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.elements;mask_check-mask_startgeometry.destinations_list.elements[0]]->geometry.masked_by_mask_index_list.num_elements;mask_check++) { + if (mask_status_list.elements[*mask_check] == 0) { + tree_next_volume = 0; + break; + } + } + } + } else tree_next_volume = Volumes[min_volume]->geometry.destinations_list.elements[0]; + #ifdef Union_trace_verbal_setting + printf("The method found the next tree volume to be %d\n",tree_next_volume); + #endif + if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes, &stop_tagging_ray, stop_creating_nodes); + current_volume = tree_next_volume; + } else { + #ifdef Union_trace_verbal_setting + printf("Many elements in destinations list, use within_which_volume\n"); + #endif + ray_position = coords_set(x,y,z); + ray_velocity = coords_set(vx,vy,vz); + tree_next_volume = within_which_volume_GPU(ray_position, Volumes[min_volume]->geometry.reduced_destinations_list, Volumes[min_volume]->geometry.destinations_list, Volumes, &mask_status_list, number_of_volumes, pre_allocated1, pre_allocated2, pre_allocated3); + + if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); + current_volume = tree_next_volume; + #ifdef Union_trace_verbal_setting + printf("Set new new volume to %d\n",tree_next_volume); + #endif + } + } else { + #ifdef Union_trace_verbal_setting + printf("Did not need updating, as another mask was covering the volume\n"); + #endif } - } } - } else tree_next_volume = Volumes[min_volume]->geometry.destinations_list.elements[0]; - #ifdef Union_trace_verbal_setting - printf("The method found the next tree volume to be %d\n",tree_next_volume); - #endif - if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes, &stop_tagging_ray, stop_creating_nodes); - current_volume = tree_next_volume; + } else { - #ifdef Union_trace_verbal_setting - printf("Many elements in destinations list, use within_which_volume\n"); - #endif - ray_position = coords_set(x,y,z); - ray_velocity = coords_set(vx,vy,vz); - tree_next_volume = within_which_volume_GPU(ray_position, Volumes[min_volume]->geometry.reduced_destinations_list, Volumes[min_volume]->geometry.destinations_list, Volumes, &mask_status_list, number_of_volumes, pre_allocated1, pre_allocated2, pre_allocated3); - - if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); - current_volume = tree_next_volume; - #ifdef Union_trace_verbal_setting - printf("Set new new volume to %d\n",tree_next_volume); - #endif + // Here beccause the mask status of the mask that is intersected was 0, and it is thus switched to 1 + mask_status_list.elements[Volumes[min_volume]->geometry.mask_index] = 1; + // When entering a mask, the new highest priority volume may be one of the masked volumes, if not we keep the current volume + ray_position = coords_set(x,y,z); + ray_velocity = coords_set(vx,vy,vz); + // Bug found on the 2/9 2016, the destinations_list of a mask does not contain the volumes inside it. Could make an additional list for this. + // The temporary fix will be to use the mask list for both reduced destinations list and destinations list. + tree_next_volume = within_which_volume_GPU(ray_position, Volumes[min_volume]->geometry.mask_list, Volumes[min_volume]->geometry.mask_list, Volumes, &mask_status_list, number_of_volumes, pre_allocated1, pre_allocated2, pre_allocated3); + // if within_which_volume returns 0, no result was found (volume 0 can not be masked, so it could not be on the mask list) + if (tree_next_volume != 0) { + if (Volumes[tree_next_volume]->geometry.priority_value > Volumes[current_volume]->geometry.priority_value) { + // In case the current volume has a higher priority, nothing happens, otherwise change current volume + if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes, &stop_tagging_ray, stop_creating_nodes); + current_volume = tree_next_volume; + } + } } - } else { - #ifdef Union_trace_verbal_setting - printf("Did not need updating, as another mask was covering the volume\n"); - #endif - } - } - - } else { - // Here beccause the mask status of the mask that is intersected was 0, and it is thus switched to 1 - mask_status_list.elements[Volumes[min_volume]->geometry.mask_index] = 1; - // When entering a mask, the new highest priority volume may be one of the masked volumes, if not we keep the current volume - ray_position = coords_set(x,y,z); - ray_velocity = coords_set(vx,vy,vz); - // Bug found on the 2/9 2016, the destinations_list of a mask does not contain the volumes inside it. Could make an additional list for this. - // The temporary fix will be to use the mask list for both reduced destinations list and destinations list. - tree_next_volume = within_which_volume_GPU(ray_position, Volumes[min_volume]->geometry.mask_list, Volumes[min_volume]->geometry.mask_list, Volumes, &mask_status_list, number_of_volumes, pre_allocated1, pre_allocated2, pre_allocated3); - // if within_which_volume returns 0, no result was found (volume 0 can not be masked, so it could not be on the mask list) - if (tree_next_volume != 0) { - if (Volumes[tree_next_volume]->geometry.priority_value > Volumes[current_volume]->geometry.priority_value) { - // In case the current volume has a higher priority, nothing happens, otherwise change current volume - if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes, &stop_tagging_ray, stop_creating_nodes); - current_volume = tree_next_volume; - } } - } - } - // Regardless of the outcome of the above code, either the mask status or current volume have changed, and thus a effective mask update is needed. - update_current_mask_intersect_status(¤t_mask_intersect_list_status, &mask_status_list, Volumes, ¤t_volume); + // Regardless of the outcome of the above code, either the mask status or current volume have changed, and thus a effective mask update is needed. + update_current_mask_intersect_status(¤t_mask_intersect_list_status, &mask_status_list, Volumes, ¤t_volume); + #ifdef Union_trace_verbal_setting + print_1d_int_list(mask_status_list,"Updated mask status list"); + print_1d_int_list(current_mask_intersect_list_status,"Updated current_mask_intersect_list_status"); + if (enable_tagging) printf("After new intersection volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + if (enable_tagging) printf("After new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif + + } #ifdef Union_trace_verbal_setting - print_1d_int_list(mask_status_list,"Updated mask status list"); - print_1d_int_list(current_mask_intersect_list_status,"Updated current_mask_intersect_list_status"); - if (enable_tagging) printf("After new intersection volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging) printf("After new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + printf(" TO VOLUME %d \n",current_volume); #endif - - } - #ifdef Union_trace_verbal_setting - printf(" TO VOLUME %d \n",current_volume); - #endif - double n1, n2; - int perform_refraction = 1; - double nx; - double ny; - double nz; - double normal_vector[3]; + double n1, n2; + int perform_refraction = 1; + double nx; + double ny; + double nz; + double normal_vector[3]; - if (previous_volume != current_volume) { // With masks, it can happen that the ray takes an extra iteration within the same volume, can skip surface / refraction + if (previous_volume != current_volume) { // With masks, it can happen that the ray takes an extra iteration within the same volume, can skip surface / refraction - double surface_wavevector_before[3]; - double surface_wavevector[3]; + double surface_wavevector_before[3]; + double surface_wavevector[3]; - nx = intersection_time_table.normal_vector_x[min_volume][min_solution]; - ny = intersection_time_table.normal_vector_y[min_volume][min_solution]; - nz = intersection_time_table.normal_vector_z[min_volume][min_solution]; - NORM(nx,ny,nz); + nx = intersection_time_table.normal_vector_x[min_volume][min_solution]; + ny = intersection_time_table.normal_vector_y[min_volume][min_solution]; + nz = intersection_time_table.normal_vector_z[min_volume][min_solution]; + NORM(nx,ny,nz); - // loop over surface processes - // Need face index of both the geometry the ray is leaving and entering, only one from scattering + // loop over surface processes + // Need face index of both the geometry the ray is leaving and entering, only one from scattering - // List of surfaces from geometry ray is leaving, bottom to top (length n_leaving) - int relevant_surface_index, n_leaving, n_entering; - struct surface_stack_struct *leaving_stack; - struct surface_stack_struct *entering_stack; + // List of surfaces from geometry ray is leaving, bottom to top (length n_leaving) + int relevant_surface_index, n_leaving, n_entering; + struct surface_stack_struct *leaving_stack; + struct surface_stack_struct *entering_stack; - #ifdef Union_trace_verbal_setting - printf(" Creating leaving surface stack %d \n",previous_volume); - #endif + #ifdef Union_trace_verbal_setting + printf(" Creating leaving surface stack %d \n",previous_volume); + #endif - if (previous_volume == 0) { - n_leaving = 0; // surrounding vacuum has no stack - } else { - if (previous_volume == min_volume) { - // ray left previous volume on a face of that volume, use that for the list - relevant_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; - leaving_stack = Volumes[previous_volume]->geometry.surface_stack_for_each_face[relevant_surface_index]; - } else { - // ray left previous volume through an internal cut of some kind - leaving_stack = Volumes[previous_volume]->geometry.internal_cut_surface_stack; - } - n_leaving = leaving_stack->number_of_surfaces; - } + if (previous_volume == 0) { + n_leaving = 0; // surrounding vacuum has no stack + } else { + if (previous_volume == min_volume) { + // ray left previous volume on a face of that volume, use that for the list + relevant_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; + leaving_stack = Volumes[previous_volume]->geometry.surface_stack_for_each_face[relevant_surface_index]; + } else { + // ray left previous volume through an internal cut of some kind + leaving_stack = Volumes[previous_volume]->geometry.internal_cut_surface_stack; + } + n_leaving = leaving_stack->number_of_surfaces; + } - #ifdef Union_trace_verbal_setting - printf(" Created leaving surface stack for volume %d with %d effects \n",previous_volume, n_leaving); - #endif + #ifdef Union_trace_verbal_setting + printf(" Created leaving surface stack for volume %d with %d effects \n",previous_volume, n_leaving); + #endif - if (current_volume == 0) { - n_entering = 0; - } else { + if (current_volume == 0) { + n_entering = 0; + } else { - // List of surfaces from geometry ray is entering, top to bottom (length n_entering) - if (current_volume == min_volume) { - // ray entered current volume on a face of that volume, use that for the list - relevant_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; - entering_stack = Volumes[current_volume]->geometry.surface_stack_for_each_face[relevant_surface_index]; - } else { - // ray left previous volume through an internal cut of some kind - entering_stack = Volumes[current_volume]->geometry.internal_cut_surface_stack; - } - n_entering = entering_stack->number_of_surfaces; - } + // List of surfaces from geometry ray is entering, top to bottom (length n_entering) + if (current_volume == min_volume) { + // ray entered current volume on a face of that volume, use that for the list + relevant_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; + entering_stack = Volumes[current_volume]->geometry.surface_stack_for_each_face[relevant_surface_index]; + } else { + // ray left previous volume through an internal cut of some kind + entering_stack = Volumes[current_volume]->geometry.internal_cut_surface_stack; + } + n_entering = entering_stack->number_of_surfaces; + } - int n_total = n_leaving + n_entering; + int n_total = n_leaving + n_entering; - #ifdef Union_trace_verbal_setting - printf(" Created entering surface stack for volume %d with %d effects. Combining into one surface stack \n",current_volume, n_entering); - #endif + #ifdef Union_trace_verbal_setting + printf(" Created entering surface stack for volume %d with %d effects. Combining into one surface stack \n",current_volume, n_entering); + #endif - // Only need to run surface system if there are any surface processes - if (n_total > 0) { + // Only need to run surface system if there are any surface processes + if (n_total > 0) { - // Make combined list, leaving bottom to top followed by entering top to bottom - // Stacks are naturally from bottom to top - for (iterator=0; iteratorp_surface_array[iterator]; - } else { - // grab from entering stack in reverse order - interface_stack.p_surface_array[iterator] = entering_stack->p_surface_array[n_entering - iterator + n_leaving - 1]; - } - } + // Make combined list, leaving bottom to top followed by entering top to bottom + // Stacks are naturally from bottom to top + for (iterator=0; iteratorp_surface_array[iterator]; + } else { + // grab from entering stack in reverse order + interface_stack.p_surface_array[iterator] = entering_stack->p_surface_array[n_entering - iterator + n_leaving - 1]; + } + } - // struct surface_process_struct **surface_list; could do interface_struct like this instead + // struct surface_process_struct **surface_list; could do interface_struct like this instead - int surface_transverse_index = 0; - int surface_direction = 1; - int surface_iterations = 0; - int in_direction; - int continues; - enum in_or_out inward_or_outward; + int surface_transverse_index = 0; + int surface_direction = 1; + int surface_iterations = 0; + int in_direction; + int continues; + enum in_or_out inward_or_outward; - struct surface_process_struct *surface_pointer; + struct surface_process_struct *surface_pointer; - surface_wavevector[0] = V2K*vx; surface_wavevector[1] = V2K*vy; surface_wavevector[2] = V2K*vz; - surface_wavevector_before[0] = surface_wavevector[0]; - surface_wavevector_before[1] = surface_wavevector[1]; - surface_wavevector_before[2] = surface_wavevector[2]; + surface_wavevector[0] = V2K*vx; surface_wavevector[1] = V2K*vy; surface_wavevector[2] = V2K*vz; + surface_wavevector_before[0] = surface_wavevector[0]; + surface_wavevector_before[1] = surface_wavevector[1]; + surface_wavevector_before[2] = surface_wavevector[2]; - #ifdef Union_trace_verbal_setting - double dot_product_before = nx*vx + ny*vy + nz*vz; - printf(" Entering surface stack loop \n"); - printf(" - normal dot v = %lf \n", dot_product_before); - #endif + #ifdef Union_trace_verbal_setting + double dot_product_before = nx*vx + ny*vy + nz*vz; + printf(" Entering surface stack loop \n"); + printf(" - normal dot v = %lf \n", dot_product_before); + #endif - while (1) { + while (1) { - #ifdef Union_trace_verbal_setting - printf(" Start of surface stack with transverse_index = %d \n", surface_transverse_index); - #endif + #ifdef Union_trace_verbal_setting + printf(" Start of surface stack with transverse_index = %d \n", surface_transverse_index); + #endif - // Escape conditions on each side of stack - if (surface_transverse_index < 0) { - // Escaped from incoming direction - perform_refraction = 0; - current_volume = previous_volume; + // Escape conditions on each side of stack + if (surface_transverse_index < 0) { + // Escaped from incoming direction + perform_refraction = 0; + current_volume = previous_volume; - #ifdef Union_trace_verbal_setting - printf(" Left stack to incoming side \n"); - #endif + #ifdef Union_trace_verbal_setting + printf(" Left stack to incoming side \n"); + #endif - break; - } + break; + } - if (surface_transverse_index >= n_total) { - // Went through all layers, continue to refraction as normal - #ifdef Union_trace_verbal_setting - printf(" Left stack by going all the way through \n"); - #endif - break; - } + if (surface_transverse_index >= n_total) { + // Went through all layers, continue to refraction as normal + #ifdef Union_trace_verbal_setting + printf(" Left stack by going all the way through \n"); + #endif + break; + } - surface_pointer = interface_stack.p_surface_array[surface_transverse_index]; + surface_pointer = interface_stack.p_surface_array[surface_transverse_index]; - if (surface_transverse_index < n_leaving) in_direction = 1; else in_direction = -1; - if (surface_direction == in_direction) inward_or_outward = inward_bound; else inward_or_outward = outward_bound; + if (surface_transverse_index < n_leaving) in_direction = 1; else in_direction = -1; + if (surface_direction == in_direction) inward_or_outward = inward_bound; else inward_or_outward = outward_bound; - // fresh normal in case surface function messed with it - normal_vector[0] = nx; normal_vector[1] = ny; normal_vector[2] = nz; - - // p, wavevector and continues updated by surface_function - #ifdef Union_trace_verbal_setting - printf(" Running physics_surface with transverse_index = %d \n", surface_transverse_index); - #endif - physics_surface(surface_pointer, &p, surface_wavevector, &continues, normal_vector, inward_or_outward, _particle); - #ifdef Union_trace_verbal_setting - printf(" physics_surface reported continues = %d \n", continues); - #endif + // fresh normal in case surface function messed with it + normal_vector[0] = nx; normal_vector[1] = ny; normal_vector[2] = nz; + + // p, wavevector and continues updated by surface_function + #ifdef Union_trace_verbal_setting + printf(" Running physics_surface with transverse_index = %d \n", surface_transverse_index); + #endif + physics_surface(surface_pointer, &p, surface_wavevector, &continues, normal_vector, inward_or_outward, _particle); + #ifdef Union_trace_verbal_setting + printf(" physics_surface reported continues = %d \n", continues); + #endif - // insert logging + // insert logging - if (!continues) surface_direction = -surface_direction; // Flip stack direction if the ray does not continue + if (!continues) surface_direction = -surface_direction; // Flip stack direction if the ray does not continue - surface_transverse_index += surface_direction; // Go to next element in stack - surface_iterations += 1; + surface_transverse_index += surface_direction; // Go to next element in stack + surface_iterations += 1; - if (surface_iterations > 10000) { - printf("ERROR: Ray stuck in surface stack, ABSORBED\n"); - done = 1; - ray_sucseeded = 0; - break; - } - } + if (surface_iterations > 10000) { + printf("ERROR: Ray stuck in surface stack, ABSORBED\n"); + done = 1; + ray_sucseeded = 0; + break; + } + } - // If velocity was updated, register that to the ray and reset intersection memory - // Hardcoded limit of 1E-10 m/s change in any direction - if (fabs(surface_wavevector_before[0] - surface_wavevector[0]) > 1E-10 || - fabs(surface_wavevector_before[1] - surface_wavevector[1]) > 1E-10 || - fabs(surface_wavevector_before[2] - surface_wavevector[2]) > 1E-10) { - - vx = surface_wavevector[0]*K2V; - vy = surface_wavevector[1]*K2V; - vz = surface_wavevector[2]*K2V; - #ifdef Union_trace_verbal_setting - printf(" ray direction updated by surface stack \n"); - printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); - printf(" - normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); - if (surface_transverse_index < 0) printf("Should have different sign \n"); - if (surface_transverse_index >= n_total) printf("Should have same sign \n"); - if (dot_product_before * (nx*vx + ny*vy + nz*vz) < 0) { - printf("Sign did change \n"); - } else printf("Sign did not change \n"); - #endif - - // Report new velocity back, - // Update velocity in all ways used in master - v[0] = vx; v[1] = vy; v[2] = vz; - v_length = sqrt(vx*vx + vy*vy + vz*vz); - k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; - ray_velocity = coords_set(vx, vy, vz); + // If velocity was updated, register that to the ray and reset intersection memory + // Hardcoded limit of 1E-10 m/s change in any direction + if (fabs(surface_wavevector_before[0] - surface_wavevector[0]) > 1E-10 || + fabs(surface_wavevector_before[1] - surface_wavevector[1]) > 1E-10 || + fabs(surface_wavevector_before[2] - surface_wavevector[2]) > 1E-10) { + + vx = surface_wavevector[0]*K2V; + vy = surface_wavevector[1]*K2V; + vz = surface_wavevector[2]*K2V; + #ifdef Union_trace_verbal_setting + printf(" ray direction updated by surface stack \n"); + printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); + printf(" - normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); + if (surface_transverse_index < 0) printf("Should have different sign \n"); + if (surface_transverse_index >= n_total) printf("Should have same sign \n"); + if (dot_product_before * (nx*vx + ny*vy + nz*vz) < 0) { + printf("Sign did change \n"); + } else printf("Sign did not change \n"); + #endif + + // Report new velocity back, + // Update velocity in all ways used in master + v[0] = vx; v[1] = vy; v[2] = vz; + v_length = sqrt(vx*vx + vy*vy + vz*vz); + k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; + ray_velocity = coords_set(vx, vy, vz); - ignore_closest = min_volume; - ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; + ignore_closest = min_volume; + ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; - // Since velocity is updated, we need to clear the intersection time table - clear_intersection_table(&intersection_time_table); + // Since velocity is updated, we need to clear the intersection time table + clear_intersection_table(&intersection_time_table); - // Reset origin point for ray - r_start[0] = x; r_start[1] = y; r_start[2] = z; - time_propagated_without_scattering = 0.0; - } - } + // Reset origin point for ray + r_start[0] = x; r_start[1] = y; r_start[2] = z; + time_propagated_without_scattering = 0.0; + } + } - // Need old and current volume here to compare refraction index - // Need information on normal vector for intersection - // Can then change direction accordingly - - #ifdef Union_trace_verbal_setting - printf("Entering refraction system \n"); - printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); - printf("n = (%f,%f,%f)\n", nx, ny, nz); - double dot_product_before = nx*vx + ny*vy + nz*vz; - printf("normal dot v = %lf \n", dot_product_before); - printf("min_volume = %d, min_solution = %d\n", min_volume, min_solution); - #endif + // Need old and current volume here to compare refraction index + // Need information on normal vector for intersection + // Can then change direction accordingly + + #ifdef Union_trace_verbal_setting + printf("Entering refraction system \n"); + printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); + printf("n = (%f,%f,%f)\n", nx, ny, nz); + double dot_product_before = nx*vx + ny*vy + nz*vz; + printf("normal dot v = %lf \n", dot_product_before); + printf("min_volume = %d, min_solution = %d\n", min_volume, min_solution); + #endif - // Check if the volume intersection was found with returns normal, allowing refraction calculation - // todo will implement differnet solution - //if (Volumes[min_volume]->geometry.returns_intersection_normal == 0) perform_refraction = 0; + // Check if the volume intersection was found with returns normal, allowing refraction calculation + // todo will implement differnet solution + //if (Volumes[min_volume]->geometry.returns_intersection_normal == 0) perform_refraction = 0; - v_length = sqrt(vx*vx+vy*vy+vz*vz); - double lambda = 3956.0032/v_length; + v_length = sqrt(vx*vx+vy*vy+vz*vz); + double lambda = 3956.0032/v_length; - if (previous_volume == 0) n1 = 1.0; - else { - if (Volumes[previous_volume]->p_physics->has_refraction_info == 0 && Volumes[previous_volume]->p_physics->is_vacuum == 0) { - perform_refraction = 0; - } else { + if (previous_volume == 0) n1 = 1.0; + else { + if (Volumes[previous_volume]->p_physics->has_refraction_info == 0 && Volumes[previous_volume]->p_physics->is_vacuum == 0) { + perform_refraction = 0; + } else { - if (Volumes[previous_volume]->p_physics->is_vacuum == 1) { - n1 = 1.0; - } else { - n1 = sqrt(1.0-(lambda*lambda*Volumes[previous_volume]->p_physics->refraction_scattering_length_density/PI)); - } + if (Volumes[previous_volume]->p_physics->is_vacuum == 1) { + n1 = 1.0; + } else { + n1 = sqrt(1.0-(lambda*lambda*Volumes[previous_volume]->p_physics->refraction_scattering_length_density/PI)); + } - // If the intersection is found with this volume, it is leaving, and the normal needs to be flipped - if (previous_volume == min_volume) { - nx *= -1; - ny *= -1; - nz *= -1; + // If the intersection is found with this volume, it is leaving, and the normal needs to be flipped + if (previous_volume == min_volume) { + nx *= -1; + ny *= -1; + nz *= -1; + } + } } - } - } - if (current_volume == 0) n2 = 1.0; - else { - if (Volumes[current_volume]->p_physics->has_refraction_info == 0 && Volumes[current_volume]->p_physics->is_vacuum == 0) { - perform_refraction = 0; - } else { + if (current_volume == 0) n2 = 1.0; + else { + if (Volumes[current_volume]->p_physics->has_refraction_info == 0 && Volumes[current_volume]->p_physics->is_vacuum == 0) { + perform_refraction = 0; + } else { - if (Volumes[current_volume]->p_physics->is_vacuum == 1) { - n2 = 1.0; - } else { - n2 = sqrt(1.0-(lambda*lambda*Volumes[current_volume]->p_physics->refraction_scattering_length_density/PI)); - } - } - } + if (Volumes[current_volume]->p_physics->is_vacuum == 1) { + n2 = 1.0; + } else { + n2 = sqrt(1.0-(lambda*lambda*Volumes[current_volume]->p_physics->refraction_scattering_length_density/PI)); + } + } + } - // Check if the two materials are the same, no need to check for refraction / reflection. - if (perform_refraction == 1 && previous_volume != 0 && current_volume != 0) { - if (strcmp(Volumes[previous_volume]->p_physics->name, Volumes[current_volume]->p_physics->name) == 0 ) { - perform_refraction = 0; - } - } + // Check if the two materials are the same, no need to check for refraction / reflection. + if (perform_refraction == 1 && previous_volume != 0 && current_volume != 0) { + if (strcmp(Volumes[previous_volume]->p_physics->name, Volumes[current_volume]->p_physics->name) == 0 ) { + perform_refraction = 0; + } + } - if (previous_volume == 0 && current_volume == 0) { - perform_refraction = 0; // Vacuum to vacuum - } else if (previous_volume == 0) { - if (Volumes[current_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum - } else if (current_volume == 0) { - if (Volumes[previous_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum - } else { - if (Volumes[previous_volume]->p_physics->is_vacuum == 1 && Volumes[current_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum - } + if (previous_volume == 0 && current_volume == 0) { + perform_refraction = 0; // Vacuum to vacuum + } else if (previous_volume == 0) { + if (Volumes[current_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum + } else if (current_volume == 0) { + if (Volumes[previous_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum + } else { + if (Volumes[previous_volume]->p_physics->is_vacuum == 1 && Volumes[current_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum + } - #ifdef Union_trace_verbal_setting - if (perform_refraction == 1) - printf("ready to calculate refraction, current_volume = %d, n1=%lf, n2=%lf \n", current_volume, n1, n2); - else - printf("skipping refraction system, current_volume = %d, n1=%lf, n2=%lf \n", current_volume, n1, n2); - #endif + #ifdef Union_trace_verbal_setting + if (perform_refraction == 1) + printf("ready to calculate refraction, current_volume = %d, n1=%lf, n2=%lf \n", current_volume, n1, n2); + else + printf("skipping refraction system, current_volume = %d, n1=%lf, n2=%lf \n", current_volume, n1, n2); + #endif - if (perform_refraction == 1) { + if (perform_refraction == 1) { - double reflectivity; + double reflectivity; - // Skipping roughness - //if (RMS>0) Surface_wavyness(&nx, &ny, &nz, atan(2*RMS/lambda), _particle); + // Skipping roughness + //if (RMS>0) Surface_wavyness(&nx, &ny, &nz, atan(2*RMS/lambda), _particle); - Coords N = coords_set(nx, ny, nz); // normal vector to surface - Coords V = coords_set(vx, vy, vz); // incoming velocity - Coords I = coords_scale(V, 1/v_length); // normalised ray = v/|v| + Coords N = coords_set(nx, ny, nz); // normal vector to surface + Coords V = coords_set(vx, vy, vz); // incoming velocity + Coords I = coords_scale(V, 1/v_length); // normalised ray = v/|v| - // compute reflectivity - double qc; - double q_normal = fabs(2*coords_sp(V, N)*V2Q); - double q_qc_quadratic_diff; - int use_fresnel; + // compute reflectivity + double qc; + double q_normal = fabs(2*coords_sp(V, N)*V2Q); + double q_qc_quadratic_diff; + int use_fresnel; - use_fresnel = 1; + use_fresnel = 1; - /* Reflectivity (see component Guide). */ - //StdReflecFunc(q_normal, par, &reflectivity); + /* Reflectivity (see component Guide). */ + //StdReflecFunc(q_normal, par, &reflectivity); - // Reflectivity calculation - if (n2/n1 < 1.0) { - // qc exists - qc = 4.0*PI*sin(acos(n2/n1))/lambda; - if (q_normal < qc) { - reflectivity = 1.0; - use_fresnel = 0; - } - // NEUTRON REFLECTION: PRINCIPLES AND EXAMPLES OF APPLICATIONS: Robert Cubitt and Giovanna Fragneto - // This expression only works when a qc exists - //q_qc_quadratic_diff = sqrt(q_normal*q_normal - qc*qc) - //reflectivity = pow((q_normal - q_qc_quadratic_diff)/(q_normal + q_qc_quadratic_diff), 2); - } - - if (use_fresnel) { - // Fresnel law for both n1 > n2 and n1 < n2 - double term1, term2, R_perp, R_parallel; - term1 = n1 * sqrt(1.0 - pow(lambda * q_normal / (4.0 * PI * n1), 2)); - term2 = n2 * sqrt(1.0 - pow(lambda * q_normal / (4.0 * PI * n2), 2)); - R_perp = ((term1 - term2) / (term1 + term2))*((term1 - term2) / (term1 + term2)); - R_parallel = ((term2 - term1) / (term2 + term1))*((term2 - term1) / (term2 + term1)); - reflectivity = 0.5*(R_perp + R_parallel); // Unpolarized neutrons - } + // Reflectivity calculation + if (n2/n1 < 1.0) { + // qc exists + qc = 4.0*PI*sin(acos(n2/n1))/lambda; + if (q_normal < qc) { + reflectivity = 1.0; + use_fresnel = 0; + } + // NEUTRON REFLECTION: PRINCIPLES AND EXAMPLES OF APPLICATIONS: Robert Cubitt and Giovanna Fragneto + // This expression only works when a qc exists + //q_qc_quadratic_diff = sqrt(q_normal*q_normal - qc*qc) + //reflectivity = pow((q_normal - q_qc_quadratic_diff)/(q_normal + q_qc_quadratic_diff), 2); + } + + if (use_fresnel) { + // Fresnel law for both n1 > n2 and n1 < n2 + double term1, term2, R_perp, R_parallel; + term1 = n1 * sqrt(1.0 - pow(lambda * q_normal / (4.0 * PI * n1), 2)); + term2 = n2 * sqrt(1.0 - pow(lambda * q_normal / (4.0 * PI * n2), 2)); + R_perp = ((term1 - term2) / (term1 + term2))*((term1 - term2) / (term1 + term2)); + R_parallel = ((term2 - term1) / (term2 + term1))*((term2 - term1) / (term2 + term1)); + reflectivity = 0.5*(R_perp + R_parallel); // Unpolarized neutrons + } - double theta1, theta2; - // theta1: incident angle to the surface normal - double cos_theta1 = -coords_sp(N,I); // cos(theta1) = -N.I + double theta1, theta2; + // theta1: incident angle to the surface normal + double cos_theta1 = -coords_sp(N,I); // cos(theta1) = -N.I - if (fabs(cos_theta1) > 1) { - printf("cos_theta1 > 1, Refraction error! Asborbed ray.\n"); - ABSORB; // should never occur... - } - theta1 = acos(cos_theta1)*RAD2DEG; + if (fabs(cos_theta1) > 1) { + printf("cos_theta1 > 1, Refraction error! Asborbed ray.\n"); + ABSORB; // should never occur... + } + theta1 = acos(cos_theta1)*RAD2DEG; - // reflected ray: probability R - // reflected beam: I + 2cos(theta1).N - Coords I_reflect = coords_add(I, coords_scale(N, 2.0*cos_theta1)); - // reflected velocity: I_reflect.v - Coords V_reflect = coords_scale(I_reflect, v_length); + // reflected ray: probability R + // reflected beam: I + 2cos(theta1).N + Coords I_reflect = coords_add(I, coords_scale(N, 2.0*cos_theta1)); + // reflected velocity: I_reflect.v + Coords V_reflect = coords_scale(I_reflect, v_length); - // compute refracted angle theta2... - double sqr_cos_theta2 = 1.0-(n1/n2)*(n1/n2)*(1.0-cos_theta1*cos_theta1); + // compute refracted angle theta2... + double sqr_cos_theta2 = 1.0-(n1/n2)*(n1/n2)*(1.0-cos_theta1*cos_theta1); - // now choose which one to use, and compute outgoing velocity - if (0 < sqr_cos_theta2 && sqr_cos_theta2 < 1.0) { - // refraction is possible + // now choose which one to use, and compute outgoing velocity + if (0 < sqr_cos_theta2 && sqr_cos_theta2 < 1.0) { + // refraction is possible - // theta2: refracted angle to the surface normal - double cos_theta2 = sqrt(sqr_cos_theta2); + // theta2: refracted angle to the surface normal + double cos_theta2 = sqrt(sqr_cos_theta2); - // select reflection (or refraction) from Monte-Carlo choice with probability R - // in this case we expect R to be small (q > Qc) - if (enable_reflection && 0.0 < reflectivity && reflectivity < 1.0 && rand01() < reflectivity) { + // select reflection (or refraction) from Monte-Carlo choice with probability R + // in this case we expect R to be small (q > Qc) + if (enable_reflection && 0.0 < reflectivity && reflectivity < 1.0 && rand01() < reflectivity) { - // choose reflection from MC - theta2 = theta1; - coords_get(V_reflect, &vx, &vy, &vz); + // choose reflection from MC + theta2 = theta1; + coords_get(V_reflect, &vx, &vy, &vz); - current_volume = previous_volume; // Reflected, stays in current volume + current_volume = previous_volume; // Reflected, stays in current volume - // Update velocity in all ways used in master - v[0] = vx; v[1] = vy; v[2] = vz; - v_length = sqrt(vx*vx + vy*vy + vz*vz); - k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; - ray_velocity = coords_set(vx, vy, vz); + // Update velocity in all ways used in master + v[0] = vx; v[1] = vy; v[2] = vz; + v_length = sqrt(vx*vx + vy*vy + vz*vz); + k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; + ray_velocity = coords_set(vx, vy, vz); - #ifdef Union_trace_verbal_setting - printf(" Refraction system : ray reflected, (branch 1) going back to volume %d\n", previous_volume); + #ifdef Union_trace_verbal_setting + printf(" Refraction system : ray reflected, (branch 1) going back to volume %d\n", previous_volume); - printf(" normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); - if ((nx*vx + ny*vy + nz*vz)*dot_product_before > 0) printf(" SIGN SHOULD HAVE CHANGED BUT DIDN'T \n"); - #endif + printf(" normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); + if ((nx*vx + ny*vy + nz*vz)*dot_product_before > 0) printf(" SIGN SHOULD HAVE CHANGED BUT DIDN'T \n"); + #endif - ignore_closest = min_volume; - ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; + ignore_closest = min_volume; + ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; - // Since velocity is updated, we need to clear the intersection time table - clear_intersection_table(&intersection_time_table); + // Since velocity is updated, we need to clear the intersection time table + clear_intersection_table(&intersection_time_table); - // Reset origin point for ray - r_start[0] = x; r_start[1] = y; r_start[2] = z; - time_propagated_without_scattering = 0.0; + // Reset origin point for ray + r_start[0] = x; r_start[1] = y; r_start[2] = z; + time_propagated_without_scattering = 0.0; - } else if (enable_refraction) { - // compute refracted ray - theta2 = acos(cos_theta2)*RAD2DEG; + } else if (enable_refraction) { + // compute refracted ray + theta2 = acos(cos_theta2)*RAD2DEG; - Coords I_refract = coords_add(coords_scale(I, n1/n2), - coords_scale(N, n1/n2*cos_theta1 + (cos_theta1 < 0 ? cos_theta2 : -cos_theta2) )); - Coords V_refract = coords_scale(I_refract, v_length); + Coords I_refract = coords_add(coords_scale(I, n1/n2), + coords_scale(N, n1/n2*cos_theta1 + (cos_theta1 < 0 ? cos_theta2 : -cos_theta2) )); + Coords V_refract = coords_scale(I_refract, v_length); - coords_get(V_refract, &vx, &vy, &vz); + coords_get(V_refract, &vx, &vy, &vz); - // Update velocity in all ways used in master - v[0] = vx; v[1] = vy; v[2] = vz; - v_length = sqrt(vx*vx + vy*vy + vz*vz); - k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; - ray_velocity = coords_set(vx, vy, vz); + // Update velocity in all ways used in master + v[0] = vx; v[1] = vy; v[2] = vz; + v_length = sqrt(vx*vx + vy*vy + vz*vz); + k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; + ray_velocity = coords_set(vx, vy, vz); - #ifdef Union_trace_verbal_setting - printf(" Refraction system : ray refracted, continues to to volume %d\n", current_volume); + #ifdef Union_trace_verbal_setting + printf(" Refraction system : ray refracted, continues to to volume %d\n", current_volume); - printf(" normal dot v = %lf theta2 = %lf \n", nx*vx + ny*vy + nz*vz, theta2); - if ((nx*vx + ny*vy + nz*vz)*dot_product_before < 0) printf(" SIGN SHOULD NOT HAVE CHANGED BUT DID \n"); - #endif + printf(" normal dot v = %lf theta2 = %lf \n", nx*vx + ny*vy + nz*vz, theta2); + if ((nx*vx + ny*vy + nz*vz)*dot_product_before < 0) printf(" SIGN SHOULD NOT HAVE CHANGED BUT DID \n"); + #endif - // Reflected can ignore some intersections in next geometry iteration - ignore_closest = min_volume; // Ignore closest intersection in next geometry iteration - ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; + // Reflected can ignore some intersections in next geometry iteration + ignore_closest = min_volume; // Ignore closest intersection in next geometry iteration + ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; - // Since velocity is updated, we need to clear the intersection time table - clear_intersection_table(&intersection_time_table); + // Since velocity is updated, we need to clear the intersection time table + clear_intersection_table(&intersection_time_table); - // Reset origin point for ray - r_start[0] = x; r_start[1] = y; r_start[2] = z; - time_propagated_without_scattering = 0.0; + // Reset origin point for ray + r_start[0] = x; r_start[1] = y; r_start[2] = z; + time_propagated_without_scattering = 0.0; - } - } else if (enable_reflection) { - // only reflection: below total reflection + } + } else if (enable_reflection) { + // only reflection: below total reflection - theta2 = theta1; - if (0 < reflectivity && reflectivity < 1) p *= reflectivity; // should be R0 - coords_get(V_reflect, &vx, &vy, &vz); + theta2 = theta1; + if (0 < reflectivity && reflectivity < 1) p *= reflectivity; // should be R0 + coords_get(V_reflect, &vx, &vy, &vz); - current_volume = previous_volume; // Reflected, stays in current volume + current_volume = previous_volume; // Reflected, stays in current volume - // Update velocity in all ways used in master - v[0] = vx; v[1] = vy; v[2] = vz; - v_length = sqrt(vx*vx + vy*vy + vz*vz); - k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; - ray_velocity = coords_set(vx, vy, vz); + // Update velocity in all ways used in master + v[0] = vx; v[1] = vy; v[2] = vz; + v_length = sqrt(vx*vx + vy*vy + vz*vz); + k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; + ray_velocity = coords_set(vx, vy, vz); - #ifdef Union_trace_verbal_setting - printf(" Refraction system : ray reflected (branch 3), going back to volume %d\n", previous_volume); - printf(" normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); - if ((nx*vx + ny*vy + nz*vz)*dot_product_before > 0) printf(" SIGN SHOULD HAVE CHANGED BUT DIDN'T \n"); - #endif + #ifdef Union_trace_verbal_setting + printf(" Refraction system : ray reflected (branch 3), going back to volume %d\n", previous_volume); + printf(" normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); + if ((nx*vx + ny*vy + nz*vz)*dot_product_before > 0) printf(" SIGN SHOULD HAVE CHANGED BUT DIDN'T \n"); + #endif - // Reflected can ignore some intersections in next geometry iteration - ignore_closest = min_volume; - ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; - // Since velocity is updated, we need to clear the intersection time table - clear_intersection_table(&intersection_time_table); + // Reflected can ignore some intersections in next geometry iteration + ignore_closest = min_volume; + ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; + // Since velocity is updated, we need to clear the intersection time table + clear_intersection_table(&intersection_time_table); - // Reset origin point for ray - r_start[0] = x; r_start[1] = y; r_start[2] = z; - time_propagated_without_scattering = 0.0; - } - } + // Reset origin point for ray + r_start[0] = x; r_start[1] = y; r_start[2] = z; + time_propagated_without_scattering = 0.0; + } + } - // todo: decide how surface on an exit volume should be treated - if (Volumes[current_volume]->geometry.is_exit_volume==1) { - done = 1; // Exit volumes allow the ray to escape the component - ray_sucseeded = 1; // Allows the ray to leave loop - } + // todo: decide how surface on an exit volume should be treated + if (Volumes[current_volume]->geometry.is_exit_volume==1) { + done = 1; // Exit volumes allow the ray to escape the component + ray_sucseeded = 1; // Allows the ray to leave loop + } - #ifdef Union_trace_verbal_setting - printf("After refraction system \n"); - printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); - printf(" - normal_dot_v = %lf \n", nx*vx + ny*vy + nz*vz); - printf("CURRENT_VOLUME = %d \n", current_volume); - #endif + #ifdef Union_trace_verbal_setting + printf("After refraction system \n"); + printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); + printf(" - normal_dot_v = %lf \n", nx*vx + ny*vy + nz*vz); + printf("CURRENT_VOLUME = %d \n", current_volume); + #endif - } // End of if (previous_volume != current_volume) - } // End of scattering or propagation if + } // End of if (previous_volume != current_volume) + } // End of scattering or propagation if - } else { // Here because a shortest time is not found - if (current_volume == 0) { - done = 1; - ray_sucseeded = 1; + } else { // Here because a shortest time is not found + if (current_volume == 0) { + done = 1; + ray_sucseeded = 1; - } else { // Check for errors (debugging phase) - if (error_msg == 0) { - component_error_msg++; - ray_sucseeded = 0; - done = 1; // stop the loop - printf("\n----------------------------------------------------------------------------------------------------\n"); - printf("Union_master %s: Somehow reached a situation with no intersection time found, but still inside volume %d instead of 0\n",NAME_CURRENT_COMP,current_volume); - for (volume_index = 1; volume_index < number_of_volumes; volume_index++) { - if (r_within_function(ray_position,&Volumes[volume_index]->geometry) == 1) - printf("The ray is in volume %d\n",volume_index); - } + } else { // Check for errors (debugging phase) + if (error_msg == 0) { + component_error_msg++; + ray_sucseeded = 0; + done = 1; // stop the loop + printf("\n----------------------------------------------------------------------------------------------------\n"); + printf("Union_master %s: Somehow reached a situation with no intersection time found, but still inside volume %d instead of 0\n",NAME_CURRENT_COMP,current_volume); + for (volume_index = 1; volume_index < number_of_volumes; volume_index++) { + if (r_within_function(ray_position,&Volumes[volume_index]->geometry) == 1) + printf("The ray is in volume %d\n",volume_index); + } - print_1d_int_list(mask_status_list,"mask status list"); - for (iterator=0;iterator 100) { - printf("To many errors encountered, exiting. \n"); - // need ERROR FLAG to be read in finally which can warn the user of problems! - exit(1); + if (component_error_msg > 100) { + printf("To many errors encountered, exiting. \n"); + // need ERROR FLAG to be read in finally which can warn the user of problems! + exit(1); + } } } - } - if (limit == 0) {done = 1; ray_sucseeded = 0; printf("Reached limit on number of interactions, and discarded the neutron, was in volume %d\n", current_volume); ABSORB;} - #ifdef Union_trace_verbal_setting - printf("----------- END OF WHILE LOOP --------------------------------------\n"); - #endif + if (limit == 0) {done = 1; ray_sucseeded = 0; printf("Reached limit on number of interactions, and discarded the neutron, was in volume %d\n", current_volume); ABSORB;} + #ifdef Union_trace_verbal_setting + printf("----------- END OF WHILE LOOP --------------------------------------\n"); + #endif - } - // Could move all add_statistics and similar to this point, but need to filter for failed rays - if (ray_sucseeded == 1) { + } + // Could move all add_statistics and similar to this point, but need to filter for failed rays + if (ray_sucseeded == 1) { - // Ray sucseeded, need to check status of conditionals - #ifdef Union_trace_verbal_setting - printf("----------- logger loop --------------------------------------\n"); - #endif - // Loggers attatched to specific volumes need to be handled with care to avoid looping over all loggers for every ray - if (enable_conditionals == 1) { - for (log_index=loggers_with_data_array.used_elements-1; log_index>-1; log_index--) { - // Check all conditionals attatched to the current logger - this_logger = loggers_with_data_array.logger_pointers[log_index]; - conditional_status = 1; - for (iterator=0;iteratorconditional_list.num_elements;iterator++) { - // Call this particular conditional. If it fails, report the status and break - #ifdef Union_trace_verbal_setting - printf("Checking conditional number %d for logger named %s \n",iterator,loggers_with_data_array.logger_pointers[log_index]->name); - #endif - if (0 == this_logger->conditional_list.conditional_functions[iterator]( - this_logger->conditional_list.p_data_unions[iterator], - &ray_position, &ray_velocity, &p, &t, ¤t_volume, - &number_of_scattering_events, scattered_flag,scattered_flag_VP)) { - conditional_status = 0; - break; - } - } - if (conditional_status == 1) { - // If a logger does not have a conditional, it will write directly to perm, and not even add it to the loggers_with_data_array, thus we know the temp_to_perm function needs to be called - // The input for the temp_to_perm function is a pointer to the logger_data_union for the appropriate logger + // Ray sucseeded, need to check status of conditionals + #ifdef Union_trace_verbal_setting + printf("----------- logger loop --------------------------------------\n"); + #endif + // Loggers attatched to specific volumes need to be handled with care to avoid looping over all loggers for every ray + if (enable_conditionals == 1) { + for (log_index=loggers_with_data_array.used_elements-1; log_index>-1; log_index--) { + // Check all conditionals attatched to the current logger + this_logger = loggers_with_data_array.logger_pointers[log_index]; + conditional_status = 1; + for (iterator=0;iteratorconditional_list.num_elements;iterator++) { + // Call this particular conditional. If it fails, report the status and break + #ifdef Union_trace_verbal_setting + printf("Checking conditional number %d for logger named %s \n",iterator,loggers_with_data_array.logger_pointers[log_index]->name); + #endif + if (0 == this_logger->conditional_list.conditional_functions[iterator]( + this_logger->conditional_list.p_data_unions[iterator], + &ray_position, &ray_velocity, &p, &t, ¤t_volume, + &number_of_scattering_events, scattered_flag,scattered_flag_VP)) { + conditional_status = 0; + break; + } + } + if (conditional_status == 1) { + // If a logger does not have a conditional, it will write directly to perm, and not even add it to the loggers_with_data_array, thus we know the temp_to_perm function needs to be called + // The input for the temp_to_perm function is a pointer to the logger_data_union for the appropriate logger - if (loggers_with_data_array.logger_pointers[log_index]->function_pointers.select_t_to_p == 1) { - loggers_with_data_array.logger_pointers[log_index]->function_pointers.temp_to_perm(&loggers_with_data_array.logger_pointers[log_index]->data_union); - } - else if (loggers_with_data_array.logger_pointers[log_index]->function_pointers.select_t_to_p == 2) { - loggers_with_data_array.logger_pointers[log_index]->function_pointers.temp_to_perm_final_p(&loggers_with_data_array.logger_pointers[log_index]->data_union,p); - } + if (loggers_with_data_array.logger_pointers[log_index]->function_pointers.select_t_to_p == 1) { + loggers_with_data_array.logger_pointers[log_index]->function_pointers.temp_to_perm(&loggers_with_data_array.logger_pointers[log_index]->data_union); + } + else if (loggers_with_data_array.logger_pointers[log_index]->function_pointers.select_t_to_p == 2) { + loggers_with_data_array.logger_pointers[log_index]->function_pointers.temp_to_perm_final_p(&loggers_with_data_array.logger_pointers[log_index]->data_union,p); + } - // The user can set a condtional_extend_index, so that the evaluation of this specific conditional can be taken easily from extend - if (loggers_with_data_array.logger_pointers[log_index]->logger_extend_index != -1) { - #ifdef Union_trace_verbal_setting - printf("Updating logger_conditional_extend_array[%d] to 1 (max length = %d)\n", loggers_with_data_array.logger_pointers[log_index]->logger_extend_index, max_conditional_extend_index); - #endif - logger_conditional_extend_array[loggers_with_data_array.logger_pointers[log_index]->logger_extend_index] = 1; // Can be reached from EXTEND - // Are all reset to 0 for each new ray - #ifdef Union_trace_verbal_setting - printf("Updated extend index sucessfully\n"); - #endif - } + // The user can set a condtional_extend_index, so that the evaluation of this specific conditional can be taken easily from extend + if (loggers_with_data_array.logger_pointers[log_index]->logger_extend_index != -1) { + #ifdef Union_trace_verbal_setting + printf("Updating logger_conditional_extend_array[%d] to 1 (max length = %d)\n", loggers_with_data_array.logger_pointers[log_index]->logger_extend_index, max_conditional_extend_index); + #endif + logger_conditional_extend_array[loggers_with_data_array.logger_pointers[log_index]->logger_extend_index] = 1; // Can be reached from EXTEND + // Are all reset to 0 for each new ray + #ifdef Union_trace_verbal_setting + printf("Updated extend index sucessfully\n"); + #endif + } - // Need to remove the current element from logger_with_data as it has been cleared and written to disk - // The remaining elements is passed on to the next Union_master as it may fulfill the conditional after that master - if (global_master_list_master->elements[global_master_list_master->num_elements-1].component_index != INDEX_CURRENT_COMP) { - // Move current logger pointer in logger_with_data to end position - loggers_with_data_array.logger_pointers[log_index] = loggers_with_data_array.logger_pointers[loggers_with_data_array.used_elements-1]; - // Decrease logger_with_data.used_elements with 1 - loggers_with_data_array.used_elements--; - } - } - } + // Need to remove the current element from logger_with_data as it has been cleared and written to disk + // The remaining elements is passed on to the next Union_master as it may fulfill the conditional after that master + if (global_master_list_master->elements[global_master_list_master->num_elements-1].component_index != INDEX_CURRENT_COMP) { + // Move current logger pointer in logger_with_data to end position + loggers_with_data_array.logger_pointers[log_index] = loggers_with_data_array.logger_pointers[loggers_with_data_array.used_elements-1]; + // Decrease logger_with_data.used_elements with 1 + loggers_with_data_array.used_elements--; + } + } + } - // Perform the same loop with abs_loggers and their conditionals - for (log_index=abs_loggers_with_data_array.used_elements-1; log_index>-1; log_index--) { - // Check all conditionals attatched to the current logger - this_abs_logger = abs_loggers_with_data_array.abs_logger_pointers[log_index]; - conditional_status = 1; - for (iterator=0;iteratorconditional_list.num_elements;iterator++) { - // Call this particular conditional. If it fails, report the status and break - #ifdef Union_trace_verbal_setting - printf("Checking conditional number %d for abs logger named %s \n",iterator, abs_loggers_with_data_array.abs_logger_pointers[log_index]->name); - #endif - if (0 == this_abs_logger->conditional_list.conditional_functions[iterator]( - this_abs_logger->conditional_list.p_data_unions[iterator], - &ray_position, &ray_velocity, &p, &t, ¤t_volume, - &number_of_scattering_events, scattered_flag, scattered_flag_VP)) { - conditional_status = 0; - break; - } - } - if (conditional_status == 1) { - // If a logger does not have a conditional, it will write directly to perm, and not even add it to the loggers_with_data_array, thus we know the temp_to_perm function needs to be called - // The input for the temp_to_perm function is a pointer to the logger_data_union for the appropriate logger - abs_loggers_with_data_array.abs_logger_pointers[log_index]->function_pointers.temp_to_perm(&abs_loggers_with_data_array.abs_logger_pointers[log_index]->data_union); + // Perform the same loop with abs_loggers and their conditionals + for (log_index=abs_loggers_with_data_array.used_elements-1; log_index>-1; log_index--) { + // Check all conditionals attatched to the current logger + this_abs_logger = abs_loggers_with_data_array.abs_logger_pointers[log_index]; + conditional_status = 1; + for (iterator=0;iteratorconditional_list.num_elements;iterator++) { + // Call this particular conditional. If it fails, report the status and break + #ifdef Union_trace_verbal_setting + printf("Checking conditional number %d for abs logger named %s \n",iterator, abs_loggers_with_data_array.abs_logger_pointers[log_index]->name); + #endif + if (0 == this_abs_logger->conditional_list.conditional_functions[iterator]( + this_abs_logger->conditional_list.p_data_unions[iterator], + &ray_position, &ray_velocity, &p, &t, ¤t_volume, + &number_of_scattering_events, scattered_flag, scattered_flag_VP)) { + conditional_status = 0; + break; + } + } + if (conditional_status == 1) { + // If a logger does not have a conditional, it will write directly to perm, and not even add it to the loggers_with_data_array, thus we know the temp_to_perm function needs to be called + // The input for the temp_to_perm function is a pointer to the logger_data_union for the appropriate logger + abs_loggers_with_data_array.abs_logger_pointers[log_index]->function_pointers.temp_to_perm(&abs_loggers_with_data_array.abs_logger_pointers[log_index]->data_union); - // The user can set a condtional_extend_index, so that the evaluation of this specific conditional can be taken easily from extend - if (abs_loggers_with_data_array.abs_logger_pointers[log_index]->abs_logger_extend_index != -1) { - #ifdef Union_trace_verbal_setting - printf("Updating logger_conditional_extend_array[%d] to 1 (max length = %d)\n",abs_loggers_with_data_array.abs_logger_pointers[log_index]->abs_logger_extend_index,max_conditional_extend_index); - #endif - abs_logger_conditional_extend_array[abs_loggers_with_data_array.abs_logger_pointers[log_index]->abs_logger_extend_index] = 1; // Can be reached from EXTEND - // Are all reset to 0 for each new ray - #ifdef Union_trace_verbal_setting - printf("Updated extend index sucessfully\n"); - #endif - } + // The user can set a condtional_extend_index, so that the evaluation of this specific conditional can be taken easily from extend + if (abs_loggers_with_data_array.abs_logger_pointers[log_index]->abs_logger_extend_index != -1) { + #ifdef Union_trace_verbal_setting + printf("Updating logger_conditional_extend_array[%d] to 1 (max length = %d)\n",abs_loggers_with_data_array.abs_logger_pointers[log_index]->abs_logger_extend_index,max_conditional_extend_index); + #endif + abs_logger_conditional_extend_array[abs_loggers_with_data_array.abs_logger_pointers[log_index]->abs_logger_extend_index] = 1; // Can be reached from EXTEND + // Are all reset to 0 for each new ray + #ifdef Union_trace_verbal_setting + printf("Updated extend index sucessfully\n"); + #endif + } - // Need to remove the current element from logger_with_data as it has been cleared and written to disk - // The remaining elements is passed on to the next Union_master as it may fulfill the conditional after that master - if (global_master_list_master->elements[global_master_list_master->num_elements-1].component_index != INDEX_CURRENT_COMP) { - // Move current logger pointer in logger_with_data to end position - abs_loggers_with_data_array.abs_logger_pointers[log_index] = abs_loggers_with_data_array.abs_logger_pointers[abs_loggers_with_data_array.used_elements-1]; - // Decrease logger_with_data.used_elements with 1 - abs_loggers_with_data_array.used_elements--; - } + // Need to remove the current element from logger_with_data as it has been cleared and written to disk + // The remaining elements is passed on to the next Union_master as it may fulfill the conditional after that master + if (global_master_list_master->elements[global_master_list_master->num_elements-1].component_index != INDEX_CURRENT_COMP) { + // Move current logger pointer in logger_with_data to end position + abs_loggers_with_data_array.abs_logger_pointers[log_index] = abs_loggers_with_data_array.abs_logger_pointers[abs_loggers_with_data_array.used_elements-1]; + // Decrease logger_with_data.used_elements with 1 + abs_loggers_with_data_array.used_elements--; + } + } + } } - } - } - if (enable_tagging && stop_tagging_ray == 0) { - conditional_status = 1; - for (iterator=0; iteratornum_elements; iterator++) { - // Call this particular conditional. If it fails, report the status and break - // Since a conditional can work for a logger and master_tagging at the same time, it may be evaluated twice - #ifdef Union_trace_verbal_setting - printf("Checking tagging conditional number %d\n",iterator); - #endif - if (0 == tagging_conditional_list->conditional_functions[iterator]( - tagging_conditional_list->p_data_unions[iterator], - &ray_position, &ray_velocity, &p, &t, ¤t_volume, - &number_of_scattering_events, scattered_flag,scattered_flag_VP)) { - conditional_status = 0; - break; - } - } - if (conditional_status == 1) { - tagging_conditional_extend = 1; - #ifdef Union_trace_verbal_setting - printf("Before adding statistics to node: current_tagging_nodbe->intensity = %f\n",current_tagging_node->intensity); - printf("Before adding statistics to node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) { + conditional_status = 1; + for (iterator=0; iteratornum_elements; iterator++) { + // Call this particular conditional. If it fails, report the status and break + // Since a conditional can work for a logger and master_tagging at the same time, it may be evaluated twice + #ifdef Union_trace_verbal_setting + printf("Checking tagging conditional number %d\n",iterator); + #endif + if (0 == tagging_conditional_list->conditional_functions[iterator]( + tagging_conditional_list->p_data_unions[iterator], + &ray_position, &ray_velocity, &p, &t, ¤t_volume, + &number_of_scattering_events, scattered_flag,scattered_flag_VP)) { + conditional_status = 0; + break; + } + } + if (conditional_status == 1) { + tagging_conditional_extend = 1; + #ifdef Union_trace_verbal_setting + printf("Before adding statistics to node: current_tagging_nodbe->intensity = %f\n",current_tagging_node->intensity); + printf("Before adding statistics to node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif - add_statistics_to_node(current_tagging_node,&ray_position, &ray_velocity, &p, &tagging_leaf_counter); + add_statistics_to_node(current_tagging_node,&ray_position, &ray_velocity, &p, &tagging_leaf_counter); - #ifdef Union_trace_verbal_setting - printf("After adding statistics to node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - printf("After adding statistics to node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif - } - } + #ifdef Union_trace_verbal_setting + printf("After adding statistics to node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + printf("After adding statistics to node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif + } + } - // Move the rays a nano meter away from the surface it left, in case activation counter > 1, this will prevent the ray from starting on a volume boundery - x += vx*1E-9; y += vy*1E-9; z += vz*1E-9; t += 1E-9; + // Move the rays a nano meter away from the surface it left, in case activation counter > 1, this will prevent the ray from starting on a volume boundery + x += vx*1E-9; y += vy*1E-9; z += vz*1E-9; t += 1E-9; - } else { - ABSORB; // Absorb rays that didn't exit correctly for whatever reason - // Could error log here - } + } else { + ABSORB; // Absorb rays that didn't exit correctly for whatever reason + // Could error log here + } - // Stores nubmer of scattering events in global master list so that another master with inherit_number_of_scattering_events can continue - global_master_list_master->elements[this_global_master_index].stored_number_of_scattering_events = number_of_scattering_events; + // Stores nubmer of scattering events in global master list so that another master with inherit_number_of_scattering_events can continue + global_master_list_master->elements[this_global_master_index].stored_number_of_scattering_events = number_of_scattering_events; + %} From 8d07185c38592d87a2760abb9b29f69959d58dc2 Mon Sep 17 00:00:00 2001 From: Diablo Date: Wed, 4 Feb 2026 16:25:43 +0100 Subject: [PATCH 04/11] Add support for mu calculation, but not proper sampling yet --- mcstas-comps/share/union-lib.c | 53 ++-- .../Inhomogenous_incoherent_process.comp | 255 +++++++++--------- mcstas-comps/union/Union_master.comp | 56 +++- 3 files changed, 212 insertions(+), 152 deletions(-) diff --git a/mcstas-comps/share/union-lib.c b/mcstas-comps/share/union-lib.c index 3c8007312..d13ab3358 100755 --- a/mcstas-comps/share/union-lib.c +++ b/mcstas-comps/share/union-lib.c @@ -501,36 +501,45 @@ union data_transfer_union{ struct scattering_process_struct { -char name[256]; // User defined process name -enum process eProcess; // enum value corresponding to this process GPU -double process_p_interact; // double between 0 and 1 that describes the fraction of events forced to undergo this process. -1 for disable -int non_isotropic_rot_index; // -1 if process is isotrpic, otherwise is the index of the process rotation matrix in the volume -int needs_cross_section_focus; // 1 if physics_my needs to call focus functions, otherwise -1 -Rotation rotation_matrix; // rotation matrix of process, reported by component in local frame, transformed and moved to volume struct in main - -union data_transfer_union data_transfer; // The way to reach the storage space allocated for this process (see examples in process.comp files) - -// probability_for_scattering_functions calculates this probability given k_i and parameters -int (*probability_for_scattering_function)(double*,double*,union data_transfer_union,struct focus_data_struct*, _class_particle *_particle); -// prop, k_i, ,parameters , focus data / function - -// A scattering_function takes k_i and parameters, returns k_f -int (*scattering_function)(double*,double*,double*,union data_transfer_union,struct focus_data_struct*, _class_particle *_particle); -// k_f, k_i, weight, parameters , focus data / function -}; - -//Utility function for initialising a scattering_process_struct with default -//values: -void scattering_process_struct_init( struct scattering_process_struct * sps ) + char name[256]; // User defined process name + enum process eProcess; // enum value corresponding to this process GPU + double process_p_interact; // double between 0 and 1 that describes the fraction of events forced to undergo this process. -1 for disable + int non_isotropic_rot_index; // -1 if process is isotrpic, otherwise is the index of the process rotation matrix in the volume + int needs_cross_section_focus; // 1 if physics_my needs to call focus functions, otherwise -1 + int needs_numerical_integration; // 1 if the process is inhomogenous and therefore needs numerical integration, otherwise -1. + Rotation rotation_matrix; // rotation matrix of process, reported by component in local frame, transformed and moved to volume struct in main + double *inhomogenous_cumul_prob; // The cumulative probability of a process in case of inhomogenous processes + double *inhomogenous_distances; // The distance of each step in which the cumulative probabilities will be calculated. + double *inhomogenous_cumul_distances; // The cumulative distances + double *inhomogenous_mu; // The different attenuation coefficients that are sampled in the numerical integration + double *inhomogenous_t; // The different times at which mu must be sampled. + int sampl_size; // Maximum number of samplings performed. If it is -1, no sampling has been done, and the arrays must be malloc'ed. + union data_transfer_union data_transfer; // The way to reach the storage space allocated for this process (see examples in process.comp files) + + // probability_for_scattering_functions calculates this probability given k_i and parameters + int (*probability_for_scattering_function)(double *, double *, union data_transfer_union, struct focus_data_struct *, _class_particle *_particle); + // prop, k_i, ,parameters , focus data / function + + // A scattering_function takes k_i and parameters, returns k_f + int (*scattering_function)(double *, double *, double *, union data_transfer_union, struct focus_data_struct *, _class_particle *_particle); + // k_f, k_i, weight, parameters , focus data / function +}; + +// Utility function for initialising a scattering_process_struct with default +// values: +void scattering_process_struct_init(struct scattering_process_struct *sps) { - memset(sps,0,sizeof(struct scattering_process_struct));//catch all + memset(sps, 0, sizeof(struct scattering_process_struct)); // catch all sps->name[0] = '\0'; sps->probability_for_scattering_function = NULL; sps->scattering_function = NULL; sps->non_isotropic_rot_index = -1; sps->needs_cross_section_focus = -1; + sps->needs_numerical_integration = -1; + sps->sampl_size = -1; } + union surface_data_transfer_union { struct Mirror_surface_storage_struct *pointer_to_a_Mirror_surface_storage_struct; diff --git a/mcstas-comps/union/Inhomogenous_incoherent_process.comp b/mcstas-comps/union/Inhomogenous_incoherent_process.comp index 12fa7ef87..cb28cb1a8 100755 --- a/mcstas-comps/union/Inhomogenous_incoherent_process.comp +++ b/mcstas-comps/union/Inhomogenous_incoherent_process.comp @@ -61,156 +61,159 @@ SETTING PARAMETERS(string inhomogenous_function = "", sigma=5.08, f_QE=0, gamma= /* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */ SHARE -%{ -%include "tinyexpr.h" -%include "tinyexpr.c" -#ifndef Union -#error "The Union_init component must be included before this Incoherent_process component" -#endif - - -struct Inhomogenous_incoherent_struct{ - // Variables that needs to be transfered between any of the following places: - // The initialize in this component - // The function for calculating my - // The function for calculating scattering - double my_scattering; - double QE_sampling_frequency; - double lorentzian_width; - -}; +%{ + %include "tinyexpr.h" + %include "tinyexpr.c" + #ifndef Union + #error "The Union_init component must be included before this Incoherent_process component" + #endif + + struct Inhomogenous_incoherent_struct{ + // Variables that needs to be transfered between any of the following places: + // The initialize in this component + // The function for calculating my + // The function for calculating scattering + double my_scattering; + double QE_sampling_frequency; + double lorentzian_width; + }; -// Function for calculating my in Incoherent case -int Inhomogenous_incoherent_physics_my(double *my,double *k_initial, union data_transfer_union data_transfer, struct focus_data_struct *focus_data, _class_particle *_particle) { - *my = data_transfer.Inhomogenous_incoherent_struct->my_scattering; - return 1; -}; -// Function for basic incoherent scattering event -int Inhomogenous_incoherent_physics_scattering(double *k_final, double *k_initial, double *weight, union data_transfer_union data_transfer, struct focus_data_struct *focus_data, _class_particle *_particle) { + // Function for calculating my in Incoherent case + int Inhomogenous_incoherent_physics_my(double *my,double *k_initial, union data_transfer_union data_transfer, struct focus_data_struct *focus_data, _class_particle *_particle) { + *my = data_transfer.Inhomogenous_incoherent_struct->my_scattering; + return 1; + }; - //New version of incoherent scattering - double k_length = sqrt(k_initial[0]*k_initial[0]+k_initial[1]*k_initial[1]+k_initial[2]*k_initial[2]); + // Function for basic incoherent scattering event + int Inhomogenous_incoherent_physics_scattering(double *k_final, double *k_initial, double *weight, union data_transfer_union data_transfer, struct focus_data_struct *focus_data, _class_particle *_particle) { - Coords k_out; - // Here is the focusing system in action, get a vector - double solid_angle; - focus_data->focusing_function(&k_out,&solid_angle,focus_data); - NORM(k_out.x,k_out.y,k_out.z); - *weight *= solid_angle*0.25/PI; + //New version of incoherent scattering + double k_length = sqrt(k_initial[0]*k_initial[0]+k_initial[1]*k_initial[1]+k_initial[2]*k_initial[2]); + + Coords k_out; + // Here is the focusing system in action, get a vector + double solid_angle; + focus_data->focusing_function(&k_out,&solid_angle,focus_data); + NORM(k_out.x,k_out.y,k_out.z); + *weight *= solid_angle*0.25/PI; - double v_i,v_f,E_i,dE,E_f; + double v_i,v_f,E_i,dE,E_f; - if (rand01() < data_transfer.Inhomogenous_incoherent_struct->QE_sampling_frequency) { - v_i = k_length * K2V; - E_i = VS2E*v_i*v_i; - dE = data_transfer.Inhomogenous_incoherent_struct->lorentzian_width*tan(PI/2*randpm1()); - E_f = E_i + dE; - if (E_f <= 0) - return 0; - v_f = SE2V*sqrt(E_f); - k_length = v_f*V2K; - } + if (rand01() < data_transfer.Inhomogenous_incoherent_struct->QE_sampling_frequency) { + v_i = k_length * K2V; + E_i = VS2E*v_i*v_i; + dE = data_transfer.Inhomogenous_incoherent_struct->lorentzian_width*tan(PI/2*randpm1()); + E_f = E_i + dE; + if (E_f <= 0) + return 0; + v_f = SE2V*sqrt(E_f); + k_length = v_f*V2K; + } - k_final[0] = k_out.x*k_length; k_final[1] = k_out.y*k_length; k_final[2] = k_out.z*k_length; - return 1; -}; + k_final[0] = k_out.x*k_length; k_final[1] = k_out.y*k_length; k_final[2] = k_out.z*k_length; + return 1; + }; -#ifndef PROCESS_DETECTOR - #define PROCESS_DETECTOR dummy -#endif + #ifndef PROCESS_DETECTOR + #define PROCESS_DETECTOR dummy + #endif -#ifndef PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR - #define PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR dummy -#endif + #ifndef PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR + #define PROCESS_INHOMOGENOUS_INCOHERENT_DETECTOR dummy + #endif %} DECLARE %{ -// Needed for transport to the main component -struct global_process_element_struct global_process_element; -struct scattering_process_struct This_process; + // Needed for transport to the main component + struct global_process_element_struct global_process_element; + struct scattering_process_struct This_process; -// Declare for this component, to do calculations on the input / store in the transported data -struct Inhomogenous_incoherent_struct Inhomogenous_storage; -double effective_my_scattering; + // Declare for this component, to do calculations on the input / store in the transported data + struct Inhomogenous_incoherent_struct Inhomogenous_storage; + double effective_my_scattering; %} INITIALIZE %{ - if (!strcmp(inhomogenous_function, "")){ - fprintf(stderr, "\nERROR! No Inhomogenous function was set!\tEXITING!\n\n"); - exit(1); - } - double pos_x, pos_y, pos_z, vel_x, vel_y, vel_z, t; - /* Store variable names and pointers. */ - te_variable vars[] = {{"pos_x", &pos_x}, {"pos_y", &pos_y}, {"pos_z", &pos_z}, - {"vel_x", &vel_x}, {"vel_y", &vel_y}, {"vel_z", &vel_z}, - {"t", &t}}; - - int err; - /* Compile the expression with variables. */ - pos_x = 10; - // pos_y = 10; - // pos_z = 10; - // vel_x = 10; - // vel_y = 10; - // vel_z = 10; - // t = 10; - te_expr *expr = te_compile(inhomogenous_function, vars, 7, &err); - if (expr){ - double result = te_eval(expr); - printf("\nResult of inhomogenous_function is %g\n\n", result); - te_free(expr); - } else { - printf("Parse error at %d\n", err); - } - // Initialize done in the component - effective_my_scattering = ((packing_factor/unit_cell_volume) * 100 * sigma); - Inhomogenous_storage.my_scattering = effective_my_scattering; + if (!strcmp(inhomogenous_function, "")){ + fprintf(stderr, "\nERROR! No Inhomogenous function was set!\tEXITING!\n\n"); + exit(1); + } + double pos_x, pos_y, pos_z, vel_x, vel_y, vel_z, t; + /* Store variable names and pointers. */ + te_variable vars[] = {{"pos_x", &pos_x}, {"pos_y", &pos_y}, {"pos_z", &pos_z}, + {"vel_x", &vel_x}, {"vel_y", &vel_y}, {"vel_z", &vel_z}, + {"t", &t}}; + + int err; + /* Compile the expression with variables. */ + pos_x = 10; + // pos_y = 10; + // pos_z = 10; + // vel_x = 10; + // vel_y = 10; + // vel_z = 10; + // t = 10; + te_expr *expr = te_compile(inhomogenous_function, vars, 7, &err); + if (expr){ + double result = te_eval(expr); + printf("\nResult of inhomogenous_function is %g\n\n", result); + te_free(expr); + } else { + printf("Parse error at %d\n", err); + } + // Initialize done in the component + effective_my_scattering = ((packing_factor/unit_cell_volume) * 100 * sigma); + Inhomogenous_storage.my_scattering = effective_my_scattering; - Inhomogenous_storage.QE_sampling_frequency = f_QE; - Inhomogenous_storage.lorentzian_width = gamma; - - //First initialise This_process with default values: - scattering_process_struct_init(&This_process); - - // Need to specify if this process is isotropic - This_process.non_isotropic_rot_index = -1; // Yes (powder) - //This_process.non_isotropic_rot_index = 1; // No (single crystal) + Inhomogenous_storage.QE_sampling_frequency = f_QE; + Inhomogenous_storage.lorentzian_width = gamma; + //Inhomogenous_storage.position = coords_set(0,0,0); + //Inhomogenous_storage.speed = coords_set(0,0,0); + //Inhomogenous_storage.time = 0; + + //First initialise This_process with default values: + scattering_process_struct_init(&This_process); + + // Need to specify if this process is isotropic + This_process.non_isotropic_rot_index = -1; // Yes (powder) + //This_process.non_isotropic_rot_index = 1; // No (single crystal) - // Need to specify if this process need to use focusing in calculation of inverse penetration depth (physics_my) - //This_process.needs_cross_section_focus = 1; // Yes - This_process.needs_cross_section_focus = -1; // No - - // The type of the process must be saved in the global enum process - This_process.eProcess = Inhomogenous_incoherent; - - // Packing the data into a structure that is transported to the main component - sprintf(This_process.name,"%s",NAME_CURRENT_COMP); - This_process.process_p_interact = interact_fraction; - This_process.data_transfer.Inhomogenous_incoherent_struct = &Inhomogenous_storage; - //This_process.data_transfer.pointer_to_a_Incoherent_physics_storage_struct->my_scattering = effective_my_scattering; - This_process.probability_for_scattering_function = &Inhomogenous_incoherent_physics_my; - This_process.scattering_function = &Inhomogenous_incoherent_physics_scattering; - - // This will be the same for all process's, and can thus be moved to an include. - sprintf(global_process_element.name,"%s",NAME_CURRENT_COMP); - global_process_element.component_index = INDEX_CURRENT_COMP; - global_process_element.p_scattering_process = &This_process; - - if (_getcomp_index(init) < 0) { - fprintf(stderr,"Incoherent_process:%s: Error identifying Union_init component, %s is not a known component name.\n", - NAME_CURRENT_COMP, init); - exit(-1); - } - - struct pointer_to_global_process_list *global_process_list = COMP_GETPAR3(Union_init, init, global_process_list); - add_element_to_process_list(global_process_list, global_process_element); + // Need to specify if this process need to use focusing in calculation of inverse penetration depth (physics_my) + //This_process.needs_cross_section_focus = 1; // Yes + This_process.needs_cross_section_focus = -1; // No + + // The type of the process must be saved in the global enum process + This_process.eProcess = Inhomogenous_incoherent; + + // Packing the data into a structure that is transported to the main component + sprintf(This_process.name,"%s",NAME_CURRENT_COMP); + This_process.process_p_interact = interact_fraction; + This_process.data_transfer.Inhomogenous_incoherent_struct = &Inhomogenous_storage; + //This_process.data_transfer.pointer_to_a_Incoherent_physics_storage_struct->my_scattering = effective_my_scattering; + This_process.probability_for_scattering_function = &Inhomogenous_incoherent_physics_my; + This_process.scattering_function = &Inhomogenous_incoherent_physics_scattering; + This_process.needs_numerical_integration = 1; + + // This will be the same for all process's, and can thus be moved to an include. + sprintf(global_process_element.name,"%s",NAME_CURRENT_COMP); + global_process_element.component_index = INDEX_CURRENT_COMP; + global_process_element.p_scattering_process = &This_process; + + if (_getcomp_index(init) < 0) { + fprintf(stderr,"Incoherent_process:%s: Error identifying Union_init component, %s is not a known component name.\n", + NAME_CURRENT_COMP, init); + exit(-1); + } + + struct pointer_to_global_process_list *global_process_list = COMP_GETPAR3(Union_init, init, global_process_list); + add_element_to_process_list(global_process_list, global_process_element); %} TRACE diff --git a/mcstas-comps/union/Union_master.comp b/mcstas-comps/union/Union_master.comp index 242833aaf..78d2468da 100755 --- a/mcstas-comps/union/Union_master.comp +++ b/mcstas-comps/union/Union_master.comp @@ -1545,7 +1545,7 @@ TRACE } /* Plan for adding in inhomogenous processes: - - The processes will have a flag, that checks if they require + - The processes will have a flag (needs_numerical_integration), that checks if they require numerical integration. - If they do, then we use a numerical integration algorithm, where we sample my from the process at different points. @@ -1564,11 +1564,59 @@ TRACE process = &Volumes[current_volume]->p_physics->p_scattering_array[p_index]; // GPU Allowed int physics_output; - physics_output = physics_my(process->eProcess, p_my_trace, k_rotated, process->data_transfer, this_focus_data, _particle); - + double mu; + if (process->needs_numerical_integration == 1){ + // First, check if the arrays are big enough to handle this + double sampling_size = 10; + double dist = length_to_boundary/sampling_size; + if (process->sampl_size == -1){ + // First numerical integration for this process. Allocate the arrays + process->inhomogenous_distances = malloc(sizeof(double)*sampling_size); + process->inhomogenous_cumul_distances = malloc(sizeof(double)*sampling_size); + process->inhomogenous_cumul_prob = malloc(sizeof(double)*sampling_size); + process->inhomogenous_mu = malloc(sizeof(double)*sampling_size); + } else if (process->sampl_size>=sampling_size){ + // Reallocate the three numerical integration arrays, to allow for this larger array + double *temp; + temp = realloc(process->inhomogenous_distances, sizeof(double)*sampling_size); + process->inhomogenous_distances = temp; + temp = realloc(process->inhomogenous_cumul_distances, sizeof(double)*sampling_size); + process->inhomogenous_cumul_distances = temp; + temp = realloc(process->inhomogenous_cumul_prob, sizeof(double)*sampling_size); + process->inhomogenous_cumul_prob = temp; + temp = realloc(process->inhomogenous_mu, sizeof(double)*sampling_size); + process->inhomogenous_mu = temp; + } + // Populate length and probability arrays: + Coords original_position = coords_set(x,y,z); + for (int i=0; iinhomogenous_distances[i] = dist; + process->inhomogenous_cumul_distances[i] = i > 0 ? process->inhomogenous_cumul_distances[i-1] + dist: dist/2; + // Transport neutron to place inside geometry + ray_velocity = coords_set(vx,vy,vz); + // Find location of scattering point in master coordinate system without changing main position / velocity variables + Coords direction = coords_scalar_mult(ray_velocity, 1.0/length_of_position_vector(ray_velocity)); + Coords sampling_displacement = coords_scalar_mult(direction, process->inhomogenous_cumul_distances[i]); + Coords sampling_point = coords_add(ray_position, sampling_displacement); + Coords sampling_point_geometry = coords_sub(sampling_point, Volumes[current_volume]->geometry.center); + // Calculate mu and probability + coords_get(sampling_point_geometry, &x, &y, &z); + physics_my(process->eProcess, &mu, k_rotated, process->data_transfer, this_focus_data, _particle); + process->inhomogenous_mu[i] = mu/sampling_size; + // TODO: add cumulative probability calculations. + } + coords_get(original_position, &x, &y, &z); + *p_my_trace = 0; + for (int i=0; iinhomogenous_mu[i]; + } else { + physics_output = physics_my(process->eProcess, p_my_trace, k_rotated, process->data_transfer, this_focus_data, _particle); + } + + printf("p_my_trace = %g\t For Process %d\n", *p_my_trace, process->eProcess); my_sum += *p_my_trace; #ifdef Union_trace_verbal_setting - printf("my_trace = %f, my_sum = %f\n",*p_my_trace,my_sum); + printf("my_trace = %f, my_sum = %f\n",*p_my_trace,my_sum); #endif // increment the pointers so that it point to the next element (max number of process in any material is allocated) p_my_trace++; From 30f60b67a0347928173a8296c3d1bed0cea611b2 Mon Sep 17 00:00:00 2001 From: Diablo Date: Thu, 5 Feb 2026 09:54:04 +0100 Subject: [PATCH 05/11] Update auto formatting with the small error with indentation for true one liner if statements. --- mcstas-comps/union/Union_master.comp | 142 +++++++++++++-------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/mcstas-comps/union/Union_master.comp b/mcstas-comps/union/Union_master.comp index 78d2468da..d5310740e 100755 --- a/mcstas-comps/union/Union_master.comp +++ b/mcstas-comps/union/Union_master.comp @@ -376,7 +376,7 @@ INITIALIZE // Set the component index of the previous Union_master component if one exists if (global_master_list_master->num_elements == 1) previous_master_index = 0; // no previous index - else previous_master_index = global_master_list_master->elements[global_master_list_master->num_elements-2].component_index; // -2 because of zero indexing and needing the previous index. + else previous_master_index = global_master_list_master->elements[global_master_list_master->num_elements-2].component_index; // -2 because of zero indexing and needing the previous index. //printf("Assigned previous_master_index = %d \n",previous_master_index); // All volumes in the global_geometry_list_master is being check for activity using the number_of_activations input made for each geometry (default is 1) @@ -390,8 +390,8 @@ INITIALIZE global_geometry_list_master->elements[iterator].activation_counter--; number_of_volumes++; if (global_geometry_list_master->elements[iterator].Volume->geometry.is_mask_volume == 1) number_of_masks++; - if (global_geometry_list_master->elements[iterator].Volume->geometry.is_masked_volume == 1) number_of_masked_volumes++; - } else global_geometry_list_master->elements[iterator].active = 0; + if (global_geometry_list_master->elements[iterator].Volume->geometry.is_masked_volume == 1) number_of_masked_volumes++; + } else global_geometry_list_master->elements[iterator].active = 0; } // Allocation of global lists @@ -399,12 +399,12 @@ INITIALIZE geometry_component_index_list.elements = malloc( geometry_component_index_list.num_elements * sizeof(int)); mask_volume_index_list.num_elements = number_of_masks; if (number_of_masks >0) mask_volume_index_list.elements = malloc( number_of_masks * sizeof(int)); - mask_status_list.num_elements = number_of_masks; + mask_status_list.num_elements = number_of_masks; if (number_of_masks >0) mask_status_list.elements = malloc( number_of_masks * sizeof(int)); - current_mask_intersect_list_status.num_elements = number_of_masked_volumes; + current_mask_intersect_list_status.num_elements = number_of_masked_volumes; if (number_of_masked_volumes >0) current_mask_intersect_list_status.elements = malloc( number_of_masked_volumes * sizeof(int)); - // Make a list of component index from each volume index + // Make a list of component index from each volume index volume_index = 0; for (iterator=0;iteratornum_elements;iterator++) { if (global_geometry_list_master->elements[iterator].active == 1) @@ -749,7 +749,7 @@ INITIALIZE } if (number_of_process_interacts_set == 0) Volumes[volume_index]->p_physics->interact_control = 0; - else Volumes[volume_index]->p_physics->interact_control = 1; + else Volumes[volume_index]->p_physics->interact_control = 1; // If all are set, check if they need renormalization so that the sum is one. if (number_of_process_interacts_set == Volumes[volume_index]->p_physics->number_of_processes) { @@ -790,9 +790,9 @@ INITIALIZE // If the volume is a mask, its volume number is added to the mask_volume_index list so volume index can be converted to mask_index. if (Volumes[volume_index]->geometry.is_mask_volume == 1) Volumes[volume_index]->geometry.mask_index = mask_index_main; - if (Volumes[volume_index]->geometry.is_mask_volume == 1) mask_volume_index_list.elements[mask_index_main++] = volume_index; + if (Volumes[volume_index]->geometry.is_mask_volume == 1) mask_volume_index_list.elements[mask_index_main++] = volume_index; - // Check all loggers assosiated with this volume and update the max_conditional_extend_index if necessary + // Check all loggers assosiated with this volume and update the max_conditional_extend_index if necessary for (iterator=0;iteratorloggers.num_elements;iterator++) { for (process_index=0;process_indexloggers.p_logger_volume[iterator].num_elements;process_index++) { if (Volumes[volume_index]->loggers.p_logger_volume[iterator].p_logger_process[process_index] != NULL) { @@ -882,8 +882,8 @@ INITIALIZE if (verbal) printf("\n ---- Overview of the lists generated for each volume ---- \n"); - if (verbal) printf("List overview for surrounding vacuum\n"); - for (volume_index_main=0;volume_index_maingeometry.children,string_output); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.children,string_output); - if (verbal) sprintf(string_output,"Direct_children for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.direct_children,string_output); + if (verbal) sprintf(string_output,"Direct_children for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.direct_children,string_output); - if (verbal) sprintf(string_output,"Intersect_check_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.intersect_check_list,string_output); + if (verbal) sprintf(string_output,"Intersect_check_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.intersect_check_list,string_output); - if (verbal) sprintf(string_output,"Mask_intersect_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_intersect_list,string_output); + if (verbal) sprintf(string_output,"Mask_intersect_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_intersect_list,string_output); - if (verbal) sprintf(string_output,"Destinations_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.destinations_list,string_output); + if (verbal) sprintf(string_output,"Destinations_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.destinations_list,string_output); - //if (verbal) sprintf(string_output,"Destinations_logic_list for Volume %d",volume_index_main); + //if (verbal) sprintf(string_output,"Destinations_logic_list for Volume %d",volume_index_main); //if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.destinations_logic_list,string_output); if (verbal) sprintf(string_output,"Reduced_destinations_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.reduced_destinations_list,string_output); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.reduced_destinations_list,string_output); - if (verbal) sprintf(string_output,"Next_volume_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.next_volume_list,string_output); + if (verbal) sprintf(string_output,"Next_volume_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.next_volume_list,string_output); - if (verbal) { + if (verbal) { if (volume_index_main != 0) printf(" Is_vacuum for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->p_physics->is_vacuum); } @@ -944,17 +944,17 @@ INITIALIZE } if (verbal) sprintf(string_output,"mask_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_list,string_output); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.mask_list,string_output); - if (verbal) sprintf(string_output,"masked_by_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_list,string_output); + if (verbal) sprintf(string_output,"masked_by_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_list,string_output); - if (verbal) sprintf(string_output,"masked_by_mask_index_list for Volume %d",volume_index_main); - if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_mask_index_list,string_output); + if (verbal) sprintf(string_output,"masked_by_mask_index_list for Volume %d",volume_index_main); + if (verbal) print_1d_int_list(Volumes[volume_index_main]->geometry.masked_by_mask_index_list,string_output); - if (verbal) printf(" mask_mode for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.mask_mode); - if (verbal) printf("\n"); - } + if (verbal) printf(" mask_mode for Volume %d = %d\n",volume_index_main,Volumes[volume_index_main]->geometry.mask_mode); + if (verbal) printf("\n"); + } ) // End of MPI_MASTER @@ -981,7 +981,7 @@ INITIALIZE intersection_time_table.n_elements[iterator] = (int) 2; // number of intersection for all other geometries } if (iterator == 0) intersection_time_table.n_elements[iterator] = (int) 0; // number of intersection solutions - intersection_time_table.calculated[iterator] = (int) 0; // Initializing calculated logic + intersection_time_table.calculated[iterator] = (int) 0; // Initializing calculated logic if (iterator == 0) { intersection_time_table.intersection_times[0] = NULL; @@ -1157,12 +1157,12 @@ TRACE current_tagging_node = master_tagging_node_list.elements[current_volume]; stop_tagging_ray = 0; // Allow this ray to be tracked if (tagging_leaf_counter > history_limit) stop_creating_nodes = 1; - } + } #ifdef Union_trace_verbal_setting if (enable_tagging) printf("current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging) printf("current_tagging_node->number_of_rays = %d \n",current_tagging_node->number_of_rays); - #endif + if (enable_tagging) printf("current_tagging_node->number_of_rays = %d \n",current_tagging_node->number_of_rays); + #endif // Propagation loop including scattering // This while loop continues until the ray leaves the ensamble of user defined volumes either through volume 0 @@ -1304,7 +1304,7 @@ TRACE printf("The mask status was 1, can actually skip intersection calculation for current volume \n"); #endif if (intersection_with_children == 1) break; - } + } } } } @@ -1469,7 +1469,7 @@ TRACE // Sample length_to_scattering in linear manner forced_length_to_scattering = safety_distance + rand01()*(length_to_boundary - safety_distance2); - ray_velocity = coords_set(vx,vy,vz); // Test for root cause + ray_velocity = coords_set(vx,vy,vz); // Test for root cause // Find location of scattering point in master coordinate system without changing main position / velocity variables Coords direction = coords_scalar_mult(ray_velocity, 1.0/length_of_position_vector(ray_velocity)); Coords scattering_displacement = coords_scalar_mult(direction, forced_length_to_scattering); @@ -1663,7 +1663,7 @@ TRACE abs_weight_factor_set = 1; // Safety feature, alert in case of nonsense my results / negative absorption if (my_sum/my_sum_plus_abs > 1.0) printf("WARNING: Absorption weight factor above 1! Should not happen! \n"); - // Select process + // Select process if (Volumes[current_volume]->p_physics->number_of_processes == 1) { // trivial case // Select the only available process, which will always have index 0 selected_process = 0; @@ -1903,7 +1903,7 @@ TRACE v_length = sqrt(vx*vx+vy*vy+vz*vz); k_new[0] = V2K*vx; k_new[1] = V2K*vy; k_new[2] = V2K*vz; if (verbal) if (v_length < 1) printf("velocity set to less than 1\n"); - ray_velocity = coords_set(vx,vy,vz); + ray_velocity = coords_set(vx,vy,vz); #ifdef Union_trace_verbal_setting printf("Running logger system for specific volumes \n"); @@ -1949,8 +1949,8 @@ TRACE printf("r = (%f,%f,%f) v = (%f,%f,%f) \n",x,y,z,vx,vy,vz); if (enable_tagging && stop_tagging_ray == 0) printf("Before new process node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("Before new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); + #endif if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_process_node(current_tagging_node, selected_process,Volumes[current_volume], &stop_tagging_ray,stop_creating_nodes); @@ -1958,8 +1958,8 @@ TRACE #ifdef Union_trace_verbal_setting if (enable_tagging && stop_tagging_ray == 0) printf("After new process node: current_tagging_node->intensity = %f\n", current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("After new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("After new process node: current_tagging_node->number_of_rays = %d\n", current_tagging_node->number_of_rays); + #endif } else { previous_volume = current_volume; // Record the current volume as previous, as this will change in this branch of the code @@ -2014,17 +2014,17 @@ TRACE #ifdef Union_trace_verbal_setting if (enable_tagging) printf("tree method moves from %d to %d\n",current_volume,tree_next_volume); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); + if (enable_tagging && stop_tagging_ray == 0) printf("Before new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); #ifdef Union_trace_verbal_setting if (enable_tagging && stop_tagging_ray == 0) printf("After new tree volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("After new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("After new tree volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif // Set next volume to the solution found in the tree method current_volume = tree_next_volume; @@ -2036,8 +2036,8 @@ TRACE } else { #ifdef Union_trace_verbal_setting if (enable_tagging && stop_tagging_ray == 0) printf("Before new intersection volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging && stop_tagging_ray == 0) printf("Before new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif + if (enable_tagging && stop_tagging_ray == 0) printf("Before new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif // Mask update: If the min_volume is not a mask, things are simple, current_volume = min_volume. // however, if it is a mask, the mask status will switch. @@ -2116,7 +2116,7 @@ TRACE printf("The method found the next tree volume to be %d\n",tree_next_volume); #endif if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes, &stop_tagging_ray, stop_creating_nodes); - current_volume = tree_next_volume; + current_volume = tree_next_volume; } else { #ifdef Union_trace_verbal_setting printf("Many elements in destinations list, use within_which_volume\n"); @@ -2126,7 +2126,7 @@ TRACE tree_next_volume = within_which_volume_GPU(ray_position, Volumes[min_volume]->geometry.reduced_destinations_list, Volumes[min_volume]->geometry.destinations_list, Volumes, &mask_status_list, number_of_volumes, pre_allocated1, pre_allocated2, pre_allocated3); if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes,&stop_tagging_ray,stop_creating_nodes); - current_volume = tree_next_volume; + current_volume = tree_next_volume; #ifdef Union_trace_verbal_setting printf("Set new new volume to %d\n",tree_next_volume); #endif @@ -2152,7 +2152,7 @@ TRACE if (Volumes[tree_next_volume]->geometry.priority_value > Volumes[current_volume]->geometry.priority_value) { // In case the current volume has a higher priority, nothing happens, otherwise change current volume if (enable_tagging && stop_tagging_ray == 0) current_tagging_node = goto_volume_node(current_tagging_node, current_volume, tree_next_volume, Volumes, &stop_tagging_ray, stop_creating_nodes); - current_volume = tree_next_volume; + current_volume = tree_next_volume; } } } @@ -2164,8 +2164,8 @@ TRACE print_1d_int_list(mask_status_list,"Updated mask status list"); print_1d_int_list(current_mask_intersect_list_status,"Updated current_mask_intersect_list_status"); if (enable_tagging) printf("After new intersection volume node: current_tagging_node->intensity = %f\n",current_tagging_node->intensity); - if (enable_tagging) printf("After new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); - #endif + if (enable_tagging) printf("After new intersection volume node: current_tagging_node->number_of_rays = %d\n",current_tagging_node->number_of_rays); + #endif } #ifdef Union_trace_verbal_setting @@ -2309,9 +2309,9 @@ TRACE surface_pointer = interface_stack.p_surface_array[surface_transverse_index]; if (surface_transverse_index < n_leaving) in_direction = 1; else in_direction = -1; - if (surface_direction == in_direction) inward_or_outward = inward_bound; else inward_or_outward = outward_bound; + if (surface_direction == in_direction) inward_or_outward = inward_bound; else inward_or_outward = outward_bound; - // fresh normal in case surface function messed with it + // fresh normal in case surface function messed with it normal_vector[0] = nx; normal_vector[1] = ny; normal_vector[2] = nz; // p, wavevector and continues updated by surface_function @@ -2327,7 +2327,7 @@ TRACE if (!continues) surface_direction = -surface_direction; // Flip stack direction if the ray does not continue - surface_transverse_index += surface_direction; // Go to next element in stack + surface_transverse_index += surface_direction; // Go to next element in stack surface_iterations += 1; if (surface_iterations > 10000) { @@ -2352,8 +2352,8 @@ TRACE printf("r = (%f,%f,%f) v = (%f,%f,%f) \n", x, y, z, vx, vy, vz); printf(" - normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); if (surface_transverse_index < 0) printf("Should have different sign \n"); - if (surface_transverse_index >= n_total) printf("Should have same sign \n"); - if (dot_product_before * (nx*vx + ny*vy + nz*vz) < 0) { + if (surface_transverse_index >= n_total) printf("Should have same sign \n"); + if (dot_product_before * (nx*vx + ny*vy + nz*vz) < 0) { printf("Sign did change \n"); } else printf("Sign did not change \n"); #endif @@ -2398,7 +2398,7 @@ TRACE double lambda = 3956.0032/v_length; if (previous_volume == 0) n1 = 1.0; - else { + else { if (Volumes[previous_volume]->p_physics->has_refraction_info == 0 && Volumes[previous_volume]->p_physics->is_vacuum == 0) { perform_refraction = 0; } else { @@ -2420,7 +2420,7 @@ TRACE } if (current_volume == 0) n2 = 1.0; - else { + else { if (Volumes[current_volume]->p_physics->has_refraction_info == 0 && Volumes[current_volume]->p_physics->is_vacuum == 0) { perform_refraction = 0; } else { @@ -2444,11 +2444,11 @@ TRACE perform_refraction = 0; // Vacuum to vacuum } else if (previous_volume == 0) { if (Volumes[current_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum - } else if (current_volume == 0) { + } else if (current_volume == 0) { if (Volumes[previous_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum - } else { + } else { if (Volumes[previous_volume]->p_physics->is_vacuum == 1 && Volumes[current_volume]->p_physics->is_vacuum == 1) perform_refraction = 0; // Vacuum to vacuum - } + } #ifdef Union_trace_verbal_setting if (perform_refraction == 1) @@ -2551,7 +2551,7 @@ TRACE printf(" normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); if ((nx*vx + ny*vy + nz*vz)*dot_product_before > 0) printf(" SIGN SHOULD HAVE CHANGED BUT DIDN'T \n"); - #endif + #endif ignore_closest = min_volume; ignore_surface_index = intersection_time_table.surface_index[min_volume][min_solution]; @@ -2585,7 +2585,7 @@ TRACE printf(" normal dot v = %lf theta2 = %lf \n", nx*vx + ny*vy + nz*vz, theta2); if ((nx*vx + ny*vy + nz*vz)*dot_product_before < 0) printf(" SIGN SHOULD NOT HAVE CHANGED BUT DID \n"); - #endif + #endif // Reflected can ignore some intersections in next geometry iteration ignore_closest = min_volume; // Ignore closest intersection in next geometry iteration @@ -2604,7 +2604,7 @@ TRACE theta2 = theta1; if (0 < reflectivity && reflectivity < 1) p *= reflectivity; // should be R0 - coords_get(V_reflect, &vx, &vy, &vz); + coords_get(V_reflect, &vx, &vy, &vz); current_volume = previous_volume; // Reflected, stays in current volume @@ -2618,7 +2618,7 @@ TRACE printf(" Refraction system : ray reflected (branch 3), going back to volume %d\n", previous_volume); printf(" normal dot v = %lf \n", nx*vx + ny*vy + nz*vz); if ((nx*vx + ny*vy + nz*vz)*dot_product_before > 0) printf(" SIGN SHOULD HAVE CHANGED BUT DIDN'T \n"); - #endif + #endif // Reflected can ignore some intersections in next geometry iteration ignore_closest = min_volume; From dbd0a6abbf8031e1d26ae43be5cb817d0cb378b7 Mon Sep 17 00:00:00 2001 From: Diablo Date: Thu, 5 Feb 2026 18:50:47 +0100 Subject: [PATCH 06/11] Get a working prototype of an integration of the inhomogenous function --- mcstas-comps/share/union-lib.c | 1 + mcstas-comps/union/Union_master.comp | 79 +++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/mcstas-comps/share/union-lib.c b/mcstas-comps/share/union-lib.c index d13ab3358..c3aa53ff4 100755 --- a/mcstas-comps/share/union-lib.c +++ b/mcstas-comps/share/union-lib.c @@ -512,6 +512,7 @@ struct scattering_process_struct double *inhomogenous_distances; // The distance of each step in which the cumulative probabilities will be calculated. double *inhomogenous_cumul_distances; // The cumulative distances double *inhomogenous_mu; // The different attenuation coefficients that are sampled in the numerical integration + double *inhomogenous_prob; // The probability of the process at the different sampled points. double *inhomogenous_t; // The different times at which mu must be sampled. int sampl_size; // Maximum number of samplings performed. If it is -1, no sampling has been done, and the arrays must be malloc'ed. union data_transfer_union data_transfer; // The way to reach the storage space allocated for this process (see examples in process.comp files) diff --git a/mcstas-comps/union/Union_master.comp b/mcstas-comps/union/Union_master.comp index d5310740e..ac0827896 100755 --- a/mcstas-comps/union/Union_master.comp +++ b/mcstas-comps/union/Union_master.comp @@ -237,6 +237,13 @@ DECLARE int number_of_process_interacts_set; int index_of_lacking_process; double total_process_interact; + + // For numerical integration + int sampling_size; + double dist; + double dist_i; + double max_prob; + int max_prob_idx; // Volume nr -> component index struct pointer_to_1d_int_list geometry_component_index_list; @@ -1546,15 +1553,15 @@ TRACE /* Plan for adding in inhomogenous processes: - The processes will have a flag (needs_numerical_integration), that checks if they require - numerical integration. + numerical integration ✅ - If they do, then we use a numerical integration algorithm, where we sample my from the process at different points. We then assume that each mu has a distance around itself that it is "correct" for, i.e the mu distribution is uniform - around the mu. + around the mu ✅ - Then each of these mu now have a smaller distance than length_to_boundary and we must therefore weight each in my_sum with the normalized length they posses. - i.e if length_to_boundary is divided into 10, divide each mu by 10. + i.e if length_to_boundary is divided into 10, divide each mu by 10. ✅ - For the sampling, we must then sample with the cumulative probability function, which we calculate for each small bit of the inhomogenous process. @@ -1565,14 +1572,17 @@ TRACE int physics_output; double mu; + sampling_size = 200; + dist = length_to_boundary/sampling_size; + max_prob = 0; + max_prob_idx = 0; if (process->needs_numerical_integration == 1){ // First, check if the arrays are big enough to handle this - double sampling_size = 10; - double dist = length_to_boundary/sampling_size; if (process->sampl_size == -1){ // First numerical integration for this process. Allocate the arrays process->inhomogenous_distances = malloc(sizeof(double)*sampling_size); process->inhomogenous_cumul_distances = malloc(sizeof(double)*sampling_size); + process->inhomogenous_prob = malloc(sizeof(double)*sampling_size); process->inhomogenous_cumul_prob = malloc(sizeof(double)*sampling_size); process->inhomogenous_mu = malloc(sizeof(double)*sampling_size); } else if (process->sampl_size>=sampling_size){ @@ -1582,16 +1592,21 @@ TRACE process->inhomogenous_distances = temp; temp = realloc(process->inhomogenous_cumul_distances, sizeof(double)*sampling_size); process->inhomogenous_cumul_distances = temp; + temp = realloc(process->inhomogenous_prob, sizeof(double)*sampling_size); + process->inhomogenous_prob = temp; temp = realloc(process->inhomogenous_cumul_prob, sizeof(double)*sampling_size); process->inhomogenous_cumul_prob = temp; temp = realloc(process->inhomogenous_mu, sizeof(double)*sampling_size); process->inhomogenous_mu = temp; + process->sampl_size = sampling_size; } // Populate length and probability arrays: Coords original_position = coords_set(x,y,z); for (int i=0; iinhomogenous_distances[i] = dist; - process->inhomogenous_cumul_distances[i] = i > 0 ? process->inhomogenous_cumul_distances[i-1] + dist: dist/2; + process->inhomogenous_cumul_distances[i] = (i > 0) ? process->inhomogenous_cumul_distances[i-1] + dist: dist/2; + //printf("dist_i = %g\t integer = %i\n", process->inhomogenous_cumul_distances[i], i); + // Transport neutron to place inside geometry ray_velocity = coords_set(vx,vy,vz); // Find location of scattering point in master coordinate system without changing main position / velocity variables @@ -1604,7 +1619,21 @@ TRACE physics_my(process->eProcess, &mu, k_rotated, process->data_transfer, this_focus_data, _particle); process->inhomogenous_mu[i] = mu/sampling_size; // TODO: add cumulative probability calculations. + // Calculate the probabilities and then add them cumulatively + process->inhomogenous_prob[i] = exp(-process->inhomogenous_mu[i]*sampling_size*process->inhomogenous_distances[i]); + if (i==0) { + process->inhomogenous_cumul_prob[i] = process->inhomogenous_prob[i]; + } else { + process->inhomogenous_cumul_prob[i] = process->inhomogenous_cumul_prob[i-1] * process->inhomogenous_prob[i]; + } + if (process->inhomogenous_cumul_prob[i] > max_prob) { + max_prob = process->inhomogenous_cumul_prob[i]; + max_prob_idx = i; + } + //printf("\ncumul_prob = %g\tinteger=%d\n", process->inhomogenous_cumul_prob[i], i); } + for (int i = 0; iinhomogenous_cumul_prob[i] = 1 - process->inhomogenous_cumul_prob[i]; coords_get(original_position, &x, &y, &z); *p_my_trace = 0; for (int i=0; ieProcess, p_my_trace, k_rotated, process->data_transfer, this_focus_data, _particle); } - printf("p_my_trace = %g\t For Process %d\n", *p_my_trace, process->eProcess); my_sum += *p_my_trace; #ifdef Union_trace_verbal_setting printf("my_trace = %f, my_sum = %f\n",*p_my_trace,my_sum); @@ -1703,9 +1731,10 @@ TRACE } } } + process = &Volumes[current_volume]->p_physics->p_scattering_array[selected_process]; // Select distance to scattering position - if (Volumes[current_volume]->p_physics->p_scattering_array[selected_process].needs_cross_section_focus == 1) { + if (process->needs_cross_section_focus == 1) { // Respect forced length to scattering chosen by process length_to_scattering = forced_length_to_scattering; // Drawing between 0 and L from constant s = 1/L and should have been q = A*exp(-kz). @@ -1717,11 +1746,35 @@ TRACE #endif } else { - // Decided the ray scatters, choose where on truncated exponential from safety_distance to length_to_boundary - safety_distance - length_to_scattering = safety_distance - log(1.0 - rand0max((1.0 - exp(-my_sum_plus_abs*(length_to_boundary-safety_distance2))))) / my_sum_plus_abs; - #ifdef Union_trace_verbal_setting - printf("Sampled length to scattering, %lf \n", length_to_scattering); - #endif + if (process->needs_numerical_integration == -1){ + // No numerical integration is necessary. + // Decided the ray scatters, choose where on truncated exponential from safety_distance to length_to_boundary - safety_distance + length_to_scattering = safety_distance - log(1.0 - rand0max(1.0 - exp(-my_sum_plus_abs*(length_to_boundary-safety_distance2)))) / my_sum_plus_abs; + #ifdef Union_trace_verbal_setting + printf("Sampled length to scattering, %lf \n", length_to_scattering); + #endif + } else { + // Numerical integration happens, and therefore we must choose between the different samples + // We do this by drawing a random number between 0 and max cumul prob, + // and then seeing which cumul prob is the first to include it. + double pseudo_rand = rand01()*(process->inhomogenous_cumul_prob[sampling_size - 1]); + int selected_sampling; + for (int i = 0; i < sampling_size; i++){ + //printf("\nCumulative probabilities = %g\trandom = %g\tinteger=%d\n",process->inhomogenous_cumul_prob[i],pseudo_rand, i); + if (pseudo_rand >= process->inhomogenous_cumul_prob[i]) + continue; + selected_sampling = i; + break; + + } + //printf("\nSelected_sampling = %d\n", selected_sampling); + dist_i = process->inhomogenous_cumul_distances[selected_sampling]; + //printf("dist i = %g\tdist=%g\n", dist_i, dist); + + length_to_scattering = safety_distance + dist_i - dist/2 + rand01()*dist; + //printf("\nChosen length to scattering = %g\n", length_to_scattering); + + } } } // Done handling scattering From b19b49f0c1c3d6612856f48fdd7d84d643ce8515 Mon Sep 17 00:00:00 2001 From: Diablo Date: Fri, 6 Feb 2026 15:32:18 +0100 Subject: [PATCH 07/11] Get inhomogenous to work with competing processes, with the same binning --- mcstas-comps/union/Union_master.comp | 99 ++++++++++++++++------------ 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/mcstas-comps/union/Union_master.comp b/mcstas-comps/union/Union_master.comp index ac0827896..183b5efcd 100755 --- a/mcstas-comps/union/Union_master.comp +++ b/mcstas-comps/union/Union_master.comp @@ -244,6 +244,8 @@ DECLARE double dist_i; double max_prob; int max_prob_idx; + int sampling_in_geometry; + int sampling_mus_allocated; // Volume nr -> component index struct pointer_to_1d_int_list geometry_component_index_list; @@ -1062,7 +1064,8 @@ TRACE double weight_limit; weight_limit = p*weight_ratio_limit; - + double *sampling_mus; + // Initialize logic done = 0; error_msg = 0; @@ -1519,10 +1522,19 @@ TRACE } else { forced_length_to_scattering = -1.0; // Signals that no forcing needed, could also if on the selected process struct } - + /* + Plan for adding in inhomogenous processes all with the same sampling size: + - In the for loop over all processes calculate all mus, and store them in array for the process, or all processes depending on + inhomogenous or not. + - The mu is summed as usual to determine scattering process + - To sample to position, we rebin the homogenous processes to the sampling size. + - Then, we calculate the cumulative transmission probability for each bin + - Then we choose the bin based on 1- cumulative transmission probability and random number. + */ + sampling_in_geometry = 0; // Reset numerical integration flag + double *mus = malloc(sizeof(double)*Volumes[current_volume]->p_physics->number_of_processes); // TODO: Dont malloc this for each neutron. int p_index; for (p_index=0; p_index < Volumes[current_volume]->p_physics->number_of_processes; p_index++ ){ // GPU - // Find correct focus_data_array index for this volume/process focus_data_index = Volumes[current_volume]->geometry.focus_array_indices.elements[p_index]; this_focus_data = &Volumes[current_volume]->geometry.focus_data_array.elements[focus_data_index]; @@ -1550,22 +1562,7 @@ TRACE k_rotated[0] = k[0]; k_rotated[1] = k[1]; k_rotated[2] = k[2]; // focus_data RayAim already updated for non isotropic processes } - /* - Plan for adding in inhomogenous processes: - - The processes will have a flag (needs_numerical_integration), that checks if they require - numerical integration ✅ - - If they do, then we use a numerical integration algorithm, - where we sample my from the process at different points. - We then assume that each mu has a distance around itself - that it is "correct" for, i.e the mu distribution is uniform - around the mu ✅ - - Then each of these mu now have a smaller distance than length_to_boundary - and we must therefore weight each in my_sum with the normalized length they posses. - i.e if length_to_boundary is divided into 10, divide each mu by 10. ✅ - - For the sampling, we must then sample with the cumulative - probability function, which we calculate for each small bit of - the inhomogenous process. - */ + // Call the probability for scattering function assighed to this specific procress (the process pointer is updated in the for loop) process = &Volumes[current_volume]->p_physics->p_scattering_array[p_index]; // GPU Allowed @@ -1576,7 +1573,9 @@ TRACE dist = length_to_boundary/sampling_size; max_prob = 0; max_prob_idx = 0; + if (process->needs_numerical_integration == 1){ + sampling_in_geometry = 1;// Flag to indicate that this geometry needs to consider numerical integration. // First, check if the arrays are big enough to handle this if (process->sampl_size == -1){ // First numerical integration for this process. Allocate the arrays @@ -1605,8 +1604,6 @@ TRACE for (int i=0; iinhomogenous_distances[i] = dist; process->inhomogenous_cumul_distances[i] = (i > 0) ? process->inhomogenous_cumul_distances[i-1] + dist: dist/2; - //printf("dist_i = %g\t integer = %i\n", process->inhomogenous_cumul_distances[i], i); - // Transport neutron to place inside geometry ray_velocity = coords_set(vx,vy,vz); // Find location of scattering point in master coordinate system without changing main position / velocity variables @@ -1617,30 +1614,21 @@ TRACE // Calculate mu and probability coords_get(sampling_point_geometry, &x, &y, &z); physics_my(process->eProcess, &mu, k_rotated, process->data_transfer, this_focus_data, _particle); - process->inhomogenous_mu[i] = mu/sampling_size; - // TODO: add cumulative probability calculations. - // Calculate the probabilities and then add them cumulatively - process->inhomogenous_prob[i] = exp(-process->inhomogenous_mu[i]*sampling_size*process->inhomogenous_distances[i]); - if (i==0) { - process->inhomogenous_cumul_prob[i] = process->inhomogenous_prob[i]; - } else { - process->inhomogenous_cumul_prob[i] = process->inhomogenous_cumul_prob[i-1] * process->inhomogenous_prob[i]; - } - if (process->inhomogenous_cumul_prob[i] > max_prob) { - max_prob = process->inhomogenous_cumul_prob[i]; - max_prob_idx = i; - } - //printf("\ncumul_prob = %g\tinteger=%d\n", process->inhomogenous_cumul_prob[i], i); + process->inhomogenous_mu[i] = mu; } - for (int i = 0; iinhomogenous_cumul_prob[i] = 1 - process->inhomogenous_cumul_prob[i]; + coords_get(original_position, &x, &y, &z); *p_my_trace = 0; for (int i=0; iinhomogenous_mu[i]; + *p_my_trace += process->inhomogenous_mu[i]/sampling_size; } else { physics_output = physics_my(process->eProcess, p_my_trace, k_rotated, process->data_transfer, this_focus_data, _particle); + if (sampling_in_geometry){ + mus[p_index] = *p_my_trace; + } + } + my_sum += *p_my_trace; #ifdef Union_trace_verbal_setting @@ -1732,7 +1720,6 @@ TRACE } } process = &Volumes[current_volume]->p_physics->p_scattering_array[selected_process]; - // Select distance to scattering position if (process->needs_cross_section_focus == 1) { // Respect forced length to scattering chosen by process @@ -1746,7 +1733,7 @@ TRACE #endif } else { - if (process->needs_numerical_integration == -1){ + if (sampling_in_geometry != 1){ // No numerical integration is necessary. // Decided the ray scatters, choose where on truncated exponential from safety_distance to length_to_boundary - safety_distance length_to_scattering = safety_distance - log(1.0 - rand0max(1.0 - exp(-my_sum_plus_abs*(length_to_boundary-safety_distance2)))) / my_sum_plus_abs; @@ -1757,6 +1744,33 @@ TRACE // Numerical integration happens, and therefore we must choose between the different samples // We do this by drawing a random number between 0 and max cumul prob, // and then seeing which cumul prob is the first to include it. + // Calculate the probabilities and then add them cumulatively + double *total_mu = calloc(sampling_size, sizeof(double)); + for (int i = 0; ip_physics->number_of_processes; i++){ + if (mus[i]){ + for (int j = 0; jp_physics->p_scattering_array[i]; + for (int j = 0; jinhomogenous_mu[j]*dist; + } + } + + } + for (int j = 0; jp_physics->my_a*(2200/v_length)*dist ; + } + double trans_prob; + for (int i = 0; iinhomogenous_cumul_prob[i] = trans_prob; + else process->inhomogenous_cumul_prob[i] = process->inhomogenous_cumul_prob[i-1] * trans_prob; + } + for (int i = 0; iinhomogenous_cumul_prob[i] = 1 - process->inhomogenous_cumul_prob[i]; + } + double pseudo_rand = rand01()*(process->inhomogenous_cumul_prob[sampling_size - 1]); int selected_sampling; for (int i = 0; i < sampling_size; i++){ @@ -1770,9 +1784,8 @@ TRACE //printf("\nSelected_sampling = %d\n", selected_sampling); dist_i = process->inhomogenous_cumul_distances[selected_sampling]; //printf("dist i = %g\tdist=%g\n", dist_i, dist); - - length_to_scattering = safety_distance + dist_i - dist/2 + rand01()*dist; - //printf("\nChosen length to scattering = %g\n", length_to_scattering); + double sampled_dist = - log(1.0 - rand01()*(1.0 - exp(-total_mu[selected_sampling]) ) ) / total_mu[selected_sampling] * dist; + length_to_scattering = safety_distance + dist_i - dist/2 + sampled_dist; } } From 453882514cfa729389ba8e4163d84d7acce88769 Mon Sep 17 00:00:00 2001 From: Diablo Date: Mon, 9 Feb 2026 13:31:14 +0100 Subject: [PATCH 08/11] Apply indentation formatter to Union mesh component --- mcstas-comps/union/Union_mesh.comp | 1310 ++++++++++++++-------------- 1 file changed, 655 insertions(+), 655 deletions(-) diff --git a/mcstas-comps/union/Union_mesh.comp b/mcstas-comps/union/Union_mesh.comp index 47eb8b280..831d8233e 100644 --- a/mcstas-comps/union/Union_mesh.comp +++ b/mcstas-comps/union/Union_mesh.comp @@ -108,7 +108,7 @@ SHARE %include "interoff-lib" #ifndef Union -#error "The Union_init component must be included before this Union_mesh component" + #error "The Union_init component must be included before this Union_mesh component" #endif #ifndef ANY_GEOMETRY_DETECTOR_DECLARE @@ -116,8 +116,8 @@ SHARE //struct pointer_to_global_geometry_list global_geometry_list = {0,NULL}; #endif -#ifndef MAX_VERT_DIST - #define MAX_VERT_DIST 1e-30 // Maximum distance between vertex points, before they are the same point. +#ifndef MAX_VERT_DIST + #define MAX_VERT_DIST 1e-30 // Maximum distance between vertex points, before they are the same point. #endif // define struct to import triangles from stl file. @@ -131,180 +131,180 @@ typedef struct { } Triangle; #pragma pack(pop) void read_stl(char* filename, - int* n_verts, - int* n_faces, - int* n_edges, - Coords** verts, - int*** faces, - char* comp_name){ - unsigned char buffer[1000]; - Triangle *triangles; - FILE *file = Open_File(filename, "r", NULL); - if (!file) { + int* n_verts, + int* n_faces, + int* n_edges, + Coords** verts, + int*** faces, + char* comp_name){ + unsigned char buffer[1000]; + Triangle *triangles; + FILE *file = Open_File(filename, "r", NULL); + if (!file) { perror("ERROR: Failed to open file"); exit(1); - } - // Check if the file is binary or ASCII - int file_is_ascii = 0; - char word[6]; // "solid" + null terminator - if (fscanf(file, "%5s", word) == 1) { - file_is_ascii = strcmp(word, "solid") == 0; - } - fclose(file); - - if (file_is_ascii){ + } + // Check if the file is binary or ASCII + int file_is_ascii = 0; + char word[6]; // "solid" + null terminator + if (fscanf(file, "%5s", word) == 1) { + file_is_ascii = strcmp(word, "solid") == 0; + } + fclose(file); + + if (file_is_ascii){ - FILE *file = Open_File(filename, "r", NULL); - char line[256]; - int capacity = 100; // initial allocation - int count = 0; - - // Allocate memory for triangles - triangles = (Triangle *)malloc(capacity * sizeof(Triangle)); - if (triangles == NULL){ - free(triangles); - printf("\nERROR: malloc failed for triangles"); - exit(1); - } + FILE *file = Open_File(filename, "r", NULL); + char line[256]; + int capacity = 100; // initial allocation + int count = 0; + + // Allocate memory for triangles + triangles = (Triangle *)malloc(capacity * sizeof(Triangle)); + if (triangles == NULL){ + free(triangles); + printf("\nERROR: malloc failed for triangles"); + exit(1); + } - Triangle current; + Triangle current; - int vertex_index = 0; - while (fgets(line, sizeof(line), file)) { + int vertex_index = 0; + while (fgets(line, sizeof(line), file)) { - char *trimmed = line; - while (*trimmed == ' ' || *trimmed == '\t') { - trimmed++; - } + char *trimmed = line; + while (*trimmed == ' ' || *trimmed == '\t') { + trimmed++; + } - // If line is empty after trimming, skip it - if (*trimmed == '\0') { - continue; - } - - if (strncmp(trimmed, "facet normal", 12) == 0) { - memset(¤t, 0, sizeof(Triangle)); - - sscanf(trimmed, "facet normal %f %f %f", - ¤t.normal[0], ¤t.normal[1], ¤t.normal[2]); - } else if (strncmp(trimmed, "vertex", 6) == 0) { - float x, y, z; - sscanf(trimmed, "vertex %f %f %f", &x, &y, &z); - if (vertex_index == 0) { - current.vertex1[0] = x; current.vertex1[1] = y; current.vertex1[2] = z; - } else if (vertex_index == 1) { - current.vertex2[0] = x; current.vertex2[1] = y; current.vertex2[2] = z; - } else if (vertex_index == 2) { - current.vertex3[0] = x; current.vertex3[1] = y; current.vertex3[2] = z; - } - vertex_index++; - if (vertex_index == 3) { - vertex_index = 0; - } - } else if (strncmp(trimmed, "endfacet", 8) == 0) { - current.attribute_byte_count = 0; // ASCII STL always 0 - if (count >= capacity) { - capacity *= 2; - void * tmp = realloc(triangles, capacity * sizeof(Triangle)); - if (tmp) { - free(triangles); - free(tmp); - perror("ERROR: Memory reallocation failed"); - fclose(file); - exit(1); - } - triangles = tmp; - } - triangles[count++] = current; - } - } - *n_faces = count; - fclose(file); + // If line is empty after trimming, skip it + if (*trimmed == '\0') { + continue; + } + + if (strncmp(trimmed, "facet normal", 12) == 0) { + memset(¤t, 0, sizeof(Triangle)); + + sscanf(trimmed, "facet normal %f %f %f", + ¤t.normal[0], ¤t.normal[1], ¤t.normal[2]); + } else if (strncmp(trimmed, "vertex", 6) == 0) { + float x, y, z; + sscanf(trimmed, "vertex %f %f %f", &x, &y, &z); + if (vertex_index == 0) { + current.vertex1[0] = x; current.vertex1[1] = y; current.vertex1[2] = z; + } else if (vertex_index == 1) { + current.vertex2[0] = x; current.vertex2[1] = y; current.vertex2[2] = z; + } else if (vertex_index == 2) { + current.vertex3[0] = x; current.vertex3[1] = y; current.vertex3[2] = z; + } + vertex_index++; + if (vertex_index == 3) { + vertex_index = 0; + } + } else if (strncmp(trimmed, "endfacet", 8) == 0) { + current.attribute_byte_count = 0; // ASCII STL always 0 + if (count >= capacity) { + capacity *= 2; + void * tmp = realloc(triangles, capacity * sizeof(Triangle)); + if (tmp) { + free(triangles); + free(tmp); + perror("ERROR: Memory reallocation failed"); + fclose(file); + exit(1); + } + triangles = tmp; + } + triangles[count++] = current; + } + } + *n_faces = count; + fclose(file); - } else { - FILE *file = Open_File(filename, "rb", NULL); - // Read header - char header[80]; - fread(header, sizeof(char), 80, file); - - // Read number of triangles - fread(n_faces, sizeof(uint32_t), 1, file); - // Allocate memory for triangles - triangles = (Triangle *)malloc(*n_faces * sizeof(Triangle)); + } else { + FILE *file = Open_File(filename, "rb", NULL); + // Read header + char header[80]; + fread(header, sizeof(char), 80, file); + + // Read number of triangles + fread(n_faces, sizeof(uint32_t), 1, file); + // Allocate memory for triangles + triangles = (Triangle *)malloc(*n_faces * sizeof(Triangle)); - if (!triangles) { - perror("ERROR: Memory allocation failed"); - fclose(file); - exit(1); - } + if (!triangles) { + perror("ERROR: Memory allocation failed"); + fclose(file); + exit(1); + } - // Read triangles - for (int i = 0; i < *n_faces; i++) { - fread(&triangles[i], sizeof(Triangle), 1, file); - } + // Read triangles + for (int i = 0; i < *n_faces; i++) { + fread(&triangles[i], sizeof(Triangle), 1, file); + } - fclose(file); - } - - *n_verts = 3* *n_faces; - *verts = (Coords *)malloc(sizeof(Coords)* *n_verts); - *faces = (int **)malloc(sizeof(int *)* *n_faces); - - // Now, we make a list of the triangles, and then give them each an index. - int j = 0; - for (int i = 0; i < *n_faces; i++) { - (*faces)[i] = (int *)malloc(sizeof(int)*3); - j = i*3; - (*verts)[j] = coords_set((double)triangles[i].vertex1[0], (double)triangles[i].vertex1[1], (double)triangles[i].vertex1[2]); - (*verts)[j+1] = coords_set((double)triangles[i].vertex2[0], (double)triangles[i].vertex2[1], (double)triangles[i].vertex2[2]); - (*verts)[j+2] = coords_set((double)triangles[i].vertex3[0], (double)triangles[i].vertex3[1], (double)triangles[i].vertex3[2]); - (*faces)[i][0] = j; - (*faces)[i][1] = j+1; - (*faces)[i][2] = j+2; - } - free(triangles); - // Loop over vertices, and make sure we only use unique vertices - Coords* unique_vertices = (Coords *)malloc( - sizeof(Coords)* *n_verts) ; + fclose(file); + } + + *n_verts = 3* *n_faces; + *verts = (Coords *)malloc(sizeof(Coords)* *n_verts); + *faces = (int **)malloc(sizeof(int *)* *n_faces); + + // Now, we make a list of the triangles, and then give them each an index. + int j = 0; + for (int i = 0; i < *n_faces; i++) { + (*faces)[i] = (int *)malloc(sizeof(int)*3); + j = i*3; + (*verts)[j] = coords_set((double)triangles[i].vertex1[0], (double)triangles[i].vertex1[1], (double)triangles[i].vertex1[2]); + (*verts)[j+1] = coords_set((double)triangles[i].vertex2[0], (double)triangles[i].vertex2[1], (double)triangles[i].vertex2[2]); + (*verts)[j+2] = coords_set((double)triangles[i].vertex3[0], (double)triangles[i].vertex3[1], (double)triangles[i].vertex3[2]); + (*faces)[i][0] = j; + (*faces)[i][1] = j+1; + (*faces)[i][2] = j+2; + } + free(triangles); + // Loop over vertices, and make sure we only use unique vertices + Coords* unique_vertices = (Coords *)malloc( + sizeof(Coords)* *n_verts) ; - int vertex_is_unique; - int x_are_equal, y_are_equal, z_are_equal; - int* map_old_to_unique = malloc(sizeof(int)* *n_verts); - int unique_counter = 0; - int vert_index_in_faces = 0; - for (int i = 0; i < *n_verts; i++) { - vertex_is_unique = 1; - // First we check if the vertex exist - for (j = 0; j < i; j++){ - x_are_equal = fabs((*verts)[i].x - (*verts)[j].x)=( *n_verts+2)){ - (*faces)[face_index] = (int *)malloc(sizeof(int)*3); - // The faces are always after the vertices in an off file. - sscanf(buffer,"%d %d %d %d", - &face_vertices, - &(*faces)[face_index][0], - &(*faces)[face_index][1], - &(*faces)[face_index][2]); - if (face_vertices>3){ - printf("\nERROR: Facets use more than 3 vertices." - "\n Please correct your .off file used for Component %s", - comp_name); - exit(1); - } - ++face_index; - } - ++n_lines; + sscanf(buffer,"%lf %lf %lf", + &(*verts)[vert_index].x, + &(*verts)[vert_index].y, + &(*verts)[vert_index].z); + vert_index++; + } + // If we are in the facet area of the file, record the facet + if (n_lines>=( *n_verts+2)){ + (*faces)[face_index] = (int *)malloc(sizeof(int)*3); + // The faces are always after the vertices in an off file. + sscanf(buffer,"%d %d %d %d", + &face_vertices, + &(*faces)[face_index][0], + &(*faces)[face_index][1], + &(*faces)[face_index][2]); + if (face_vertices>3){ + printf("\nERROR: Facets use more than 3 vertices." + "\n Please correct your .off file used for Component %s", + comp_name); + exit(1); + } + ++face_index; + } + ++n_lines; - } - fclose(fp); + } + fclose(fp); } int mesh_is_not_closed(int n_verts, int n_faces, int n_edges){ - if (n_verts - n_edges + n_faces ==2){ - return 0; - } - return 1; + if (n_verts - n_edges + n_faces ==2){ + return 0; + } + return 1; } -void generate_vertex_vertex_pair_list(int** faces, int** vert_pairs, - int n_faces){ - int vert1, vert2, vert3, vert_pair_0; - // Make list of vertex vertex pairs - for (int i=0; i < n_faces; i++){ - vert1 = faces[i][0]; - vert2 = faces[i][1]; - vert3 = faces[i][2]; - vert_pairs[i][0] = vert1; - vert_pairs[i][1] = vert2; - vert_pairs[i + n_faces][0] = vert1; - vert_pairs[i + n_faces][1] = vert3; - vert_pairs[i + 2*n_faces][0] = vert2; - vert_pairs[i + 2*n_faces][1] = vert3; - } +void generate_vertex_vertex_pair_list(int** faces, int** vert_pairs, + int n_faces){ + int vert1, vert2, vert3, vert_pair_0; + // Make list of vertex vertex pairs + for (int i=0; i < n_faces; i++){ + vert1 = faces[i][0]; + vert2 = faces[i][1]; + vert3 = faces[i][2]; + vert_pairs[i][0] = vert1; + vert_pairs[i][1] = vert2; + vert_pairs[i + n_faces][0] = vert1; + vert_pairs[i + n_faces][1] = vert3; + vert_pairs[i + 2*n_faces][0] = vert2; + vert_pairs[i + 2*n_faces][1] = vert3; + } } -void find_unique_vertex_vertex_pairs(int* unique_index, int** unique_verts, - int** vert_pairs, int* n_faces){ - int vert1,vert2; - int pair_is_unique; - - // Make a copy of only the unique pairs - for (int i=0; i < 3* (*n_faces); i++){ - // Check if the first vertex exist in the unique list - vert1 = vert_pairs[i][0]; - vert2 = vert_pairs[i][1]; - pair_is_unique = 1; - for (int j = 0; j<(*unique_index); j++){ - if (unique_verts[j][0]==vert1){ - if (unique_verts[j][1]==vert2) { - pair_is_unique=0; - break; +void find_unique_vertex_vertex_pairs(int* unique_index, int** unique_verts, + int** vert_pairs, int* n_faces){ + int vert1,vert2; + int pair_is_unique; + + // Make a copy of only the unique pairs + for (int i=0; i < 3* (*n_faces); i++){ + // Check if the first vertex exist in the unique list + vert1 = vert_pairs[i][0]; + vert2 = vert_pairs[i][1]; + pair_is_unique = 1; + for (int j = 0; j<(*unique_index); j++){ + if (unique_verts[j][0]==vert1){ + if (unique_verts[j][1]==vert2) { + pair_is_unique=0; + break; + } } - } - else if (unique_verts[j][0]==vert2){ - if (unique_verts[j][1]==vert1) { - pair_is_unique=0; - break; + else if (unique_verts[j][0]==vert2){ + if (unique_verts[j][1]==vert1) { + pair_is_unique=0; + break; + } } - } - } - if (pair_is_unique){ - unique_verts[*unique_index][0] = vert1; - unique_verts[*unique_index][1] = vert2; - *unique_index +=1; - - } - } + } + if (pair_is_unique){ + unique_verts[*unique_index][0] = vert1; + unique_verts[*unique_index][1] = vert2; + *unique_index +=1; + + } + } } int coord_comp(Coords A,Coords B) { @@ -458,222 +458,222 @@ int coord_comp(Coords A,Coords B) { return 0; }; Coords get_coords_from_string(char* line){ - Coords vert_coords = coords_set(1,2,1); - return vert_coords; + Coords vert_coords = coords_set(1,2,1); + return vert_coords; } void mcdisplay_mesh_function(struct lines_to_draw *lines_to_draw_output,int index, struct geometry_struct **Geometries,int number_of_volumes) { - // Function to call in mcdisplay section of the sample component for this volume - - int n_facets = Geometries[index]->geometry_parameters.p_mesh_storage->n_facets; - double *v1_x = Geometries[index]->geometry_parameters.p_mesh_storage->v1_x; - double *v1_y = Geometries[index]->geometry_parameters.p_mesh_storage->v1_y; - double *v1_z = Geometries[index]->geometry_parameters.p_mesh_storage->v1_z; - double *v2_x = Geometries[index]->geometry_parameters.p_mesh_storage->v2_x; - double *v2_y = Geometries[index]->geometry_parameters.p_mesh_storage->v2_y; - double *v2_z = Geometries[index]->geometry_parameters.p_mesh_storage->v2_z; - double *v3_x = Geometries[index]->geometry_parameters.p_mesh_storage->v3_x; - double *v3_y = Geometries[index]->geometry_parameters.p_mesh_storage->v3_y; - double *v3_z = Geometries[index]->geometry_parameters.p_mesh_storage->v3_z; - - Coords center = Geometries[index]->center; - - struct lines_to_draw lines_to_draw_temp; - lines_to_draw_temp.number_of_lines = 0; - - Coords point1,point2,point3; - int iterate, i,j; - int print1 = 0; - int print2 = 0; - int print3 = 0; - - Coords *list_startpoints = (Coords*)calloc(n_facets*3,sizeof(Coords)); - Coords *list_endpoints = (Coords*)calloc(n_facets*3,sizeof(Coords)); - // Check for failed allocation - if (list_startpoints == NULL || list_endpoints == NULL){ - free(list_startpoints); - free(list_endpoints); - } - - int counter=0; - // For every triangle it should add three lines - for (iterate=0 ; iteraterotation_matrix,coords_set(*(v1_x+iterate),*(v1_y+iterate),*(v1_z+iterate))),center); - point2 = coords_add(rot_apply(Geometries[index]->rotation_matrix,coords_set(*(v2_x+iterate),*(v2_y+iterate),*(v2_z+iterate))),center); - point3 = coords_add(rot_apply(Geometries[index]->rotation_matrix,coords_set(*(v3_x+iterate),*(v3_y+iterate),*(v3_z+iterate))),center); - - print1 = 1; - print2 = 1; - print3 = 1; + // Function to call in mcdisplay section of the sample component for this volume + + int n_facets = Geometries[index]->geometry_parameters.p_mesh_storage->n_facets; + double *v1_x = Geometries[index]->geometry_parameters.p_mesh_storage->v1_x; + double *v1_y = Geometries[index]->geometry_parameters.p_mesh_storage->v1_y; + double *v1_z = Geometries[index]->geometry_parameters.p_mesh_storage->v1_z; + double *v2_x = Geometries[index]->geometry_parameters.p_mesh_storage->v2_x; + double *v2_y = Geometries[index]->geometry_parameters.p_mesh_storage->v2_y; + double *v2_z = Geometries[index]->geometry_parameters.p_mesh_storage->v2_z; + double *v3_x = Geometries[index]->geometry_parameters.p_mesh_storage->v3_x; + double *v3_y = Geometries[index]->geometry_parameters.p_mesh_storage->v3_y; + double *v3_z = Geometries[index]->geometry_parameters.p_mesh_storage->v3_z; + + Coords center = Geometries[index]->center; + + struct lines_to_draw lines_to_draw_temp; + lines_to_draw_temp.number_of_lines = 0; + + Coords point1,point2,point3; + int iterate, i,j; + int print1 = 0; + int print2 = 0; + int print3 = 0; + + Coords *list_startpoints = (Coords*)calloc(n_facets*3,sizeof(Coords)); + Coords *list_endpoints = (Coords*)calloc(n_facets*3,sizeof(Coords)); + // Check for failed allocation + if (list_startpoints == NULL || list_endpoints == NULL){ + free(list_startpoints); + free(list_endpoints); + } + + int counter=0; + // For every triangle it should add three lines + for (iterate=0 ; iteraterotation_matrix,coords_set(*(v1_x+iterate),*(v1_y+iterate),*(v1_z+iterate))),center); + point2 = coords_add(rot_apply(Geometries[index]->rotation_matrix,coords_set(*(v2_x+iterate),*(v2_y+iterate),*(v2_z+iterate))),center); + point3 = coords_add(rot_apply(Geometries[index]->rotation_matrix,coords_set(*(v3_x+iterate),*(v3_y+iterate),*(v3_z+iterate))),center); + + print1 = 1; + print2 = 1; + print3 = 1; - // Make sure it does not print a line if it is already printed.... (might take a while?) - for (i = 0 ; i < counter ; i++){ - if (print1 == 1 && coord_comp(point1 , list_startpoints[i])){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point2 , list_startpoints[i])){ - print1 = 0; - } - } - } - if (print2 == 1 && coord_comp(point2 , list_startpoints[i])){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point1 , list_startpoints[i])){ - print1 = 0; - } - } - } - if (print2 == 1 && coord_comp(point2 , list_startpoints[i]) ){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point3 , list_startpoints[i])){ - print2 = 0; - } - } - } - if (print3 == 1 && coord_comp(point3 , list_startpoints[i]) ){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point2 , list_startpoints[i])){ - print2 = 0; - } - } - } - if (print1 == 1 && coord_comp(point1 , list_startpoints[i]) ){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point1 , list_startpoints[i])){ - print3 = 0; - } - } - } - if (print3 == 1 && coord_comp(point3 , list_startpoints[i])){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point1 , list_startpoints[i])){ - print3 = 0; - } - } - } + // Make sure it does not print a line if it is already printed.... (might take a while?) + for (i = 0 ; i < counter ; i++){ + if (print1 == 1 && coord_comp(point1 , list_startpoints[i])){ + for (j = 0 ; j < counter ; j++){ + if (coord_comp(point2 , list_startpoints[i])){ + print1 = 0; + } + } + } + if (print2 == 1 && coord_comp(point2 , list_startpoints[i])){ + for (j = 0 ; j < counter ; j++){ + if (coord_comp(point1 , list_startpoints[i])){ + print1 = 0; + } + } + } + if (print2 == 1 && coord_comp(point2 , list_startpoints[i]) ){ + for (j = 0 ; j < counter ; j++){ + if (coord_comp(point3 , list_startpoints[i])){ + print2 = 0; + } + } + } + if (print3 == 1 && coord_comp(point3 , list_startpoints[i]) ){ + for (j = 0 ; j < counter ; j++){ + if (coord_comp(point2 , list_startpoints[i])){ + print2 = 0; + } + } + } + if (print1 == 1 && coord_comp(point1 , list_startpoints[i]) ){ + for (j = 0 ; j < counter ; j++){ + if (coord_comp(point1 , list_startpoints[i])){ + print3 = 0; + } + } + } + if (print3 == 1 && coord_comp(point3 , list_startpoints[i])){ + for (j = 0 ; j < counter ; j++){ + if (coord_comp(point1 , list_startpoints[i])){ + print3 = 0; + } + } + } - } + } - // Create lines - // Line 1 - if (print1 == 1){ - lines_to_draw_temp = draw_line_with_highest_priority(point1,point2,index,Geometries,number_of_volumes,100); - merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); - list_startpoints[counter] = point1; - list_endpoints[counter] = point2; - counter++; - } - // Line 2 - if (print2 == 1){ - lines_to_draw_temp = draw_line_with_highest_priority(point2,point3,index,Geometries,number_of_volumes,100); - merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); - list_startpoints[counter] = point2; - list_endpoints[counter] = point3; - counter++; - } - // Line 3 - if (print3 == 1){ - lines_to_draw_temp = draw_line_with_highest_priority(point3,point1,index,Geometries,number_of_volumes,100); - merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); - list_startpoints[counter] = point3; - list_endpoints[counter] = point1; - counter++; - } + // Create lines + // Line 1 + if (print1 == 1){ + lines_to_draw_temp = draw_line_with_highest_priority(point1,point2,index,Geometries,number_of_volumes,100); + merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); + list_startpoints[counter] = point1; + list_endpoints[counter] = point2; + counter++; + } + // Line 2 + if (print2 == 1){ + lines_to_draw_temp = draw_line_with_highest_priority(point2,point3,index,Geometries,number_of_volumes,100); + merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); + list_startpoints[counter] = point2; + list_endpoints[counter] = point3; + counter++; + } + // Line 3 + if (print3 == 1){ + lines_to_draw_temp = draw_line_with_highest_priority(point3,point1,index,Geometries,number_of_volumes,100); + merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); + list_startpoints[counter] = point3; + list_endpoints[counter] = point1; + counter++; + } - } - free(list_startpoints); - free(list_endpoints); + } + free(list_startpoints); + free(list_endpoints); }; struct pointer_to_1d_coords_list allocate_shell_points(struct geometry_struct *geometry,int max_number_of_points) { - // Function that returns a number (less than max) of points on the geometry surface - // Run trhough all points in list of faces, and remove dublicates - // There are three points in a face and very often these will be dublicated a few times. This removes dublicates to boost performance down stream... + // Function that returns a number (less than max) of points on the geometry surface + // Run trhough all points in list of faces, and remove dublicates + // There are three points in a face and very often these will be dublicated a few times. This removes dublicates to boost performance down stream... - struct pointer_to_1d_coords_list mesh_shell_array; + struct pointer_to_1d_coords_list mesh_shell_array; - int n_facets = geometry->geometry_parameters.p_mesh_storage->n_facets; - double *v1_x = geometry->geometry_parameters.p_mesh_storage->v1_x; - double *v1_y = geometry->geometry_parameters.p_mesh_storage->v1_y; - double *v1_z = geometry->geometry_parameters.p_mesh_storage->v1_z; - double *v2_x = geometry->geometry_parameters.p_mesh_storage->v2_x; - double *v2_y = geometry->geometry_parameters.p_mesh_storage->v2_y; - double *v2_z = geometry->geometry_parameters.p_mesh_storage->v2_z; - double *v3_x = geometry->geometry_parameters.p_mesh_storage->v3_x; - double *v3_y = geometry->geometry_parameters.p_mesh_storage->v3_y; - double *v3_z = geometry->geometry_parameters.p_mesh_storage->v3_z; - int number_of_points_in_array = 0; - mesh_shell_array.elements = malloc(3*n_facets * sizeof(Coords)); - int is_dublicate = 0; - Coords this_vert; - int i,j; - for (i=0 ; i < n_facets ; i++){ + int n_facets = geometry->geometry_parameters.p_mesh_storage->n_facets; + double *v1_x = geometry->geometry_parameters.p_mesh_storage->v1_x; + double *v1_y = geometry->geometry_parameters.p_mesh_storage->v1_y; + double *v1_z = geometry->geometry_parameters.p_mesh_storage->v1_z; + double *v2_x = geometry->geometry_parameters.p_mesh_storage->v2_x; + double *v2_y = geometry->geometry_parameters.p_mesh_storage->v2_y; + double *v2_z = geometry->geometry_parameters.p_mesh_storage->v2_z; + double *v3_x = geometry->geometry_parameters.p_mesh_storage->v3_x; + double *v3_y = geometry->geometry_parameters.p_mesh_storage->v3_y; + double *v3_z = geometry->geometry_parameters.p_mesh_storage->v3_z; + int number_of_points_in_array = 0; + mesh_shell_array.elements = malloc(3*n_facets * sizeof(Coords)); + int is_dublicate = 0; + Coords this_vert; + int i,j; + for (i=0 ; i < n_facets ; i++){ - // v1 - is_dublicate = 0; - this_vert = coords_set(*(v1_x+i),*(v1_y+i),*(v1_z+i)); + // v1 + is_dublicate = 0; + this_vert = coords_set(*(v1_x+i),*(v1_y+i),*(v1_z+i)); - // test if dublicate - for (j = 0; j < number_of_points_in_array ; j++ ){ - if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ - is_dublicate = 1; - j = number_of_points_in_array; - } - } - if (is_dublicate == 0){ - mesh_shell_array.elements[number_of_points_in_array] = this_vert; - number_of_points_in_array += 1; - } + // test if dublicate + for (j = 0; j < number_of_points_in_array ; j++ ){ + if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ + is_dublicate = 1; + j = number_of_points_in_array; + } + } + if (is_dublicate == 0){ + mesh_shell_array.elements[number_of_points_in_array] = this_vert; + number_of_points_in_array += 1; + } - // v2 - is_dublicate = 0; - this_vert = coords_set(*(v2_x+i),*(v2_y+i),*(v2_z+i)); + // v2 + is_dublicate = 0; + this_vert = coords_set(*(v2_x+i),*(v2_y+i),*(v2_z+i)); - for (j = 0; j < number_of_points_in_array ; j++){ - if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ - is_dublicate = 1; - j = number_of_points_in_array; - } - } - if (is_dublicate == 0){ - mesh_shell_array.elements[number_of_points_in_array] = this_vert; - number_of_points_in_array += 1; - } + for (j = 0; j < number_of_points_in_array ; j++){ + if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ + is_dublicate = 1; + j = number_of_points_in_array; + } + } + if (is_dublicate == 0){ + mesh_shell_array.elements[number_of_points_in_array] = this_vert; + number_of_points_in_array += 1; + } - // v3 - is_dublicate = 0; - this_vert = coords_set(*(v3_x+i),*(v3_y+i),*(v3_z+i)); + // v3 + is_dublicate = 0; + this_vert = coords_set(*(v3_x+i),*(v3_y+i),*(v3_z+i)); - // test if dublicate - for (j = 0; j < number_of_points_in_array ; j++ ){ - if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ - is_dublicate = 1; - j = number_of_points_in_array; - } - } - if (is_dublicate == 0){ - mesh_shell_array.elements[number_of_points_in_array] = this_vert; - number_of_points_in_array += 1; - } - } + // test if dublicate + for (j = 0; j < number_of_points_in_array ; j++ ){ + if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ + is_dublicate = 1; + j = number_of_points_in_array; + } + } + if (is_dublicate == 0){ + mesh_shell_array.elements[number_of_points_in_array] = this_vert; + number_of_points_in_array += 1; + } + } - j = number_of_points_in_array - 1; // Last legal index, currently j is out of bounds. + j = number_of_points_in_array - 1; // Last legal index, currently j is out of bounds. - mesh_shell_array.num_elements = number_of_points_in_array; + mesh_shell_array.num_elements = number_of_points_in_array; - for (i=0; icenter); - mesh_shell_array.elements[i] = rot_apply(geometry->rotation_matrix, mesh_shell_array.elements[i]); - } - return mesh_shell_array; + for (i=0; icenter); + mesh_shell_array.elements[i] = rot_apply(geometry->rotation_matrix, mesh_shell_array.elements[i]); + } + return mesh_shell_array; } @@ -707,7 +707,7 @@ void initialize_mesh_geometry_from_main_component(struct geometry_struct *mesh) double square(double x){ - return x*x; + return x*x; } %} @@ -750,48 +750,48 @@ INITIALIZE geometry_struct_init(&(mesh_vol.geometry)); mesh_vol.geometry.skip_hierarchy_optimization = skip_convex_check; // Initializes the focusing system for this volume including input sanitation. -focus_initialize(&mesh_vol.geometry, - POS_A_COMP_INDEX(INDEX_CURRENT_COMP+target_index), - POS_A_CURRENT_COMP, - ROT_A_CURRENT_COMP, - target_index, - target_x, - target_y, - target_z, - focus_aw, - focus_ah, - focus_xw, - focus_xh, - focus_r, - NAME_CURRENT_COMP); +focus_initialize(&mesh_vol.geometry, + POS_A_COMP_INDEX(INDEX_CURRENT_COMP+target_index), + POS_A_CURRENT_COMP, + ROT_A_CURRENT_COMP, + target_index, + target_x, + target_y, + target_z, + focus_aw, + focus_ah, + focus_xw, + focus_xh, + focus_r, + NAME_CURRENT_COMP); if (_getcomp_index(init) < 0) { - fprintf(stderr,"Union_mesh:%s: Error identifying Union_init component," - "%s is not a known component name.\n",NAME_CURRENT_COMP, init); -exit(-1); + fprintf(stderr,"Union_mesh:%s: Error identifying Union_init component," + "%s is not a known component name.\n",NAME_CURRENT_COMP, init); + exit(-1); } struct pointer_to_global_material_list *global_material_list = COMP_GETPAR3( - Union_init, - init, - global_material_list); + Union_init, + init, + global_material_list); // Use sanitation #ifdef MATERIAL_DETECTOR -if (global_material_list->num_elements == 0) { - // Here if the user have defined a material, but only after this material - printf("\nERROR: Need to define a material using Union_make_material" - " before using a Union geometry component. \n"); - printf("%s was defined before first use of Union_make_material.\n",NAME_CURRENT_COMP); - exit(1); -} + if (global_material_list->num_elements == 0) { + // Here if the user have defined a material, but only after this material + printf("\nERROR: Need to define a material using Union_make_material" + " before using a Union geometry component. \n"); + printf("%s was defined before first use of Union_make_material.\n",NAME_CURRENT_COMP); + exit(1); + } #endif #ifndef MATERIAL_DETECTOR -printf("\nERROR: Need to define a material using Union_make_material" - " before using a Union geometry component. \n"); - exit(1); + printf("\nERROR: Need to define a material using Union_make_material" + " before using a Union geometry component. \n"); + exit(1); #endif @@ -800,8 +800,8 @@ mesh_vol.geometry.is_exit_volume = 0; mesh_vol.geometry.is_mask_volume = 0; struct pointer_to_global_geometry_list *global_geometry_list = COMP_GETPAR3(Union_init, - init, - global_geometry_list); + init, + global_geometry_list); //============================================================================== // Find out what this component masks //============================================================================== @@ -809,29 +809,29 @@ struct pointer_to_global_geometry_list *global_geometry_list = COMP_GETPAR3(Unio // Read the material input, or if it lacks, use automatic linking. -if (mask_string && - strlen(mask_string) && - strcmp(mask_string, "NULL") && - strcmp(mask_string, "0")) { - // A mask volume is used to limit the extend of other volumes, - // called the masked volumes. These are specified in the mask_string. - // In order for a ray to enter a masked volume, - // it needs to be both in the region covered by that volume AND the mask volume. +if (mask_string && + strlen(mask_string) && + strcmp(mask_string, "NULL") && + strcmp(mask_string, "0")) { + // A mask volume is used to limit the extend of other volumes, + // called the masked volumes. These are specified in the mask_string. + // In order for a ray to enter a masked volume, + // it needs to be both in the region covered by that volume AND the mask volume. // When more than mesh_vol.geometry.mask_mode = 1; // Default mask mode is ALL if (mask_setting && strlen(mask_setting) && strcmp(mask_setting, - "NULL") && strcmp(mask_setting, "0")) { - if (strcmp(mask_setting,"ALL") == 0 || strcmp(mask_setting,"All") == 0) { - mesh_vol.geometry.mask_mode = 1; - } - else if (strcmp(mask_setting,"ANY") == 0 || strcmp(mask_setting,"Any") == 0) { - mesh_vol.geometry.mask_mode = 2; - } - else { - printf("The mask_mode of component %s is set to %s," - " but must be either ALL or ANY.\n", - NAME_CURRENT_COMP,mask_setting); - exit(1); + "NULL") && strcmp(mask_setting, "0")) { + if (strcmp(mask_setting,"ALL") == 0 || strcmp(mask_setting,"All") == 0) { + mesh_vol.geometry.mask_mode = 1; + } + else if (strcmp(mask_setting,"ANY") == 0 || strcmp(mask_setting,"Any") == 0) { + mesh_vol.geometry.mask_mode = 2; + } + else { + printf("The mask_mode of component %s is set to %s," + " but must be either ALL or ANY.\n", + NAME_CURRENT_COMP,mask_setting); + exit(1); } } @@ -855,9 +855,9 @@ if (mask_string && } } if (found_geometries == 0) { - printf("The mask_string in geometry: " - "%s did not find any of the specified volumes in the mask_string " - "%s \n",NAME_CURRENT_COMP,mask_string); + printf("The mask_string in geometry: " + "%s did not find any of the specified volumes in the mask_string " + "%s \n",NAME_CURRENT_COMP,mask_string); exit(1); } mesh_vol.p_physics = malloc(sizeof(struct physics_struct)); @@ -868,21 +868,21 @@ if (mask_string && mesh_vol.geometry.is_mask_volume = 1; -// Read the material input, or if it lacks, use automatic linking. -} else if (material_string - && strlen(material_string) - && strcmp(material_string, "NULL") - && strcmp(material_string, "0")) { + // Read the material input, or if it lacks, use automatic linking. +} else if (material_string + && strlen(material_string) + && strcmp(material_string, "NULL") + && strcmp(material_string, "0")) { // A geometry string was given, use it to determine which material - if (0 == strcmp(material_string,"vacuum") - || 0 == strcmp(material_string,"Vacuum")) { + if (0 == strcmp(material_string,"vacuum") + || 0 == strcmp(material_string,"Vacuum")) { // One could have a global physics struct for vacuum instead of creating one for each mesh_vol.p_physics = malloc(sizeof(struct physics_struct)); mesh_vol.p_physics->is_vacuum = 1; // Makes this volume a vacuum mesh_vol.p_physics->number_of_processes = (int) 0; mesh_vol.p_physics->my_a = 0; // Should not be used. sprintf(mesh_vol.p_physics->name,"Vacuum"); - } else if (0 == strcmp(material_string,"exit") + } else if (0 == strcmp(material_string,"exit") || 0 == strcmp(material_string,"Exit")) { // One could have a global physics struct for exit instead of creating one for each mesh_vol.p_physics = malloc(sizeof(struct physics_struct)); @@ -893,25 +893,25 @@ if (mask_string && sprintf(mesh_vol.p_physics->name,"Exit"); } else { for (loop_index=0;loop_indexnum_elements;loop_index++) { - if (0 == strcmp(material_string,global_material_list->elements[loop_index].name)) { - mesh_vol.p_physics = global_material_list->elements[loop_index].physics; - break; - } - if (loop_index == global_material_list->num_elements-1) { - printf("\n"); - printf("ERROR: The material string \"%s\" in Union geometry \"%s\"" - " did not match a specified material. \n",material_string,NAME_CURRENT_COMP); - printf(" The materials available at this point" - " (need to be defined before the geometry): \n"); - for (loop_index=0;loop_indexnum_elements;loop_index++) - printf(" %s\n",global_material_list->elements[loop_index].name); - printf("\n"); - printf(" It is also possible to use one of the defualt materials avaiable: \n"); - printf(" Vacuum (for a Volume without scattering or absorption)\n"); - printf(" Exit (for a Volume where the ray exits the component if it enters)\n"); - printf(" Mask (for a Volume that masks existing volumes specified in the mask_string\n"); - exit(1); - } + if (0 == strcmp(material_string,global_material_list->elements[loop_index].name)) { + mesh_vol.p_physics = global_material_list->elements[loop_index].physics; + break; + } + if (loop_index == global_material_list->num_elements-1) { + printf("\n"); + printf("ERROR: The material string \"%s\" in Union geometry \"%s\"" + " did not match a specified material. \n",material_string,NAME_CURRENT_COMP); + printf(" The materials available at this point" + " (need to be defined before the geometry): \n"); + for (loop_index=0;loop_indexnum_elements;loop_index++) + printf(" %s\n",global_material_list->elements[loop_index].name); + printf("\n"); + printf(" It is also possible to use one of the defualt materials avaiable: \n"); + printf(" Vacuum (for a Volume without scattering or absorption)\n"); + printf(" Exit (for a Volume where the ray exits the component if it enters)\n"); + printf(" Mask (for a Volume that masks existing volumes specified in the mask_string\n"); + exit(1); + } } } } else { @@ -923,9 +923,9 @@ if (mask_string && mesh_vol.p_physics = global_material_list->elements[global_material_list->num_elements-1].physics; } //============================================================================== -// READ FIle +// READ FIle //============================================================================== -// Read input file and put into storage. +// Read input file and put into storage. // We assume that the input file is using triangular faces, otherwise // the check for closed mesh using the Euler-Poincare characteristic // is wrong. @@ -940,39 +940,39 @@ int unique_index = 0; const char *dot = strrchr(filename, '.'); if (!dot || dot == filename) { - printf("ERROR: given file has no extension %s", NAME_CURRENT_COMP); - exit(1); + printf("ERROR: given file has no extension %s", NAME_CURRENT_COMP); + exit(1); } if(strcmp(dot, ".stl") == 0 || strcmp(dot, ".STL") == 0){ - printf("\n%s, Given file is in stl format. Union_mesh assumes three vertices per face.\n", - NAME_CURRENT_COMP); - read_stl(filename, - &n_verts, - &n_faces, - &n_edges, - &verts, - &faces, - NAME_CURRENT_COMP); + printf("\n%s, Given file is in stl format. Union_mesh assumes three vertices per face.\n", + NAME_CURRENT_COMP); + read_stl(filename, + &n_verts, + &n_faces, + &n_edges, + &verts, + &faces, + NAME_CURRENT_COMP); } else if (strcmp(dot, ".off") == 0 || strcmp(dot, ".OFF") == 0) { - printf("\n%s, Given file is in off format. Union_mesh assumes three vertices per face.\n", - NAME_CURRENT_COMP); - read_off_file_vertices_and_faces(filename, - &n_verts, - &n_faces, - &n_edges, - &verts, - &faces, - NAME_CURRENT_COMP); + printf("\n%s, Given file is in off format. Union_mesh assumes three vertices per face.\n", + NAME_CURRENT_COMP); + read_off_file_vertices_and_faces(filename, + &n_verts, + &n_faces, + &n_edges, + &verts, + &faces, + NAME_CURRENT_COMP); } else { - printf("\nERROR IN %s: File %s is read as neither an stl or an off file.", - NAME_CURRENT_COMP, filename); - exit(1); + printf("\nERROR IN %s: File %s is read as neither an stl or an off file.", + NAME_CURRENT_COMP, filename); + exit(1); } -printf("\nCOMPONENT %s: Number of faces read: %d\t Number of vertices read: %d\n", - NAME_CURRENT_COMP, n_verts, n_faces); +printf("\nCOMPONENT %s: Number of faces read: %d\t Number of vertices read: %d\n", + NAME_CURRENT_COMP, n_verts, n_faces); // Loop over all vertices and multiply their positions with coordinate_scale for (int i = 0; imax_dist){ - max_dist = dist; - B_sphere_y = verts[i]; - } + dist = sqrt(B_sphere_x.x - verts[i].x + + B_sphere_x.y - verts[i].y + + B_sphere_x.z - verts[i].z); + if (dist>max_dist){ + max_dist = dist; + B_sphere_y = verts[i]; + } } Coords B_sphere_z = B_sphere_y; max_dist = 0; for (int i=0; imax_dist){ - max_dist = dist; - B_sphere_z = verts[i]; - } + if (dist>max_dist){ + max_dist = dist; + B_sphere_z = verts[i]; + } } double radius = sqrt(square(B_sphere_y.x-B_sphere_z.x) - + square(B_sphere_y.y-B_sphere_z.y) - + square(B_sphere_y.z-B_sphere_z.z))/2; + + square(B_sphere_y.y-B_sphere_z.y) + + square(B_sphere_y.z-B_sphere_z.z))/2; Coords bbcenter = coords_set((B_sphere_y.x + B_sphere_z.x)/2, - (B_sphere_y.y + B_sphere_z.y)/2, - (B_sphere_y.z + B_sphere_z.z)/2); + (B_sphere_y.y + B_sphere_z.y)/2, + (B_sphere_y.z + B_sphere_z.z)/2); mesh_data.Bounding_Box_Center = bbcenter; double test_rad = 0; for (int i=0; iradius){ - radius = test_rad; - } + test_rad = sqrt(square(bbcenter.x-verts[i].x) + + square(bbcenter.y-verts[i].y) + + square(bbcenter.z-verts[i].z)); + if (test_rad>radius){ + radius = test_rad; + } } mesh_data.Bounding_Box_Radius = radius; @@ -1088,32 +1088,32 @@ mesh_data.normal_x = (double *)malloc(n_faces*sizeof(double)); mesh_data.normal_y = (double *)malloc(n_faces*sizeof(double)); mesh_data.normal_z = (double *)malloc(n_faces*sizeof(double)); for (int i=0; i Date: Mon, 9 Feb 2026 14:11:24 +0100 Subject: [PATCH 09/11] Use Microsofts C formatter on monochromator bent --- mcstas-comps/contrib/Monochromator_bent.comp | 3172 ++++++++++-------- 1 file changed, 1728 insertions(+), 1444 deletions(-) diff --git a/mcstas-comps/contrib/Monochromator_bent.comp b/mcstas-comps/contrib/Monochromator_bent.comp index 3cc6f41bd..68ecd387a 100755 --- a/mcstas-comps/contrib/Monochromator_bent.comp +++ b/mcstas-comps/contrib/Monochromator_bent.comp @@ -85,1534 +85,1818 @@ NOACC SHARE %{ - #include - - /////////////////////////////////////////////////////////////////////////// - /////////////// Structs for the component - /////////////////////////////////////////////////////////////////////////// - - struct Monochromator_values{ - double length, height, thickness; - double mosaicity_horizontal, mosaicity_vertical; - int type; - double radius_horizontal; - double radius_vertical; - double radius_outer; - double radius_inner; - double Debye_Waller_factor; - double lattice_spacing; - double Maier_Leibnitz_reflectivity; - double poisson_ratio; - double bound_atom_scattering_cross_section; - double absorption_for_1AA_Neutrons; - double incoherent_scattering_cross_section; - double volume; - double Constant_from_Freund_paper; - double debye_temperature; - double atomic_number; - double temperature_mono; - double B0; - double BT; - double single_phonon_absorption; - double multiple_phonon_absorption; - double nuclear_capture_absorption; - double total_absorption; - double tau[3]; - double perp_to_tau[3]; - double lattice_spacing_gradient_field[3][3]; - double gradient_of_bragg_angle; - double domain_thickness; - double max_angle; - double min_angle; - double angle_range; - double rotation_matrices[3][3]; // pointer to rotation matrices - double neg_rotation_matrix[3][3]; // pointer to rotation matrices - double x; - double y; - double z; - double bounding_box_thickness; // the xthickness plus the arrowheight (the saggita) - }; - - struct Monochromator_array{ - struct Monochromator_values* crystal; - int number_of_crystals; - int verbosity; - }; - - struct neutron_values { - // Statically allocate vectors that are always 3 - double ki[3]; // Incoming wavevector - double kf[3]; // outgoig wavevector - double r[3]; - double v[3]; // velocity of neutron - double tau[3]; //Reciprocal lattice vector - double ki_size; // size of incoming wavevector - double v_size; // speed - double tau_size; // size of reciprocal lattice vector - double kf_size; // size of outgoing wavevector - double* vert_angle; // Angle of deviation by the mosaic crystal vertically - double* horiz_angle; // Angle of deviation by the mosaic crystal in x-z plane - double* beta; // Gradient of deviation from bragg condition - double* eps_zero; // Angular deviation from bragg angle - double absorption; // Absorption factor - double path; // Length of the path the neutron follows - double wavelength; // De Broglie wavelength of neutron - double kinematic_reflectivity; // The Q value from the paper this code is based on. - double* path_length; // The time spent in crystals, to add to path for attenuation - double* entry_time; // Time from start of crystal, to entrance of each lamella - double* exit_time; // Time from start of crystal, to exit of each lamella - double* probabilities; // Probability of reflection in each lamella - double* accu_probs; // Accumulating probability in each lamella - double TOR; // The time in s from crystal edge to reflection - int chosen_crystal; // Which crystal the neutron reflects from in - int transmit_neutron; - int direction; // Direction of neutron - int n; // Number of crystals in the monochromator - int reflections; // How many reflections has the neutron performed - int intersections; // How many crystals the neutron has intersected - int* intersection_list; // List of intersected crystals, sorted by intersection time. - }; - - enum crystal_type {flat, bent, mosaic, bent_mosaic}; - - //////////////////////////////////////////////////////////////////////////// - /////////////// Mathematical functions for the component - //////////////////////////////////////////////////////////////////////////// - - double sign(double x){ - if (x >= 0) return 1; - return -1; - } - - double square(double x){ - return x*x; - } - // Function to generate numbers in a uniform distribution - double random_normal_distribution(double* sigma, _class_particle* _particle){ - double u1, u2; - u1 = rand01(); - u2 = rand01(); - double r = sqrt(-2 * log(u1)); - double theta = 2 * M_PI * u2; - return *sigma * r * cos(theta); - } - - // The following two function returns, respectively, - // the Gaussian cumulative distribution function, - // And the inverse gaussian cumulative distribution function. - double normalCDF(double x, double sigma) { - return 0.5 * (1 + erf( x * M_SQRT1_2)); - } - // Inspired by https://gist.github.com/kmpm/1211922/6b7fcd0155b23c3dc71e6f4969f2c48785371292 - double inverseNormalCDF(double p, double sigma){ - if (p <= 0 || p >= 1) return sign(p)*6; - - double mu = 0; - double r, val; - double q = p - 0.5; - - if (fabs(q) <= .425) { - r = .180625 - q * q; - val = - q * (((((((r * 2509.0809287301226727 + - 33430.575583588128105) * r + 67265.770927008700853) * r + - 45921.953931549871457) * r + 13731.693765509461125) * r + - 1971.5909503065514427) * r + 133.14166789178437745) * r + - 3.387132872796366608) - / (((((((r * 5226.495278852854561 + - 28729.085735721942674) * r + 39307.89580009271061) * r + - 21213.794301586595867) * r + 5394.1960214247511077) * r + - 687.1870074920579083) * r + 42.313330701600911252) * r + 1); +#include + +/////////////////////////////////////////////////////////////////////////// +/////////////// Structs for the component +/////////////////////////////////////////////////////////////////////////// + +struct Monochromator_values +{ + double length, height, thickness; + double mosaicity_horizontal, mosaicity_vertical; + int type; + double radius_horizontal; + double radius_vertical; + double radius_outer; + double radius_inner; + double Debye_Waller_factor; + double lattice_spacing; + double Maier_Leibnitz_reflectivity; + double poisson_ratio; + double bound_atom_scattering_cross_section; + double absorption_for_1AA_Neutrons; + double incoherent_scattering_cross_section; + double volume; + double Constant_from_Freund_paper; + double debye_temperature; + double atomic_number; + double temperature_mono; + double B0; + double BT; + double single_phonon_absorption; + double multiple_phonon_absorption; + double nuclear_capture_absorption; + double total_absorption; + double tau[3]; + double perp_to_tau[3]; + double lattice_spacing_gradient_field[3][3]; + double gradient_of_bragg_angle; + double domain_thickness; + double max_angle; + double min_angle; + double angle_range; + double rotation_matrices[3][3]; // pointer to rotation matrices + double neg_rotation_matrix[3][3]; // pointer to rotation matrices + double x; + double y; + double z; + double bounding_box_thickness; // the xthickness plus the arrowheight (the saggita) +}; + +struct Monochromator_array +{ + struct Monochromator_values *crystal; + int number_of_crystals; + int verbosity; +}; + +struct neutron_values +{ + // Statically allocate vectors that are always 3 + double ki[3]; // Incoming wavevector + double kf[3]; // outgoig wavevector + double r[3]; + double v[3]; // velocity of neutron + double tau[3]; // Reciprocal lattice vector + double ki_size; // size of incoming wavevector + double v_size; // speed + double tau_size; // size of reciprocal lattice vector + double kf_size; // size of outgoing wavevector + double *vert_angle; // Angle of deviation by the mosaic crystal vertically + double *horiz_angle; // Angle of deviation by the mosaic crystal in x-z plane + double *beta; // Gradient of deviation from bragg condition + double *eps_zero; // Angular deviation from bragg angle + double absorption; // Absorption factor + double path; // Length of the path the neutron follows + double wavelength; // De Broglie wavelength of neutron + double kinematic_reflectivity; // The Q value from the paper this code is based on. + double *path_length; // The time spent in crystals, to add to path for attenuation + double *entry_time; // Time from start of crystal, to entrance of each lamella + double *exit_time; // Time from start of crystal, to exit of each lamella + double *probabilities; // Probability of reflection in each lamella + double *accu_probs; // Accumulating probability in each lamella + double TOR; // The time in s from crystal edge to reflection + int chosen_crystal; // Which crystal the neutron reflects from in + int transmit_neutron; + int direction; // Direction of neutron + int n; // Number of crystals in the monochromator + int reflections; // How many reflections has the neutron performed + int intersections; // How many crystals the neutron has intersected + int *intersection_list; // List of intersected crystals, sorted by intersection time. +}; + +enum crystal_type +{ + flat, + bent, + mosaic, + bent_mosaic +}; + +//////////////////////////////////////////////////////////////////////////// +/////////////// Mathematical functions for the component +//////////////////////////////////////////////////////////////////////////// + +double sign(double x) +{ + if (x >= 0) + return 1; + return -1; +} + +double square(double x) +{ + return x * x; +} +// Function to generate numbers in a uniform distribution +double random_normal_distribution(double *sigma, _class_particle *_particle) +{ + double u1, u2; + u1 = rand01(); + u2 = rand01(); + double r = sqrt(-2 * log(u1)); + double theta = 2 * M_PI * u2; + return *sigma * r * cos(theta); +} + +// The following two function returns, respectively, +// the Gaussian cumulative distribution function, +// And the inverse gaussian cumulative distribution function. +double normalCDF(double x, double sigma) +{ + return 0.5 * (1 + erf(x * M_SQRT1_2)); +} +// Inspired by https://gist.github.com/kmpm/1211922/6b7fcd0155b23c3dc71e6f4969f2c48785371292 +double inverseNormalCDF(double p, double sigma) +{ + if (p <= 0 || p >= 1) + return sign(p) * 6; + + double mu = 0; + double r, val; + double q = p - 0.5; + + if (fabs(q) <= .425) + { + r = .180625 - q * q; + val = + q * (((((((r * 2509.0809287301226727 + 33430.575583588128105) * r + 67265.770927008700853) * r + 45921.953931549871457) * r + 13731.693765509461125) * r + 1971.5909503065514427) * r + 133.14166789178437745) * r + 3.387132872796366608) / (((((((r * 5226.495278852854561 + 28729.085735721942674) * r + 39307.89580009271061) * r + 21213.794301586595867) * r + 5394.1960214247511077) * r + 687.1870074920579083) * r + 42.313330701600911252) * r + 1); + } + else + { + if (q > 0) + { + r = 1 - p; + } + else + { + r = p; } - else { - if (q > 0) { - r = 1 - p; - } - else { - r = p; - } - - r = sqrt(-log(r)); - if (r <= 5) - { - r += -1.6; - val = (((((((r * 7.7454501427834140764e-4 + - .0227238449892691845833) * r + .24178072517745061177) * - r + 1.27045825245236838258) * r + - 3.64784832476320460504) * r + 5.7694972214606914055) * - r + 4.6303378461565452959) * r + - 1.42343711074968357734) - / (((((((r * - 1.05075007164441684324e-9 + 5.475938084995344946e-4) * - r + .0151986665636164571966) * r + - .14810397642748007459) * r + .68976733498510000455) * - r + 1.6763848301838038494) * r + - 2.05319162663775882187) * r + 1); - } - else { /* very close to 0 or 1 */ - r += -5; - val = (((((((r * 2.01033439929228813265e-7 + - 2.71155556874348757815e-5) * r + - .0012426609473880784386) * r + .026532189526576123093) * - r + .29656057182850489123) * r + - 1.7848265399172913358) * r + 5.4637849111641143699) * - r + 6.6579046435011037772) - / (((((((r * - 2.04426310338993978564e-15 + 1.4215117583164458887e-7) * - r + 1.8463183175100546818e-5) * r + - 7.868691311456132591e-4) * r + .0148753612908506148525) - * r + .13692988092273580531) * r + - .59983220655588793769) * r + 1); - } + r = sqrt(-log(r)); + + if (r <= 5) + { + r += -1.6; + val = (((((((r * 7.7454501427834140764e-4 + + .0227238449892691845833) * + r + + .24178072517745061177) * + r + + 1.27045825245236838258) * + r + + 3.64784832476320460504) * + r + + 5.7694972214606914055) * + r + + 4.6303378461565452959) * + r + + 1.42343711074968357734) / + (((((((r * + 1.05075007164441684324e-9 + + 5.475938084995344946e-4) * + r + + .0151986665636164571966) * + r + + .14810397642748007459) * + r + + .68976733498510000455) * + r + + 1.6763848301838038494) * + r + + 2.05319162663775882187) * + r + + 1); + } + else + { /* very close to 0 or 1 */ + r += -5; + val = (((((((r * 2.01033439929228813265e-7 + + 2.71155556874348757815e-5) * + r + + .0012426609473880784386) * + r + + .026532189526576123093) * + r + + .29656057182850489123) * + r + + 1.7848265399172913358) * + r + + 5.4637849111641143699) * + r + + 6.6579046435011037772) / + (((((((r * + 2.04426310338993978564e-15 + + 1.4215117583164458887e-7) * + r + + 1.8463183175100546818e-5) * + r + + 7.868691311456132591e-4) * + r + + .0148753612908506148525) * + r + + .13692988092273580531) * + r + + .59983220655588793769) * + r + + 1); + } - if (q < 0.0) { - val = -val; - } + if (q < 0.0) + { + val = -val; } + } - return mu + sigma * val; - } - //////////////////////////////////////////////////////////////////////////// - // End of mathematical functions - //////////////////////////////////////////////////////////////////////////// - - //========================================================================== - //======== Functions for choosing the right crystal for reflections ======== - //========================================================================== - enum crystal_plane {Cu111, Cu200, Cu220, Cu311, Cu400, Cu331, Cu420, Cu440, Ge111, Ge220, Ge311, - Ge400, Ge331, Ge422, Ge511, Ge533, Ge711, Ge551, Si111, Si220, Si311, Si400, Si331, - Si422, Si333, Si511, Si440, Si711, Si551, Be10, Be100, Be102, Be103, Be110, Be112, Be200, - Be00_2, Be10_1, PG00_2,PG00_4,PG00_6, Fe110, HS111,HS222,HS111star,Di111,Di220, Di311, Di400, - Di331, Di422, Di333, Di511, Di440}; - - // An array containing all the possible strings that will be accepted if given as an - // argument to the parameter plane_of_reflection - const char* crystal_planeStrings[] = { - "Cu111", "Cu200", "Cu220", "Cu311", "Cu400", "Cu331", "Cu420", "Cu440", "Ge111", - "Ge220", "Ge311", "Ge400", "Ge331", "Ge422", "Ge511", "Ge533", "Ge711", "Ge551", - "Si111", "Si220", "Si311", "Si400", "Si331", "Si422", "Si333", "Si511", "Si440", - "Si711", "Si551"," Be10", "Be100", "Be102", "Be103", "Be110", "Be112", "Be200", - "Be00_2", "Be10_1", "PG00_2","PG00_4","PG00_6", "Fe110", "HS111","HS222","HS111star", - "Di111","Di220", "Di311", "Di400", "Di331", "Di422", "Di333", "Di511", "Di440"}; - - // Function to convert a string to an enum value - enum crystal_plane stringToEnum(const char* plane) { - for (int i = 0; i < sizeof(crystal_planeStrings) / sizeof(crystal_planeStrings[0]); ++i) { - if (strcmp(plane, crystal_planeStrings[i]) == 0) { - return (enum crystal_plane)i; - } + return mu + sigma * val; +} +//////////////////////////////////////////////////////////////////////////// +// End of mathematical functions +//////////////////////////////////////////////////////////////////////////// + +//========================================================================== +//======== Functions for choosing the right crystal for reflections ======== +//========================================================================== +enum crystal_plane +{ + Cu111, + Cu200, + Cu220, + Cu311, + Cu400, + Cu331, + Cu420, + Cu440, + Ge111, + Ge220, + Ge311, + Ge400, + Ge331, + Ge422, + Ge511, + Ge533, + Ge711, + Ge551, + Si111, + Si220, + Si311, + Si400, + Si331, + Si422, + Si333, + Si511, + Si440, + Si711, + Si551, + Be10, + Be100, + Be102, + Be103, + Be110, + Be112, + Be200, + Be00_2, + Be10_1, + PG00_2, + PG00_4, + PG00_6, + Fe110, + HS111, + HS222, + HS111star, + Di111, + Di220, + Di311, + Di400, + Di331, + Di422, + Di333, + Di511, + Di440 +}; + +// An array containing all the possible strings that will be accepted if given as an +// argument to the parameter plane_of_reflection +const char *crystal_planeStrings[] = { + "Cu111", "Cu200", "Cu220", "Cu311", "Cu400", "Cu331", "Cu420", "Cu440", "Ge111", + "Ge220", "Ge311", "Ge400", "Ge331", "Ge422", "Ge511", "Ge533", "Ge711", "Ge551", + "Si111", "Si220", "Si311", "Si400", "Si331", "Si422", "Si333", "Si511", "Si440", + "Si711", "Si551", " Be10", "Be100", "Be102", "Be103", "Be110", "Be112", "Be200", + "Be00_2", "Be10_1", "PG00_2", "PG00_4", "PG00_6", "Fe110", "HS111", "HS222", "HS111star", + "Di111", "Di220", "Di311", "Di400", "Di331", "Di422", "Di333", "Di511", "Di440"}; + +// Function to convert a string to an enum value +enum crystal_plane stringToEnum(const char *plane) +{ + for (int i = 0; i < sizeof(crystal_planeStrings) / sizeof(crystal_planeStrings[0]); ++i) + { + if (strcmp(plane, crystal_planeStrings[i]) == 0) + { + return (enum crystal_plane)i; } - return 0; } - /* TITLE Crystal table for perfect crystal bent monochromator - Table copied from SIMRES, current url: https://github.com/saroun/simres - Contents: dhkl, QML,sigmab,sigmaa,V0,A,thetaD,C2,poi - dhkl ... Lattice spacing of crystal plane. - QML = 4*PI*(F*dhkl/V0)**2 [ A^-1 cm^-1] - sigmab ... bound-atom scattering cross-section [barn] - sigmaa ... absorption for 1A neutrons [barn*A^-1] - sigmai ... incoherent scattering cross-section [barn] - V0 .... volume [A^3]/atom - A .... atomic number - thetaD .... Debye temperature (K) - C2 .... constant from the Freund's paper [A^-2 eV^-1] - poi .... Poisson elastic constant */ - - - double crystal_table[56][10] = {{ 2.087063, 0.23391E+00 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 1.80745 , 0.17544E+00 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 1.27806 , 0.87718E-01 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 1.089933, 0.63795E-01 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 0.903725, 0.43859E-01 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 0.829315, 0.36934E-01 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 0.808316, 0.35087E-01 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 0.63903 , 0.21930E-01 ,7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, - { 3.26665 , 0.87700E-01 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.15450E+00}, - { 2.00041 , 0.65760E-01 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.30000E+00}, - { 1.70595 , 0.23920E-01 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.15430E+00}, - { 1.41450 , 0.32880E-01 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27300E+00}, - { 1.29803 , 0.13850E-01 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.15430E+00}, - { 1.15493 , 0.21925E-01 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, - { 1.08888 , 0.97400E-02 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, - { 0.86284 , 0.61200E-02 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, - { 0.79228 , 0.51588E-02 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, - { 0.79228 , 0.51600E-02 ,8.42 , 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, - { 3.13536 , 0.25970E-01 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.18080E+00}, - { 1.92001 , 0.19480E-01 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.30000E+00}, - { 1.63739 , 0.70800E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 1.35765 , 0.97400E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 1.24587 , 0.41000E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.18080E+00}, - { 1.10852 , 0.64930E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 1.04512 , 0.28900E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 1.04512 , 0.28900E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 0.96000 , 0.48700E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 0.76044 , 0.15277E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 0.76044 , 0.15277E-02 ,2.18 , 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, - { 1.97956 , 0.11361 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.30000E+00}, - { 1.97956 , 0.11361 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, - { 1.32857 , 0.05117 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, - { 1.02290 , 0.091 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, - { 1.14290 , 0.15147 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, - { 0.96363 , 0.10768 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, - { 0.98978 , 0.0284 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, - { 1.79215 , 0.37245 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.30000E+00}, - { 1.73285 , 0.26116 ,7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.30000E+00}, - { 3.35500 , 0.79500E+00 ,5.555, 0.0019, 0.0, 8.80, 12.01, 1050, 20.00, 0.30000E+00}, - { 1.67750 , 0.18000E+00 ,5.555, 0.0019, 0.0, 8.80, 12.01, 1050, 20.00, 0.30000E+00}, - { 1.11830 , 0.08833E+00 ,5.555, 0.0019, 0.0, 8.80, 12.01, 1050, 20.00, 0.30000E+00}, - { 2.02660 , 0.34031E+00 ,11.43, 2.53, 0.4 , 11.75 , 55.85, 411, 10.67 , 0.30000E+00}, - { 3.43500 , 0.11020E+00 ,1.79, 2.88, 0.55, 13.16, 48.0, 300, 12.00 , 0.30000E+00}, - { 1.71750 , 0.13130E+00 ,1.79, 2.88, 0.55, 13.16, 48.0, 300, 12.00 , 0.30000E+00}, - { 3.43500 , 0.55100E-01 ,1.79, 2.88, 0.55, 13.16, 48.0, 300, 12.00 , 0.30000E+00}, - { 2.05929 , 0.36606 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 1.26105 , 0.27455 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 1.07543 , 0.09984 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 0.89170 , 0.13727 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 0.81828 , 0.0578 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 0.72807 , 0.09152 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 0.68643 , 0.04067 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 0.68643 , 0.04067 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 0.63053 , 0.06864 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, - { 0.63053 , 0.06864 ,5.55449 ,0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00} - }; - /////////////////////////////////////////////////////////////////////////// - // End of functions for choosing crystal reflections - /////////////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////////////// - /////////////// Testing function - /////////////////////////////////////////////////////////////////////////// - void print_neutron_state(struct neutron_values* neutron){ - printf("Neutron state:\nki %g, %g, %g\ntau %g, %g, %g\nkf %g, %g, %g\nv %g, %g, %g\nr %g, %g, %g\nki size %g, tau size %g, kf size %g, v size %g\n\n", - neutron->ki[0], neutron->ki[1], neutron->ki[2], - neutron->tau[0], neutron->tau[1], neutron->tau[2], - neutron->kf[0], neutron->kf[1], neutron->kf[2], - neutron->v[0], neutron->v[1], neutron->v[2], - neutron->r[0], neutron->r[1], neutron->r[2], - neutron->ki_size, neutron->tau_size, neutron->kf_size, neutron->v_size - ); - } - - /////////////////////////////////////////////////////////////////////////// - /////////////// Calculations for absorption factor - /////////////// Based on the cross sections from - /////////////// A. K. Freund in Nuclear Instruments and Methods 213 (1983) 495-501 - /////////////////////////////////////////////////////////////////////////// - - // Integral needed for debye factor - - double calculate_phi_integral(double x){ + return 0; +} +/* TITLE Crystal table for perfect crystal bent monochromator +Table copied from SIMRES, current url: https://github.com/saroun/simres +Contents: dhkl, QML,sigmab,sigmaa,V0,A,thetaD,C2,poi +dhkl ... Lattice spacing of crystal plane. +QML = 4*PI*(F*dhkl/V0)**2 [ A^-1 cm^-1] +sigmab ... bound-atom scattering cross-section [barn] +sigmaa ... absorption for 1A neutrons [barn*A^-1] +sigmai ... incoherent scattering cross-section [barn] +V0 .... volume [A^3]/atom +A .... atomic number +thetaD .... Debye temperature (K) +C2 .... constant from the Freund's paper [A^-2 eV^-1] +poi .... Poisson elastic constant */ + +double crystal_table[56][10] = {{2.087063, 0.23391E+00, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {1.80745, 0.17544E+00, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {1.27806, 0.87718E-01, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {1.089933, 0.63795E-01, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {0.903725, 0.43859E-01, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {0.829315, 0.36934E-01, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {0.808316, 0.35087E-01, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {0.63903, 0.21930E-01, 7.485, 2.094, 0.55, 11.81, 63.54, 315, 12.00, 0.30000E+00}, + {3.26665, 0.87700E-01, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.15450E+00}, + {2.00041, 0.65760E-01, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.30000E+00}, + {1.70595, 0.23920E-01, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.15430E+00}, + {1.41450, 0.32880E-01, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27300E+00}, + {1.29803, 0.13850E-01, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.15430E+00}, + {1.15493, 0.21925E-01, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, + {1.08888, 0.97400E-02, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, + {0.86284, 0.61200E-02, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, + {0.79228, 0.51588E-02, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, + {0.79228, 0.51600E-02, 8.42, 1.216, 0.18, 22.63, 72.6, 290, 9.0, 0.27270E+00}, + {3.13536, 0.25970E-01, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.18080E+00}, + {1.92001, 0.19480E-01, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.30000E+00}, + {1.63739, 0.70800E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {1.35765, 0.97400E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {1.24587, 0.41000E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.18080E+00}, + {1.10852, 0.64930E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {1.04512, 0.28900E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {1.04512, 0.28900E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {0.96000, 0.48700E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {0.76044, 0.15277E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {0.76044, 0.15277E-02, 2.18, 0.0889, 0.0, 20.02, 28.09, 420, 6.36, 0.28000E+00}, + {1.97956, 0.11361, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.30000E+00}, + {1.97956, 0.11361, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, + {1.32857, 0.05117, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, + {1.02290, 0.091, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, + {1.14290, 0.15147, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, + {0.96363, 0.10768, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, + {0.98978, 0.0284, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.28000E+00}, + {1.79215, 0.37245, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.30000E+00}, + {1.73285, 0.26116, 7.62579, 0.00422655, 0.002, 8.10926, 9.012, 1100, 7.62, 0.30000E+00}, + {3.35500, 0.79500E+00, 5.555, 0.0019, 0.0, 8.80, 12.01, 1050, 20.00, 0.30000E+00}, + {1.67750, 0.18000E+00, 5.555, 0.0019, 0.0, 8.80, 12.01, 1050, 20.00, 0.30000E+00}, + {1.11830, 0.08833E+00, 5.555, 0.0019, 0.0, 8.80, 12.01, 1050, 20.00, 0.30000E+00}, + {2.02660, 0.34031E+00, 11.43, 2.53, 0.4, 11.75, 55.85, 411, 10.67, 0.30000E+00}, + {3.43500, 0.11020E+00, 1.79, 2.88, 0.55, 13.16, 48.0, 300, 12.00, 0.30000E+00}, + {1.71750, 0.13130E+00, 1.79, 2.88, 0.55, 13.16, 48.0, 300, 12.00, 0.30000E+00}, + {3.43500, 0.55100E-01, 1.79, 2.88, 0.55, 13.16, 48.0, 300, 12.00, 0.30000E+00}, + {2.05929, 0.36606, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {1.26105, 0.27455, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {1.07543, 0.09984, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {0.89170, 0.13727, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {0.81828, 0.0578, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {0.72807, 0.09152, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {0.68643, 0.04067, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {0.68643, 0.04067, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {0.63053, 0.06864, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}, + {0.63053, 0.06864, 5.55449, 0.00194444, 0.0, 5.67213, 12.01, 1860, 3.00, 0.30000E+00}}; +/////////////////////////////////////////////////////////////////////////// +// End of functions for choosing crystal reflections +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +/////////////// Testing function +/////////////////////////////////////////////////////////////////////////// +void print_neutron_state(struct neutron_values *neutron) +{ + printf("Neutron state:\nki %g, %g, %g\ntau %g, %g, %g\nkf %g, %g, %g\nv %g, %g, %g\nr %g, %g, %g\nki size %g, tau size %g, kf size %g, v size %g\n\n", + neutron->ki[0], neutron->ki[1], neutron->ki[2], + neutron->tau[0], neutron->tau[1], neutron->tau[2], + neutron->kf[0], neutron->kf[1], neutron->kf[2], + neutron->v[0], neutron->v[1], neutron->v[2], + neutron->r[0], neutron->r[1], neutron->r[2], + neutron->ki_size, neutron->tau_size, neutron->kf_size, neutron->v_size); +} + +/////////////////////////////////////////////////////////////////////////// +/////////////// Calculations for absorption factor +/////////////// Based on the cross sections from +/////////////// A. K. Freund in Nuclear Instruments and Methods 213 (1983) 495-501 +/////////////////////////////////////////////////////////////////////////// + +// Integral needed for debye factor + +double calculate_phi_integral(double x) +{ // Asymptotic approximation - if (x > 5) return PI * PI / 6 - exp(-x)/(x+1); + if (x > 5) + return PI * PI / 6 - exp(-x) / (x + 1); // Integate with Simpson/3. I dont know what this means - double z = 1 + x/(exp(x)-1); - double dx = x/100; - double ksi; - for (int i = 2; i <= 100; i++) { - ksi = (i-1)*dx; - switch (i%2){ - case 1: - z = z + 4 * ksi/(exp(ksi)-1); - break; - case 0: - z = z + 2 * ksi/(exp(ksi)-1); - break; - } + double z = 1 + x / (exp(x) - 1); + double dx = x / 100; + double ksi; + for (int i = 2; i <= 100; i++) + { + ksi = (i - 1) * dx; + switch (i % 2) + { + case 1: + z = z + 4 * ksi / (exp(ksi) - 1); + break; + case 0: + z = z + 2 * ksi / (exp(ksi) - 1); + break; } - return z*dx/3; - } - - /////////////////////////////////////////////////////////////////////////// - /////////////// Function for checking if the neutron is inside the - /////////////// monochromator - /////////////////////////////////////////////////////////////////////////// - - int neutron_is_inside_crystal(double* x, double* y, double* z, - struct Monochromator_values* mono){ - // Check that r, theta and h are within parameters - double num_sig = 1e-6; - double r = sqrt(*x* *x + *z* *z ); - if (r < mono->radius_inner - num_sig || r > mono->radius_outer + num_sig) { - return 0;} - double theta = atan2(*z, *x); - //TODO: This arctan2 call is what makes the component alot slower. - // SOURCE: https://math.stackexchange.com/questions/1098487/atan2-faster-approximation - // It mostly works but fails often. Could be implemented if necessary in the future. - // double a = min(fabs(*z), fabs(*x)) / max(fabs(*z), fabs(*x)); - // double s = a * a; - // double test = ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a; - // if (fabs(*z) > fabs(a)) test = 1.57079637 - test; - // if (*x < 0) test = 3.14159274 - test; - // if (*z < 0) test = -test; - if (theta < 0 && mono->radius_horizontal>0) theta = 2*PI + theta; - if (theta < mono->min_angle - num_sig || theta > mono->max_angle + num_sig) { - return 0;} - if (*y< - mono->height/2 - num_sig|| *y > mono->height/2 + num_sig) { - return 0;} - return 1; } - - /////////////////////////////////////////////////////////////////////////// - // Function that sorts which times are the two lowest for a single crystal - /////////////////////////////////////////////////////////////////////////// - void sort_times(double* t1, double* t2, double* new_t){ - // NOTE: This algorithm breaks down if an intersection - // is at exactly -1 second away. - // Make t1radius_inner - num_sig || r > mono->radius_outer + num_sig) + { + return 0; + } + double theta = atan2(*z, *x); + // TODO: This arctan2 call is what makes the component alot slower. + // SOURCE: https://math.stackexchange.com/questions/1098487/atan2-faster-approximation + // It mostly works but fails often. Could be implemented if necessary in the future. + // double a = min(fabs(*z), fabs(*x)) / max(fabs(*z), fabs(*x)); + // double s = a * a; + // double test = ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a; + // if (fabs(*z) > fabs(a)) test = 1.57079637 - test; + // if (*x < 0) test = 3.14159274 - test; + // if (*z < 0) test = -test; + if (theta < 0 && mono->radius_horizontal > 0) + theta = 2 * PI + theta; + if (theta < mono->min_angle - num_sig || theta > mono->max_angle + num_sig) + { + return 0; + } + if (*y < -mono->height / 2 - num_sig || *y > mono->height / 2 + num_sig) + { + return 0; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////////// +// Function that sorts which times are the two lowest for a single crystal +/////////////////////////////////////////////////////////////////////////// +void sort_times(double *t1, double *t2, double *new_t) +{ + // NOTE: This algorithm breaks down if an intersection + // is at exactly -1 second away. + // Make t1r[0] + neutron->v[0]* *new_t; - y = neutron->r[1] + neutron->v[1]* *new_t; - z = neutron->r[2] + neutron->v[2]* *new_t; - if (neutron_is_inside_crystal(&x, &y, &z, mono)){ - sort_times(t1, t2, new_t); + else if (*new_t < *t2) + { + if (*new_t < *t1) + { + *t2 = *t1; + *t1 = *new_t; } + else + *t2 = *new_t; } +} +//////////////////////////////////////////////////////////////////////////// +/////////////// Function for checking if an intersection has happened, +/////////////// and then updating the intersection times to match. +//////////////////////////////////////////////////////////////////////////// +void check_intersection_and_update_times(double *t1, double *t2, double *new_t, + struct neutron_values *neutron, + struct Monochromator_values *mono) +{ + // Function for checking if an intersection has happened, + // and then updating the intersection times to match. + double x, y, z; + x = neutron->r[0] + neutron->v[0] * *new_t; + y = neutron->r[1] + neutron->v[1] * *new_t; + z = neutron->r[2] + neutron->v[2] * *new_t; + if (neutron_is_inside_crystal(&x, &y, &z, mono)) + { + sort_times(t1, t2, new_t); + } +} + +//////////////////////////////////////////////////////////////////////////// +/////////////// Function for finding intersection times for a single crystal +//////////////////////////////////////////////////////////////////////////// +int cylinder_cut_out_intersect(double *t1, double *t2, + struct neutron_values *neutron, + struct Monochromator_values *mono) +{ + // TODO: Add reference to our paper for a visualisation of the geometry. + // The equations for this code are derived from the equation of the circle, + // equations for the neutron line, and the coordinates with cos and sin. + // This algorithm finds the two lowest values of time, + // and sets those as t1min_angle) * neutron->r[0] - neutron->r[2]) / + (neutron->v[2] - tan(mono->min_angle) * neutron->v[0]); + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + temp_t = (tan(mono->max_angle) * neutron->r[0] - neutron->r[2]) / + (neutron->v[2] - tan(mono->max_angle) * neutron->v[0]); + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + // Find intersections on the circular part of the crystal + double term1, term2, divisor; + term1 = mono->radius_inner * mono->radius_inner - neutron->r[0] * neutron->r[0] - neutron->r[2] * neutron->r[2]; + term2 = neutron->r[0] * neutron->v[0] + neutron->r[2] * neutron->v[2]; + divisor = neutron->v[0] * neutron->v[0] + neutron->v[2] * neutron->v[2]; + term1 = term1 / divisor + square(term2 / divisor); + if (term1 > 0) + { + term2 = neutron->r[0] * neutron->v[0] + neutron->r[2] * neutron->v[2]; - //////////////////////////////////////////////////////////////////////////// - /////////////// Function for finding intersection times for a single crystal - //////////////////////////////////////////////////////////////////////////// - int cylinder_cut_out_intersect(double *t1, double *t2, - struct neutron_values* neutron, - struct Monochromator_values* mono){ - // TODO: Add reference to our paper for a visualisation of the geometry. - // The equations for this code are derived from the equation of the circle, - // equations for the neutron line, and the coordinates with cos and sin. - // This algorithm finds the two lowest values of time, - // and sets those as t1min_angle)*neutron->r[0] - neutron->r[2])/ - (neutron->v[2] - tan(mono->min_angle)* neutron->v[0]); - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); - temp_t = (tan(mono->max_angle)*neutron->r[0] - neutron->r[2])/ - (neutron->v[2] - tan(mono->max_angle)* neutron->v[0]); - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); - // Find intersections on the circular part of the crystal - double term1, term2, divisor; - term1 = mono->radius_inner*mono->radius_inner - - neutron->r[0]*neutron->r[0] - - neutron->r[2]*neutron->r[2]; - term2 = neutron->r[0]*neutron->v[0] + neutron->r[2]*neutron->v[2]; - divisor = neutron->v[0]*neutron->v[0] + neutron->v[2]*neutron->v[2]; - term1 = term1/divisor + square(term2/divisor); - if ( term1>0){ - term2 = neutron->r[0]*neutron->v[0] + neutron->r[2]*neutron->v[2]; - - temp_t = sqrt(term1)-term2/divisor; - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); - temp_t = -sqrt(term1)-term2/divisor; - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); - } - term1 = mono->radius_outer * mono->radius_outer - - neutron->r[0] * neutron->r[0] - - neutron->r[2] * neutron->r[2]; + temp_t = sqrt(term1) - term2 / divisor; + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + temp_t = -sqrt(term1) - term2 / divisor; + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + } + term1 = mono->radius_outer * mono->radius_outer - neutron->r[0] * neutron->r[0] - neutron->r[2] * neutron->r[2]; + term2 = neutron->r[0] * neutron->v[0] + neutron->r[2] * neutron->v[2]; + divisor = neutron->v[0] * neutron->v[0] + neutron->v[2] * neutron->v[2]; + term1 = term1 / divisor + square(term2 / divisor); + if (term1 > 0) + { term2 = neutron->r[0] * neutron->v[0] + neutron->r[2] * neutron->v[2]; - divisor = neutron->v[0] * neutron->v[0] + neutron->v[2] * neutron->v[2]; - term1 = term1/divisor + square(term2/divisor); - if ( term1>0){ - term2 = neutron->r[0]*neutron->v[0] + neutron->r[2]*neutron->v[2]; - temp_t = sqrt(term1)-term2/divisor; - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); - temp_t = -sqrt(term1)-term2/divisor; - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); + temp_t = sqrt(term1) - term2 / divisor; + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + temp_t = -sqrt(term1) - term2 / divisor; + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + } + // Find intersections with the flat top and bottom planes. + temp_t = (mono->height - neutron->r[1]) / neutron->v[1]; + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + temp_t = (-mono->height - neutron->r[1]) / neutron->v[1]; + check_intersection_and_update_times(t1, t2, &temp_t, neutron, mono); + if (*t1 > 0) + return 2; + if (*t2 > 0) + return 1; + return 0; +} +/////////////////////////////////////////////////////////////////////////// +// Function for transforming coordinates into local crystal coordinates. +// Difference between rotate point and coordinate transformation +// is that the one only acts on a point, and the other on a neutron +/////////////////////////////////////////////////////////////////////////// + +void Coordinate_transformation(struct neutron_values *neutron, + struct Monochromator_values *mono) +{ + // Now rotate the neutron, in the crystal coordinate system + // such that the flat of the crystal is aligned with the z-axis. + // Rotations are around first x then y then z. + double new_v[3] = {0, 0, 0}; + double new_r[3] = {0, 0, 0}; + // First translate, then rotate the neutron + double neutron_r[3] = {neutron->r[0] - mono->x, + neutron->r[1] - mono->y, + neutron->r[2] - mono->z}; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + new_r[i] += mono->rotation_matrices[i][j] * neutron_r[j]; + new_v[i] += mono->rotation_matrices[i][j] * neutron->v[j]; } - - // Find intersections with the flat top and bottom planes. - temp_t = (mono->height-neutron->r[1])/ neutron->v[1]; - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); - temp_t = (-mono->height-neutron->r[1])/ neutron->v[1]; - check_intersection_and_update_times(t1,t2,&temp_t, neutron, mono); - if (*t1>0) return 2; - if (*t2>0) return 1; - return 0; - } - /////////////////////////////////////////////////////////////////////////// - // Function for transforming coordinates into local crystal coordinates. - // Difference between rotate point and coordinate transformation - // is that the one only acts on a point, and the other on a neutron - /////////////////////////////////////////////////////////////////////////// - - void Coordinate_transformation(struct neutron_values* neutron, - struct Monochromator_values* mono){ - // Now rotate the neutron, in the crystal coordinate system - // such that the flat of the crystal is aligned with the z-axis. - // Rotations are around first x then y then z. - double new_v[3] = {0,0,0}; - double new_r[3] = {0,0,0}; - // First translate, then rotate the neutron - double neutron_r[3] = {neutron->r[0] - mono->x, - neutron->r[1] - mono->y, - neutron->r[2] - mono->z}; - for (int i = 0; i<3; i++){ - for (int j = 0; j<3; j++){ - new_r[i] += mono->rotation_matrices[i][j]*neutron_r[j]; - new_v[i] += mono->rotation_matrices[i][j]*neutron->v[j]; - } - } - // Set the neutrons values to be these new ones - // and update the wavevector - for (int i =0; i<3; i++){ - neutron->r[i] = new_r[i]; - neutron->v[i] = new_v[i]; - neutron->ki[i] = neutron->v[i]*V2K; - } + // Set the neutrons values to be these new ones + // and update the wavevector + for (int i = 0; i < 3; i++) + { + neutron->r[i] = new_r[i]; + neutron->v[i] = new_v[i]; + neutron->ki[i] = neutron->v[i] * V2K; } - //////////////////////////////////////////////////////////////////////////// - // Functions for mcdisplay. It rotates, then moves the crystals - //////////////////////////////////////////////////////////////////////////// - - void rotate_point(double *point, - struct Monochromator_values *mono){ - double new_point[3]={0,0,0}; - // In order to not get the rotation matrix anew for each point, - // define it here and since this is a passive rotation of the crystal - // use the transposed matrix. - ; - double transp_mat[3][3]; - rot_transpose(mono->rotation_matrices,transp_mat); - for (int i = 0; i<3; i++){ - for (int j = 0; j<3; j++){ - new_point[i] += transp_mat[i][j]*point[j]; - // if (mono->verbosity){ - // printf("transp_mat[%d,%d]=%g\n", i,j,transp_mat[i][j]);} - } - } - point[0] = new_point[0] + mono->x; - point[1] = new_point[1] + mono->y; - point[2] = new_point[2] + mono->z; - } - - void rotate_all_points(double* x1, double* x2, - double* x3, double* x4, - double* y1, double* y2, - double* z1, double* z2, - double* z3, double* z4, - double p[][3], - struct Monochromator_values *mono){ - // First define the points of the first box - p[0][0] = *x1; p[0][1]=*y1; p[0][2]=*z1; - p[1][0] = *x1; p[1][1]=*y2; p[1][2]=*z1; - p[2][0] = *x2; p[2][1]=*y1; p[2][2]=*z2; - p[3][0] = *x2; p[3][1]=*y2; p[3][2]=*z2; - // // Now define the points of the second box - p[4][0] = *x3; p[4][1]=*y1; p[4][2]=*z3; - p[5][0] = *x3; p[5][1]=*y2; p[5][2]=*z3; - p[6][0] = *x4; p[6][1]=*y1; p[6][2]=*z4; - p[7][0] = *x4; p[7][1]=*y2; p[7][2]=*z4; - // Now Rotate all the points and perform their translation - for (int i = 0; i<8; i++){ - rotate_point(p[i], mono); +} +//////////////////////////////////////////////////////////////////////////// +// Functions for mcdisplay. It rotates, then moves the crystals +//////////////////////////////////////////////////////////////////////////// + +void rotate_point(double *point, + struct Monochromator_values *mono) +{ + double new_point[3] = {0, 0, 0}; + // In order to not get the rotation matrix anew for each point, + // define it here and since this is a passive rotation of the crystal + // use the transposed matrix. + ; + double transp_mat[3][3]; + rot_transpose(mono->rotation_matrices, transp_mat); + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + new_point[i] += transp_mat[i][j] * point[j]; + // if (mono->verbosity){ + // printf("transp_mat[%d,%d]=%g\n", i,j,transp_mat[i][j]);} } } - /////////////////////////////////////////////////////////////////////////// - // Function for sorting which crystal is intersected first. - /////////////////////////////////////////////////////////////////////////// - void sort_intersections(double* t, double* t1, int* l, struct neutron_values* neut){ - for (int i = 0; in; i++){ - - if (neut->entry_time[i]==0 && neut->exit_time[i]==0) { - // If t is the lates time, set it. - neut->entry_time[i] = *t; - neut->exit_time[i] = *t1; - neut->intersection_list[i] = *l; - break; - } - else if (*tentry_time[i]){ - //Move all the other times up one. - for (int j = neut->n-1; j>=i; j--){ - neut->entry_time[j] = neut->entry_time[j-1]; - neut->exit_time[j] = neut->exit_time[j-1]; - neut->intersection_list[j] = neut->intersection_list[j-1]; - } - neut->entry_time[i] = *t; - neut->exit_time[i] = *t1; - neut->intersection_list[i] = *l; - break; + point[0] = new_point[0] + mono->x; + point[1] = new_point[1] + mono->y; + point[2] = new_point[2] + mono->z; +} + +void rotate_all_points(double *x1, double *x2, + double *x3, double *x4, + double *y1, double *y2, + double *z1, double *z2, + double *z3, double *z4, + double p[][3], + struct Monochromator_values *mono) +{ + // First define the points of the first box + p[0][0] = *x1; + p[0][1] = *y1; + p[0][2] = *z1; + p[1][0] = *x1; + p[1][1] = *y2; + p[1][2] = *z1; + p[2][0] = *x2; + p[2][1] = *y1; + p[2][2] = *z2; + p[3][0] = *x2; + p[3][1] = *y2; + p[3][2] = *z2; + // // Now define the points of the second box + p[4][0] = *x3; + p[4][1] = *y1; + p[4][2] = *z3; + p[5][0] = *x3; + p[5][1] = *y2; + p[5][2] = *z3; + p[6][0] = *x4; + p[6][1] = *y1; + p[6][2] = *z4; + p[7][0] = *x4; + p[7][1] = *y2; + p[7][2] = *z4; + // Now Rotate all the points and perform their translation + for (int i = 0; i < 8; i++) + { + rotate_point(p[i], mono); + } +} +/////////////////////////////////////////////////////////////////////////// +// Function for sorting which crystal is intersected first. +/////////////////////////////////////////////////////////////////////////// +void sort_intersections(double *t, double *t1, int *l, struct neutron_values *neut) +{ + for (int i = 0; i < neut->n; i++) + { + + if (neut->entry_time[i] == 0 && neut->exit_time[i] == 0) + { + // If t is the lates time, set it. + neut->entry_time[i] = *t; + neut->exit_time[i] = *t1; + neut->intersection_list[i] = *l; + break; + } + else if (*t < neut->entry_time[i]) + { + // Move all the other times up one. + for (int j = neut->n - 1; j >= i; j--) + { + neut->entry_time[j] = neut->entry_time[j - 1]; + neut->exit_time[j] = neut->exit_time[j - 1]; + neut->intersection_list[j] = neut->intersection_list[j - 1]; } + neut->entry_time[i] = *t; + neut->exit_time[i] = *t1; + neut->intersection_list[i] = *l; + break; } } - /////////////////////////////////////////////////////////////////////////// - // Function for finding intersections with all the crystals in the array. - /////////////////////////////////////////////////////////////////////////// - void find_intersections(struct Monochromator_array* mono_arr, - struct neutron_values* neutron){ - - memset(neutron->intersection_list, -1, sizeof(int)*neutron->n); - memset(neutron->entry_time, 0, sizeof(double)*neutron->n); - memset(neutron->exit_time, 0, sizeof(double)*neutron->n); - memset(neutron->path_length, 0, sizeof(double)*neutron->n); - int intersects_bounding_box=0; - double t1, t2; - double temp1,temp2; - double position[3] = {neutron->r[0], neutron->r[1], neutron->r[2]}; - double speed[3] = {neutron->v[0], neutron->v[1], neutron->v[2]}; - double dx, dy, dz; - for (int i = 0; inumber_of_crystals; i++){ - if (mono_arr->verbosity){printf("Crystal %d out of %d is being processed for intersections\n", i,mono_arr->number_of_crystals );} - intersects_bounding_box=0; - dx = mono_arr->crystal[i].bounding_box_thickness; - dy = 2*mono_arr->crystal[i].height; - dz = mono_arr->crystal[i].length; - Coordinate_transformation(neutron, &mono_arr->crystal[i]); - // Before doing proper intersection, check if the neutron is in a bounding box - intersects_bounding_box = box_intersect(&temp1, &temp2, - neutron->r[0], neutron->r[1], neutron->r[2], - neutron->v[0], neutron->v[1], neutron->v[2], - dx, dy, dz); - if (intersects_bounding_box){ - if (mono_arr->verbosity){printf("Bounding box check survived\n");} - neutron->r[0] -= mono_arr->crystal[i].radius_horizontal; - cylinder_cut_out_intersect(&t1, &t2, neutron, &mono_arr->crystal[i]); - if (t1 >= 0 || t2 >= 0){ - // neutron intersects with crystal from outside of crystal - // If neutron starts inside crystal, set entry time to 0. - if (t1<0) {t1 = 0;} - sort_intersections(&t1, &t2, &i, neutron); - } +} +/////////////////////////////////////////////////////////////////////////// +// Function for finding intersections with all the crystals in the array. +/////////////////////////////////////////////////////////////////////////// +void find_intersections(struct Monochromator_array *mono_arr, + struct neutron_values *neutron) +{ + + memset(neutron->intersection_list, -1, sizeof(int) * neutron->n); + memset(neutron->entry_time, 0, sizeof(double) * neutron->n); + memset(neutron->exit_time, 0, sizeof(double) * neutron->n); + memset(neutron->path_length, 0, sizeof(double) * neutron->n); + int intersects_bounding_box = 0; + double t1, t2; + double temp1, temp2; + double position[3] = {neutron->r[0], neutron->r[1], neutron->r[2]}; + double speed[3] = {neutron->v[0], neutron->v[1], neutron->v[2]}; + double dx, dy, dz; + for (int i = 0; i < mono_arr->number_of_crystals; i++) + { + if (mono_arr->verbosity) + { + printf("Crystal %d out of %d is being processed for intersections\n", i, mono_arr->number_of_crystals); + } + intersects_bounding_box = 0; + dx = mono_arr->crystal[i].bounding_box_thickness; + dy = 2 * mono_arr->crystal[i].height; + dz = mono_arr->crystal[i].length; + Coordinate_transformation(neutron, &mono_arr->crystal[i]); + // Before doing proper intersection, check if the neutron is in a bounding box + intersects_bounding_box = box_intersect(&temp1, &temp2, + neutron->r[0], neutron->r[1], neutron->r[2], + neutron->v[0], neutron->v[1], neutron->v[2], + dx, dy, dz); + if (intersects_bounding_box) + { + if (mono_arr->verbosity) + { + printf("Bounding box check survived\n"); } - - for (int j = 0; j<3; j++){ - neutron->r[j] = position[j]; - neutron->v[j] = speed[j]; + neutron->r[0] -= mono_arr->crystal[i].radius_horizontal; + cylinder_cut_out_intersect(&t1, &t2, neutron, &mono_arr->crystal[i]); + if (t1 >= 0 || t2 >= 0) + { + // neutron intersects with crystal from outside of crystal + // If neutron starts inside crystal, set entry time to 0. + if (t1 < 0) + { + t1 = 0; + } + sort_intersections(&t1, &t2, &i, neutron); } } - // Find the number of intersections, and assign the path length through those crystals. - neutron->intersections = 0; - for (int i = 0; inumber_of_crystals; i++){ - if (neutron->intersection_list[i] == -1){break;} - neutron->intersections += 1; - neutron->path_length[i] = neutron->exit_time[i] - neutron->entry_time[i]; + + for (int j = 0; j < 3; j++) + { + neutron->r[j] = position[j]; + neutron->v[j] = speed[j]; } } - - /////////////////////////////////////////////////////////////////////////// - /////////////// B0 and BT are values used for the Debye factor - /////////////////////////////////////////////////////////////////////////// - void calculate_B0_and_BT(struct Monochromator_values *monochromator){ - double x; - monochromator->B0 = 2872.556/monochromator->atomic_number - /monochromator->debye_temperature; - - if (monochromator->temperature_mono>0.1) x = monochromator->debye_temperature - /monochromator->temperature_mono; - else x =monochromator->debye_temperature/0.1; - double phis = calculate_phi_integral(x); - - monochromator->BT = 4 * monochromator->B0 * phis / square(x); - } - - //////////////////////////////////////////////////////////////////////////// - /////////////// The kinematic reflectivity is calculated as in - /////////////// Zachariasen - //////////////////////////////////////////////////////////////////////////// - double calculate_kinematic_reflectivity(struct Monochromator_values* monochromator, - struct neutron_values* neutron){ - double sine_of_bragg_angle = neutron->wavelength/2/monochromator->lattice_spacing; - if (sine_of_bragg_angle>=1) return 0; // Only do first order reflections - double cosine_of_bragg_angle = sqrt(1-square(sine_of_bragg_angle)); - double extinction_length = monochromator->lattice_spacing - /neutron->wavelength - *sqrt(4*PI/monochromator->Maier_Leibnitz_reflectivity*100); - // Kinenatic reflectivity = QML*DHKL*sin(theta_B)**2/PI/cos(theta_B) [m⁻1] - double kinematic_reflectivity = monochromator->Maier_Leibnitz_reflectivity; - kinematic_reflectivity *= monochromator->lattice_spacing; - kinematic_reflectivity *= square(sine_of_bragg_angle); - kinematic_reflectivity *= 1/PI/cosine_of_bragg_angle; - kinematic_reflectivity *= monochromator->Debye_Waller_factor; - // Primary extinction factor, using the approximation - // in G.E Bacon and R.D. Lowde, Acta Cryst. (1948). 1, 303 - - kinematic_reflectivity *= tanh(monochromator->domain_thickness/extinction_length) - /monochromator->domain_thickness*extinction_length; - return kinematic_reflectivity; - } - - //////////////////////////////////////////////////////////////////////////// - /////////////// The actual calculations for the att coefficient - /////////////// See the citation for Freund higher up. - //////////////////////////////////////////////////////////////////////////// - double calculate_attenuation_coefficient(struct Monochromator_values* mono, - struct neutron_values* neutron){ - double E = square(neutron->v_size)*VS2E; // Neutron energy in meV - // Get factor for single phonon cross section - - double Bernoulli_sequence[31] = {1,-0.5,0.166667,0,-0.033333,0,0.0238095,0,-0.033333, - 0,0.0757576,0,-0.253114,0,1.16667,0,-7.09216,0,54.9712, - 0,-529.124,0,6192.12,0,-86580.3,0,1.42551717e6,0,-2.7298231e7, - 0,6.01580874e8}; - double x; - if (mono->temperature_mono - 0.1 <= 0){ - x = mono->debye_temperature/0.1; + // Find the number of intersections, and assign the path length through those crystals. + neutron->intersections = 0; + for (int i = 0; i < mono_arr->number_of_crystals; i++) + { + if (neutron->intersection_list[i] == -1) + { + break; } - else{ - x = mono->debye_temperature/mono->temperature_mono; - } - double R, Ifact, Xn; - if (x<6){ - R = 0; - Ifact = 1; - Xn = 1/x; - //JS: TODO, R may converge quickly, then the loop could be terminated sooner than after 31 steps - for (int i=0; i<30; i++){ - R += Bernoulli_sequence[i]*Xn/Ifact/(i + 2.5); - Xn *= x; - Ifact *= i + 1; - } + neutron->intersections += 1; + neutron->path_length[i] = neutron->exit_time[i] - neutron->entry_time[i]; + } +} + +/////////////////////////////////////////////////////////////////////////// +/////////////// B0 and BT are values used for the Debye factor +/////////////////////////////////////////////////////////////////////////// +void calculate_B0_and_BT(struct Monochromator_values *monochromator) +{ + double x; + monochromator->B0 = 2872.556 / monochromator->atomic_number / monochromator->debye_temperature; + + if (monochromator->temperature_mono > 0.1) + x = monochromator->debye_temperature / monochromator->temperature_mono; + else + x = monochromator->debye_temperature / 0.1; + double phis = calculate_phi_integral(x); + + monochromator->BT = 4 * monochromator->B0 * phis / square(x); +} + +//////////////////////////////////////////////////////////////////////////// +/////////////// The kinematic reflectivity is calculated as in +/////////////// Zachariasen +//////////////////////////////////////////////////////////////////////////// +double calculate_kinematic_reflectivity(struct Monochromator_values *monochromator, + struct neutron_values *neutron) +{ + double sine_of_bragg_angle = neutron->wavelength / 2 / monochromator->lattice_spacing; + if (sine_of_bragg_angle >= 1) + return 0; // Only do first order reflections + double cosine_of_bragg_angle = sqrt(1 - square(sine_of_bragg_angle)); + double extinction_length = monochromator->lattice_spacing / neutron->wavelength * sqrt(4 * PI / monochromator->Maier_Leibnitz_reflectivity * 100); + // Kinenatic reflectivity = QML*DHKL*sin(theta_B)**2/PI/cos(theta_B) [m⁻1] + double kinematic_reflectivity = monochromator->Maier_Leibnitz_reflectivity; + kinematic_reflectivity *= monochromator->lattice_spacing; + kinematic_reflectivity *= square(sine_of_bragg_angle); + kinematic_reflectivity *= 1 / PI / cosine_of_bragg_angle; + kinematic_reflectivity *= monochromator->Debye_Waller_factor; + // Primary extinction factor, using the approximation + // in G.E Bacon and R.D. Lowde, Acta Cryst. (1948). 1, 303 + + kinematic_reflectivity *= tanh(monochromator->domain_thickness / extinction_length) / monochromator->domain_thickness * extinction_length; + return kinematic_reflectivity; +} + +//////////////////////////////////////////////////////////////////////////// +/////////////// The actual calculations for the att coefficient +/////////////// See the citation for Freund higher up. +//////////////////////////////////////////////////////////////////////////// +double calculate_attenuation_coefficient(struct Monochromator_values *mono, + struct neutron_values *neutron) +{ + double E = square(neutron->v_size) * VS2E; // Neutron energy in meV + // Get factor for single phonon cross section + + double Bernoulli_sequence[31] = {1, -0.5, 0.166667, 0, -0.033333, 0, 0.0238095, 0, -0.033333, + 0, 0.0757576, 0, -0.253114, 0, 1.16667, 0, -7.09216, 0, 54.9712, + 0, -529.124, 0, 6192.12, 0, -86580.3, 0, 1.42551717e6, 0, -2.7298231e7, + 0, 6.01580874e8}; + double x; + if (mono->temperature_mono - 0.1 <= 0) + { + x = mono->debye_temperature / 0.1; + } + else + { + x = mono->debye_temperature / mono->temperature_mono; + } + double R, Ifact, Xn; + if (x < 6) + { + R = 0; + Ifact = 1; + Xn = 1 / x; + // JS: TODO, R may converge quickly, then the loop could be terminated sooner than after 31 steps + for (int i = 0; i < 30; i++) + { + R += Bernoulli_sequence[i] * Xn / Ifact / (i + 2.5); + Xn *= x; + Ifact *= i + 1; } - else R = 3.3/sqrt(x*x*x*x*x*x*x); + } + else + R = 3.3 / sqrt(x * x * x * x * x * x * x); // Define boltzmann_constant in units of (meV/K) - double boltzmann_constant = 0.08617333262; - double DWMF = 1-exp(-(mono->B0+mono->BT) - *mono->Constant_from_Freund_paper*E/1000); - // Factor 1000 is to convert Freund constant to meV + double boltzmann_constant = 0.08617333262; + double DWMF = 1 - exp(-(mono->B0 + mono->BT) * mono->Constant_from_Freund_paper * E / 1000); + // Factor 1000 is to convert Freund constant to meV // Set the cross sections, as written in freunds paper - mono->nuclear_capture_absorption = mono->incoherent_scattering_cross_section - +mono->absorption_for_1AA_Neutrons*neutron->wavelength; - - mono->multiple_phonon_absorption = mono->bound_atom_scattering_cross_section - *square(mono->atomic_number/(mono->atomic_number + 1)) - *DWMF; - - mono->single_phonon_absorption = 3*mono->bound_atom_scattering_cross_section/mono->atomic_number - * sqrt(boltzmann_constant * mono->debye_temperature/E) * R; - - double attenuation_coefficient = (mono->nuclear_capture_absorption - + mono->single_phonon_absorption - + mono->multiple_phonon_absorption) - /mono->volume; // [10^-28m^2/10^-30m^3] - attenuation_coefficient *= 100; // [m^-1] - return attenuation_coefficient; - } - /////////////////////////////////////////////////////////////////////////// - /////////////// Function that retrieves local scattering vector G or tau. - /////////////////////////////////////////////////////////////////////////// - void calculate_local_scattering_vector(struct Monochromator_values* mono, - struct neutron_values* neutron, int* crystal){ - double tau_temp[3] = {mono->tau[0], mono->tau[1], mono->tau[2]}; - - double size_of_in_plane_tau = sqrt(square(mono->tau[0]) - + square(mono->tau[2])); - for (int i=0 ; i<3; i++) { - tau_temp[i] += mono->lattice_spacing_gradient_field[i][0]*neutron->r[0] - +mono->lattice_spacing_gradient_field[i][1]*neutron->r[1] - +mono->lattice_spacing_gradient_field[i][2]*neutron->r[2]; - } - - double tau_size = sqrt(square(tau_temp[0]) - + square(tau_temp[1]) - + square(tau_temp[2])); - - // Add the angles of the mosaic block to the scattering vector - neutron->tau[0] = tau_temp[0] - + tau_temp[2]*neutron->horiz_angle[*crystal] - - mono->tau[1]*mono->tau[0]/size_of_in_plane_tau - * neutron->vert_angle[*crystal]; - neutron->tau[1] = tau_temp[1] + size_of_in_plane_tau *neutron->vert_angle[*crystal]; - neutron->tau[2] = tau_temp[2] - - tau_temp[0]*neutron->horiz_angle[*crystal] - - mono->tau[1]*mono->tau[2]/size_of_in_plane_tau - * neutron->vert_angle[*crystal]; - - // Renormalize local scat vect - double normalization_factor = tau_size - /sqrt(square(neutron->tau[0]) - + square(neutron->tau[1]) + square(neutron->tau[2])); - - neutron->tau[0] *= neutron->direction*normalization_factor; - neutron->tau[1] *= neutron->direction*normalization_factor; - neutron->tau[2] *= neutron->direction*normalization_factor; - } - //////////////////////////////////////////////////////////////////////////// - // Function that sets the neutron structs values at a point and speed - //////////////////////////////////////////////////////////////////////////// - void set_neutron_values( - struct neutron_values* neutron, - double x, double y, double z, - double vx, double vy, double vz){ - neutron->r[0] = x; - neutron->r[1] = y; - neutron->r[2] = z; - neutron->v[0] = vx; - neutron->v[1] = vy; - neutron->v[2] = vz; - neutron->v_size = 0; - neutron->ki_size = 0; - neutron->kf_size = 0; - for (int i =0; i<3; i++){ - neutron->ki[i] = neutron->v[i]*V2K; - neutron->ki_size += square(neutron->ki[i]); - neutron->v_size += square(neutron->v[i]); - } - - neutron->v_size = sqrt(neutron->v_size); - neutron->ki_size = sqrt(neutron->ki_size); - neutron->wavelength = 3956/neutron->v_size;// Wavelength in Angstrom. - } - //////////////////////////////////////////////////////////////////////////// - /////////////// Functions that find epsilon zero and beta. - //////////////////////////////////////////////////////////////////////////// - void calculate_epszero_and_beta(struct Monochromator_values* mono, - struct neutron_values* neutron, int lamella){ - // Update the final wavevector, as well as the size of the reciprocal lattice vector - neutron->tau_size = 0; - neutron->kf_size = 0; - for (int i=0; i<3; i++){ - neutron->kf[i] = neutron->ki[i] + neutron->tau[i]; - neutron->tau_size += square(neutron->tau[i]); - neutron->kf_size += square(neutron->kf[i]); - } + mono->nuclear_capture_absorption = mono->incoherent_scattering_cross_section + mono->absorption_for_1AA_Neutrons * neutron->wavelength; + + mono->multiple_phonon_absorption = mono->bound_atom_scattering_cross_section * square(mono->atomic_number / (mono->atomic_number + 1)) * DWMF; + + mono->single_phonon_absorption = 3 * mono->bound_atom_scattering_cross_section / mono->atomic_number * sqrt(boltzmann_constant * mono->debye_temperature / E) * R; + + double attenuation_coefficient = (mono->nuclear_capture_absorption + mono->single_phonon_absorption + mono->multiple_phonon_absorption) / mono->volume; // [10^-28m^2/10^-30m^3] + attenuation_coefficient *= 100; // [m^-1] + return attenuation_coefficient; +} +/////////////////////////////////////////////////////////////////////////// +/////////////// Function that retrieves local scattering vector G or tau. +/////////////////////////////////////////////////////////////////////////// +void calculate_local_scattering_vector(struct Monochromator_values *mono, + struct neutron_values *neutron, int *crystal) +{ + double tau_temp[3] = {mono->tau[0], mono->tau[1], mono->tau[2]}; + + double size_of_in_plane_tau = sqrt(square(mono->tau[0]) + square(mono->tau[2])); + for (int i = 0; i < 3; i++) + { + tau_temp[i] += mono->lattice_spacing_gradient_field[i][0] * neutron->r[0] + mono->lattice_spacing_gradient_field[i][1] * neutron->r[1] + mono->lattice_spacing_gradient_field[i][2] * neutron->r[2]; + } - neutron->tau_size = sqrt(neutron->tau_size); - neutron->kf_size = sqrt(neutron->kf_size); - double a = 0; - double b = 0; - // a is the numerator for the angular deviation of the bragg angle. - // a = (ki + tau_0 + tau*gamma)^2 - ki^2 - a = square(neutron->kf_size) - square(neutron->ki_size); - // b is the angle between k_i and tau, muktiplied by the size of each. - // b = tau*(ki + tau_0 + delta nabla tau * ki + k*gamma) - // But only the part that is along the - // direction of the mosaic angle, and therefore it becomes - // tau*k*cos(theta_b) in the paper. - b = neutron->direction*neutron->tau_size*(neutron->kf[0]*mono->perp_to_tau[0] - +neutron->kf[1]*mono->perp_to_tau[1] - +neutron->kf[2]*mono->perp_to_tau[2]); - - // Calculate the angular deviation from the Bragg condition - // eps_zero = - neutron->eps_zero[lamella] = -a/(2*b); - // Calculate gradient of the angular deviation - neutron->beta[lamella] = 0; - - for (int i = 0; i<3; i++){ - double z = 0; - for (int j = 0; j<3; j++){ - z += neutron->direction*mono->lattice_spacing_gradient_field[i][j] - *neutron->ki[j]; - } - neutron->beta[lamella] += (neutron->ki[i]+ mono->tau[i])*z; - } - neutron->beta[lamella] *= -1/b/neutron->ki_size; - // These definitions of beta and eps_zero exactly correspond to eq.4 of NIMA paper - } - //////////////////////////////////////////////////////////////////////////// - /////////////// Function that finds the probability - /////////////// that a neutron will reflect - //////////////////////////////////////////////////////////////////////////// - - void find_propability_of_reflection(struct Monochromator_values* mono, - struct neutron_values* neutron, int lamella){ - double kinematic_reflectivity = calculate_kinematic_reflectivity(mono, neutron); - if (mono->type==bent){ - // P = 1 - exp(-Q/(beta)) - neutron->probabilities[lamella] = 1 - exp(-kinematic_reflectivity - /fabs(neutron->beta[lamella])); - } - else if (mono->type==bent_mosaic){ - // P=1-e^[-Q/beta*(Phi[eps_0/eta + beta k delta/eta] - Phi[eps_0/eta])] - // arg1 = [eps_0/eta + beta k delta/eta] - double arg1 = (neutron->eps_zero[lamella] + - neutron->beta[lamella]*neutron->v_size - *neutron->path_length[lamella])/ - mono->mosaicity_horizontal; - // arg2 = [eps_0/eta] - double arg2 = neutron->eps_zero[lamella]/mono->mosaicity_horizontal; - neutron->probabilities[lamella] = 1-exp(-kinematic_reflectivity - /neutron->beta[lamella]* - (normalCDF(arg1, 1) - normalCDF(arg2, 1))); - } - } - - //////////////////////////////////////////////////////////////////////////// - /////////////// Simple function to choose the random angle of the mosaic - /////////////// block - //////////////////////////////////////////////////////////////////////////// - void choose_mosaic_block_angle(struct Monochromator_values* mono, - struct neutron_values* neutron, int* i, _class_particle* particle){ - if (mono->type==bent_mosaic){ - neutron->vert_angle[*i] = random_normal_distribution(&mono->mosaicity_vertical, particle); - neutron->horiz_angle[*i] = random_normal_distribution(&mono->mosaicity_horizontal, particle); - } - else { - neutron->vert_angle[*i] = 0; - neutron->horiz_angle[*i] = 0; - } + double tau_size = sqrt(square(tau_temp[0]) + square(tau_temp[1]) + square(tau_temp[2])); + + // Add the angles of the mosaic block to the scattering vector + neutron->tau[0] = tau_temp[0] + tau_temp[2] * neutron->horiz_angle[*crystal] - mono->tau[1] * mono->tau[0] / size_of_in_plane_tau * neutron->vert_angle[*crystal]; + neutron->tau[1] = tau_temp[1] + size_of_in_plane_tau * neutron->vert_angle[*crystal]; + neutron->tau[2] = tau_temp[2] - tau_temp[0] * neutron->horiz_angle[*crystal] - mono->tau[1] * mono->tau[2] / size_of_in_plane_tau * neutron->vert_angle[*crystal]; + + // Renormalize local scat vect + double normalization_factor = tau_size / sqrt(square(neutron->tau[0]) + square(neutron->tau[1]) + square(neutron->tau[2])); + + neutron->tau[0] *= neutron->direction * normalization_factor; + neutron->tau[1] *= neutron->direction * normalization_factor; + neutron->tau[2] *= neutron->direction * normalization_factor; +} +//////////////////////////////////////////////////////////////////////////// +// Function that sets the neutron structs values at a point and speed +//////////////////////////////////////////////////////////////////////////// +void set_neutron_values( + struct neutron_values *neutron, + double x, double y, double z, + double vx, double vy, double vz) +{ + neutron->r[0] = x; + neutron->r[1] = y; + neutron->r[2] = z; + neutron->v[0] = vx; + neutron->v[1] = vy; + neutron->v[2] = vz; + neutron->v_size = 0; + neutron->ki_size = 0; + neutron->kf_size = 0; + for (int i = 0; i < 3; i++) + { + neutron->ki[i] = neutron->v[i] * V2K; + neutron->ki_size += square(neutron->ki[i]); + neutron->v_size += square(neutron->v[i]); } - //=================================================================== - //===== FUNCTIONS TO MOVE NEUTRON IN MONOCHROMATOR COORDINATES ====== - //=================================================================== - void transport_neutron_to_crystal_coordinates(struct Monochromator_values* mono, - struct neutron_values* neutron, - int* lamella){ - neutron->r[0] += neutron->v[0]*neutron->entry_time[*lamella]; - neutron->r[1] += neutron->v[1]*neutron->entry_time[*lamella]; - neutron->r[2] += neutron->v[2]*neutron->entry_time[*lamella]; - Coordinate_transformation(neutron, mono); - } - - void propagate_neutrons_to_point_of_reflection(struct neutron_values* neutron){ - neutron->r[0] += neutron->v[0]*neutron->TOR; - neutron->r[1] += neutron->v[1]*neutron->TOR; - neutron->r[2] += neutron->v[2]*neutron->TOR; - } - - - // ========================================================================= - //============= START OF OVERVIEW FUNCTIONS CALLED FROM TRACE ============== - //========================================================================== - - void check_if_neutron_intersects(struct Monochromator_array* mono_arr, - struct neutron_values* neutron){ - if (mono_arr->verbosity){printf( - "Checking if neutron intersects with Monochromator\n");} - find_intersections(mono_arr, neutron); - if (neutron->entry_time[0] <0){ - if (mono_arr->verbosity) { - printf("!!! POSSIBLE ERROR AT MONOCHROMATOR_BENT!!! \n" - "Neutron enters the crystal at a negative time=%g", - neutron->entry_time[0]); - } - // Different setups may yield this error. - // The default behaviour is then to let the neutron pass through. - neutron->transmit_neutron = 1; - } - if (mono_arr->verbosity) { - for (int i = 0; i < neutron->intersections; i++){ - printf("Intersection %d: t=%g\n",i,neutron->entry_time[i]); - } - } + + neutron->v_size = sqrt(neutron->v_size); + neutron->ki_size = sqrt(neutron->ki_size); + neutron->wavelength = 3956 / neutron->v_size; // Wavelength in Angstrom. +} +//////////////////////////////////////////////////////////////////////////// +/////////////// Functions that find epsilon zero and beta. +//////////////////////////////////////////////////////////////////////////// +void calculate_epszero_and_beta(struct Monochromator_values *mono, + struct neutron_values *neutron, int lamella) +{ + // Update the final wavevector, as well as the size of the reciprocal lattice vector + neutron->tau_size = 0; + neutron->kf_size = 0; + for (int i = 0; i < 3; i++) + { + neutron->kf[i] = neutron->ki[i] + neutron->tau[i]; + neutron->tau_size += square(neutron->tau[i]); + neutron->kf_size += square(neutron->kf[i]); } - - // - // ========================================================================= - // - - void calculate_probabilities_of_reflection(struct Monochromator_array* mono_arr, - struct neutron_values* neutron, _class_particle* particle){ - - if (mono_arr->verbosity) {printf("Calculating probabilities of reflection\n");} - double position[3] = {neutron->r[0], neutron->r[1], neutron->r[2]}; - double speed[3] = {neutron->v[0], neutron->v[1], neutron->v[2]}; - for (int i = 0; i < neutron->intersections; i++){ - struct Monochromator_values* mono = &mono_arr->crystal[neutron->intersection_list[i]]; - - transport_neutron_to_crystal_coordinates(mono, neutron, &i); - choose_mosaic_block_angle(mono, neutron, &i, particle); - // It is necessary to calculate the local scattering vector and - // epszero and beta without any horizontal mosaicity, as per the equations. - double mos_temp = neutron->horiz_angle[i]; - neutron->horiz_angle[i] = 0; - calculate_local_scattering_vector(mono, neutron, &i); - calculate_epszero_and_beta(mono, neutron, i); - neutron->horiz_angle[i] = mos_temp; - find_propability_of_reflection(mono, neutron, i); - if (mono_arr->verbosity) {printf("Raw probability is %f\n", neutron->probabilities[i]);} - // Check if reflection would be inside the crystal - // It should only ever not be, when the mono is at 0 mosaicity - if (mono->type==bent){ - neutron->TOR = -neutron->eps_zero[i]/(neutron->ki_size*neutron->beta[i]); - neutron->TOR *= neutron->ki_size/neutron->v_size; - propagate_neutrons_to_point_of_reflection(neutron); - double transposed_x = neutron->r[0] - mono->radius_horizontal; - if (!neutron_is_inside_crystal(&transposed_x, &neutron->r[1], - &neutron->r[2], mono)) { - neutron->probabilities[i] = 0; - } - } - if (i==0 && mono->type==bent && neutron->reflections>0){ - neutron->probabilities[i] = 0; - // Don't allow double reflections in a perfect crystal - } - - if (i == 0){ - neutron->accu_probs[i] = neutron->probabilities[i]; - } else { - neutron->accu_probs[i] = 1 - (1-neutron->accu_probs[i-1])* - (1-neutron->probabilities[i]); - } - if (mono_arr->verbosity) { - printf("P(intersection %d)= %f\taccuP=%f\n", i, neutron->probabilities[i], - neutron->accu_probs[i]); - } - // Place neutron back to the original position - // wit the original speed and direction - for (int j = 0; j < 3; j++) { - neutron->r[j] = position[j]; - neutron->v[j] = speed[j]; - } + + neutron->tau_size = sqrt(neutron->tau_size); + neutron->kf_size = sqrt(neutron->kf_size); + double a = 0; + double b = 0; + // a is the numerator for the angular deviation of the bragg angle. + // a = (ki + tau_0 + tau*gamma)^2 - ki^2 + a = square(neutron->kf_size) - square(neutron->ki_size); + // b is the angle between k_i and tau, muktiplied by the size of each. + // b = tau*(ki + tau_0 + delta nabla tau * ki + k*gamma) + // But only the part that is along the + // direction of the mosaic angle, and therefore it becomes + // tau*k*cos(theta_b) in the paper. + b = neutron->direction * neutron->tau_size * (neutron->kf[0] * mono->perp_to_tau[0] + neutron->kf[1] * mono->perp_to_tau[1] + neutron->kf[2] * mono->perp_to_tau[2]); + + // Calculate the angular deviation from the Bragg condition + // eps_zero = + neutron->eps_zero[lamella] = -a / (2 * b); + // Calculate gradient of the angular deviation + neutron->beta[lamella] = 0; + + for (int i = 0; i < 3; i++) + { + double z = 0; + for (int j = 0; j < 3; j++) + { + z += neutron->direction * mono->lattice_spacing_gradient_field[i][j] * neutron->ki[j]; } + neutron->beta[lamella] += (neutron->ki[i] + mono->tau[i]) * z; + } + neutron->beta[lamella] *= -1 / b / neutron->ki_size; + // These definitions of beta and eps_zero exactly correspond to eq.4 of NIMA paper +} +//////////////////////////////////////////////////////////////////////////// +/////////////// Function that finds the probability +/////////////// that a neutron will reflect +//////////////////////////////////////////////////////////////////////////// + +void find_propability_of_reflection(struct Monochromator_values *mono, + struct neutron_values *neutron, int lamella) +{ + double kinematic_reflectivity = calculate_kinematic_reflectivity(mono, neutron); + if (mono->type == bent) + { + // P = 1 - exp(-Q/(beta)) + neutron->probabilities[lamella] = 1 - exp(-kinematic_reflectivity / fabs(neutron->beta[lamella])); + } + else if (mono->type == bent_mosaic) + { + // P=1-e^[-Q/beta*(Phi[eps_0/eta + beta k delta/eta] - Phi[eps_0/eta])] + // arg1 = [eps_0/eta + beta k delta/eta] + double arg1 = (neutron->eps_zero[lamella] + + neutron->beta[lamella] * neutron->v_size * neutron->path_length[lamella]) / + mono->mosaicity_horizontal; + // arg2 = [eps_0/eta] + double arg2 = neutron->eps_zero[lamella] / mono->mosaicity_horizontal; + neutron->probabilities[lamella] = 1 - exp(-kinematic_reflectivity / neutron->beta[lamella] * + (normalCDF(arg1, 1) - normalCDF(arg2, 1))); + } +} + +//////////////////////////////////////////////////////////////////////////// +/////////////// Simple function to choose the random angle of the mosaic +/////////////// block +//////////////////////////////////////////////////////////////////////////// +void choose_mosaic_block_angle(struct Monochromator_values *mono, + struct neutron_values *neutron, int *i, _class_particle *particle) +{ + if (mono->type == bent_mosaic) + { + neutron->vert_angle[*i] = random_normal_distribution(&mono->mosaicity_vertical, particle); + neutron->horiz_angle[*i] = random_normal_distribution(&mono->mosaicity_horizontal, particle); + } + else + { + neutron->vert_angle[*i] = 0; + neutron->horiz_angle[*i] = 0; } - - // - // ========================================================================= - // - - void choose_crystal_to_reflect_from(struct Monochromator_array* mono_arr, - struct neutron_values* neutron, - int* optimize, _class_particle* _particle){ - if (mono_arr->verbosity) { printf("Choosing crystal to reflect from\n");} - double reflect_condition; - if (neutron->direction>0 && *optimize){ - reflect_condition = neutron->accu_probs[neutron->intersections-1]*rand01(); - } else{ - reflect_condition = 1*rand01(); - } - neutron->chosen_crystal = 0; // The starting crystal is always 0. - // Find the crystal the neutron reflects from, or the - // final crystal the neutron is in. - while(neutron->accu_probs[neutron->chosen_crystal]<= reflect_condition - && neutron->chosen_crystal < neutron->intersections){ - neutron->chosen_crystal += 1; +} +//=================================================================== +//===== FUNCTIONS TO MOVE NEUTRON IN MONOCHROMATOR COORDINATES ====== +//=================================================================== +void transport_neutron_to_crystal_coordinates(struct Monochromator_values *mono, + struct neutron_values *neutron, + int *lamella) +{ + neutron->r[0] += neutron->v[0] * neutron->entry_time[*lamella]; + neutron->r[1] += neutron->v[1] * neutron->entry_time[*lamella]; + neutron->r[2] += neutron->v[2] * neutron->entry_time[*lamella]; + Coordinate_transformation(neutron, mono); +} + +void propagate_neutrons_to_point_of_reflection(struct neutron_values *neutron) +{ + neutron->r[0] += neutron->v[0] * neutron->TOR; + neutron->r[1] += neutron->v[1] * neutron->TOR; + neutron->r[2] += neutron->v[2] * neutron->TOR; +} + +// ========================================================================= +//============= START OF OVERVIEW FUNCTIONS CALLED FROM TRACE ============== +//========================================================================== + +void check_if_neutron_intersects(struct Monochromator_array *mono_arr, + struct neutron_values *neutron) +{ + if (mono_arr->verbosity) + { + printf( + "Checking if neutron intersects with Monochromator\n"); + } + find_intersections(mono_arr, neutron); + if (neutron->entry_time[0] < 0) + { + if (mono_arr->verbosity) + { + printf("!!! POSSIBLE ERROR AT MONOCHROMATOR_BENT!!! \n" + "Neutron enters the crystal at a negative time=%g", + neutron->entry_time[0]); } - if (mono_arr->verbosity) { - printf("Chosen crystal = %d\t at refcon=%g, accuprobs=%g\n", - neutron->chosen_crystal, reflect_condition, - neutron->accu_probs[neutron->chosen_crystal]); + // Different setups may yield this error. + // The default behaviour is then to let the neutron pass through. + neutron->transmit_neutron = 1; + } + if (mono_arr->verbosity) + { + for (int i = 0; i < neutron->intersections; i++) + { + printf("Intersection %d: t=%g\n", i, neutron->entry_time[i]); } - } +} - // - // ========================================================================= - // +// +// ========================================================================= +// - void check_if_neutron_should_pass_through(struct Monochromator_array* mono_arr, - struct neutron_values* neutron, - double* weight, double* weight_init){ - if (mono_arr->verbosity) {printf("Checking if neutron should pass through\n");} - if (neutron->chosen_crystal == neutron->intersections) { - neutron->transmit_neutron = 1; - neutron->chosen_crystal -=1; - } - else if (*weight*neutron->accu_probs[neutron->chosen_crystal]/ *weight_init - < 1e-3){ - neutron->transmit_neutron = 1; +void calculate_probabilities_of_reflection(struct Monochromator_array *mono_arr, + struct neutron_values *neutron, _class_particle *particle) +{ + + if (mono_arr->verbosity) + { + printf("Calculating probabilities of reflection\n"); + } + double position[3] = {neutron->r[0], neutron->r[1], neutron->r[2]}; + double speed[3] = {neutron->v[0], neutron->v[1], neutron->v[2]}; + for (int i = 0; i < neutron->intersections; i++) + { + struct Monochromator_values *mono = &mono_arr->crystal[neutron->intersection_list[i]]; + + transport_neutron_to_crystal_coordinates(mono, neutron, &i); + choose_mosaic_block_angle(mono, neutron, &i, particle); + // It is necessary to calculate the local scattering vector and + // epszero and beta without any horizontal mosaicity, as per the equations. + double mos_temp = neutron->horiz_angle[i]; + neutron->horiz_angle[i] = 0; + calculate_local_scattering_vector(mono, neutron, &i); + calculate_epszero_and_beta(mono, neutron, i); + neutron->horiz_angle[i] = mos_temp; + find_propability_of_reflection(mono, neutron, i); + if (mono_arr->verbosity) + { + printf("Raw probability is %f\n", neutron->probabilities[i]); } - if (mono_arr->verbosity && neutron->transmit_neutron) { - printf("Neutron has not reflected\n");} - } - - // - // ========================================================================= - // - - void sample_reflection_time(struct Monochromator_array* mono_arr, struct neutron_values* neutron, - _class_particle* _particle){ - if (mono_arr->verbosity){printf("Sampling reflection time\n");} - int crystal = neutron->chosen_crystal; - struct Monochromator_values* mono = &mono_arr->crystal[neutron->intersection_list[crystal]]; - if (mono->type==bent){ - // Note: This equation can also be solved precisely as a - // quadratic equation in Bragg's law. - neutron->TOR = -neutron->eps_zero[crystal]/(neutron->ki_size*neutron->beta[crystal]); - } - else if (mono->type==bent_mosaic){ - double kinematic_reflectivity = calculate_kinematic_reflectivity(mono, neutron); - // TOR = eta/k/beta * Phi^-1 [Phi(eps_0/eta) - - // beta/Q * ln(1-ksi*P(delta_n))] - eps_0/k/beta - // arg1 = eps_0/eta - double arg1 = neutron->eps_zero[crystal]/mono->mosaicity_horizontal; - // log_result = ln(1-ksi*P(delta_n)) - // Done like this to ensure type safety - double log_arg = 1-rand01()*neutron->probabilities[crystal]; - double log_result = (double) log((double) log_arg); - // arg2 = beta/Q * ln(1-ksi*P(delta_n)) - double arg2 = neutron->beta[crystal]/kinematic_reflectivity*log_result; - neutron->TOR = inverseNormalCDF(normalCDF(arg1, 1) - arg2, 1); - neutron->TOR *= mono->mosaicity_horizontal; - neutron->TOR -= neutron->eps_zero[crystal]; - neutron->TOR *= 1/neutron->beta[crystal]/neutron->ki_size; - } - neutron->TOR *= neutron->ki_size/neutron->v_size; - transport_neutron_to_crystal_coordinates(mono, neutron, &crystal); - propagate_neutrons_to_point_of_reflection(neutron); - double transposed_x = neutron->r[0] - mono->radius_horizontal; - // Check if the neutron is in the monochromator. + // Check if reflection would be inside the crystal // It should only ever not be, when the mono is at 0 mosaicity - // at the point of reflection - if (!neutron_is_inside_crystal(&transposed_x, &neutron->r[1], - &neutron->r[2], mono)) { - if (mono_arr->verbosity) {printf("ERROR: THE FOUND REFLECTION IS NOT INSIDE CRYSTAL.\n");} - neutron->transmit_neutron = 1; + if (mono->type == bent) + { + neutron->TOR = -neutron->eps_zero[i] / (neutron->ki_size * neutron->beta[i]); + neutron->TOR *= neutron->ki_size / neutron->v_size; + propagate_neutrons_to_point_of_reflection(neutron); + double transposed_x = neutron->r[0] - mono->radius_horizontal; + if (!neutron_is_inside_crystal(&transposed_x, &neutron->r[1], + &neutron->r[2], mono)) + { + neutron->probabilities[i] = 0; + } } - if (mono_arr->verbosity) {printf("TOR = %g\n", neutron->TOR);} - - } - - // - // ========================================================================= - // - - void reflect_neutron(struct Monochromator_array* mono_arr, - struct neutron_values* neutron, - double* speed_x, double* speed_y, double* speed_z, - double* weight, int* optimize){ - if (mono_arr->verbosity) {printf("Reflecting neutron\n");} - int crystal = neutron->chosen_crystal; - struct Monochromator_values* mono = &mono_arr->crystal[neutron->intersection_list[crystal]]; - double calculated_epsilon = neutron->eps_zero[crystal] + - neutron->beta[crystal]*neutron->TOR*neutron->v_size; - neutron->horiz_angle[crystal] = calculated_epsilon; - calculate_local_scattering_vector(mono, neutron, &crystal); - - *speed_x = (neutron->ki[0] + neutron->tau[0]); - *speed_y = (neutron->ki[1] + neutron->tau[1]); - *speed_z = (neutron->ki[2] + neutron->tau[2]); - // Rotate the speed vector back into the original coordinate system from the crystal coordinates system - double new_v[3] = {0,0,0}; - double transp_mat[3][3]; - rot_transpose(mono->rotation_matrices,transp_mat); - for (int i = 0; i<3; i++){ - new_v[i] += transp_mat[i][0]* *speed_x; - new_v[i] += transp_mat[i][1]* *speed_y; - new_v[i] += transp_mat[i][2]* *speed_z; + if (i == 0 && mono->type == bent && neutron->reflections > 0) + { + neutron->probabilities[i] = 0; + // Don't allow double reflections in a perfect crystal } - *speed_x = new_v[0]; - *speed_y = new_v[1]; - *speed_z = new_v[2]; - - // Renormalize the neutron as we are adding a - // reciprocal lattice vector with a changing - // lattice spacing across the crystal - double v_size = sqrt(square(*speed_x) + square(*speed_y) + square(*speed_z)); - *speed_x *= neutron->ki_size/v_size*K2V; - *speed_y *= neutron->ki_size/v_size*K2V; - *speed_z *= neutron->ki_size/v_size*K2V; - - - if (neutron->direction>0 && *optimize){ - if (mono_arr->verbosity) {printf("p*=%g \n", neutron->accu_probs[neutron->intersections-1]);} - *weight *= neutron->accu_probs[neutron->intersections-1]; + if (i == 0) + { + neutron->accu_probs[i] = neutron->probabilities[i]; } - - for (int i = 0; ichosen_crystal; i++){ - neutron->path += neutron->path_length[i]; - } - neutron->path += neutron->TOR; - neutron->direction *= -1; - neutron->reflections += 1; - } - - // - // ========================================================================= - // - - void find_new_intersections(struct Monochromator_array* mono_arr, - struct neutron_values* neutron){ - if (mono_arr->verbosity) {printf("Finding new intersections\n");} - find_intersections(mono_arr, neutron); - if (mono_arr->verbosity) { - for (int i = 0; i < neutron->intersections; i++){ - printf("Intersection %d: t=%g\n",i,neutron->entry_time[i]); - } + else + { + neutron->accu_probs[i] = 1 - (1 - neutron->accu_probs[i - 1]) * + (1 - neutron->probabilities[i]); + } + if (mono_arr->verbosity) + { + printf("P(intersection %d)= %f\taccuP=%f\n", i, neutron->probabilities[i], + neutron->accu_probs[i]); + } + // Place neutron back to the original position + // wit the original speed and direction + for (int j = 0; j < 3; j++) + { + neutron->r[j] = position[j]; + neutron->v[j] = speed[j]; } } - - // - // ========================================================================= - // - - void attenuate_neutron(struct Monochromator_array* mono_arr, - struct neutron_values* neutron, - double* p){ - if (mono_arr->verbosity) {printf("Attenuating neutron\n");} - if (neutron->transmit_neutron == 1){ - for (int i = 0; i < neutron->intersections; i++){ - neutron->path += neutron->path_length[i]; - } +} + +// +// ========================================================================= +// + +void choose_crystal_to_reflect_from(struct Monochromator_array *mono_arr, + struct neutron_values *neutron, + int *optimize, _class_particle *_particle) +{ + if (mono_arr->verbosity) + { + printf("Choosing crystal to reflect from\n"); + } + double reflect_condition; + if (neutron->direction > 0 && *optimize) + { + reflect_condition = neutron->accu_probs[neutron->intersections - 1] * rand01(); + } + else + { + reflect_condition = 1 * rand01(); + } + neutron->chosen_crystal = 0; // The starting crystal is always 0. + // Find the crystal the neutron reflects from, or the + // final crystal the neutron is in. + while (neutron->accu_probs[neutron->chosen_crystal] <= reflect_condition && neutron->chosen_crystal < neutron->intersections) + { + neutron->chosen_crystal += 1; + } + if (mono_arr->verbosity) + { + printf("Chosen crystal = %d\t at refcon=%g, accuprobs=%g\n", + neutron->chosen_crystal, reflect_condition, + neutron->accu_probs[neutron->chosen_crystal]); + } +} + +// +// ========================================================================= +// + +void check_if_neutron_should_pass_through(struct Monochromator_array *mono_arr, + struct neutron_values *neutron, + double *weight, double *weight_init) +{ + if (mono_arr->verbosity) + { + printf("Checking if neutron should pass through\n"); + } + if (neutron->chosen_crystal == neutron->intersections) + { + neutron->transmit_neutron = 1; + neutron->chosen_crystal -= 1; + } + else if (*weight * neutron->accu_probs[neutron->chosen_crystal] / *weight_init < 1e-3) + { + neutron->transmit_neutron = 1; + } + if (mono_arr->verbosity && neutron->transmit_neutron) + { + printf("Neutron has not reflected\n"); + } +} + +// +// ========================================================================= +// + +void sample_reflection_time(struct Monochromator_array *mono_arr, struct neutron_values *neutron, + _class_particle *_particle) +{ + if (mono_arr->verbosity) + { + printf("Sampling reflection time\n"); + } + int crystal = neutron->chosen_crystal; + struct Monochromator_values *mono = &mono_arr->crystal[neutron->intersection_list[crystal]]; + if (mono->type == bent) + { + // Note: This equation can also be solved precisely as a + // quadratic equation in Bragg's law. + neutron->TOR = -neutron->eps_zero[crystal] / (neutron->ki_size * neutron->beta[crystal]); + } + else if (mono->type == bent_mosaic) + { + double kinematic_reflectivity = calculate_kinematic_reflectivity(mono, neutron); + // TOR = eta/k/beta * Phi^-1 [Phi(eps_0/eta) - + // beta/Q * ln(1-ksi*P(delta_n))] - eps_0/k/beta + // arg1 = eps_0/eta + double arg1 = neutron->eps_zero[crystal] / mono->mosaicity_horizontal; + // log_result = ln(1-ksi*P(delta_n)) + // Done like this to ensure type safety + double log_arg = 1 - rand01() * neutron->probabilities[crystal]; + double log_result = (double)log((double)log_arg); + // arg2 = beta/Q * ln(1-ksi*P(delta_n)) + double arg2 = neutron->beta[crystal] / kinematic_reflectivity * log_result; + neutron->TOR = inverseNormalCDF(normalCDF(arg1, 1) - arg2, 1); + neutron->TOR *= mono->mosaicity_horizontal; + neutron->TOR -= neutron->eps_zero[crystal]; + neutron->TOR *= 1 / neutron->beta[crystal] / neutron->ki_size; + } + neutron->TOR *= neutron->ki_size / neutron->v_size; + transport_neutron_to_crystal_coordinates(mono, neutron, &crystal); + propagate_neutrons_to_point_of_reflection(neutron); + double transposed_x = neutron->r[0] - mono->radius_horizontal; + // Check if the neutron is in the monochromator. + // It should only ever not be, when the mono is at 0 mosaicity + // at the point of reflection + if (!neutron_is_inside_crystal(&transposed_x, &neutron->r[1], + &neutron->r[2], mono)) + { + if (mono_arr->verbosity) + { + printf("ERROR: THE FOUND REFLECTION IS NOT INSIDE CRYSTAL.\n"); } - double attenuation_coefficient = calculate_attenuation_coefficient(&mono_arr->crystal[0], neutron); - // TODO: This attenuation does not support multiple different crystals in the array. - // It is not currently the use case, and therefore we will live with it. - *p *= exp(-attenuation_coefficient*neutron->path*neutron->v_size); + neutron->transmit_neutron = 1; } + if (mono_arr->verbosity) + { + printf("TOR = %g\n", neutron->TOR); + } +} + +// +// ========================================================================= +// + +void reflect_neutron(struct Monochromator_array *mono_arr, + struct neutron_values *neutron, + double *speed_x, double *speed_y, double *speed_z, + double *weight, int *optimize) +{ + if (mono_arr->verbosity) + { + printf("Reflecting neutron\n"); + } + int crystal = neutron->chosen_crystal; + struct Monochromator_values *mono = &mono_arr->crystal[neutron->intersection_list[crystal]]; + double calculated_epsilon = neutron->eps_zero[crystal] + + neutron->beta[crystal] * neutron->TOR * neutron->v_size; + neutron->horiz_angle[crystal] = calculated_epsilon; + calculate_local_scattering_vector(mono, neutron, &crystal); + + *speed_x = (neutron->ki[0] + neutron->tau[0]); + *speed_y = (neutron->ki[1] + neutron->tau[1]); + *speed_z = (neutron->ki[2] + neutron->tau[2]); + // Rotate the speed vector back into the original coordinate system from the crystal coordinates system + double new_v[3] = {0, 0, 0}; + double transp_mat[3][3]; + rot_transpose(mono->rotation_matrices, transp_mat); + for (int i = 0; i < 3; i++) + { + new_v[i] += transp_mat[i][0] * *speed_x; + new_v[i] += transp_mat[i][1] * *speed_y; + new_v[i] += transp_mat[i][2] * *speed_z; + } + *speed_x = new_v[0]; + *speed_y = new_v[1]; + *speed_z = new_v[2]; + + // Renormalize the neutron as we are adding a + // reciprocal lattice vector with a changing + // lattice spacing across the crystal + + double v_size = sqrt(square(*speed_x) + square(*speed_y) + square(*speed_z)); + *speed_x *= neutron->ki_size / v_size * K2V; + *speed_y *= neutron->ki_size / v_size * K2V; + *speed_z *= neutron->ki_size / v_size * K2V; + + if (neutron->direction > 0 && *optimize) + { + if (mono_arr->verbosity) + { + printf("p*=%g \n", neutron->accu_probs[neutron->intersections - 1]); + } + *weight *= neutron->accu_probs[neutron->intersections - 1]; + } + + for (int i = 0; i < neutron->chosen_crystal; i++) + { + neutron->path += neutron->path_length[i]; + } + neutron->path += neutron->TOR; + neutron->direction *= -1; + neutron->reflections += 1; +} + +// +// ========================================================================= +// + +void find_new_intersections(struct Monochromator_array *mono_arr, + struct neutron_values *neutron) +{ + if (mono_arr->verbosity) + { + printf("Finding new intersections\n"); + } + find_intersections(mono_arr, neutron); + if (mono_arr->verbosity) + { + for (int i = 0; i < neutron->intersections; i++) + { + printf("Intersection %d: t=%g\n", i, neutron->entry_time[i]); + } + } +} + +// +// ========================================================================= +// + +void attenuate_neutron(struct Monochromator_array *mono_arr, + struct neutron_values *neutron, + double *p) +{ + if (mono_arr->verbosity) + { + printf("Attenuating neutron\n"); + } + if (neutron->transmit_neutron == 1) + { + for (int i = 0; i < neutron->intersections; i++) + { + neutron->path += neutron->path_length[i]; + } + } + double attenuation_coefficient = calculate_attenuation_coefficient(&mono_arr->crystal[0], neutron); + // TODO: This attenuation does not support multiple different crystals in the array. + // It is not currently the use case, and therefore we will live with it. + *p *= exp(-attenuation_coefficient * neutron->path * neutron->v_size); +} %} DECLARE %{ - int counter; - int counter2; - double curvature; - int MAX_REFLECTIONS; +int counter; +int counter2; +double curvature; +int MAX_REFLECTIONS; - struct neutron_values neutron; - struct Monochromator_array mono_arr; +struct neutron_values neutron; +struct Monochromator_array mono_arr; %} INITIALIZE %{ - /////////////////////////////////////////////////////////////////////////// - /////////////// ERROR FUNCTIONS - /////////////////////////////////////////////////////////////////////////// - if (xthickness <= 0) - exit(printf("Monochromator_Bent: %s: " - "invalid monochromator xthickness=%g\n", NAME_CURRENT_COMP, xthickness)); - if (zwidth <= 0) - exit(printf("Monochromator_Bent: %s: " - "invalid monochromator zwidth=%g\n", NAME_CURRENT_COMP, zwidth)); - if (yheight <= 0) - exit(printf("Monochromator_Bent: %s: " - "invalid monochromator yheight=%g\n", NAME_CURRENT_COMP, yheight)); - - int x_pos_mem_flag = 0; - int y_pos_mem_flag = 0; - int z_pos_mem_flag = 0; - int x_rot_mem_flag = 0; - int y_rot_mem_flag = 0; - int z_rot_mem_flag = 0; - double *temp = calloc(n_crystals, sizeof(double)); - if (!x_pos){ - if (verbose) printf("X pos is not defined, using 0 as position\n"); - int x_pos_mem_flag = 1; - x_pos = calloc(n_crystals, sizeof(double)); - memcpy(x_pos, temp, n_crystals * sizeof(double)); - } - if (!y_pos){ - if (verbose) printf("Y pos is not defined, using 0 as position\n"); - int y_pos_mem_flag = 1; - y_pos = calloc(n_crystals, sizeof(double)); - memcpy(y_pos, temp, n_crystals * sizeof(double)); - } - if (!z_pos){ - if (verbose) printf("Z pos is not defined, using 0 as position\n"); - int z_pos_mem_flag = 1; - z_pos = calloc(n_crystals, sizeof(double)); - memcpy(z_pos, temp, n_crystals * sizeof(double)); - } - if (!x_rot){ - if (verbose) printf("X rot is not defined, using 0 as rotation\n"); - int x_rot_mem_flag = 1; - x_rot = calloc(n_crystals, sizeof(double)); - memcpy(x_rot, temp, n_crystals * sizeof(double)); - } - if (!y_rot){ - if (verbose) printf("Y rot is not defined, using 0 as rotation\n"); - int y_rot_mem_flag = 1; - y_rot = calloc(n_crystals, sizeof(double)); - memcpy(y_rot, temp, n_crystals * sizeof(double)); - } - if (!z_rot){ - if (verbose) printf("Z rot is not defined, using 0 as rotation\n"); - int z_rot_mem_flag = 1; - z_rot = calloc(n_crystals, sizeof(double)); - memcpy(z_rot, temp, n_crystals * sizeof(double)); - } +/////////////////////////////////////////////////////////////////////////// +/////////////// ERROR FUNCTIONS +/////////////////////////////////////////////////////////////////////////// +if (xthickness <= 0) + exit(printf("Monochromator_Bent: %s: " + "invalid monochromator xthickness=%g\n", + NAME_CURRENT_COMP, xthickness)); +if (zwidth <= 0) + exit(printf("Monochromator_Bent: %s: " + "invalid monochromator zwidth=%g\n", + NAME_CURRENT_COMP, zwidth)); +if (yheight <= 0) + exit(printf("Monochromator_Bent: %s: " + "invalid monochromator yheight=%g\n", + NAME_CURRENT_COMP, yheight)); + +int x_pos_mem_flag = 0; +int y_pos_mem_flag = 0; +int z_pos_mem_flag = 0; +int x_rot_mem_flag = 0; +int y_rot_mem_flag = 0; +int z_rot_mem_flag = 0; +double *temp = calloc(n_crystals, sizeof(double)); +if (!x_pos) +{ + if (verbose) + printf("X pos is not defined, using 0 as position\n"); + int x_pos_mem_flag = 1; + x_pos = calloc(n_crystals, sizeof(double)); + memcpy(x_pos, temp, n_crystals * sizeof(double)); +} +if (!y_pos) +{ + if (verbose) + printf("Y pos is not defined, using 0 as position\n"); + int y_pos_mem_flag = 1; + y_pos = calloc(n_crystals, sizeof(double)); + memcpy(y_pos, temp, n_crystals * sizeof(double)); +} +if (!z_pos) +{ + if (verbose) + printf("Z pos is not defined, using 0 as position\n"); + int z_pos_mem_flag = 1; + z_pos = calloc(n_crystals, sizeof(double)); + memcpy(z_pos, temp, n_crystals * sizeof(double)); +} +if (!x_rot) +{ + if (verbose) + printf("X rot is not defined, using 0 as rotation\n"); + int x_rot_mem_flag = 1; + x_rot = calloc(n_crystals, sizeof(double)); + memcpy(x_rot, temp, n_crystals * sizeof(double)); +} +if (!y_rot) +{ if (verbose) - for (int i=0;i<1;i++){ + printf("Y rot is not defined, using 0 as rotation\n"); + int y_rot_mem_flag = 1; + y_rot = calloc(n_crystals, sizeof(double)); + memcpy(y_rot, temp, n_crystals * sizeof(double)); +} +if (!z_rot) +{ + if (verbose) + printf("Z rot is not defined, using 0 as rotation\n"); + int z_rot_mem_flag = 1; + z_rot = calloc(n_crystals, sizeof(double)); + memcpy(z_rot, temp, n_crystals * sizeof(double)); +} +if (verbose) + for (int i = 0; i < 1; i++) + { printf("x,y,z,rot=(%g,%g,%g,%g,%g,%g)\n", - x_pos[i],y_pos[i],z_pos[i],x_rot[i],y_rot[i],z_rot[i]); - } - if (verbose){ - printf("Monochromator_Bent output: " - "Component name is %s:\n", NAME_CURRENT_COMP); - } - //////////////////////////////////////////////////////////////////////////// - /////////////// INITIALIZING PARAMETERS - //////////////////////////////////////////////////////////////////////////// - mono_arr.crystal = (struct Monochromator_values*) malloc(n_crystals * sizeof(struct Monochromator_values)); - mono_arr.number_of_crystals = n_crystals; // [#] - mono_arr.verbosity = verbose; // [#] - for (int i=0; i0){ - mono_arr.crystal[i].max_angle = PI + asin(zwidth/(2*radius_x)); - mono_arr.crystal[i].min_angle = PI - asin(zwidth/(2*radius_x)); - } else if (radius_x<0){ - mono_arr.crystal[i].max_angle = -asin(zwidth/(2*radius_x)); - mono_arr.crystal[i].min_angle = asin(zwidth/(2*radius_x)); - } - mono_arr.crystal[i].angle_range = mono_arr.crystal[i].max_angle - mono_arr.crystal[i].min_angle; - // Figure out the type of Monochromator - if (radius_x) mono_arr.crystal[i].type=bent; - if (mosaicity) mono_arr.crystal[i].type = mosaic; - if (mosaicity && radius_x) mono_arr.crystal[i].type = bent_mosaic; - if (!radius_x && !mosaicity) mono_arr.crystal[i].type = flat; - // Read the designated plane of reflection, for use in the Monochromator. - enum crystal_plane plane = stringToEnum((const char *)&plane_of_reflection); - // Set Monochromator values - mono_arr.crystal[i].length = zwidth; // [m] - mono_arr.crystal[i].height = yheight; // [m] - mono_arr.crystal[i].thickness = xthickness; // [m] - mono_arr.crystal[i].radius_horizontal = radius_x; // [m] - mono_arr.crystal[i].radius_vertical = radius_y; // [m] - mono_arr.crystal[i].radius_inner = fabs(mono_arr.crystal[i].radius_horizontal) - mono_arr.crystal[i].thickness/2; // [m] - mono_arr.crystal[i].radius_outer = fabs(mono_arr.crystal[i].radius_horizontal) + mono_arr.crystal[i].thickness/2; // [m] - double arrowheight = mono_arr.crystal[i].radius_outer*(1-cos(mono_arr.crystal[i].angle_range/2)); //sagita of circles - mono_arr.crystal[i].bounding_box_thickness = mono_arr.crystal[i].thickness + 2*arrowheight; - mono_arr.crystal[i].domain_thickness = domainthickness; // [] - mono_arr.crystal[i].temperature_mono = temperature; // [T] - mono_arr.crystal[i].lattice_spacing = crystal_table[plane][0]; // [A] - mono_arr.crystal[i].Maier_Leibnitz_reflectivity = crystal_table[plane][1]*100; // [A^-1 m^-1] - mono_arr.crystal[i].bound_atom_scattering_cross_section = crystal_table[plane][2]; // [barn] - mono_arr.crystal[i].absorption_for_1AA_Neutrons = crystal_table[plane][3];// [barn*A^-1] - mono_arr.crystal[i].incoherent_scattering_cross_section = crystal_table[plane][4];// [barn] - mono_arr.crystal[i].volume = crystal_table[plane][5]; // [A^-3] - mono_arr.crystal[i].atomic_number = crystal_table[plane][6]; // [#] - mono_arr.crystal[i].debye_temperature = crystal_table[plane][7]; // [K] - mono_arr.crystal[i].Constant_from_Freund_paper = crystal_table[plane][8]; //[A^-2 eV^-1] - mono_arr.crystal[i].poisson_ratio = crystal_table[plane][9]; // [] - calculate_B0_and_BT(&mono_arr.crystal[i]); - mono_arr.crystal[i].Debye_Waller_factor = exp(-(mono_arr.crystal[i].B0 + mono_arr.crystal[i].BT)/2/square(mono_arr.crystal[i].lattice_spacing)); - - mono_arr.crystal[i].x = x_pos[i]; - mono_arr.crystal[i].y = y_pos[i]; - mono_arr.crystal[i].z = z_pos[i]; - double xrot = x_rot[i] * DEG2RAD; - double yrot = y_rot[i] * DEG2RAD; - double zrot = z_rot[i] * DEG2RAD; - rot_set_rotation(mono_arr.crystal[i].rotation_matrices, xrot, yrot, zrot); - rot_set_rotation(mono_arr.crystal[i].neg_rotation_matrix, -xrot, -yrot, -zrot); - if (verbose){ - printf("%d'th crystal\nrot_x=%g\trot_y=%g\trot_z=%g\n" - "tr_x=%g\ttr_y=%g\ttr_z=%g\n",i, - x_rot[i], y_rot[i], z_rot[i], - x_pos[i], y_pos[i], z_pos[i] - ); - } + x_pos[i], y_pos[i], z_pos[i], x_rot[i], y_rot[i], z_rot[i]); + } +if (verbose) +{ + printf("Monochromator_Bent output: " + "Component name is %s:\n", + NAME_CURRENT_COMP); +} +//////////////////////////////////////////////////////////////////////////// +/////////////// INITIALIZING PARAMETERS +//////////////////////////////////////////////////////////////////////////// +mono_arr.crystal = (struct Monochromator_values *)malloc(n_crystals * sizeof(struct Monochromator_values)); +mono_arr.number_of_crystals = n_crystals; // [#] +mono_arr.verbosity = verbose; // [#] +for (int i = 0; i < n_crystals; i++) +{ + // // Initialize angles of the Monochromator + if (radius_x > 0) + { + mono_arr.crystal[i].max_angle = PI + asin(zwidth / (2 * radius_x)); + mono_arr.crystal[i].min_angle = PI - asin(zwidth / (2 * radius_x)); + } + else if (radius_x < 0) + { + mono_arr.crystal[i].max_angle = -asin(zwidth / (2 * radius_x)); + mono_arr.crystal[i].min_angle = asin(zwidth / (2 * radius_x)); + } + mono_arr.crystal[i].angle_range = mono_arr.crystal[i].max_angle - mono_arr.crystal[i].min_angle; + // Figure out the type of Monochromator + if (radius_x) + mono_arr.crystal[i].type = bent; + if (mosaicity) + mono_arr.crystal[i].type = mosaic; + if (mosaicity && radius_x) + mono_arr.crystal[i].type = bent_mosaic; + if (!radius_x && !mosaicity) + mono_arr.crystal[i].type = flat; + // Read the designated plane of reflection, for use in the Monochromator. + enum crystal_plane plane = stringToEnum((const char *)&plane_of_reflection); + // Set Monochromator values + mono_arr.crystal[i].length = zwidth; // [m] + mono_arr.crystal[i].height = yheight; // [m] + mono_arr.crystal[i].thickness = xthickness; // [m] + mono_arr.crystal[i].radius_horizontal = radius_x; // [m] + mono_arr.crystal[i].radius_vertical = radius_y; // [m] + mono_arr.crystal[i].radius_inner = fabs(mono_arr.crystal[i].radius_horizontal) - mono_arr.crystal[i].thickness / 2; // [m] + mono_arr.crystal[i].radius_outer = fabs(mono_arr.crystal[i].radius_horizontal) + mono_arr.crystal[i].thickness / 2; // [m] + double arrowheight = mono_arr.crystal[i].radius_outer * (1 - cos(mono_arr.crystal[i].angle_range / 2)); // sagita of circles + mono_arr.crystal[i].bounding_box_thickness = mono_arr.crystal[i].thickness + 2 * arrowheight; + mono_arr.crystal[i].domain_thickness = domainthickness; // [] + mono_arr.crystal[i].temperature_mono = temperature; // [T] + mono_arr.crystal[i].lattice_spacing = crystal_table[plane][0]; // [A] + mono_arr.crystal[i].Maier_Leibnitz_reflectivity = crystal_table[plane][1] * 100; // [A^-1 m^-1] + mono_arr.crystal[i].bound_atom_scattering_cross_section = crystal_table[plane][2]; // [barn] + mono_arr.crystal[i].absorption_for_1AA_Neutrons = crystal_table[plane][3]; // [barn*A^-1] + mono_arr.crystal[i].incoherent_scattering_cross_section = crystal_table[plane][4]; // [barn] + mono_arr.crystal[i].volume = crystal_table[plane][5]; // [A^-3] + mono_arr.crystal[i].atomic_number = crystal_table[plane][6]; // [#] + mono_arr.crystal[i].debye_temperature = crystal_table[plane][7]; // [K] + mono_arr.crystal[i].Constant_from_Freund_paper = crystal_table[plane][8]; //[A^-2 eV^-1] + mono_arr.crystal[i].poisson_ratio = crystal_table[plane][9]; // [] + calculate_B0_and_BT(&mono_arr.crystal[i]); + mono_arr.crystal[i].Debye_Waller_factor = exp(-(mono_arr.crystal[i].B0 + mono_arr.crystal[i].BT) / 2 / square(mono_arr.crystal[i].lattice_spacing)); + + mono_arr.crystal[i].x = x_pos[i]; + mono_arr.crystal[i].y = y_pos[i]; + mono_arr.crystal[i].z = z_pos[i]; + double xrot = x_rot[i] * DEG2RAD; + double yrot = y_rot[i] * DEG2RAD; + double zrot = z_rot[i] * DEG2RAD; + rot_set_rotation(mono_arr.crystal[i].rotation_matrices, xrot, yrot, zrot); + rot_set_rotation(mono_arr.crystal[i].neg_rotation_matrix, -xrot, -yrot, -zrot); + if (verbose) + { + printf("%d'th crystal\nrot_x=%g\trot_y=%g\trot_z=%g\n" + "tr_x=%g\ttr_y=%g\ttr_z=%g\n", + i, + x_rot[i], y_rot[i], z_rot[i], + x_pos[i], y_pos[i], z_pos[i]); + } - - //Set the mosaicity if relevant - if (mono_arr.crystal[i].type == mosaic || mono_arr.crystal[i].type == bent_mosaic){ - //Input mosaicity is in arc min. Convert to Degrees and then to radians - // (And multiply with R8LN2 which I don't know what is). - // Is it because of input being fwhm instead of sigma? - double R8LN2 = 2.354820045; - mono_arr.crystal[i].mosaicity_horizontal = mosaicity/60*DEG2RAD/R8LN2; - mono_arr.crystal[i].mosaicity_vertical = mono_arr.crystal[i].mosaicity_horizontal*mosaic_anisotropy; - } - // Initialize reciprocal lattice vector G or tau in some texts, and perp_to_tau. - - double chi = angle_to_cut_horizontal*DEG2RAD; - - double tau_size_zero = 2*PI/mono_arr.crystal[i].lattice_spacing; - - mono_arr.crystal[i].tau[0] = tau_size_zero*cos(chi); - mono_arr.crystal[i].tau[1] = 0; - mono_arr.crystal[i].tau[2] = tau_size_zero*sin(chi); - - mono_arr.crystal[i].perp_to_tau[0] = sin(chi); - mono_arr.crystal[i].perp_to_tau[1] = 0; - mono_arr.crystal[i].perp_to_tau[2] = -cos(chi); - - // Initialize lattice_spacing_gradient_field - curvature = 1/mono_arr.crystal[i].radius_horizontal; - mono_arr.crystal[i].lattice_spacing_gradient_field[0][0] = -mono_arr.crystal[i].poisson_ratio*cos(chi)*tau_size_zero*curvature; - mono_arr.crystal[i].lattice_spacing_gradient_field[0][1] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[0][2] = sin(chi) - *tau_size_zero*curvature; - mono_arr.crystal[i].lattice_spacing_gradient_field[1][0] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[1][1] = mono_arr.crystal[i].radius_vertical!=0 ? tau_size_zero*cos(chi)/mono_arr.crystal[i].radius_vertical : 0;; - mono_arr.crystal[i].lattice_spacing_gradient_field[1][2] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[2][0] = sin(chi) - *tau_size_zero*curvature; - mono_arr.crystal[i].lattice_spacing_gradient_field[2][1] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[2][2] = -cos(chi) - *tau_size_zero*curvature; - } - - // Initialize neutron structs values - neutron.beta = (double*) calloc (n_crystals, sizeof(double)); - neutron.eps_zero = (double*) calloc (n_crystals, sizeof(double)); - neutron.vert_angle = (double*) calloc (n_crystals, sizeof(double)); - neutron.horiz_angle = (double*) calloc (n_crystals, sizeof(double)); - neutron.path_length = (double*) calloc (n_crystals, sizeof(double)); - neutron.entry_time = (double*) calloc (n_crystals, sizeof(double)); - neutron.exit_time = (double*) calloc (n_crystals, sizeof(double)); - neutron.probabilities = (double*) calloc (n_crystals, sizeof(double)); - neutron.accu_probs = (double*) calloc (n_crystals, sizeof(double)); - neutron.intersection_list = (int*) calloc (n_crystals, sizeof(int)); - neutron.n = n_crystals; - neutron.direction = 1; // Default direction is going away from the instrument - counter = 0; - counter2 = 0; - MAX_REFLECTIONS = 100; // Chosen maximum number of reflections - - // Free the position and rotations memories - if (x_pos_mem_flag) free(x_pos); - if (y_pos_mem_flag) free(y_pos); - if (z_pos_mem_flag) free(z_pos); - if (x_rot_mem_flag) free(x_rot); - if (y_rot_mem_flag) free(y_rot); - if (z_rot_mem_flag) free(z_rot); + // Set the mosaicity if relevant + if (mono_arr.crystal[i].type == mosaic || mono_arr.crystal[i].type == bent_mosaic) + { + // Input mosaicity is in arc min. Convert to Degrees and then to radians + // (And multiply with R8LN2 which I don't know what is). + // Is it because of input being fwhm instead of sigma? + double R8LN2 = 2.354820045; + mono_arr.crystal[i].mosaicity_horizontal = mosaicity / 60 * DEG2RAD / R8LN2; + mono_arr.crystal[i].mosaicity_vertical = mono_arr.crystal[i].mosaicity_horizontal * mosaic_anisotropy; + } + // Initialize reciprocal lattice vector G or tau in some texts, and perp_to_tau. + + double chi = angle_to_cut_horizontal * DEG2RAD; + + double tau_size_zero = 2 * PI / mono_arr.crystal[i].lattice_spacing; + + mono_arr.crystal[i].tau[0] = tau_size_zero * cos(chi); + mono_arr.crystal[i].tau[1] = 0; + mono_arr.crystal[i].tau[2] = tau_size_zero * sin(chi); + + mono_arr.crystal[i].perp_to_tau[0] = sin(chi); + mono_arr.crystal[i].perp_to_tau[1] = 0; + mono_arr.crystal[i].perp_to_tau[2] = -cos(chi); + + // Initialize lattice_spacing_gradient_field + curvature = 1 / mono_arr.crystal[i].radius_horizontal; + mono_arr.crystal[i].lattice_spacing_gradient_field[0][0] = -mono_arr.crystal[i].poisson_ratio * cos(chi) * tau_size_zero * curvature; + mono_arr.crystal[i].lattice_spacing_gradient_field[0][1] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[0][2] = sin(chi) * tau_size_zero * curvature; + mono_arr.crystal[i].lattice_spacing_gradient_field[1][0] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[1][1] = mono_arr.crystal[i].radius_vertical != 0 ? tau_size_zero * cos(chi) / mono_arr.crystal[i].radius_vertical : 0; + ; + mono_arr.crystal[i].lattice_spacing_gradient_field[1][2] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[2][0] = sin(chi) * tau_size_zero * curvature; + mono_arr.crystal[i].lattice_spacing_gradient_field[2][1] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[2][2] = -cos(chi) * tau_size_zero * curvature; +} + +// Initialize neutron structs values +neutron.beta = (double *)calloc(n_crystals, sizeof(double)); +neutron.eps_zero = (double *)calloc(n_crystals, sizeof(double)); +neutron.vert_angle = (double *)calloc(n_crystals, sizeof(double)); +neutron.horiz_angle = (double *)calloc(n_crystals, sizeof(double)); +neutron.path_length = (double *)calloc(n_crystals, sizeof(double)); +neutron.entry_time = (double *)calloc(n_crystals, sizeof(double)); +neutron.exit_time = (double *)calloc(n_crystals, sizeof(double)); +neutron.probabilities = (double *)calloc(n_crystals, sizeof(double)); +neutron.accu_probs = (double *)calloc(n_crystals, sizeof(double)); +neutron.intersection_list = (int *)calloc(n_crystals, sizeof(int)); +neutron.n = n_crystals; +neutron.direction = 1; // Default direction is going away from the instrument +counter = 0; +counter2 = 0; +MAX_REFLECTIONS = 100; // Chosen maximum number of reflections + +// Free the position and rotations memories +if (x_pos_mem_flag) + free(x_pos); +if (y_pos_mem_flag) + free(y_pos); +if (z_pos_mem_flag) + free(z_pos); +if (x_rot_mem_flag) + free(x_rot); +if (y_rot_mem_flag) + free(y_rot); +if (z_rot_mem_flag) + free(z_rot); %} TRACE %{ - // Initialize variables for use in TRACE - int final_reflection = 0; - neutron.path = 0; - neutron.reflections = 0; - int neutron_is_inside_crystal =1; - double weight_init = p; if (weight_init <= 0.0) ABSORB; - neutron.transmit_neutron = 0; - neutron.direction = 1; - set_neutron_values(&neutron, x,y,z,vx,vy,vz); - if (verbose){ - printf("\nNEW NEUTRON STARTED\n"); - } - check_if_neutron_intersects(&mono_arr, &neutron); - - while (neutron_is_inside_crystal){ - calculate_probabilities_of_reflection(&mono_arr, &neutron, _particle); - choose_crystal_to_reflect_from(&mono_arr, &neutron, &optimize, _particle); - check_if_neutron_should_pass_through(&mono_arr, &neutron, &p, &weight_init); - if (neutron.reflections>MAX_REFLECTIONS){neutron.transmit_neutron=1;} - if (neutron.transmit_neutron){break;} - final_reflection = neutron.chosen_crystal; - sample_reflection_time(&mono_arr, &neutron, _particle); - // Let neutron pass through if point of reflection is outside of crystal - if (neutron.transmit_neutron){break;} - PROP_DT(neutron.TOR+neutron.entry_time[neutron.chosen_crystal]); - SCATTER; - reflect_neutron(&mono_arr, &neutron, &vx, &vy, &vz, &p, &optimize); - set_neutron_values(&neutron, x,y,z,vx,vy,vz); // Update speeds and wavevectors - find_new_intersections(&mono_arr, &neutron); - } - attenuate_neutron(&mono_arr, &neutron, &p); - +// Initialize variables for use in TRACE +int final_reflection = 0; +neutron.path = 0; +neutron.reflections = 0; +int neutron_is_inside_crystal = 1; +double weight_init = p; +if (weight_init <= 0.0) + ABSORB; +neutron.transmit_neutron = 0; +neutron.direction = 1; +set_neutron_values(&neutron, x, y, z, vx, vy, vz); +if (verbose) +{ + printf("\nNEW NEUTRON STARTED\n"); +} +check_if_neutron_intersects(&mono_arr, &neutron); + +while (neutron_is_inside_crystal) +{ + calculate_probabilities_of_reflection(&mono_arr, &neutron, _particle); + choose_crystal_to_reflect_from(&mono_arr, &neutron, &optimize, _particle); + check_if_neutron_should_pass_through(&mono_arr, &neutron, &p, &weight_init); + if (neutron.reflections > MAX_REFLECTIONS) + { + neutron.transmit_neutron = 1; + } + if (neutron.transmit_neutron) + { + break; + } + final_reflection = neutron.chosen_crystal; + sample_reflection_time(&mono_arr, &neutron, _particle); + // Let neutron pass through if point of reflection is outside of crystal + if (neutron.transmit_neutron) + { + break; + } + PROP_DT(neutron.TOR + neutron.entry_time[neutron.chosen_crystal]); + SCATTER; + reflect_neutron(&mono_arr, &neutron, &vx, &vy, &vz, &p, &optimize); + set_neutron_values(&neutron, x, y, z, vx, vy, vz); // Update speeds and wavevectors + find_new_intersections(&mono_arr, &neutron); +} +attenuate_neutron(&mono_arr, &neutron, &p); %} FINALLY %{ - // Finally free the neutron - free(neutron.beta); - free(neutron.eps_zero); - free(neutron.vert_angle); - free(neutron.horiz_angle); - free(neutron.path_length); - free(neutron.entry_time); - free(neutron.exit_time); - free(neutron.probabilities); - free(neutron.accu_probs); - free(neutron.intersection_list); - - - free(mono_arr.crystal); +// Finally free the neutron +free(neutron.beta); +free(neutron.eps_zero); +free(neutron.vert_angle); +free(neutron.horiz_angle); +free(neutron.path_length); +free(neutron.entry_time); +free(neutron.exit_time); +free(neutron.probabilities); +free(neutron.accu_probs); +free(neutron.intersection_list); + +free(mono_arr.crystal); %} MCDISPLAY %{ - double x_inner [2]; - double x_outer [2]; - double y_top; - double y_bottom; - double z_inner [2]; - double z_outer [2]; - double points[8][3]; - // We draw the monochromator by drawing lines between chosen points. - // For this reason we need to move the points, - // in accordance to their position in the array. - for (int j=0; jradius_horizontal) - xthickness/2; - // double outer_radii = inner_radii + xthickness; - double angle0, angle1, movex, movey, movez; - y_top = yheight/2; - y_bottom = -yheight/2; - for (i = 0; i < max_i-0.2; i = i + 0.2) { - angle0 = i/max_i*mono->angle_range + mono->min_angle; - angle1 = (i+0.2)/max_i*mono->angle_range + mono->min_angle; - // Define the 8 coordinates of the n'th box in the crystal - x_inner[0] = (radius_x) + cos(angle0)*mono->radius_inner; - x_inner[1] = (radius_x) + cos(angle1)*mono->radius_inner; - - z_inner[0] = -sin(angle0)*mono->radius_inner; - z_inner[1] = -sin(angle1)*mono->radius_inner; - - x_outer[0] = (radius_x) + cos(angle0)*mono->radius_outer; - x_outer[1] = (radius_x) + cos(angle1)*mono->radius_outer; - - z_outer[0] = -sin(angle0)*mono->radius_outer; - z_outer[1] = -sin(angle1)*mono->radius_outer; - // These 8 coordinates define 8 points. Coordinate transform these - // to the current crystal - rotate_all_points(&x_inner[0], &x_outer[0], - &x_inner[1], &x_outer[1], - &y_top, &y_bottom, - &z_inner[0], &z_outer[0], - &z_inner[1], &z_outer[1], - points, mono); - // Draw a box in th xy plane - multiline(5, - points[0][0],points[0][1],points[0][2], - points[2][0],points[2][1],points[2][2], - points[3][0],points[3][1],points[3][2], - points[1][0],points[1][1],points[1][2], - points[0][0],points[0][1],points[0][2]); - - // Draw curving parts of crystal in the zx plane - line(points[0][0], points[0][1], points[0][2], - points[4][0], points[4][1], points[4][2]); - line(points[1][0], points[1][1], points[1][2], - points[5][0], points[5][1], points[5][2]); - line(points[2][0], points[2][1], points[2][2], - points[6][0], points[6][1], points[6][2]); - line(points[3][0], points[3][1], points[3][2], - points[7][0], points[7][1], points[7][2]); - } - // Draw a final box in the xy plane - multiline(5, - points[4][0],points[4][1],points[4][2], - points[6][0],points[6][1],points[6][2], - points[7][0],points[7][1],points[7][2], - points[5][0],points[5][1],points[5][2], - points[4][0],points[4][1],points[4][2]); - - } - - // line(0,0,0, - // -mono.perp_to_tau[0], -mono.perp_to_tau[1], -mono.perp_to_tau[2]); - if (draw_as_rectangles){ - for (int crystal=0; crystalradius_horizontal) - xthickness/2; + // double outer_radii = inner_radii + xthickness; + double angle0, angle1, movex, movey, movez; + y_top = yheight / 2; + y_bottom = -yheight / 2; + for (i = 0; i < max_i - 0.2; i = i + 0.2) + { + angle0 = i / max_i * mono->angle_range + mono->min_angle; + angle1 = (i + 0.2) / max_i * mono->angle_range + mono->min_angle; + // Define the 8 coordinates of the n'th box in the crystal + x_inner[0] = (radius_x) + cos(angle0) * mono->radius_inner; + x_inner[1] = (radius_x) + cos(angle1) * mono->radius_inner; + + z_inner[0] = -sin(angle0) * mono->radius_inner; + z_inner[1] = -sin(angle1) * mono->radius_inner; + + x_outer[0] = (radius_x) + cos(angle0) * mono->radius_outer; + x_outer[1] = (radius_x) + cos(angle1) * mono->radius_outer; + + z_outer[0] = -sin(angle0) * mono->radius_outer; + z_outer[1] = -sin(angle1) * mono->radius_outer; + // These 8 coordinates define 8 points. Coordinate transform these + // to the current crystal + rotate_all_points(&x_inner[0], &x_outer[0], + &x_inner[1], &x_outer[1], + &y_top, &y_bottom, + &z_inner[0], &z_outer[0], + &z_inner[1], &z_outer[1], + points, mono); + // Draw a box in th xy plane + multiline(5, + points[0][0], points[0][1], points[0][2], + points[2][0], points[2][1], points[2][2], + points[3][0], points[3][1], points[3][2], + points[1][0], points[1][1], points[1][2], + points[0][0], points[0][1], points[0][2]); + + // Draw curving parts of crystal in the zx plane + line(points[0][0], points[0][1], points[0][2], + points[4][0], points[4][1], points[4][2]); + line(points[1][0], points[1][1], points[1][2], + points[5][0], points[5][1], points[5][2]); + line(points[2][0], points[2][1], points[2][2], + points[6][0], points[6][1], points[6][2]); + line(points[3][0], points[3][1], points[3][2], + points[7][0], points[7][1], points[7][2]); + } + // Draw a final box in the xy plane + multiline(5, + points[4][0], points[4][1], points[4][2], + points[6][0], points[6][1], points[6][2], + points[7][0], points[7][1], points[7][2], + points[5][0], points[5][1], points[5][2], + points[4][0], points[4][1], points[4][2]); +} + +// line(0,0,0, +// -mono.perp_to_tau[0], -mono.perp_to_tau[1], -mono.perp_to_tau[2]); +if (draw_as_rectangles) +{ + for (int crystal = 0; crystal < n_crystals; crystal++) + { + double origo[3] = {0, 0, 0}; + rotate_point(origo, &mono_arr.crystal[crystal]); + // Set the box + box(origo[0], origo[1], origo[2], xthickness, yheight, zwidth, xthickness, 0, 0, 0); } +} %} END From 4d7dec07ac05ee817fb1b4f85e4087ee97db7995 Mon Sep 17 00:00:00 2001 From: Diablo Date: Mon, 9 Feb 2026 14:24:20 +0100 Subject: [PATCH 10/11] Apply microsoft formatting to Union_mesh comp --- mcstas-comps/union/Union_mesh.comp | 927 ++++++++++++++++------------- 1 file changed, 508 insertions(+), 419 deletions(-) diff --git a/mcstas-comps/union/Union_mesh.comp b/mcstas-comps/union/Union_mesh.comp index 831d8233e..768ccc32a 100644 --- a/mcstas-comps/union/Union_mesh.comp +++ b/mcstas-comps/union/Union_mesh.comp @@ -108,21 +108,22 @@ SHARE %include "interoff-lib" #ifndef Union - #error "The Union_init component must be included before this Union_mesh component" +#error "The Union_init component must be included before this Union_mesh component" #endif #ifndef ANY_GEOMETRY_DETECTOR_DECLARE - #define ANY_GEOMETRY_DETECTOR_DECLARE dummy - //struct pointer_to_global_geometry_list global_geometry_list = {0,NULL}; +#define ANY_GEOMETRY_DETECTOR_DECLARE dummy +// struct pointer_to_global_geometry_list global_geometry_list = {0,NULL}; #endif #ifndef MAX_VERT_DIST - #define MAX_VERT_DIST 1e-30 // Maximum distance between vertex points, before they are the same point. +#define MAX_VERT_DIST 1e-30 // Maximum distance between vertex points, before they are the same point. #endif // define struct to import triangles from stl file. #pragma pack(push, 1) // Disable padding -typedef struct { +typedef struct +{ float normal[3]; float vertex1[3]; float vertex2[3]; @@ -130,30 +131,34 @@ typedef struct { uint16_t attribute_byte_count; } Triangle; #pragma pack(pop) -void read_stl(char* filename, - int* n_verts, - int* n_faces, - int* n_edges, - Coords** verts, - int*** faces, - char* comp_name){ +void read_stl(char *filename, + int *n_verts, + int *n_faces, + int *n_edges, + Coords **verts, + int ***faces, + char *comp_name) +{ unsigned char buffer[1000]; Triangle *triangles; FILE *file = Open_File(filename, "r", NULL); - if (!file) { + if (!file) + { perror("ERROR: Failed to open file"); exit(1); } // Check if the file is binary or ASCII int file_is_ascii = 0; char word[6]; // "solid" + null terminator - if (fscanf(file, "%5s", word) == 1) { + if (fscanf(file, "%5s", word) == 1) + { file_is_ascii = strcmp(word, "solid") == 0; } fclose(file); - if (file_is_ascii){ - + if (file_is_ascii) + { + FILE *file = Open_File(filename, "r", NULL); char line[256]; int capacity = 100; // initial allocation @@ -161,52 +166,75 @@ void read_stl(char* filename, // Allocate memory for triangles triangles = (Triangle *)malloc(capacity * sizeof(Triangle)); - if (triangles == NULL){ + if (triangles == NULL) + { free(triangles); printf("\nERROR: malloc failed for triangles"); exit(1); } - + Triangle current; int vertex_index = 0; - while (fgets(line, sizeof(line), file)) { - + while (fgets(line, sizeof(line), file)) + { + char *trimmed = line; - while (*trimmed == ' ' || *trimmed == '\t') { + while (*trimmed == ' ' || *trimmed == '\t') + { trimmed++; } - + // If line is empty after trimming, skip it - if (*trimmed == '\0') { + if (*trimmed == '\0') + { continue; } - if (strncmp(trimmed, "facet normal", 12) == 0) { + if (strncmp(trimmed, "facet normal", 12) == 0) + { memset(¤t, 0, sizeof(Triangle)); sscanf(trimmed, "facet normal %f %f %f", - ¤t.normal[0], ¤t.normal[1], ¤t.normal[2]); - } else if (strncmp(trimmed, "vertex", 6) == 0) { + ¤t.normal[0], ¤t.normal[1], ¤t.normal[2]); + } + else if (strncmp(trimmed, "vertex", 6) == 0) + { float x, y, z; sscanf(trimmed, "vertex %f %f %f", &x, &y, &z); - if (vertex_index == 0) { - current.vertex1[0] = x; current.vertex1[1] = y; current.vertex1[2] = z; - } else if (vertex_index == 1) { - current.vertex2[0] = x; current.vertex2[1] = y; current.vertex2[2] = z; - } else if (vertex_index == 2) { - current.vertex3[0] = x; current.vertex3[1] = y; current.vertex3[2] = z; + if (vertex_index == 0) + { + current.vertex1[0] = x; + current.vertex1[1] = y; + current.vertex1[2] = z; + } + else if (vertex_index == 1) + { + current.vertex2[0] = x; + current.vertex2[1] = y; + current.vertex2[2] = z; + } + else if (vertex_index == 2) + { + current.vertex3[0] = x; + current.vertex3[1] = y; + current.vertex3[2] = z; } vertex_index++; - if (vertex_index == 3) { + if (vertex_index == 3) + { vertex_index = 0; } - } else if (strncmp(trimmed, "endfacet", 8) == 0) { + } + else if (strncmp(trimmed, "endfacet", 8) == 0) + { current.attribute_byte_count = 0; // ASCII STL always 0 - if (count >= capacity) { + if (count >= capacity) + { capacity *= 2; - void * tmp = realloc(triangles, capacity * sizeof(Triangle)); - if (tmp) { + void *tmp = realloc(triangles, capacity * sizeof(Triangle)); + if (tmp) + { free(triangles); free(tmp); perror("ERROR: Memory reallocation failed"); @@ -220,8 +248,9 @@ void read_stl(char* filename, } *n_faces = count; fclose(file); - - } else { + } + else + { FILE *file = Open_File(filename, "rb", NULL); // Read header char header[80]; @@ -231,180 +260,191 @@ void read_stl(char* filename, fread(n_faces, sizeof(uint32_t), 1, file); // Allocate memory for triangles triangles = (Triangle *)malloc(*n_faces * sizeof(Triangle)); - - - if (!triangles) { + if (!triangles) + { perror("ERROR: Memory allocation failed"); fclose(file); exit(1); } // Read triangles - for (int i = 0; i < *n_faces; i++) { + for (int i = 0; i < *n_faces; i++) + { fread(&triangles[i], sizeof(Triangle), 1, file); } - + fclose(file); } - *n_verts = 3* *n_faces; - *verts = (Coords *)malloc(sizeof(Coords)* *n_verts); - *faces = (int **)malloc(sizeof(int *)* *n_faces); + *n_verts = 3 * *n_faces; + *verts = (Coords *)malloc(sizeof(Coords) * *n_verts); + *faces = (int **)malloc(sizeof(int *) * *n_faces); // Now, we make a list of the triangles, and then give them each an index. int j = 0; - for (int i = 0; i < *n_faces; i++) { - (*faces)[i] = (int *)malloc(sizeof(int)*3); - j = i*3; + for (int i = 0; i < *n_faces; i++) + { + (*faces)[i] = (int *)malloc(sizeof(int) * 3); + j = i * 3; (*verts)[j] = coords_set((double)triangles[i].vertex1[0], (double)triangles[i].vertex1[1], (double)triangles[i].vertex1[2]); - (*verts)[j+1] = coords_set((double)triangles[i].vertex2[0], (double)triangles[i].vertex2[1], (double)triangles[i].vertex2[2]); - (*verts)[j+2] = coords_set((double)triangles[i].vertex3[0], (double)triangles[i].vertex3[1], (double)triangles[i].vertex3[2]); + (*verts)[j + 1] = coords_set((double)triangles[i].vertex2[0], (double)triangles[i].vertex2[1], (double)triangles[i].vertex2[2]); + (*verts)[j + 2] = coords_set((double)triangles[i].vertex3[0], (double)triangles[i].vertex3[1], (double)triangles[i].vertex3[2]); (*faces)[i][0] = j; - (*faces)[i][1] = j+1; - (*faces)[i][2] = j+2; + (*faces)[i][1] = j + 1; + (*faces)[i][2] = j + 2; } free(triangles); // Loop over vertices, and make sure we only use unique vertices - Coords* unique_vertices = (Coords *)malloc( - sizeof(Coords)* *n_verts) ; - + Coords *unique_vertices = (Coords *)malloc( + sizeof(Coords) * *n_verts); + int vertex_is_unique; int x_are_equal, y_are_equal, z_are_equal; - int* map_old_to_unique = malloc(sizeof(int)* *n_verts); + int *map_old_to_unique = malloc(sizeof(int) * *n_verts); int unique_counter = 0; int vert_index_in_faces = 0; - for (int i = 0; i < *n_verts; i++) { + for (int i = 0; i < *n_verts; i++) + { vertex_is_unique = 1; // First we check if the vertex exist - for (j = 0; j < i; j++){ - x_are_equal = fabs((*verts)[i].x - (*verts)[j].x)=( *n_verts+2)){ - (*faces)[face_index] = (int *)malloc(sizeof(int)*3); + if (n_lines >= (*n_verts + 2)) + { + (*faces)[face_index] = (int *)malloc(sizeof(int) * 3); // The faces are always after the vertices in an off file. - sscanf(buffer,"%d %d %d %d", - &face_vertices, - &(*faces)[face_index][0], - &(*faces)[face_index][1], - &(*faces)[face_index][2]); - if (face_vertices>3){ + sscanf(buffer, "%d %d %d %d", + &face_vertices, + &(*faces)[face_index][0], + &(*faces)[face_index][1], + &(*faces)[face_index][2]); + if (face_vertices > 3) + { printf("\nERROR: Facets use more than 3 vertices." - "\n Please correct your .off file used for Component %s", - comp_name); + "\n Please correct your .off file used for Component %s", + comp_name); exit(1); } ++face_index; } ++n_lines; - } fclose(fp); } - - - -int mesh_is_not_closed(int n_verts, int n_faces, int n_edges){ - if (n_verts - n_edges + n_faces ==2){ +int mesh_is_not_closed(int n_verts, int n_faces, int n_edges) +{ + if (n_verts - n_edges + n_faces == 2) + { return 0; } return 1; } -void generate_vertex_vertex_pair_list(int** faces, int** vert_pairs, - int n_faces){ +void generate_vertex_vertex_pair_list(int **faces, int **vert_pairs, + int n_faces) +{ int vert1, vert2, vert3, vert_pair_0; // Make list of vertex vertex pairs - for (int i=0; i < n_faces; i++){ + for (int i = 0; i < n_faces; i++) + { vert1 = faces[i][0]; vert2 = faces[i][1]; vert3 = faces[i][2]; @@ -412,57 +452,68 @@ void generate_vertex_vertex_pair_list(int** faces, int** vert_pairs, vert_pairs[i][1] = vert2; vert_pairs[i + n_faces][0] = vert1; vert_pairs[i + n_faces][1] = vert3; - vert_pairs[i + 2*n_faces][0] = vert2; - vert_pairs[i + 2*n_faces][1] = vert3; + vert_pairs[i + 2 * n_faces][0] = vert2; + vert_pairs[i + 2 * n_faces][1] = vert3; } } -void find_unique_vertex_vertex_pairs(int* unique_index, int** unique_verts, - int** vert_pairs, int* n_faces){ - int vert1,vert2; +void find_unique_vertex_vertex_pairs(int *unique_index, int **unique_verts, + int **vert_pairs, int *n_faces) +{ + int vert1, vert2; int pair_is_unique; // Make a copy of only the unique pairs - for (int i=0; i < 3* (*n_faces); i++){ + for (int i = 0; i < 3 * (*n_faces); i++) + { // Check if the first vertex exist in the unique list vert1 = vert_pairs[i][0]; vert2 = vert_pairs[i][1]; pair_is_unique = 1; - for (int j = 0; j<(*unique_index); j++){ - if (unique_verts[j][0]==vert1){ - if (unique_verts[j][1]==vert2) { - pair_is_unique=0; + for (int j = 0; j < (*unique_index); j++) + { + if (unique_verts[j][0] == vert1) + { + if (unique_verts[j][1] == vert2) + { + pair_is_unique = 0; break; } } - else if (unique_verts[j][0]==vert2){ - if (unique_verts[j][1]==vert1) { - pair_is_unique=0; + else if (unique_verts[j][0] == vert2) + { + if (unique_verts[j][1] == vert1) + { + pair_is_unique = 0; break; } } } - if (pair_is_unique){ + if (pair_is_unique) + { unique_verts[*unique_index][0] = vert1; unique_verts[*unique_index][1] = vert2; - *unique_index +=1; - + *unique_index += 1; } } } -int coord_comp(Coords A,Coords B) { - if (A.x==B.x && A.y==B.y && A.z==B.z){ +int coord_comp(Coords A, Coords B) +{ + if (A.x == B.x && A.y == B.y && A.z == B.z) + { return 1; } return 0; }; -Coords get_coords_from_string(char* line){ - Coords vert_coords = coords_set(1,2,1); +Coords get_coords_from_string(char *line) +{ + Coords vert_coords = coords_set(1, 2, 1); return vert_coords; } -void mcdisplay_mesh_function(struct lines_to_draw *lines_to_draw_output,int index, struct geometry_struct **Geometries,int number_of_volumes) { +void mcdisplay_mesh_function(struct lines_to_draw *lines_to_draw_output, int index, struct geometry_struct **Geometries, int number_of_volumes) +{ // Function to call in mcdisplay section of the sample component for this volume int n_facets = Geometries[index]->geometry_parameters.p_mesh_storage->n_facets; @@ -481,119 +532,139 @@ void mcdisplay_mesh_function(struct lines_to_draw *lines_to_draw_output,int inde struct lines_to_draw lines_to_draw_temp; lines_to_draw_temp.number_of_lines = 0; - Coords point1,point2,point3; - int iterate, i,j; + Coords point1, point2, point3; + int iterate, i, j; int print1 = 0; int print2 = 0; int print3 = 0; - Coords *list_startpoints = (Coords*)calloc(n_facets*3,sizeof(Coords)); - Coords *list_endpoints = (Coords*)calloc(n_facets*3,sizeof(Coords)); + Coords *list_startpoints = (Coords *)calloc(n_facets * 3, sizeof(Coords)); + Coords *list_endpoints = (Coords *)calloc(n_facets * 3, sizeof(Coords)); // Check for failed allocation - if (list_startpoints == NULL || list_endpoints == NULL){ + if (list_startpoints == NULL || list_endpoints == NULL) + { free(list_startpoints); free(list_endpoints); } - int counter=0; + int counter = 0; // For every triangle it should add three lines - for (iterate=0 ; iteraterotation_matrix,coords_set(*(v1_x+iterate),*(v1_y+iterate),*(v1_z+iterate))),center); - point2 = coords_add(rot_apply(Geometries[index]->rotation_matrix,coords_set(*(v2_x+iterate),*(v2_y+iterate),*(v2_z+iterate))),center); - point3 = coords_add(rot_apply(Geometries[index]->rotation_matrix,coords_set(*(v3_x+iterate),*(v3_y+iterate),*(v3_z+iterate))),center); + for (iterate = 0; iterate < n_facets; iterate++) + { + point1 = coords_add(rot_apply(Geometries[index]->rotation_matrix, coords_set(*(v1_x + iterate), *(v1_y + iterate), *(v1_z + iterate))), center); + point2 = coords_add(rot_apply(Geometries[index]->rotation_matrix, coords_set(*(v2_x + iterate), *(v2_y + iterate), *(v2_z + iterate))), center); + point3 = coords_add(rot_apply(Geometries[index]->rotation_matrix, coords_set(*(v3_x + iterate), *(v3_y + iterate), *(v3_z + iterate))), center); print1 = 1; print2 = 1; print3 = 1; - + // Make sure it does not print a line if it is already printed.... (might take a while?) - for (i = 0 ; i < counter ; i++){ - if (print1 == 1 && coord_comp(point1 , list_startpoints[i])){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point2 , list_startpoints[i])){ + for (i = 0; i < counter; i++) + { + if (print1 == 1 && coord_comp(point1, list_startpoints[i])) + { + for (j = 0; j < counter; j++) + { + if (coord_comp(point2, list_startpoints[i])) + { print1 = 0; } } } - if (print2 == 1 && coord_comp(point2 , list_startpoints[i])){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point1 , list_startpoints[i])){ + if (print2 == 1 && coord_comp(point2, list_startpoints[i])) + { + for (j = 0; j < counter; j++) + { + if (coord_comp(point1, list_startpoints[i])) + { print1 = 0; } } } - if (print2 == 1 && coord_comp(point2 , list_startpoints[i]) ){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point3 , list_startpoints[i])){ + if (print2 == 1 && coord_comp(point2, list_startpoints[i])) + { + for (j = 0; j < counter; j++) + { + if (coord_comp(point3, list_startpoints[i])) + { print2 = 0; } } } - if (print3 == 1 && coord_comp(point3 , list_startpoints[i]) ){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point2 , list_startpoints[i])){ + if (print3 == 1 && coord_comp(point3, list_startpoints[i])) + { + for (j = 0; j < counter; j++) + { + if (coord_comp(point2, list_startpoints[i])) + { print2 = 0; } } } - if (print1 == 1 && coord_comp(point1 , list_startpoints[i]) ){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point1 , list_startpoints[i])){ + if (print1 == 1 && coord_comp(point1, list_startpoints[i])) + { + for (j = 0; j < counter; j++) + { + if (coord_comp(point1, list_startpoints[i])) + { print3 = 0; } } } - if (print3 == 1 && coord_comp(point3 , list_startpoints[i])){ - for (j = 0 ; j < counter ; j++){ - if (coord_comp(point1 , list_startpoints[i])){ + if (print3 == 1 && coord_comp(point3, list_startpoints[i])) + { + for (j = 0; j < counter; j++) + { + if (coord_comp(point1, list_startpoints[i])) + { print3 = 0; } } } - } - // Create lines // Line 1 - if (print1 == 1){ - lines_to_draw_temp = draw_line_with_highest_priority(point1,point2,index,Geometries,number_of_volumes,100); - merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); + if (print1 == 1) + { + lines_to_draw_temp = draw_line_with_highest_priority(point1, point2, index, Geometries, number_of_volumes, 100); + merge_lines_to_draw(lines_to_draw_output, &lines_to_draw_temp); list_startpoints[counter] = point1; list_endpoints[counter] = point2; counter++; } // Line 2 - if (print2 == 1){ - lines_to_draw_temp = draw_line_with_highest_priority(point2,point3,index,Geometries,number_of_volumes,100); - merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); + if (print2 == 1) + { + lines_to_draw_temp = draw_line_with_highest_priority(point2, point3, index, Geometries, number_of_volumes, 100); + merge_lines_to_draw(lines_to_draw_output, &lines_to_draw_temp); list_startpoints[counter] = point2; list_endpoints[counter] = point3; counter++; } // Line 3 - if (print3 == 1){ - lines_to_draw_temp = draw_line_with_highest_priority(point3,point1,index,Geometries,number_of_volumes,100); - merge_lines_to_draw(lines_to_draw_output,&lines_to_draw_temp); + if (print3 == 1) + { + lines_to_draw_temp = draw_line_with_highest_priority(point3, point1, index, Geometries, number_of_volumes, 100); + merge_lines_to_draw(lines_to_draw_output, &lines_to_draw_temp); list_startpoints[counter] = point3; list_endpoints[counter] = point1; counter++; } - } free(list_startpoints); free(list_endpoints); }; - -struct pointer_to_1d_coords_list allocate_shell_points(struct geometry_struct *geometry,int max_number_of_points) { +struct pointer_to_1d_coords_list allocate_shell_points(struct geometry_struct *geometry, int max_number_of_points) +{ // Function that returns a number (less than max) of points on the geometry surface // Run trhough all points in list of faces, and remove dublicates // There are three points in a face and very often these will be dublicated a few times. This removes dublicates to boost performance down stream... - - + struct pointer_to_1d_coords_list mesh_shell_array; - + int n_facets = geometry->geometry_parameters.p_mesh_storage->n_facets; double *v1_x = geometry->geometry_parameters.p_mesh_storage->v1_x; double *v1_y = geometry->geometry_parameters.p_mesh_storage->v1_y; @@ -605,70 +676,76 @@ struct pointer_to_1d_coords_list allocate_shell_points(struct geometry_struct *g double *v3_y = geometry->geometry_parameters.p_mesh_storage->v3_y; double *v3_z = geometry->geometry_parameters.p_mesh_storage->v3_z; int number_of_points_in_array = 0; - mesh_shell_array.elements = malloc(3*n_facets * sizeof(Coords)); + mesh_shell_array.elements = malloc(3 * n_facets * sizeof(Coords)); int is_dublicate = 0; Coords this_vert; - int i,j; - for (i=0 ; i < n_facets ; i++){ - + int i, j; + for (i = 0; i < n_facets; i++) + { + // v1 is_dublicate = 0; - this_vert = coords_set(*(v1_x+i),*(v1_y+i),*(v1_z+i)); - + this_vert = coords_set(*(v1_x + i), *(v1_y + i), *(v1_z + i)); + // test if dublicate - for (j = 0; j < number_of_points_in_array ; j++ ){ - if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ + for (j = 0; j < number_of_points_in_array; j++) + { + if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z) + { is_dublicate = 1; j = number_of_points_in_array; } } - if (is_dublicate == 0){ + if (is_dublicate == 0) + { mesh_shell_array.elements[number_of_points_in_array] = this_vert; number_of_points_in_array += 1; } - - - + // v2 is_dublicate = 0; - this_vert = coords_set(*(v2_x+i),*(v2_y+i),*(v2_z+i)); - - for (j = 0; j < number_of_points_in_array ; j++){ - if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ + this_vert = coords_set(*(v2_x + i), *(v2_y + i), *(v2_z + i)); + + for (j = 0; j < number_of_points_in_array; j++) + { + if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z) + { is_dublicate = 1; j = number_of_points_in_array; } } - if (is_dublicate == 0){ + if (is_dublicate == 0) + { mesh_shell_array.elements[number_of_points_in_array] = this_vert; number_of_points_in_array += 1; } - - - + // v3 is_dublicate = 0; - this_vert = coords_set(*(v3_x+i),*(v3_y+i),*(v3_z+i)); - + this_vert = coords_set(*(v3_x + i), *(v3_y + i), *(v3_z + i)); + // test if dublicate - for (j = 0; j < number_of_points_in_array ; j++ ){ - if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z){ + for (j = 0; j < number_of_points_in_array; j++) + { + if (this_vert.x == mesh_shell_array.elements[j].x && this_vert.y == mesh_shell_array.elements[j].y && this_vert.z == mesh_shell_array.elements[j].z) + { is_dublicate = 1; j = number_of_points_in_array; } } - if (is_dublicate == 0){ + if (is_dublicate == 0) + { mesh_shell_array.elements[number_of_points_in_array] = this_vert; number_of_points_in_array += 1; } } - + j = number_of_points_in_array - 1; // Last legal index, currently j is out of bounds. - + mesh_shell_array.num_elements = number_of_points_in_array; - - for (i=0; icenter); mesh_shell_array.elements[i] = rot_apply(geometry->rotation_matrix, mesh_shell_array.elements[i]); @@ -676,27 +753,27 @@ struct pointer_to_1d_coords_list allocate_shell_points(struct geometry_struct *g return mesh_shell_array; } - -void initialize_mesh_geometry_from_main_component(struct geometry_struct *mesh) { +void initialize_mesh_geometry_from_main_component(struct geometry_struct *mesh) +{ // Function to be called in initialize of the main component // This is done as the rotation matrix needs to be relative to the main component instead of global // Everything done in initialize in this component file has the rotation matrix relative to global - + Coords simple_vector; Coords mesh_vector; - + // Start with vector that points along the mesh in the local frame - simple_vector = coords_set(0,1,0); + simple_vector = coords_set(0, 1, 0); // Rotate the direction vector of the mesh to the master component frame of reference - mesh_vector = rot_apply(mesh->rotation_matrix,simple_vector); - NORM(mesh_vector.x,mesh_vector.y,mesh_vector.z); + mesh_vector = rot_apply(mesh->rotation_matrix, simple_vector); + NORM(mesh_vector.x, mesh_vector.y, mesh_vector.z); mesh->geometry_parameters.p_mesh_storage->direction_vector.x = mesh_vector.x; mesh->geometry_parameters.p_mesh_storage->direction_vector.y = mesh_vector.y; mesh->geometry_parameters.p_mesh_storage->direction_vector.z = mesh_vector.z; - + mesh->geometry_parameters.p_mesh_storage->Bounding_Box_Center = rot_apply(mesh->rotation_matrix, mesh->geometry_parameters.p_mesh_storage->Bounding_Box_Center); - + /* // Works for pure translation print_position(mesh->geometry_parameters.p_mesh_storage->Bounding_Box_Center, "BB before adjustment"); @@ -705,11 +782,10 @@ void initialize_mesh_geometry_from_main_component(struct geometry_struct *mesh) */ } - -double square(double x){ - return x*x; +double square(double x) +{ + return x * x; } - %} //============================================================================= @@ -737,9 +813,6 @@ struct mesh_storage mesh_data; // Structs for surface effects struct surface_stack_struct surface_stack; struct surface_stack_struct cut_surface_stack; - - - %} //============================================================================= // INITIALIZE SECTION @@ -751,160 +824,172 @@ geometry_struct_init(&(mesh_vol.geometry)); mesh_vol.geometry.skip_hierarchy_optimization = skip_convex_check; // Initializes the focusing system for this volume including input sanitation. focus_initialize(&mesh_vol.geometry, - POS_A_COMP_INDEX(INDEX_CURRENT_COMP+target_index), - POS_A_CURRENT_COMP, - ROT_A_CURRENT_COMP, - target_index, - target_x, - target_y, - target_z, - focus_aw, - focus_ah, - focus_xw, - focus_xh, - focus_r, - NAME_CURRENT_COMP); - - - -if (_getcomp_index(init) < 0) { - fprintf(stderr,"Union_mesh:%s: Error identifying Union_init component," - "%s is not a known component name.\n",NAME_CURRENT_COMP, init); + POS_A_COMP_INDEX(INDEX_CURRENT_COMP + target_index), + POS_A_CURRENT_COMP, + ROT_A_CURRENT_COMP, + target_index, + target_x, + target_y, + target_z, + focus_aw, + focus_ah, + focus_xw, + focus_xh, + focus_r, + NAME_CURRENT_COMP); + +if (_getcomp_index(init) < 0) +{ + fprintf(stderr, "Union_mesh:%s: Error identifying Union_init component," + "%s is not a known component name.\n", + NAME_CURRENT_COMP, init); exit(-1); } struct pointer_to_global_material_list *global_material_list = COMP_GETPAR3( - Union_init, - init, - global_material_list); + Union_init, + init, + global_material_list); // Use sanitation #ifdef MATERIAL_DETECTOR - if (global_material_list->num_elements == 0) { - // Here if the user have defined a material, but only after this material - printf("\nERROR: Need to define a material using Union_make_material" - " before using a Union geometry component. \n"); - printf("%s was defined before first use of Union_make_material.\n",NAME_CURRENT_COMP); - exit(1); - } +if (global_material_list->num_elements == 0) +{ + // Here if the user have defined a material, but only after this material + printf("\nERROR: Need to define a material using Union_make_material" + " before using a Union geometry component. \n"); + printf("%s was defined before first use of Union_make_material.\n", NAME_CURRENT_COMP); + exit(1); +} #endif #ifndef MATERIAL_DETECTOR - printf("\nERROR: Need to define a material using Union_make_material" - " before using a Union geometry component. \n"); - exit(1); +printf("\nERROR: Need to define a material using Union_make_material" + " before using a Union geometry component. \n"); +exit(1); #endif - mesh_vol.geometry.is_masked_volume = 0; mesh_vol.geometry.is_exit_volume = 0; mesh_vol.geometry.is_mask_volume = 0; struct pointer_to_global_geometry_list *global_geometry_list = COMP_GETPAR3(Union_init, - init, - global_geometry_list); + init, + global_geometry_list); //============================================================================== // Find out what this component masks //============================================================================== - - // Read the material input, or if it lacks, use automatic linking. if (mask_string && - strlen(mask_string) && - strcmp(mask_string, "NULL") && - strcmp(mask_string, "0")) { + strlen(mask_string) && + strcmp(mask_string, "NULL") && + strcmp(mask_string, "0")) +{ // A mask volume is used to limit the extend of other volumes, // called the masked volumes. These are specified in the mask_string. // In order for a ray to enter a masked volume, // it needs to be both in the region covered by that volume AND the mask volume. // When more than mesh_vol.geometry.mask_mode = 1; // Default mask mode is ALL - if (mask_setting && strlen(mask_setting) && strcmp(mask_setting, - "NULL") && strcmp(mask_setting, "0")) { - if (strcmp(mask_setting,"ALL") == 0 || strcmp(mask_setting,"All") == 0) { + if (mask_setting && strlen(mask_setting) && strcmp(mask_setting, "NULL") && strcmp(mask_setting, "0")) + { + if (strcmp(mask_setting, "ALL") == 0 || strcmp(mask_setting, "All") == 0) + { mesh_vol.geometry.mask_mode = 1; } - else if (strcmp(mask_setting,"ANY") == 0 || strcmp(mask_setting,"Any") == 0) { + else if (strcmp(mask_setting, "ANY") == 0 || strcmp(mask_setting, "Any") == 0) + { mesh_vol.geometry.mask_mode = 2; } - else { + else + { printf("The mask_mode of component %s is set to %s," - " but must be either ALL or ANY.\n", - NAME_CURRENT_COMP,mask_setting); + " but must be either ALL or ANY.\n", + NAME_CURRENT_COMP, mask_setting); exit(1); } } - + int found_geometries = 0; - for (loop_index=0;loop_indexnum_elements;loop_index++) { + for (loop_index = 0; loop_index < global_geometry_list->num_elements; loop_index++) + { // Add mask list - if (1 == manual_linking_function(global_geometry_list->elements[loop_index].name,mask_string)) { - add_element_to_int_list(&mesh_vol.geometry.mask_list,global_geometry_list->elements[loop_index].component_index); - add_element_to_int_list(&global_geometry_list->elements[loop_index].Volume->geometry.masked_by_list,INDEX_CURRENT_COMP); + if (1 == manual_linking_function(global_geometry_list->elements[loop_index].name, mask_string)) + { + add_element_to_int_list(&mesh_vol.geometry.mask_list, global_geometry_list->elements[loop_index].component_index); + add_element_to_int_list(&global_geometry_list->elements[loop_index].Volume->geometry.masked_by_list, INDEX_CURRENT_COMP); global_geometry_list->elements[loop_index].Volume->geometry.is_masked_volume = 1; if (mesh_vol.geometry.mask_mode == 2) global_geometry_list->elements[loop_index].Volume->geometry.mask_mode = 2; - if (mesh_vol.geometry.mask_mode == 1) { + if (mesh_vol.geometry.mask_mode == 1) + { if (global_geometry_list->elements[loop_index].Volume->geometry.is_masked_volume == 1 && global_geometry_list->elements[loop_index].Volume->geometry.mask_mode != 2) // If more than one mask is added to one volume, the ANY mode overwrites the (default) ALL mode. global_geometry_list->elements[loop_index].Volume->geometry.mask_mode = 1; } - + found_geometries = 1; } } - if (found_geometries == 0) { + if (found_geometries == 0) + { printf("The mask_string in geometry: " - "%s did not find any of the specified volumes in the mask_string " - "%s \n",NAME_CURRENT_COMP,mask_string); + "%s did not find any of the specified volumes in the mask_string " + "%s \n", + NAME_CURRENT_COMP, mask_string); exit(1); } mesh_vol.p_physics = malloc(sizeof(struct physics_struct)); - mesh_vol.p_physics->is_vacuum = 0; // Makes this volume a vacuum - mesh_vol.p_physics->number_of_processes = (int) 0; // Should not be used. - mesh_vol.p_physics->my_a = 0; // Should not be used. - sprintf(mesh_vol.p_physics->name,"Mask"); + mesh_vol.p_physics->is_vacuum = 0; // Makes this volume a vacuum + mesh_vol.p_physics->number_of_processes = (int)0; // Should not be used. + mesh_vol.p_physics->my_a = 0; // Should not be used. + sprintf(mesh_vol.p_physics->name, "Mask"); mesh_vol.geometry.is_mask_volume = 1; - - + // Read the material input, or if it lacks, use automatic linking. -} else if (material_string - && strlen(material_string) - && strcmp(material_string, "NULL") - && strcmp(material_string, "0")) { +} +else if (material_string && strlen(material_string) && strcmp(material_string, "NULL") && strcmp(material_string, "0")) +{ // A geometry string was given, use it to determine which material - if (0 == strcmp(material_string,"vacuum") - || 0 == strcmp(material_string,"Vacuum")) { + if (0 == strcmp(material_string, "vacuum") || 0 == strcmp(material_string, "Vacuum")) + { // One could have a global physics struct for vacuum instead of creating one for each mesh_vol.p_physics = malloc(sizeof(struct physics_struct)); mesh_vol.p_physics->is_vacuum = 1; // Makes this volume a vacuum - mesh_vol.p_physics->number_of_processes = (int) 0; + mesh_vol.p_physics->number_of_processes = (int)0; mesh_vol.p_physics->my_a = 0; // Should not be used. - sprintf(mesh_vol.p_physics->name,"Vacuum"); - } else if (0 == strcmp(material_string,"exit") - || 0 == strcmp(material_string,"Exit")) { + sprintf(mesh_vol.p_physics->name, "Vacuum"); + } + else if (0 == strcmp(material_string, "exit") || 0 == strcmp(material_string, "Exit")) + { // One could have a global physics struct for exit instead of creating one for each mesh_vol.p_physics = malloc(sizeof(struct physics_struct)); mesh_vol.p_physics->is_vacuum = 1; // Makes this volume a vacuum - mesh_vol.p_physics->number_of_processes = (int) 0; + mesh_vol.p_physics->number_of_processes = (int)0; mesh_vol.p_physics->my_a = 0; // Should not be used. mesh_vol.geometry.is_exit_volume = 1; - sprintf(mesh_vol.p_physics->name,"Exit"); - } else { - for (loop_index=0;loop_indexnum_elements;loop_index++) { - if (0 == strcmp(material_string,global_material_list->elements[loop_index].name)) { + sprintf(mesh_vol.p_physics->name, "Exit"); + } + else + { + for (loop_index = 0; loop_index < global_material_list->num_elements; loop_index++) + { + if (0 == strcmp(material_string, global_material_list->elements[loop_index].name)) + { mesh_vol.p_physics = global_material_list->elements[loop_index].physics; break; } - if (loop_index == global_material_list->num_elements-1) { + if (loop_index == global_material_list->num_elements - 1) + { printf("\n"); printf("ERROR: The material string \"%s\" in Union geometry \"%s\"" - " did not match a specified material. \n",material_string,NAME_CURRENT_COMP); + " did not match a specified material. \n", + material_string, NAME_CURRENT_COMP); printf(" The materials available at this point" - " (need to be defined before the geometry): \n"); - for (loop_index=0;loop_indexnum_elements;loop_index++) - printf(" %s\n",global_material_list->elements[loop_index].name); + " (need to be defined before the geometry): \n"); + for (loop_index = 0; loop_index < global_material_list->num_elements; loop_index++) + printf(" %s\n", global_material_list->elements[loop_index].name); printf("\n"); printf(" It is also possible to use one of the defualt materials avaiable: \n"); printf(" Vacuum (for a Volume without scattering or absorption)\n"); @@ -914,13 +999,15 @@ if (mask_string && } } } -} else { - // Automatic linking, simply using the last defined material. - #ifndef MATERIAL_DETECTOR - printf("Need to define a material before the geometry to use automatic linking %s.\n",NAME_CURRENT_COMP); - exit(1); - #endif - mesh_vol.p_physics = global_material_list->elements[global_material_list->num_elements-1].physics; +} +else +{ +// Automatic linking, simply using the last defined material. +#ifndef MATERIAL_DETECTOR + printf("Need to define a material before the geometry to use automatic linking %s.\n", NAME_CURRENT_COMP); + exit(1); +#endif + mesh_vol.p_physics = global_material_list->elements[global_material_list->num_elements - 1].physics; } //============================================================================== // READ FIle @@ -932,65 +1019,73 @@ if (mask_string && int n_verts = 0; int n_faces = 0; int n_edges = 0; -Coords* verts; -Coords tmp_vert = coords_set(0,0,0); +Coords *verts; +Coords tmp_vert = coords_set(0, 0, 0); verts = &tmp_vert; // This tmp vert is just for linter play... -int** faces; +int **faces; int unique_index = 0; const char *dot = strrchr(filename, '.'); -if (!dot || dot == filename) { +if (!dot || dot == filename) +{ printf("ERROR: given file has no extension %s", NAME_CURRENT_COMP); exit(1); } -if(strcmp(dot, ".stl") == 0 || strcmp(dot, ".STL") == 0){ +if (strcmp(dot, ".stl") == 0 || strcmp(dot, ".STL") == 0) +{ printf("\n%s, Given file is in stl format. Union_mesh assumes three vertices per face.\n", - NAME_CURRENT_COMP); + NAME_CURRENT_COMP); read_stl(filename, - &n_verts, - &n_faces, - &n_edges, - &verts, - &faces, - NAME_CURRENT_COMP); -} else if (strcmp(dot, ".off") == 0 || strcmp(dot, ".OFF") == 0) { + &n_verts, + &n_faces, + &n_edges, + &verts, + &faces, + NAME_CURRENT_COMP); +} +else if (strcmp(dot, ".off") == 0 || strcmp(dot, ".OFF") == 0) +{ printf("\n%s, Given file is in off format. Union_mesh assumes three vertices per face.\n", - NAME_CURRENT_COMP); + NAME_CURRENT_COMP); read_off_file_vertices_and_faces(filename, - &n_verts, - &n_faces, - &n_edges, - &verts, - &faces, - NAME_CURRENT_COMP); -} else { + &n_verts, + &n_faces, + &n_edges, + &verts, + &faces, + NAME_CURRENT_COMP); +} +else +{ printf("\nERROR IN %s: File %s is read as neither an stl or an off file.", - NAME_CURRENT_COMP, filename); + NAME_CURRENT_COMP, filename); exit(1); } printf("\nCOMPONENT %s: Number of faces read: %d\t Number of vertices read: %d\n", - NAME_CURRENT_COMP, n_verts, n_faces); + NAME_CURRENT_COMP, n_verts, n_faces); // Loop over all vertices and multiply their positions with coordinate_scale -for (int i = 0; imax_dist){ +for (int i = 0; i < n_verts; i++) +{ + dist = sqrt(B_sphere_x.x - verts[i].x + B_sphere_x.y - verts[i].y + B_sphere_x.z - verts[i].z); + if (dist > max_dist) + { max_dist = dist; B_sphere_y = verts[i]; } } Coords B_sphere_z = B_sphere_y; max_dist = 0; -for (int i=0; imax_dist){ +for (int i = 0; i < n_verts; i++) +{ + dist = sqrt(square(B_sphere_y.x - verts[i].x) + square(B_sphere_y.y - verts[i].y) + square(B_sphere_y.z - verts[i].z)); + + if (dist > max_dist) + { max_dist = dist; B_sphere_z = verts[i]; } } -double radius = sqrt(square(B_sphere_y.x-B_sphere_z.x) - + square(B_sphere_y.y-B_sphere_z.y) - + square(B_sphere_y.z-B_sphere_z.z))/2; -Coords bbcenter = coords_set((B_sphere_y.x + B_sphere_z.x)/2, - (B_sphere_y.y + B_sphere_z.y)/2, - (B_sphere_y.z + B_sphere_z.z)/2); +double radius = sqrt(square(B_sphere_y.x - B_sphere_z.x) + square(B_sphere_y.y - B_sphere_z.y) + square(B_sphere_y.z - B_sphere_z.z)) / 2; +Coords bbcenter = coords_set((B_sphere_y.x + B_sphere_z.x) / 2, + (B_sphere_y.y + B_sphere_z.y) / 2, + (B_sphere_y.z + B_sphere_z.z) / 2); mesh_data.Bounding_Box_Center = bbcenter; double test_rad = 0; -for (int i=0; iradius){ +for (int i = 0; i < n_verts; i++) +{ + test_rad = sqrt(square(bbcenter.x - verts[i].x) + square(bbcenter.y - verts[i].y) + square(bbcenter.z - verts[i].z)); + if (test_rad > radius) + { radius = test_rad; } } mesh_data.Bounding_Box_Radius = radius; - - - Coords vert1, vert2, vert3; Coords edge1, edge2; // Allocate space vertices in mesh data // TODO: Change data format to be in a less verbose data structure, or a more effective one. -mesh_data.v1_x = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v1_y = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v1_z = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v2_x = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v2_y = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v2_z = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v3_x = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v3_y = (double *)malloc(n_faces*sizeof(double)); -mesh_data.v3_z = (double *)malloc(n_faces*sizeof(double)); -mesh_data.normal_x = (double *)malloc(n_faces*sizeof(double)); -mesh_data.normal_y = (double *)malloc(n_faces*sizeof(double)); -mesh_data.normal_z = (double *)malloc(n_faces*sizeof(double)); -for (int i=0; i Date: Mon, 9 Feb 2026 14:26:05 +0100 Subject: [PATCH 11/11] Format monochromator Bent complex.comp to use microsoft formatter --- .../contrib/Monochromator_bent_complex.comp | 466 +++++++++--------- 1 file changed, 242 insertions(+), 224 deletions(-) diff --git a/mcstas-comps/contrib/Monochromator_bent_complex.comp b/mcstas-comps/contrib/Monochromator_bent_complex.comp index b1f572344..5c105af87 100755 --- a/mcstas-comps/contrib/Monochromator_bent_complex.comp +++ b/mcstas-comps/contrib/Monochromator_bent_complex.comp @@ -78,174 +78,186 @@ NOACC SHARE INHERIT Monochromator_bent DECLARE %{ - int counter; - int counter2; - double curvature; - int MAX_REFLECTIONS; - struct neutron_values neutron; - struct Monochromator_array mono_arr; +int counter; +int counter2; +double curvature; +int MAX_REFLECTIONS; +struct neutron_values neutron; +struct Monochromator_array mono_arr; %} INITIALIZE %{ - if (verbose) - for (int i=0;i<1;i++){ +if (verbose) + for (int i = 0; i < 1; i++) + { printf("x,y,z,rot=(%g,%g,%g,%g,%g,%g)\n", - x_pos[i],y_pos[i],z_pos[i],x_rot[i],y_rot[i],z_rot[i]); + x_pos[i], y_pos[i], z_pos[i], x_rot[i], y_rot[i], z_rot[i]); } - if (verbose){ - printf("Monochromator_Bent output: " - "Component name is %s:\n", NAME_CURRENT_COMP); - } - //////////////////////////////////////////////////////////////////////////// - /////////////// INITIALIZING PARAMETERS - //////////////////////////////////////////////////////////////////////////// - mono_arr.crystal = (struct Monochromator_values*) malloc(n_crystals * sizeof(struct Monochromator_values)); - mono_arr.number_of_crystals = n_crystals; // [#] - mono_arr.verbosity = verbose; // [#] - - // Separate the string into individual crystals - int MAX_TOKENS = 6*n_crystals; +if (verbose) +{ + printf("Monochromator_Bent output: " + "Component name is %s:\n", + NAME_CURRENT_COMP); +} +//////////////////////////////////////////////////////////////////////////// +/////////////// INITIALIZING PARAMETERS +//////////////////////////////////////////////////////////////////////////// +mono_arr.crystal = (struct Monochromator_values *)malloc(n_crystals * sizeof(struct Monochromator_values)); +mono_arr.number_of_crystals = n_crystals; // [#] +mono_arr.verbosity = verbose; // [#] - char** planes = malloc(n_crystals*sizeof(char*)); - if (planes == NULL) { - exit(fprintf(stderr, "Error: memory allocation failed for planes\n")); - } - int token_count = 0; - // Remove trailing newline, if any - plane_of_reflection[strcspn(plane_of_reflection, "\n")] = '\0'; +// Separate the string into individual crystals +int MAX_TOKENS = 6 * n_crystals; + +char **planes = malloc(n_crystals * sizeof(char *)); +if (planes == NULL) +{ + exit(fprintf(stderr, "Error: memory allocation failed for planes\n")); +} +int token_count = 0; +// Remove trailing newline, if any +plane_of_reflection[strcspn(plane_of_reflection, "\n")] = '\0'; - // Tokenize the string using ';' as delimiter - char *plane = strtok(plane_of_reflection, ";"); - while (plane != NULL && token_count < MAX_TOKENS) { - planes[token_count++] = plane; - plane = strtok(NULL, ";"); - } +// Tokenize the string using ';' as delimiter +char *plane = strtok(plane_of_reflection, ";"); +while (plane != NULL && token_count < MAX_TOKENS) +{ + planes[token_count++] = plane; + plane = strtok(NULL, ";"); +} - // Print the tokens - if (mono_arr.verbosity){ - printf("\nPlanes:\n"); - for (int i = 0; i < token_count; ++i) { - printf("[%d]: %s\n", i, planes[i]); - } +// Print the tokens +if (mono_arr.verbosity) +{ + printf("\nPlanes:\n"); + for (int i = 0; i < token_count; ++i) + { + printf("[%d]: %s\n", i, planes[i]); } - - for (int i=0; i0){ - mono_arr.crystal[i].max_angle = PI + asin(zwidth[i]/(2*radius_x[i])); - mono_arr.crystal[i].min_angle = PI - asin(zwidth[i]/(2*radius_x[i])); - } else if (radius_x[i]<0){ - mono_arr.crystal[i].max_angle = -asin(zwidth[i]/(2*radius_x[i])); - mono_arr.crystal[i].min_angle = asin(zwidth[i]/(2*radius_x[i])); - } - mono_arr.crystal[i].angle_range = mono_arr.crystal[i].max_angle - mono_arr.crystal[i].min_angle; - // Figure out the type of Monochromator - if (radius_x[i]) mono_arr.crystal[i].type=bent; - if (mosaicity[i]) mono_arr.crystal[i].type = mosaic; - if ((mosaicity[i]>0) && (fabs(radius_x[i])>0)) mono_arr.crystal[i].type = bent_mosaic; - // Read the designated plane of reflection, for use in the Monochromator. - enum crystal_plane plane = stringToEnum((const char *)planes[i]); - // Set Monochromator values - mono_arr.crystal[i].length = zwidth[i]; // [m] - mono_arr.crystal[i].height = yheight[i]; // [m] - mono_arr.crystal[i].thickness = xthickness[i]; // [m] - mono_arr.crystal[i].radius_horizontal = radius_x[i]; // [m] - mono_arr.crystal[i].radius_vertical = radius_y[i]; // [m] - mono_arr.crystal[i].radius_inner = fabs(mono_arr.crystal[i].radius_horizontal) - mono_arr.crystal[i].thickness/2; // [m] - mono_arr.crystal[i].radius_outer = fabs(mono_arr.crystal[i].radius_horizontal) + mono_arr.crystal[i].thickness/2; // [m] - double arrowheight = mono_arr.crystal[i].radius_outer*(1-cos(mono_arr.crystal[i].angle_range/2)); //sagita of circles - mono_arr.crystal[i].bounding_box_thickness = mono_arr.crystal[i].thickness + 2*arrowheight; - mono_arr.crystal[i].domain_thickness = domainthickness[i]; // [] - mono_arr.crystal[i].temperature_mono = temperature[i]; // [T] - mono_arr.crystal[i].lattice_spacing = crystal_table[plane][0]; // [A] +} - mono_arr.crystal[i].Maier_Leibnitz_reflectivity = crystal_table[plane][1]*100; // [A^-1 m^-1] - mono_arr.crystal[i].bound_atom_scattering_cross_section = crystal_table[plane][2]; // [barn] - mono_arr.crystal[i].absorption_for_1AA_Neutrons = crystal_table[plane][3];// [barn*A^-1] - mono_arr.crystal[i].incoherent_scattering_cross_section = crystal_table[plane][4];// [barn] - mono_arr.crystal[i].volume = crystal_table[plane][5]; // [A^-3] - mono_arr.crystal[i].atomic_number = crystal_table[plane][6]; // [#] - mono_arr.crystal[i].debye_temperature = crystal_table[plane][7]; // [K] - mono_arr.crystal[i].Constant_from_Freund_paper = crystal_table[plane][8]; //[A^-2 eV^-1] - mono_arr.crystal[i].poisson_ratio = crystal_table[plane][9]; // [] - calculate_B0_and_BT(&mono_arr.crystal[i]); - mono_arr.crystal[i].Debye_Waller_factor = exp(-(mono_arr.crystal[i].B0 + mono_arr.crystal[i].BT)/2/square(mono_arr.crystal[i].lattice_spacing)); +for (int i = 0; i < n_crystals; i++) +{ + // // Initialize angles of the Monochromator + if (radius_x[i] > 0) + { + mono_arr.crystal[i].max_angle = PI + asin(zwidth[i] / (2 * radius_x[i])); + mono_arr.crystal[i].min_angle = PI - asin(zwidth[i] / (2 * radius_x[i])); + } + else if (radius_x[i] < 0) + { + mono_arr.crystal[i].max_angle = -asin(zwidth[i] / (2 * radius_x[i])); + mono_arr.crystal[i].min_angle = asin(zwidth[i] / (2 * radius_x[i])); + } + mono_arr.crystal[i].angle_range = mono_arr.crystal[i].max_angle - mono_arr.crystal[i].min_angle; + // Figure out the type of Monochromator + if (radius_x[i]) + mono_arr.crystal[i].type = bent; + if (mosaicity[i]) + mono_arr.crystal[i].type = mosaic; + if ((mosaicity[i] > 0) && (fabs(radius_x[i]) > 0)) + mono_arr.crystal[i].type = bent_mosaic; + // Read the designated plane of reflection, for use in the Monochromator. + enum crystal_plane plane = stringToEnum((const char *)planes[i]); + // Set Monochromator values + mono_arr.crystal[i].length = zwidth[i]; // [m] + mono_arr.crystal[i].height = yheight[i]; // [m] + mono_arr.crystal[i].thickness = xthickness[i]; // [m] + mono_arr.crystal[i].radius_horizontal = radius_x[i]; // [m] + mono_arr.crystal[i].radius_vertical = radius_y[i]; // [m] + mono_arr.crystal[i].radius_inner = fabs(mono_arr.crystal[i].radius_horizontal) - mono_arr.crystal[i].thickness / 2; // [m] + mono_arr.crystal[i].radius_outer = fabs(mono_arr.crystal[i].radius_horizontal) + mono_arr.crystal[i].thickness / 2; // [m] + double arrowheight = mono_arr.crystal[i].radius_outer * (1 - cos(mono_arr.crystal[i].angle_range / 2)); // sagita of circles + mono_arr.crystal[i].bounding_box_thickness = mono_arr.crystal[i].thickness + 2 * arrowheight; + mono_arr.crystal[i].domain_thickness = domainthickness[i]; // [] + mono_arr.crystal[i].temperature_mono = temperature[i]; // [T] + mono_arr.crystal[i].lattice_spacing = crystal_table[plane][0]; // [A] - mono_arr.crystal[i].x = x_pos[i]; - mono_arr.crystal[i].y = y_pos[i]; - mono_arr.crystal[i].z = z_pos[i]; - double xrot = x_rot[i] * DEG2RAD; - double yrot = y_rot[i] * DEG2RAD; - double zrot = z_rot[i] * DEG2RAD; - rot_set_rotation(mono_arr.crystal[i].rotation_matrices, xrot, yrot, zrot); - rot_set_rotation(mono_arr.crystal[i].neg_rotation_matrix, -xrot, -yrot, -zrot); - if (verbose){ - printf("%d'th crystal\nrot_x=%g\trot_y=%g\trot_z=%g\n" - "tr_x=%g\ttr_y=%g\ttr_z=%g\n",i, - xrot, yrot, zrot, - x_pos[i], y_pos[i], z_pos[i] - ); - } + mono_arr.crystal[i].Maier_Leibnitz_reflectivity = crystal_table[plane][1] * 100; // [A^-1 m^-1] + mono_arr.crystal[i].bound_atom_scattering_cross_section = crystal_table[plane][2]; // [barn] + mono_arr.crystal[i].absorption_for_1AA_Neutrons = crystal_table[plane][3]; // [barn*A^-1] + mono_arr.crystal[i].incoherent_scattering_cross_section = crystal_table[plane][4]; // [barn] + mono_arr.crystal[i].volume = crystal_table[plane][5]; // [A^-3] + mono_arr.crystal[i].atomic_number = crystal_table[plane][6]; // [#] + mono_arr.crystal[i].debye_temperature = crystal_table[plane][7]; // [K] + mono_arr.crystal[i].Constant_from_Freund_paper = crystal_table[plane][8]; //[A^-2 eV^-1] + mono_arr.crystal[i].poisson_ratio = crystal_table[plane][9]; // [] + calculate_B0_and_BT(&mono_arr.crystal[i]); + mono_arr.crystal[i].Debye_Waller_factor = exp(-(mono_arr.crystal[i].B0 + mono_arr.crystal[i].BT) / 2 / square(mono_arr.crystal[i].lattice_spacing)); - - //Set the mosaicity if relevant - if (mono_arr.crystal[i].type == mosaic || mono_arr.crystal[i].type == bent_mosaic){ - //Input mosaicity is in arc min. Convert to Degrees and then to radians - // (And multiply with R8LN2 which I don't know what is). - // Is it because of input being fwhm instead of sigma? - double R8LN2 = 2.354820045; - mono_arr.crystal[i].mosaicity_horizontal = mosaicity[i]/60*DEG2RAD/R8LN2; - mono_arr.crystal[i].mosaicity_vertical = mono_arr.crystal[i].mosaicity_horizontal*mosaic_anisotropy[i]; - } - // Initialize reciprocal lattice vector G or tau in some texts, and perp_to_tau. + mono_arr.crystal[i].x = x_pos[i]; + mono_arr.crystal[i].y = y_pos[i]; + mono_arr.crystal[i].z = z_pos[i]; + double xrot = x_rot[i] * DEG2RAD; + double yrot = y_rot[i] * DEG2RAD; + double zrot = z_rot[i] * DEG2RAD; + rot_set_rotation(mono_arr.crystal[i].rotation_matrices, xrot, yrot, zrot); + rot_set_rotation(mono_arr.crystal[i].neg_rotation_matrix, -xrot, -yrot, -zrot); + if (verbose) + { + printf("%d'th crystal\nrot_x=%g\trot_y=%g\trot_z=%g\n" + "tr_x=%g\ttr_y=%g\ttr_z=%g\n", + i, + xrot, yrot, zrot, + x_pos[i], y_pos[i], z_pos[i]); + } - double chi = angle_to_cut_horizontal[i]*DEG2RAD; + // Set the mosaicity if relevant + if (mono_arr.crystal[i].type == mosaic || mono_arr.crystal[i].type == bent_mosaic) + { + // Input mosaicity is in arc min. Convert to Degrees and then to radians + // (And multiply with R8LN2 which I don't know what is). + // Is it because of input being fwhm instead of sigma? + double R8LN2 = 2.354820045; + mono_arr.crystal[i].mosaicity_horizontal = mosaicity[i] / 60 * DEG2RAD / R8LN2; + mono_arr.crystal[i].mosaicity_vertical = mono_arr.crystal[i].mosaicity_horizontal * mosaic_anisotropy[i]; + } + // Initialize reciprocal lattice vector G or tau in some texts, and perp_to_tau. - double tau_size_zero = 2*PI/mono_arr.crystal[i].lattice_spacing; + double chi = angle_to_cut_horizontal[i] * DEG2RAD; - mono_arr.crystal[i].tau[0] = tau_size_zero*cos(chi); - mono_arr.crystal[i].tau[1] = 0; - mono_arr.crystal[i].tau[2] = tau_size_zero*sin(chi); + double tau_size_zero = 2 * PI / mono_arr.crystal[i].lattice_spacing; - mono_arr.crystal[i].perp_to_tau[0] = sin(chi); - mono_arr.crystal[i].perp_to_tau[1] = 0; - mono_arr.crystal[i].perp_to_tau[2] = -cos(chi); + mono_arr.crystal[i].tau[0] = tau_size_zero * cos(chi); + mono_arr.crystal[i].tau[1] = 0; + mono_arr.crystal[i].tau[2] = tau_size_zero * sin(chi); - // Initialize lattice_spacing_gradient_field - curvature = 1/mono_arr.crystal[i].radius_horizontal; - mono_arr.crystal[i].lattice_spacing_gradient_field[0][0] = -mono_arr.crystal[i].poisson_ratio*cos(chi)*tau_size_zero*curvature; - mono_arr.crystal[i].lattice_spacing_gradient_field[0][1] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[0][2] = sin(chi) - *tau_size_zero*curvature; - mono_arr.crystal[i].lattice_spacing_gradient_field[1][0] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[1][1] = mono_arr.crystal[i].radius_vertical!=0 ? tau_size_zero*cos(chi)/mono_arr.crystal[i].radius_vertical : 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[1][2] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[2][0] = sin(chi) - *tau_size_zero*curvature; - mono_arr.crystal[i].lattice_spacing_gradient_field[2][1] = 0; - mono_arr.crystal[i].lattice_spacing_gradient_field[2][2] = -cos(chi) - *tau_size_zero*curvature; - } - free(planes); - //TODO: This is very gpu unfriendly. Should be changed to depend on OPENACC usage - // Initialize neutron structs values - neutron.beta = (double*) calloc (n_crystals, sizeof(double)); - neutron.eps_zero = (double*) calloc (n_crystals, sizeof(double)); - neutron.vert_angle = (double*) calloc (n_crystals, sizeof(double)); - neutron.horiz_angle = (double*) calloc (n_crystals, sizeof(double)); - neutron.path_length = (double*) calloc (n_crystals, sizeof(double)); - neutron.entry_time = (double*) calloc (n_crystals, sizeof(double)); - neutron.exit_time = (double*) calloc (n_crystals, sizeof(double)); - neutron.probabilities = (double*) calloc (n_crystals, sizeof(double)); - neutron.accu_probs = (double*) calloc (n_crystals, sizeof(double)); - neutron.intersection_list = (int*) calloc (n_crystals, sizeof(int)); - neutron.n = n_crystals; - neutron.direction = 1; // Default direction is going away from the instrument - counter = 0; - counter2 = 0; - MAX_REFLECTIONS = 100; // Chosen maximum number of reflections + mono_arr.crystal[i].perp_to_tau[0] = sin(chi); + mono_arr.crystal[i].perp_to_tau[1] = 0; + mono_arr.crystal[i].perp_to_tau[2] = -cos(chi); + + // Initialize lattice_spacing_gradient_field + curvature = 1 / mono_arr.crystal[i].radius_horizontal; + mono_arr.crystal[i].lattice_spacing_gradient_field[0][0] = -mono_arr.crystal[i].poisson_ratio * cos(chi) * tau_size_zero * curvature; + mono_arr.crystal[i].lattice_spacing_gradient_field[0][1] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[0][2] = sin(chi) * tau_size_zero * curvature; + mono_arr.crystal[i].lattice_spacing_gradient_field[1][0] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[1][1] = mono_arr.crystal[i].radius_vertical != 0 ? tau_size_zero * cos(chi) / mono_arr.crystal[i].radius_vertical : 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[1][2] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[2][0] = sin(chi) * tau_size_zero * curvature; + mono_arr.crystal[i].lattice_spacing_gradient_field[2][1] = 0; + mono_arr.crystal[i].lattice_spacing_gradient_field[2][2] = -cos(chi) * tau_size_zero * curvature; +} +free(planes); +// TODO: This is very gpu unfriendly. Should be changed to depend on OPENACC usage +// Initialize neutron structs values +neutron.beta = (double *)calloc(n_crystals, sizeof(double)); +neutron.eps_zero = (double *)calloc(n_crystals, sizeof(double)); +neutron.vert_angle = (double *)calloc(n_crystals, sizeof(double)); +neutron.horiz_angle = (double *)calloc(n_crystals, sizeof(double)); +neutron.path_length = (double *)calloc(n_crystals, sizeof(double)); +neutron.entry_time = (double *)calloc(n_crystals, sizeof(double)); +neutron.exit_time = (double *)calloc(n_crystals, sizeof(double)); +neutron.probabilities = (double *)calloc(n_crystals, sizeof(double)); +neutron.accu_probs = (double *)calloc(n_crystals, sizeof(double)); +neutron.intersection_list = (int *)calloc(n_crystals, sizeof(int)); +neutron.n = n_crystals; +neutron.direction = 1; // Default direction is going away from the instrument +counter = 0; +counter2 = 0; +MAX_REFLECTIONS = 100; // Chosen maximum number of reflections %} TRACE INHERIT Monochromator_bent @@ -255,88 +267,94 @@ FINALLY INHERIT Monochromator_bent MCDISPLAY %{ - double x_inner [2]; - double x_outer [2]; - double y_top; - double y_bottom; - double z_inner [2]; - double z_outer [2]; - double points[8][3]; - // We draw the monochromator by drawing lines between chosen points. - // For this reason we need to move the points, - // in accordance to their position in the array. - for (int j=0; jradius_horizontal) - xthickness/2; - // double outer_radii = inner_radii + xthickness; - double angle0, angle1, movex, movey, movez; - y_top = mono->height/2; - y_bottom = -mono->height/2; - for (i = 0; i < max_i-0.2; i = i + 0.2) { - angle0 = i/max_i*mono->angle_range + mono->min_angle; - angle1 = (i+0.2)/max_i*mono->angle_range + mono->min_angle; - // Define the 8 coordinates of the n'th box in the crystal - x_inner[0] = mono->radius_horizontal + cos(angle0)*mono->radius_inner; - x_inner[1] = mono->radius_horizontal + cos(angle1)*mono->radius_inner; +double x_inner[2]; +double x_outer[2]; +double y_top; +double y_bottom; +double z_inner[2]; +double z_outer[2]; +double points[8][3]; +// We draw the monochromator by drawing lines between chosen points. +// For this reason we need to move the points, +// in accordance to their position in the array. +for (int j = 0; j < n_crystals; j++) +{ + if (draw_as_rectangles) + { + break; + } + struct Monochromator_values *mono = &mono_arr.crystal[j]; + double max_i = 5; + double i = 0; + // double inner_radii = fabs(mono->radius_horizontal) - xthickness/2; + // double outer_radii = inner_radii + xthickness; + double angle0, angle1, movex, movey, movez; + y_top = mono->height / 2; + y_bottom = -mono->height / 2; + for (i = 0; i < max_i - 0.2; i = i + 0.2) + { + angle0 = i / max_i * mono->angle_range + mono->min_angle; + angle1 = (i + 0.2) / max_i * mono->angle_range + mono->min_angle; + // Define the 8 coordinates of the n'th box in the crystal + x_inner[0] = mono->radius_horizontal + cos(angle0) * mono->radius_inner; + x_inner[1] = mono->radius_horizontal + cos(angle1) * mono->radius_inner; - z_inner[0] = -sin(angle0)*mono->radius_inner; - z_inner[1] = -sin(angle1)*mono->radius_inner; + z_inner[0] = -sin(angle0) * mono->radius_inner; + z_inner[1] = -sin(angle1) * mono->radius_inner; - x_outer[0] = mono->radius_horizontal + cos(angle0)*mono->radius_outer; - x_outer[1] = mono->radius_horizontal + cos(angle1)*mono->radius_outer; + x_outer[0] = mono->radius_horizontal + cos(angle0) * mono->radius_outer; + x_outer[1] = mono->radius_horizontal + cos(angle1) * mono->radius_outer; - z_outer[0] = -sin(angle0)*mono->radius_outer; - z_outer[1] = -sin(angle1)*mono->radius_outer; - // These 8 coordinates define 8 points. Coordinate transform these - // to the current crystal - rotate_all_points(&x_inner[0], &x_outer[0], - &x_inner[1], &x_outer[1], - &y_top, &y_bottom, - &z_inner[0], &z_outer[0], - &z_inner[1], &z_outer[1], - points, mono); - // Draw a box in th xy plane - multiline(5, - points[0][0],points[0][1],points[0][2], - points[2][0],points[2][1],points[2][2], - points[3][0],points[3][1],points[3][2], - points[1][0],points[1][1],points[1][2], - points[0][0],points[0][1],points[0][2]); - - // Draw curving parts of crystal in the zx plane - line(points[0][0], points[0][1], points[0][2], - points[4][0], points[4][1], points[4][2]); - line(points[1][0], points[1][1], points[1][2], - points[5][0], points[5][1], points[5][2]); - line(points[2][0], points[2][1], points[2][2], - points[6][0], points[6][1], points[6][2]); - line(points[3][0], points[3][1], points[3][2], - points[7][0], points[7][1], points[7][2]); - } - // Draw a final box in the xy plane - multiline(5, - points[4][0],points[4][1],points[4][2], - points[6][0],points[6][1],points[6][2], - points[7][0],points[7][1],points[7][2], - points[5][0],points[5][1],points[5][2], - points[4][0],points[4][1],points[4][2]); + z_outer[0] = -sin(angle0) * mono->radius_outer; + z_outer[1] = -sin(angle1) * mono->radius_outer; + // These 8 coordinates define 8 points. Coordinate transform these + // to the current crystal + rotate_all_points(&x_inner[0], &x_outer[0], + &x_inner[1], &x_outer[1], + &y_top, &y_bottom, + &z_inner[0], &z_outer[0], + &z_inner[1], &z_outer[1], + points, mono); + // Draw a box in th xy plane + multiline(5, + points[0][0], points[0][1], points[0][2], + points[2][0], points[2][1], points[2][2], + points[3][0], points[3][1], points[3][2], + points[1][0], points[1][1], points[1][2], + points[0][0], points[0][1], points[0][2]); + // Draw curving parts of crystal in the zx plane + line(points[0][0], points[0][1], points[0][2], + points[4][0], points[4][1], points[4][2]); + line(points[1][0], points[1][1], points[1][2], + points[5][0], points[5][1], points[5][2]); + line(points[2][0], points[2][1], points[2][2], + points[6][0], points[6][1], points[6][2]); + line(points[3][0], points[3][1], points[3][2], + points[7][0], points[7][1], points[7][2]); } + // Draw a final box in the xy plane + multiline(5, + points[4][0], points[4][1], points[4][2], + points[6][0], points[6][1], points[6][2], + points[7][0], points[7][1], points[7][2], + points[5][0], points[5][1], points[5][2], + points[4][0], points[4][1], points[4][2]); +} - // line(0,0,0, - // -mono.perp_to_tau[0], -mono.perp_to_tau[1], -mono.perp_to_tau[2]); - if (draw_as_rectangles){ - for (int crystal=0; crystalthickness,mono->height,mono->length,mono->thickness,0,0,0); - } +// line(0,0,0, +// -mono.perp_to_tau[0], -mono.perp_to_tau[1], -mono.perp_to_tau[2]); +if (draw_as_rectangles) +{ + for (int crystal = 0; crystal < n_crystals; crystal++) + { + struct Monochromator_values *mono = &mono_arr.crystal[crystal]; + double origo[3] = {0, 0, 0}; + rotate_point(origo, mono); + // Set the box + box(origo[0], origo[1], origo[2], mono->thickness, mono->height, mono->length, mono->thickness, 0, 0, 0); } +} %} END