You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
5.1 KiB

10 months ago
7 months ago
10 months ago
  1. # flake8: noqa
  2. from parameterisations.utils.parse_regression_coef_to_array import (
  3. parse_regression_coef_to_array,
  4. )
  5. from parameterisations.utils.fit_linear_regression_model import (
  6. fit_linear_regression_model,
  7. )
  8. import uproot
  9. import argparse
  10. import awkward as ak
  11. from pathlib import Path
  12. def parameterise_magnet_kink(
  13. input_file: str = "data/param_data_selected.root",
  14. tree_name: str = "Selected",
  15. per_layer=False,
  16. ) -> Path:
  17. """Function that calculates parameters for estimating the magnet kink z position.
  18. Args:
  19. input_file (str, optional): Defaults to "data/param_data_selected.root".
  20. tree_name (str, optional): Defaults to "Selected".
  21. per_layer (bool, optional): If true also calculates parameters per SciFi layer. Defaults to False.
  22. Returns:
  23. Path: Path to cpp code file.
  24. """
  25. input_tree = uproot.open({input_file: tree_name})
  26. # this is an event list of dictionaries containing awkward arrays
  27. array = input_tree.arrays()
  28. array["dSlope_fringe"] = array["tx_ref"] - array["tx"]
  29. # the magnet kink position is the point of intersection of the track tagents
  30. array["z_mag_x_fringe"] = (
  31. array["x"]
  32. - array["x_ref"]
  33. - array["tx"] * array["z"]
  34. + array["tx_ref"] * array["z_ref"]
  35. ) / array["dSlope_fringe"]
  36. array["dSlope_xEndT"] = array["tx_l11"] - array["tx"]
  37. array["dSlope_xEndT_abs"] = abs(array["dSlope_xEndT"])
  38. array["x_EndT_abs"] = abs(
  39. array["x_l11"] + array["tx_l11"] * (9410.0 - array["z_l11"]),
  40. )
  41. # the magnet kink position is the point of intersection of the track tagents
  42. array["z_mag_xEndT"] = (
  43. array["x"]
  44. - array["x_l11"]
  45. - array["tx"] * array["z"]
  46. + array["tx_l11"] * array["z_l11"]
  47. ) / array["dSlope_xEndT"]
  48. if per_layer:
  49. layered_features = [f"x_diff_straight_l{layer}" for layer in range(12)]
  50. rows = []
  51. for i, feat in enumerate(layered_features):
  52. scale = 3000
  53. if "dSlope" not in feat:
  54. array[f"x_l{i}_rel"] = array[f"x_l{i}"] / scale
  55. array[f"x_diff_straight_l{i}"] = (
  56. array[f"x_l{i}"]
  57. - array["x"]
  58. - array["tx"] * (array[f"z_l{i}"] - array["z"])
  59. )
  60. model, poly_features = fit_linear_regression_model(
  61. array,
  62. target_feat="z_mag_x_fringe",
  63. features=[
  64. "tx",
  65. "ty",
  66. feat,
  67. ],
  68. keep=[
  69. "tx^2",
  70. f"tx x_diff_straight_l{i}",
  71. "ty^2",
  72. f"x_diff_straight_l{i}^2",
  73. ],
  74. degree=2,
  75. fit_intercept=True,
  76. )
  77. rows.append(
  78. "{"
  79. + str(model.intercept_)
  80. + "f,"
  81. + ",".join([str(coef) + "f" for coef in model.coef_ if coef != 0.0])
  82. + "}",
  83. )
  84. cpp_decl = parse_regression_coef_to_array(
  85. model,
  86. poly_features,
  87. "zMagnetParamsLayers",
  88. rows=rows,
  89. )
  90. # now fit model for the reference plane
  91. model_ref, poly_features_ref = fit_linear_regression_model(
  92. array,
  93. target_feat="z_mag_x_fringe",
  94. features=["tx", "ty", "dSlope_fringe"],
  95. keep=["tx^2", "tx dSlope_fringe", "ty^2", "dSlope_fringe^2"],
  96. degree=2,
  97. fit_intercept=True,
  98. )
  99. cpp_ref = parse_regression_coef_to_array(
  100. model_ref,
  101. poly_features_ref,
  102. "zMagnetParamsRef",
  103. )
  104. model_endt, poly_features_endt = fit_linear_regression_model(
  105. array,
  106. target_feat="z_mag_xEndT",
  107. features=["tx", "dSlope_xEndT", "dSlope_xEndT_abs", "x_EndT_abs"],
  108. keep=["tx^2", "dSlope_xEndT^2", "dSlope_xEndT_abs", "x_EndT_abs"],
  109. degree=2,
  110. fit_intercept=True,
  111. )
  112. cpp_ref += parse_regression_coef_to_array(
  113. model_endt,
  114. poly_features_endt,
  115. "zMagnetParamsEndT",
  116. )
  117. outpath = Path("parameterisations/result/z_mag_kink_params.hpp")
  118. outpath.parent.mkdir(parents=True, exist_ok=True)
  119. with open(outpath, "w") as result:
  120. result.writelines(cpp_decl + cpp_ref if per_layer else cpp_ref)
  121. return outpath
  122. if __name__ == "__main__":
  123. parser = argparse.ArgumentParser()
  124. parser.add_argument(
  125. "--input-file",
  126. type=str,
  127. help="Path to the input file",
  128. required=False,
  129. )
  130. parser.add_argument(
  131. "--tree-name",
  132. type=str,
  133. help="Path to the input file",
  134. required=False,
  135. )
  136. args = parser.parse_args()
  137. args_dict = {arg: val for arg, val in vars(args).items() if val is not None}
  138. outfile = parameterise_magnet_kink(**args_dict)
  139. try:
  140. import subprocess
  141. # run clang-format for nicer looking result
  142. subprocess.run(
  143. [
  144. "clang-format",
  145. "-i",
  146. f"{outfile}",
  147. ],
  148. check=True,
  149. )
  150. except:
  151. pass