Skip to content
Branch: master
Find file History

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.

Files

Permalink
Type Name Latest commit message Commit time
..
Failed to load latest commit information.
doc/figs
models
src
test
thirdparty
.clang-format
.gitignore
CMakeLists.GoogleTest.cmake
CMakeLists.txt
README.md
README_zh.md
build.sh
config-example.json
format.sh

README.md

C++ codes

中文版说明

After testing my algorithms on matlab codes, I start a C++ project for higher performance. Currently the C++ version can only run from command, no GUI.

Installation

Requires: Boost (>= 1.54), OpenCV (>= 3.3), CMake (>= 3.12). Has been tested on Mac OSX 10.14 and Ubuntu 14.04.

First download the entire project,

git clone --recursive git@github.com:LoveDaisy/ice_halo_sim.git
cd ice_halo_sim/cpp

This C++ project is built with CMake. You can just run the build script to build the executable:

./build.sh release  # Release version. Max performance.

or

./build.sh debug  # Debug version

For other useful options, see the help message via ./build.sh -h or just ./build.sh.

Then the release version executable binaries will be at build/cmake_install, and the debug version will be at build/cmake_build.

Note, I introduce the GoogleTest framework to help do my unit tests. GoogleTest is a submodule of this project. Generally you do not need to care about these codes nor the test cases in test folder. If you are interested in my unit tests, please pass -t option when run the build script. If -t option is set, the test cases will be built and test on. Anf if test fails, the final executable will not be installed to build/cmake_install.

Getting started

Simulation

You can start simulatino by ./build/cmake_install/IceHaloSim <config-file>. The file config-example.json is an example configuration file. After the simulation is done you will get several .bin files in your data path set in configuration file. You can run the simulation multiple times to cumulate many data and then render them at last.

Visualization

After all simulations are done, you will get several .bin files that contain results of ray tracing, as well as several lines printed on the screen that describe crystal geometry. I have prepared several tools for visualization those results. Some are matlab codes.

  • Halo picture.
    Please run ./build/cmake_install/IceHaloRender <config-file> for visualization. I highly recommand this render your halo picture in this way, rather than the following matlab way. Just use the same configuration file as you run the simulation. The rendered picture will be placed at the data path set in configuration file.

    There is also a matlab tool for generating halo picture. Script matlab/src/read_binary_result-example.m reads the .bin files and renders the ray tracing result. See matlab folder for details.

  • Crystals
    The matlab script matlab/src/plot_crystal-example.m plots the shape of crystals. You can copy data from program output on screen. The lines start with v indicate vertex data, and those start with f indicate face data. See matlab folder for details.

Endless mode

The simulate-and-then-render way need many disk space to store the intermediate .bin files. They are data files that will be used for further analysis (not develop yet). If you do not want to save these intermediate data, then this endless mode is good for you. Please run ./build/cmake_install/IceHaloEndless <config-file> for endless mode. It runs endlessly, until you press ^+C (control + C) to force break it. It will continously refresh the output image. The total ray numbers and will be displayed on the screen.

Configuration file

This file containing all configurations. It uses JSON format. I use Rapidjson to parse JSON file.

Basic infomation for simulation

Here is an example for basic information:

"sun": {
    "altitude": 25,
    "diameter": 0.5
},
"ray": {
    "number": 500000,
    "wavelength": [420, 460, 500, 540, 580, 620],
    "weight": [1, 1, 1, 1, 1, 1]
},
"max_recursion": 8,
"data_folder": "<path-to-your-data-folder>"
  • sun: It has two attributes,

    • altitude, defining the altitude of the sun. In degree.
    • diameter, defining the actual diameter used in the simulation, in degree. Please set to 0.5 for ture sun.
  • ray: It defines some properties of rays used in simulation,

    • number, the total ray number for simulation. Note that even with a single incident ray, it may result in multiple rays output, due to reflections and refractions in crystal. This number defines the input ray number, but not output ray number. Note, this is the ray number for a single wavelength. If you want a real color simulation (thus there will be multiple wavelengths), the total number will be multiplier of this number by the number of following wavelength.
    • wavelength, the wavelengths used during simulation. It is an array contains all wavelengths you want to use. The refractive index data is from Refractive Index of Crystals.
    • weight, the weights for wavelengths. It must have the same length with wavelength.
  • max_recursion: It defines the max number that a ray hits a surface during a simulation. If a ray hits more than this number and still doesn't leave the crystal, it will be dropped.

  • data_folder: It defines where output data files should be located. The simulation program will put data into this folder and the rendering program will read data from this folder. Also the rendered image will be put in this folder. In endless mode, there is no intermediate data file, only final image will be put in this folder.

