From d8ec14c6bda2bcb78ac2d4e78d15e906dd294061 Mon Sep 17 00:00:00 2001 From: rodwyer100 Date: Wed, 5 Feb 2025 01:13:43 -0800 Subject: [PATCH 1/5] Add files via upload --- .../tracking/kalman/KalmanPatRecDriver.java | 83 +++++++++++++------ 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java index 6121d5e67..3ff856fc9 100644 --- a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java +++ b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java @@ -17,6 +17,8 @@ import org.hps.recon.tracking.TrackData; import org.hps.recon.tracking.TrackIntersectData; import org.hps.recon.tracking.TrackResidualsData; +//import org.hps.recon.tracking.KFKinkData; + import org.hps.recon.tracking.MaterialSupervisor.ScatteringDetectorVolume; import org.hps.recon.tracking.MaterialSupervisor.SiStripPlane; import org.hps.recon.tracking.gbl.GBLStripClusterData; @@ -100,6 +102,7 @@ public class KalmanPatRecDriver extends Driver { private boolean useBeamPositionConditions; // True to use beam position from database private boolean useFixedVertexZPosition; // True to override the database just for the z beam position private Level logLevel = Level.WARNING; // Set log level from steering + private boolean addKinks; private boolean addResiduals; // If true add the hit-on-track residuals to the LCIO event private List sensors = null; // List of tracker sensors @@ -132,6 +135,10 @@ public void setSiHitsLimit(int input) { siHitsLimit = input; } + public void setAddKinks(boolean input) { + addKinks = input; + } + public void setAddResiduals(boolean input) { addResiduals = input; } @@ -322,16 +329,21 @@ public void process(EventHeader event) { //For GBL Refitting List allClstrs = new ArrayList(); List gblStripClusterDataRelations = new ArrayList(); - + + //For layer by layer X and Z Kinks + List trackXKinks = new ArrayList(); + List trackXKinksRelations = new ArrayList(); + List trackZKinks = new ArrayList(); + List trackZKinksRelations = new ArrayList(); + //For hit-on-track residuals information List trackResiduals = new ArrayList(); List trackResidualsRelations = new ArrayList(); List trackIntersects = new ArrayList(); List trackIntersectsRelations = new ArrayList(); - ArrayList[] kPatList = prepareTrackCollections(event, outputFullTracks, trackDataCollection, trackDataRelations, allClstrs, gblStripClusterDataRelations, trackResiduals, trackResidualsRelations, trackIntersects, trackIntersectsRelations); + ArrayList[] kPatList = prepareTrackCollections(event, outputFullTracks, trackDataCollection, trackDataRelations, allClstrs, gblStripClusterDataRelations,trackXKinks,trackXKinksRelations,trackZKinks,trackZKinksRelations,trackResiduals, trackResidualsRelations, trackIntersects, trackIntersectsRelations); - // ArrayList[] kPatList = prepareTrackCollections(event, outputFullTracks, trackDataCollection, trackDataRelations, allClstrs, gblStripClusterDataRelations, trackResiduals, trackResidualsRelations); //mg debug why the track data relations (and others I think) are screwed // for (LCRelation tdRel: trackDataRelations){ @@ -344,12 +356,19 @@ public void process(EventHeader event) { event.put("KFGBLStripClusterDataRelations", gblStripClusterDataRelations, LCRelation.class, flag); event.put("KFTrackData",trackDataCollection, TrackData.class,0); event.put("KFTrackDataRelations",trackDataRelations,LCRelation.class,0); - + + if (addKinks) { + event.put("KFXKink", trackXKinks, TrackResidualsData.class,0); + event.put("KFXKinkRelations", trackXKinksRelations,LCRelation.class,0); + event.put("KFZKink", trackZKinks, TrackResidualsData.class,0); + event.put("KFZKinkRelations", trackZKinksRelations,LCRelation.class,0); + } + if (addResiduals) { event.put("KFUnbiasRes", trackResiduals, TrackResidualsData.class,0); event.put("KFUnbiasResRelations",trackResidualsRelations, LCRelation.class,0); - event.put("KFUnbiasInt", trackIntersects, TrackIntersectData.class, 0); - event.put("KFUnbiasIntRelations", trackIntersectsRelations, LCRelation.class, 0); + event.put("KFUnbiasInt", trackIntersects, TrackIntersectData.class, 0); + event.put("KFUnbiasIntRelations", trackIntersectsRelations, LCRelation.class, 0); } if (kPlot != null) { @@ -384,6 +403,8 @@ public int compare(TrackerHit o1, TrackerHit o2) { private ArrayList[] prepareTrackCollections(EventHeader event, List outputFullTracks, List trackDataCollection, List trackDataRelations, List allClstrs, List gblStripClusterDataRelations, + List trackXKinks, List trackXKinksRelations, + List trackZKinks, List trackZKinksRelations, List trackResiduals, List trackResidualsRelations, List trackIntersects, List trackIntersectsRelations) { @@ -502,32 +523,29 @@ private ArrayList[] prepareTrackCollections(EventHeader event, List layers = new ArrayList(); - List residuals = new ArrayList(); + List residuals = new ArrayList(); List sigmas = new ArrayList(); - List layersInt = new ArrayList(); - List intersect = new ArrayList(); + List layersInt = new ArrayList(); + List intersect = new ArrayList(); List sigmasInt = new ArrayList(); int uindex = 0; int vindex = 1; int windex = 2; - //...loop over clusters and save millipedID to residuals - for (GBLStripClusterData clstr : clstrs) { - Pair res_and_sigma = kTk.unbiasedResidualMillipede(clstr.getId()); + for (int ilay = 0; ilay<14; ilay++) { + Pair res_and_sigma = kTk.unbiasedResidual(ilay); if (res_and_sigma.getSecondElement() > -1.) { - layers.add(clstr.getId()); + layers.add(ilay); residuals.add(res_and_sigma.getFirstElement()); sigmas.add(res_and_sigma.getSecondElement().floatValue()); } - }//Loop on clusters - for (int ilay = 0; ilay<14; ilay++) { - Pair inter_and_sigma = kTk.unbiasedIntersect(ilay, true); + Pair inter_and_sigma = kTk.unbiasedIntersect(ilay, true); layersInt.add(ilay); intersect.add(inter_and_sigma.getFirstElement()[uindex]); intersect.add(inter_and_sigma.getFirstElement()[vindex]); intersect.add(inter_and_sigma.getFirstElement()[windex]); sigmasInt.add(inter_and_sigma.getSecondElement().floatValue()); }//Loop on layers - + //Add the Track Data TrackData KFtrackData = new TrackData(trackerVolume, (float) kTk.getTime(), qualityArray, momentum_f, (float) origin_bFieldY, (float) target_bFieldY, (float) ecal_bFieldY, (float) svtCenter_bFieldY); trackDataCollection.add(KFtrackData); @@ -541,7 +559,22 @@ private ArrayList[] prepareTrackCollections(EventHeader event, List(); + List Xkinks = new ArrayList(); + List Zkinks = new ArrayList(); + for(int ilay=0;ilay<14;ilay++){ + layers.add(ilay); + Xkinks.add(kTk.scatX(ilay)); + Zkinks.add(kTk.scatZ(ilay)); + } + TrackResidualsData kinkXData = new TrackResidualsData(trackerVolume,layers,Xkinks,sigmas); + trackXKinks.add(kinkXData); + trackXKinksRelations.add(new BaseLCRelation(kinkXData, KalmanTrackHPS)); + TrackResidualsData kinkZData = new TrackResidualsData(trackerVolume,layers,Zkinks,sigmas); + trackZKinks.add(kinkZData); + trackZKinksRelations.add(new BaseLCRelation(kinkZData, KalmanTrackHPS)); + /* if (KalmanTrackHPS.getTrackerHits().size() != residuals.size()) { System.out.println("KalmanPatRecDriver::Residuals consistency check failed."); System.out.printf("Track has %d hits while I have %d residuals \n", KalmanTrackHPS.getTrackerHits().size(), residuals.size()); @@ -588,13 +621,13 @@ public void setNumKalmanIteration(int numKalmanIteration) { public void setMaxPtInverse(double maxPtInverse) { this.maxPtInverse = maxPtInverse; } - public void setMaxD0(double maxD0) { + public void setMaxDZero(double maxD0) { this.maxD0 = maxD0; } - public void setMaxZ0(double maxZ0) { + public void setMaxZZero(double maxZ0) { this.maxZ0 = maxZ0; } - public void setMaxChi2(double maxChi2) { + public void setMaxChiTwo(double maxChi2) { this.maxChi2 = maxChi2; } public void setMinHits(int minHits) { @@ -615,19 +648,19 @@ public void setMaxTanLambda(double maxTanLambda) { public void setMaxResidual(double maxResidual) { this.maxResidual = maxResidual; } - public void setMaxChi2Inc(double maxChi2Inc) { + public void setMaxChiTwoInc(double maxChi2Inc) { this.maxChi2Inc = maxChi2Inc; } - public void setMinChi2IncBad(double minChi2IncBad) { + public void setMinChiTwoIncBad(double minChi2IncBad) { this.minChi2IncBad = minChi2IncBad; } - public void setMxChi2Vtx(double mxChi2Vtx) { + public void setMxChiTwoVtx(double mxChi2Vtx) { this.mxChi2Vtx = mxChi2Vtx; } public void setMaxResidShare(double maxResidShare) { this.maxResidShare = maxResidShare; } - public void setMaxChi2IncShare(double maxChi2IncShare) { + public void setMaxChiTwoIncShare(double maxChi2IncShare) { this.maxChi2IncShare = maxChi2IncShare; } public void setNumEvtPlots(int numEvtPlots) { From e76fdb2fb980a3621bb4a0bc3d0d63da60235a6c Mon Sep 17 00:00:00 2001 From: rodwyer100 Date: Wed, 5 Feb 2025 01:15:32 -0800 Subject: [PATCH 2/5] Update KalmanPatRecDriver.java --- .../recon/tracking/kalman/KalmanPatRecDriver.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java index 3ff856fc9..c9ec1d36e 100644 --- a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java +++ b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java @@ -17,7 +17,6 @@ import org.hps.recon.tracking.TrackData; import org.hps.recon.tracking.TrackIntersectData; import org.hps.recon.tracking.TrackResidualsData; -//import org.hps.recon.tracking.KFKinkData; import org.hps.recon.tracking.MaterialSupervisor.ScatteringDetectorVolume; import org.hps.recon.tracking.MaterialSupervisor.SiStripPlane; @@ -621,13 +620,13 @@ public void setNumKalmanIteration(int numKalmanIteration) { public void setMaxPtInverse(double maxPtInverse) { this.maxPtInverse = maxPtInverse; } - public void setMaxDZero(double maxD0) { + public void setMaxD0(double maxD0) { this.maxD0 = maxD0; } - public void setMaxZZero(double maxZ0) { + public void setMaxZ0(double maxZ0) { this.maxZ0 = maxZ0; } - public void setMaxChiTwo(double maxChi2) { + public void setMaxChi2(double maxChi2) { this.maxChi2 = maxChi2; } public void setMinHits(int minHits) { @@ -648,19 +647,19 @@ public void setMaxTanLambda(double maxTanLambda) { public void setMaxResidual(double maxResidual) { this.maxResidual = maxResidual; } - public void setMaxChiTwoInc(double maxChi2Inc) { + public void setMaxChi2Inc(double maxChi2Inc) { this.maxChi2Inc = maxChi2Inc; } - public void setMinChiTwoIncBad(double minChi2IncBad) { + public void setMinChi2IncBad(double minChi2IncBad) { this.minChi2IncBad = minChi2IncBad; } - public void setMxChiTwoVtx(double mxChi2Vtx) { + public void setMxChi2Vtx(double mxChi2Vtx) { this.mxChi2Vtx = mxChi2Vtx; } public void setMaxResidShare(double maxResidShare) { this.maxResidShare = maxResidShare; } - public void setMaxChiTwoIncShare(double maxChi2IncShare) { + public void setMaxChi2IncShare(double maxChi2IncShare) { this.maxChi2IncShare = maxChi2IncShare; } public void setNumEvtPlots(int numEvtPlots) { From 89402a7adff8d27c5145acb75c66613c15b92e35 Mon Sep 17 00:00:00 2001 From: rodwyer100 Date: Wed, 5 Feb 2025 11:08:57 -0800 Subject: [PATCH 3/5] Add files via upload --- .../tracking/kalman/KalmanPatRecDriver.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java index c9ec1d36e..c04137a57 100644 --- a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java +++ b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java @@ -17,6 +17,7 @@ import org.hps.recon.tracking.TrackData; import org.hps.recon.tracking.TrackIntersectData; import org.hps.recon.tracking.TrackResidualsData; +//import org.hps.recon.tracking.KFKinkData; import org.hps.recon.tracking.MaterialSupervisor.ScatteringDetectorVolume; import org.hps.recon.tracking.MaterialSupervisor.SiStripPlane; @@ -530,14 +531,16 @@ private ArrayList[] prepareTrackCollections(EventHeader event, List res_and_sigma = kTk.unbiasedResidual(ilay); + for (GBLStripClusterData clstr: clstrs) { + Pair res_and_sigma = kTk.unbiasedResidualMillipede(clstr.getId()); if (res_and_sigma.getSecondElement() > -1.) { - layers.add(ilay); + layers.add(clstr.getId()); residuals.add(res_and_sigma.getFirstElement()); sigmas.add(res_and_sigma.getSecondElement().floatValue()); } - Pair inter_and_sigma = kTk.unbiasedIntersect(ilay, true); + } + for(int ilay = 0;ilay<14;ilay++){ + Pair inter_and_sigma = kTk.unbiasedIntersect(ilay, true); layersInt.add(ilay); intersect.add(inter_and_sigma.getFirstElement()[uindex]); intersect.add(inter_and_sigma.getFirstElement()[vindex]); @@ -562,10 +565,10 @@ private ArrayList[] prepareTrackCollections(EventHeader event, List(); List Xkinks = new ArrayList(); List Zkinks = new ArrayList(); - for(int ilay=0;ilay<14;ilay++){ - layers.add(ilay); - Xkinks.add(kTk.scatX(ilay)); - Zkinks.add(kTk.scatZ(ilay)); + for(int i = 0; i<14; i++){ + layers.add(i); + Xkinks.add(kTk.scatX(i)); + Zkinks.add(kTk.scatZ(i)); } TrackResidualsData kinkXData = new TrackResidualsData(trackerVolume,layers,Xkinks,sigmas); trackXKinks.add(kinkXData); @@ -620,13 +623,13 @@ public void setNumKalmanIteration(int numKalmanIteration) { public void setMaxPtInverse(double maxPtInverse) { this.maxPtInverse = maxPtInverse; } - public void setMaxD0(double maxD0) { + public void setMaxDZero(double maxD0) { this.maxD0 = maxD0; } - public void setMaxZ0(double maxZ0) { + public void setMaxZZero(double maxZ0) { this.maxZ0 = maxZ0; } - public void setMaxChi2(double maxChi2) { + public void setMaxChiTwo(double maxChi2) { this.maxChi2 = maxChi2; } public void setMinHits(int minHits) { @@ -647,19 +650,19 @@ public void setMaxTanLambda(double maxTanLambda) { public void setMaxResidual(double maxResidual) { this.maxResidual = maxResidual; } - public void setMaxChi2Inc(double maxChi2Inc) { + public void setMaxChiTwoInc(double maxChi2Inc) { this.maxChi2Inc = maxChi2Inc; } - public void setMinChi2IncBad(double minChi2IncBad) { + public void setMinChiTwoIncBad(double minChi2IncBad) { this.minChi2IncBad = minChi2IncBad; } - public void setMxChi2Vtx(double mxChi2Vtx) { + public void setMxChiTwoVtx(double mxChi2Vtx) { this.mxChi2Vtx = mxChi2Vtx; } public void setMaxResidShare(double maxResidShare) { this.maxResidShare = maxResidShare; } - public void setMaxChi2IncShare(double maxChi2IncShare) { + public void setMaxChiTwoIncShare(double maxChi2IncShare) { this.maxChi2IncShare = maxChi2IncShare; } public void setNumEvtPlots(int numEvtPlots) { From cd7956dcad6b7a0fb4d0ecb919997dab56de5a8e Mon Sep 17 00:00:00 2001 From: rodwyer100 Date: Wed, 5 Feb 2025 12:38:34 -0800 Subject: [PATCH 4/5] Add files via upload --- .../hps/recon/tracking/kalman/KalTrack.java | 43 +++++++++++++++++++ .../tracking/kalman/KalmanPatRecDriver.java | 24 ++++++++--- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalTrack.java b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalTrack.java index c713a7a0a..c617c6a24 100644 --- a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalTrack.java +++ b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalTrack.java @@ -35,6 +35,7 @@ public class KalTrack { private Map interceptMomVects; Map millipedeMap; Map lyrMap; + Map laymilli; public int eventNumber; public boolean bad; HelixState helixAtOrigin; @@ -317,6 +318,48 @@ private void makeMillipedeMap() { } } + private void makeLayMilli(){ + laymilli = new HashMap(14); + for (MeasurementSite site : SiteList){ + laymilli.put(site.m.millipedeID,site.m.Layer); + } + } + + public int millToLay(int millipedeID){ + if (laymilli == null) { + makeLayMilli(); + } + if (millipedeMap.containsKey(millipedeID)) { + return laymilli.get(millipedeID); + } else { + return -1; + } + } + + // Does the scatX for Millipede + public double scatXMillipede(int millipedeID){ + if (laymilli == null) { + makeLayMilli(); + } + if (laymilli.containsKey(millipedeID)) { + return scatX(laymilli.get(millipedeID)); + } else { + return -1000.0; + } + } + + // Does the scatZ for Millipede + public double scatZMillipede(int millipedeID){ + if (laymilli == null) { + makeLayMilli(); + } + if (laymilli.containsKey(millipedeID)) { + return scatZ(laymilli.get(millipedeID)); + } else { + return -1000.0; + } + } + // Find the change in smoothed helix angle in XY between one layer and the next public double scatX(int layer) { if (lyrMap == null) { diff --git a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java index c04137a57..b432ca8b7 100644 --- a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java +++ b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java @@ -87,6 +87,7 @@ public class KalmanPatRecDriver extends Driver { private double mxChi2Vtx; // Maximum chi^2 for 5-hit tracks with a vertex constraint private int numEvtPlots; // Number of event displays to plot (gnuplot files) private boolean doDebugPlots; // Whether to make all the debugging histograms + private boolean doForLayer; // Does the track residuals and kinks per layer, not millipede id private int siHitsLimit; // Maximum number of SiClusters in one event allowed for KF pattern reco // (protection against monster events) private double seedCompThr; // Threshold for seedTrack helix parameters compatibility @@ -143,6 +144,10 @@ public void setAddResiduals(boolean input) { addResiduals = input; } + public void setDoForLayer(boolean input) { + doForLayer = input; + } + public void setTargetPosition(double target_pos){ this.target_pos = target_pos; } @@ -534,8 +539,12 @@ private ArrayList[] prepareTrackCollections(EventHeader event, List res_and_sigma = kTk.unbiasedResidualMillipede(clstr.getId()); if (res_and_sigma.getSecondElement() > -1.) { - layers.add(clstr.getId()); - residuals.add(res_and_sigma.getFirstElement()); + int i = clstr.getId(); + if(doForLayer){ + i = kTk.millToLay(i); + } + layers.add(i); + residuals.add(res_and_sigma.getFirstElement()); sigmas.add(res_and_sigma.getSecondElement().floatValue()); } } @@ -565,10 +574,15 @@ private ArrayList[] prepareTrackCollections(EventHeader event, List(); List Xkinks = new ArrayList(); List Zkinks = new ArrayList(); - for(int i = 0; i<14; i++){ + for(GBLStripClusterData clstr: clstrs){ + int milliID = clstr.getId(); + int i = milliID; + if(doForLayer){ + i = kTk.millToLay(i); + } layers.add(i); - Xkinks.add(kTk.scatX(i)); - Zkinks.add(kTk.scatZ(i)); + Xkinks.add(kTk.scatXMillipede(i)); + Zkinks.add(kTk.scatZMillipede(i)); } TrackResidualsData kinkXData = new TrackResidualsData(trackerVolume,layers,Xkinks,sigmas); trackXKinks.add(kinkXData); From 120929c87bff2e473bee08aa70efeb4637d91ffc Mon Sep 17 00:00:00 2001 From: rodwyer100 Date: Wed, 5 Feb 2025 13:51:36 -0800 Subject: [PATCH 5/5] Update KalmanPatRecDriver.java --- .../recon/tracking/kalman/KalmanPatRecDriver.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java index b432ca8b7..9118deb45 100644 --- a/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java +++ b/tracking/src/main/java/org/hps/recon/tracking/kalman/KalmanPatRecDriver.java @@ -637,13 +637,13 @@ public void setNumKalmanIteration(int numKalmanIteration) { public void setMaxPtInverse(double maxPtInverse) { this.maxPtInverse = maxPtInverse; } - public void setMaxDZero(double maxD0) { + public void setMaxD0(double maxD0) { this.maxD0 = maxD0; } - public void setMaxZZero(double maxZ0) { + public void setMaxZ0(double maxZ0) { this.maxZ0 = maxZ0; } - public void setMaxChiTwo(double maxChi2) { + public void setMaxChi2(double maxChi2) { this.maxChi2 = maxChi2; } public void setMinHits(int minHits) { @@ -664,19 +664,19 @@ public void setMaxTanLambda(double maxTanLambda) { public void setMaxResidual(double maxResidual) { this.maxResidual = maxResidual; } - public void setMaxChiTwoInc(double maxChi2Inc) { + public void setMaxChi2Inc(double maxChi2Inc) { this.maxChi2Inc = maxChi2Inc; } - public void setMinChiTwoIncBad(double minChi2IncBad) { + public void setMinChi2IncBad(double minChi2IncBad) { this.minChi2IncBad = minChi2IncBad; } - public void setMxChiTwoVtx(double mxChi2Vtx) { + public void setMxChi2Vtx(double mxChi2Vtx) { this.mxChi2Vtx = mxChi2Vtx; } public void setMaxResidShare(double maxResidShare) { this.maxResidShare = maxResidShare; } - public void setMaxChiTwoIncShare(double maxChi2IncShare) { + public void setMaxChi2IncShare(double maxChi2IncShare) { this.maxChi2IncShare = maxChi2IncShare; } public void setNumEvtPlots(int numEvtPlots) {