tool
povray
borgShapeViewer
borgWarp
ADDA

ADDA > tool > make_pov_png_180121.py > v0.1-v0.7 > to make [Povray file] and [png files] of the particle shape from the [IntField-Y] in terms of (slant, top, front, and side) views

Tested_Environment
GeForce GTX 1070 (8GB)
ASRock Z170M Pro4S [Intel Z170chipset]
Ubuntu 16.04 LTS desktop amd64
TensorFlow v1.2.1
cuDNN v5.1 for Linux
CUDA v8.0
Python 3.5.2
Numpy v1.13.1
IPython 6.0.0 -- An enhanced Interactive Python.
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
scipy v0.19.1
geopandas v0.3.0
MATLAB R2017b (Home Edition)
ADDA v.1.3b6
POV-Ray 3.7.0.unofficial

This article is related to ADDA (light scattering simulator based on the discrete dipole approximation).

About

In this article, a tool to make Povray file and png files of the particle shape is introduced.

By using the Matplotlib, it took 43 minutes to show the Chebyshev particle with N=206,800.
(see. this article for the detail).
Instead of using the Matplotlib, Povray is used to render the images.

The tool processes as follows:

  1. read (x,y,z) positions in the [LN-IntField-Y]
    • [LN-IntField-Y] is the symbolic link of [IntField-Y]
  2. created Povray file based on the coordinates
    • for 4 views (slant, top, front, and side)
  3. render the image by executing the Povray

IntField-Y: Input file

The following is the example command to create [IntField-Y] using ADDA.

./adda -shape cylinder 1.5 -store_int_field -grid 26 -maxiter 10 

Where, the -maxiter is used because the calculation do not need to be finished with the high accuracy. Only the position information in the 'IntField-Y' is used.

In another case, the users can use [IntField-Y] for the calculation where the iterative solver converges with the desired accuracy where the -maxiter is not specified.

code

Requirements

Following tools are required.

  • Python 3 (e.g. Python 3.5.2)
  • Numpy (e.g. Numpy v1.13.1)
  • Povray (e.g. POV-Ray 3.7.0.unofficial)

Python script (make_pov_png_180121.py v0.1-v0.7)

Following is the Python script named make_pov_png_180121.py used to create Povray file and png files.

make_pov_png_180121.py
import numpy as np
import sys
import subprocess as sb

'''
v0.7 Jan. 27, 2018
  - ** rename [make_pov_180121.py] to [make_pov_png_180121.py]
  - create also (top, front, side) images
  - refactor > reposition constants definitions
  - execute povray command
  - add make_pov_file()
  - read [IntField-Y] file instead of (x,y,z) file
v0.6 Jan. 27, 2018
  - refactor
    + from [IN_FILE] to [IN_FILE_XYZ]
v0.5 Jan. 23, 2018
  - convert [right-handed] to [left-handed] coordinate
    + interchange y and z
v0.4 Jan. 23, 2018 viewing geometry
  - [light_source] takes [LOCX], [LOCY], [LOCZ]
  - change [camera.location]
    + main() change [CONFIG_FORMAT]
    + add calc_xyz()
    + [CONFIG_FORMAT] takes [LOCX], [LOCY], [LOCZ]
    + add [VIEW_RADIUS]
    + add [ELEVATION_DEG], [AZIMUTH_DEG]
v0.3 Jan., 21, 2018
  - each particle is colored
  - [SHAPE_FORMAT] has color value template
    + [RED], [GREEN], [BLUE]
v0.2 Jan., 21, 2018
  - tweak [MONOMER_RADIUS] from 0.5 to 0.25
v0.1 Jan., 21, 2018
  - output [.pov] file
    + add main()
  - add [SHAPE_FORMAT]
  - add [CONFIG_FORMAT]
'''

# tested on Python 3.5.2
# coding rule: PEP8

CONFIG_FORMAT = """
camera {
  location <LOCX, LOCY, LOCZ>
  look_at <0, 0, 0>
}
light_source { <LOCX, LOCY, LOCZ>
  color rgb <1.0, 1.0, 1.0>
}

background{color rgb <1.0,1.0,1.0>}
"""

SHAPE_FORMAT = """
sphere { <XXX, YYY, ZZZ>, RRR
  texture {
    pigment { color rgb <RED,GREEN,BLUE> }
    finish {      ambient 0.4    }
  }
}
"""

# IN_FILE_XYZ = 'LN-SHAPE'
IN_FILE_INTFIELD_Y = 'LN-IntField-Y'  # LN: symbolic link file
OUT_FILE = "shape_180121.pov"
MONOMER_RADIUS = 0.25

RGBSET = [
    [0.40000000000000002, 0.76078431372549016, 0.6470588235294118],
    [0.40000000000000002, 0.76078431372549016, 0.6470588235294118],
    [0.9882352941176471, 0.55294117647058827, 0.3843137254901961],
    [0.55294117647058827, 0.62745098039215685, 0.79607843137254897],
    [0.90588235294117647, 0.54117647058823526, 0.76470588235294112],
    [0.65098039215686276, 0.84705882352941175, 0.32941176470588235],
    [0.65098039215686276, 0.84705882352941175, 0.32941176470588235],
    [1.0, 0.85098039215686272, 0.18431372549019609],
    [0.89803921568627454, 0.7686274509803922, 0.58039215686274515],
    [0.70196078431372544, 0.70196078431372544, 0.70196078431372544],
    [0.70196078431372544, 0.70196078431372544, 0.70196078431372544],
]

X_MAX = 10  # used to set colors based on the x position


def calc_xyz(theta_deg, phi_deg, radius):
    ath = np.deg2rad(theta_deg)
    aph = np.deg2rad(phi_deg)
    x = radius * np.cos(aph) * np.sin(ath)
    y = radius * np.sin(aph) * np.sin(ath)
    z = radius * np.cos(ath)
    return x, y, z


def read_IntFieldY(filepath):
    # skip 1st row (title)
    dat = np.genfromtxt(filepath, skip_header=1)
    # extract only first 3 columns (x,y,z)
    wrk = dat[:, :3]
    return wrk


def make_pov_file(filepath, azenith, aazimuth):
    # dat = np.genfromtxt(IN_FILE_XYZ)
    dat = read_IntFieldY(filepath)
    with open(OUT_FILE, 'wb+') as fd:
        # camera position and lightsource position
        cax, cay, caz = calc_xyz(azenith, aazimuth, VIEW_RADIUS)
        wrk = CONFIG_FORMAT.replace('LOCX', '%s' % cax)
        wrk = wrk.replace('LOCY', '%s' % caz)  # left-handed coord.
        wrk = wrk.replace('LOCZ', '%s' % cay)  # left-handed coord.
        wrk = np.array(wrk).reshape(1,)
        np.savetxt(fd, wrk, fmt='%s')
        # each monomer
        for elem in dat:
            wrk = SHAPE_FORMAT.replace('XXX', '%s' % elem[0])
            # position (left-handed coordinate)
            wrk = wrk.replace('YYY', '%s' % elem[2])
            wrk = wrk.replace('ZZZ', '%s' % elem[1])
            #
            wrk = wrk.replace('RRR', '%s' % MONOMER_RADIUS)
            # color
            #    clidx = (elem[0] - (-50)) / (50 - (-50))
            clidx = (elem[0] - (-X_MAX)) / (X_MAX - (-X_MAX))
            clidx = clidx * len(RGBSET)
            if clidx < 0.0:
                clidx = 0.0
            if clidx > X_MAX:
                clidx = X_MAX
            acol = RGBSET[int(clidx)]
            wrk = wrk.replace('RED', '%s' % acol[0])
            wrk = wrk.replace('GREEN', '%s' % acol[1])
            wrk = wrk.replace('BLUE', '%s' % acol[2])
            #
            wrk = np.array(wrk).reshape(1,)
            np.savetxt(fd, wrk, fmt='%s')
    print('[%s] is created' % OUT_FILE)


def make_png_file(infile, azenith, aazimuth, suffix):
    make_pov_file(infile, azenith, aazimuth)
    outfile = OUT_FILE.replace('.', suffix + '.')
    cmd = 'mv %s %s' % (OUT_FILE, outfile)
    sb.call(cmd.split())
    cmd = 'povray ' + outfile
    sb.call(cmd.split())
    #
    msg = ''
    msg += '[%s] is created\n' % outfile
    msg += '[%s] is created\n' % outfile.replace('pov', 'png')
    return msg