Simulation settings

Here is an example of simulation settings:

"multi_scatter": [
    {
        "crystal": [2, 1, 5, 11, 12],
        "population": [150, 100, 15, 30, 10],
        "probability": 1.0,
        "ray_path_filter": [0, 0, 0, 0, 0]
    },
    {
        "crystal": [2, 1, 5, 11, 12],
        "population": [150, 100, 15, 30, 10],
        "probability": 1.0,
        "ray_path_filter": [0, 0, 0, 0, 0]
    }
]
  • multi_scatter: It is an array defining how to perform multi/single scattering. The example defines a 2-scatter simulation. Each element in this array defines a single scattering process, and contains 4 properties:

    • crystal: what crystal(s) are used in this scattering process. It is an array, filled with crystal IDs (See the section Crystal Settings).
    • population: the crystal population. It is an array and its length must be the same with of crystal.
    • ray_path_filter: what filter(s) are used to filter out rays. It is an array and its length must be the same with of crystal. The rays filtered out are not used in the next scattering process. See the section Filter Settings for detail.
    • probability: how many output rays are used for next scattering process. If it is set to 0.5, then 50% output rays are used for next scattering process.

    Multi-scattering is a highlight feature of this project.

Rendering settings

Here is an example of rendering settings:

"camera": {
    "azimuth": 0,
    "elevation": 89.99,
    "rotation": 0,
    "fov": 95,
    "lens": "fisheye_equidistant"
},
"render": {
    "width": 4096,
    "height": 4096,
    "visible_semi_sphere": "upper",
    "ray_color": "real",
    "background_color": [0, 0, 0],
    "intensity_factor": 20,
    "offset": [0, 0]
}
  • camera: It defines properties related to camera, including:

    • azimuth, elevation, rotation: the direction where camera pointing at. In degree.
    • fov: (half) field of view, the angle from center to edge. In degree.
    • lens: lens type, can be one of these values: fisheye, linear, dual_fisheye_equidistant, dual_fisheye_equiarea.
  • render: It defines some useful attributes used when rendering:

    • width, height: the size of output image. In pixel.
    • visible_semi_sphere, which semi-sphere should be rendered. The example value is uppper, indicating the upper semi sphere should be rendered, and the lower one will be black, which is the common scene. If it is set to lower, then halos that occure under horizontal, say, subparhilia, will be rendered. The values could be one of these: upper, lower, camera, full.
    • intensity_factor, controls the intensity. The value locates between 0.01 and 100.0.
    • offset, defines the rendering offset. In pixel.
    • ray_color, defines the color used to plot the ray scatter points. It can be a 3-element array defining the RGB color, or can be a string 'real' indicating to use real colors. NOTE: RGB value must between 0.0 and 1.0.
      Real-color is also a highlighted feature of this project.
    • background_color, defines the RGB color used for background. Each element must be between 0.0 and 1.0.

Crystal settings

Here is an example of it:

