NEFM-TUDresden / MCRpy

Microstructure Characterization and Reconstruction in Python
Apache License 2.0
40 stars 14 forks source link

Reconstruct microstructure from pymks two point correlation data #1

Closed owaisahmad18 closed 1 year ago

owaisahmad18 commented 1 year ago

data_correlation = TwoPointCorrelation( periodic_boundary=True, cutoff=25, correlations=[(0,0),(0,1)] ).transform(data)

how can i use the output from TwoPointCorrelation command in pymks package and feed it to MCRpy to reconstruct microstructure. please help.

s5409693 commented 1 year ago

Please excuse the delayed response, I did not receive a notification of the opened issue.

The easiest approach would be to use the TwoPointCorrelation descriptor of MCRpy, which is a differentiable approximatio to the TwoPointCorrelation in pyMKS. Or even better, you could use the three-point correlations, which are called Correlations in MCRpy.

Alternatively, if you really need to use the version from pymks, then you can convert the two. The conversion formula is given in this work https://www.researchgate.net/publication/352036973_Reconstructing_random_heterogeneous_media_through_differentiable_optimization in Equation 27. Note that pyMKS provides all symmetrically equivalent entries of S2, which MCRpy does not. Also, the entries are sorted in a different way. An example implementation for this conversion is given here:

import numpy as np

from pymks import TwoPointCorrelation
import mcrpy

cutoff = 25
limit_to = cutoff + 1
ms = np.load('mcrpy/example_microstructures/pymks_ms_64x64_2.npy') # this example is included in the MCRpy GitHub repo

pymks_correlations = TwoPointCorrelation(correlations=[(1, 1)], cutoff=cutoff, periodic_boundary=True).transform(
        np.expand_dims(np.stack([1-ms, ms], axis=-1), axis=0)) # note that we compute only the autocorrelation of phase 1

settings = mcrpy.CharacterizationSettings(
    descriptor_types=['TwoPointCorrelations'], limit_to=limit_to, use_multigrid_descriptor=False, use_multiphase=False)
mcrpy_correlations = mcrpy.characterize(ms, settings)['TwoPointCorrelations']

def compute_factor(settings: mcrpy.CharacterizationSettings) -> float:
    zl = 1 / (1 + np.exp(0.75 * settings.threshold_steepness))
    zu = 1 / (1 + np.exp(-(0.25 * settings.threshold_steepness) ))
    a = 1 / (zu - zl)
    b = -a * zl
    sigmoid = lambda z: 1/(1 + np.exp(-z))
    return sigmoid(-0.25 * settings.threshold_steepness) * a + b

def correct_thresholding(pcs: np.array, settings: mcrpy.CharacterizationSettings) -> np.array:
    ft05 = compute_factor(settings) # Equation 27
    factor = 2 * ft05 ** 2
    pcs[1:] = (1 - factor) * pcs[1:] + factor * pcs[0]
    return pcs

def sort_pymks_to_mcrpy(pymks_s2: np.ndarray, limit_to: int) -> np.ndarray:
    assert pymks_s2.shape[0] == 1
    assert pymks_s2.shape[-1] == 1
    assert len(pymks_s2.shape) == 4
    pymks_s2 = pymks_s2[0, ..., 0]

    out = []
    for i in range(limit_to):
        for j in range(limit_to):
            out.append(pymks_s2[cutoff + i, cutoff + j])
    for i in range(1, limit_to):
        for j in range(1, limit_to):
            out.append(pymks_s2[cutoff + i, cutoff - j])
    return np.array(out)

def convert_pymks_to_mcrpy(pymks_correlations: np.ndarray, settings: mcrpy.CharacterizationSettings) -> np.ndarray:
    return correct_thresholding(sort_pymks_to_mcrpy(pymks_correlations, settings.limit_to), settings)

def error(a, b):
    return np.max(np.abs(a - b))

print(error(convert_pymks_to_mcrpy(pymks_correlations, settings), mcrpy_correlations)) # should be around 1E-9

If you have any further questions, please send an e-mail to paul.seibert@tu-dresden.de