# viewing geometry
ELEVATION_DEG = 30.0  # elevation angle [degree]
AZIMUTH_DEG = -60.0  # azimuth angle [degree]
VIEW_RADIUS = 30.0  # radius of the viewing geometry
#
zenith_deg = 90.0 - ELEVATION_DEG  # zenith angle [degree]


def main():
    infile = IN_FILE_INTFIELD_Y
    msg = ''
    msg += make_png_file(infile, zenith_deg, AZIMUTH_DEG, '_slant')
    msg += make_png_file(infile, 0, 0, '_top')
    msg += make_png_file(infile, 90, 0, '_front')
    msg += make_png_file(infile, 90, -90, '_side')
    print(msg)
    msg = 'To view images at once, open [view_180128.html]\n'
    msg += 'on your web browser\n'
    msg += 'e.g. google-chrome view_180128.html'
    print(msg)

if __name__ == '__main__':
    main()

html to view outputs (view_180128.html v0.1)

The following is a html file to view the output files on the Web browser.

view_180128.html
<!--
v0.1 Jan. 28, 2018
  - show 4 images
-->
<html>
<table>

<tr>
<td>slant (Theta=60deg, Phi=-60deg)</td><td>top</td>
</tr>
<tr>
<td><img src=shape_180121_slant.png></td>
<td><img src=shape_180121_top.png></td>
</tr>

<tr>
<td>front</td><td>side</td>
</tr>
<tr>
<td><img src=shape_180121_front.png></td>
<td><img src=shape_180121_side.png></td>
</tr>

</table>
</html>

How to use

1. prepare [LN-IntField-Y]

Following is the example of the symbolic linkage of the ADDA output.

$ln -fs ../CALC_180117_MUELLER/gHN_N0500_THETA_1p0/run44242_chebyshev_g104_m1.5/IntField-Y LN-IntField-Y

Also, instead of the symbolic link, the user can copy the ADDA output in the name of [LN-IntField-Y].

2. run the script

$python3 make_pov_png_180121.py 
...
...
...
...
...
...
Render Time:
  Photon Time:      No photons
  Radiosity Time:   No radiosity
  Trace Time:       0 hours  0 minutes  0 seconds (0.122 seconds)
              using 8 thread(s) with 0.523 CPU-seconds total
POV-Ray finished

[shape_180121_slant.pov] is created
[shape_180121_slant.png] is created
[shape_180121_top.pov] is created
[shape_180121_top.png] is created
[shape_180121_front.pov] is created
[shape_180121_front.png] is created
[shape_180121_side.pov] is created
[shape_180121_side.png] is created

To view images at once, open [view_180128.html]
on your web browser
e.g. google-chrome view_180128.html

3. view the images

As shown in the Step2, output files can be viewed by reading [view_180128.html].
For example, with the Google Chrome, following command can be used (depending on the OS).
(Or, drag and drop the [view_180182.html] file onto the web browser).

$google-chrome view_180128.html

Then, in the web browser, the user can see the following images.

qiita.png

Output example

bisphere

command: './adda -shape bisphere 1.0 -store_int_field -grid 26 -maxiter 10 '

N=18,656
Processing time: 8.287sec

qiita.png

Capsule

command: './adda -shape capsule 1.5 -store_int_field -grid 26 -maxiter 10 '

N=30,280
Processing time: 9.986sec

qiita.png

Cylinder

command: './adda -shape cylinder 1.5 -store_int_field -grid 26 -maxiter 10 '

N=21,600
Processing time: 8.524sec

qiita.png

Egg

command: './adda -shape egg 0.7 0.5 -store_int_field -grid 26 -maxiter 10 '

N=13,748
Processing time: 7.740sec

qiita.png

Sphere

command: './adda -shape sphere -store_int_field -grid 26 -maxiter 10 '

N=9,328
Processing time: 6.968sec

qiita.png

Chebyshev

command: './adda -shape chebyshev 0.7 12 -grid 104 -store_int_field -maxiter 10 -eq_rad 6.299605 '

N=206,800
Processing time: 32.261sec

qiita.png