"crystal": [
    {
        "id": 1,
        "type": "HexPrism",
        "parameter": 2.4,
        "zenith": {
            "mean": 90,
            "std": 0.3,
            "type": "gauss"
        },
        "roll": {
            "mean": 0,
            "std": 0,
            "type": "uniform"
        }
    },
    {
        "id": 10,
        "type": "HexPyramid",
        "parameter": [0.0, 0.0, 0.2],
        "zenith": {
            "mean": 0,
            "std": 0.3,
            "type": "gauss"
        },
        "roll": {
            "mean": 0,
            "std": 0,
            "type": "uniform"
        }
    },
    {
        "id": 3,
        "type": "IrregularHexPyramid",
        "parameter": [1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 0.3, 0.8, 0.3],
        "zenith": {
            "mean": 90,
            "std": 0.8,
            "type": "gauss"
        },
        "roll": {
            "mean": 0,
            "std": 0,
            "type": "uniform"
        }
    },
    {
        "id": 9,
        "type": "CubicPyramid",
        "parameter": [0.8, 0.8],
        "zenith": {
            "mean": 90,
            "std": 0.3,
            "type": "gauss"
        },
        "roll": {
            "mean": 0,
            "std": 0,
            "type": "uniform"
        }
    }
]
  • id is the ID for this crystal. It is the only reference used in other settings, e.g. in multi-scatter settings. It should be a unique number greater than 0. It is not necessary to keep IDs increasing one by one.

  • zenith, roll and azimuth (optional): These fields defines the orientation of crystals. zenith defines the c-axis orientation, and roll defines the rotation around c-axis.

    These fields all has three attributes, mean, std, type.

    • type defines the random distribution type, either gauss, for Gaussian distribution, or uniform, for uniform distribution. NOTE: if type of axis is uniform, then mean and std will be ignored and the axis will uniformly distributed on sphere. Similarly, if type of roll is uniform then it will uniformly distributed between 0 and 360 degree.
    • mean defines the mean of random distribution. For example for zenith it means the zenith angle.
    • std defines the deviation of the distribution. For Gaussian distribution, it is the standard deviation, and for uniform distribution, it defines the value range.

    All angles are in degrees.

  • population: It defines how many crystals used in a simulation. Note that it is not the actual number, just for a ratio. So if one crystal set to 2.0 and the other set to 3.0, it is equivalent to set one to 20 and the other to 30.

  • type and parameter: Currently there are 7 crystal shapes, HexPrism, HexPyramid, HexPyramidStackHalf, IrregularHexPrism, IrregularHexPyramid, CubicPyramid, Custom. Each shape has its own shape parameters.

    • HexPrism: Only 1 parameter, defines h / a where h is the prism height, a is the diameter along a-axis (also x-axis in my program).
      .

    • HexPyramid: May have 3, 5, or 7 parameters.

      • For 3 parameters case, they are h1 / H1, h2 / a, h3 / H3 respectly, where H1 means the max possible height for upper pyramid segment, and H3 the same but for lower pyramid segment.
        .
      • For 5 parameters case, the last 3 parameters are same as the first case, and the first 2 parameters indicate the face direction. They must be integers. The face direction is described with Miller index. For example, a, b, represents a face with Miller index of (a, 0, -a, b). For a typical ice crystal face (face number 13), its Miller index is (1, 0, -1, 1). So it can be described using parameters 1, 1.
      • For 7 parameters case, the first 4 parameters are interges and describe the upper and lower pyramid segment face directions. For example a, b, c, d describe upper pyramid segment with Miller index of (a, 0, -a, b) and lower pyramid segment of (c, 0, -c, d). NOTE: for faces with different Miller index, their maximumn height H for pyramid segment are also different.

      With these description, you will have the maximized freedom to design your crystal shape.

    • HexPyramidStackHalf: 7 parameters. Similar to 7 parameters HexPyramid case. h / H for pyramid segment, and h / a for prism segment.
      .

    • IrregularHexPrism: Last parameter is height of the crystal. The distance factor here means the ratio of actual distance w.r.t regular haxegon distance. Thus, a regular haxegon has distance of [1, 1, 1, 1, 1, 1]. The following figure shows an irregular hexegon with distance of [1.1, 0.9, 1.5, 0.9, 1.7, 1.2]
      .

    • IrregularHexPyramid: 13 parameters. First 6 parameters define the prism face distance from the origin. Next 4 parameters are Miller index describing upper and lower pyramid segment. Last 3 parameters are heights of each segment, from upper to lower.
      .

    • CubicPyramid: 2 parameters. Similar to cases above, the 2 parameters defines h1 / H1 and h2 / H2.
      NOTE: this kind crystal has cubic system.
      .

    • Custom: 1 parameters that indicates the model file name.
      Customized crystal type supports Wavefront obj file format. It is an ASCII based 3D model file format, which means it is human read-frendly and you can open and edit the model file with any text editor. Of course it is a better and elegent way to create your crystal in a 3D modeling software, such as Maya, 3DMax, Blender, etc.
      NOTE: Though the obj file can contain polygons having more than 3 vertexes, my program can only handle triangles. A face is only represented with its first 3 vertexes (if you set more than 3). Currently my program cannot handle vertex texture nor vertex normal information. Please make sure your obj file does not contain any of them (the face line does not contain any slashes).

TODO list

  • Use OpenCL / OpenGL / CUDA to accelerate. Since I've seen good enough performance with a simple threading pool implemented by myself, I doubt the margin to more improvements.
  • Write a (web) GUI for these code.
You can’t perform that action at this time.