<commit_before>package se.raddo.raddose3D;

import java.util.HashMap;
import java.util.Map;

import javax.management.RuntimeErrorException;

/**
 * The CrystalCuboid class is for a cuboid-shaped crystal with a given start
 * orientation and position defined by:
 * - x,y,z sizes in um
 * - crystres in 1/um
 * - starting angles P and L.
 * - A coefCalc object
 */

public class CrystalCuboid extends Crystal {

  /** Resolution of crystal in 1/um. */
  private final double         crystalPixPerUM;

  /**
   * Initial orientation of the crystal in the plane of the loop (right handed
   * rotation about z) and of the loop (right handed rotation about x) in
   * radians.
   */
  private final double         p, l;

  /**
   * 3 element array defining dimensions of
   * bounding box of crystal in um.
   */
  private final double[]       crystSizeUM;

  /** 3 element array defining dimensions of bounding box in voxels. */
  private final int[]          crystSizeVoxels;

  /**
   * Dose and fluence arrays holding the scalar
   * fields for these values at voxel i,j,k.
   */
  private double[][][]         dose, fluence, elastic;

  /**
   * 4d array where the 4th dimension is a 3 element array with the coordinates
   * of the voxel i,j,k in the starting position.
   */
  private final double[][][][] crystCoord;

  /**
   * 8 by 3 double array that defines the xyz coordinates of the crystal in its
   * starting position.
   */
  private final double[][]     vertices;

  private double[][]           verticesRotatedNormals;
  private double[][]           verticesRotatedv1s;
  private double[]             verticesRotatedDenominators;

  /**
   * 6 by 4 integer array that defines the faces of the crystal, each 4 element
   * row represents the vertices that make up that face.
   */
  private final int[][]        face = {
                                    { 5, 8, 7, 6 },
                                    { 1, 2, 3, 4 },
                                    { 4, 3, 7, 8 },
                                    { 5, 6, 2, 1 },
                                    { 1, 4, 8, 5 },
                                    { 6, 7, 3, 2 }
                                    };

