from SWCTransforms import SWCScale, SWCTranslate, ArgGenIterator, objFun import multiprocessing as mp import numpy as np import json import sys from itertools import product from regmaxsn.core.transforms import compose_matrix debugging = False # debugging = True assert len(sys.argv) == 2, 'Only one argument, the path of the swcfile expected, ' + str(len(sys.argv)) + 'found' parFile = sys.argv[1] with open(parFile, 'r') as fle: pars = json.load(fle) refSWC, SWC2Align, outFiles, gridSizes, bounds, minStepSize, nCPU = pars initBounds = bounds boundL = lambda x, y: max(y[0], min(y[1], x)) data = np.loadtxt(SWC2Align)[:, 2:5] dataCentered = data - data.mean(axis=0) maxDist = max(np.linalg.norm(dataCentered, axis=1).max(), gridSizes[0] * 1.01) pool = mp.Pool(processes=nCPU) SWCDatas = [SWCScale(refSWC, SWC2Align, x) for x in gridSizes] bestSol = [1.0, 1.0, 1.0] stepSizes = [max(minStepSize, min(2.0, (maxDist / (maxDist - g)))) for g in gridSizes] if debugging: print(maxDist, [(maxDist / (maxDist - g)) for g in gridSizes]) overestimationError = lambda d, g: (d + g) / d underestimationError = lambda d, g: ((d + 1.5 * g) * d) / ((d - 0.5 * g) * (d + g)) for gridInd, gridSize in enumerate(gridSizes): stepSize = stepSizes[gridInd] bounds = np.array(bounds) boundsExponents = np.log([x / y for x, y in zip(bounds, bestSol)]) / np.log(stepSize) boundsExponentsRoundedDown = np.sign(boundsExponents) * np.ceil(np.abs(boundsExponents)) possiblePts1D = [(bestSol[x] * (stepSize ** np.arange(int(y[0]), int(y[1]) + 1))) for x, y in enumerate(boundsExponentsRoundedDown)] if debugging: print(stepSize) print('Gridsize:' + str(gridSize)) print(bounds) print(map(len, possiblePts1D)) print([bestSol[x] * (stepSize ** y) for x, y in enumerate(boundsExponentsRoundedDown)]) possiblePts3D = np.round(list(product(*possiblePts1D)), 6).tolist() argGen = ArgGenIterator(possiblePts3D, SWCDatas[gridInd]) funcVals = pool.map_async(objFun, argGen).get(1800) minimum = min(funcVals) minimzers = [y for x, y in enumerate(possiblePts3D) if funcVals[x] == minimum] if not gridInd: distFrom0 = [np.mean([max(x, 1 / x) for x in y]) for y in minimzers] bestSol = minimzers[np.argmin(distFrom0)] else: prevVals = [objFun((x, SWCDatas[gridInd - 1])) for x in minimzers] bestSol = minimzers[np.argmin(prevVals)] bounds = [[boundL(x / overestimationError(maxDist, gridSize), iB), boundL(x * underestimationError(maxDist, gridSize), iB)] for x, iB in zip(bestSol, initBounds)] if debugging: print(bestSol) if stepSizes[-1] > minStepSize: stepSize = minStepSize bounds = np.array(bounds) boundsExponents = np.log([x / y for x, y in zip(bounds, bestSol)]) / np.log(stepSize) boundsExponentsRoundedDown = np.sign(boundsExponents) * np.ceil(np.abs(boundsExponents)) possiblePts1D = [(bestSol[x] * (stepSize ** np.arange(int(y[0]), int(y[1]) + 1))) for x, y in enumerate(boundsExponentsRoundedDown)] if debugging: print(stepSize) print(bounds) print(map(len, possiblePts1D)) print([bestSol[x] * (stepSize ** y) for x, y in enumerate(boundsExponentsRoundedDown)]) possiblePts3D = np.round(list(product(*possiblePts1D)), 6).tolist() argGen = ArgGenIterator(possiblePts3D, SWCDatas[-1]) funcVals = pool.map_async(objFun, argGen).get(1800) minimum = min(funcVals) minimzers = [y for x, y in enumerate(possiblePts3D) if funcVals[x] == minimum] prevVals = [objFun((x, SWCDatas[-2])) for x in minimzers] bestSol = minimzers[np.argmin(prevVals)] if debugging: print(bestSol, min(funcVals)) bestVal = objFun((bestSol, SWCDatas[-1])) nochange = objFun(([1, 1, 1], SWCDatas[-1])) if debugging: bestVals = [objFun((bestSol, x)) for x in SWCDatas] print(bestSol, nochange, bestVal) done = False # all values are worse than doing nothing if bestVal > nochange: done = True bestSol = [1, 1, 1] bestVal = nochange # best solution and no change are equally worse elif bestVal == nochange: # the solution step is very close to zero if np.abs(bestSol).max() <= min(minStepSize, stepSizes[-1]): done = True bestSol = [1, 1, 1] bestVal = nochange SWCDatas[-1].writeSolution(outFiles[0], bestSol) temp = SWCTranslate(refSWC, outFiles[0], gridSizes[-1]) bestVal = objFun(([0, 0, 0], temp)) matrix = compose_matrix(scale=bestSol).tolist() with open(outFiles[1], 'w') as fle: json.dump({'type': 'XYZ Scales', 'bestSol': bestSol, 'transMat': matrix, 'done': done, 'bestVal': bestVal}, fle)