Source code for simulariumio.mem3dg.mem3dg_converter

from netCDF4 import Dataset
import numpy as np
from pathlib import Path

from ..trajectory_converter import TrajectoryConverter
from ..data_objects import (
    AgentData,
    TrajectoryData,
    DimensionData,
    DisplayData,
)
from ..constants import DISPLAY_TYPE
from ..exceptions import InputDataError
from .mem3dg_data import Mem3dgData


[docs] class Mem3dgConverter(TrajectoryConverter): def __init__( self, input_data: Mem3dgData, ): """ Parameters ---------- input_data : Mem3dgData An object containing info for reading Mem3DG simulation trajectory output """ self._data = self._read(input_data)
[docs] def write_to_obj(self, filepath, data, frame): # Extract XYZ coordinates for vertices coordinates = np.array( data.groups["Trajectory"].variables["coordinates"][frame] ) coordinates = np.reshape(coordinates, (-1, 3)) # Extract indices of vertices to make faces (all triangles) topology = np.array(data.groups["Trajectory"].variables["topology"][frame]) topology = np.reshape(topology, (-1, 3)) # change indices to be 1 indexed instead of 0 indexed for .obj files topology += 1 # Generate one .obj file per frame with open(filepath, "w") as file: file.write(f"# Frame {frame}\n") for v in coordinates: file.write(f"v {v[0]} {v[1]} {v[2]}\n") for t in topology: file.write(f"f {t[0]} {t[1]} {t[2]}\n")
def _read_traj_data(self, input_data: Mem3dgData) -> AgentData: try: data = Dataset(input_data.input_file_path, "r") n_frames = np.size(data.groups["Trajectory"].variables["time"]) except Exception as e: raise InputDataError(f"Error reading input Mem3DG data: {e}") # for now, we are representing converted Mem3DG trajectories as one # unique mesh agent per frame dimensions = DimensionData(total_steps=n_frames, max_agents=1) agent_data = AgentData.from_dimensions(dimensions) agent_data.n_timesteps = n_frames base_agent_name = input_data.agent_name or "object" for frame in range(n_frames): agent_data.times[frame] = data.groups["Trajectory"].variables["time"][frame] agent_data.n_agents[frame] = 1 output_file_path = Path(input_data.output_obj_file_path) / f"{frame}.obj" self.write_to_obj(output_file_path, data, frame) agent_data.radii[frame][0] = input_data.meta_data.scale_factor agent_data.unique_ids[frame][0] = frame name = str(frame) agent_data.types[frame].append(name) object_display_data = DisplayData( name=f"{base_agent_name}#frame{frame}", display_type=DISPLAY_TYPE.OBJ, url=f"{frame}.obj", color=input_data.agent_color, ) agent_data.display_data[name] = object_display_data return agent_data def _read(self, input_data: Mem3dgData) -> TrajectoryData: """ Return a TrajectoryData object containing the Mem3DG data """ print("Reading Mem3DG Data -------------") if input_data.meta_data.scale_factor is None: input_data.meta_data.scale_factor = 1.0 agent_data = self._read_traj_data(input_data) input_data.spatial_units.multiply(1.0 / input_data.meta_data.scale_factor) input_data.meta_data._set_box_size() result = TrajectoryData( meta_data=input_data.meta_data, agent_data=agent_data, time_units=input_data.time_units, spatial_units=input_data.spatial_units, plots=input_data.plots, ) return result