main.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import asyncio
  2. import logging
  3. import os
  4. from datetime import datetime
  5. from seq_interp.src.hardware.constraints import HardwareConstraints
  6. from seq_interp.src.interfaces.pulseq_adapter import PulseqLoader
  7. from seq_interp.src.core.synchronizer import Synchronizer
  8. from seq_interp.src.interfaces.xml_generator import XMLGenerator
  9. from seq_interp.src.interfaces.rf_exporter import RFExporter
  10. from seq_interp.src.interfaces.gradient_exporter import GradientExporter
  11. from seq_interp.src.interfaces.picoscope_exporter import PicoScopeExporter
  12. from seq_interp.src.interfaces.post_request_generator import PostRequestGenerator
  13. from seq_interp.src.config import config
  14. async def main(sequence_path: str = None, hw_config_path: str = None, output_dir: str = "output") -> None:
  15. """
  16. Точка входа интерпретатора MRI-последовательности.
  17. """
  18. log_dir = "log"
  19. os.makedirs(log_dir, exist_ok=True)
  20. log_filename = os.path.join(log_dir, f"interp_log_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log")
  21. logging.basicConfig(
  22. level=logging.INFO,
  23. format="%(asctime)s [%(levelname)s] %(message)s",
  24. handlers=[logging.FileHandler(log_filename), logging.StreamHandler()],
  25. )
  26. logger = logging.getLogger("MRISequenceInterpreter")
  27. if not sequence_path:
  28. raise ValueError("sequence_path is required")
  29. hw = HardwareConstraints(json_path=hw_config_path)
  30. loader = PulseqLoader(hw)
  31. seq_data = loader.load(sequence_path)
  32. os.makedirs(output_dir, exist_ok=True)
  33. sync_sequence = seq_data["sequence"]
  34. params = seq_data["params"]
  35. synchronizer = Synchronizer(hw)
  36. sync_data = synchronizer.process(sync_sequence)
  37. xml_generator = XMLGenerator()
  38. rf_exporter = RFExporter()
  39. grad_exporter = GradientExporter()
  40. pico_exporter = PicoScopeExporter()
  41. post_generator = PostRequestGenerator()
  42. hw_cfg = config.hw_config # полный словарь из hw_config.json
  43. xml_path = os.path.join(output_dir, "sync_v2.xml")
  44. adc_values, adc_starts = await asyncio.to_thread(xml_generator.generate, sync_data, xml_path, hw)
  45. tasks = []
  46. tasks.append(asyncio.to_thread(rf_exporter.export, seq_data, params, output_dir))
  47. if all(k in seq_data for k in ["gx", "gy", "gz", "t_gx", "t_gy", "t_gz"]):
  48. tasks.append(asyncio.to_thread(grad_exporter.export, seq_data, params, output_dir))
  49. iadc_cfg = hw_cfg.get("iadc", {})
  50. tasks.append(asyncio.to_thread(
  51. pico_exporter.generate,
  52. adc_values, adc_starts, output_dir, hw,
  53. sampling_freq=iadc_cfg.get("srate", 8e6),
  54. num_channels=iadc_cfg.get("n_channels", 3),
  55. ))
  56. await asyncio.gather(*tasks)
  57. # Генерация и (опционально) отправка POST-манифеста
  58. post_payload = post_generator.build(
  59. seq_data=seq_data,
  60. adc_values=adc_values,
  61. sequence_path=sequence_path,
  62. output_dir=output_dir,
  63. hw_cfg=hw_cfg,
  64. rf_raster_time=params["rf_raster_time"],
  65. )
  66. post_generator.write(post_payload, output_dir)
  67. hw_service_url = hw_cfg.get("hw_service_url")
  68. if hw_service_url:
  69. await post_generator.send(post_payload, hw_service_url)
  70. logger.info("Интерпретация завершена, результаты записаны в: %s", output_dir)
  71. if __name__ == "__main__":
  72. script_dir = os.path.dirname(os.path.abspath(__file__))
  73. project_root = os.path.dirname(os.path.dirname(script_dir))
  74. asyncio.run(
  75. main(
  76. sequence_path=os.path.join(project_root, "seq_interp", "data", "input", "rf_adc_only_fixed3 (4).seq"),
  77. hw_config_path=os.path.join(project_root, "seq_interp", "cfg", "hw_config.json"),
  78. output_dir=os.path.join(project_root, "seq_interp", "data", "output"),
  79. )
  80. )