  /**
   * Generic property constructor for cuboid crystals. Extracts all required
   * information from a Map data structure.
   * *
   * Used properties:
   * CRYSTAL_DIM_X
   * CRYSTAL_DIM_Y
   * CRYSTAL_DIM_Z
   * CRYSTAL_RESOLUTION (optional. Default: use getDefaultLimitedResolution)
   * CRYSTAL_ANGLE_P (optional. Default: 0)
   * CRYSTAL_ANGLE_L (optional. Default: 0)
   * 
   * @param properties
   *          Map of type <Object, Object> that contains all crystal properties.
   *          The keys of the Map are defined by the constants in the
   *          {@link Crystal} class.
   */
  public CrystalCuboid(final Map<Object, Object> properties) {
    // Pass properties to Crystal()-constructor
    super(properties);

    // Check if optional values are initialized, otherwise set to defaults.
    Map<Object, Object> mergedProperties = new HashMap<Object, Object>();
    mergedProperties.put(Crystal.CRYSTAL_ANGLE_P, 0d);
    mergedProperties.put(Crystal.CRYSTAL_ANGLE_L, 0d);
    mergedProperties.putAll(properties);

    // Check for valid parameters
    Assertions a = new Assertions("Could not create cuboid crystal: ");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_DIM_X), Double.class,
        "no X dimension specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_DIM_Y), Double.class,
        "no Y dimension specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_DIM_Z), Double.class,
        "no Z dimension specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_ANGLE_P), Double.class,
        "no P angle specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_ANGLE_L), Double.class,
        "no L angle specified");

    Double xdim = (Double) mergedProperties.get(Crystal.CRYSTAL_DIM_X);
    Double ydim = (Double) mergedProperties.get(Crystal.CRYSTAL_DIM_Y);
    Double zdim = (Double) mergedProperties.get(Crystal.CRYSTAL_DIM_Z);

    if ((mergedProperties.get(Crystal.CRYSTAL_RESOLUTION) == null)
        || (!Double.class.isAssignableFrom(
            mergedProperties.get(Crystal.CRYSTAL_RESOLUTION).getClass()))) {
      mergedProperties.put(Crystal.CRYSTAL_RESOLUTION,
          getDefaultLimitedResolution(xdim, ydim, zdim));
    }

    // Assign the final variables that can be set directly from the constructor
    crystalPixPerUM = (Double) mergedProperties.get(Crystal.CRYSTAL_RESOLUTION);
    p = Math.toRadians((Double) mergedProperties.get(Crystal.CRYSTAL_ANGLE_P));
    l = Math.toRadians((Double) mergedProperties.get(Crystal.CRYSTAL_ANGLE_L));

    double[] tempCrystDim = { xdim, ydim, zdim };
    crystSizeUM = tempCrystDim; // Final Value

    // Set number of voxels to match crystal dimensions
    int nx = (int) StrictMath.round(xdim * crystalPixPerUM) + 1;
    int ny = (int) StrictMath.round(ydim * crystalPixPerUM) + 1;
    int nz = (int) StrictMath.round(zdim * crystalPixPerUM) + 1;
    int[] tempCrystSize = { nx, ny, nz };
    crystSizeVoxels = tempCrystSize; // Final Value

    // Initialise dose, elastic, and fluence to the correct size
    dose = new double[nx][ny][nz];
    fluence = new double[nx][ny][nz];
    elastic = new double[nx][ny][nz];

    /*
     * Calculate Crystal Coordinates, and assign them:
     */

    double[][][][] tempCrystCoords = new double[nx][ny][nz][3];

    for (int i = 0; i < nx; i++) {
      for (int j = 0; j < ny; j++) {
        for (int k = 0; k < nz; k++) {

          /*
           * Set original coordinate. Temporary variables needed since we use
           * all of the previous xyz's to set each of the new ones.
           */
          double x = -xdim / 2 + i / crystalPixPerUM;
          double y = -ydim / 2 + j / crystalPixPerUM;
          double z = -zdim / 2 + k / crystalPixPerUM;

          /*
           * rotation in plane about [0 0 1] (P) Temporary variables needed
           * since we use all of the previous xyz's to set each of the new ones.
           */
          double x2 = x * Math.cos(p) + y * Math.sin(p);
          double y2 = -1 * x * Math.sin(p) + y * Math.cos(p);
          double z2 = z;

          /*
           * rotation loop about [1 0 0] (L)
           */
          tempCrystCoords[i][j][k][0] = x2;
          tempCrystCoords[i][j][k][1] = y2 * Math.cos(l) + z2 * Math.sin(l);
          tempCrystCoords[i][j][k][2] = -1 * y2 * Math.sin(l) + z2
              * Math.cos(l);
        }
      }
    }

    crystCoord = tempCrystCoords; // Final value

    /*
     * Set initial vertex positions:
     */

    // make sure rounding errors don't put voxels outside the surface
    double delta = 10 / crystalPixPerUM;

    // Set initial positions of vertices
    double[][] makeVertices = {
        { xdim / 2 + delta, ydim / 2 + delta, zdim / 2 + delta },
        { -xdim / 2 - delta, ydim / 2 + delta, zdim / 2 + delta },
        { -xdim / 2 - delta, -ydim / 2 - delta, zdim / 2 + delta },
        { xdim / 2 + delta, -ydim / 2 - delta, zdim / 2 + delta },
        { xdim / 2 + delta, ydim / 2 + delta, -zdim / 2 - delta },<commit_msg>Added a fix to bug reported by Helen, and added extra commends to help explain this. Not tested.<commit_after>package se.raddo.raddose3D;

import java.util.HashMap;
import java.util.Map;

import javax.management.RuntimeErrorException;

/**
 * The CrystalCuboid class is for a cuboid-shaped crystal with a given start
 * orientation and position defined by:
 * - x,y,z sizes in um
 * - crystres in 1/um
 * - starting angles P and L.
 * - A coefCalc object
 */

public class CrystalCuboid extends Crystal {

  /** Resolution of crystal in 1/um. */
  private final double         crystalPixPerUM;

  /**
   * Initial orientation of the crystal in the plane of the loop (right handed
   * rotation about z) and of the loop (right handed rotation about x) in
   * radians.
   */
  private final double         p, l;

  /**
   * 3 element array defining dimensions of
   * bounding box of crystal in um.
   */
  private final double[]       crystSizeUM;

  /** 3 element array defining dimensions of bounding box in voxels. */
  private final int[]          crystSizeVoxels;

  /**
   * Dose and fluence arrays holding the scalar
   * fields for these values at voxel i,j,k.
   */
  private double[][][]         dose, fluence, elastic;

  /**
   * 4d array where the 4th dimension is a 3 element array with the coordinates
   * of the voxel i,j,k in the starting position.
   */
  private final double[][][][] crystCoord;

  /**
   * 8 by 3 double array that defines the xyz coordinates of the crystal in its
   * starting position.
   */
  private final double[][]     vertices;

  private double[][]           verticesRotatedNormals;
  private double[][]           verticesRotatedv1s;
  private double[]             verticesRotatedDenominators;

  /**
   * 6 by 4 integer array that defines the faces of the crystal, each 4 element
   * row represents the vertices that make up that face.
   */
  private final int[][]        face = {
                                    { 5, 8, 7, 6 },
                                    { 1, 2, 3, 4 },
                                    { 4, 3, 7, 8 },
                                    { 5, 6, 2, 1 },
                                    { 1, 4, 8, 5 },
                                    { 6, 7, 3, 2 }
                                    };

  /**
   * Generic property constructor for cuboid crystals. Extracts all required
   * information from a Map data structure.
   * *
   * Used properties:
   * CRYSTAL_DIM_X
   * CRYSTAL_DIM_Y
   * CRYSTAL_DIM_Z
   * CRYSTAL_RESOLUTION (optional. Default: use getDefaultLimitedResolution)
   * CRYSTAL_ANGLE_P (optional. Default: 0)
   * CRYSTAL_ANGLE_L (optional. Default: 0)
   * 
   * @param properties
   *          Map of type <Object, Object> that contains all crystal properties.
   *          The keys of the Map are defined by the constants in the
   *          {@link Crystal} class.
   */
  public CrystalCuboid(final Map<Object, Object> properties) {
    // Pass properties to Crystal()-constructor
    super(properties);

    // Check if optional values are initialized, otherwise set to defaults.
    Map<Object, Object> mergedProperties = new HashMap<Object, Object>();
    mergedProperties.put(Crystal.CRYSTAL_ANGLE_P, 0d);
    mergedProperties.put(Crystal.CRYSTAL_ANGLE_L, 0d);
    mergedProperties.putAll(properties);

    // Check for valid parameters
    Assertions a = new Assertions("Could not create cuboid crystal: ");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_DIM_X), Double.class,
        "no X dimension specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_DIM_Y), Double.class,
        "no Y dimension specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_DIM_Z), Double.class,
        "no Z dimension specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_ANGLE_P), Double.class,
        "no P angle specified");
    a.checkIsClass(mergedProperties.get(Crystal.CRYSTAL_ANGLE_L), Double.class,
        "no L angle specified");

    Double xdim = (Double) mergedProperties.get(Crystal.CRYSTAL_DIM_X);
    Double ydim = (Double) mergedProperties.get(Crystal.CRYSTAL_DIM_Y);
    Double zdim = (Double) mergedProperties.get(Crystal.CRYSTAL_DIM_Z);

    if ((mergedProperties.get(Crystal.CRYSTAL_RESOLUTION) == null)
        || (!Double.class.isAssignableFrom(
            mergedProperties.get(Crystal.CRYSTAL_RESOLUTION).getClass()))) {
      mergedProperties.put(Crystal.CRYSTAL_RESOLUTION,
          getDefaultLimitedResolution(xdim, ydim, zdim));
    }

    // Assign the final variables that can be set directly from the constructor
    crystalPixPerUM = (Double) mergedProperties.get(Crystal.CRYSTAL_RESOLUTION);
    p = Math.toRadians((Double) mergedProperties.get(Crystal.CRYSTAL_ANGLE_P));
    l = Math.toRadians((Double) mergedProperties.get(Crystal.CRYSTAL_ANGLE_L));

    double[] tempCrystDim = { xdim, ydim, zdim };
    crystSizeUM = tempCrystDim; // Final Value

    // Set number of voxels to match crystal dimensions
    int nx = (int) StrictMath.round(xdim * crystalPixPerUM) + 1;
    int ny = (int) StrictMath.round(ydim * crystalPixPerUM) + 1;
    int nz = (int) StrictMath.round(zdim * crystalPixPerUM) + 1;
    int[] tempCrystSize = { nx, ny, nz };
    crystSizeVoxels = tempCrystSize; // Final Value

    // Initialise dose, elastic, and fluence to the correct size
    dose = new double[nx][ny][nz];
    fluence = new double[nx][ny][nz];
    elastic = new double[nx][ny][nz];

    /*
     * Calculate Crystal Coordinates, and assign them:
     */

    double[][][][] tempCrystCoords = new double[nx][ny][nz][3];

    for (int i = 0; i < nx; i++) {
      for (int j = 0; j < ny; j++) {
        for (int k = 0; k < nz; k++) {

          /*
           * Set original coordinate. Temporary variables needed since we use
           * all of the previous xyz's to set each of the new ones.
           */
          double x = -xdim / 2 + i / crystalPixPerUM;
          double y = -ydim / 2 + j / crystalPixPerUM;
          double z = -zdim / 2 + k / crystalPixPerUM;

          /*
           * rotation in plane about [0 0 1] (P) Temporary variables needed
           * since we use all of the previous xyz's to set each of the new ones.
           */
          double x2 = x * Math.cos(p) + y * Math.sin(p);
          double y2 = -1 * x * Math.sin(p) + y * Math.cos(p);
          double z2 = z;

          /*
           * rotation loop about [1 0 0] (L)
           */
          tempCrystCoords[i][j][k][0] = x2;
          tempCrystCoords[i][j][k][1] = y2 * Math.cos(l) + z2 * Math.sin(l);
          tempCrystCoords[i][j][k][2] = -1 * y2 * Math.sin(l) + z2
              * Math.cos(l);
        }
      }
    }

    crystCoord = tempCrystCoords; // Final value

    /*
     * Set initial vertex positions. A constant 'delta' is added to each vertex so that the voxels
     * on the surface do not appear beyond the faces defined by the vertices. Basically, the box 
     * bounded by the vertices is slightly bigger than the box bounded by the voxels, and so when we 
     * rotate everything, the voxels never end up outside the 'vertex' box due to rounding errors.
     */

    // make sure rounding errors don't put voxels outside the surface. Should be small relative to voxel size.
    double delta = 1 / 10*crystalPixPerUM;

    // Set initial positions of vertices
    double[][] makeVertices = {
        { xdim / 2 + delta, ydim / 2 + delta, zdim / 2 + delta },
        { -xdim / 2 - delta, ydim / 2 + delta, zdim / 2 + delta },
        { -xdim / 2 - delta, -ydim / 2 - delta, zdim / 2 + delta },
        { xdim / 2 + delta, -ydim / 2 - delta, zdim / 2 + delta },
        { xdim / 2 + delta, ydim / 2 + delta, -zdim / 2 - delta },
{'fraction_non_alphanumeric': 0.10781887499163935, 'fraction_numerical': 0.011838672998461641, 'mean_word_length': 2.298477829252151, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1999429', 'n_tokens_mistral': 4939, 'n_tokens_neox': 4582, 'n_words': 1457}