DDRK Omega Unified KSampler (advanced)
One KSampler for Flux, SDXL, and everything in between
- model
- positive
- negative
- latent_image
- LATENT
If you've been around ComfyUI long enough to have opinions, you know the sampler rules flipped on you. DPM++ 2M Karras was the safe default on SD 1.5/SDXL, and then flow-matching models arrived and Karras went from safe to actively wrong on them. Suddenly you're running one Euler workflow for Flux and another sampler entirely for SDXL, relearning parameters every time you swap a checkpoint. DDRK Omega Unified KSampler is this pack's answer to exactly that whiplash: a drop-in replacement for the stock KSampler that figures out which model family it's talking to and recalibrates itself.
What it actually does
The node looks at your model's sigma schedule - sigma_max above ~5 means EDM (SDXL, SD 1.5, SD 2), otherwise flow matching (Flux, SD3, Qwen, Krea, HiDream, Chroma, Lumina) - and routes sampling through three phases, each with its own integrator policy and post-processing. The headline feature is the HC2 integrator, an exponential multistep method in the DPM-Solver++/UniPC family: second-order accuracy at one model call per step, which is roughly Heun quality at half the compute on flow-matching models. There's also ancestral SDE noise (FM only), Karras-style churn (EDM only), SABER spatial stabilization, and a final-step perceptual sharpen. The author measured all of this and, refreshingly, published the negative results too: HC2 shows no advantage on EDM, where auto or heun stays the sensible pick.
The inputs that matter
Beyond the usual model, positive, negative, latent_image, seed, steps and cfg, you mostly touch three things:
integrator-auto,hc2,rk4,heun,euler. Leave it onautounless you specifically want HC2.smart_defaults- auto-detects the family and sets scheduler, shift, integrator and enhancer levels. It never touches steps or CFG, which stay checkpoint-specific and are yours to set. It defaults to off; the README's quick start says turn it on.auto_optimize- caps or disables the enhancer stack by compute budget on FM few-step runs. On by default.
The EDM knobs (s_churn, s_tmin, s_tmax, s_noise) and the HC2 knobs (limiter_kappa, hc2_max_order, and the experimental hc2_corrector/sigma_adapt) live in the optional inputs and can stay at defaults until you know you need them. Output is a LATENT, wired straight into the VAE decode like any KSampler.
Installing it
No dependencies, no model downloads - the pyproject.toml ships with an empty dependency list. Either grab it from ComfyUI Manager (search "DDRK Omega Sampler") or:
cd ComfyUI/custom_nodes/
git clone https://github.com/HVOSTOVSKY/DDRK-Omega-Sampler.git
Restart ComfyUI and it's in the node menu.
Where people get burned
- At 6 steps or fewer, the node forces
eulerunless you've explicitly selectedhc2. The console reports the override, so check there if your low-step run suddenly isn't doing what you picked. - Compare at equal model calls, not equal steps. Heun costs 2 calls per step, RK4 costs 4, HC2 and Euler cost 1. An HC2 run at 20 steps is not "like" a Heun run at 20 steps; it's cheaper.
sharpnessdoes nothing on EDM. The parameter is shared across families; the feature isn't.denoisecan't go to 0.0 - it scales steps viasteps/denoise, so exactly zero is a division by zero. The minimum is 0.01, which is also just "do nothing."- If a run goes sideways, flip
debug_modeon and it writes per-step JSON/CSV/summary logs to your ComfyUI output folder. The README is honest that most of the 1.6.0 fixes were found reading those logs, not the code.
Fair warning up front: this is a young pack with essentially no community history yet, so you won't find a Reddit thread full of settings for it. What you get instead is an unusually well-documented project - read the README's "What is actually verified" section before you trust the numbers.
Inputs (47)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| latent_image | LATENT | — | |
| seed | INT | 00–18446744073709550000 | — |
| steps | INT | 201–1000 | — |
| cfg | FLOAT | 5.01–100 | — |
| denoise | FLOAT | 1.000.01–1 | Denoise strength, as in the stock KSampler. Minimum is 0.01, not 0.0: denoise scales the step count via steps/denoise, so exactly 0.0 is a division by zero, and 0.0 denoise means 'do nothing' anyway. |
| scheduler_type | COMBO | ddrk_auto | ddrk_auto: EDM -> ddrk_edm_karras; Flow Matching -> ddrk_model (since 1.8.0; was ddrk_cosine). ddrk_model = the model's own 'simple' schedule, so the shift comes from the model (and any ModelSampling* node in the graph); flow_shift and auto_flow_shift are ignored. ddrk_model_beta = ComfyUI's 'beta' on the same table: same shift, steps denser at both ends, a much smaller final jump (analytic bench: 2-4x less error on FM; not yet image-tested). |
| flow_shift | FLOAT | 3.01–10 | Used by the ddrk_flow_*/cosine/beta/cosmos schedules only. ddrk_model and FM ddrk_auto take the shift from the model. |
| auto_flow_shift | BOOLEAN | false | Derive flow_shift from the latent's token count instead of using the widget value, the way Flux/SD3 intend (shift should grow with image area). At 512x768 the derived value is ~2.05, at 1024x1024 ~3.16 - so a single fixed number cannot be right at both. FM only; ignored on EDM, and ignored by ddrk_model / FM ddrk_auto, which use the model's own shift. WARNING: if ModelSamplingFlux is already in your graph it applies the same shift at the model level and this would double it. Use one or the other. UNVALIDATED - no ablation yet. |
| integrator | COMBO | hc3 | hc3 (recommended): HC2 plus trust damping and a zero-cost corrector - third order at one model call per step, and it falls back towards first order by itself where high CFG makes extrapolation unsafe. hc2: second order, one call per step (the 1.6-1.10 default for FM). euler: first order, one call. heun: 2 calls per step. rk4: 4 calls per step. auto: per-phase choice (heun/rk4 early, hc2 late; 1-4 calls per step). Compare integrators at equal MODEL CALLS, not equal steps. |
| sde_strength | FLOAT | 0.000–0.5 | Ancestral SDE noise, gated to flat regions. 0 = fully deterministic. FM only - ignored on EDM, which uses s_churn. MEASURED (Krea2 Turbo, 8 steps, 3 seeds): 0.00, 0.08 and 0.15 were indistinguishable by dynamic range (within 0.2%); 0.30 widened it 3.6%. The operator saw no quality change at any setting, only a different composition - which is what stochastic sampling does, it moves to a different sample rather than a better one. Treat this as a variation dial, not a quality dial. |
| sharpness | FLOAT | 0.000–1.5 | Final-step perceptual sharpen. FM only - disabled on EDM by design, so it does nothing there. MEASURED (Krea2 Turbo, 8 steps, 3 seeds): 0.10 widened dynamic range 2.6%, 0.12 widened it 3.2%, both consistent across seeds, and the operator saw a clear sharpness increase. The effect had NOT saturated at the point where an inherited cap used to cut it off, so values above 0.12 are now reachable and genuinely untested - halos and edge ringing are the failure mode to watch for. |
| saber_fusion | FLOAT | 0.000–1 | Spatial stabilization (a gated blur). 0 disables the module entirely. MEASURED (Krea2 Turbo, 8 steps, 3 seeds): this consistently NARROWS dynamic range - 0.10 by 0.4%, 0.15 by 0.8% - and the operator reported smoother shadows and a silkier look, but graininess appearing by 0.15. Every other measurement in this project has associated a narrower range with a softer, less detailed result, so treat this as a stylistic smoothing control with a real cost, not as a quality improvement. Turn it off for text, graphics and pixel art. |
| warmup_steps | INT | 00–5 | — |
| beta_a | FLOAT | 2.00.1–10 | Shape parameter A, used only by ddrk_beta. Higher A front-loads larger steps at high sigma and leaves finer steps near sigma 0. Ignored by every other scheduler. |
| beta_b | FLOAT | 1.00.1–10 | Shape parameter B, used only by ddrk_beta. Raising B above ~2 shifts resolution toward high sigma and leaves a large final step, which is usually undesirable. A=2, B=1 gives Karras-like monotonically shrinking steps. |
| auto_optimize | BOOLEAN | true | Flow Matching only: caps or disables SABER/SDE/momentum/sharpness by step budget, and at <=10 steps turns integrator 'auto' into 'hc2'. Does NOT set steps/cfg or the schedule. |
| smart_defaults | BOOLEAN | false | Auto-detect architecture and set scheduler/integrator/shift/saber/sharpness only. Steps/CFG are checkpoint-specific and must be tuned manually. |
| saber_modeopt | COMBO | auto | 3 options: auto, image, video |
| use_ema_saberopt | BOOLEAN | true | — |
| ema_decayopt | FLOAT | 0.700–0.99 | — |
| dyn_thresh_percentileopt | FLOAT | 1.0000.9–1 | Percentile latent limiter. 1.0 = off (default since 1.8.0): at 0.995 it clipped the brightest 0.5% of the final FM latent in 4 of 6 live Krea 2 runs. |
| latent_rescaleopt | FLOAT | 0.000–1 | DEPRECATED - leave at 0. Measured ~30% dynamic range loss and visible artifacts. Use HC2 limiter_kappa instead. |
| restart_repeatsopt | INT | 00–4 | Restart Sampling (Xu et al. 2023). 0 = off. Deterministic solvers accumulate discretisation error; jumping back up in noise a few times contracts it the way an SDE does, without paying on every step. Each repeat costs restart_steps extra model calls. Set sde_strength to 0 when using this. MEASURED: fires correctly and does what it should on EDM (Illustrious, 20 steps: +0.8% dynamic range for 15% more calls, so not a clear win by that metric). On Flow Matching the first attempt never fired at all - see restart_t_min, which must be set relative to the schedule's actual sigma range. |
| restart_stepsopt | INT | 31–8 | Steps taken to descend back after each restart jump. Total extra model calls = restart_repeats x restart_steps. |
| restart_t_minopt | FLOAT | 0.100.01–0.9 | Lower edge of the restart window, as a FRACTION OF SIGMA_MAX - and that is the catch, because the two model families live on different sigma scales. On EDM sigma_max is ~14.6, so 0.10 means sigma 1.46 and the schedule passes through it. On Flow Matching sigma_max is 1.0, so 0.10 means sigma 0.10 - while an 8-step schedule's smallest non-terminal sigma is around 0.33, and restart silently never fired. For FM at few steps use 0.40 or higher. If no schedule point falls in the window the console now says so and prints the value that would work. |
| restart_t_maxopt | FLOAT | 0.350.02–0.95 | Upper edge: how far back up the jump goes, as a fraction of sigma_max. Must exceed restart_t_min. Larger jumps contract more error but discard more of the structure already resolved. |
| hc2_correctoropt | FLOAT | 0.000–1 | HC2 selective corrector. 0 = off. On steps where the high-order correction exceeds this fraction of the first-order step, HC2 spends a SECOND model call to redo the step with an interpolated slope instead of an extrapolated one. MEASURED (Krea2 Turbo, 8 steps, CFG 1, 3 seeds): correction activity peaks around 0.14, so thresholds of 0.30 and 0.50 NEVER FIRE - those settings are identical to 0. At 0.10 it fired on 3 of 8 steps for 12 calls instead of 9; dynamic range fell 4.2% while the operator judged detail and lighting improved, so the metric and the eye disagree here. Useful range is roughly 0.05-0.15. EXPERIMENTAL. |
| sigma_adaptopt | FLOAT | 0.000–0.5 | HC2 adaptive step placement. 0 = off. Moves the intermediate sigma values by up to this fraction to equalise estimated error across steps; step COUNT, start and terminal zero are unchanged. MEASURED (Krea2 Turbo, 8 steps, CFG 1, 3 seeds): 0.10 gave the largest single gain of any option tested, +3.3% dynamic range, reaching +11% on one seed. 0.30 and 0.50 went slightly negative, matching the operator's report that higher values start to hurt on some seeds. Start at 0.10. Note the controller saturates at its own bound when activity falls monotonically, which is most of a run - so above ~0.20 this behaves less like adaptation and more like a fixed schedule stretch. |
| hc2_max_orderopt | INT | 21–3 | HC2 maximum order. 2 = second order, one model call per step (default). 3 = allow third order: uses two past denoiser evaluations, spends ONE extra model call on the first step to bootstrap (a multistep method's first step is otherwise first-order and caps the whole run's accuracy), and falls back to second order on any step where the expansion stops converging. Ignored by every other integrator. |
| limiter_kappaopt | FLOAT | 1.000.1–3 | HC2 slope limiter. Caps the 2nd-order correction at this multiple of the 1st-order step, per element. MEASURED (Anima, CFG 5, 3 seeds): the control responds monotonically - kappa 3.0 clips 2.1% of elements on average, 1.0 clips 6.1%, 0.5 clips 11.8%. By dynamic range the default 1.0 came out best, 0.5 worst (-1.6%). Note the original premise was only partly borne out: going from CFG 1 to CFG 5 raised correction activity by ~57%, not by the order of magnitude that would make aggressive limiting necessary. Leave at 1.0 unless you see overshoot. Ignored by every other integrator. |
| momentum_betaopt | FLOAT | 0.000–0.8 | Adams-Bashforth 2 slope extrapolation for EULER steps only. 0 = plain Euler. Ignored by heun, rk4 and hc2 since 1.10.0: on a higher-order method it makes it first order (measured: RK4 error ~250x, Heun 3-5x). |
| sde_seedopt | INT | -1-1–18446744073709550000 | SDE noise seed. -1 derives the seed from ComfyUI's globally seeded Torch RNG, so the workflow seed remains reproducible. |
| s_churnopt | FLOAT | 00–100 | EDM churn (Karras Alg 2). 0 = off. Try 5-15 for SDXL. EDM models only; silently ignored for Flow Matching. |
| s_tminopt | FLOAT | 0.00–999999 | EDM churn lower sigma bound (Karras Alg 2). Churn only fires while s_tmin <= sigma <= s_tmax. 0.0 = no lower bound. |
| s_tmaxopt | FLOAT | 9999990–999999 | EDM churn upper sigma bound. Default (max) means unbounded, matching Karras Alg 2's s_tmax=inf. Lower it to restrict churn to high-sigma steps only. |
| s_noiseopt | FLOAT | 1.000–2 | EDM churn noise multiplier. 1.0 = standard. |
| content_awareopt | BOOLEAN | true | Content-aware SABER — edge-gated fusion. Disable for pixel-art/flat styles. |
| debug_modeopt | BOOLEAN | false | Write a per-step diagnostics log (JSON+CSV+summary) to your ComfyUI output folder. Off by default; adds overhead only when on. |
| debug_tagopt | STRING | Optional label included in the debug log filename, e.g. 'test1'. | |
| hc2_spaceopt | COMBO | ve | HC2 time variable on Flow Matching. ve (default): lambda = -log(sigma), as HC2 always was. flow: the exact FM parameterisation, half-log-SNR log((1-sigma)/sigma) with a (1-sigma) weight on the correction. MEASURED (Anima, CFG 4, 25 steps, 2 seeds, distance to an RK4 reference): a draw - better on one seed, worse on the other - so it is opt-in. No effect on EDM, where both are the same. |
| refine_scaleopt | FLOAT | 1.001–2 | Second pass (hires fix in latent space). 1.0 = off. Above 1.0 the finished latent is upscaled by this factor and re-sampled from refine_denoise with the same settings: more pixels for eyes, hands and texture than the model gets at its base size. Costs refine_steps extra calls at the larger size. |
| refine_denoiseopt | FLOAT | 0.350.05–1 | How much of the upscaled latent the second pass rewrites. 0.3-0.4 adds detail and keeps the composition; above ~0.5 it starts to redraw. |
| refine_stepsopt | INT | 51–50 | Model calls spent on the second pass (steps actually run at refine_denoise). |
| hc2_free_correctoropt | BOOLEAN | false | HC2 zero-cost corrector (UniPC-style). Off by default. After each HC2 step the model is called at the step's end point anyway, for the next step; with this on, that output is also used to redo the finished step by interpolation instead of extrapolation, then the next step proceeds from the corrected latent. No extra model calls. MEASURED on the analytic bench only (tests/analytic.py, equal calls): EDM Karras 20-32 calls, error 3-3.6x lower than plain HC2; Flow Matching with the model's schedule, a few percent, because the final jump to sigma 0 dominates there. NOT validated on images - A/B it before relying on it. Ignored by other integrators and on steps that follow SDE noise, churn or a restart jump. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |