import json from pathlib import Path import numpy as np from common import load_config def bytes_feature(value: bytes): import tensorflow.compat.v1 as tf return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) def int64_feature(value: int): import tensorflow.compat.v1 as tf return tf.train.Feature(int64_list=tf.train.Int64List(value=[value])) def make_positions(rng, num_steps: int, num_particles: int, dim: int, bounds): low, high = float(bounds[0]), float(bounds[1]) position = rng.uniform(low + 0.2, high - 0.2, size=(num_particles, dim)) frames = [] for _ in range(num_steps): velocity = rng.normal(0.0, 0.015, size=(num_particles, dim)) position = np.clip(position + velocity, low + 0.05, high - 0.05) frames.append(position.astype(np.float32)) return np.stack(frames, axis=0) def make_particle_types(num_particles: int, num_node_types: int): particle_type = np.full((num_particles,), 5, dtype=np.int64) particle_type[::5] = 3 particle_type = np.clip(particle_type, 0, num_node_types - 1) return particle_type def write_split(path: Path, split: str, num_sequences: int, cfg, rng) -> None: import tensorflow.compat.v1 as tf num_steps = int(cfg.data.fake.num_steps) num_particles = int(cfg.data.fake.num_particles) dim = int(cfg.dim) bounds = cfg.data.fake.bounds writer_path = path / f"{split}.tfrecord" with tf.io.TFRecordWriter(str(writer_path)) as writer: for index in range(num_sequences): positions = make_positions(rng, num_steps, num_particles, dim, bounds) particle_type = make_particle_types(num_particles, int(cfg.data.num_node_types)) context = tf.train.Features( feature={ "key": int64_feature(index), "particle_type": bytes_feature(particle_type.tobytes()), } ) feature_list = tf.train.FeatureList( feature=[bytes_feature(frame.tobytes()) for frame in positions] ) example = tf.train.SequenceExample( context=context, feature_lists=tf.train.FeatureLists( feature_list={"position": feature_list} ), ) writer.write(example.SerializeToString()) def write_metadata(path: Path, cfg) -> None: dim = int(cfg.dim) bounds = [float(v) for v in cfg.data.fake.bounds] metadata = { "sequence_length": int(cfg.data.fake.num_steps) - 1, "dt": 1.0, "default_connectivity_radius": float(cfg.data.fake.connectivity_radius), "bounds": [bounds for _ in range(dim)], "dim": dim, "vel_mean": [0.0] * dim, "vel_std": [1.0] * dim, "acc_mean": [0.0] * dim, "acc_std": [1.0] * dim, } with open(path / "metadata.json", "w", encoding="utf-8") as f: json.dump(metadata, f, indent=2) def main(): cfg = load_config() data_dir = Path(cfg.data.data_dir) data_dir.mkdir(parents=True, exist_ok=True) write_metadata(data_dir, cfg) rng = np.random.default_rng(int(cfg.data.fake.seed)) for split in ("train", "valid", "test"): split_cfg = getattr(cfg.data, split) write_split(data_dir, split_cfg.split, int(split_cfg.num_sequences), cfg, rng) print(f"Fake Lagrangian TFRecord data written to {data_dir}") if __name__ == "__main__": main()