From e16b63aa6027f9e3f25ac49e3478a9ad1bdfe0f7 Mon Sep 17 00:00:00 2001 From: Peter Willendrup Date: Thu, 22 Oct 2026 13:31:35 +0200 Subject: [PATCH] Monitor_nD: support 1D x or y banks in Mantid mode Mantid's LoadMcStas requires 6 event columns (p x y n id t), so a 'mantid square' monitor binned only in x (or y) wrote 5 columns and Mantid silently loaded no events; 'y bins=1' was the workaround. - In mantid mode with a square monitor, add the missing x or y coordinate with a single bin spanning the monitor, keeping x before y. - MANTID_RECTANGULAR_DET now finds the x, y and pixel coordinates by type instead of assuming positions 1, 2 and 4, so 'y ... x' no longer gives a 90-degree rotated IDF. - mcdisplay-mantid: write xstart/ystart as the first pixel centre, as Mantid expects, instead of the bin edge (half-pixel shift, half the detector size in a 1-bin direction). Fixes #2178 Co-Authored-By: Claude Opus 5.5 --- mcstas-comps/share/monitor_nd-lib.c | 44 ++++++++++++++++--- mcstas-comps/share/monitor_nd_noacc-lib.c | 44 ++++++++++++++++--- .../Python/mcdisplay/mantid_xml/mcdisplay.py | 4 +- 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/mcstas-comps/share/monitor_nd-lib.c b/mcstas-comps/share/monitor_nd-lib.c index 5bf9a26e4..7afff5846 100644 --- a/mcstas-comps/share/monitor_nd-lib.c +++ b/mcstas-comps/share/monitor_nd-lib.c @@ -572,6 +572,36 @@ void Monitor_nD_Init(MonitornD_Defines_type *DEFS, if (!Vars->Flag_List && nexusbins==1) Vars->Flag_nexusbins=1; free(option_copy); + + /* Mantid LoadMcStas needs both x and y event columns (p x y n id t): + add the missing one with a single bin for 1D x or y banks (#2178) */ + if (Vars->Flag_mantid && abs(Vars->Flag_Shape) == DEFS->SHAPE_SQUARE && Vars->Coord_Number < MONnD_COORD_NMAX-1) { + long ix=0, iy=0, k; + for (i=1; i<=Vars->Coord_Number; i++) { + int ct = Vars->Coord_Type[i] & (DEFS->COORD_LOG-1); + if (ct==DEFS->COORD_X && !ix) ix=i; + if (ct==DEFS->COORD_Y && !iy) iy=i; + } + if (!ix != !iy) { + k = ix ? ix+1 : iy; /* keep x before y */ + for (i=Vars->Coord_Number; i>=k; i--) { + Vars->Coord_Type[i+1]=Vars->Coord_Type[i]; + memcpy(Vars->Coord_Label[i+1],Vars->Coord_Label[i],30); + memcpy(Vars->Coord_Var[i+1],Vars->Coord_Var[i],30); + Vars->Coord_Bin[i+1]=Vars->Coord_Bin[i]; + Vars->Coord_Min[i+1]=Vars->Coord_Min[i]; + Vars->Coord_Max[i+1]=Vars->Coord_Max[i]; + } + Vars->Coord_Type[k] = ix ? DEFS->COORD_Y : DEFS->COORD_X; + strcpy(Vars->Coord_Label[k], ix ? "y [m]" : "x [m]"); + strcpy(Vars->Coord_Var[k], ix ? "y" : "x"); + Vars->Coord_Bin[k] = 1; + Vars->Coord_Min[k] = ix ? Vars->mymin : Vars->mxmin; + Vars->Coord_Max[k] = ix ? Vars->mymax : Vars->mxmax; + Vars->Coord_Number++; + Vars->Coord_NumberNoPixel++; + } + } if (carg == 128) printf("Monitor_nD: %s reached max number of tokens (%i). Skipping.\n", Vars->compcurname, 128); if ((Vars->Flag_Shape == DEFS->SHAPE_BOX) && (fabs(Vars->mzmax - Vars->mzmin) == 0)) Vars->Flag_Shape = DEFS->SHAPE_SQUARE; @@ -2160,12 +2190,16 @@ void Monitor_nD_McDisplay(MonitornD_Defines_type *DEFS, (double)xmin, (double)ymin, 0.0); if (Vars->Flag_mantid) { - /* First define the base pixel type */ - double dx, dy; - dx = (Vars->Coord_Max[1]-Vars->Coord_Min[1])/Vars->Coord_Bin[1]; - dy = (Vars->Coord_Max[2]-Vars->Coord_Min[2])/Vars->Coord_Bin[2]; + /* x, y and pixel coordinates may come in any order (#2178) */ + int ix=1, iy=2, ip=4; + for (i=1; i<=Vars->Coord_Number; i++) { + int ct = Vars->Coord_Type[i] & (DEFS->COORD_LOG-1); + if (ct==DEFS->COORD_X) ix=i; + if (ct==DEFS->COORD_Y) iy=i; + if (ct==DEFS->COORD_PIXELID) ip=i; + } printf("MANTID_RECTANGULAR_DET: %g, %g, %g, %g, %li, %li, %llu\n", - Vars->Coord_Min[1],Vars->Coord_Max[1], Vars->Coord_Min[2],Vars->Coord_Max[2], Vars->Coord_Bin[1], Vars->Coord_Bin[2], (long long unsigned)Vars->Coord_Min[4]); + Vars->Coord_Min[ix],Vars->Coord_Max[ix], Vars->Coord_Min[iy],Vars->Coord_Max[iy], Vars->Coord_Bin[ix], Vars->Coord_Bin[iy], (long long unsigned)Vars->Coord_Min[ip]); } } /* full cylinder/banana */ diff --git a/mcstas-comps/share/monitor_nd_noacc-lib.c b/mcstas-comps/share/monitor_nd_noacc-lib.c index 10dee8265..09feddd7e 100644 --- a/mcstas-comps/share/monitor_nd_noacc-lib.c +++ b/mcstas-comps/share/monitor_nd_noacc-lib.c @@ -580,6 +580,36 @@ void Monitor_nd_noaccInit(Monitornd_noaccDefines_type *DEFS, if (!Vars->Flag_List && nexusbins==1) Vars->Flag_nexusbins=1; free(option_copy); + + /* Mantid LoadMcStas needs both x and y event columns (p x y n id t): + add the missing one with a single bin for 1D x or y banks (#2178) */ + if (Vars->Flag_mantid && abs(Vars->Flag_Shape) == DEFS->SHAPE_SQUARE && Vars->Coord_Number < MONnD_COORD_NMAX-1) { + long ix=0, iy=0, k; + for (i=1; i<=Vars->Coord_Number; i++) { + int ct = Vars->Coord_Type[i] & (DEFS->COORD_LOG-1); + if (ct==DEFS->COORD_X && !ix) ix=i; + if (ct==DEFS->COORD_Y && !iy) iy=i; + } + if (!ix != !iy) { + k = ix ? ix+1 : iy; /* keep x before y */ + for (i=Vars->Coord_Number; i>=k; i--) { + Vars->Coord_Type[i+1]=Vars->Coord_Type[i]; + memcpy(Vars->Coord_Label[i+1],Vars->Coord_Label[i],30); + memcpy(Vars->Coord_Var[i+1],Vars->Coord_Var[i],30); + Vars->Coord_Bin[i+1]=Vars->Coord_Bin[i]; + Vars->Coord_Min[i+1]=Vars->Coord_Min[i]; + Vars->Coord_Max[i+1]=Vars->Coord_Max[i]; + } + Vars->Coord_Type[k] = ix ? DEFS->COORD_Y : DEFS->COORD_X; + strcpy(Vars->Coord_Label[k], ix ? "y [m]" : "x [m]"); + strcpy(Vars->Coord_Var[k], ix ? "y" : "x"); + Vars->Coord_Bin[k] = 1; + Vars->Coord_Min[k] = ix ? Vars->mymin : Vars->mxmin; + Vars->Coord_Max[k] = ix ? Vars->mymax : Vars->mxmax; + Vars->Coord_Number++; + Vars->Coord_NumberNoPixel++; + } + } if (carg == 128) printf("Monitor_nD: %s reached max number of tokens (%i). Skipping.\n", Vars->compcurname, 128); if ((Vars->Flag_Shape == DEFS->SHAPE_BOX) && (fabs(Vars->mzmax - Vars->mzmin) == 0)) Vars->Flag_Shape = DEFS->SHAPE_SQUARE; @@ -2125,12 +2155,16 @@ void Monitor_nd_noaccMcDisplay(Monitornd_noaccDefines_type *DEFS, (double)xmin, (double)ymin, 0.0); if (Vars->Flag_mantid) { - /* First define the base pixel type */ - double dx, dy; - dx = (Vars->Coord_Max[1]-Vars->Coord_Min[1])/Vars->Coord_Bin[1]; - dy = (Vars->Coord_Max[2]-Vars->Coord_Min[2])/Vars->Coord_Bin[2]; + /* x, y and pixel coordinates may come in any order (#2178) */ + int ix=1, iy=2, ip=4; + for (i=1; i<=Vars->Coord_Number; i++) { + int ct = Vars->Coord_Type[i] & (DEFS->COORD_LOG-1); + if (ct==DEFS->COORD_X) ix=i; + if (ct==DEFS->COORD_Y) iy=i; + if (ct==DEFS->COORD_PIXELID) ip=i; + } printf("MANTID_RECTANGULAR_DET: %g, %g, %g, %g, %li, %li, %llu\n", - Vars->Coord_Min[1],Vars->Coord_Max[1], Vars->Coord_Min[2],Vars->Coord_Max[2], Vars->Coord_Bin[1], Vars->Coord_Bin[2], (long long unsigned)Vars->Coord_Min[4]); + Vars->Coord_Min[ix],Vars->Coord_Max[ix], Vars->Coord_Min[iy],Vars->Coord_Max[iy], Vars->Coord_Bin[ix], Vars->Coord_Bin[iy], (long long unsigned)Vars->Coord_Min[ip]); } } /* full cylinder/banana */ diff --git a/tools/Python/mcdisplay/mantid_xml/mcdisplay.py b/tools/Python/mcdisplay/mantid_xml/mcdisplay.py index ffd428d89..137fd7e45 100755 --- a/tools/Python/mcdisplay/mantid_xml/mcdisplay.py +++ b/tools/Python/mcdisplay/mantid_xml/mcdisplay.py @@ -320,9 +320,9 @@ def _get_mantid_rectangular_monitor(self): s = s.replace('ROT_X', str(rot_vector.x)) s = s.replace('ROT_Y', str(rot_vector.y)) s = s.replace('ROT_Z', str(rot_vector.z)) - s_type = s_type.replace('X_MIN', rec.xmin) + s_type = s_type.replace('X_MIN', str(float(rec.xmin) + x_step_half)) # Mantid xstart is the first pixel centre s_type = s_type.replace('X_STEP', str(x_step)) - s_type = s_type.replace('Y_MIN', rec.ymin) + s_type = s_type.replace('Y_MIN', str(float(rec.ymin) + y_step_half)) s_type = s_type.replace('Y_STEP', str(y_step)) s_type = s_type.replace('X_NUM', rec.nx) s_type = s_type.replace('Y_NUM', rec.ny)