diff --git a/cellpack/autopack/Analysis.py b/cellpack/autopack/Analysis.py index 73f123e5f..d0b67b95e 100644 --- a/cellpack/autopack/Analysis.py +++ b/cellpack/autopack/Analysis.py @@ -2200,7 +2200,6 @@ def pack_one_seed( seed_index, seed_list, bounding_box, - packing_basename, center_distance_dict=None, pairwise_distance_dict=None, ingredient_position_dict=None, @@ -2215,17 +2214,14 @@ def pack_one_seed( """ Packs one seed of a recipe and returns the recipe object """ - seed_basename = f"seed_{seed_index}_{packing_basename}" - self.env.result_file = str( - self.env.out_folder / f"results_seed_{seed_index}_{packing_basename}" - ) + seed_basename = self.env.add_seed_number_to_base_name(seed_index) + seed = seed_list[seed_index] # Clear if self.afviewer: self.afviewer.clearFill("Test_Spheres2D") else: self.env.reset() self.env.saveResult = True - seed = seed_list[seed_index] # int(time()) numpy.random.seed(seed) self.build_grid() two_d = self.env.is_two_d() @@ -2425,7 +2421,7 @@ def doloop( """ if seed_list is None: seed_list = self.getHaltonUnique(number_of_packings) - packing_basename = f"{self.env.name}_{config_name}_{recipe_version}" + packing_basename = self.env.base_name numpy.savetxt( self.env.out_folder / f"seeds_{packing_basename}.txt", seed_list, @@ -2514,7 +2510,6 @@ def doloop( seed_index=seed_index, seed_list=seed_list, bounding_box=bounding_box, - packing_basename=packing_basename, center_distance_dict=center_distance_dict, pairwise_distance_dict=pairwise_distance_dict, ingredient_position_dict=ingredient_position_dict, diff --git a/cellpack/autopack/Environment.py b/cellpack/autopack/Environment.py index 80be50ae4..9c90038fc 100644 --- a/cellpack/autopack/Environment.py +++ b/cellpack/autopack/Environment.py @@ -52,7 +52,6 @@ from scipy import spatial import numpy import pickle -import math import json from json import encoder import logging @@ -83,7 +82,7 @@ from cellpack.autopack import IOutils from .octree import Octree from .Gradient import Gradient -from .transformation import euler_from_matrix, signed_angle_between_vectors +from .transformation import signed_angle_between_vectors # backward compatibility with kevin method from cellpack.autopack.BaseGrid import BaseGrid as BaseGrid @@ -150,9 +149,7 @@ def __init__(self, config=None, recipe=None): # saving/pickle option self.saveResult = "out" in config self.out_folder = create_output_dir(config["out"], name, config["place_method"]) - self.result_file = ( - f"{self.out_folder}/{self.name}_{config['name']}_{self.version}" - ) + self.base_name = f"{self.name}_{config['name']}_{self.version}" self.grid_file_out = ( f"{self.out_folder}/{self.name}_{config['name']}_{self.version}_grid.dat" ) @@ -516,9 +513,7 @@ def save_result( free_points, distances, t0, - vAnalysis, vTestid, - seedNum, all_ingr_as_array, save_grid_logs=False, save_result_as_file=False, @@ -538,7 +533,6 @@ def save_result( self.store_asTxt() Writer(format=self.format_output).save( self, - self.result_file, kwds=["compNum"], result=True, quaternion=True, @@ -547,142 +541,6 @@ def save_result( ) self.log.info("time to save result file %d", time() - t0) - if vAnalysis == 1: - # START Analysis Tools: Graham added back this big chunk of code - # for analysis tools and graphic on 5/16/12 - # Needs to be cleaned up into a function and proper uPy code - # totalVolume = self.grid.gridVolume*unitVol - unitVol = self.grid.gridSpacing**3 - wrkDirRes = self.result_file + "_analyze_" - for o in self.compartments: # only for compartment ? - # totalVolume -= o.surfaceVolume - # totalVolume -= o.interiorVolume - innerPointNum = len(o.insidePoints) - 1 - self.log.info(" . . . . ") - self.log.info("for compartment o = %s", o.name) - self.log.info("inner Point Count = %d", innerPointNum) - self.log.info("inner Volume = %s", o.interiorVolume) - self.log.info("innerVolume temp Confirm = %d", innerPointNum * unitVol) - usedPts = 0 - unUsedPts = 0 - vDistanceString = "" - insidepointindce = numpy.nonzero( - numpy.equal(self.grid.compartment_ids, -o.number) - )[0] - for i in insidepointindce: # xrange(innerPointNum): - # pt = o.insidePoints[i] #fpts[i] - # print (pt,type(pt)) - # for pt in self.histo.freePointsAfterFill:#[:self.histo.nbFreePointsAfterFill]: - d = self.distancesAfterFill[i] - vDistanceString += str(d) + "\n" - if d <= 0: # >self.smallestProteinSize-0.001: - usedPts += 1 - else: - unUsedPts += 1 - filename = ( - wrkDirRes - + "vResultMatrix1" - + o.name - + "_Testid" - + str(vTestid) - + "_Seed" - + str(seedNum) - + "_dists.txt" - ) # Used this from thesis to overwrite less informative SVN version on next line on July 5, 2012 - # filename = wrkDirRes+"/vDistances1.txt" - f = open(filename, "w") - f.write(vDistanceString) - f.close() - - # result is [pos,rot,ingr.name,ingr.compNum,ptInd] - # if resultfilename == None: - # resultfilename = self.result_file - resultfilenameT = ( - wrkDirRes - + "vResultMatrix1" - + o.name - + "_Testid" - + str(vTestid) - + "_Seed" - + str(seedNum) - + "_Trans.txt" - ) # Used this from thesis to overwrite less informative SVN version on next line on July 5, 2012 - resultfilenameR = ( - wrkDirRes - + "vResultMatrix1" - + o.name - + "_Testid" - + str(vTestid) - + "_Seed" - + str(seedNum) - + "_Rot.txt" - ) - vTranslationString = "" - vRotationString = "" - result = [] - matCount = 0 - for pos, rot, ingr, ptInd in o.molecules: - # BEGIN: newer code from Theis version added July 5, 2012 - if hasattr(self, "afviewer"): - mat = rot.copy() - mat[:3, 3] = pos - - # r = R.from_matrix(mat).as_euler("xyz", degrees=False) - r = euler_from_matrix(mat, "rxyz") - h1 = math.degrees(math.pi + r[0]) - p1 = math.degrees(r[1]) - b1 = math.degrees(-math.pi + r[2]) - self.log.info("rot from matrix = %r %r %r %r", r, h1, p1, b1) - # END: newer code from Theis version added July 5, 2012 - result.append([pos, rot]) - pt3d = result[matCount][0] - ( - x, - y, - z, - ) = pt3d - - vTranslationString += ( - str(x) + ",\t" + str(y) + ",\t" + str(z) + "\n" - ) - # vRotationString += str(rot3d) #str(h)+ ",\t" + str(p) + ",\t" + str(b) + "\n" - vRotationString += ( - str(h1) - + ",\t" - + str(p1) - + ",\t" - + str(b1) - + ",\t" - + ingr.name - + "\n" - ) - matCount += 1 - - rfile = open(resultfilenameT, "w") - rfile.write(vTranslationString) - rfile.close() - - rfile = open(resultfilenameR, "w") - rfile.write(vRotationString) - rfile.close() - self.log.info("len(result) = %d", len(result)) - self.log.info("len(self.molecules) = %d", len(self.molecules)) - # Graham Note: There is overused disk space- the rotation matrix is 4x4 with an offset of 0,0,0 - # and we have a separate translation vector in the results and molecules arrays. - # Get rid of the translation vector and move it to the rotation matrix to save space... - # will that slow the time it takes to extract the vector from the matrix when we need to call it? - self.log.info( - "*************************************************** vDistance String Should be on" - ) - self.log.info("unitVolume2 = %d", unitVol) - self.log.info("Number of Points Unused = %d", unUsedPts) - self.log.info("Number of Points Used = %d", usedPts) - self.log.info("Volume Used = %d", usedPts * unitVol) - self.log.info("Volume Unused = %d", unUsedPts * unitVol) - self.log.info("vTestid = %d", vTestid) - self.log.info("self.grid.nbGridPoints = %r", self.grid.nbGridPoints) - self.log.info("self.gridVolume = %d", self.grid.gridVolume) - self.log.info("self.compartments In Environment = %d", len(self.compartments)) if self.compartments == []: unitVol = self.grid.gridSpacing**3 @@ -2055,12 +1913,20 @@ def update_count(self, allIngredients): ingr.count = count ingr.left_to_place = count + def add_seed_number_to_base_name(self, seed_number): + return f"{self.base_name}_seed_{seed_number}" + + def set_result_file_name(self, seed_basename): + """ + Sets the result file name using the output folder path and a given seed basename + """ + self.result_file = str(self.out_folder / f"results_{seed_basename}") + def pack_grid( self, - seedNum=14, + seedNum=0, name=None, vTestid=3, - vAnalysis=0, **kw, ): """ @@ -2070,6 +1936,8 @@ def pack_grid( # set periodicity autopack.testPeriodicity = self.use_periodicity t1 = time() + seed_base_name = self.add_seed_number_to_base_name(seedNum) + self.set_result_file_name(seed_base_name) self.timeUpDistLoopTotal = 0 self.static = [] if self.grid is None: @@ -2404,9 +2272,7 @@ def pack_grid( free_points, distances=distances, t0=stime, - vAnalysis=vAnalysis, vTestid=vTestid, - seedNum=seedNum, all_ingr_as_array=all_ingr_as_array, ) @@ -2423,9 +2289,7 @@ def pack_grid( free_points, distances=distances, t0=time(), - vAnalysis=vAnalysis, vTestid=vTestid, - seedNum=seedNum, all_ingr_as_array=all_ingr_as_array, ) diff --git a/cellpack/autopack/writers/__init__.py b/cellpack/autopack/writers/__init__.py index 914918ee2..64736a0a9 100644 --- a/cellpack/autopack/writers/__init__.py +++ b/cellpack/autopack/writers/__init__.py @@ -9,6 +9,21 @@ from collections import OrderedDict from cellpack import autopack +from cellpack.autopack.ingredient.grow import ActinIngredient, GrowIngredient +import cellpack.autopack.transformation as tr + + +def updatePositionsRadii(ingr): + toupdate = {"positions": []} + toupdate["radii"] = [] + if getattr(ingr, "positions", None) is not None: + nLOD = len(ingr.positions) + for i in range(nLOD): + toupdate["positions"].append( + {"coords": numpy.array(ingr.positions[i]).flatten().tolist()} + ) + toupdate["radii"].append({"radii": ingr.radii[i]}) + return toupdate class IOingredientTool(object): @@ -36,6 +51,62 @@ def write(self, ingr, filename, ingr_format="xml", kwds=None, result=False): f.write(ingrnode) f.close() + def ingrJsonNode(self, ingr, result=False, kwds=None, transpose=False): + # force position instead of sphereFile + ingdic = OrderedDict() + if kwds is None: + kwds = ingr.KWDS + for k in kwds: + v = getattr(ingr, str(k)) + # if hasattr(v,"tolist"): + # v=v.tolist() + # ingdic[k] = v + if v is not None: + ingdic.update(Writer.setValueToJsonNode(v, str(k))) + # if sphereTree file present should not use the pos-radii keyword + # if ingr.sphereFile is not None and not result: + # remove the position and radii key + # ingdic.pop("positions", None) + # ingdic.pop("radii", None) + # update the positions and radii to new format + toupdate = updatePositionsRadii(ingr) + ingdic.update(toupdate) + if numpy.sum(ingr.offset) != 0.0: + if "transform" not in ingr.source: + ingr.source["transform"] = {"offset": ingr.offset} + else: + ingr.source["transform"]["offset"] = ingr.offset + + # reslt ?s + if result: + ingdic["results"] = [] + for r in ingr.results: + # position + if hasattr(r[0], "tolist"): + r[0] = r[0].tolist() + # rotation + if hasattr(r[1], "tolist"): + r[1] = r[1].tolist() + R = numpy.array(r[1]).tolist() # this will not work with cellvIEW? + if transpose: + R = ( + numpy.array(r[1]).transpose().tolist() + ) # this will not work with cellvIEW? + # transpose ? + if self.use_quaternion: + R = tr.quaternion_from_matrix(R).tolist() + ingdic["results"].append([r[0], R]) + if isinstance(ingr, GrowIngredient) or isinstance(ingr, ActinIngredient): + ingdic["nbCurve"] = ingr.nbCurve + for i in range(ingr.nbCurve): + lp = numpy.array(ingr.listePtLinear[i]) + ingr.listePtLinear[i] = lp.tolist() + ingdic["curve" + str(i)] = ingr.listePtLinear[i] + # res=numpy.array(ingdic["results"]).transpose() + # ingdic["results"]=res.tolist() + ingdic["name"] = ingr.composition_name + return ingdic + class NumpyArrayEncoder(json.JSONEncoder): def default(self, obj): @@ -78,9 +149,7 @@ def setValueToJsonNode(value, attrname): vdic[attrname] = value return vdic - def save_as_simularium( - self, env, result_file_path, all_ingr_as_array, compartments - ): + def save_as_simularium(self, env, all_ingr_as_array, compartments): env.helper.clear() grid_positions = env.grid.masterGridPositions if env.show_grid_spheres else None @@ -103,15 +172,11 @@ def save_as_simularium( env.helper.add_grid_data_to_scene( f"{gradient.name}-weights", grid_positions, gradient.weight ) - - env.helper.writeToFile( - f"{result_file_path}_results", env.boundingBox, env.name, env.version - ) + env.helper.writeToFile(env.result_file, env.boundingBox, env.name, env.version) def save_Mixed_asJson( self, env, - setupfile, useXref=True, kwds=None, result=False, @@ -127,14 +192,12 @@ def save_Mixed_asJson( """ io_ingr = IOingredientTool(env=env) io_ingr.use_quaternion = quaternion - env.setupfile = setupfile # +".json"provide the server? + file_name = f"{env.result_file}.json" # the output path for this recipes files - if env.setupfile.find("http") != -1 or env.setupfile.find("ftp") != -1: - pathout = os.path.dirname( - os.path.abspath(autopack.retrieveFile(env.setupfile)) - ) + if file_name.find("http") != -1 or file_name.find("ftp") != -1: + pathout = os.path.dirname(os.path.abspath(autopack.retrieveFile(file_name))) else: - pathout = os.path.dirname(os.path.abspath(env.setupfile)) + pathout = os.path.dirname(os.path.abspath(file_name)) if env.version is None: env.version = "1.0" env.jsondic = OrderedDict( @@ -143,8 +206,6 @@ def save_Mixed_asJson( if env.custom_paths: # this was the used path at loading time env.jsondic["recipe"]["paths"] = env.custom_paths - if result: - env.jsondic["recipe"]["setupfile"] = env.setupfile if packing_options: env.jsondic["options"] = {} for k in env.OPTIONS: @@ -291,7 +352,7 @@ def save_Mixed_asJson( env.jsondic["compartments"][str(o.name)]["interior"][ "ingredients" ][ingr.composition_name]["name"] = ingr.composition_name - with open(setupfile, "w") as fp: # doesnt work with symbol link ? + with open(file_name, "w") as fp: # doesnt work with symbol link ? if indent: json.dump( env.jsondic, @@ -319,7 +380,6 @@ def return_object_value(data): def save( self, env, - setupfile, kwds=None, result=False, grid=False, @@ -334,7 +394,6 @@ def save( if output_format == "json": self.save_Mixed_asJson( env, - setupfile, useXref=False, kwds=kwds, result=result, @@ -345,6 +404,6 @@ def save( transpose=transpose, ) elif output_format == "simularium": - self.save_as_simularium(env, setupfile, all_ingr_as_array, compartments) + self.save_as_simularium(env, all_ingr_as_array, compartments) else: print("format output " + output_format + " not recognized (json,python)")